aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2017-10-24 22:10:47 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2017-10-24 22:10:47 +0000
commit6de8466358aad789d13f78a8c59127884afede60 (patch)
tree13d704048d21c52d88da1a7f830519800bb86399
parente91ee0faa811b6cae44d146aa16c379797ad191e (diff)
parent6ab5a6f30f2a3a9db37604195ff4b802779f83bc (diff)
downloadgcc-6de8466358aad789d13f78a8c59127884afede60.zip
gcc-6de8466358aad789d13f78a8c59127884afede60.tar.gz
gcc-6de8466358aad789d13f78a8c59127884afede60.tar.bz2
Merge from trunk revision 254059.
From-SVN: r254062
-rw-r--r--ChangeLog13
-rw-r--r--MAINTAINERS5
-rw-r--r--config/ChangeLog4
-rw-r--r--config/bootstrap-cet.mk4
-rw-r--r--contrib/ChangeLog4
-rwxr-xr-xcontrib/gcc_update4
-rw-r--r--fixincludes/ChangeLog5
-rwxr-xr-xfixincludes/fixinc.in2
-rw-r--r--gcc/ChangeLog4281
-rw-r--r--gcc/DATESTAMP2
-rw-r--r--gcc/Makefile.in4
-rw-r--r--gcc/ada/ChangeLog1435
-rw-r--r--gcc/ada/Makefile.rtl1
-rw-r--r--gcc/ada/adabkend.adb14
-rw-r--r--gcc/ada/adaint.c28
-rw-r--r--gcc/ada/ali-util.adb4
-rw-r--r--gcc/ada/ali.adb27
-rw-r--r--gcc/ada/ali.ads10
-rw-r--r--gcc/ada/aspects.adb2
-rw-r--r--gcc/ada/atree.adb115
-rw-r--r--gcc/ada/atree.ads28
-rw-r--r--gcc/ada/bindgen.adb243
-rw-r--r--gcc/ada/bindusg.adb7
-rw-r--r--gcc/ada/cal.c8
-rw-r--r--gcc/ada/checks.adb18
-rw-r--r--gcc/ada/clean.adb2
-rw-r--r--gcc/ada/comperr.adb5
-rw-r--r--gcc/ada/cstand.adb49
-rw-r--r--gcc/ada/debug.adb26
-rw-r--r--gcc/ada/doc/gnat_rm/implementation_defined_aspects.rst14
-rw-r--r--gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst3
-rw-r--r--gcc/ada/doc/gnat_rm/representation_clauses_and_pragmas.rst2
-rw-r--r--gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst20
-rw-r--r--gcc/ada/doc/gnat_ugn/elaboration_order_handling_in_gnat.rst3245
-rw-r--r--gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst37
-rw-r--r--gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst8
-rw-r--r--gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst2
-rw-r--r--gcc/ada/doc/share/conf.py1
-rw-r--r--gcc/ada/einfo.adb139
-rw-r--r--gcc/ada/einfo.ads132
-rw-r--r--gcc/ada/errout.adb10
-rw-r--r--gcc/ada/erroutc.adb2
-rw-r--r--gcc/ada/exp_aggr.adb159
-rw-r--r--gcc/ada/exp_atag.ads4
-rw-r--r--gcc/ada/exp_attr.adb32
-rw-r--r--gcc/ada/exp_ch11.adb33
-rw-r--r--gcc/ada/exp_ch11.ads7
-rw-r--r--gcc/ada/exp_ch13.adb4
-rw-r--r--gcc/ada/exp_ch3.adb356
-rw-r--r--gcc/ada/exp_ch4.adb195
-rw-r--r--gcc/ada/exp_ch5.adb80
-rw-r--r--gcc/ada/exp_ch6.adb923
-rw-r--r--gcc/ada/exp_ch6.ads35
-rw-r--r--gcc/ada/exp_ch7.adb49
-rw-r--r--gcc/ada/exp_ch8.adb13
-rw-r--r--gcc/ada/exp_ch9.adb341
-rw-r--r--gcc/ada/exp_dbug.adb2
-rw-r--r--gcc/ada/exp_disp.adb187
-rw-r--r--gcc/ada/exp_disp.ads5
-rw-r--r--gcc/ada/exp_imgv.adb198
-rw-r--r--gcc/ada/exp_prag.adb300
-rw-r--r--gcc/ada/exp_prag.ads18
-rw-r--r--gcc/ada/exp_spark.adb193
-rw-r--r--gcc/ada/exp_unst.adb4
-rw-r--r--gcc/ada/exp_util.adb155
-rw-r--r--gcc/ada/exp_util.ads7
-rw-r--r--gcc/ada/fe.h2
-rw-r--r--gcc/ada/fmap.adb10
-rw-r--r--gcc/ada/fname-sf.adb16
-rw-r--r--gcc/ada/freeze.adb2
-rw-r--r--gcc/ada/freeze.ads14
-rw-r--r--gcc/ada/frontend.adb36
-rw-r--r--gcc/ada/gcc-interface/Make-lang.in2
-rw-r--r--gcc/ada/gcc-interface/Makefile.in14
-rw-r--r--gcc/ada/gcc-interface/decl.c13
-rw-r--r--gcc/ada/gcc-interface/gigi.h4
-rw-r--r--gcc/ada/gcc-interface/lang.opt6
-rw-r--r--gcc/ada/gcc-interface/misc.c19
-rw-r--r--gcc/ada/gcc-interface/trans.c82
-rw-r--r--gcc/ada/gcc-interface/utils.c20
-rw-r--r--gcc/ada/gcc-interface/utils2.c24
-rw-r--r--gcc/ada/ghost.adb6
-rw-r--r--gcc/ada/gnat1drv.adb68
-rw-r--r--gcc/ada/gnat_rm.texi26
-rw-r--r--gcc/ada/gnat_ugn.texi3062
-rw-r--r--gcc/ada/gnatdll.adb6
-rw-r--r--gcc/ada/gnatfind.adb4
-rw-r--r--gcc/ada/gnatlink.adb4
-rw-r--r--gcc/ada/gnatls.adb5
-rw-r--r--gcc/ada/gnatname.adb2
-rw-r--r--gcc/ada/gnatxref.adb6
-rw-r--r--gcc/ada/gprep.adb10
-rw-r--r--gcc/ada/layout.adb32
-rw-r--r--gcc/ada/layout.ads5
-rw-r--r--gcc/ada/lib-load.adb173
-rw-r--r--gcc/ada/lib-writ.adb19
-rw-r--r--gcc/ada/lib-writ.ads29
-rw-r--r--gcc/ada/lib-xref-spark_specific.adb2
-rw-r--r--gcc/ada/lib-xref.ads5
-rw-r--r--gcc/ada/lib.adb65
-rw-r--r--gcc/ada/lib.ads149
-rw-r--r--gcc/ada/libgnarl/a-exetim__darwin.adb1
-rw-r--r--gcc/ada/libgnarl/a-exetim__mingw.adb1
-rw-r--r--gcc/ada/libgnarl/s-intman__vxworks.adb1
-rw-r--r--gcc/ada/libgnarl/s-linux__x32.ads9
-rw-r--r--gcc/ada/libgnarl/s-osinte__darwin.adb1
-rw-r--r--gcc/ada/libgnarl/s-osinte__linux.ads3
-rw-r--r--gcc/ada/libgnarl/s-osinte__lynxos178.adb2
-rw-r--r--gcc/ada/libgnarl/s-osinte__x32.adb1
-rw-r--r--gcc/ada/libgnarl/s-solita.adb31
-rw-r--r--gcc/ada/libgnarl/s-taenca.adb1
-rw-r--r--gcc/ada/libgnarl/s-taprob.adb2
-rw-r--r--gcc/ada/libgnarl/s-taprop__linux.adb173
-rw-r--r--gcc/ada/libgnarl/s-taprop__mingw.adb11
-rw-r--r--gcc/ada/libgnarl/s-taprop__posix.adb253
-rw-r--r--gcc/ada/libgnarl/s-taprop__solaris.adb11
-rw-r--r--gcc/ada/libgnarl/s-taprop__vxworks.adb11
-rw-r--r--gcc/ada/libgnarl/s-tarest.adb190
-rw-r--r--gcc/ada/libgnarl/s-tarest.ads65
-rw-r--r--gcc/ada/libgnarl/s-taskin.adb3
-rw-r--r--gcc/ada/libgnarl/s-taskin.ads14
-rw-r--r--gcc/ada/libgnarl/s-tassta.adb96
-rw-r--r--gcc/ada/libgnarl/s-tassta.ads21
-rw-r--r--gcc/ada/libgnarl/s-tpobop.adb1
-rw-r--r--gcc/ada/libgnarl/s-tpopmo.adb283
-rw-r--r--gcc/ada/libgnarl/s-tporft.adb21
-rw-r--r--gcc/ada/libgnat/a-cfhama.ads2
-rw-r--r--gcc/ada/libgnat/a-strmap.adb2
-rw-r--r--gcc/ada/libgnat/a-strunb.adb2
-rw-r--r--gcc/ada/libgnat/a-stwiun.adb2
-rw-r--r--gcc/ada/libgnat/a-stzunb.adb2
-rw-r--r--gcc/ada/libgnat/a-tags.adb12
-rw-r--r--gcc/ada/libgnat/a-tags.ads13
-rw-r--r--gcc/ada/libgnat/a-teioed.adb1
-rw-r--r--gcc/ada/libgnat/g-alvety.ads2
-rw-r--r--gcc/ada/libgnat/g-expect.adb2
-rw-r--r--gcc/ada/libgnat/g-regist.adb6
-rw-r--r--gcc/ada/libgnat/g-socket.adb1
-rw-r--r--gcc/ada/libgnat/g-socthi__mingw.ads2
-rw-r--r--gcc/ada/libgnat/g-socthi__vxworks.ads2
-rw-r--r--gcc/ada/libgnat/s-os_lib.ads3
-rw-r--r--gcc/ada/libgnat/s-parame.adb28
-rw-r--r--gcc/ada/libgnat/s-parame.ads32
-rw-r--r--gcc/ada/libgnat/s-parame__ae653.ads26
-rw-r--r--gcc/ada/libgnat/s-parame__hpux.ads26
-rw-r--r--gcc/ada/libgnat/s-parame__rtems.adb48
-rw-r--r--gcc/ada/libgnat/s-parame__vxworks.adb12
-rw-r--r--gcc/ada/libgnat/s-parame__vxworks.ads26
-rw-r--r--gcc/ada/libgnat/s-resfil.ads4
-rw-r--r--gcc/ada/libgnat/s-secsta.adb470
-rw-r--r--gcc/ada/libgnat/s-secsta.ads198
-rw-r--r--gcc/ada/libgnat/s-soflin.adb81
-rw-r--r--gcc/ada/libgnat/s-soflin.ads50
-rw-r--r--gcc/ada/libgnat/s-soliin.adb47
-rw-r--r--gcc/ada/libgnat/s-soliin.ads48
-rw-r--r--gcc/ada/libgnat/s-stausa.adb1
-rw-r--r--gcc/ada/libgnat/s-stchop__vxworks.adb2
-rw-r--r--gcc/ada/libgnat/s-thread.ads6
-rw-r--r--gcc/ada/libgnat/s-thread__ae653.adb45
-rw-r--r--gcc/ada/libgnat/s-tsmona__linux.adb2
-rw-r--r--gcc/ada/libgnat/s-tsmona__mingw.adb2
-rw-r--r--gcc/ada/make.adb24
-rw-r--r--gcc/ada/makeusg.adb2
-rw-r--r--gcc/ada/mingw32.h10
-rw-r--r--gcc/ada/namet.adb2
-rw-r--r--gcc/ada/namet.ads2
-rw-r--r--gcc/ada/opt.ads28
-rw-r--r--gcc/ada/osint.adb16
-rw-r--r--gcc/ada/osint.ads10
-rw-r--r--gcc/ada/output.ads4
-rw-r--r--gcc/ada/par-ch10.adb4
-rw-r--r--gcc/ada/par-ch12.adb4
-rw-r--r--gcc/ada/par-ch3.adb2
-rw-r--r--gcc/ada/par-ch8.adb122
-rw-r--r--gcc/ada/par.adb2
-rw-r--r--gcc/ada/prepcomp.adb19
-rw-r--r--gcc/ada/put_scos.adb8
-rw-r--r--gcc/ada/repinfo.adb38
-rw-r--r--gcc/ada/rtfinal.c4
-rw-r--r--gcc/ada/rtsfind.adb2
-rw-r--r--gcc/ada/rtsfind.ads6
-rw-r--r--gcc/ada/s-oscons-tmplt.c3
-rw-r--r--gcc/ada/scn.ads2
-rw-r--r--gcc/ada/sem.adb27
-rw-r--r--gcc/ada/sem.ads4
-rw-r--r--gcc/ada/sem_aggr.adb70
-rw-r--r--gcc/ada/sem_attr.adb40
-rw-r--r--gcc/ada/sem_aux.adb1
-rw-r--r--gcc/ada/sem_aux.ads2
-rw-r--r--gcc/ada/sem_ch10.adb191
-rw-r--r--gcc/ada/sem_ch10.ads8
-rw-r--r--gcc/ada/sem_ch12.adb298
-rw-r--r--gcc/ada/sem_ch13.adb119
-rw-r--r--gcc/ada/sem_ch3.adb192
-rw-r--r--gcc/ada/sem_ch4.adb61
-rw-r--r--gcc/ada/sem_ch5.adb212
-rw-r--r--gcc/ada/sem_ch6.adb63
-rw-r--r--gcc/ada/sem_ch7.adb62
-rw-r--r--gcc/ada/sem_ch8.adb1772
-rw-r--r--gcc/ada/sem_ch8.ads22
-rw-r--r--gcc/ada/sem_ch9.adb43
-rw-r--r--gcc/ada/sem_dim.adb58
-rw-r--r--gcc/ada/sem_elab.adb10301
-rw-r--r--gcc/ada/sem_elab.ads231
-rw-r--r--gcc/ada/sem_prag.adb102
-rw-r--r--gcc/ada/sem_prag.ads19
-rw-r--r--gcc/ada/sem_res.adb227
-rw-r--r--gcc/ada/sem_spark.adb5
-rw-r--r--gcc/ada/sem_type.adb53
-rw-r--r--gcc/ada/sem_util.adb1188
-rw-r--r--gcc/ada/sem_util.ads132
-rw-r--r--gcc/ada/sem_warn.adb69
-rw-r--r--gcc/ada/sem_warn.ads2
-rw-r--r--gcc/ada/sinfo.adb394
-rw-r--r--gcc/ada/sinfo.ads435
-rw-r--r--gcc/ada/sinput-c.adb2
-rw-r--r--gcc/ada/sinput-d.adb12
-rw-r--r--gcc/ada/sinput-l.adb13
-rw-r--r--gcc/ada/sinput.ads2
-rw-r--r--gcc/ada/snames.ads-tmpl2
-rw-r--r--gcc/ada/sprint.adb15
-rw-r--r--gcc/ada/switch-b.adb12
-rw-r--r--gcc/ada/switch-c.adb1
-rw-r--r--gcc/ada/sysdep.c8
-rw-r--r--gcc/ada/targparm.adb22
-rw-r--r--gcc/ada/types.ads5
-rw-r--r--gcc/ada/widechar.ads5
-rw-r--r--gcc/ada/xr_tabls.adb4
-rw-r--r--gcc/ada/xref_lib.adb4
-rw-r--r--gcc/alias.c6
-rw-r--r--gcc/asan.c13
-rw-r--r--gcc/attribs.c3
-rw-r--r--gcc/auto-profile.c22
-rw-r--r--gcc/basic-block.h11
-rw-r--r--gcc/bb-reorder.c32
-rw-r--r--gcc/brig-builtins.def195
-rw-r--r--gcc/brig/ChangeLog68
-rw-r--r--gcc/brig/brig-lang.c160
-rw-r--r--gcc/brig/brigfrontend/brig-branch-inst-handler.cc20
-rw-r--r--gcc/brig/brigfrontend/brig-code-entry-handler.cc28
-rw-r--r--gcc/brig/brigfrontend/brig-fbarrier-handler.cc3
-rw-r--r--gcc/brig/brigfrontend/brig-function-handler.cc40
-rw-r--r--gcc/brig/brigfrontend/brig-function.cc38
-rw-r--r--gcc/brig/brigfrontend/brig-function.h27
-rw-r--r--gcc/brig/brigfrontend/brig-to-generic.cc229
-rw-r--r--gcc/brig/brigfrontend/brig-to-generic.h32
-rw-r--r--gcc/brig/brigfrontend/brig-util.cc28
-rw-r--r--gcc/brig/brigfrontend/brig-util.h28
-rw-r--r--gcc/brig/brigfrontend/brig-variable-handler.cc29
-rw-r--r--gcc/brig/brigfrontend/phsa.h5
-rw-r--r--gcc/builtins.c49
-rw-r--r--gcc/builtins.def1
-rw-r--r--gcc/c-family/ChangeLog138
-rw-r--r--gcc/c-family/c-ada-spec.c565
-rw-r--r--gcc/c-family/c-attribs.c44
-rw-r--r--gcc/c-family/c-common.c170
-rw-r--r--gcc/c-family/c-common.h3
-rw-r--r--gcc/c-family/c-format.c45
-rw-r--r--gcc/c-family/c-gimplify.c2
-rw-r--r--gcc/c-family/c-opts.c16
-rw-r--r--gcc/c-family/c-pretty-print.c9
-rw-r--r--gcc/c-family/c-warn.c36
-rw-r--r--gcc/c-family/c.opt2
-rw-r--r--gcc/c/ChangeLog57
-rw-r--r--gcc/c/c-decl.c21
-rw-r--r--gcc/c/c-parser.c65
-rw-r--r--gcc/c/c-parser.h3
-rw-r--r--gcc/c/c-tree.h4
-rw-r--r--gcc/c/c-typeck.c84
-rw-r--r--gcc/c/gimple-parser.c4
-rw-r--r--gcc/caller-save.c14
-rw-r--r--gcc/calls.c77
-rw-r--r--gcc/cfg.c56
-rw-r--r--gcc/cfganal.c1
-rw-r--r--gcc/cfgbuild.c11
-rw-r--r--gcc/cfgcleanup.c9
-rw-r--r--gcc/cfgexpand.c66
-rw-r--r--gcc/cfghooks.c35
-rw-r--r--gcc/cfgloop.c67
-rw-r--r--gcc/cfgloop.h1
-rw-r--r--gcc/cfgloopanal.c4
-rw-r--r--gcc/cfgloopmanip.c20
-rw-r--r--gcc/cfgrtl.c20
-rw-r--r--gcc/cgraph.c33
-rw-r--r--gcc/cgraph.h2
-rw-r--r--gcc/cgraphunit.c154
-rw-r--r--gcc/combine-stack-adj.c2
-rw-r--r--gcc/combine.c86
-rw-r--r--gcc/common.opt76
-rw-r--r--gcc/common/config/arm/arm-common.c18
-rw-r--r--gcc/common/config/i386/i386-common.c48
-rw-r--r--gcc/compare-elim.c142
-rw-r--r--gcc/config.gcc115
-rw-r--r--gcc/config/aarch64/aarch64-builtins.c5
-rw-r--r--gcc/config/aarch64/aarch64-c.c1
-rw-r--r--gcc/config/aarch64/aarch64-cores.def6
-rw-r--r--gcc/config/aarch64/aarch64-option-extensions.def8
-rw-r--r--gcc/config/aarch64/aarch64-protos.h16
-rw-r--r--gcc/config/aarch64/aarch64-simd-builtins.def8
-rw-r--r--gcc/config/aarch64/aarch64-simd.md121
-rw-r--r--gcc/config/aarch64/aarch64.c283
-rw-r--r--gcc/config/aarch64/aarch64.h36
-rw-r--r--gcc/config/aarch64/aarch64.md29
-rw-r--r--gcc/config/aarch64/arm_neon.h93
-rw-r--r--gcc/config/aarch64/constraints.md14
-rw-r--r--gcc/config/aarch64/iterators.md8
-rw-r--r--gcc/config/aarch64/predicates.md12
-rw-r--r--gcc/config/alpha/alpha.c23
-rw-r--r--gcc/config/alpha/alpha.h8
-rw-r--r--gcc/config/arc/arc.c3
-rw-r--r--gcc/config/arc/arc.h13
-rw-r--r--gcc/config/arm/arm-builtins.c14
-rw-r--r--gcc/config/arm/arm-c.c6
-rw-r--r--gcc/config/arm/arm-cpus.in285
-rw-r--r--gcc/config/arm/arm-isa.h172
-rw-r--r--gcc/config/arm/arm.c280
-rw-r--r--gcc/config/arm/arm.h35
-rw-r--r--gcc/config/arm/arm_neon_builtins.def4
-rw-r--r--gcc/config/arm/iterators.md9
-rw-r--r--gcc/config/arm/neon.md70
-rw-r--r--gcc/config/arm/parsecpu.awk213
-rw-r--r--gcc/config/arm/t-arm11
-rw-r--r--gcc/config/arm/t-multilib2
-rw-r--r--gcc/config/arm/types.md8
-rw-r--r--gcc/config/arm/unspecs.md2
-rw-r--r--gcc/config/avr/avr-protos.h1
-rw-r--r--gcc/config/avr/avr.c15
-rw-r--r--gcc/config/avr/avr.h2
-rw-r--r--gcc/config/avr/avr.md11
-rw-r--r--gcc/config/bfin/bfin.c5
-rw-r--r--gcc/config/bfin/bfin.h11
-rw-r--r--gcc/config/c6x/c6x.h1
-rw-r--r--gcc/config/cr16/cr16.c3
-rw-r--r--gcc/config/cr16/cr16.h7
-rw-r--r--gcc/config/cris/cris.c21
-rw-r--r--gcc/config/cris/cris.h15
-rw-r--r--gcc/config/darwin-c.c8
-rw-r--r--gcc/config/darwin.c6
-rw-r--r--gcc/config/darwin.opt4
-rw-r--r--gcc/config/epiphany/epiphany.c25
-rw-r--r--gcc/config/epiphany/epiphany.h12
-rw-r--r--gcc/config/fr30/fr30.c3
-rw-r--r--gcc/config/fr30/fr30.h13
-rw-r--r--gcc/config/frv/frv.c2
-rw-r--r--gcc/config/frv/frv.h22
-rw-r--r--gcc/config/ft32/ft32.c3
-rw-r--r--gcc/config/ft32/ft32.h10
-rw-r--r--gcc/config/gnu-user.h6
-rw-r--r--gcc/config/h8300/h8300.h7
-rw-r--r--gcc/config/i386/avx512dqintrin.h85
-rw-r--r--gcc/config/i386/cet.c76
-rw-r--r--gcc/config/i386/cetintrin.h134
-rw-r--r--gcc/config/i386/constraints.md5
-rw-r--r--gcc/config/i386/cpuid.h3
-rw-r--r--gcc/config/i386/darwin.h26
-rw-r--r--gcc/config/i386/darwin64.h26
-rw-r--r--gcc/config/i386/driver-i386.c18
-rw-r--r--gcc/config/i386/i386-builtin-types.def2
-rw-r--r--gcc/config/i386/i386-builtin.def99
-rw-r--r--gcc/config/i386/i386-c.c21
-rw-r--r--gcc/config/i386/i386-modes.def10
-rw-r--r--gcc/config/i386/i386-passes.def2
-rw-r--r--gcc/config/i386/i386-protos.h21
-rw-r--r--gcc/config/i386/i386.c5433
-rw-r--r--gcc/config/i386/i386.h80
-rw-r--r--gcc/config/i386/i386.md1376
-rw-r--r--gcc/config/i386/i386.opt30
-rw-r--r--gcc/config/i386/ia32intrin.h12
-rw-r--r--gcc/config/i386/immintrin.h2
-rw-r--r--gcc/config/i386/linux-common.h5
-rw-r--r--gcc/config/i386/predicates.md58
-rw-r--r--gcc/config/i386/sse.md511
-rw-r--r--gcc/config/i386/subst.md4
-rw-r--r--gcc/config/i386/sync.md100
-rw-r--r--gcc/config/i386/t-cet21
-rw-r--r--gcc/config/i386/t-i38616
-rw-r--r--gcc/config/i386/x86-tune-costs.h2272
-rw-r--r--gcc/config/i386/x86-tune-sched-atom.c244
-rw-r--r--gcc/config/i386/x86-tune-sched-bd.c822
-rw-r--r--gcc/config/i386/x86-tune-sched-core.c255
-rw-r--r--gcc/config/i386/x86-tune-sched.c627
-rw-r--r--gcc/config/i386/x86-tune.def89
-rw-r--r--gcc/config/ia64/ia64.c32
-rw-r--r--gcc/config/ia64/ia64.h13
-rw-r--r--gcc/config/iq2000/iq2000.c26
-rw-r--r--gcc/config/iq2000/iq2000.h7
-rw-r--r--gcc/config/lm32/lm32.c15
-rw-r--r--gcc/config/lm32/lm32.h7
-rw-r--r--gcc/config/m32c/m32c.h1
-rw-r--r--gcc/config/m32r/m32r.c16
-rw-r--r--gcc/config/m32r/m32r.h15
-rw-r--r--gcc/config/m68k/m68k.h1
-rw-r--r--gcc/config/mcore/mcore.c3
-rw-r--r--gcc/config/mcore/mcore.h12
-rw-r--r--gcc/config/microblaze/linux.h2
-rw-r--r--gcc/config/microblaze/microblaze.c24
-rw-r--r--gcc/config/microblaze/microblaze.h10
-rw-r--r--gcc/config/mips/mips.c47
-rw-r--r--gcc/config/mips/mips.h24
-rw-r--r--gcc/config/mmix/mmix-protos.h2
-rw-r--r--gcc/config/mmix/mmix.c20
-rw-r--r--gcc/config/mmix/mmix.h6
-rw-r--r--gcc/config/mn10300/mn10300.h7
-rw-r--r--gcc/config/moxie/moxie.c3
-rw-r--r--gcc/config/moxie/moxie.h10
-rw-r--r--gcc/config/msp430/msp430.c6
-rw-r--r--gcc/config/msp430/msp430.h1
-rw-r--r--gcc/config/nds32/nds32.c8
-rw-r--r--gcc/config/nds32/nds32.h2
-rw-r--r--gcc/config/netbsd-protos.h20
-rw-r--r--gcc/config/netbsd-stdint.h16
-rw-r--r--gcc/config/netbsd.c54
-rw-r--r--gcc/config/netbsd.h6
-rw-r--r--gcc/config/nios2/nios2-protos.h5
-rw-r--r--gcc/config/nios2/nios2.c392
-rw-r--r--gcc/config/nios2/nios2.h5
-rw-r--r--gcc/config/nios2/nios2.md81
-rw-r--r--gcc/config/nvptx/nvptx.c13
-rw-r--r--gcc/config/nvptx/nvptx.h1
-rw-r--r--gcc/config/pa/pa-linux.h3
-rw-r--r--gcc/config/pa/pa.c47
-rw-r--r--gcc/config/pa/pa.h18
-rw-r--r--gcc/config/pdp11/pdp11.h6
-rw-r--r--gcc/config/powerpcspe/aix.h12
-rw-r--r--gcc/config/powerpcspe/darwin.h10
-rw-r--r--gcc/config/powerpcspe/powerpcspe-c.c7
-rw-r--r--gcc/config/powerpcspe/powerpcspe.c59
-rw-r--r--gcc/config/powerpcspe/powerpcspe.h24
-rw-r--r--gcc/config/riscv/riscv.c14
-rw-r--r--gcc/config/riscv/riscv.h18
-rw-r--r--gcc/config/rl78/rl78-protos.h10
-rw-r--r--gcc/config/rl78/rl78.c39
-rw-r--r--gcc/config/rl78/rl78.h1
-rw-r--r--gcc/config/rl78/rl78.md20
-rw-r--r--gcc/config/rs6000/aix.h12
-rw-r--r--gcc/config/rs6000/altivec.h2
-rw-r--r--gcc/config/rs6000/altivec.md22
-rw-r--r--gcc/config/rs6000/amo.h152
-rw-r--r--gcc/config/rs6000/darwin.h10
-rw-r--r--gcc/config/rs6000/predicates.md28
-rw-r--r--gcc/config/rs6000/rs6000-builtin.def44
-rw-r--r--gcc/config/rs6000/rs6000-c.c87
-rw-r--r--gcc/config/rs6000/rs6000-p8swap.c271
-rw-r--r--gcc/config/rs6000/rs6000-protos.h4
-rw-r--r--gcc/config/rs6000/rs6000-string.c4
-rw-r--r--gcc/config/rs6000/rs6000.c757
-rw-r--r--gcc/config/rs6000/rs6000.h49
-rw-r--r--gcc/config/rs6000/rs6000.md690
-rw-r--r--gcc/config/rs6000/sysv4.h2
-rw-r--r--gcc/config/rs6000/vsx.md134
-rw-r--r--gcc/config/rx/rx.h1
-rw-r--r--gcc/config/s390/predicates.md7
-rw-r--r--gcc/config/s390/s390-builtin-types.def77
-rw-r--r--gcc/config/s390/s390-builtins.def27
-rw-r--r--gcc/config/s390/s390.c403
-rw-r--r--gcc/config/s390/s390.h4
-rw-r--r--gcc/config/s390/vecintrin.h4
-rw-r--r--gcc/config/s390/vector.md286
-rw-r--r--gcc/config/s390/vx-builtins.md39
-rw-r--r--gcc/config/sh/sh.c3
-rw-r--r--gcc/config/sh/sh.h10
-rw-r--r--gcc/config/sparc/sparc.c41
-rw-r--r--gcc/config/sparc/sparc.h12
-rw-r--r--gcc/config/spu/spu.c25
-rw-r--r--gcc/config/spu/spu.h3
-rw-r--r--gcc/config/stormy16/stormy16.c3
-rw-r--r--gcc/config/stormy16/stormy16.h6
-rw-r--r--gcc/config/t-netbsd21
-rw-r--r--gcc/config/tilegx/tilegx.c3
-rw-r--r--gcc/config/tilegx/tilegx.h8
-rw-r--r--gcc/config/tilepro/tilepro.c3
-rw-r--r--gcc/config/tilepro/tilepro.h8
-rw-r--r--gcc/config/v850/v850.h7
-rw-r--r--gcc/config/vax/elf.h4
-rw-r--r--gcc/config/vax/vax.c15
-rw-r--r--gcc/config/vax/vax.h6
-rw-r--r--gcc/config/visium/visium.c30
-rw-r--r--gcc/config/visium/visium.h21
-rw-r--r--gcc/config/vms/vms-c.c4
-rw-r--r--gcc/config/xtensa/xtensa.c33
-rw-r--r--gcc/config/xtensa/xtensa.h15
-rwxr-xr-xgcc/configure2
-rw-r--r--gcc/configure.ac2
-rw-r--r--gcc/cp/ChangeLog429
-rw-r--r--gcc/cp/Make-lang.in2
-rw-r--r--gcc/cp/call.c73
-rw-r--r--gcc/cp/class.c58
-rw-r--r--gcc/cp/constexpr.c22
-rw-r--r--gcc/cp/constraint.cc7
-rw-r--r--gcc/cp/cp-objcp-common.c72
-rw-r--r--gcc/cp/cp-tree.h107
-rw-r--r--gcc/cp/cvt.c41
-rw-r--r--gcc/cp/decl.c115
-rw-r--r--gcc/cp/decl2.c151
-rw-r--r--gcc/cp/error.c5
-rw-r--r--gcc/cp/except.c10
-rw-r--r--gcc/cp/expr.c147
-rw-r--r--gcc/cp/init.c3
-rw-r--r--gcc/cp/lambda.c175
-rw-r--r--gcc/cp/lex.c2
-rw-r--r--gcc/cp/mangle.c54
-rw-r--r--gcc/cp/method.c10
-rw-r--r--gcc/cp/name-lookup.c231
-rw-r--r--gcc/cp/name-lookup.h9
-rw-r--r--gcc/cp/optimize.c4
-rw-r--r--gcc/cp/parser.c511
-rw-r--r--gcc/cp/parser.h4
-rw-r--r--gcc/cp/pt.c120
-rw-r--r--gcc/cp/rtti.c8
-rw-r--r--gcc/cp/semantics.c71
-rw-r--r--gcc/cp/tree.c28
-rw-r--r--gcc/cp/typeck.c52
-rw-r--r--gcc/cp/typeck2.c14
-rw-r--r--gcc/cse.c23
-rw-r--r--gcc/dbxout.c8
-rw-r--r--gcc/defaults.h4
-rw-r--r--gcc/diagnostic-color.c28
-rw-r--r--gcc/doc/extend.texi401
-rw-r--r--gcc/doc/gimple.texi12
-rw-r--r--gcc/doc/install.texi7
-rw-r--r--gcc/doc/invoke.texi207
-rw-r--r--gcc/doc/md.texi9
-rw-r--r--gcc/doc/rtl.texi20
-rw-r--r--gcc/doc/sourcebuild.texi27
-rw-r--r--gcc/doc/tm.texi68
-rw-r--r--gcc/doc/tm.texi.in33
-rw-r--r--gcc/domwalk.c72
-rw-r--r--gcc/domwalk.h19
-rw-r--r--gcc/dse.c2
-rw-r--r--gcc/dwarf2out.c245
-rw-r--r--gcc/emit-rtl.c1
-rw-r--r--gcc/except.c39
-rw-r--r--gcc/explow.c258
-rw-r--r--gcc/explow.h12
-rw-r--r--gcc/expmed.c4
-rw-r--r--gcc/expr.c35
-rw-r--r--gcc/file-find.c35
-rw-r--r--gcc/file-find.h1
-rw-r--r--gcc/final.c9
-rw-r--r--gcc/flag-types.h21
-rw-r--r--gcc/fold-const-call.c12
-rw-r--r--gcc/fold-const.c555
-rw-r--r--gcc/fold-const.h2
-rw-r--r--gcc/fortran/ChangeLog335
-rw-r--r--gcc/fortran/check.c14
-rw-r--r--gcc/fortran/class.c3
-rw-r--r--gcc/fortran/cpp.c4
-rw-r--r--gcc/fortran/decl.c37
-rw-r--r--gcc/fortran/dump-parse-tree.c49
-rw-r--r--gcc/fortran/expr.c14
-rw-r--r--gcc/fortran/frontend-passes.c384
-rw-r--r--gcc/fortran/gfortran.h16
-rw-r--r--gcc/fortran/interface.c97
-rw-r--r--gcc/fortran/intrinsic.c31
-rw-r--r--gcc/fortran/invoke.texi65
-rw-r--r--gcc/fortran/io.c34
-rw-r--r--gcc/fortran/lang.opt14
-rw-r--r--gcc/fortran/match.c11
-rw-r--r--gcc/fortran/misc.c41
-rw-r--r--gcc/fortran/module.c32
-rw-r--r--gcc/fortran/openmp.c33
-rw-r--r--gcc/fortran/parse.c24
-rw-r--r--gcc/fortran/primary.c69
-rw-r--r--gcc/fortran/resolve.c188
-rw-r--r--gcc/fortran/scanner.c10
-rw-r--r--gcc/fortran/symbol.c112
-rw-r--r--gcc/fortran/target-memory.c2
-rw-r--r--gcc/fortran/trans-array.c29
-rw-r--r--gcc/fortran/trans-const.c2
-rw-r--r--gcc/fortran/trans-decl.c16
-rw-r--r--gcc/fortran/trans-expr.c68
-rw-r--r--gcc/fortran/trans-intrinsic.c15
-rw-r--r--gcc/fortran/trans-io.c4
-rw-r--r--gcc/fortran/trans-stmt.c45
-rw-r--r--gcc/fortran/trans-types.c38
-rw-r--r--gcc/fortran/trans.c2
-rw-r--r--gcc/function.c65
-rw-r--r--gcc/function.h8
-rw-r--r--gcc/fwprop.c4
-rw-r--r--gcc/gcc-ar.c8
-rw-r--r--gcc/genmodes.c2
-rw-r--r--gcc/genrecog.c15
-rw-r--r--gcc/gimple-expr.c10
-rw-r--r--gcc/gimple-fold.c2
-rw-r--r--gcc/gimple-pretty-print.c13
-rw-r--r--gcc/gimple-ssa-isolate-paths.c1
-rw-r--r--gcc/gimple-ssa-sprintf.c60
-rw-r--r--gcc/gimple-ssa-store-merging.c15
-rw-r--r--gcc/gimple-ssa-strength-reduction.c8
-rw-r--r--gcc/gimple-ssa-warn-alloca.c95
-rw-r--r--gcc/gimple.c33
-rw-r--r--gcc/gimple.h22
-rw-r--r--gcc/gimplify.c26
-rw-r--r--gcc/go/ChangeLog9
-rw-r--r--gcc/go/Make-lang.in1
-rw-r--r--gcc/go/go-system.h6
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/escape.cc2
-rw-r--r--gcc/go/gofrontend/expressions.cc56
-rw-r--r--gcc/go/gofrontend/gogo.cc218
-rw-r--r--gcc/go/gofrontend/gogo.h118
-rw-r--r--gcc/go/gofrontend/import.cc14
-rw-r--r--gcc/go/gofrontend/names.cc803
-rw-r--r--gcc/go/gofrontend/types.cc626
-rw-r--r--gcc/go/gofrontend/types.h122
-rw-r--r--gcc/godump.c2
-rw-r--r--gcc/graphite-dependences.c78
-rw-r--r--gcc/graphite-isl-ast-to-gimple.c2182
-rw-r--r--gcc/graphite-optimize-isl.c38
-rw-r--r--gcc/graphite-scop-detection.c951
-rw-r--r--gcc/graphite-sese-to-poly.c202
-rw-r--r--gcc/graphite.c245
-rw-r--r--gcc/graphite.h3
-rw-r--r--gcc/haifa-sched.c144
-rw-r--r--gcc/hooks.c6
-rw-r--r--gcc/hooks.h2
-rw-r--r--gcc/hsa-common.h3
-rw-r--r--gcc/hsa-gen.c233
-rw-r--r--gcc/ifcvt.c14
-rw-r--r--gcc/inchash.h11
-rw-r--r--gcc/incpath.c76
-rw-r--r--gcc/incpath.h17
-rw-r--r--gcc/internal-fn.c18
-rw-r--r--gcc/ipa-cp.c4
-rw-r--r--gcc/ipa-devirt.c8
-rw-r--r--gcc/ipa-icf.c28
-rw-r--r--gcc/ipa-inline-transform.c9
-rw-r--r--gcc/ipa-polymorphic-call.c5
-rw-r--r--gcc/ipa-prop.c13
-rw-r--r--gcc/ipa-pure-const.c22
-rw-r--r--gcc/ipa-split.c1
-rw-r--r--gcc/ipa-utils.c34
-rw-r--r--gcc/ipa-utils.h17
-rw-r--r--gcc/ira-color.c9
-rw-r--r--gcc/ira-costs.c5
-rw-r--r--gcc/ira.c6
-rw-r--r--gcc/jit/ChangeLog107
-rw-r--r--gcc/jit/docs/_build/texinfo/libgccjit.texi1162
-rw-r--r--gcc/jit/docs/cp/topics/expressions.rst20
-rw-r--r--gcc/jit/docs/topics/compatibility.rst15
-rw-r--r--gcc/jit/docs/topics/expressions.rst40
-rw-r--r--gcc/jit/docs/topics/function-pointers.rst80
-rw-r--r--gcc/jit/docs/topics/index.rst1
-rw-r--r--gcc/jit/docs/topics/types.rst9
-rw-r--r--gcc/jit/jit-common.h2
-rw-r--r--gcc/jit/jit-playback.c30
-rw-r--r--gcc/jit/jit-playback.h8
-rw-r--r--gcc/jit/jit-recording.c331
-rw-r--r--gcc/jit/jit-recording.h80
-rw-r--r--gcc/jit/libgccjit++.h31
-rw-r--r--gcc/jit/libgccjit.c80
-rw-r--r--gcc/jit/libgccjit.h32
-rw-r--r--gcc/jit/libgccjit.map10
-rw-r--r--gcc/langhooks.c4
-rw-r--r--gcc/langhooks.h8
-rw-r--r--gcc/loop-doloop.c2
-rw-r--r--gcc/loop-unroll.c10
-rw-r--r--gcc/lra-constraints.c18
-rw-r--r--gcc/lra-lives.c13
-rw-r--r--gcc/lra-spills.c4
-rw-r--r--gcc/lra.c3
-rw-r--r--gcc/lto-streamer-in.c9
-rw-r--r--gcc/lto-streamer-out.c25
-rw-r--r--gcc/lto/ChangeLog15
-rw-r--r--gcc/lto/lto-lang.c2
-rw-r--r--gcc/lto/lto.c6
-rw-r--r--gcc/match.pd270
-rw-r--r--gcc/modulo-sched.c18
-rw-r--r--gcc/objc/ChangeLog14
-rw-r--r--gcc/objc/objc-act.c39
-rw-r--r--gcc/omp-expand.c38
-rw-r--r--gcc/omp-low.c18
-rw-r--r--gcc/optabs-query.c2
-rw-r--r--gcc/optabs.c44
-rw-r--r--gcc/optc-gen.awk4
-rw-r--r--gcc/optc-save-gen.awk4
-rw-r--r--gcc/opts-common.c27
-rw-r--r--gcc/opts.c9
-rw-r--r--gcc/opts.h2
-rw-r--r--gcc/params.def32
-rw-r--r--gcc/passes.c4
-rw-r--r--gcc/postreload-gcse.c12
-rw-r--r--gcc/predict.c73
-rw-r--r--gcc/predict.h3
-rw-r--r--gcc/pretty-print.c664
-rw-r--r--gcc/print-rtl.c2
-rw-r--r--gcc/print-tree.c4
-rw-r--r--gcc/profile-count.c25
-rw-r--r--gcc/profile-count.h92
-rw-r--r--gcc/profile.c5
-rw-r--r--gcc/recog.c4
-rw-r--r--gcc/ree.c14
-rw-r--r--gcc/reg-notes.def11
-rw-r--r--gcc/reg-stack.c31
-rw-r--r--gcc/regcprop.c16
-rw-r--r--gcc/reload1.c5
-rw-r--r--gcc/rtl.h4
-rw-r--r--gcc/rtlanal.c22
-rw-r--r--gcc/rtlhooks.c28
-rw-r--r--gcc/sanitizer.def24
-rw-r--r--gcc/sanopt.c268
-rw-r--r--gcc/sbitmap.c230
-rw-r--r--gcc/sbitmap.h27
-rw-r--r--gcc/sched-deps.c5
-rw-r--r--gcc/sched-int.h13
-rw-r--r--gcc/sched-rgn.c4
-rw-r--r--gcc/sel-sched-ir.c2
-rw-r--r--gcc/selftest-run-tests.c2
-rw-r--r--gcc/selftest.h2
-rw-r--r--gcc/sese.c319
-rw-r--r--gcc/sese.h35
-rw-r--r--gcc/shrink-wrap.c1
-rw-r--r--gcc/simplify-rtx.c89
-rw-r--r--gcc/stmt.c4
-rw-r--r--gcc/stor-layout.c16
-rw-r--r--gcc/substring-locations.c17
-rw-r--r--gcc/substring-locations.h4
-rw-r--r--gcc/system.h23
-rw-r--r--gcc/target-insns.def1
-rw-r--r--gcc/target.def64
-rw-r--r--gcc/target.h6
-rw-r--r--gcc/targhooks.c44
-rw-r--r--gcc/targhooks.h6
-rw-r--r--gcc/testsuite/ChangeLog2093
-rw-r--r--gcc/testsuite/brig.dg/test/gimple/fbarrier.hsail8
-rw-r--r--gcc/testsuite/brig.dg/test/gimple/function_calls.hsail2
-rw-r--r--gcc/testsuite/brig.dg/test/gimple/smoke_test.hsail6
-rw-r--r--gcc/testsuite/brig.dg/test/gimple/variables.hsail7
-rw-r--r--gcc/testsuite/c-c++-common/Wbuiltin-declaration-mismatch-1.c4
-rw-r--r--gcc/testsuite/c-c++-common/Wno-builtin-declaration-mismatch-1.c4
-rw-r--r--gcc/testsuite/c-c++-common/Wtautological-compare-6.c11
-rw-r--r--gcc/testsuite/c-c++-common/Wtautological-compare-7.c11
-rw-r--r--gcc/testsuite/c-c++-common/attr-nocf-check-1.c30
-rw-r--r--gcc/testsuite/c-c++-common/attr-nocf-check-2.c5
-rw-r--r--gcc/testsuite/c-c++-common/attr-nocf-check-3.c29
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c4
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c3
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c3
-rw-r--r--gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c3
-rw-r--r--gcc/testsuite/c-c++-common/fcf-protection-1.c4
-rw-r--r--gcc/testsuite/c-c++-common/fcf-protection-2.c4
-rw-r--r--gcc/testsuite/c-c++-common/fcf-protection-3.c4
-rw-r--r--gcc/testsuite/c-c++-common/fcf-protection-4.c2
-rw-r--r--gcc/testsuite/c-c++-common/fcf-protection-5.c4
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-double-reduction-n.c2
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-double-reduction.c2
-rw-r--r--gcc/testsuite/c-c++-common/goacc/kernels-reduction.c2
-rw-r--r--gcc/testsuite/c-c++-common/gomp/pr63326.c22
-rw-r--r--gcc/testsuite/c-c++-common/missing-close-symbol.c2
-rw-r--r--gcc/testsuite/c-c++-common/missing-symbol.c35
-rw-r--r--gcc/testsuite/c-c++-common/pr57371-4.c12
-rw-r--r--gcc/testsuite/c-c++-common/rotate-5.c67
-rw-r--r--gcc/testsuite/c-c++-common/rotate-6.c582
-rw-r--r--gcc/testsuite/c-c++-common/rotate-6a.c6
-rw-r--r--gcc/testsuite/c-c++-common/rotate-7.c582
-rw-r--r--gcc/testsuite/c-c++-common/rotate-7a.c6
-rw-r--r--gcc/testsuite/c-c++-common/rotate-8.c171
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/attrib-5.c10
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/builtin-1.c36
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c224
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-10.c66
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c82
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c24
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c40
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c24
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c24
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-8.c78
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-9.c52
-rw-r--r--gcc/testsuite/c-c++-common/ubsan/ptr-overflow-sanitization-1.c78
-rw-r--r--gcc/testsuite/g++.dg/abi/mangle41.C4
-rw-r--r--gcc/testsuite/g++.dg/asan/asan_test.C1
-rw-r--r--gcc/testsuite/g++.dg/asan/default-options-1.C2
-rw-r--r--gcc/testsuite/g++.dg/cet-notrack-1.C25
-rw-r--r--gcc/testsuite/g++.dg/concepts/pr71368.C25
-rw-r--r--gcc/testsuite/g++.dg/concepts/req6.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp/string-3.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/alignas12.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-61323.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-64462.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-68754.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-ctor20.C8
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/constexpr-ice18.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/enum35.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/enum36.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/error1.C11
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-70343.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-asm1.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-redundancy.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const6.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const7.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice22.C25
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice23.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested8.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/lambda/lambda-stmtexpr1.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/noexcept31.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr67625.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr70338.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr70887.C31
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr80805.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr82299.C9
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/pr82560.C28
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic-crash3.C32
-rw-r--r--gcc/testsuite/g++.dg/cpp0x/variadic-crash4.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn40.C37
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn41.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn42.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn43.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn44.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/auto-fn45.C27
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/constexpr-68754.C7
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-69078-1.C28
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-69078-2.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-69977.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-70570.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-78018.C37
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-79005.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4a.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep2.C18
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice5.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice6.C13
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice7.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice8.C16
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-nested1.C34
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-noexcept1.C10
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic5.C61
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic6.C19
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr65202.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr66690.C14
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr71875.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr77786.C21
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr78523.C12
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr80194.C17
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr80471.C23
-rw-r--r--gcc/testsuite/g++.dg/cpp1y/pr82373.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction44.C5
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction45.C24
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/class-deduction46.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/constexpr-lambda17.C30
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/constexpr-lambda18.C30
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/cplusplus.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/cplusplus_1z.C6
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/lambda-this1.C20
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C2
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/noexcept-type18.C15
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/pr81016.C4
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/bitfield1.C77
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/bitfield2.C26
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/bitfield3.C55
-rw-r--r--gcc/testsuite/g++.dg/cpp2a/ptrmem1.C23
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp11.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp14.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp98.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/pr77363.C8
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-1.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-2.C4
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-3.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-5.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-params-1.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-params-13.C10
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-params-2.C4
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-params-3.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/template-params-5.C2
-rw-r--r--gcc/testsuite/g++.dg/debug/dwarf2/typedef6.C2
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C57
-rw-r--r--gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C11
-rw-r--r--gcc/testsuite/g++.dg/eh/uncaught1.C3
-rw-r--r--gcc/testsuite/g++.dg/eh/uncaught2.C2
-rw-r--r--gcc/testsuite/g++.dg/eh/uncaught3.C1
-rw-r--r--gcc/testsuite/g++.dg/eh/uncaught4.C1
-rw-r--r--gcc/testsuite/g++.dg/ext/attr-ifunc-1.C34
-rw-r--r--gcc/testsuite/g++.dg/ext/attr-ifunc-2.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/attr-ifunc-3.C23
-rw-r--r--gcc/testsuite/g++.dg/ext/attr-ifunc-4.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/attr-ifunc-5.C45
-rw-r--r--gcc/testsuite/g++.dg/ext/attrib54.C14
-rw-r--r--gcc/testsuite/g++.dg/ext/bitfield6.C15
-rw-r--r--gcc/testsuite/g++.dg/ext/bitfield7.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/bitfield8.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/bitfield9.C10
-rw-r--r--gcc/testsuite/g++.dg/ext/is_trivially_constructible5.C12
-rw-r--r--gcc/testsuite/g++.dg/ext/pr57362.C2
-rw-r--r--gcc/testsuite/g++.dg/ext/varargs2.C17
-rw-r--r--gcc/testsuite/g++.dg/gomp/pr77578.C31
-rw-r--r--gcc/testsuite/g++.dg/guality/pr82630.C58
-rw-r--r--gcc/testsuite/g++.dg/lookup/extern-c-hidden.C4
-rw-r--r--gcc/testsuite/g++.dg/lookup/extern-c-redecl.C2
-rw-r--r--gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C25
-rw-r--r--gcc/testsuite/g++.dg/lto/pr82414_0.C13
-rw-r--r--gcc/testsuite/g++.dg/missing-symbol-2.C58
-rw-r--r--gcc/testsuite/g++.dg/opt/pr70100.C21
-rw-r--r--gcc/testsuite/g++.dg/opt/pr81715.C36
-rw-r--r--gcc/testsuite/g++.dg/opt/pr82159-2.C65
-rw-r--r--gcc/testsuite/g++.dg/opt/pr82159.C18
-rw-r--r--gcc/testsuite/g++.dg/opt/pr82577.C22
-rw-r--r--gcc/testsuite/g++.dg/other/do1.C4
-rw-r--r--gcc/testsuite/g++.dg/other/dump-ada-spec-10.C24
-rw-r--r--gcc/testsuite/g++.dg/other/pr53574.C48
-rw-r--r--gcc/testsuite/g++.dg/other/pr68252.C5
-rw-r--r--gcc/testsuite/g++.dg/parse/builtin2.C2
-rw-r--r--gcc/testsuite/g++.dg/parse/error11.C2
-rw-r--r--gcc/testsuite/g++.dg/parse/pragma2.C4
-rw-r--r--gcc/testsuite/g++.dg/pr82155.C36
-rw-r--r--gcc/testsuite/g++.dg/pr82413.C3
-rw-r--r--gcc/testsuite/g++.dg/template/bitfield4.C6
-rw-r--r--gcc/testsuite/g++.dg/template/cast4.C4
-rw-r--r--gcc/testsuite/g++.dg/template/crash108.C2
-rw-r--r--gcc/testsuite/g++.dg/template/crash128.C19
-rw-r--r--gcc/testsuite/g++.dg/template/error11.C2
-rw-r--r--gcc/testsuite/g++.dg/template/extern-c.C66
-rw-r--r--gcc/testsuite/g++.dg/torture/pr77555.C20
-rw-r--r--gcc/testsuite/g++.dg/torture/pr79180.C23
-rw-r--r--gcc/testsuite/g++.dg/tree-ssa/pr8781.C2
-rw-r--r--gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C16
-rw-r--r--gcc/testsuite/g++.dg/ubsan/pr81929.C14
-rw-r--r--gcc/testsuite/g++.dg/ubsan/pr82353-2-aux.cc32
-rw-r--r--gcc/testsuite/g++.dg/ubsan/pr82353-2.C20
-rw-r--r--gcc/testsuite/g++.dg/ubsan/pr82353-2.h31
-rw-r--r--gcc/testsuite/g++.dg/ubsan/pr82353.C60
-rw-r--r--gcc/testsuite/g++.dg/vect/slp-pr56812.cc4
-rw-r--r--gcc/testsuite/g++.dg/warn/Wbuiltin_declaration_mismatch-1.C7
-rw-r--r--gcc/testsuite/g++.dg/warn/Wreturn-local-addr-4.C18
-rw-r--r--gcc/testsuite/g++.dg/warn/mvp.C78
-rw-r--r--gcc/testsuite/g++.dg/warn/pr82424.C20
-rw-r--r--gcc/testsuite/g++.old-deja/g++.abi/vtable2.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.mike/eh48.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.mike/p811.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/using9.C2
-rw-r--r--gcc/testsuite/g++.old-deja/g++.pt/crash3.C4
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr82337.c27
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr82381.c18
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr82389.c13
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/pr82549.c9
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20030209-1.c16
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20040709-3.c5
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20040805-1.c4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/20171008-1.c38
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/920410-1.c8
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/921113-1.c8
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/921208-2.c9
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/comp-goto-1.c4
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr20621-1.c7
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr28982b.c6
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr80421.c121
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr81423.c15
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr82387.c27
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr82388.c17
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr82524.c37
-rw-r--r--gcc/testsuite/gcc.dg/Walloca-15.c17
-rw-r--r--gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c12
-rw-r--r--gcc/testsuite/gcc.dg/Wstrict-overflow-7.c2
-rw-r--r--gcc/testsuite/gcc.dg/asan/pr82517.c43
-rw-r--r--gcc/testsuite/gcc.dg/asan/pr82545.c17
-rw-r--r--gcc/testsuite/gcc.dg/attr-alloc_size-11.c4
-rw-r--r--gcc/testsuite/gcc.dg/attr-ifunc-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/attr-ifunc-2.c4
-rw-r--r--gcc/testsuite/gcc.dg/attr-ifunc-3.c2
-rw-r--r--gcc/testsuite/gcc.dg/attr-ifunc-4.c6
-rw-r--r--gcc/testsuite/gcc.dg/attr-ifunc-5.c4
-rw-r--r--gcc/testsuite/gcc.dg/c90-const-expr-11.c2
-rw-r--r--gcc/testsuite/gcc.dg/cold-1.c22
-rw-r--r--gcc/testsuite/gcc.dg/compat/struct-layout-1_generate.c2
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/asm-line1.c2
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/discriminator.c2
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/pr53948.c2
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/sso-1.c (renamed from gcc/testsuite/gcc.dg/debug/dwarf2/sso.c)0
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/sso-2.c28
-rw-r--r--gcc/testsuite/gcc.dg/debug/dwarf2/sso-3.c31
-rw-r--r--gcc/testsuite/gcc.dg/diagnostic-range-bad-called-object.c2
-rw-r--r--gcc/testsuite/gcc.dg/gomp/pr82374.c31
-rw-r--r--gcc/testsuite/gcc.dg/graphite/graphite.exp4
-rw-r--r--gcc/testsuite/gcc.dg/graphite/id-15.c1
-rw-r--r--gcc/testsuite/gcc.dg/graphite/id-30.c16
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr35356-3.c3
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr69728.c10
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr77362.c20
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr81373-2.c40
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr81373.c40
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr82321.c36
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr82355.c23
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr82421.c21
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr82422.c13
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr82451.c21
-rw-r--r--gcc/testsuite/gcc.dg/graphite/pr82563.c24
-rw-r--r--gcc/testsuite/gcc.dg/graphite/run-id-pr67700-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-10.c2
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-24.c29
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-7.c2
-rw-r--r--gcc/testsuite/gcc.dg/graphite/scop-8.c2
-rw-r--r--gcc/testsuite/gcc.dg/ipa/inlinehint-4.c4
-rw-r--r--gcc/testsuite/gcc.dg/missing-symbol-2.c71
-rw-r--r--gcc/testsuite/gcc.dg/missing-symbol-3.c50
-rw-r--r--gcc/testsuite/gcc.dg/noncompile/940112-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/noncompile/971104-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/overflow-warn-5.c2
-rw-r--r--gcc/testsuite/gcc.dg/overflow-warn-8.c2
-rw-r--r--gcc/testsuite/gcc.dg/param-type-mismatch.c83
-rw-r--r--gcc/testsuite/gcc.dg/pr35691-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr35691-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/pr35691-3.c12
-rw-r--r--gcc/testsuite/gcc.dg/pr35691-4.c12
-rw-r--r--gcc/testsuite/gcc.dg/pr35691-5.c125
-rw-r--r--gcc/testsuite/gcc.dg/pr35691-6.c72
-rw-r--r--gcc/testsuite/gcc.dg/pr68533.c8
-rw-r--r--gcc/testsuite/gcc.dg/pr81854.c30
-rw-r--r--gcc/testsuite/gcc.dg/pr82274-1.c16
-rw-r--r--gcc/testsuite/gcc.dg/pr82274-2.c26
-rw-r--r--gcc/testsuite/gcc.dg/pr82386.c38
-rw-r--r--gcc/testsuite/gcc.dg/pr82389.c13
-rw-r--r--gcc/testsuite/gcc.dg/pr82596.c27
-rw-r--r--gcc/testsuite/gcc.dg/pragma-diag-3.c2
-rw-r--r--gcc/testsuite/gcc.dg/predict-13.c2
-rw-r--r--gcc/testsuite/gcc.dg/predict-8.c4
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-10.c41
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-2.c66
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-3.c86
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-4.c42
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-5.c79
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-6.c56
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-6a.c19
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-7.c36
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-8.c139
-rw-r--r--gcc/testsuite/gcc.dg/stack-check-9.c2022
-rw-r--r--gcc/testsuite/gcc.dg/store_merging_9.c33
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr52451.c55
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82129.c52
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82264.c21
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82276.c32
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82285.c16
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82291.c37
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82320.c39
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82473.c22
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82603.c24
-rw-r--r--gcc/testsuite/gcc.dg/torture/pr82697.c23
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/comp-goto-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/tree-prof/switch-case-2.c6
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/cmpdiv.c18
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-16.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-17.c4
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-25.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-27.c41
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-28.c16
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-29.c17
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-30.c16
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-31.c19
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-32.c29
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-33.c21
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-34.c15
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-35.c28
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-36.c28
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ldist-7.c2
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c42
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr82163.c23
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr82340.c14
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr82363.c50
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr82472.c24
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr82498.c53
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/pr82574.c19
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-1.c18
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-26.c32
-rw-r--r--gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c44
-rw-r--r--gcc/testsuite/gcc.dg/ubsan/pr82498.c159
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr31699.c6
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr60656.c3
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr61194.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr65947-10.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr65947-9.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr66142.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr66251.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr78558.c44
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr82289.c28
-rw-r--r--gcc/testsuite/gcc.dg/vect/pr82436.c35
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-10.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-11c.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-12b.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-18.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-33.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-cond-2-big-array.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-cond-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/slp-perm-9.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-align-1.c4
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-align-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-cond-10.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-cond-8.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-cond-9.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-float-extend-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-float-truncate-1.c1
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-floatint-conversion-2.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-intfloat-conversion-3.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-outer-3a-big-array.c2
-rw-r--r--gcc/testsuite/gcc.dg/vect/vect-outer-3a.c2
-rw-r--r--gcc/testsuite/gcc.target/aarch64/bic_imm_1.c56
-rw-r--r--gcc/testsuite/gcc.target/aarch64/cmpelim_mult_uses_1.c17
-rw-r--r--gcc/testsuite/gcc.target/aarch64/orr_imm_1.c54
-rw-r--r--gcc/testsuite/gcc.target/aarch64/pr71727-2.c16
-rw-r--r--gcc/testsuite/gcc.target/aarch64/pr80295.c8
-rw-r--r--gcc/testsuite/gcc.target/aarch64/pr81422.C15
-rw-r--r--gcc/testsuite/gcc.target/aarch64/var_shift_mask_2.c51
-rw-r--r--gcc/testsuite/gcc.target/aarch64/vect_copy_lane_1.c3
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/align4.c3
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/align_rec4.c1
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/neon-vect1.c5
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/neon-vect2.c1
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/neon-vect3.c1
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/neon-vect4.c3
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/neon-vect5.c1
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/neon-vect6.c1
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/neon-vect7.c1
-rw-r--r--gcc/testsuite/gcc.target/arm/aapcs/neon-vect8.c1
-rw-r--r--gcc/testsuite/gcc.target/arm/peep-ldrd-1.c2
-rw-r--r--gcc/testsuite/gcc.target/arm/peep-ldrd-2.c11
-rw-r--r--gcc/testsuite/gcc.target/arm/peep-strd-1.c2
-rw-r--r--gcc/testsuite/gcc.target/arm/peep-strd-2.c9
-rw-r--r--gcc/testsuite/gcc.target/i386/387-ficom-1.c41
-rw-r--r--gcc/testsuite/gcc.target/i386/387-ficom-2.c9
-rw-r--r--gcc/testsuite/gcc.target/i386/asm-mem.c59
-rw-r--r--gcc/testsuite/gcc.target/i386/attr-nocf-check-1a.c32
-rw-r--r--gcc/testsuite/gcc.target/i386/attr-nocf-check-3a.c32
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-1.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/avx-pr82370.c65
-rw-r--r--gcc/testsuite/gcc.target/i386/avx2-pr82370.c23
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512bw-pr82370.c33
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512bw-vpermt2w-1.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-1.c13
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-2.c66
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512dq-vreducess-1.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512dq-vreducess-2.c68
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512f-constant-float-return.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512f-constant-set.c11
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512f-pr82370.c33
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512f-prefer.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512f-vpermt2d-1.c6
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512f-vpermt2pd-1.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512f-vpermt2ps-1.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512f-vpermt2q-1.c6
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512vbmi-vpermt2b-1.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512vl-pr82370.c31
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512vl-vpermt2d-1.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512vl-vpermt2pd-1.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512vl-vpermt2ps-1.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512vl-vpermt2q-1.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/avx512vlbw-pr82370.c33
-rw-r--r--gcc/testsuite/gcc.target/i386/bt-5.c11
-rw-r--r--gcc/testsuite/gcc.target/i386/bt-6.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/bt-mask-3.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/bt-mask-4.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/builtin_target.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-intrin-10.c10
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-intrin-3.c33
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-intrin-4.c31
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-intrin-5.c10
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-intrin-6.c10
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-intrin-7.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-intrin-8.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-intrin-9.c10
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-label-2.c24
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-label.c16
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-1a.c22
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-1b.c23
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-2a.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-2b.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-3.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-4a.c6
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-4b.c6
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-5a.c16
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-5b.c21
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-6a.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-6b.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-7.c15
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-icf-1.c31
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-icf-2.c30
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-icf-3.c36
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-notrack-icf-4.c35
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-property-1.c11
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-property-2.c11
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-rdssp-1.c39
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-sjlj-1.c42
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-sjlj-2.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-sjlj-3.c46
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-sjlj-4.c45
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-sjlj-5.c48
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-switch-1.c26
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-switch-2.c26
-rw-r--r--gcc/testsuite/gcc.target/i386/cet-switch-3.c34
-rw-r--r--gcc/testsuite/gcc.target/i386/funcspec-56.inc1
-rw-r--r--gcc/testsuite/gcc.target/i386/pr79683.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr80732.c2
-rw-r--r--gcc/testsuite/gcc.target/i386/pr81481.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82196-1.c5
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82196-2.c5
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82260-1.c26
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82260-2.c25
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82267.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82361-1.c53
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82361-2.c10
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82370.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82460-1.c30
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82460-2.c17
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82483-1.c44
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82483-2.c9
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82498-1.c52
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82498-2.c46
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82499-1.c21
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82499-2.c21
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82499-3.c21
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82556.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82580.c39
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82618.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82628.c34
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82659-1.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82659-2.c17
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82659-3.c20
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82659-4.c14
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82659-5.c10
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82659-6.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82662.c26
-rw-r--r--gcc/testsuite/gcc.target/i386/pr82673.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/sse-13.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/sse-23.c4
-rw-r--r--gcc/testsuite/gcc.target/i386/stack-check-11.c18
-rw-r--r--gcc/testsuite/gcc.target/i386/vect-pack-trunc-2.c2
-rw-r--r--gcc/testsuite/gcc.target/nios2/cdx-branch.c4
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-bypass.c40
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-char.c60
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-int.c40
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-pic.c38
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-short.c51
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-tls.c38
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-uchar.c58
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-ushort.c49
-rw-r--r--gcc/testsuite/gcc.target/nios2/lo-addr-volatile.c41
-rw-r--r--gcc/testsuite/gcc.target/powerpc/amo1.c253
-rw-r--r--gcc/testsuite/gcc.target/powerpc/amo2.c121
-rw-r--r--gcc/testsuite/gcc.target/powerpc/builtin-fctid-fctiw-runnable.c137
-rw-r--r--gcc/testsuite/gcc.target/powerpc/builtins-5-p9-runnable.c309
-rw-r--r--gcc/testsuite/gcc.target/powerpc/direct-move-float1.c8
-rw-r--r--gcc/testsuite/gcc.target/powerpc/direct-move-float3.c30
-rw-r--r--gcc/testsuite/gcc.target/powerpc/float128-fma1.c32
-rw-r--r--gcc/testsuite/gcc.target/powerpc/float128-fma2.c9
-rw-r--r--gcc/testsuite/gcc.target/powerpc/float128-odd.c75
-rw-r--r--gcc/testsuite/gcc.target/powerpc/float128-sqrt1.c11
-rw-r--r--gcc/testsuite/gcc.target/powerpc/float128-sqrt2.c9
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-char.c86
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-double.c51
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-float.c51
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-int.c86
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-longlong.c86
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-short.c87
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p8.c7
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p9.c7
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-splat-16.c46
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-splat-32.c46
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-splat-8.c46
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-splats-char.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-splats-floatdouble.c27
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-splats-int.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-splats-longlong.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-splats-short.c23
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-st-char.c94
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-st-double.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-st-float.c34
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-st-int.c84
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-st-longlong.c41
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-st-pixel.c22
-rw-r--r--gcc/testsuite/gcc.target/powerpc/fold-vec-st-short.c83
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr71977-1.c12
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr77687.c20
-rw-r--r--gcc/testsuite/gcc.target/powerpc/pr80210-2.c11
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-28.c29
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-29.c29
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-30.c31
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-31.c27
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-32.c27
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-33.c29
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-34.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-35.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-36.c28
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-37.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-38.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-39.c28
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-40.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-41.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-42.c28
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-43.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-44.c26
-rw-r--r--gcc/testsuite/gcc.target/powerpc/swaps-p8-45.c28
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/pr82317.c19
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/pr82322.c22
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/pr82463.c14
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/pr82465.c16
-rw-r--r--gcc/testsuite/gcc.target/s390/zvector/vec-cmp-2.c98
-rw-r--r--gcc/testsuite/gfortran.dg/argument_checking_10.f902
-rw-r--r--gcc/testsuite/gfortran.dg/argument_checking_13.f9016
-rw-r--r--gcc/testsuite/gfortran.dg/argument_checking_15.f9014
-rw-r--r--gcc/testsuite/gfortran.dg/argument_checking_18.f904
-rw-r--r--gcc/testsuite/gfortran.dg/argument_checking_3.f908
-rw-r--r--gcc/testsuite/gfortran.dg/argument_checking_4.f908
-rw-r--r--gcc/testsuite/gfortran.dg/argument_checking_5.f9020
-rw-r--r--gcc/testsuite/gfortran.dg/argument_checking_6.f902
-rw-r--r--gcc/testsuite/gfortran.dg/array_constructor_51.f9020
-rw-r--r--gcc/testsuite/gfortran.dg/associate_26.f9015
-rw-r--r--gcc/testsuite/gfortran.dg/associate_27.f9023
-rw-r--r--gcc/testsuite/gfortran.dg/associate_28.f9064
-rw-r--r--gcc/testsuite/gfortran.dg/associate_29.f9030
-rw-r--r--gcc/testsuite/gfortran.dg/associate_30.f9015
-rw-r--r--gcc/testsuite/gfortran.dg/associate_32.f0393
-rw-r--r--gcc/testsuite/gfortran.dg/assumed_size_2.f904
-rw-r--r--gcc/testsuite/gfortran.dg/binding_label_tests_28.f9012
-rw-r--r--gcc/testsuite/gfortran.dg/contiguous_4.f9019
-rw-r--r--gcc/testsuite/gfortran.dg/data_derived_1.f9013
-rw-r--r--gcc/testsuite/gfortran.dg/dec_structure_22.f9038
-rw-r--r--gcc/testsuite/gfortran.dg/derived_init_4.f9060
-rw-r--r--gcc/testsuite/gfortran.dg/do_subscript_1.f9057
-rw-r--r--gcc/testsuite/gfortran.dg/do_subscript_2.f9023
-rw-r--r--gcc/testsuite/gfortran.dg/execute_command_line_3.f9023
-rw-r--r--gcc/testsuite/gfortran.dg/goacc/wait.f9012
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/pr82568.f9075
-rw-r--r--gcc/testsuite/gfortran.dg/gomp/udr8.f908
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/id-27.f9040
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/id-28.f9015
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/interchange-3.f902
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/pr29581.f903
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/pr29832.f904
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/pr42326-1.f901
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/pr42326.f901
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/pr71351.f9015
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/pr82449.f11
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/pr82451.f39
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/pr82672.f9033
-rw-r--r--gcc/testsuite/gfortran.dg/graphite/run-id-3.f903
-rw-r--r--gcc/testsuite/gfortran.dg/illegal_char.f906
-rw-r--r--gcc/testsuite/gfortran.dg/intrinsic_bounds_1.f907
-rw-r--r--gcc/testsuite/gfortran.dg/intrinsic_param_1.f906
-rw-r--r--gcc/testsuite/gfortran.dg/pdt_13.f0392
-rw-r--r--gcc/testsuite/gfortran.dg/pdt_14.f0390
-rw-r--r--gcc/testsuite/gfortran.dg/pdt_15.f03106
-rw-r--r--gcc/testsuite/gfortran.dg/pdt_16.f0321
-rw-r--r--gcc/testsuite/gfortran.dg/pdt_17.f0311
-rw-r--r--gcc/testsuite/gfortran.dg/pdt_18.f0319
-rw-r--r--gcc/testsuite/gfortran.dg/pdt_4.f032
-rw-r--r--gcc/testsuite/gfortran.dg/pdt_8.f035
-rw-r--r--gcc/testsuite/gfortran.dg/pr82397.f32
-rw-r--r--gcc/testsuite/gfortran.dg/predcom-1.f2
-rw-r--r--gcc/testsuite/gfortran.dg/promotion_3.f9017
-rw-r--r--gcc/testsuite/gfortran.dg/promotion_4.f9017
-rw-r--r--gcc/testsuite/gfortran.dg/spellcheck-operator.f9030
-rw-r--r--gcc/testsuite/gfortran.dg/spellcheck-parameter.f9015
-rw-r--r--gcc/testsuite/gfortran.dg/spellcheck-procedure_1.f9041
-rw-r--r--gcc/testsuite/gfortran.dg/spellcheck-procedure_2.f9035
-rw-r--r--gcc/testsuite/gfortran.dg/spellcheck-structure.f9035
-rw-r--r--gcc/testsuite/gfortran.dg/submodule_30.f0842
-rw-r--r--gcc/testsuite/gfortran.dg/typebound_proc_36.f9077
-rw-r--r--gcc/testsuite/gfortran.dg/unconstrained_commons.f4
-rw-r--r--gcc/testsuite/gfortran.dg/vect/fast-math-mgrid-resid.f1
-rw-r--r--gcc/testsuite/gfortran.dg/vect/pr60510.f1
-rw-r--r--gcc/testsuite/gfortran.dg/vect/pr77848.f1
-rw-r--r--gcc/testsuite/gfortran.dg/vect/vect-8.f903
-rw-r--r--gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f902
-rw-r--r--gcc/testsuite/gfortran.dg/zero_sized_7.f9018
-rw-r--r--gcc/testsuite/gnat.dg/class_wide3.adb8
-rw-r--r--gcc/testsuite/gnat.dg/class_wide3_pkg.ads16
-rw-r--r--gcc/testsuite/gnat.dg/class_wide4.adb20
-rw-r--r--gcc/testsuite/gnat.dg/class_wide4_pkg.ads21
-rw-r--r--gcc/testsuite/gnat.dg/class_wide4_pkg2.ads30
-rw-r--r--gcc/testsuite/gnat.dg/default_pkg_actual.adb32
-rw-r--r--gcc/testsuite/gnat.dg/default_pkg_actual2.adb27
-rw-r--r--gcc/testsuite/gnat.dg/dimensions.adb5
-rw-r--r--gcc/testsuite/gnat.dg/dimensions.ads29
-rw-r--r--gcc/testsuite/gnat.dg/discr48.adb9
-rw-r--r--gcc/testsuite/gnat.dg/discr48_pkg.ads19
-rw-r--r--gcc/testsuite/gnat.dg/entry_family.adb28
-rw-r--r--gcc/testsuite/gnat.dg/remote_call_iface.adb7
-rw-r--r--gcc/testsuite/gnat.dg/remote_call_iface.ads5
-rw-r--r--gcc/testsuite/gnat.dg/specs/discr2.ads (renamed from gcc/testsuite/gnat.dg/specs/discr_private.ads)4
-rw-r--r--gcc/testsuite/gnat.dg/specs/discr3.ads (renamed from gcc/testsuite/gnat.dg/specs/discr_record_constant.ads)4
-rw-r--r--gcc/testsuite/gnat.dg/specs/discr4.ads23
-rw-r--r--gcc/testsuite/gnat.dg/specs/discr4_pkg.ads27
-rw-r--r--gcc/testsuite/gnat.dg/stack_usage4.adb11
-rw-r--r--gcc/testsuite/gnat.dg/stack_usage4_pkg.ads12
-rw-r--r--gcc/testsuite/gnat.dg/sync_iface_call.adb34
-rw-r--r--gcc/testsuite/gnat.dg/sync_iface_call_pkg.ads21
-rw-r--r--gcc/testsuite/gnat.dg/sync_iface_call_pkg2.adb8
-rw-r--r--gcc/testsuite/gnat.dg/sync_iface_call_pkg2.ads7
-rw-r--r--gcc/testsuite/gnat.dg/unchecked_union2.adb35
-rw-r--r--gcc/testsuite/gnat.dg/unchecked_union3.adb38
-rw-r--r--gcc/testsuite/gnat.dg/validity_check2.adb11
-rw-r--r--gcc/testsuite/gnat.dg/validity_check2_pkg.ads16
-rw-r--r--gcc/testsuite/jit.dg/all-non-failing-tests.h10
-rw-r--r--gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c92
-rw-r--r--gcc/testsuite/jit.dg/test-expressions.c30
-rw-r--r--gcc/testsuite/jit.dg/test-returning-function-ptr.c162
-rw-r--r--gcc/testsuite/jit.dg/test-vector-rvalues.cc211
-rw-r--r--gcc/testsuite/lib/scanasm.exp18
-rw-r--r--gcc/testsuite/lib/scandump.exp6
-rw-r--r--gcc/testsuite/lib/target-supports-dg.exp15
-rw-r--r--gcc/testsuite/lib/target-supports.exp385
-rw-r--r--gcc/testsuite/obj-c++.dg/exceptions-6.mm6
-rw-r--r--gcc/testsuite/obj-c++.dg/pr48187.mm8
-rw-r--r--gcc/testsuite/objc.dg/exceptions-6.m4
-rw-r--r--gcc/toplev.c100
-rw-r--r--gcc/toplev.h2
-rw-r--r--gcc/tracer.c6
-rw-r--r--gcc/trans-mem.c19
-rw-r--r--gcc/tree-affine.c4
-rw-r--r--gcc/tree-call-cdce.c6
-rw-r--r--gcc/tree-cfg.c52
-rw-r--r--gcc/tree-cfgcleanup.c7
-rw-r--r--gcc/tree-chkp.c3
-rw-r--r--gcc/tree-chrec.c6
-rw-r--r--gcc/tree-chrec.h17
-rw-r--r--gcc/tree-complex.c2
-rw-r--r--gcc/tree-core.h5
-rw-r--r--gcc/tree-data-ref.c120
-rw-r--r--gcc/tree-data-ref.h4
-rw-r--r--gcc/tree-dfa.c17
-rw-r--r--gcc/tree-dump.c2
-rw-r--r--gcc/tree-eh.c3
-rw-r--r--gcc/tree-if-conv.c191
-rw-r--r--gcc/tree-inline.c90
-rw-r--r--gcc/tree-into-ssa.c2
-rw-r--r--gcc/tree-loop-distribution.c952
-rw-r--r--gcc/tree-object-size.c3
-rw-r--r--gcc/tree-outof-ssa.c2
-rw-r--r--gcc/tree-outof-ssa.h4
-rw-r--r--gcc/tree-pass.h1
-rw-r--r--gcc/tree-predcom.c3
-rw-r--r--gcc/tree-pretty-print.c11
-rw-r--r--gcc/tree-scalar-evolution.c410
-rw-r--r--gcc/tree-scalar-evolution.h4
-rw-r--r--gcc/tree-sra.c44
-rw-r--r--gcc/tree-ssa-address.c4
-rw-r--r--gcc/tree-ssa-alias.c6
-rw-r--r--gcc/tree-ssa-ccp.c51
-rw-r--r--gcc/tree-ssa-coalesce.c28
-rw-r--r--gcc/tree-ssa-coalesce.h1
-rw-r--r--gcc/tree-ssa-dce.c16
-rw-r--r--gcc/tree-ssa-dom.c153
-rw-r--r--gcc/tree-ssa-dse.c56
-rw-r--r--gcc/tree-ssa-forwprop.c81
-rw-r--r--gcc/tree-ssa-ifcombine.c3
-rw-r--r--gcc/tree-ssa-loop-im.c6
-rw-r--r--gcc/tree-ssa-loop-ivcanon.c2
-rw-r--r--gcc/tree-ssa-loop-ivopts.c11
-rw-r--r--gcc/tree-ssa-loop-ivopts.h1
-rw-r--r--gcc/tree-ssa-loop-manip.c96
-rw-r--r--gcc/tree-ssa-loop-manip.h6
-rw-r--r--gcc/tree-ssa-loop-niter.c47
-rw-r--r--gcc/tree-ssa-loop-prefetch.c3
-rw-r--r--gcc/tree-ssa-loop-split.c6
-rw-r--r--gcc/tree-ssa-loop-unswitch.c16
-rw-r--r--gcc/tree-ssa-math-opts.c2
-rw-r--r--gcc/tree-ssa-phionlycprop.c1
-rw-r--r--gcc/tree-ssa-phiopt.c146
-rw-r--r--gcc/tree-ssa-pre.c236
-rw-r--r--gcc/tree-ssa-reassoc.c218
-rw-r--r--gcc/tree-ssa-sccvn.c34
-rw-r--r--gcc/tree-ssa-structalias.c50
-rw-r--r--gcc/tree-ssa-tail-merge.c15
-rw-r--r--gcc/tree-ssa-threadupdate.c245
-rw-r--r--gcc/tree-ssa-uninit.c4
-rw-r--r--gcc/tree-ssanames.c6
-rw-r--r--gcc/tree-switch-conversion.c29
-rw-r--r--gcc/tree-tailcall.c9
-rw-r--r--gcc/tree-vect-data-refs.c151
-rw-r--r--gcc/tree-vect-loop-manip.c71
-rw-r--r--gcc/tree-vect-loop.c14
-rw-r--r--gcc/tree-vect-patterns.c4
-rw-r--r--gcc/tree-vect-slp.c18
-rw-r--r--gcc/tree-vect-stmts.c110
-rw-r--r--gcc/tree-vectorizer.h36
-rw-r--r--gcc/tree-vrp.c271
-rw-r--r--gcc/tree.c214
-rw-r--r--gcc/tree.def4
-rw-r--r--gcc/tree.h221
-rw-r--r--gcc/ubsan.c113
-rw-r--r--gcc/unique-ptr-tests.cc234
-rw-r--r--gcc/value-prof.c28
-rw-r--r--gcc/varasm.c19
-rw-r--r--gcc/vec.c93
-rw-r--r--gcc/wide-int.cc33
-rw-r--r--gcc/wide-int.h156
-rw-r--r--include/ChangeLog10
-rw-r--r--include/unique-ptr.h405
-rw-r--r--libatomic/ChangeLog15
-rw-r--r--libatomic/Makefile.am2
-rw-r--r--libatomic/Makefile.in2
-rw-r--r--libatomic/acinclude.m43
-rwxr-xr-xlibatomic/configure8
-rw-r--r--libatomic/libatomic_i.h6
-rw-r--r--libbacktrace/ChangeLog138
-rw-r--r--libbacktrace/Makefile.am37
-rw-r--r--libbacktrace/Makefile.in108
-rw-r--r--libbacktrace/config.h.in15
-rwxr-xr-xlibbacktrace/configure265
-rw-r--r--libbacktrace/configure.ac47
-rw-r--r--libbacktrace/elf.c2250
-rw-r--r--libbacktrace/fileline.c6
-rw-r--r--libbacktrace/internal.h10
-rw-r--r--libbacktrace/pecoff.c3
-rw-r--r--libbacktrace/unknown.c1
-rw-r--r--libbacktrace/xcoff.c147
-rw-r--r--libbacktrace/ztest.c474
-rw-r--r--libcc1/ChangeLog5
-rw-r--r--libcc1/libcp1plugin.cc6
-rw-r--r--libcpp/ChangeLog5
-rw-r--r--libcpp/macro.c14
-rw-r--r--libffi/ChangeLog17
-rw-r--r--libffi/src/powerpc/aix.S240
-rw-r--r--libffi/src/powerpc/aix_closure.S253
-rw-r--r--libffi/src/powerpc/ffi_darwin.c91
-rw-r--r--libffi/src/powerpc/ffitarget.h3
-rw-r--r--libgcc/ChangeLog85
-rw-r--r--libgcc/config.in3
-rw-r--r--libgcc/config/ft32/crti-hw.S28
-rw-r--r--libgcc/config/i386/cpuinfo.c4
-rw-r--r--libgcc/config/i386/cpuinfo.h1
-rw-r--r--libgcc/config/i386/i386-asm.h46
-rw-r--r--libgcc/config/microblaze/crti.S6
-rw-r--r--libgcc/config/microblaze/crtn.S6
-rw-r--r--libgcc/config/microblaze/divsi3.S6
-rw-r--r--libgcc/config/microblaze/moddi3.S6
-rw-r--r--libgcc/config/microblaze/modsi3.S6
-rw-r--r--libgcc/config/microblaze/muldi3_hard.S6
-rw-r--r--libgcc/config/microblaze/mulsi3.S6
-rw-r--r--libgcc/config/microblaze/stack_overflow_exit.S6
-rw-r--r--libgcc/config/microblaze/udivsi3.S6
-rw-r--r--libgcc/config/microblaze/umodsi3.S6
-rw-r--r--libgcc/config/pa/milli64.S6
-rw-r--r--libgcc/config/rl78/adddi3.S58
-rw-r--r--libgcc/config/rl78/subdi3.S58
-rw-r--r--libgcc/config/rl78/t-rl784
-rw-r--r--libgcc/configure39
-rw-r--r--libgcc/configure.ac16
-rw-r--r--libgcc/libgcc2.c3
-rw-r--r--libgfortran/ChangeLog11
-rw-r--r--libgfortran/intrinsics/execute_command_line.c10
-rw-r--r--libgfortran/runtime/bounds.c5
-rw-r--r--libgo/Makefile.am20
-rw-r--r--libgo/Makefile.in18
-rw-r--r--libgo/go/cmd/cgo/gcc.go79
-rw-r--r--libgo/go/cmd/cgo/out.go21
-rw-r--r--libgo/go/cmd/go/internal/base/signal_unix.go2
-rw-r--r--libgo/go/cmd/go/internal/work/build.go18
-rw-r--r--libgo/go/debug/dwarf/entry.go4
-rw-r--r--libgo/go/debug/dwarf/entry_test.go60
-rw-r--r--libgo/go/debug/dwarf/open.go19
-rw-r--r--libgo/go/debug/dwarf/typeunit.go11
-rw-r--r--libgo/go/debug/dwarf/unit.go11
-rw-r--r--libgo/go/debug/elf/file.go42
-rw-r--r--libgo/go/debug/xcoff/file.go539
-rw-r--r--libgo/go/debug/xcoff/file_test.go150
-rw-r--r--libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-execbin0 -> 54694 bytes
-rw-r--r--libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-execbin0 -> 63312 bytes
-rw-r--r--libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-execbin0 -> 57152 bytes
-rw-r--r--libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-execbin0 -> 66618 bytes
-rw-r--r--libgo/go/debug/xcoff/testdata/hello.c7
-rw-r--r--libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-execbin0 -> 6529 bytes
-rw-r--r--libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-execbin0 -> 6112 bytes
-rw-r--r--libgo/go/debug/xcoff/xcoff.go262
-rw-r--r--libgo/go/go/build/deps_test.go3
-rw-r--r--libgo/go/go/internal/gccgoimporter/importer.go42
-rw-r--r--libgo/go/internal/poll/export_posix_test.go2
-rw-r--r--libgo/go/internal/poll/fd_poll_runtime.go2
-rw-r--r--libgo/go/internal/poll/fd_posix.go2
-rw-r--r--libgo/go/internal/poll/fd_posix_test.go2
-rw-r--r--libgo/go/internal/poll/fd_unix.go2
-rw-r--r--libgo/go/internal/poll/hook_unix.go2
-rw-r--r--libgo/go/internal/poll/sockopt.go2
-rw-r--r--libgo/go/internal/poll/sockoptip.go2
-rw-r--r--libgo/go/internal/poll/sys_cloexec.go2
-rw-r--r--libgo/go/net/error_posix.go2
-rw-r--r--libgo/go/net/sock_posix.go10
-rw-r--r--libgo/go/os/user/cgo_lookup_unix.go2
-rw-r--r--libgo/go/runtime/export_unix_test.go2
-rw-r--r--libgo/go/runtime/netpoll_aix.go15
-rw-r--r--libgo/go/syscall/dirent.go2
-rw-r--r--libgo/go/syscall/forkpipe_bsd.go2
-rw-r--r--libgo/go/syscall/libcall_aix.go130
-rw-r--r--libgo/go/syscall/socket_aix.go89
-rw-r--r--libgo/go/syscall/socket_bsd.go2
-rw-r--r--libgo/go/syscall/syscall_aix.go19
-rw-r--r--libgo/go/syscall/syscall_aix_ppc.go49
-rw-r--r--libgo/go/syscall/syscall_aix_ppc64.go49
-rwxr-xr-xlibgo/mkrsysinfo.sh1
-rwxr-xr-xlibgo/mksysinfo.sh2
-rw-r--r--libgo/runtime/go-caller.c2
-rw-r--r--libgo/runtime/proc.c2
-rw-r--r--libgomp/ChangeLog92
-rw-r--r--libgomp/testsuite/libgomp.c++/for-12.C2
-rw-r--r--libgomp/testsuite/libgomp.c++/pr69393.C2
-rw-r--r--libgomp/testsuite/libgomp.c++/taskloop-1.C2
-rw-r--r--libgomp/testsuite/libgomp.c++/taskloop-3.C2
-rw-r--r--libgomp/testsuite/libgomp.c++/taskloop-4.C2
-rw-r--r--libgomp/testsuite/libgomp.c/for-4.c2
-rw-r--r--libgomp/testsuite/libgomp.c/pr66199-3.c2
-rw-r--r--libgomp/testsuite/libgomp.c/pr66199-4.c2
-rw-r--r--libgomp/testsuite/libgomp.c/pr66199-6.c2
-rw-r--r--libgomp/testsuite/libgomp.c/taskloop-1.c2
-rw-r--r--libgomp/testsuite/libgomp.c/taskloop-3.c2
-rw-r--r--libgomp/testsuite/libgomp.c/taskloop-4.c2
-rw-r--r--libgomp/testsuite/libgomp.fortran/aligned1.f032
-rw-r--r--libgomp/testsuite/libgomp.fortran/condinc1.f1
-rw-r--r--libgomp/testsuite/libgomp.fortran/condinc3.f901
-rw-r--r--libgomp/testsuite/libgomp.fortran/crayptr1.f902
-rw-r--r--libgomp/testsuite/libgomp.fortran/crayptr2.f902
-rw-r--r--libgomp/testsuite/libgomp.fortran/crayptr3.f902
-rw-r--r--libgomp/testsuite/libgomp.fortran/omp_cond1.f1
-rw-r--r--libgomp/testsuite/libgomp.fortran/omp_cond3.F901
-rw-r--r--libgomp/testsuite/libgomp.fortran/pr66199-1.f902
-rw-r--r--libgomp/testsuite/libgomp.fortran/pr66199-2.f902
-rw-r--r--libgomp/testsuite/libgomp.fortran/recursion1.f902
-rw-r--r--libgomp/testsuite/libgomp.fortran/target2.f902
-rw-r--r--libgomp/testsuite/libgomp.fortran/target5.f901
-rw-r--r--libgomp/testsuite/libgomp.fortran/task3.f901
-rw-r--r--libgomp/testsuite/libgomp.hsa.c/pr82416.c37
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/declare-1.c2
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/declare-2.c2
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/declare-4.c2
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/declare-5.c2
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-1.c2
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-2.c2
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/loop-red-g-1.c2
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-3.c3
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-4.c5
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/parallel-reduction.c4
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/reduction-7.c5
-rw-r--r--libgomp/testsuite/libgomp.oacc-c-c++-common/routine-g-1.c2
-rw-r--r--libgomp/testsuite/libgomp.oacc-fortran/declare-1.f903
-rw-r--r--libgomp/testsuite/libgomp.oacc-fortran/declare-2.f902
-rw-r--r--libgomp/testsuite/libgomp.oacc-fortran/declare-3.f903
-rw-r--r--libgomp/testsuite/libgomp.oacc-fortran/declare-4.f902
-rw-r--r--libgomp/testsuite/libgomp.oacc-fortran/declare-5.f902
-rw-r--r--libgomp/testsuite/libgomp.oacc-fortran/firstprivate-1.f902
-rw-r--r--libgomp/testsuite/libgomp.oacc-fortran/parallel-reduction.f904
-rw-r--r--libhsail-rt/ChangeLog12
-rw-r--r--libhsail-rt/include/internal/phsa-rt.h3
-rw-r--r--libhsail-rt/include/internal/workitems.h5
-rw-r--r--libhsail-rt/rt/workitems.c50
-rw-r--r--libiberty/ChangeLog44
-rw-r--r--libiberty/cp-demangle.c148
-rw-r--r--libiberty/simple-object-elf.c44
-rw-r--r--libiberty/simple-object.c3
-rw-r--r--libiberty/testsuite/demangle-expected54
-rw-r--r--libsanitizer/ChangeLog46
-rw-r--r--libsanitizer/MERGE2
-rw-r--r--libsanitizer/Makefile.am3
-rw-r--r--libsanitizer/Makefile.in3
-rw-r--r--libsanitizer/asan/Makefile.am2
-rw-r--r--libsanitizer/asan/Makefile.in17
-rw-r--r--libsanitizer/asan/asan_activation.cc19
-rw-r--r--libsanitizer/asan/asan_activation_flags.inc2
-rw-r--r--libsanitizer/asan/asan_allocator.cc193
-rw-r--r--libsanitizer/asan/asan_allocator.h56
-rw-r--r--libsanitizer/asan/asan_descriptions.cc21
-rw-r--r--libsanitizer/asan/asan_descriptions.h6
-rw-r--r--libsanitizer/asan/asan_errors.cc138
-rw-r--r--libsanitizer/asan/asan_errors.h84
-rw-r--r--libsanitizer/asan/asan_fake_stack.cc4
-rw-r--r--libsanitizer/asan/asan_flags.cc48
-rw-r--r--libsanitizer/asan/asan_flags.inc25
-rw-r--r--libsanitizer/asan/asan_fuchsia.cc216
-rw-r--r--libsanitizer/asan/asan_globals.cc46
-rw-r--r--libsanitizer/asan/asan_globals_win.cc60
-rw-r--r--libsanitizer/asan/asan_interceptors.cc292
-rw-r--r--libsanitizer/asan/asan_interceptors.h49
-rw-r--r--libsanitizer/asan/asan_interceptors_memintrinsics.cc42
-rw-r--r--libsanitizer/asan/asan_interceptors_memintrinsics.h146
-rw-r--r--libsanitizer/asan/asan_interface.inc167
-rw-r--r--libsanitizer/asan/asan_interface_internal.h12
-rw-r--r--libsanitizer/asan/asan_internal.h27
-rw-r--r--libsanitizer/asan/asan_linux.cc31
-rw-r--r--libsanitizer/asan/asan_mac.cc36
-rw-r--r--libsanitizer/asan/asan_malloc_linux.cc72
-rw-r--r--libsanitizer/asan/asan_malloc_win.cc7
-rw-r--r--libsanitizer/asan/asan_mapping.h16
-rw-r--r--libsanitizer/asan/asan_memory_profile.cc92
-rw-r--r--libsanitizer/asan/asan_new_delete.cc73
-rw-r--r--libsanitizer/asan/asan_poisoning.cc11
-rw-r--r--libsanitizer/asan/asan_poisoning.h11
-rw-r--r--libsanitizer/asan/asan_posix.cc68
-rw-r--r--libsanitizer/asan/asan_report.cc130
-rw-r--r--libsanitizer/asan/asan_report.h4
-rw-r--r--libsanitizer/asan/asan_rtl.cc153
-rw-r--r--libsanitizer/asan/asan_scariness_score.h2
-rw-r--r--libsanitizer/asan/asan_shadow_setup.cc159
-rw-r--r--libsanitizer/asan/asan_stack.h4
-rw-r--r--libsanitizer/asan/asan_suppressions.cc12
-rw-r--r--libsanitizer/asan/asan_thread.cc60
-rw-r--r--libsanitizer/asan/asan_thread.h34
-rw-r--r--libsanitizer/asan/asan_win.cc151
-rw-r--r--libsanitizer/asan/asan_win_dll_thunk.cc473
-rw-r--r--libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc44
-rw-r--r--libsanitizer/asan/asan_win_weak_interception.cc21
-rw-r--r--libsanitizer/asan/libtool-version2
-rw-r--r--libsanitizer/builtins/assembly.h57
-rw-r--r--libsanitizer/configure.tgt2
-rw-r--r--libsanitizer/include/sanitizer/asan_interface.h4
-rw-r--r--libsanitizer/include/sanitizer/common_interface_defs.h11
-rw-r--r--libsanitizer/include/sanitizer/coverage_interface.h40
-rw-r--r--libsanitizer/include/sanitizer/lsan_interface.h6
-rw-r--r--libsanitizer/include/sanitizer/tsan_interface.h136
-rw-r--r--libsanitizer/interception/interception.h41
-rw-r--r--libsanitizer/interception/interception_linux.cc13
-rw-r--r--libsanitizer/interception/interception_linux.h4
-rw-r--r--libsanitizer/interception/interception_win.cc24
-rw-r--r--libsanitizer/libbacktrace/backtrace-rename.h1
-rw-r--r--libsanitizer/lsan/Makefile.am11
-rw-r--r--libsanitizer/lsan/Makefile.in77
-rw-r--r--libsanitizer/lsan/lsan.cc17
-rw-r--r--libsanitizer/lsan/lsan.h51
-rw-r--r--libsanitizer/lsan/lsan_allocator.cc109
-rw-r--r--libsanitizer/lsan/lsan_allocator.h57
-rw-r--r--libsanitizer/lsan/lsan_common.cc253
-rw-r--r--libsanitizer/lsan/lsan_common.h83
-rw-r--r--libsanitizer/lsan/lsan_common_linux.cc104
-rw-r--r--libsanitizer/lsan/lsan_common_mac.cc197
-rw-r--r--libsanitizer/lsan/lsan_interceptors.cc236
-rw-r--r--libsanitizer/lsan/lsan_linux.cc31
-rw-r--r--libsanitizer/lsan/lsan_mac.cc190
-rw-r--r--libsanitizer/lsan/lsan_malloc_mac.cc53
-rw-r--r--libsanitizer/lsan/lsan_thread.cc21
-rw-r--r--libsanitizer/lsan/lsan_thread.h2
-rw-r--r--libsanitizer/sanitizer_common/Makefile.am9
-rw-r--r--libsanitizer/sanitizer_common/Makefile.in37
-rw-r--r--libsanitizer/sanitizer_common/sancov_flags.cc57
-rw-r--r--libsanitizer/sanitizer_common/sancov_flags.h38
-rw-r--r--libsanitizer/sanitizer_common/sancov_flags.inc19
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_addrhashmap.h12
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator.cc59
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator.h29
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_checks.cc21
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_checks.h73
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_combined.h77
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_interface.h9
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_internal.h25
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h145
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h78
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h582
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h69
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h30
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_atomic.h5
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_atomic_clang.h21
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h64
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common.cc188
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common.h332
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc624
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc19
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interface.inc37
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_interface_posix.inc12
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc199
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_common_nolibc.cc34
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cc238
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc31
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc1043
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cc218
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc120
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cc19
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cc19
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_win_sections.cc20
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cc22
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_dbghelp.h40
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_errno.cc33
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_errno.h35
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_errno_codes.h32
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_file.cc175
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_file.h108
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_flag_parser.h31
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_flags.h6
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_flags.inc69
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_fuchsia.cc517
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_fuchsia.h29
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_interface_internal.h50
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_internal_defs.h99
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libignore.cc65
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_libignore.h45
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux.cc563
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux.h63
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc117
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_linux_s390.cc7
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_list.h11
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mac.cc261
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mac.h13
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mac_libcdep.cc28
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc39
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_mutex.h8
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform.h38
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h346
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cc357
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h566
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc20
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h62
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_posix.cc209
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_posix.h4
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc68
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_printf.cc75
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps.h93
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc61
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps_freebsd.cc77
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc87
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc304
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_quarantine.h183
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_report_decorator.h5
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_signal_interceptors.inc65
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stackdepot.cc6
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace.cc17
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace.h9
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc25
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc24
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h3
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stoptheworld.h38
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc101
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cc176
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_suppressions.cc3
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer.cc8
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer.h12
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_fuchsia.cc105
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h5
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc3
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc181
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc125
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc40
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc30
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_thread_registry.cc42
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_thread_registry.h9
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc26
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h2
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc9
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win.cc238
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win.h24
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win_defs.h151
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cc100
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h180
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cc19
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cc92
-rw-r--r--libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h31
-rw-r--r--libsanitizer/tsan/Makefile.am1
-rw-r--r--libsanitizer/tsan/Makefile.in27
-rw-r--r--libsanitizer/tsan/tsan_clock.cc501
-rw-r--r--libsanitizer/tsan/tsan_clock.h213
-rw-r--r--libsanitizer/tsan/tsan_debugging.cc90
-rw-r--r--libsanitizer/tsan/tsan_defs.h45
-rw-r--r--libsanitizer/tsan/tsan_dense_alloc.h11
-rw-r--r--libsanitizer/tsan/tsan_external.cc123
-rw-r--r--libsanitizer/tsan/tsan_fd.cc6
-rw-r--r--libsanitizer/tsan/tsan_flags.cc4
-rw-r--r--libsanitizer/tsan/tsan_flags.h1
-rw-r--r--libsanitizer/tsan/tsan_flags.inc3
-rw-r--r--libsanitizer/tsan/tsan_interceptors.cc235
-rw-r--r--libsanitizer/tsan/tsan_interceptors.h11
-rw-r--r--libsanitizer/tsan/tsan_interceptors_mac.cc35
-rw-r--r--libsanitizer/tsan/tsan_interface.cc4
-rw-r--r--libsanitizer/tsan/tsan_interface.h34
-rw-r--r--libsanitizer/tsan/tsan_interface_ann.cc112
-rw-r--r--libsanitizer/tsan/tsan_interface_atomic.cc30
-rw-r--r--libsanitizer/tsan/tsan_interface_inl.h8
-rw-r--r--libsanitizer/tsan/tsan_interface_java.cc31
-rw-r--r--libsanitizer/tsan/tsan_interface_java.h4
-rw-r--r--libsanitizer/tsan/tsan_libdispatch_mac.cc88
-rw-r--r--libsanitizer/tsan/tsan_malloc_mac.cc4
-rw-r--r--libsanitizer/tsan/tsan_mman.cc102
-rw-r--r--libsanitizer/tsan/tsan_mman.h15
-rw-r--r--libsanitizer/tsan/tsan_new_delete.cc13
-rw-r--r--libsanitizer/tsan/tsan_platform.h50
-rw-r--r--libsanitizer/tsan/tsan_platform_linux.cc57
-rw-r--r--libsanitizer/tsan/tsan_platform_mac.cc125
-rw-r--r--libsanitizer/tsan/tsan_platform_posix.cc27
-rw-r--r--libsanitizer/tsan/tsan_platform_windows.cc4
-rw-r--r--libsanitizer/tsan/tsan_report.cc87
-rw-r--r--libsanitizer/tsan/tsan_report.h9
-rw-r--r--libsanitizer/tsan/tsan_rtl.cc39
-rw-r--r--libsanitizer/tsan/tsan_rtl.h80
-rw-r--r--libsanitizer/tsan/tsan_rtl_aarch64.S127
-rw-r--r--libsanitizer/tsan/tsan_rtl_amd64.S6
-rw-r--r--libsanitizer/tsan/tsan_rtl_mutex.cc132
-rw-r--r--libsanitizer/tsan/tsan_rtl_report.cc63
-rw-r--r--libsanitizer/tsan/tsan_rtl_thread.cc26
-rw-r--r--libsanitizer/tsan/tsan_stat.cc15
-rw-r--r--libsanitizer/tsan/tsan_stat.h15
-rw-r--r--libsanitizer/tsan/tsan_suppressions.cc2
-rw-r--r--libsanitizer/tsan/tsan_sync.cc10
-rw-r--r--libsanitizer/tsan/tsan_sync.h48
-rw-r--r--libsanitizer/tsan/tsan_trace.h2
-rw-r--r--libsanitizer/ubsan/Makefile.am5
-rw-r--r--libsanitizer/ubsan/Makefile.in9
-rw-r--r--libsanitizer/ubsan/libtool-version2
-rw-r--r--libsanitizer/ubsan/ubsan_checks.inc1
-rw-r--r--libsanitizer/ubsan/ubsan_diag.cc47
-rw-r--r--libsanitizer/ubsan/ubsan_diag.h12
-rw-r--r--libsanitizer/ubsan/ubsan_diag_standalone.cc36
-rw-r--r--libsanitizer/ubsan/ubsan_flags.cc21
-rw-r--r--libsanitizer/ubsan/ubsan_handlers.cc166
-rw-r--r--libsanitizer/ubsan/ubsan_handlers.h45
-rw-r--r--libsanitizer/ubsan/ubsan_handlers_cxx.cc23
-rw-r--r--libsanitizer/ubsan/ubsan_handlers_cxx.h13
-rw-r--r--libsanitizer/ubsan/ubsan_init.cc44
-rw-r--r--libsanitizer/ubsan/ubsan_init.h3
-rw-r--r--libsanitizer/ubsan/ubsan_init_standalone.cc14
-rw-r--r--libsanitizer/ubsan/ubsan_init_standalone_preinit.cc35
-rw-r--r--libsanitizer/ubsan/ubsan_interface.inc52
-rw-r--r--libsanitizer/ubsan/ubsan_platform.h9
-rw-r--r--libsanitizer/ubsan/ubsan_signals_standalone.cc52
-rw-r--r--libsanitizer/ubsan/ubsan_signals_standalone.h23
-rw-r--r--libsanitizer/ubsan/ubsan_type_hash_itanium.cc4
-rw-r--r--libsanitizer/ubsan/ubsan_win_dll_thunk.cc19
-rw-r--r--libsanitizer/ubsan/ubsan_win_dynamic_runtime_thunk.cc19
-rw-r--r--libsanitizer/ubsan/ubsan_win_weak_interception.cc21
-rw-r--r--libstdc++-v3/ChangeLog347
-rw-r--r--libstdc++-v3/config/locale/gnu/c_locale.cc1
-rw-r--r--libstdc++-v3/doc/xml/manual/intro.xml10
-rw-r--r--libstdc++-v3/doc/xml/manual/status_cxx2017.xml32
-rw-r--r--libstdc++-v3/doc/xml/manual/status_cxxis29124.xml315
-rw-r--r--libstdc++-v3/include/Makefile.am6
-rw-r--r--libstdc++-v3/include/Makefile.in6
-rw-r--r--libstdc++-v3/include/bits/basic_string.h2
-rw-r--r--libstdc++-v3/include/bits/c++config7
-rw-r--r--libstdc++-v3/include/bits/fs_dir.h526
-rw-r--r--libstdc++-v3/include/bits/fs_fwd.h348
-rw-r--r--libstdc++-v3/include/bits/fs_ops.h311
-rw-r--r--libstdc++-v3/include/bits/fs_path.h1163
-rw-r--r--libstdc++-v3/include/bits/functional_hash.h4
-rw-r--r--libstdc++-v3/include/bits/specfun.h2
-rw-r--r--libstdc++-v3/include/bits/stl_bvector.h2
-rw-r--r--libstdc++-v3/include/bits/stl_map.h17
-rw-r--r--libstdc++-v3/include/bits/stl_multimap.h16
-rw-r--r--libstdc++-v3/include/bits/streambuf_iterator.h61
-rw-r--r--libstdc++-v3/include/bits/string_view.tcc12
-rw-r--r--libstdc++-v3/include/bits/unordered_map.h22
-rw-r--r--libstdc++-v3/include/c_compatibility/complex.h4
-rw-r--r--libstdc++-v3/include/c_compatibility/math.h4
-rw-r--r--libstdc++-v3/include/c_global/cstddef4
-rw-r--r--libstdc++-v3/include/experimental/bits/fs_dir.h4
-rw-r--r--libstdc++-v3/include/experimental/bits/fs_fwd.h4
-rw-r--r--libstdc++-v3/include/experimental/bits/fs_ops.h4
-rw-r--r--libstdc++-v3/include/experimental/bits/fs_path.h8
-rw-r--r--libstdc++-v3/include/experimental/filesystem30
-rw-r--r--libstdc++-v3/include/experimental/string_view8
-rw-r--r--libstdc++-v3/include/precompiled/stdc++.h5
-rw-r--r--libstdc++-v3/include/std/charconv658
-rw-r--r--libstdc++-v3/include/std/chrono4
-rw-r--r--libstdc++-v3/include/std/filesystem45
-rw-r--r--libstdc++-v3/include/std/mutex6
-rw-r--r--libstdc++-v3/include/std/optional20
-rw-r--r--libstdc++-v3/include/std/string_view95
-rw-r--r--libstdc++-v3/include/std/variant13
-rw-r--r--libstdc++-v3/libsupc++/exception3
-rw-r--r--libstdc++-v3/libsupc++/exception_ptr.h13
-rw-r--r--libstdc++-v3/python/libstdcxx/v6/printers.py4
-rw-r--r--libstdc++-v3/src/c++11/istream-inst.cc2
-rw-r--r--libstdc++-v3/src/c++11/locale-inst.cc2
-rw-r--r--libstdc++-v3/src/c++11/ostream-inst.cc2
-rw-r--r--libstdc++-v3/src/c++11/wlocale-inst.cc2
-rw-r--r--libstdc++-v3/src/c++98/complex_io.cc2
-rw-r--r--libstdc++-v3/src/c++98/hash-long-double-tr1-aux.cc2
-rw-r--r--libstdc++-v3/src/filesystem/Makefile.am10
-rw-r--r--libstdc++-v3/src/filesystem/Makefile.in16
-rw-r--r--libstdc++-v3/src/filesystem/cow-dir.cc2
-rw-r--r--libstdc++-v3/src/filesystem/cow-ops.cc2
-rw-r--r--libstdc++-v3/src/filesystem/cow-path.cc2
-rw-r--r--libstdc++-v3/src/filesystem/cow-std-dir.cc26
-rw-r--r--libstdc++-v3/src/filesystem/cow-std-ops.cc26
-rw-r--r--libstdc++-v3/src/filesystem/cow-std-path.cc26
-rw-r--r--libstdc++-v3/src/filesystem/dir-common.h149
-rw-r--r--libstdc++-v3/src/filesystem/dir.cc258
-rw-r--r--libstdc++-v3/src/filesystem/ops-common.h148
-rw-r--r--libstdc++-v3/src/filesystem/ops.cc289
-rw-r--r--libstdc++-v3/src/filesystem/path.cc35
-rw-r--r--libstdc++-v3/src/filesystem/std-dir.cc318
-rw-r--r--libstdc++-v3/src/filesystem/std-ops.cc1513
-rw-r--r--libstdc++-v3/src/filesystem/std-path.cc688
-rw-r--r--libstdc++-v3/testsuite/18_support/byte/requirements.cc6
-rw-r--r--libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc1
-rw-r--r--libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc7
-rw-r--r--libstdc++-v3/testsuite/20_util/from_chars/1.cc80
-rw-r--r--libstdc++-v3/testsuite/20_util/from_chars/1_neg.cc38
-rw-r--r--libstdc++-v3/testsuite/20_util/from_chars/2.cc205
-rw-r--r--libstdc++-v3/testsuite/20_util/from_chars/requirements.cc61
-rw-r--r--libstdc++-v3/testsuite/20_util/optional/hash.cc17
-rw-r--r--libstdc++-v3/testsuite/20_util/to_chars/1.cc662
-rw-r--r--libstdc++-v3/testsuite/20_util/to_chars/1_neg.cc35
-rw-r--r--libstdc++-v3/testsuite/20_util/to_chars/2.cc78
-rw-r--r--libstdc++-v3/testsuite/20_util/to_chars/requirements.cc49
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc53
-rw-r--r--libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc53
-rw-r--r--libstdc++-v3/testsuite/22_locale/money_get/get/char/22131.cc2
-rw-r--r--libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/22131.cc2
-rw-r--r--libstdc++-v3/testsuite/23_containers/map/modifiers/insert/dr2354.cc32
-rw-r--r--libstdc++-v3/testsuite/23_containers/multimap/modifiers/insert/dr2354.cc32
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_map/insert/dr2354.cc32
-rw-r--r--libstdc++-v3/testsuite/23_containers/unordered_multimap/insert/dr2354.cc32
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/bool/82558.cc32
-rw-r--r--libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/2.cc10
-rw-r--r--libstdc++-v3/testsuite/24_iterators/range_access_cpp17.cc4
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/clamp/1.cc12
-rw-r--r--libstdc++-v3/testsuite/25_algorithms/clamp/constexpr.cc4
-rw-r--r--libstdc++-v3/testsuite/26_numerics/complex/c99.cc3
-rw-r--r--libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc27
-rw-r--r--libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_global_c++17.cc111
-rw-r--r--libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_c++11.h33
-rw-r--r--libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_c++98.h55
-rw-r--r--libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_gnu++11.h52
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc150
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc117
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc188
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc54
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc139
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc200
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc84
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc83
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc65
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc96
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc58
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc74
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc115
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc71
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc109
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc162
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc167
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc67
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc51
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc64
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc92
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc46
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc97
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc118
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc127
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc70
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc87
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc94
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc56
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc51
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc51
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc49
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc69
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc56
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc55
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc51
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc40
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc112
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc56
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc70
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc70
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc73
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc70
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc59
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc43
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc61
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc62
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc52
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc53
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc53
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc55
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc127
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc46
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc64
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc62
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc53
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc59
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc45
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc70
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc52
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc44
-rw-r--r--libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc44
-rw-r--r--libstdc++-v3/testsuite/decimal/conversion-to-integral.cc2
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc19
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/operations/create_directory.cc1
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc2
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc1
-rw-r--r--libstdc++-v3/testsuite/experimental/filesystem/path/itr/traversal.cc18
-rw-r--r--libstdc++-v3/testsuite/util/testsuite_fs.h27
-rw-r--r--maintainer-scripts/ChangeLog5
-rw-r--r--maintainer-scripts/crontab1
-rwxr-xr-xmaintainer-scripts/update_version_svn2
2085 files changed, 110298 insertions, 35908 deletions
diff --git a/ChangeLog b/ChangeLog
index e4a8d01..739a3ac 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2017-10-16 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
+
+ * MAINTAINERS (write after approval): Add myself.
+
+2017-10-01 Gerald Pfeifer <gerald@pfeifer.com>
+
+ * MAINTAINERS: Add a note that maintainership also includes web
+ pages, docs, and testsuite related to that area.
+
+2017-09-25 Tom de Vries <tom@codesourcery.com>
+
+ * MAINTAINERS (CPU Port Maintainers): Add myself as nvptx maintainer.
+
2017-09-18 Pierre-Marie de Rodat <derodat@adacore.com>
* MAINTAINERS: Add myself as a maintainer for the Ada front end.
diff --git a/MAINTAINERS b/MAINTAINERS
index 99babdc..9c3a56e 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -37,6 +37,9 @@ Note that while global reviewers can approve changes to any part of
the compiler or associated libraries, they still need approval for
their own patches from other maintainers or reviewers.
+Also note that maintainership of any area covers changes to web pages,
+docs, and the testsuite related to that.
+
CPU Port Maintainers (CPU alphabetical order)
aarch64 port Richard Earnshaw <richard.earnshaw@arm.com>
@@ -85,6 +88,7 @@ nds32 port Chung-Ju Wu <jasonwucj@gmail.com>
nds32 port Shiva Chen <shiva0217@gmail.com>
nios2 port Chung-Lin Tang <cltang@codesourcery.com>
nios2 port Sandra Loosemore <sandra@codesourcery.com>
+nvptx port Tom de Vries <tom@codesourcery.com>
pdp11 port Paul Koning <ni1d@arrl.net>
picochip port Daniel Towner <dant@picochip.com>
powerpcspe port Andrew Jenner <andrew@codesourcery.com>
@@ -599,6 +603,7 @@ Ilya Tocar <tocarip@gmail.com>
Philipp Tomsich <philipp.tomsich@theobroma-systems.com>
Konrad Trifunovic <konrad.trifunovic@inria.fr>
Markus Trippelsdorf <markus@trippelsdorf.de>
+Igor Tsimbalist <igor.v.tsimbalist@intel.com>
Martin Uecker <uecker@eecs.berkeley.edu>
David Ung <davidu@mips.com>
Neil Vachharajani <nvachhar@gmail.com>
diff --git a/config/ChangeLog b/config/ChangeLog
index 6732bf4..2e3ead0 100644
--- a/config/ChangeLog
+++ b/config/ChangeLog
@@ -1,3 +1,7 @@
+2017-10-24 H.J. Lu <hongjiu.lu@intel.com>
+
+ * bootstrap-cet.mk: New file.
+
2017-06-19 Martin Liska <mliska@suse.cz>
* bootstrap-lto-noplugin.mk: Enable -flto in all PGO stages.
diff --git a/config/bootstrap-cet.mk b/config/bootstrap-cet.mk
new file mode 100644
index 0000000..f09193a6
--- /dev/null
+++ b/config/bootstrap-cet.mk
@@ -0,0 +1,4 @@
+# This option enables -fcf-protection -mcet for stage2 and stage3.
+
+STAGE2_CFLAGS += -fcf-protection -mcet
+STAGE3_CFLAGS += -fcf-protection -mcet
diff --git a/contrib/ChangeLog b/contrib/ChangeLog
index 45ccc16..df4b1bc 100644
--- a/contrib/ChangeLog
+++ b/contrib/ChangeLog
@@ -1,3 +1,7 @@
+2017-10-02 Thomas Schwinge <thomas@codesourcery.com>
+
+ * gcc_update (files_and_dependencies): Handle libbacktrace.
+
2017-09-18 Richard Biener <rguenther@suse.de>
* download_prerequisites (isl): Bump version to 0.18.
diff --git a/contrib/gcc_update b/contrib/gcc_update
index 8c11195..2e5d5ff 100755
--- a/contrib/gcc_update
+++ b/contrib/gcc_update
@@ -168,6 +168,10 @@ liboffloadmic/configure: liboffloadmic/configure.ac
liboffloadmic/plugin/aclocal.m4: liboffloadmic/plugin/configure.ac
liboffloadmic/plugin/Makefile.in: liboffloadmic/plugin/Makefile.am
liboffloadmic/plugin/configure: liboffloadmic/plugin/configure.ac
+libbacktrace/aclocal.m4: libbacktrace/configure.ac
+libbacktrace/Makefile.in: libbacktrace/Makefile.am libbacktrace/aclocal.m4
+libbacktrace/configure: libbacktrace/configure.ac libbacktrace/aclocal.m4
+libbacktrace/config.h.in: libbacktrace/configure.ac libbacktrace/aclocal.m4
# Top level
Makefile.in: Makefile.tpl Makefile.def
configure: configure.ac config/acx.m4
diff --git a/fixincludes/ChangeLog b/fixincludes/ChangeLog
index ffd1718..1f29148 100644
--- a/fixincludes/ChangeLog
+++ b/fixincludes/ChangeLog
@@ -1,3 +1,8 @@
+2017-10-13 Mike Frysinger <vapier@chromium.org>
+
+ * fixinc.in (dirname): Change sed from 's|[^/]*/||' to
+ 's|[^/]*//*||'.
+
2017-06-12 Doug Rupp <rupp@adacore.com>
* inclhack.def (AAB_vxworks_stdint): Remove hack.
diff --git a/fixincludes/fixinc.in b/fixincludes/fixinc.in
index 15cbaa2..cd0b458 100755
--- a/fixincludes/fixinc.in
+++ b/fixincludes/fixinc.in
@@ -344,7 +344,7 @@ if $LINKS; then
mkdir $component >/dev/null 2>&1
cd $component
dirmade=$dirmade/$component
- dirname=`echo $dirname | sed -e 's|[^/]*/||'`
+ dirname=`echo $dirname | sed -e 's|[^/]*//*||'`
done
fi
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 9576c8c..2f750ac 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,8 +1,4277 @@
-2017-09-19 Uros Bizjak <ubizjak@gmail.com>
+2017-10-24 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82460
+ * config/i386/sse.md (UNSPEC_VPERMI2, UNSPEC_VPERMI2_MASK): Remove.
+ (VPERMI2, VPERMI2I): New mode iterators.
+ (<avx512>_vpermi2var<mode>3_maskz): Remove 3 define_expand patterns.
+ (<avx512>_vpermi2var<mode>3<sd_maskz_name>): Remove 3 define_insn
+ patterns.
+ (<avx512>_vpermi2var<mode>3_mask): New define_expand using VPERMI2
+ mode iterator. Remove 3 old define_insn patterns.
+ (*<avx512>_vpermi2var<mode>3_mask): 2 new define_insn patterns.
+ (<avx512>_vpermt2var<mode>3_maskz): Adjust 1 define_expand to use
+ VPERMI2 mode iterator, remove the other two expanders.
+ (<avx512>_vpermt2var<mode>3<sd_maskz_name>): Adjust 1 define_insn
+ to use VPERMI2 mode iterator, add another alternative for vpermi2*
+ instructions, remove the other two patterns.
+ (<avx512>_vpermt2var<mode>3_mask): Adjust 1 define_insn to use VPERMI2
+ mode iterator, remove the other two patterns.
+ * config/i386/i386.c (ix86_expand_vec_perm_vpermi2): Renamed to ...
+ (ix86_expand_vec_perm_vpermt2): ... this. Swap mask and op0
+ arguments, use gen_*vpermt2* expanders instead of gen_*vpermi2*
+ and adjust argument order accordingly.
+ (ix86_expand_vec_perm): Adjust caller.
+ (expand_vec_perm_1): Likewise.
+ (expand_vec_perm_vpermi2_vpshub2): Rename to ...
+ (expand_vec_perm_vpermt2_vpshub2): ... this.
+ (ix86_expand_vec_perm_const_1): Adjust caller.
+ (ix86_vectorize_vec_perm_const_ok): Adjust comments.
+
+ PR target/82370
+ * config/i386/sse.md (VIMAX_AVX2): Remove V4TImode.
+ (VIMAX_AVX2_AVX512BW, VIMAX_AVX512VL): New mode iterators.
+ (vec_shl_<mode>): Remove unused expander.
+ (avx512bw_<shift_insn><mode>3): New define_insn.
+ (<sse2_avx2>_ashl<mode>3, <sse2_avx2>_lshr<mode>3): Replaced by ...
+ (<sse2_avx2>_<shift_insn><mode>3): ... this. New define_insn.
+
+2017-10-24 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82466
+ * doc/invoke.texi ([Wbuiltin-declaration-mismatch]): Extend
+ description.
+
+2017-10-24 Wilco Dijkstra <wdijkstr@arm.com>
+
+ PR rtl-optimization/82396
+ * gcc/haifa-sched.c (ready_sort_real): Remove qsort workaround.
+ (autopref_multipass_init): Simplify initialization.
+ (autopref_rank_data): Simplify sort order.
+ * gcc/sched-int.h (autopref_multipass_data_): Remove
+ multi_mem_insn_p, min_offset and max_offset.
+
+2017-10-24 Wilco Dijkstra <wdijkstr@arm.com>
+
+ PR middle-end/60580
+ * config/aarch64/aarch64.c (aarch64_frame_pointer_required)
+ Check special value of flag_omit_frame_pointer.
+ (aarch64_can_eliminate): Likewise.
+ (aarch64_override_options_after_change_1): Simplify handling of
+ -fomit-frame-pointer and -fomit-leaf-frame-pointer.
+
+2017-10-24 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82697
+ * tree-ssa-phiopt.c (cond_store_replacement): Use alias-set
+ zero for conditional load and unconditional store.
+
+2017-10-24 H.J. Lu <hongjiu.lu@intel.com>
+
+ * doc/install.texi: Document bootstrap-cet.
+
+2017-10-24 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/82659
+ * config/i386/i386.c (rest_of_insert_endbranch): Don't insert
+ ENDBR instruction at function entrance if function is only
+ called directly.
+
+2017-10-24 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82628
+ * config/i386/i386.md (addcarry<mode>, subborrow<mode>): Change
+ patterns to better describe from which operation the CF is computed.
+ (addcarry<mode>_0, subborrow<mode>_0): New patterns.
+ * config/i386/i386.c (ix86_expand_builtin) <case handlecarry>: Pass
+ one LTU with [DT]Imode and another one with [SD]Imode. If arg0
+ is 0, use _0 suffixed expanders instead of emitting a comparison
+ before it.
+
+2017-10-06 Sergey Shalnov <Sergey.Shalnov@intel.com>
+
+ * config/i386/i386.md(*movsf_internal, *movdf_internal):
+ Avoid 512-bit AVX modes for TARGET_PREFER_AVX256.
+
+2017-10-24 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR middle-end/82569
+ * tree-outof-ssa.h (always_initialized_rtx_for_ssa_name_p): Delete.
+ * expr.c (expand_expr_real_1) <expand_decl_rtl>: Revert latest change.
+ * loop-iv.c (iv_get_reaching_def): Likewise.
+ * cfgexpand.c (expand_one_ssa_partition): Initialize the RTX if the
+ variable is promoted and the partition contains undefined values.
+
+2017-10-23 Sandra Loosemore <sandra@codesourcery.com>
+
+ * config/nios2/nios2.c (nios2_rtx_costs): Make costs better
+ reflect reality.
+ (nios2_address_cost): Define.
+ (nios2_legitimize_address): Recognize (exp + constant) directly.
+ (TARGET_ADDRESS_COST): Define.
+
+2017-10-23 Sandra Loosemore <sandra@codesourcery.com>
+
+ * config/nios2/nios2-protos.h (nios2_large_constant_p): Declare.
+ (nios2_symbolic_memory_operand_p): Declare.
+ (nios2_split_large_constant): Declare.
+ (nios2_split_symbolic_memory_operand): Declare.
+ * config/nios2/nios2.c: Adjust includes.
+ (nios2_symbolic_constant_allowed): New.
+ (nios2_symbolic_constant_p): New.
+ (nios2_plus_symbolic_constant_p): New.
+ (nios2_valid_addr_expr_p): Recognize addresses involving
+ symbolic constants.
+ (nios2_legitimate_address_p): Likewise, also LO_SUM.
+ (nios2_symbolic_memory_operand_p): New.
+ (nios2_large_constant_p): New.
+ (nios2_split_large_constant): New.
+ (nios2_split_plus_large_constant): New.
+ (nios2_split_symbolic_memory_operand): New.
+ (nios2_legitimize_address): Code refactoring. Handle addresses
+ involving symbolic constants.
+ (nios2_emit_move_sequence): Likewise.
+ (nios2_print_operand): Improve error output.
+ (nios2_print_operand_address): Handle LO_SUM.
+ (nios2_cdx_narrow_form_p): Likewise.
+ * config/nios2/nios2.md (movqi_internal): Add splitter for memory
+ operands involving symbolic constants.
+ (movhi_internal, movsi_internal): Likewise.
+ (zero_extendhisi2, zero_extendqi<mode>2): Likewise.
+ (extendhisi2, extendqi<mode>2): Likewise.
+
+2017-10-23 Sandra Loosemore <sandra@codesourcery.com>
+
+ * tree-pass.h (PROP_rtl_split_insns): Define.
+ * recog.c (pass_data_split_all_insns): Provide PROP_rtl_split_insns.
+
+2017-10-23 Sandra Loosemore <sandra@codesourcery.com>
+
+ * config/nios2/nios2.c (TARGET_LRA_P): Don't override.
+
+2017-10-23 Jakub Jelinek <jakub@redhat.com>
+
+ PR debug/82630
+ * target.def (const_not_ok_for_debug_p): Default to
+ default_const_not_ok_for_debug_p instead of hook_bool_rtx_false.
+ * targhooks.h (default_const_not_ok_for_debug_p): New declaration.
+ * targhooks.c (default_const_not_ok_for_debug_p): New function.
+ * dwarf2out.c (const_ok_for_output_1): Only reject UNSPECs for
+ which targetm.const_not_ok_for_debug_p returned true.
+ * config/arm/arm.c (arm_const_not_ok_for_debug_p): Return true
+ for UNSPECs.
+ * config/powerpcspe/powerpcspe.c (rs6000_const_not_ok_for_debug_p):
+ Likewise.
+ * config/rs6000/rs6000.c (rs6000_const_not_ok_for_debug_p): Likewise.
+ * config/i386/i386.c (ix86_delegitimize_address_1): Don't delegitimize
+ UNSPEC_GOTOFF with addend into addend - _GLOBAL_OFFSET_TABLE_ + symbol
+ if !base_term_p.
+ (ix86_const_not_ok_for_debug_p): New function.
+ (i386_asm_output_addr_const_extra): Handle UNSPEC_GOTOFF.
+ (TARGET_CONST_NOT_OK_FOR_DEBUG_P): Redefine.
+
+2017-10-23 David Malcolm <dmalcolm@redhat.com>
+
+ PR bootstrap/82610
+ * system.h: Conditionally include "unique-ptr.h" if
+ INCLUDE_UNIQUE_PTR is defined.
+ * unique-ptr-tests.cc: Remove include of "unique-ptr.h" in favor
+ of defining INCLUDE_UNIQUE_PTR before including "system.h".
+
+2017-10-23 Sebastian Perta <sebastian.perta@renesas.com>
+
+ * config/rl78/rl78.md: New define_expand "subdi3".
+
+2017-10-23 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/82673
+ * config/i386/i386.c (ix86_finalize_stack_frame_flags): Skip
+ DF_REF_INSN if DF_REF_INSN_INFO is false.
+
+2017-10-23 Jan Hubicka <hubicka@ucw.cz>
+
+ * i386.c (dimode_scalar_chain::compute_convert_gain): Use
+ xmm_move instead of sse_move.
+ (sse_store_index): New function.
+ (ix86_register_move_cost): Be more sensible about mismatch stall;
+ model AVX moves correctly; make difference between sse->integer and
+ integer->sse.
+ (ix86_builtin_vectorization_cost): Model correctly aligned and unaligned
+ moves; make difference between SSE and AVX.
+ * i386.h (processor_costs): Remove sse_move; add xmm_move, ymm_move
+ and zmm_move. Increase size of sse load and store tables;
+ add unaligned load and store tables; add ssemmx_to_integer.
+ * x86-tune-costs.h: Update all entries according to real
+ move latencies from Agner Fog's manual and chip documentation.
+
+2017-10-23 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82628
+ * config/i386/predicates.md (x86_64_dwzext_immediate_operand): New.
+ * config/i386/constraints.md (Wf): New constraint.
+ * config/i386/i386.md (UNSPEC_SBB): New unspec.
+ (cmp<dwi>_doubleword): Removed.
+ (sub<mode>3_carry_ccc, *sub<mode>3_carry_ccc_1): New patterns.
+ (sub<mode>3_carry_ccgz): Use unspec instead of compare.
+ * config/i386/i386.c (ix86_expand_branch) <case E_TImode>: Don't
+ expand with cmp<dwi>_doubleword. For LTU and GEU use
+ sub<mode>3_carry_ccc instead of sub<mode>3_carry_ccgz and use CCCmode.
+
+ * common.opt (gcolumn-info): Enable by default.
+ * doc/invoke.texi (gcolumn-info): Document new default.
+
+2017-10-23 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82672
+ * graphite-isl-ast-to-gimple.c (graphite_copy_stmts_from_block):
+ Fold the stmt if we propagated into it.
+
+2017-10-23 Richard Biener <rguenther@suse.de>
+
+ * tree-ssa-pre.c (bitmap_remove_from_set): Rename to...
+ (bitmap_remove_expr_from_set): ... this. All callers call this
+ for non-constant values.
+ (bitmap_set_subtract): Rename to...
+ (bitmap_set_subtract_expressions): ... this. Adjust and
+ optimize.
+ (bitmap_set_contains_value): Remove superfluous check.
+ (bitmap_set_replace_value): Inline into single caller ...
+ (bitmap_value_replace_in_set): ... here and simplify.
+ (dependent_clean): Merge into ...
+ (clean): ... this using an overload. Adjust.
+ (prune_clobbered_mems): Adjust.
+ (compute_antic_aux): Likewise.
+ (compute_partial_antic_aux): Likewise.
+
+2017-10-23 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82129
+ Revert
+ 2017-08-01 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/81181
+ * tree-ssa-pre.c (compute_antic_aux): Defer clean() to ...
+ (compute_antic): ... end of iteration here.
+
+2017-10-23 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * target.def (starting_frame_offset): New hook.
+ * doc/tm.texi (STARTING_FRAME_OFFSET): Remove in favor of...
+ (TARGET_STARTING_FRAME_OFFSET): ...this new hook.
+ * doc/tm.texi.in: Regenerate.
+ * hooks.h (hook_hwi_void_0): Declare.
+ * hooks.c (hook_hwi_void_0): New function.
+ * doc/rtl.texi: Refer to TARGET_STARTING_FRAME_OFFSET instead of
+ STARTING_FRAME_OFFSET.
+ * builtins.c (expand_builtin_setjmp_receiver): Likewise.
+ * reload1.c (reload): Likewise.
+ * cfgexpand.c (expand_used_vars): Use targetm.starting_frame_offset
+ instead of STARTING_FRAME_OFFSET.
+ * function.c (try_fit_stack_local): Likewise.
+ (assign_stack_local_1): Likewise
+ (instantiate_virtual_regs): Likewise.
+ * rtlanal.c (rtx_addr_can_trap_p_1): Likewise.
+ * config/avr/avr.md (nonlocal_goto_receiver): Likewise.
+ * config/aarch64/aarch64.h (STARTING_FRAME_OFFSET): Delete.
+ * config/alpha/alpha.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/arc/arc.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/arm/arm.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/bfin/bfin.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/c6x/c6x.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/cr16/cr16.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/cris/cris.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/fr30/fr30.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/frv/frv.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/ft32/ft32.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/h8300/h8300.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/i386/i386.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/ia64/ia64.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/m32c/m32c.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/m68k/m68k.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/mcore/mcore.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/mn10300/mn10300.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/moxie/moxie.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/msp430/msp430.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/nds32/nds32.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/nios2/nios2.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/nvptx/nvptx.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/pdp11/pdp11.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/riscv/riscv.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/rl78/rl78.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/rx/rx.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/s390/s390.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/sh/sh.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/sparc/sparc.c (sparc_compute_frame_size): Likewise.
+ * config/sparc/sparc.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/spu/spu.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/stormy16/stormy16.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/tilegx/tilegx.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/tilepro/tilepro.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/v850/v850.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/visium/visium.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/avr/avr.h (STARTING_FRAME_OFFSET): Likewise.
+ * config/avr/avr-protos.h (avr_starting_frame_offset): Likewise.
+ * config/avr/avr.c (avr_starting_frame_offset): Make static and
+ return a HOST_WIDE_INT.
+ (avr_builtin_setjmp_frame_value): Use it instead of
+ STARTING_FRAME_OFFSET.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * config/epiphany/epiphany.h (STARTING_FRAME_OFFSET): Delete.
+ * config/epiphany/epiphany.c (epiphany_starting_frame_offset):
+ New function.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * config/iq2000/iq2000.h (STARTING_FRAME_OFFSET): Delete.
+ * config/iq2000/iq2000.c (iq2000_starting_frame_offset): New function.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/lm32/lm32.h (STARTING_FRAME_OFFSET): Delete.
+ * config/lm32/lm32.c (lm32_starting_frame_offset): New function.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * config/m32r/m32r.h (STARTING_FRAME_OFFSET): Delete.
+ * config/m32r/m32r.c (m32r_starting_frame_offset): New function.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * config/microblaze/microblaze.h (STARTING_FRAME_OFFSET): Delete.
+ * config/microblaze/microblaze.c (microblaze_starting_frame_offset):
+ New function.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * config/mips/mips.h (STARTING_FRAME_OFFSET): Delete.
+ * config/mips/mips.c (mips_compute_frame_info): Refer to
+ TARGET_STARTING_FRAME_OFFSET instead of STARTING_FRAME_OFFSET.
+ (mips_starting_frame_offset): New function.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * config/mmix/mmix.h (STARTING_FRAME_OFFSET): Delete.
+ * config/mmix/mmix-protos.h (mmix_starting_frame_offset): Delete.
+ * config/mmix/mmix.c (mmix_starting_frame_offset): Make static
+ and return a HOST_WIDE_INT.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ (mmix_initial_elimination_offset): Refer to
+ TARGET_STARTING_FRAME_OFFSET instead of STARTING_FRAME_OFFSET.
+ * config/pa/pa.h (STARTING_FRAME_OFFSET): Delete.
+ * config/pa/pa.c (pa_starting_frame_offset): New function.
+ (pa_compute_frame_size): Use it instead of STARTING_FRAME_OFFSET.
+ (pa_expand_prologue): Likewise.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * config/powerpcspe/aix.h (STARTING_FRAME_OFFSET): Split out
+ !FRAME_GROWS_DOWNWARD handling to...
+ (RS6000_STARTING_FRAME_OFFSET): ...this new macro.
+ * config/powerpcspe/darwin.h (STARTING_FRAME_OFFSET): Split out
+ !FRAME_GROWS_DOWNWARD handling to...
+ (RS6000_STARTING_FRAME_OFFSET): ...this new macro.
+ * config/powerpcspe/powerpcspe.h (STARTING_FRAME_OFFSET): Split out
+ !FRAME_GROWS_DOWNWARD handling to...
+ (RS6000_STARTING_FRAME_OFFSET): ...this new macro.
+ * config/powerpcspe/powerpcspe.c (TARGET_STARTING_FRAME_OFFSET):
+ Redefine.
+ (rs6000_starting_frame_offset): New function.
+ * config/rs6000/aix.h (STARTING_FRAME_OFFSET): Split out
+ !FRAME_GROWS_DOWNWARD handling to...
+ (RS6000_STARTING_FRAME_OFFSET): ...this new macro.
+ * config/rs6000/darwin.h (STARTING_FRAME_OFFSET): Split out
+ !FRAME_GROWS_DOWNWARD handling to...
+ (RS6000_STARTING_FRAME_OFFSET): ...this new macro.
+ * config/rs6000/rs6000.h (STARTING_FRAME_OFFSET): Split out
+ !FRAME_GROWS_DOWNWARD handling to...
+ (RS6000_STARTING_FRAME_OFFSET): ...this new macro.
+ * config/rs6000/rs6000.c (TARGET_STARTING_FRAME_OFFSET): Refine.
+ (rs6000_starting_frame_offset): New function.
+ * config/vax/elf.h (STARTING_FRAME_OFFSET): Delete.
+ * config/vax/vax.h (STARTING_FRAME_OFFSET): Delete.
+ * config/vax/vax.c (vax_starting_frame_offset): New function.
+ (vax_expand_prologue): Use it instead of STARTING_FRAME_OFFSET.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * config/xtensa/xtensa.h (STARTING_FRAME_OFFSET): Delete.
+ * config/xtensa/xtensa.c (xtensa_starting_frame_offset): New function.
+ (TARGET_STARTING_FRAME_OFFSET): Redefine.
+ * system.h (STARTING_FRAME_OFFSET): Poison.
+
+2017-10-23 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * tree-vect-loop.c (vect_create_epilog_for_reduction): Use
+ SCALAR_TYPE_MODE instead of TYPE_MODE.
+
+2017-10-23 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * dwarf2out.c (loc_list_from_tree_1): Use SCALAR_INT_TYPE_MODE
+
+2017-10-23 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * expmed.c (expand_shift_1): Use scalar_mode for scalar_mode.
+
+2017-10-23 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82129
+ * tree-ssa-pre.c (bitmap_set_and): Remove.
+ (compute_antic_aux): Compute ANTIC_OUT intersection in a way
+ canonicalizing expressions in the set to those with lowest
+ ID rather than taking that from the first edge.
+
+2017-10-23 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * combine.c (rtx_equal_for_field_assignment_p): Use
+ byte_lowpart_offset.
+
+2017-10-22 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * internal-fn.c (expand_direct_optab_fn): Don't assign directly
+ to a SUBREG_PROMOTED_VAR.
+
+2017-10-22 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * cfgexpand.c (expand_debug_expr): Use GET_MODE_UNIT_PRECISION.
+ (expand_debug_source_expr): Likewise.
+ * combine.c (combine_simplify_rtx): Likewise.
+ * cse.c (fold_rtx): Likewise.
+ * optabs.c (expand_float): Likewise.
+ * simplify-rtx.c (simplify_unary_operation_1): Likewise.
+ (simplify_binary_operation_1): Likewise.
+
+2017-10-22 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * combine.c (simplify_comparison): Use HWI_COMPUTABLE_MODE_P.
+ (record_promoted_value): Likewise.
+ * expr.c (expand_expr_real_2): Likewise.
+ * ree.c (update_reg_equal_equiv_notes): Likewise.
+ (combine_set_extension): Likewise.
+ * rtlanal.c (low_bitmask_len): Likewise.
+ * simplify-rtx.c (neg_const_int): Likewise.
+ (simplify_binary_operation_1): Likewise.
+
+2017-10-22 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * lra-spills.c (assign_mem_slot): Use subreg_size_lowpart_offset.
+ * regcprop.c (maybe_mode_change): Likewise.
+ * reload1.c (alter_reg): Likewise.
+
+2017-10-22 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * inchash.h (inchash::hash::add_wide_int): New function.
+ * lto-streamer-out.c (hash_tree): Use it.
+
+2017-10-22 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * inchash.h (inchash::hash::add_wide_int): Rename to...
+ (inchash::hash::add_hwi): ...this.
+ * ipa-devirt.c (hash_odr_vtable): Update accordingly.
+ (polymorphic_call_target_hasher::hash): Likewise.
+ * ipa-icf.c (sem_function::get_hash, sem_function::init): Likewise.
+ (sem_item::add_expr, sem_item::add_type, sem_variable::get_hash)
+ (sem_item_optimizer::update_hash_by_addr_refs): Likewise.
+ * lto-streamer-out.c (hash_tree): Likewise.
+ * optc-save-gen.awk: Likewise.
+ * tree.c (add_expr): Likewise.
+
+2017-10-22 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/52451
+ * config/i386/i386.c (ix86_fp_compare_mode): Return CCFPmode
+ for ordered inequality comparisons even with TARGET_IEEE_FP.
+
+2017-10-22 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/82628
+ * config/i386/i386.md (cmp<dwi>_doubleword): New pattern.
+ * config/i386/i386.c (ix86_expand_branch) <case E_TImode>:
+ Expand with cmp<dwi>_doubleword.
+
+2017-10-21 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
+
+ * extend.texi: Add x86 specific to 'nocf_check' attribute.
+ List CET intrinsics.
+ * invoke.texi: Add -mcet, -mibt, -mshstk options. Add x86
+ specific to -fcf-protection option.
+
+2017-10-21 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
+
+ * common/config/i386/i386-common.c (OPTION_MASK_ISA_IBT_SET): New.
+ (OPTION_MASK_ISA_SHSTK_SET): Likewise.
+ (OPTION_MASK_ISA_IBT_UNSET): Likewise.
+ (OPTION_MASK_ISA_SHSTK_UNSET): Likewise.
+ (ix86_handle_option): Add -mibt, -mshstk, -mcet handling.
+ * config.gcc (extra_headers): Add cetintrin.h for x86 targets.
+ (extra_objs): Add cet.o for Linux/x86 targets.
+ (tmake_file): Add i386/t-cet for Linux/x86 targets.
+ * config/i386/cet.c: New file.
+ * config/i386/cetintrin.h: Likewise.
+ * config/i386/t-cet: Likewise.
+ * config/i386/cpuid.h (bit_SHSTK): New.
+ (bit_IBT): Likewise.
+ * config/i386/driver-i386.c (host_detect_local_cpu): Detect and
+ pass IBT and SHSTK bits.
+ * config/i386/i386-builtin-types.def
+ (VOID_FTYPE_UNSIGNED_PVOID): New.
+ (VOID_FTYPE_UINT64_PVOID): Likewise.
+ * config/i386/i386-builtin.def: Add CET intrinsics.
+ * config/i386/i386-c.c (ix86_target_macros_internal): Add
+ OPTION_MASK_ISA_IBT, OPTION_MASK_ISA_SHSTK handling.
+ * config/i386/i386-passes.def: Add pass_insert_endbranch pass.
+ * config/i386/i386-protos.h (make_pass_insert_endbranch): New
+ prototype.
+ * config/i386/i386.c (rest_of_insert_endbranch): New.
+ (pass_data_insert_endbranch): Likewise.
+ (pass_insert_endbranch): Likewise.
+ (make_pass_insert_endbranch): Likewise.
+ (ix86_notrack_prefixed_insn_p): Likewise.
+ (ix86_target_string): Add -mibt, -mshstk flags.
+ (ix86_option_override_internal): Add flag_cf_protection
+ processing.
+ (ix86_valid_target_attribute_inner_p): Set OPT_mibt, OPT_mshstk.
+ (ix86_print_operand): Add 'notrack' prefix output.
+ (ix86_init_mmx_sse_builtins): Add CET intrinsics.
+ (ix86_expand_builtin): Expand CET intrinsics.
+ (x86_output_mi_thunk): Add 'endbranch' instruction.
+ * config/i386/i386.h (TARGET_IBT): New.
+ (TARGET_IBT_P): Likewise.
+ (TARGET_SHSTK): Likewise.
+ (TARGET_SHSTK_P): Likewise.
+ * config/i386/i386.md (unspecv): Add UNSPECV_NOP_RDSSP,
+ UNSPECV_INCSSP, UNSPECV_SAVEPREVSSP, UNSPECV_RSTORSSP,
+ UNSPECV_WRSS, UNSPECV_WRUSS, UNSPECV_SETSSBSY, UNSPECV_CLRSSBSY.
+ (builtin_setjmp_setup): New pattern.
+ (builtin_longjmp): Likewise.
+ (rdssp<mode>): Likewise.
+ (incssp<mode>): Likewise.
+ (saveprevssp): Likewise.
+ (rstorssp): Likewise.
+ (wrss<mode>): Likewise.
+ (wruss<mode>): Likewise.
+ (setssbsy): Likewise.
+ (clrssbsy): Likewise.
+ (nop_endbr): Likewise.
+ * config/i386/i386.opt: Add -mcet, -mibt, -mshstk and -mcet-switch
+ options.
+ * config/i386/immintrin.h: Include <cetintrin.h>.
+ * config/i386/linux-common.h
+ (file_end_indicate_exec_stack_and_cet): New prototype.
+ (TARGET_ASM_FILE_END): New.
+
+2017-10-20 Jan Hubicka <hubicka@ucw.cz>
+
+ * i386.c (ix86_builtin_vectorization_cost): Use existing rtx_cost
+ latencies instead of having separate table; make difference between
+ integer and float costs.
+ * i386.h (processor_costs): Remove scalar_stmt_cost,
+ scalar_load_cost, scalar_store_cost, vec_stmt_cost, vec_to_scalar_cost,
+ scalar_to_vec_cost, vec_align_load_cost, vec_unalign_load_cost,
+ vec_store_cost.
+ * x86-tune-costs.h: Remove entries which has been removed in
+ procesor_costs from all tables; make cond_taken_branch_cost
+ and cond_not_taken_branch_cost COST_N_INSNS based.
+
+2017-10-20 Jan Hubicka <hubicka@ucw.cz>
+
+ * x86-tune-costs.h (intel_cost, generic_cost): Fix move costs.
+
+2017-10-20 Jakub Jelinek <jakub@redhat.com>
+
+ * config/i386/i386.md (isa): Remove fma_avx512f.
+ * config/i386/sse.md (<avx512>_fmadd_<mode>_mask<round_name>,
+ <avx512>_fmadd_<mode>_mask3<round_name>,
+ <avx512>_fmsub_<mode>_mask<round_name>,
+ <avx512>_fmsub_<mode>_mask3<round_name>,
+ <avx512>_fnmadd_<mode>_mask<round_name>,
+ <avx512>_fnmadd_<mode>_mask3<round_name>,
+ <avx512>_fnmsub_<mode>_mask<round_name>,
+ <avx512>_fnmsub_<mode>_mask3<round_name>,
+ <avx512>_fmaddsub_<mode>_mask<round_name>,
+ <avx512>_fmaddsub_<mode>_mask3<round_name>,
+ <avx512>_fmsubadd_<mode>_mask<round_name>,
+ <avx512>_fmsubadd_<mode>_mask3<round_name>): Remove isa attribute.
+ (*vec_widen_umult_even_v16si<mask_name>,
+ *vec_widen_smult_even_v16si<mask_name>): Likewise.
+ (<mask_codefor>avx512bw_dbpsadbw<mode><mask_name>): Likewise.
+
+2017-10-20 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
+
+ * extend.texi: Add 'nocf_check' documentation.
+ * gimple.texi: Add second parameter to
+ gimple_build_call_from_tree.
+ * invoke.texi: Add -fcf-protection documentation.
+ * rtl.texi: Add REG_CALL_NOTRACK documenation.
+
+2017-10-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82473
+ * tree-vect-loop.c (vectorizable_reduction): Properly get at
+ the largest input type.
+
+2017-10-20 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
+
+ * c-attribs.c (handle_nocf_check_attribute): New function.
+ (c_common_attribute_table): Add 'nocf_check' handling.
+ * gimple-parser.c: Add second argument NULL to
+ gimple_build_call_from_tree.
+ * attrib.c (comp_type_attributes): Check nocf_check attribute.
+ * cfgexpand.c (expand_call_stmt): Set REG_CALL_NOCF_CHECK for
+ call insn.
+ * combine.c (distribute_notes): Add REG_CALL_NOCF_CHECK handling.
+ * common.opt: Add fcf-protection flag.
+ * emit-rtl.c (try_split): Add REG_CALL_NOCF_CHECK handling.
+ * flag-types.h: Add enum cf_protection_level.
+ * gimple.c (gimple_build_call_from_tree): Add second parameter.
+ Add 'nocf_check' attribute propagation to gimple call.
+ * gimple.h (gf_mask): Add GF_CALL_NOCF_CHECK.
+ (gimple_build_call_from_tree): Update prototype.
+ (gimple_call_nocf_check_p): New function.
+ (gimple_call_set_nocf_check): Likewise.
+ * gimplify.c: Add second argument to gimple_build_call_from_tree.
+ * ipa-icf.c: Add nocf_check attribute in statement hash.
+ * recog.c (peep2_attempt): Add REG_CALL_NOCF_CHECK handling.
+ * reg-notes.def: Add REG_NOTE (CALL_NOCF_CHECK).
+ * toplev.c (process_options): Add flag_cf_protection handling.
+
+2017-10-19 Jan Hubicka <hubicka@ucw.cz>
+
+ * x86-tune-costs.h (core_cost): Fix div, move and sqrt latencies.
+
+2017-10-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82603
+ * tree-if-conv.c (predicate_mem_writes): Make sure to only
+ remove false predicated stores.
+
+2017-10-20 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c
+ (translate_isl_ast_to_gimple::graphite_copy_stmts_from_block):
+ Remove return value and simplify, dump copied stmt after lhs
+ adjustment.
+ (translate_isl_ast_to_gimple::translate_isl_ast_node_user):
+ Reduce dump verbosity.
+ (gsi_insert_earliest): Likewise.
+ (translate_isl_ast_to_gimple::copy_bb_and_scalar_dependences): Adjust.
+ * graphite.c (print_global_statistics): Adjust dumping.
+ (print_graphite_scop_statistics): Likewise.
+ (print_graphite_statistics): Do not dump loops here.
+ (graphite_transform_loops): But here.
+
+2017-10-20 Nicolas Roche <roche@adacore.com>
+
+ * configure.ac (ACX_PROG_GNAT): Append "libgnat" to include search dir.
+ * configure: Regenerate.
+
+2017-10-20 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82158
+ * tree-cfg.c (pass_warn_function_return::execute): In noreturn
+ functions when optimizing replace GIMPLE_RETURN stmts with
+ calls to __builtin_unreachable ().
+
+ PR sanitizer/82595
+ * config/gnu-user.h (LIBTSAN_EARLY_SPEC): Add libtsan_preinit.o
+ for -fsanitize=thread link of executables.
+ (LIBLSAN_EARLY_SPEC): Add liblsan_preinit.o for -fsanitize=leak
+ link of executables.
+
+ PR target/82370
+ * config/i386/sse.md (VI248_AVX2, VI248_AVX512BW, VI248_AVX512BW_2):
+ New mode iterators.
+ (<shift_insn><mode>3<mask_name>): Change the last of the 3
+ define_insns for logical vector shifts to use VI248_AVX512BW
+ iterator instead of VI48_AVX512, remove <mask_mode512bit_condition>
+ condition, useless isa and prefix attributes. Change the first
+ 2 of these define_insns to ...
+ (<mask_codefor><shift_insn><mode>3<mask_name>): ... this, new
+ define_insn for avx512vl.
+ (<shift_insn><mode>3): ... and this, new define_insn without
+ masking for non-avx512vl.
+
+ PR target/82370
+ * config/i386/sse.md (*andnot<mode>3,
+ <mask_codefor><code><mode>3<mask_name>, *<code><mode>3): Split
+ (=v,v,vm) alternative into (=x,x,xm) and (=v,v,vm), for 128-bit
+ and 256-bit vectors, the (=x,x,xm) alternative and when mask is
+ not applied use empty suffix even for TARGET_AVX512VL.
+ * config/i386/subst.md (mask_prefix3, mask_prefix4): When mask
+ is applied, supply evex,evex or evex,evex,evex instead of just
+ evex.
+
+2017-10-20 Julia Koval <julia.koval@intel.com>
+
+ * common/config/i386/i386-common.c (OPTION_MASK_ISA_GFNI_SET,
+ (OPTION_MASK_ISA_GFNI_UNSET): New.
+ (ix86_handle_option): Handle OPT_mgfni.
+ * config/i386/cpuid.h (bit_GFNI): New.
+ * config/i386/driver-i386.c (host_detect_local_cpu): Detect gfni.
+ * config/i386/i386-c.c (ix86_target_macros_internal): Define __GFNI__.
+ * config/i386/i386.c (ix86_target_string): Add -mgfni.
+ (ix86_valid_target_attribute_inner_p): Add OPT_mgfni.
+ * config/i386/i386.h (TARGET_GFNI, TARGET_GFNI_P): New.
+ * config/i386/i386.opt: Add mgfni.
+
+2017-10-20 Orlando Arias <oarias@knights.ucf.edu>
+
+ * config/msp430/msp430.c (msp430_option_override): Disable
+ -fdelete-null-pointer-checks.
+ * doc/invoke.text (-fdelete-null-pointer-checks): Document that.
+
+2017-10-19 Jan Hubicka <hubicka@ucw.cz>
+
+ * x86-tune-costs.h (generic_cost, core_cost): Correct costs
+ of x87 and SSE instructions.
+
+2017-10-19 Jan Hubicka <hubicka@ucw.cz>
+
+ * asan.c (create_cond_insert_point): Do not update edge count.
+ * auto-profile.c (afdo_propagate_edge): Update for edge count removal.
+ (afdo_propagate_circuit): Likewise.
+ (afdo_calculate_branch_prob): Likewise.
+ (afdo_annotate_cfg): Likewise.
+ * basic-block.h (struct edge_def): Remove count.
+ (edge_def::count): New accessor.
+ * bb-reorder.c (rotate_loop): Update.
+ (find_traces_1_round): Update.
+ (connect_traces): Update.
+ (sanitize_hot_paths): Update.
+ * cfg.c (unchecked_make_edge): Update.
+ (make_single_succ_edge): Update.
+ (check_bb_profile): Update.
+ (dump_edge_info): Update.
+ (update_bb_profile_for_threading): Update.
+ (scale_bbs_frequencies_int): Update.
+ (scale_bbs_frequencies_gcov_type): Update.
+ (scale_bbs_frequencies_profile_count): Update.
+ (scale_bbs_frequencies): Update.
+ * cfganal.c (connect_infinite_loops_to_exit): Update.
+ * cfgbuild.c (compute_outgoing_frequencies): Update.
+ (find_many_sub_basic_blocks): Update.
+ * cfgcleanup.c (try_forward_edges): Update.
+ (try_crossjump_to_edge): Update
+ * cfgexpand.c (expand_gimple_cond): Update
+ (expand_gimple_tailcall): Update
+ (construct_exit_block): Update
+ * cfghooks.c (verify_flow_info): Update
+ (redirect_edge_succ_nodup): Update
+ (split_edge): Update
+ (make_forwarder_block): Update
+ (duplicate_block): Update
+ (account_profile_record): Update
+ * cfgloop.c (find_subloop_latch_edge_by_profile): Update.
+ * cfgloopanal.c (expected_loop_iterations_unbounded): Update.
+ * cfgloopmanip.c (scale_loop_profile): Update.
+ (loopify): Update.
+ (lv_adjust_loop_entry_edge): Update.
+ * cfgrtl.c (try_redirect_by_replacing_jump): Update.
+ (force_nonfallthru_and_redirect): Update.
+ (purge_dead_edges): Update.
+ (rtl_flow_call_edges_add): Update.
+ * cgraphunit.c (init_lowered_empty_function): Update.
+ (cgraph_node::expand_thunk): Update.
+ * gimple-pretty-print.c (dump_probability): Update.
+ (dump_edge_probability): Update.
+ * gimple-ssa-isolate-paths.c (isolate_path): Update.
+ * haifa-sched.c (sched_create_recovery_edges): Update.
+ * hsa-gen.c (convert_switch_statements): Update.
+ * ifcvt.c (dead_or_predicable): Update.
+ * ipa-inline-transform.c (inline_transform): Update.
+ * ipa-split.c (split_function): Update.
+ * ipa-utils.c (ipa_merge_profiles): Update.
+ * loop-doloop.c (add_test): Update.
+ * loop-unroll.c (unroll_loop_runtime_iterations): Update.
+ * lto-streamer-in.c (input_cfg): Update.
+ (input_function): Update.
+ * lto-streamer-out.c (output_cfg): Update.
+ * modulo-sched.c (sms_schedule): Update.
+ * postreload-gcse.c (eliminate_partially_redundant_load): Update.
+ * predict.c (maybe_hot_edge_p): Update.
+ (unlikely_executed_edge_p): Update.
+ (probably_never_executed_edge_p): Update.
+ (dump_prediction): Update.
+ (drop_profile): Update.
+ (propagate_unlikely_bbs_forward): Update.
+ (determine_unlikely_bbs): Update.
+ (force_edge_cold): Update.
+ * profile.c (compute_branch_probabilities): Update.
+ * reg-stack.c (better_edge): Update.
+ * shrink-wrap.c (handle_simple_exit): Update.
+ * tracer.c (better_p): Update.
+ * trans-mem.c (expand_transaction): Update.
+ (split_bb_make_tm_edge): Update.
+ * tree-call-cdce.c: Update.
+ * tree-cfg.c (gimple_find_sub_bbs): Update.
+ (gimple_split_edge): Update.
+ (gimple_duplicate_sese_region): Update.
+ (gimple_duplicate_sese_tail): Update.
+ (gimple_flow_call_edges_add): Update.
+ (insert_cond_bb): Update.
+ (execute_fixup_cfg): Update.
+ * tree-cfgcleanup.c (cleanup_control_expr_graph): Update.
+ * tree-complex.c (expand_complex_div_wide): Update.
+ * tree-eh.c (lower_resx): Update.
+ (unsplit_eh): Update.
+ (cleanup_empty_eh_move_lp): Update.
+ * tree-inline.c (copy_edges_for_bb): Update.
+ (freqs_to_counts): Update.
+ (copy_cfg_body): Update.
+ * tree-ssa-dce.c (remove_dead_stmt): Update.
+ * tree-ssa-ifcombine.c (update_profile_after_ifcombine): Update.
+ * tree-ssa-loop-im.c (execute_sm_if_changed): Update.
+ * tree-ssa-loop-ivcanon.c (remove_exits_and_undefined_stmts): Update.
+ (unloop_loops): Update.
+ * tree-ssa-loop-manip.c (tree_transform_and_unroll_loop): Update.
+ * tree-ssa-loop-split.c (connect_loops): Update.
+ (split_loop): Update.
+ * tree-ssa-loop-unswitch.c (hoist_guard): Update.
+ * tree-ssa-phionlycprop.c (propagate_rhs_into_lhs): Update.
+ * tree-ssa-phiopt.c (replace_phi_edge_with_variable): Update.
+ * tree-ssa-reassoc.c (branch_fixup): Update.
+ * tree-ssa-tail-merge.c (replace_block_by): Update.
+ * tree-ssa-threadupdate.c (remove_ctrl_stmt_and_useless_edges): Update.
+ (compute_path_counts): Update.
+ (update_profile): Update.
+ (recompute_probabilities): Update.
+ (update_joiner_offpath_counts): Update.
+ (estimated_freqs_path): Update.
+ (freqs_to_counts_path): Update.
+ (clear_counts_path): Update.
+ (ssa_fix_duplicate_block_edges): Update.
+ (duplicate_thread_path): Update.
+ * tree-switch-conversion.c (hoist_edge_and_branch_if_true): Update.
+ (case_bit_test_cmp): Update.
+ (collect_switch_conv_info): Update.
+ (gen_inbound_check): Update.
+ (do_jump_if_equal): Update.
+ (emit_cmp_and_jump_insns): Update.
+ * tree-tailcall.c (decrease_profile): Update.
+ (eliminate_tail_call): Update.
+ * tree-vect-loop-manip.c (slpeel_add_loop_guard): Update.
+ (vect_do_peeling): Update.
+ * tree-vect-loop.c (scale_profile_for_vect_loop): Update.
+ * ubsan.c (ubsan_expand_null_ifn): Update.
+ (ubsan_expand_ptr_ifn): Update.
+ * value-prof.c (gimple_divmod_fixed_value): Update.
+ (gimple_mod_pow2): Update.
+ (gimple_mod_subtract): Update.
+ (gimple_ic): Update.
+ (gimple_stringop_fixed_value): Update.
+
+2017-10-19 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/82618
+ * config/i386/i386.md (sub to cmp): New peephole2 pattern.
+
+2017-10-19 Alexander Monakov <amonakov@ispras.ru>
+
+ PR rtl-optimization/82395
+ * ira-color.c (allocno_priority_compare_func): Fix comparison step
+ based on non_spilled_static_chain_regno_p.
+
+2017-10-19 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386.c (output_387_binary_op): Rewrite SSE part.
+ (ix86_emit_mode_set): Rewrite insn mnemonic construction.
+ (ix86_prepare_fp_compare_args): Redefine is_sse as bool.
+
+2017-10-19 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/82596
+ * tree.c (array_at_struct_end_p): Handle STRING_CST.
+
+2017-10-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * asan.c (handle_builtin_alloca): Deal with all alloca variants.
+ (get_mem_refs_of_builtin_call): Likewise.
+ * builtins.c (expand_builtin_apply): Adjust call to
+ allocate_dynamic_stack_space.
+ (expand_builtin_alloca): For __builtin_alloca_with_align_and_max, pass
+ the third argument to allocate_dynamic_stack_space, otherwise -1.
+ (expand_builtin): Deal with all alloca variants.
+ (is_inexpensive_builtin): Likewise.
+ * builtins.def (BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX): New.
+ * calls.c (special_function_p): Deal with all alloca variants.
+ (initialize_argument_information): Adjust call to
+ allocate_dynamic_stack_space.
+ (expand_call): Likewise.
+ * cfgexpand.c (expand_call_stmt): Deal with all alloca variants.
+ * doc/extend.texi (Built-ins): Add __builtin_alloca_with_align_and_max
+ * explow.c (allocate_dynamic_stack_space): Add MAX_SIZE parameter and
+ use it for the stack usage computation.
+ * explow.h (allocate_dynamic_stack_space): Adjust prototype.
+ * function.c (gimplify_parameters): Call build_alloca_call_expr.
+ * gimple-ssa-warn-alloca.c (alloca_call_type): Simplify control flow.
+ Take into account 3rd argument of __builtin_alloca_with_align_and_max.
+ (in_loop_p): Remove first argument and useless check.
+ (pass_walloca::execute): Remove useless test and adjust call to above.
+ * gimple.c (gimple_build_call_from_tree): Deal with all alloc variants
+ * gimplify.c (gimplify_vla_decl): Call build_alloca_call_expr.
+ (gimplify_call_expr): Deal with all alloca variants.
+ * hsa-gen.c (gen_hsa_alloca): Likewise.
+ (gen_hsa_insns_for_call): Likewise.
+ * ipa-pure-const.c (special_builtin_state): Likewise.
+ * tree-chkp.c (chkp_build_returned_bound): Likewise.
+ * tree-object-size.c (alloc_object_size): Likewise.
+ * tree-ssa-alias.c (ref_maybe_used_by_call_p_1): Likewise.
+ (call_may_clobber_ref_p_1): Likewise.
+ * tree-ssa-ccp.c (evaluate_stmt): Likewise.
+ (ccp_fold_stmt): Likewise.
+ (optimize_stack_restore): Likewise.
+ * tree-ssa-dce.c (mark_stmt_if_obviously_necessary): Likewise.
+ (mark_all_reaching_defs_necessary_1): Likewise.
+ (propagate_necessity): Likewise.
+ (eliminate_unnecessary_stmts): Likewise.
+ * tree.c (build_common_builtin_nodes): Build
+ BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX.
+ (build_alloca_call_expr): New function.
+ * tree.h (ALLOCA_FUNCTION_CODE_P): New macro.
+ (CASE_BUILT_IN_ALLOCA): Likewise.
+ (build_alloca_call_expr): Declare.
+ * varasm.c (incorporeal_function_p): Deal with all alloca variants.
+
+2017-10-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR debug/82509
+ * dwarf2out.c (new_die_raw): New static inline function.
+ (new_die): Use it to create the DIE.
+ (add_AT_external_die_ref): Likewise.
+ (clone_die): Likewise.
+ (clone_as_declaration): Likewise.
+ (dwarf2out_vms_debug_main_pointer): Likewise.
+ (base_type_die): Likewise. Remove early return for corner cases.
+ Do not call add_pubtype on the DIE here.
+ (is_base_type): Remove ERROR_MARK and return 0 for VOID_TYPE.
+ (modified_type_die): Adjust the lookup for reverse order DIEs. Skip
+ typedefs for base types with DW_AT_endianity. Make sure a DIE with
+ native order exists for base types, attach the DIE manually and call
+ add_pubtype on it. Do not equate a reverse order DIE to the type.
+
+2017-10-19 Richard Earnshaw <rearnsha@arm.com>
+
+ * config/arm/arm.c (align_ok_ldrd_strd): New function.
+ (mem_ok_for_ldrd_strd): New parameter align. Extract the alignment of
+ the mem into it.
+ (gen_operands_ldrd_strd): Validate the alignment of the accesses.
+
+2017-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ * flag-types.h (enum sanitize_code): Add SANITIZE_BUILTIN. Or
+ SANITIZE_BUILTIN into SANITIZE_UNDEFINED.
+ * sanitizer.def (BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN,
+ BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT): New builtins.
+ * opts.c (sanitizer_opts): Add builtin.
+ * ubsan.c (instrument_builtin): New function.
+ (pass_ubsan::execute): Call it.
+ (pass_ubsan::gate): Enable even for SANITIZE_BUILTIN.
+ * doc/invoke.texi: Document -fsanitize=builtin.
+
+ * ubsan.c (ubsan_expand_null_ifn): Use _v1 suffixed type mismatch
+ builtins, store max (log2 (align), 0) into uchar field instead of
+ align into uptr field.
+ (ubsan_expand_objsize_ifn): Use _v1 suffixed type mismatch builtins,
+ store uchar 0 field instead of uptr 0 field.
+ (instrument_nonnull_return): Use _v1 suffixed nonnull return builtin,
+ instead of passing one address of struct with 2 locations pass
+ two addresses of structs with 1 location each.
+ * sanitizer.def (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH,
+ BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT,
+ BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN,
+ BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT): Removed.
+ (BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1,
+ BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT,
+ BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1,
+ BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT): New builtins.
+
+2017-10-19 Martin Liska <mliska@suse.cz>
+
+ PR driver/81829
+ * file-find.c (remove_prefix): Remove.
+ * file-find.h (remove_prefix): Likewise.
+ * gcc-ar.c: Remove smartness of lookup.
+
+2017-10-19 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/rs6000.md (*call_indirect_aix<mode>,
+ *call_value_indirect_aix<mode>, *call_indirect_elfv2<mode>,
+ *call_value_indirect_elfv2<mode>): Add correct mode to the unspec.
+
+2017-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82580
+ * config/i386/i386.md (setcc + movzbl to xor + setcc): New peephole2.
+ (setcc + and to xor + setcc): New peephole2.
+
+2017-10-19 Tom de Vries <tom@codesourcery.com>
+
+ * doc/sourcebuild.texi (Test Directives, Variants of
+ dg-require-support): Add dg-require-stack-size.
+
+2017-10-19 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82517
+ * gimplify.c (gimplify_decl_expr): Do not instrument variables
+ that have a large alignment.
+ (gimplify_target_expr): Likewise.
+
+2017-10-18 Segher Boessenkool <segher@kernel.crashing.org>
+
+ PR rtl-optimization/82602
+ * ira.c (rtx_moveable_p): Return false for volatile asm.
+
+2017-10-18 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/82580
+ * config/i386/i386-modes.def (CCGZ): New CC mode.
+ * config/i386/i386.md (sub<mode>3_carry_ccgz): New insn pattern.
+ * config/i386/predicates.md (ix86_comparison_operator):
+ Handle CCGZmode.
+ * config/i386/i386.c (ix86_expand_branch) <case E_TImode>:
+ Emulate LE, LEU, GT, GTU, LT, LTU, GE and GEU double-word comparisons
+ with double-word subtraction.
+ (put_condition_code): Handle CCGZmode.
+
+2017-10-18 Aldy Hernandez <aldyh@redhat.com>
+
+ * wide-int.cc (debug (const wide_int &)): New.
+ (debug (const wide_int *)): New.
+ (debug (const widest_int &)): New.
+ (debug (const widest_int *)): New.
+
+2017-10-18 Vladimir Makarov <vmakarov@redhat.com>
+
+ PR middle-end/82556
+ * lra-constraints.c (curr_insn_transform): Use non-input operand
+ instead of output one for matched reload.
+
+2017-10-18 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-loop-distribution.c (INCLUDE_ALGORITHM): New header file.
+ (tree-ssa-loop-ivopts.h): New header file.
+ (struct builtin_info): New fields.
+ (classify_builtin_1): Compute and record base and offset parts for
+ memset builtin partition by calling strip_offset.
+ (offset_cmp, fuse_memset_builtins): New functions.
+ (finalize_partitions): Fuse adjacent memset partitions by calling
+ above function.
+ * tree-ssa-loop-ivopts.c (strip_offset): Delete static declaration.
+ Expose the interface.
+ * tree-ssa-loop-ivopts.h (strip_offset): New declaration.
+
+2017-10-18 Bin Cheng <bin.cheng@arm.com>
+
+ PR tree-optimization/82574
+ * tree-loop-distribution.c (find_single_drs): New parameter. Check
+ that data reference must be executed exactly once per iteration
+ against the outermost loop in nest.
+ (classify_partition): Update call to above function.
+
+2017-10-18 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82591
+ * graphite.c (graphite_transform_loops): Move code gen message
+ printing ...
+ * graphite-isl-ast-to-gimple.c (graphite_regenerate_ast_isl):
+ Here. Handle scop_to_isl_ast failing.
+ (scop_to_isl_ast): Limit the number of ISL operations.
+
+2017-10-18 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c
+ (translate_isl_ast_to_gimple::set_rename): Simplify.
+ (translate_isl_ast_to_gimple::set_rename_for_each_def): Inline...
+ (graphite_copy_stmts_from_block): ... here.
+ (copy_bb_and_scalar_dependences): Simplify.
+ (add_parameters_to_ivs_params): Canonicalize.
+ (generate_entry_out_of_ssa_copies): Simplify.
+ * graphite-sese-to-poly.c (extract_affine_name): Simplify
+ by passing in ISL dimension.
+ (parameter_index_in_region_1): Rename to ...
+ (parameter_index_in_region): ... this.
+ (extract_affine): Adjust assert, pass down parameter index.
+ (add_param_constraints): Use range-info when available.
+ (build_scop_context): Adjust.
+ * sese.c (new_sese_info): Adjust.
+ (free_sese_info): Likewise.
+ * sese.h (bb_map_t, rename_map_t, phi_rename, init_back_edge_pair_t):
+ Remove unused typedefs.
+ (struct sese_info_t): Simplify rename_map, remove incomplete_phis.
+
+2017-10-18 Martin Liska <mliska@suse.cz>
+
+ * combine.c (simplify_compare_const): Add gcc_fallthrough.
+
+2017-10-18 Robin Dapp <rdapp@linux.vnet.ibm.com>
+
+ * config/s390/s390.c (s390_bb_fallthru_entry_likely): New function.
+ (s390_sched_init): Do not reset s390_sched_state if we entered the
+ current basic block via a fallthru edge and all others are unlikely.
+
+2017-10-18 Robin Dapp <rdapp@linux.vnet.ibm.com>
+
+ * config/s390/s390.c (NUM_SIDES): New variable.
+ (LONGRUNNING_THRESHOLD): New variable.
+ (LATENCY_FACTOR): New variable.
+ (s390_sched_score): Decrease score for long-running instructions on
+ wrong side.
+ (s390_sched_variable_issue): Perform bookkeeping for long-running
+ instructions.
+
+2017-10-18 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c (gcc_expression_from_isl_ast_expr_id):
+ Simplify with removal of the parameter rename map.
+ (set_rename): Likewise.
+ (should_copy_to_new_region): Likewise.
+ (graphite_copy_stmts_from_block): Likewise.
+ (copy_bb_and_scalar_dependences): Remove initialization of
+ unused copied_bb_map.
+ (copy_def): Remove.
+ (copy_internal_parameters): Likewise.
+ (graphite_regenerate_ast_isl): Do not call copy_internal_parameters.
+ * graphite-scop-detection.c (scop_detection::stmt_simple_for_scop_p):
+ Use INTEGRAL_TYPE_P.
+ (parameter_index_in_region_1): Rename to ...
+ (assign_parameter_index_in_region): ... this. Assert we have
+ a parameter we handle.
+ (scan_tree_for_params): Adjust.
+ * sese.h (parameter_rename_map_t): Remove.
+ (struct sese_info_t): Remove unused parameter_rename_map and
+ copied_bb_map members.
+ * sese.c (new_sese_info): Adjust.
+ (free_sese_info): Likewise.
+
+2017-10-18 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82545
+ * asan.c (asan_expand_poison_ifn): Do not put gimple stmt
+ on an abnormal edge.
+
+2017-10-18 Sebastian Huber <sebastian.huber@embedded-brains.de>
+
+ * doc/invoke.texi (ffunction-sections and fdata-sections):
+ Update.
+
+2017-10-17 Eric Botcazou <ebotcazou@adacore.com>
+
+ * tree-ssa-loop-ivopts.c (add_autoinc_candidates): Bail out only if
+ the use statement can throw internally.
+
+2017-10-17 Eric Botcazou <ebotcazou@adacore.com>
+
+ * config/visium/visium.c (visium_select_cc_mode): Return CCmode for
+ any RTX present on the RHS of a SET.
+ * compare-elim.c (try_eliminate_compare): Restore comment.
+
+2017-10-17 Jakub Jelinek <jakub@redhat.com>
+
+ * langhooks.h (struct lang_hooks): Document that tree_size langhook
+ may be also called on tcc_type nodes.
+ * langhooks.c (lhd_tree_size): Likewise.
+
+2017-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * gimple-ssa-sprintf.c (fmtwarn): Update for changed signature of
+ format_warning_at_substring.
+ (maybe_warn): Convert source_range * param to a location_t. Pass
+ UNKNOWN_LOCATION rather than NULL to fmtwarn.
+ (format_directive): Remove code to extract source_ranges and
+ source_range * in favor of just a location_t.
+ (parse_directive): Pass UNKNOWN_LOCATION rather than NULL to
+ fmtwarn.
+ * substring-locations.c (format_warning_va): Convert
+ source_range * param to a location_t.
+ (format_warning_at_substring): Likewise.
+ * substring-locations.h (format_warning_va): Likewise.
+ (format_warning_at_substring): Likewise.
+
+2017-10-17 Jan Hubicka <hubicka@ucw.cz>
+
+ * target.h (enum vect_cost_for_stmt): Add vec_gather_load and
+ vec_scatter_store
+ * tree-vect-stmts.c (record_stmt_cost): Make difference between normal
+ and scatter/gather ops.
+
+ * aarch64/aarch64.c (aarch64_builtin_vectorization_cost): Add
+ vec_gather_load and vec_scatter_store.
+ * arm/arm.c (arm_builtin_vectorization_cost): Likewise.
+ * powerpcspe/powerpcspe.c (rs6000_builtin_vectorization_cost): Likewise.
+ * rs6000/rs6000.c (rs6000_builtin_vectorization_cost): Likewise.
+ * s390/s390.c (s390_builtin_vectorization_cost): Likewise.
+ * spu/spu.c (spu_builtin_vectorization_cost): Likewise.
+ * i386/i386.c (x86_builtin_vectorization_cost): Likewise.
+
+2017-10-17 Uros Bizjak <ubizjak@gmail.com>
+
+ * reg-stack.c (compare_for_stack_reg): Add bool argument.
+ Detect FTST instruction and handle its register pops. Only pop
+ second operand if can_pop_second_op is true.
+ (subst_stack_regs_pat) <case COMPARE>: Detect FCOMI instruction to
+ set can_pop_second_op to false in the compare_for_stack_reg call.
+
+ * config/i386/i386.md (*cmpi<FPCMP:unord><MODEF:mode>): Only call
+ output_fp_compare for stack register operands.
+ * config/i386/i386.c (output_fp_compare): Do not output SSE compare
+ instructions here. Do not emit stack register pops here. Assert
+ that FCOMPP pops next to top stack register. Rewrite function.
+
+2017-10-17 Nathan Sidwell <nathan@acm.org>
+
+ PR middle-end/82577
+ * alias.c (compare_base_decls): Check HAS_DECL_ASSEMBLER_NAME_P,
+ use DECL_ASSEMBLER_NAME_RAW.
+
+ PR middle-end/82546
+ * tree.c (tree_code_size): Reformat. Punt to lang hook for unknown
+ TYPE nodes.
+
+2017-10-17 Qing Zhao <qing.zhao@oracle.com>
+ Wilco Dijkstra <wilco.dijkstra@arm.com>
+
+ * builtins.c (expand_builtin_update_setjmp_buf): Add a
+ converstion to Pmode from the buf_addr.
+
+2017-10-17 Richard Biener <rguenther@suse.de>
+
+ * graphite-dependences.c (scop_get_reads_and_writes): Change
+ output parameters to references.
+
+2017-10-17 Jackson Woodruff <jackson.woodruff@arm.com>
+
+ PR 71026/tree-optimization
+ * fold-const.c (distribute_real_division): Removed.
+ (fold_binary_loc): Remove calls to distribute_real_divison.
+
+2017-10-17 Richard Biener <rguenther@suse.de>
+
+ * graphite-scop-detection.c
+ (scop_detection::stmt_has_simple_data_refs_p): Always use
+ the full nest as region.
+ (try_generate_gimple_bb): Likewise.
+ * sese.c (scalar_evolution_in_region): Simplify now that
+ SCEV can handle instantiation in regions.
+ * tree-scalar-evolution.c (instantiate_scev_name): Also instantiate
+ in the non-loop part of a function if requested.
+
+2017-10-17 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82563
+ * graphite-isl-ast-to-gimple.c (generate_entry_out_of_ssa_copies):
+ New function.
+ (graphite_regenerate_ast_isl): Call it.
+ * graphite-scop-detection.c (build_scops): Remove entry edge split.
+
+2017-10-17 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/82549
+ * fold-const.c (optimize_bit_field_compare, fold_truth_andor_1):
+ Formatting fixes. Instead of calling make_bit_field_ref with negative
+ bitpos return 0.
+
+2017-10-17 Olga Makhotina <olga.makhotina@intel.com>
+
+ * config/i386/avx512dqintrin.h (_mm_mask_reduce_sd,
+ _mm_maskz_reduce_sd, _mm_mask_reduce_ss,=20
+ _mm_maskz_reduce_ss): New.
+ * config/i386/i386-builtin.def (__builtin_ia32_reducesd_mask,
+ __builtin_ia32_reducess_mask): Ditto..
+ (__builtin_ia32_reducesd, __builtin_ia32_reducess): Remove.
+ * config/i386/sse.md (reduces<mode>): Renamed to ...
+ (reduces<mode><mask_scalar_name>): ... this.
+ (vreduce<ssescalarmodesuffix>\t{%3, %2, %1, %0|%0, %1, %2, %3}): Changed
+ to ...
+ (vreduce<ssescalarmodesuffix>\t{%3, %2, %1, %0<mask_scalar_operand4>|
+ %0<mask_scalar_operand4>, %1, %2, %3}): ... this.
+
+2017-10-16 David Malcolm <dmalcolm@redhat.com>
+
+ * Makefile.in (OBJS): Add unique-ptr-tests.o.
+ * selftest-run-tests.c (selftest::run_tests): Call
+ selftest::unique_ptr_tests_cc_tests.
+ * selftest.h (selftest::unique_ptr_tests_cc_tests): New decl.
+ * unique-ptr-tests.cc: New file.
+
+2017-10-16 Vladimir Makarov <vmakarov@redhat.com>
+
+ PR sanitizer/82353
+ * lra.c (collect_non_operand_hard_regs): Don't ignore operator
+ locations.
+ * lra-lives.c (bb_killed_pseudos, bb_gen_pseudos): Move up.
+ (make_hard_regno_born, make_hard_regno_dead): Update
+ bb_killed_pseudos and bb_gen_pseudos for fixed regs.
+
+2017-10-16 Jeff Law <law@redhat.com>
+
+ * tree-ssa-dse.c (live_bytes_read): Fix thinko.
+
+2017-10-16 Jan Hubicka <hubicka@ucw.cz>
+
+ * x86-tune-costs.h (znver1_cost): Fix move cost tables.
+
+2017-10-16 Olivier Hainque <hainque@adacore.com>
+
+ * gcc/config.gcc (powerpc*-*-*spe*): Pick 8548 as the default
+ with_cpu if we were configured for an e500v2 target cpu name.
+
+2017-10-16 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * config/arm/arm-cpus.in (cortex-m33): Add nodsp option.
+ * doc/invoke.texi: Document +nodsp as a valid extension for
+ -mcpu=cortex-m33.
+
+2017-10-16 Martin Liska <mliska@suse.cz>
+
+ * sbitmap.c (bitmap_bit_in_range_p_checking): New function.
+ (test_set_range): Likewise.
+ (test_range_functions): Rename to ...
+ (test_bit_in_range): ... this.
+ (sbitmap_c_tests): Add new test.
+
+2017-10-16 Tamar Christina <tamar.christina@arm.com>
+
+ * config/aarch64/arm_neon.h (vdot_u32, vdotq_u32, vdot_s32, vdotq_s32): New.
+ (vdot_lane_u32, vdot_laneq_u32, vdotq_lane_u32, vdotq_laneq_u32): New.
+ (vdot_lane_s32, vdot_laneq_s32, vdotq_lane_s32, vdotq_laneq_s32): New.
+
+2017-10-16 Tamar Christina <tamar.christina@arm.com>
+
+ * config/aarch64/aarch64-builtins.c
+ (aarch64_types_quadopu_lane_qualifiers): New.
+ (TYPES_QUADOPU_LANE): New.
+ * config/aarch64/aarch64-simd.md (aarch64_<sur>dot<vsi2qi>): New.
+ (<sur>dot_prod<vsi2qi>, aarch64_<sur>dot_lane<vsi2qi>): New.
+ (aarch64_<sur>dot_laneq<vsi2qi>): New.
+ * config/aarch64/aarch64-simd-builtins.def (sdot, udot): New.
+ (sdot_lane, udot_lane, sdot_laneq, udot_laneq): New.
+ * config/aarch64/iterators.md (sur): Add UNSPEC_SDOT, UNSPEC_UDOT.
+ (Vdottype, DOTPROD): New.
+ (sur): Add SDOT and UDOT.
+
+2017-10-16 Tamar Christina <tamar.christina@arm.com>
+
+ * config/aarch64/aarch64.h (AARCH64_FL_DOTPROD): New.
+ (AARCH64_ISA_DOTPROD, TARGET_DOTPROD): New.
+ * config/aarch64/aarch64-c.c (aarch64_update_cpp_builtins): Add TARGET_DOTPROD.
+ * config/aarch64/aarch64-option-extensions.def (dotprod): New.
+ * config/aarch64/aarch64-cores.def (cortex-a55, cortex-a75): Enable TARGET_DOTPROD.
+ (cortex-a75.cortex-a55): Likewise.
+ * doc/invoke.texi (aarch64-feature-modifiers): Document dotprod.
+
+2017-10-16 Tamar Christina <tamar.christina@arm.com>
+
+ * config/arm/arm-builtins.c (arm_unsigned_uternop_qualifiers): New.
+ (UTERNOP_QUALIFIERS, arm_umac_lane_qualifiers, UMAC_LANE_QUALIFIERS): New.
+ * config/arm/arm_neon_builtins.def (sdot, udot, sdot_lane, udot_lane): new.
+ * config/arm/iterators.md (DOTPROD, VSI2QI, vsi2qi): New.
+ (UNSPEC_DOT_S, UNSPEC_DOT_U, opsuffix): New.
+ * config/arm/neon.md (neon_<sup>dot<vsi2qi>): New.
+ (neon_<sup>dot_lane<vsi2qi>, <sup>dot_prod<vsi2qi>): New.
+ * config/arm/types.md (neon_dot, neon_dot_q): New.
+ * config/arm/unspecs.md (sup): Add UNSPEC_DOT_S, UNSPEC_DOT_U.
+
+2017-10-16 Tamar Christina <tamar.christina@arm.com>
+
+ * config/arm/arm.h (TARGET_DOTPROD): New.
+ * config/arm/arm.c (arm_arch_dotprod): New.
+ (arm_option_reconfigure_globals): Add arm_arch_dotprod.
+ * config/arm/arm-c.c (__ARM_FEATURE_DOTPROD): New.
+ * config/arm/arm-cpus.in (armv8.2-a): Enabled +dotprod.
+ (feature dotprod, group dotprod, ALL_SIMD_INTERNAL): New.
+ (ALL_FPU_INTERNAL): Use ALL_SIMD_INTERNAL.
+ * config/arm/t-multilib (v8_2_a_simd_variants): Add dotprod.
+ * doc/invoke.texi (armv8.2-a): Document dotprod
+
+2017-10-14 Jan Hubicka <hubicka@ucw.cz>
+
+ * i386.c (ix86_vec_cost): New function.
+ (ix86_rtx_costs): Handle vector operations better.
+ * i386.h (struct processor_costs): Add sse_op, fmasd, fmass.
+ * x86-tune-costs.h: Add new costs to all tables.
+
+2017-10-14 Jan Hubicka <hubicka@ucw.cz>
+
+ * i386.c (ix86_rtx_costs): Make difference between x87 and SSE
+ operations.
+ * i386.h (struct processor_costs): Add addss, mulss, mulsd, divss,
+ divsd, sqrtss and sqrtsd
+ * x86-tune-costs.h: Add new entries to all costs.
+ (znver1_cost): Fix to match real instruction latencies.
+
+2017-10-14 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+ Michael Collison <michael.collison@arm.com>
+
+ * compare-elim.c: Include emit-rtl.h.
+ (can_merge_compare_into_arith): New function.
+ (try_validate_parallel): Likewise.
+ (try_merge_compare): Likewise.
+ (try_eliminate_compare): Call the above when no previous clobber
+ is available.
+ (execute_compare_elim_after_reload): Add DF_UD_CHAIN and DF_DU_CHAIN
+ dataflow problems.
+
+2017-10-14 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/62263
+ PR middle-end/82498
+ * tree-ssa-phiopt.c (value_replacement): Comment fix. Handle
+ up to 2 preparation statements for ASSIGN in MIDDLE_BB.
+
+ PR middle-end/62263
+ PR middle-end/82498
+ * tree-ssa-forwprop.c (simplify_rotate): Allow def_arg1[N]
+ to be any operand_equal_p operands. For & (B - 1) require
+ B to be power of 2. Recognize
+ (X << (Y & (B - 1))) | (X >> ((-Y) & (B - 1))) and similar patterns.
+
+2017-10-14 Uros Bizjak <ubizjak@gmail.com>
+
+ PR bootstrap/82553
+ * optabs.c (expand_memory_blockage): Fix call of
+ targetm.have_memory_blockage.
+
+2017-10-14 Jakub Jelinek <jakub@redhat.com>
+
+ PR bootstrap/82548
+ * config.gcc (*-*-solaris2*, i[34567]86-*-cygwin*,
+ x86_64-*-cygwin*, i[34567]86-*-mingw* | x86_64-*-mingw*): Append
+ objects to extra_objs instead of overwriting it.
+
+2017-10-14 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/sync.md (FILD_ATOMIC/FIST_ATOMIC FP load peephole2):
+ Use any_fp_register_operand as operand[3] predicate. Simplify
+ equality test for operands[2] and operands[4] memory location.
+ (LDX_ATOMIC/STX_ATOMIC FP load peephole2): Ditto.
+ (FILD_ATOMIC/FIST_ATOMIC FP load peephole2 with mem blockage): New.
+ (LDX_ATOMIC/LDX_ATOMIC FP load peephole2 with mem blockage): Ditto.
+ (FILD_ATOMIC/FIST_ATOMIC FP store peephole2): Use
+ any_fp_register_operand as operand[1] predicate. Simplify
+ equality test for operands[0] and operands[3] memory location.
+ (LDX_ATOMIC/STX_ATOMIC FP store peephole2): Ditto.
+ (FILD_ATOMIC/FIST_ATOMIC FP store peephole2 with mem blockage): New.
+ (LDX_ATOMIC/LDX_ATOMIC FP storepeephole2 with mem blockage): Ditto.
+
+2017-10-14 Uros Bizjak <ubizjak@gmail.com>
+
+ * target-insns.def: Add memory_blockage.
+ * optabs.c (expand_memory_blockage): New function.
+ (expand_asm_memory_barrier): Rename ...
+ (expand_asm_memory_blockage): ... to this.
+ (expand_mem_thread_fence): Call expand_memory_blockage
+ instead of expand_asm_memory_barrier.
+ (expand_mem_singnal_fence): Ditto.
+ (expand_atomic_load): Ditto.
+ (expand_atomic_store): Ditto.
+ * doc/md.texi (Standard Pattern Names For Generation):
+ Document memory_blockage instruction pattern.
+
+2017-10-13 Sebastian Perta <sebastian.perta@renesas.com>
+
+ * config/rl78/rl78.c (rl78_emit_libcall): New function.
+ * config/rl78/rl78-protos.h (rl78_emit_libcall): New function.
+ * config/rl78/rl78.md: New define_expand "adddi3".
+
+2017-10-13 Jan Hubicka <hubicka@ucw.cz>
+
+ * cfghooks.c (verify_flow_info): Disable check that all probabilities
+ are set correctly.
+
+2017-10-13 Jeff Law <law@redhat.com>
+
+ * tree-ssa-reassoc.c (reassociate_bb): Clarify code slighly.
+
+2017-10-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82274
+ * internal-fn.c (expand_mul_overflow): If both operands have
+ the same highpart of -1 or 0 and the topmost bit of lowpart
+ is different, overflow is if res <= 0 rather than res < 0.
+
+2017-10-13 Pat Haugen <pthaugen@us.ibm.com>
+
+ * config/rs6000/rs6000.c (rs6000_builtin_vectorization_cost): Remove
+ TARGET_P9_VECTOR code for unaligned_load case.
+
+2017-10-13 Jan Hubicka <hubicka@ucw.cz>
+
+ * cfghooks.c (verify_flow_info): Check that edge probabilities are set.
+
+2017-10-13 Nathan Sidwell <nathan@acm.org>
+
+ * tree-core.h (tree_contains_struct): Make bool.
+ * tree.c (tree_contains_struct): Likewise.
+ * tree.h (MARK_TS_BASE): Remove do ... while (0) idiom.
+ (MARK_TS_TYPED, MARK_TS_COMMON, MARK_TS_TYPE_COMMON,
+ MARK_TS_TYPE_WITH_LANG_SPECIFIC, MARK_TS_DECL_MINIMAL,
+ MARK_TS_DECL_COMMON, MARK_TS_DECL_WRTL, MARK_TS_DECL_WITH_VIS,
+ MARK_TS_DECL_NON_COMMON): Likewise, use comma operator.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c
+ (translate_isl_ast_to_gimple::get_rename_from_scev): Remove unused
+ parameters and dominance check.
+ (translate_isl_ast_to_gimple::graphite_copy_stmts_from_block): Adjust.
+ (translate_isl_ast_to_gimple::copy_bb_and_scalar_dependences): Likewise.
+ (translate_isl_ast_to_gimple::graphite_regenerate_ast_isl):
+ Do not update SSA form here or do intermediate IL verification.
+ * graphite.c: Include tree-ssa.h and tree-into-ssa.h.
+ (graphite_initialize): Remove check on the number of loops in
+ the function and inline into graphite_transform_loops.
+ (graphite_finalize): Inline into graphite_transform_loops.
+ (graphite_transform_loops): Perform SSA update and IL verification
+ here.
+ * params.def (PARAM_GRAPHITE_MIN_LOOPS_PER_FUNCTION): Remove.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c (max_mode_int_precision,
+ graphite_expression_type_precision): Avoid global constructor
+ by moving ...
+ (translate_isl_ast_to_gimple::translate_isl_ast_to_gimple): Here.
+ (translate_isl_ast_to_gimple::graphite_expr_type): Add type member.
+ (translate_isl_ast_to_gimple::translate_isl_ast_node_for): Use it.
+ (translate_isl_ast_to_gimple::build_iv_mapping): Likewise.
+ (translate_isl_ast_to_gimple::graphite_create_new_guard): Likewise.
+ * graphite-sese-to-poly.c (build_original_schedule): Return nothing.
+
+2017-10-13 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/82499
+ * config/i386/i386.h (ix86_red_zone_size): New.
+ * config/i386/i386.md (push peephole2s): Replace
+ "!ix86_using_red_zone ()" with "ix86_red_zone_size == 0".
+
+2017-10-13 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * combine.c (can_change_dest_mode): Reject changes in
+ REGMODE_NATURAL_SIZE.
+
+2017-10-13 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * cfgexpand.c (expand_debug_expr): Use GET_MODE_UNIT_BITSIZE.
+ (expand_debug_source_expr): Likewise.
+ * combine.c (combine_simplify_rtx): Likewise.
+ * cse.c (fold_rtx): Likewise.
+ * fwprop.c (canonicalize_address): Likewise.
+ * targhooks.c (default_shift_truncation_mask): Likewise.
+
+2017-10-13 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * optabs.c (add_equal_note): Use GET_MODE_UNIT_SIZE.
+ (widened_mode): Likewise.
+ (expand_unop): Likewise.
+ * ree.c (transform_ifelse): Likewise.
+ (merge_def_and_ext): Likewise.
+ (combine_reaching_defs): Likewise.
+ * simplify-rtx.c (simplify_unary_operation_1): Likewise.
+
+2017-10-13 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * caller-save.c (replace_reg_with_saved_mem): Use byte_lowpart_offset.
+ * combine.c (gen_lowpart_for_combine): Likewise.
+ * dwarf2out.c (rtl_for_decl_location): Likewise.
+ * final.c (alter_subreg): Likewise.
+ * rtlhooks.c (gen_lowpart_general): Likewise.
+ (gen_lowpart_if_possible): Likewise.
+
+2017-10-13 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * calls.c (expand_call): Use subreg_lowpart_offset.
+ * cse.c (cse_insn): Likewise.
+ * regcprop.c (copy_value): Likewise.
+ (copyprop_hardreg_forward_1): Likewise.
+
+2017-10-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82524
+ * config/i386/i386.md (addqi_ext_1, andqi_ext_1,
+ *andqi_ext_1_cc, *<code>qi_ext_1, *xorqi_ext_1_cc): Change
+ =Q constraints to +Q and into insn condition add check
+ that operands[0] and operands[1] are equal.
+ (*addqi_ext_2, *andqi_ext_2, *<code>qi_ext_2): Change
+ =Q constraints to +Q and into insn condition add check
+ that operands[0] is equal to either operands[1] or operands[2].
+
+ PR target/82498
+ * fold-const.c (fold_binary_loc) <bit_rotate>: Code cleanups,
+ instead of handling MINUS_EXPR twice (once for each argument),
+ canonicalize operand order and handle just once, use rtype where
+ possible. Handle (A << B) | (A >> (-B & (Z - 1))).
+
+ PR target/82498
+ * config/i386/ia32intrin.h (__rold, __rord, __rolq, __rorq): Allow
+ any values of __C while still being pattern recognizable as a simple
+ rotate instruction.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82451
+ Revert
+ 2017-10-02 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82355
+ * graphite-isl-ast-to-gimple.c (build_iv_mapping): Also build
+ a mapping for the enclosing loop but avoid generating one for
+ the loop tree root.
+ (copy_bb_and_scalar_dependences): Remove premature codegen
+ error on PHIs in blocks duplicated into multiple places.
+ * graphite-scop-detection.c
+ (scop_detection::stmt_has_simple_data_refs_p): For a loop not
+ in the region use it as loop and nest to analyze the DR in.
+ (try_generate_gimple_bb): Likewise.
+ * graphite-sese-to-poly.c (extract_affine_chrec): Adjust.
+ (add_loop_constraints): For blocks in a loop not in the region
+ create a dimension with a single iteration.
+ * sese.h (gbb_loop_at_index): Remove assert.
+
+ * cfgloop.c (loop_preheader_edge): For the loop tree root
+ return the single successor of the entry block.
+ * graphite-isl-ast-to-gimple.c (graphite_regenerate_ast_isl):
+ Reset the SCEV hashtable and niters.
+ * graphite-scop-detection.c
+ (scop_detection::graphite_can_represent_scev): Add SCOP parameter,
+ assert that we only have POLYNOMIAL_CHREC that vary in loops
+ contained in the region.
+ (scop_detection::graphite_can_represent_expr): Adjust.
+ (scop_detection::stmt_has_simple_data_refs_p): For loops
+ not in the region set loop to NULL. The nest is now the
+ entry edge to the region.
+ (try_generate_gimple_bb): Likewise.
+ * sese.c (scalar_evolution_in_region): Adjust for
+ instantiate_scev change.
+ * tree-data-ref.h (graphite_find_data_references_in_stmt):
+ Make nest parameter the edge into the region.
+ (create_data_ref): Likewise.
+ * tree-data-ref.c (dr_analyze_indices): Make nest parameter an
+ entry edge into a region and adjust instantiate_scev calls.
+ (create_data_ref): Likewise.
+ (graphite_find_data_references_in_stmt): Likewise.
+ (find_data_references_in_stmt): Pass the loop preheader edge
+ from the nest argument.
+ * tree-scalar-evolution.h (instantiate_scev): Make instantiate_below
+ parameter the edge into the region.
+ (instantiate_parameters): Use the loop preheader edge as entry.
+ * tree-scalar-evolution.c (analyze_scalar_evolution): Handle
+ NULL loop.
+ (get_instantiated_value_entry): Make instantiate_below parameter
+ the edge into the region.
+ (instantiate_scev_name): Likewise. Adjust dominance checks,
+ when we cannot use loop-based instantiation instantiate by
+ walking use-def chains.
+ (instantiate_scev_poly): Adjust.
+ (instantiate_scev_binary): Likewise.
+ (instantiate_scev_convert): Likewise.
+ (instantiate_scev_not): Likewise.
+ (instantiate_array_ref): Remove.
+ (instantiate_scev_3): Likewise.
+ (instantiate_scev_2): Likewise.
+ (instantiate_scev_1): Likewise.
+ (instantiate_scev_r): Do not blindly handle N-operand trees.
+ Do not instantiate array-refs. Handle all constants and invariants.
+ (instantiate_scev): Make instantiate_below parameter
+ the edge into the region.
+ (resolve_mixers): Use the loop preheader edge for the region
+ parameter to instantiate_scev_r.
+ * tree-ssa-loop-prefetch.c (determine_loop_nest_reuse): Adjust.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82525
+ * graphite-isl-ast-to-gimple.c
+ (translate_isl_ast_to_gimple::widest_int_from_isl_expr_int): Split
+ out from ...
+ (translate_isl_ast_to_gimple::gcc_expression_from_isl_expr_int): Here.
+ Fail code generation when we cannot represent the isl integer.
+ (binary_op_to_tree): Elide modulo operations that are no-ops
+ in the type we code generate. Remove now superfluous code
+ generation errors.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ * graphite-scop-detection.c (loop_ivs_can_be_represented): Remove.
+ (scop_detection::harmful_loop_in_region): Remove premature
+ IV type restriction.
+ (scop_detection::graphite_can_represent_scev): We can handle
+ pointer IVs just fine.
+
+2017-10-13 Alan Modra <amodra@gmail.com>
+
+ * doc/extend.texi (Extended Asm <Clobbers>): Rename to
+ "Clobbers and Scratch Registers". Add paragraph on
+ alternative to clobbers for scratch registers and OpenBLAS
+ example.
+
+2017-10-13 Alan Modra <amodra@gmail.com>
+
+ * doc/extend.texi (Clobbers): Correct vax example. Delete old
+ example of a memory input for a string of known length. Move
+ commentary out of table. Add a number of new examples
+ covering array memory inputs.
+
+2017-10-12 Martin Liska <mliska@suse.cz>
+
+ PR tree-optimization/82493
+ * sbitmap.c (bitmap_bit_in_range_p): Fix the implementation.
+ (test_range_functions): New function.
+ (sbitmap_c_tests): Likewise.
+ * selftest-run-tests.c (selftest::run_tests): Run new tests.
+ * selftest.h (sbitmap_c_tests): New function.
+
+ * tree-ssa-dse.c (live_bytes_read): Fix thinko.
+
+2017-10-12 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/amo.h: Fix spacing issue.
+
+2017-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82498
+ * config/i386/i386.md (*ashl<mode>3_mask_1,
+ *<shift_insn><mode>3_mask_1, *<rotate_insn><mode>3_mask_1,
+ *<btsc><mode>_mask_1, *btr<mode>_mask_1): New define_insn_and_split
+ patterns.
+
+2017-10-12 Jan Hubicka <hubicka@ucw.cz>
+
+ * profile-count.h (safe_scale_64bit): Fix GCC4.x path.
+ (profile_probability): Set max_probability
+ to (uint32_t) 1 << (n_bits - 2) and update accessors to avoid overlfows
+ in temporaries.
+ * profile-count.c (profile_probability::differs_from_p): Do not
+ rely on max_probaiblity == 10000
+
+2017-10-12 Jeff Law <law@redhat.com>
+
+ * tree-ssa-dse.c (valid_ao_ref_for_dse): Reject ao_refs with
+ negative offsets.
+
+2017-10-12 Martin Sebor <msebor@redhat.com>
+
+ PR other/82301
+ PR c/82435
+ * cgraphunit.c (maybe_diag_incompatible_alias): New function.
+ (handle_alias_pairs): Call it.
+ * common.opt (-Wattribute-alias): New option.
+ * doc/extend.texi (ifunc attribute): Discuss C++ specifics.
+ * doc/invoke.texi (-Wattribute-alias): Document.
+
+2017-10-12 Vladimir Makarov <vmakarov@redhat.com>
+
+ Revert
+ 2017-10-11 Vladimir Makarov <vmakarov@redhat.com>
+ PR sanitizer/82353
+ * lra.c (collect_non_operand_hard_regs): Don't ignore operator
+ locations.
+ * lra-lives.c (bb_killed_pseudos, bb_gen_pseudos): Move up.
+ (make_hard_regno_born, make_hard_regno_dead): Update
+ bb_killed_pseudos and bb_gen_pseudos.
+
+2017-10-12 Jan Hubicka <hubicka@ucw.cz>
+
+ * config/i386/x86-tune-sched.c (ix86_adjust_cost): Fix Zen support.
+
+2017-10-12 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/alpha/alpha.c (alpha_split_conditional_move):
+ Use std::swap instead of manually swapping.
+ (alpha_stdarg_optimize_hook): Ditto.
+ (alpha_canonicalize_comparison): Ditto.
+
+2017-10-12 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-loop-distribution.c (struct builtin_info): New struct.
+ (struct partition): Refactor fields into struct builtin_info.
+ (partition_free): Free struct builtin_info.
+ (build_size_arg_loc, build_addr_arg_loc): Delete.
+ (generate_memset_builtin, generate_memcpy_builtin): Get memory range
+ information from struct builtin_info.
+ (find_single_drs): New function refactored from classify_partition.
+ Also moved builtin validity checks to this function.
+ (compute_access_range, alloc_builtin): New functions.
+ (classify_builtin_st, classify_builtin_ldst): New functions.
+ (classify_partition): Refactor code into functions find_single_drs,
+ classify_builtin_st and classify_builtin_ldst.
+ (distribute_loop): Don't do runtime alias check when distributing
+ loop nest.
+ (find_seed_stmts_for_distribution): New function.
+ (pass_loop_distribution::execute): Refactor code finding seed
+ stmts into above function. Support distribution for the innermost
+ two-level loop nest. Adjust dump information.
+
+2017-10-12 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-loop-distribution.c: Adjust the general comment.
+ (NUM_PARTITION_THRESHOLD): New macro.
+ (ssa_name_has_uses_outside_loop_p): Support loop nest distribution.
+ (classify_partition): Skip builtin pattern of loop nest's inner loop.
+ (merge_dep_scc_partitions): New parameter ignore_alias_p and use it
+ in call to build_partition_graph.
+ (finalize_partitions): New parameter. Make loop distribution more
+ conservative by fusing more partitions.
+ (distribute_loop): Don't do runtime alias check in case of loop nest
+ distribution.
+ (find_seed_stmts_for_distribution): New function.
+ (prepare_perfect_loop_nest): New function.
+ (pass_loop_distribution::execute): Refactor code finding seed stmts
+ and loop nest into above functions. Support loop nest distribution.
+ Adjust dump information accordingly.
+
+2017-10-12 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-loop-distribution.c (break_alias_scc_partitions): Add comment
+ and set PTYPE_SEQUENTIAL for merged partition.
+
+2017-10-12 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/69728
+ Revert
+ 2017-09-19 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/69728
+ * graphite-sese-to-poly.c (schedule_error): New global.
+ (add_loop_schedule): Handle empty domain by failing the
+ schedule.
+ (build_original_schedule): Handle schedule_error.
+
+ * graphite-sese-to-poly.c (add_loop_schedule): Handle empty
+ domain by returning an unchanged schedule.
+
+2017-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * genrecog.c (validate_pattern): For VEC_SELECT verify that
+ CONST_INT selectors are 0 to GET_MODE_NUNITS (imode) - 1.
+
+2017-10-12 Aldy Hernandez <aldyh@redhat.com>
+
+ * Makefile.in (TAGS): Merge all the *.def files into one pattern.
+ Handle params.def.
+
+2017-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82159
+ * expr.c (store_field): Don't optimize away bitsize == 0 store
+ from CALL_EXPR with addressable return type.
+
+2017-10-11 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/rs6000.h (TARGET_ISEL64): Delete.
+ * config/rs6000/rs6000.md (sel): Delete mode attribute.
+ (mov<mode>cc, isel_signed_<mode>, isel_unsigned_<mode>,
+ *isel_reversed_signed_<mode>, *isel_reversed_unsigned_<mode>): Use
+ TARGET_ISEL instead of TARGET_ISEL<sel>.
+
+2017-10-11 David Edelsohn <dje.gcc@gmail.com>
+
+ * config/rs6000/rs6000.c
+ (rs6000_xcoff_asm_output_aligned_decl_common): Test for NULL decl.
+
+2017-10-11 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/predicates.md (zero_constant, all_ones_constant):
+ Move up in file.
+ (reg_or_cint_operand): Fix comment.
+ (reg_or_zero_operand): New predicate.
+ * config/rs6000/rs6000-protos.h (output_isel): Delete.
+ * config/rs6000/rs6000.c (output_isel): Delete.
+ * config/rs6000/rs6000.md (isel_signed_<mode>): Use reg_or_zero_operand
+ instead of reg_or_cint_operand. Output instruction directly (not via
+ output_isel).
+ (isel_unsigned_<mode>): Ditto.
+ (*isel_reversed_signed_<mode>): Use reg_or_zero_operand instead of
+ gpc_reg_operand. Add an instruction alternative for this. Output
+ instruction directly.
+ (*isel_reversed_unsigned_<mode>): Ditto.
+
+2017-10-11 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386.c (ix86_canonicalize_comparison): New function.
+ (TARGET_CANONICALIZE_COMPARISON): Define.
+
+2017-10-11 Qing Zhao <qing.zhao@oracle.com>
+
+ PR target/81422
+ * config/aarch64/aarch64.c (aarch64_load_symref_appropriately):
+ Check whether the dest is REG before adding REG_EQUIV note.
+
+2017-10-11 Vladimir Makarov <vmakarov@redhat.com>
+
+ PR sanitizer/82353
+ * lra.c (collect_non_operand_hard_regs): Don't ignore operator
+ locations.
+ * lra-lives.c (bb_killed_pseudos, bb_gen_pseudos): Move up.
+ (make_hard_regno_born, make_hard_regno_dead): Update
+ bb_killed_pseudos and bb_gen_pseudos.
+
+2017-10-11 Nathan Sidwell <nathan@acm.org>
+
+ * incpath.h (enum incpath_kind): Name enum, prefix values.
+ (add_path, add_cpp_dir_path, get_added_cpp_dirs): Use incpath_kind.
+ * incpath.c (heads, tails): Use INC_MAX.
+ (add_env_var_paths, add_standard_paths): Use incpath_kind.
+ (merge_include_chains, split_quote_chain,
+ register_include_chains): Update incpath_kind names.
+ (add_cpp_dir_path, add_path, get_added_cpp_dirs): Use incpath_kind.
+ * config/darwin-c.c (add_system_framework_path): Update incpath_kind
+ names.
+ (add_framework_path, darwin_register_objc_includes): Likewise.
+ * config/vms/vms-c.c (vms_c_register_includes): Likewise.
+
+2017-10-11 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386.md (*cmp<X87MODEF:mode>_<SWI24:mode>_i387):
+ Do not use float_operator operator predicate.
+ (*cmp<X87MODEF:mode>_<SWI24:mode>_cc_i387): Ditto.
+ * config/i386/predicates.md (float_operator): Remove predicate.
+
+2017-10-11 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386.md (*jcc<mode>_0_i387): Remove insn pattern.
+ (*jccxf_i387): Ditto.
+ (*jcc<mode>_i387): Ditto.
+ (*jccu<mode>_i387): Ditto.
+ (*jcc<X87MODEF:mode>_<SWI24:mode>_i387): Ditto.
+ (*jcc_*_i387 splitters): Remove.
+ * config/i386/i386-protos.h (ix86_split_fp_branch): Remove prototype.
+ * config/i386/i386.c (ix86_split_fp_branch): Remove.
+ * config/i386/predicates.md (ix86_swapped_fp_comparison_operator):
+ Remove predicate.
+
+2017-10-11 Jan Hubicka <hubicka@ucw.cz>
+
+ * profile-count.h (slow_safe_scale_64bit): New function.
+ (safe_scale_64bit): New inline.
+ (profile_count::max_safe_multiplier): Remove; use safe_scale_64bit.
+ * profile-count.c: Include wide-int.h
+ (slow_safe_scale_64bit): New.
+
+2017-10-11 Nathan Sidwell <nathan@acm.org>
+
+ * tree.h (DECL_ASSEMBLER_NAME_SET_P): Don't check
+ HAS_DECL_ASSEMBLER_NAME_P.
+ * gimple-expr.c (gimple_decl_printable_name: Check
+ HAS_DECL_ASSEMBLER_NAME_P too.
+ * ipa-utils.h (type_in_anonymous_namespace_p): Check
+ DECL_ASSEMBLER_NAME_SET_P of TYPE_NAME.
+ (odr_type_p): No need to assert TYPE_NAME is a TYPE_DECL.
+ * passes.c (rest_of_decl_compilation): Check
+ HAS_DECL_ASSEMBLER_NAME_P too.
+ * recog.c (verify_changes): Likewise.
+ * tree-pretty-print.c (dump_decl_name): Likewise.
+ * tree-ssa-structalias.c (alias_get_name): Likewise. Reimplement.
+
+ * tree.h (DECL_ASSEMBLER_NAME_RAW): New.
+ (SET_DECL_ASSEMBLER_NAME): Use it.
+ (DECL_ASSEMBLER_NAME_SET_P): Likewise.
+ (COPY_DECL_ASSEMBLER_NAME): Likewise.
+ * tree.c (decl_assembler_name): Use DECL_ASSEMBLER_NAME_RAW.
+
+2017-10-11 Jan Hubicka <hubicka@ucw.cz>
+
+ * config.gcc (i386, x86_64): Add extra objects.
+ * config/i386/i386-protos.h (ix86_rip_relative_addr_p): Declare.
+ (ix86_min_insn_size): Declare.
+ (ix86_issue_rate): Declare.
+ (ix86_adjust_cost): Declare.
+ (ia32_multipass_dfa_lookahead): Declare.
+ (ix86_macro_fusion_p): Declare.
+ (ix86_macro_fusion_pair_p): Declare.
+ (ix86_bd_has_dispatch): Declare.
+ (ix86_bd_do_dispatch): Declare.
+ (ix86_core2i7_init_hooks): Declare.
+ (ix86_atom_sched_reorder): Declare.
+ * config/i386/i386.c Move all CPU cost tables to x86-tune-costs.h.
+ (COSTS_N_BYTES): Move to x86-tune-costs.h.
+ (DUMMY_STRINGOP_ALGS):Move to x86-tune-costs.h.
+ (rip_relative_addr_p): Rename to ...
+ (ix86_rip_relative_addr_p): ... this one; export.
+ (memory_address_length): Update.
+ (ix86_issue_rate): Move to x86-tune-sched.c.
+ (ix86_flags_dependent): Move to x86-tune-sched.c.
+ (ix86_agi_dependent): Move to x86-tune-sched.c.
+ (exact_dependency_1): Move to x86-tune-sched.c.
+ (exact_store_load_dependency): Move to x86-tune-sched.c.
+ (ix86_adjust_cost): Move to x86-tune-sched.c.
+ (ia32_multipass_dfa_lookahead): Move to x86-tune-sched.c.
+ (ix86_macro_fusion_p): Move to x86-tune-sched.c.
+ (ix86_macro_fusion_pair_p): Move to x86-tune-sched.c.
+ (do_reorder_for_imul): Move to x86-tune-sched-atom.c.
+ (swap_top_of_ready_list): Move to x86-tune-sched-atom.c.
+ (ix86_sched_reorder): Move to x86-tune-sched-atom.c.
+ (core2i7_first_cycle_multipass_init): Move to x86-tune-sched-core.c.
+ (core2i7_dfa_post_advance_cycle): Move to x86-tune-sched-core.c.
+ (min_insn_size): Rename to ...
+ (ix86_min_insn_size): ... this one; export.
+ (core2i7_first_cycle_multipass_begin): Move to x86-tune-sched-core.c.
+ (core2i7_first_cycle_multipass_issue): Move to x86-tune-sched-core.c.
+ (core2i7_first_cycle_multipass_backtrack): Move to
+ x86-tune-sched-core.c.
+ (core2i7_first_cycle_multipass_end): Move to x86-tune-sched-core.c.
+ (core2i7_first_cycle_multipass_fini): Move to x86-tune-sched-core.c.
+ (ix86_sched_init_global): Break up logic to ix86_core2i7_init_hooks.
+ (ix86_avoid_jump_mispredicts): Update.
+ (TARGET_SCHED_DISPATCH): Move to ix86-tune-sched-bd.c.
+ (TARGET_SCHED_DISPATCH_DO): Move to ix86-tune-sched-bd.c.
+ (TARGET_SCHED_REORDER): Move to ix86-tune-sched-bd.c.
+ (DISPATCH_WINDOW_SIZE): Move to ix86-tune-sched-bd.c.
+ (MAX_DISPATCH_WINDOWS): Move to ix86-tune-sched-bd.c.
+ (MAX_INSN): Move to ix86-tune-sched-bd.c.
+ (MAX_IMM): Move to ix86-tune-sched-bd.c.
+ (MAX_IMM_SIZE): Move to ix86-tune-sched-bd.c.
+ (MAX_IMM_32): Move to ix86-tune-sched-bd.c.
+ (MAX_IMM_64): Move to ix86-tune-sched-bd.c.
+ (MAX_LOAD): Move to ix86-tune-sched-bd.c.
+ (MAX_STORE): Move to ix86-tune-sched-bd.c.
+ (BIG): Move to ix86-tune-sched-bd.c.
+ (enum dispatch_group): Move to ix86-tune-sched-bd.c.
+ (enum insn_path): Move to ix86-tune-sched-bd.c.
+ (get_mem_group): Move to ix86-tune-sched-bd.c.
+ (is_cmp): Move to ix86-tune-sched-bd.c.
+ (dispatch_violation): Move to ix86-tune-sched-bd.c.
+ (is_branch): Move to ix86-tune-sched-bd.c.
+ (is_prefetch): Move to ix86-tune-sched-bd.c.
+ (init_window): Move to ix86-tune-sched-bd.c.
+ (allocate_window): Move to ix86-tune-sched-bd.c.
+ (init_dispatch_sched): Move to ix86-tune-sched-bd.c.
+ (is_end_basic_block): Move to ix86-tune-sched-bd.c.
+ (process_end_window): Move to ix86-tune-sched-bd.c.
+ (allocate_next_window): Move to ix86-tune-sched-bd.c.
+ (find_constant): Move to ix86-tune-sched-bd.c.
+ (get_num_immediates): Move to ix86-tune-sched-bd.c.
+ (has_immediate): Move to ix86-tune-sched-bd.c.
+ (get_insn_path): Move to ix86-tune-sched-bd.c.
+ (get_insn_group): Move to ix86-tune-sched-bd.c.
+ (count_num_restricted): Move to ix86-tune-sched-bd.c.
+ (fits_dispatch_window): Move to ix86-tune-sched-bd.c.
+ (add_insn_window): Move to ix86-tune-sched-bd.c.
+ (add_to_dispatch_window): Move to ix86-tune-sched-bd.c.
+ (debug_dispatch_window_file): Move to ix86-tune-sched-bd.c.
+ (debug_dispatch_window): Move to ix86-tune-sched-bd.c.
+ (debug_insn_dispatch_info_file): Move to ix86-tune-sched-bd.c.
+ (debug_ready_dispatch): Move to ix86-tune-sched-bd.c.
+ (do_dispatch): Move to ix86-tune-sched-bd.c.
+ (has_dispatch): Move to ix86-tune-sched-bd.c.
+ * config/i386/t-i386: Add new object files.
+ * config/i386/x86-tune-costs.h: New file.
+ * config/i386/x86-tune-sched-atom.c: New file.
+ * config/i386/x86-tune-sched-bd.c: New file.
+ * config/i386/x86-tune-sched-core.c: New file.
+ * config/i386/x86-tune-sched.c: New file.
+
+2017-10-11 Liu Hao <lh_mouse@126.com>
+
+ * pretty-print.c [_WIN32] (colorize_init): Remove. Use
+ the generic version below instead.
+ (should_colorize): Recognize Windows consoles as terminals
+ for MinGW targets.
+ * pretty-print.c [__MINGW32__] (write_all): New function.
+ [__MINGW32__] (find_esc_head): Likewise.
+ [__MINGW32__] (find_esc_terminator): Likewise.
+ [__MINGW32__] (eat_esc_sequence): Likewise.
+ [__MINGW32__] (mingw_ansi_fputs): New function that handles
+ ANSI escape codes.
+ (pp_write_text_to_stream): Use mingw_ansi_fputs instead of fputs
+ for MinGW targets.
+
+2017-10-11 Richard Biener <rguenther@suse.de>
+
+ * tree-ssa-loop-niter.c (infer_loop_bounds_from_pointer_arith):
+ Properly call analyze_scalar_evolution with the loop of the stmt.
+
+2017-10-11 Richard Biener <rguenther@suse.de>
+
+ * tree.def (POLYNOMIAL_CHREC): Remove CHREC_VARIABLE tree operand.
+ * tree-core.h (tree_base): Add chrec_var union member.
+ * tree.h (CHREC_VAR): Remove.
+ (CHREC_LEFT, CHREC_RIGHT, CHREC_VARIABLE): Adjust.
+ * tree-chrec.h (build_polynomial_chrec): Adjust.
+ * tree-chrec.c (reset_evolution_in_loop): Use build_polynomial_chrec.
+ * tree-pretty-print.c (dump_generic_node): Use CHREC_VARIABLE.
+
+2017-10-11 Marc Glisse <marc.glisse@inria.fr>
+
+ * fold-const.c (fold_binary_loc) [X +- Y CMP X]: Move ...
+ * match.pd: ... here.
+ ((T) X == (T) Y): Relax condition.
+
+2017-10-11 Bin Cheng <bin.cheng@arm.com>
+
+ PR tree-optimization/82472
+ * tree-loop-distribution.c (sort_partitions_by_post_order): Refine
+ comment.
+ (break_alias_scc_partitions): Update postorder number.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82490
+ * opts.c (parse_no_sanitize_attribute): Do not use error_value
+ variable.
+ * opts.h (parse_no_sanitize_attribute): Remove last argument.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ * print-rtl.c (print_insn): Move declaration of idbuf
+ to same scope as name.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ Revert r253637:
+
+ PR sanitizer/82484
+ * sanopt.c (sanitize_rewrite_addressable_params): Do not handle
+ volatile arguments.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82484
+ * sanopt.c (sanitize_rewrite_addressable_params): Do not handle
+ volatile arguments.
+
+2017-10-11 Adhemerval Zanella <adhemerval.zanella@linaro.org>
+
+ * config.gcc (default_gnu_indirect_function): Default to yes for
+ arm*-*-linux* with glibc.
+
+2017-10-11 Richard Biener <rguenther@suse.de>
+
+ * tree-scalar-evolution.c (get_scalar_evolution): Handle
+ default-defs and types we do not want to analyze.
+ (interpret_loop_phi): Replace unreachable code with an assert.
+ (compute_scalar_evolution_in_loop): Remove and inline ...
+ (analyze_scalar_evolution_1): ... here, replacing condition with
+ what makes the intent clearer. Remove handling of cases
+ get_scalar_evolution now handles.
+
+2017-10-10 Jim Wilson <wilson@tuliptree.org>
+
+ PR rtl-optimization/81434
+ * haifa-sched.c (prune_ready_list): Init min_cost_group to 0. Update
+ comment for main loop. In sched_group_found if, also add checks for
+ pass and min_cost_group.
+
+2017-10-10 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/rs6000.c (TARGET_INSN_COST): New.
+ (rs6000_insn_cost): New function.
+ * config/rs6000/rs6000.md (cost): New attribute.
+
+2017-10-10 Jakub Jelinek <jakub@redhat.com>
+ H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/79565
+ PR target/82483
+ * config/i386/i386.c (ix86_init_mmx_sse_builtins): Add
+ OPTION_MASK_ISA_MMX for __builtin_ia32_maskmovq,
+ __builtin_ia32_vec_ext_v4hi and __builtin_ia32_vec_set_v4hi.
+ (ix86_expand_builtin): Treat OPTION_MASK_ISA_MMX similarly
+ to OPTION_MASK_ISA_AVX512VL - builtins that have both
+ OPTION_MASK_ISA_MMX and some other bit set require both
+ mmx and the ISAs without the mmx bit.
+ * config/i386/i386-builtin.def (__builtin_ia32_cvtps2pi,
+ __builtin_ia32_cvttps2pi, __builtin_ia32_cvtpi2ps,
+ __builtin_ia32_pavgb, __builtin_ia32_pavgw, __builtin_ia32_pmulhuw,
+ __builtin_ia32_pmaxub, __builtin_ia32_pmaxsw, __builtin_ia32_pminub,
+ __builtin_ia32_pminsw, __builtin_ia32_psadbw, __builtin_ia32_pmovmskb,
+ __builtin_ia32_pshufw, __builtin_ia32_cvtpd2pi,
+ __builtin_ia32_cvttpd2pi, __builtin_ia32_cvtpi2pd,
+ __builtin_ia32_pmuludq, __builtin_ia32_pabsb, __builtin_ia32_pabsw,
+ __builtin_ia32_pabsd, __builtin_ia32_phaddw, __builtin_ia32_phaddd,
+ __builtin_ia32_phaddsw, __builtin_ia32_phsubw, __builtin_ia32_phsubd,
+ __builtin_ia32_phsubsw, __builtin_ia32_pmaddubsw,
+ __builtin_ia32_pmulhrsw, __builtin_ia32_pshufb, __builtin_ia32_psignb,
+ __builtin_ia32_psignw, __builtin_ia32_psignd, __builtin_ia32_movntq,
+ __builtin_ia32_paddq, __builtin_ia32_psubq, __builtin_ia32_palignr):
+ Add OPTION_MASK_ISA_MMX.
+
+2017-10-10 Andreas Tobler <andreast@gcc.gnu.org>
+
+ * config.gcc (armv7*-*-freebsd*): New target.
+ (armv6*-*-freebsd*): Remove obsolete TARGET_FREEBSD_ARMv6 define.
+
+2017-10-10 Jan Hubicka <hubicka@ucw.cz>
+
+ * x86-tune.def (X86_TUNE_AVOID_FALSE_DEP_FOR_BMI,
+ X86_TUNE_ADJUST_UNROLL, X86_TUNE_ONE_IF_CONV_INSN): Move to right
+ spot in the file.
+
+2017-10-10 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * wide-int.h (wide_int_ref_storage): Make host_dependent_precision
+ a template parameter.
+ (WIDE_INT_REF_FOR): Update accordingly.
+ * tree.h (wi::int_traits <const_tree>): Delete.
+ (wi::tree_to_widest_ref, wi::tree_to_offset_ref): New typedefs.
+ (wi::to_widest, wi::to_offset): Use them. Expand commentary.
+ (wi::tree_to_wide_ref): New typedef.
+ (wi::to_wide): New function.
+ * calls.c (get_size_range): Use wi::to_wide when operating on
+ trees as wide_ints.
+ * cgraph.c (cgraph_node::create_thunk): Likewise.
+ * config/i386/i386.c (ix86_data_alignment): Likewise.
+ (ix86_local_alignment): Likewise.
+ * dbxout.c (stabstr_O): Likewise.
+ * dwarf2out.c (add_scalar_info, gen_enumeration_type_die): Likewise.
+ * expr.c (const_vector_from_tree): Likewise.
+ * fold-const-call.c (host_size_t_cst_p, fold_const_call_1): Likewise.
+ * fold-const.c (may_negate_without_overflow_p, negate_expr_p)
+ (fold_negate_expr_1, int_const_binop_1, const_binop)
+ (fold_convert_const_int_from_real, optimize_bit_field_compare)
+ (all_ones_mask_p, sign_bit_p, unextend, extract_muldiv_1)
+ (fold_div_compare, fold_single_bit_test, fold_plusminus_mult_expr)
+ (pointer_may_wrap_p, expr_not_equal_to, fold_binary_loc)
+ (fold_ternary_loc, multiple_of_p, fold_negate_const, fold_abs_const)
+ (fold_not_const, round_up_loc): Likewise.
+ * gimple-fold.c (gimple_fold_indirect_ref): Likewise.
+ * gimple-ssa-warn-alloca.c (alloca_call_type_by_arg): Likewise.
+ (alloca_call_type): Likewise.
+ * gimple.c (preprocess_case_label_vec_for_gimple): Likewise.
+ * godump.c (go_output_typedef): Likewise.
+ * graphite-sese-to-poly.c (tree_int_to_gmp): Likewise.
+ * internal-fn.c (get_min_precision): Likewise.
+ * ipa-cp.c (ipcp_store_vr_results): Likewise.
+ * ipa-polymorphic-call.c
+ (ipa_polymorphic_call_context::ipa_polymorphic_call_context): Likewise.
+ * ipa-prop.c (ipa_print_node_jump_functions_for_edge): Likewise.
+ (ipa_modify_call_arguments): Likewise.
+ * match.pd: Likewise.
+ * omp-low.c (scan_omp_1_op, lower_omp_ordered_clauses): Likewise.
+ * print-tree.c (print_node_brief, print_node): Likewise.
+ * stmt.c (expand_case): Likewise.
+ * stor-layout.c (layout_type): Likewise.
+ * tree-affine.c (tree_to_aff_combination): Likewise.
+ * tree-cfg.c (group_case_labels_stmt): Likewise.
+ * tree-data-ref.c (dr_analyze_indices): Likewise.
+ (prune_runtime_alias_test_list): Likewise.
+ * tree-dump.c (dequeue_and_dump): Likewise.
+ * tree-inline.c (remap_gimple_op_r, copy_tree_body_r): Likewise.
+ * tree-predcom.c (is_inv_store_elimination_chain): Likewise.
+ * tree-pretty-print.c (dump_generic_node): Likewise.
+ * tree-scalar-evolution.c (iv_can_overflow_p): Likewise.
+ (simple_iv_with_niters): Likewise.
+ * tree-ssa-address.c (addr_for_mem_ref): Likewise.
+ * tree-ssa-ccp.c (ccp_finalize, evaluate_stmt): Likewise.
+ * tree-ssa-loop-ivopts.c (constant_multiple_of): Likewise.
+ * tree-ssa-loop-niter.c (split_to_var_and_offset)
+ (refine_value_range_using_guard, number_of_iterations_ne_max)
+ (number_of_iterations_lt_to_ne, number_of_iterations_lt)
+ (get_cst_init_from_scev, record_nonwrapping_iv)
+ (scev_var_range_cant_overflow): Likewise.
+ * tree-ssa-phiopt.c (minmax_replacement): Likewise.
+ * tree-ssa-pre.c (compute_avail): Likewise.
+ * tree-ssa-sccvn.c (vn_reference_fold_indirect): Likewise.
+ (vn_reference_maybe_forwprop_address, valueized_wider_op): Likewise.
+ * tree-ssa-structalias.c (get_constraint_for_ptr_offset): Likewise.
+ * tree-ssa-uninit.c (is_pred_expr_subset_of): Likewise.
+ * tree-ssanames.c (set_nonzero_bits, get_nonzero_bits): Likewise.
+ * tree-switch-conversion.c (collect_switch_conv_info, array_value_type)
+ (dump_case_nodes, try_switch_expansion): Likewise.
+ * tree-vect-loop-manip.c (vect_gen_vector_loop_niters): Likewise.
+ (vect_do_peeling): Likewise.
+ * tree-vect-patterns.c (vect_recog_bool_pattern): Likewise.
+ * tree-vect-stmts.c (vectorizable_load): Likewise.
+ * tree-vrp.c (compare_values_warnv, vrp_int_const_binop): Likewise.
+ (zero_nonzero_bits_from_vr, ranges_from_anti_range): Likewise.
+ (extract_range_from_binary_expr_1, adjust_range_with_scev): Likewise.
+ (overflow_comparison_p_1, register_edge_assert_for_2): Likewise.
+ (is_masked_range_test, find_switch_asserts, maybe_set_nonzero_bits)
+ (vrp_evaluate_conditional_warnv_with_ops, intersect_ranges): Likewise.
+ (range_fits_type_p, two_valued_val_range_p, vrp_finalize): Likewise.
+ (evrp_dom_walker::before_dom_children): Likewise.
+ * tree.c (cache_integer_cst, real_value_from_int_cst, integer_zerop)
+ (integer_all_onesp, integer_pow2p, integer_nonzerop, tree_log2)
+ (tree_floor_log2, tree_ctz, mem_ref_offset, tree_int_cst_sign_bit)
+ (tree_int_cst_sgn, get_unwidened, int_fits_type_p): Likewise.
+ (get_type_static_bounds, num_ending_zeros, drop_tree_overflow)
+ (get_range_pos_neg): Likewise.
+ * ubsan.c (ubsan_expand_ptr_ifn): Likewise.
+ * config/darwin.c (darwin_mergeable_constant_section): Likewise.
+ * config/aarch64/aarch64.c (aapcs_vfp_sub_candidate): Likewise.
+ * config/arm/arm.c (aapcs_vfp_sub_candidate): Likewise.
+ * config/avr/avr.c (avr_fold_builtin): Likewise.
+ * config/bfin/bfin.c (bfin_local_alignment): Likewise.
+ * config/msp430/msp430.c (msp430_attr): Likewise.
+ * config/nds32/nds32.c (nds32_insert_attributes): Likewise.
+ * config/powerpcspe/powerpcspe-c.c
+ (altivec_resolve_overloaded_builtin): Likewise.
+ * config/powerpcspe/powerpcspe.c (rs6000_aggregate_candidate)
+ (rs6000_expand_ternop_builtin): Likewise.
+ * config/rs6000/rs6000-c.c
+ (altivec_resolve_overloaded_builtin): Likewise.
+ * config/rs6000/rs6000.c (rs6000_aggregate_candidate): Likewise.
+ (rs6000_expand_ternop_builtin): Likewise.
+ * config/s390/s390.c (s390_handle_hotpatch_attribute): Likewise.
+
+2017-10-10 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-vect-loop-manip.c (rename_variables_in_bb): Rename PHI nodes
+ when copying loop nest with only one inner loop.
+
+2017-10-10 Richard Biener <rguenther@suse.de>
+
+ * tree-cfgcleanup.c (cleanup_tree_cfg_noloop): Avoid compacting
+ blocks if SCEV is active.
+ * tree-scalar-evolution.c (analyze_scalar_evolution_1): Remove
+ dead code.
+ (analyze_scalar_evolution): Handle cached evolutions the obvious way.
+ (scev_initialize): Assert we are not yet initialized.
+
+2017-10-10 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-loop-distribution.c (generate_loops_for_partition): Remove
+ inner loop's exit stmt by making it always exit the loop, otherwise
+ we would generate an infinite empty loop.
+
+2017-10-10 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-vect-loop-manip.c (slpeel_tree_duplicate_loop_to_edge_cfg): Skip
+ renaming variables in new preheader if it's deleted.
+
+2017-10-10 Bin Cheng <bin.cheng@arm.com>
+
+ * tree-loop-distribution.c (struct partition): Remove unused field
+ loops of the structure.
+ (partition_alloc, partition_free): Ditto.
+ (build_rdg_partition_for_vertex): Ditto.
+
+2017-10-09 Jeff Law <law@redhat.com>
+
+ * targhooks.c (default_stack_clash_protection_final_dynamic_probe): Fix
+ return type to match prototype and documentation.
+
+2010-10-09 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/rs6000.c (processor_costs): Move to ...
+ * config/rs6000/rs6000.h: ... here.
+ (rs6000_cost): Declare.
+
+2017-10-09 Eric Botcazou <ebotcazou@adacore.com>
+
+ * except.c (setjmp_fn): New global variable.
+ (init_eh): Initialize it if DONT_USE_BUILTIN_SETJMP is defined.
+ (sjlj_emit_function_enter): Call it instead of BUILTIN_SETJMP
+ if DONT_USE_BUILTIN_SETJMP is defined.
+
+2017-10-09 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * target.def (insn_cost): New hook.
+ * doc/tm.texi.in (TARGET_INSN_COST): New hook.
+ * doc/tm.texi: Regenerate.
+ * rtlanal.c (insn_cost): Use the new hook.
+
+2017-10-09 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * combine.c (combine_validate_cost): Compute the new insn_cost,
+ not just pattern_cost.
+ (try_combine): Adjust comment.
+
+2017-10-09 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * cfgrtl.c (rtl_account_profile_record): Replace insn_rtx_cost with
+ insn_cost.
+ * combine.c (uid_insn_cost): Adjust comment.
+ (combine_validate_cost): Adjust comment. Use pattern_cost instead
+ of insn_rtx_cost
+ (combine_instructions): Use insn_cost instead of insn_rtx_cost.
+ * dse.c (find_shift_sequence): Ditto.
+ * ifcvt.c (cheap_bb_rtx_cost_p): Ditto.
+ (bb_valid_for_noce_process_p): Use pattern_cost.
+ * rtl.h (insn_rtx_cost): Delete.
+ (pattern_cost): New prototype.
+ (insn_cost): New prototype.
+ * rtlanal.c (insn_rtx_cost): Rename to...
+ (pattern_cost): ... this.
+ (insn_cost): New.
+
+2017-10-09 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386.md (*jcc_2): Remove insn pattern.
+ (*jcc<mode>_0_r_i387): Ditto.
+ (*jccxf_r_i387): Ditto.
+ (*jcc<mode>_r_i387): Ditto.
+ (*jccu<mode>_r_i387): Ditto.
+ (*jcc<X87MODEF:mode>_<SWI24:mode>_r_i387): Ditto.
+ (*jcc): Rename from *jcc_1.
+
+2017-10-09 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ * config/rs6000/rs6000-p8swap.c (rs6000_analyze_swaps): Process
+ deferred rescans after the lvx/stvx recombination pre-pass.
+
+2017-10-09 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/amo.h: New include file to provide ISA 3.0 atomic
+ memory operation instruction support.
+ * config.gcc (powerpc*-*-*): Include amo.h as an extra header.
+ (rs6000-ibm-aix[789]*): Likewise.
+ * doc/extend.texi (PowerPC Atomic Memory Operation Functions):
+ Document new functions.
+
+2017-10-09 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82397
+ * tree-data-ref.c (data_ref_compare_tree): Make sure to return
+ equality only for semantically equal trees.
+
+2017-10-09 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82449
+ * sese.c (scev_analyzable_p): Check whether the SCEV is linear.
+ * tree-chrec.h (evolution_function_is_constant_p): Adjust to
+ allow constant addresses.
+ * tree-chrec.c (scev_is_linear_expression): Constant evolutions
+ are linear.
+
+2017-10-09 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/s390-builtins.def (vec_nabs, vec_vfi): Fix builtin
+ flags.
+
+2017-10-09 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ PR target/82463
+ * config/s390/vecintrin.h (vec_madd, vec_msub): Fix macro
+ definitions.
+
+2017-10-09 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ PR target/82465
+ * config/s390/s390-builtins.def (vec_sqrt): Fix builtin flags.
+
+2017-10-09 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82464
+ * config/s390/s390-builtins.def (s390_vec_xor_flt_a,
+ s390_vec_xor_flt_b, s390_vec_xor_flt_c): New.
+
+2017-10-09 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * wide-int.h (WI_BINARY_OPERATOR_RESULT): New macro.
+ (WI_BINARY_PREDICATE_RESULT): Likewise.
+ (wi::binary_traits::operator_result): New type.
+ (wi::binary_traits::predicate_result): Likewise.
+ (generic_wide_int::operator~, unary generic_wide_int::operator-)
+ (generic_wide_int::operator==, generic_wide_int::operator!=)
+ (generic_wide_int::operator&, generic_wide_int::and_not)
+ (generic_wide_int::operator|, generic_wide_int::or_not)
+ (generic_wide_int::operator^, generic_wide_int::operator+
+ (binary generic_wide_int::operator-, generic_wide_int::operator*):
+ Delete.
+ (operator~, unary operator-, operator==, operator!=, operator&)
+ (operator|, operator^, operator+, binary operator-, operator*): New
+ functions.
+ * expr.c (get_inner_reference): Use wi::bit_and_not.
+ * fold-const.c (fold_binary_loc): Likewise.
+ * ipa-prop.c (ipa_compute_jump_functions_for_edge): Likewise.
+ * tree-ssa-ccp.c (get_value_from_alignment): Likewise.
+ (bit_value_binop): Likewise.
+ * tree-ssa-math-opts.c (find_bswap_or_nop_load): Likewise.
+ * tree-vrp.c (zero_nonzero_bits_from_vr): Likewise.
+ (extract_range_from_binary_expr_1): Likewise.
+ (masked_increment): Likewise.
+ (simplify_bit_ops_using_ranges): Likewise.
+
+2017-10-09 Martin Jambor <mjambor@suse.cz>
+
+ PR hsa/82416
+ * hsa-common.h (hsa_op_with_type): New method extend_int_to_32bit.
+ * hsa-gen.c (hsa_extend_inttype_to_32bit): New function.
+ (hsa_type_for_scalar_tree_type): Use it. Always force min32int for
+ COMPLEX types.
+ (hsa_fixup_mov_insn_type): New function.
+ (hsa_op_with_type::get_in_type): Use it.
+ (hsa_build_append_simple_mov): Likewise. Allow sub-32bit
+ immediates in an assert.
+ (hsa_op_with_type::extend_int_to_32bit): New method.
+ (gen_hsa_insns_for_bitfield): Fixup instruction and intermediary
+ types. Convert to dest type if necessary.
+ (gen_hsa_insns_for_bitfield_load): Fixup load type if necessary.
+ (reg_for_gimple_ssa): Pass false as min32int to
+ hsa_type_for_scalar_tree_type.
+ (gen_hsa_addr): Fixup type when creating addresable temporary.
+ (gen_hsa_cmp_insn_from_gimple): Extend operands if necessary.
+ (gen_hsa_unary_operation): Extend operands and convert to dest type if
+ necessary. Call hsa_fixup_mov_insn_type.
+ (gen_hsa_binary_operation): Changed operand types to hsa_op_with_type,
+ extend operands and convert to dest type if necessary.
+ (gen_hsa_insns_for_operation_assignment): Extend operands and convert
+ to dest type if necessary.
+ (set_output_in_type): Call hsa_fixup_mov_insn_type. Just ude dest
+ if conversion nt necessary and size matches.
+ (gen_hsa_insns_for_load): Call hsa_fixup_mov_insn_type, convert
+ to dest type if necessary.
+ (gen_hsa_insns_for_store): Call hsa_fixup_mov_insn_type.
+ (gen_hsa_insns_for_switch_stmt): Likewise. Also extend operands if
+ necessary.
+ (gen_hsa_clrsb): Likewise.
+ (gen_hsa_ffs): Likewise.
+ (gen_hsa_divmod): Extend operands and convert to dest type if
+ necessary.
+ (gen_hsa_atomic_for_builtin): Change type of op to hsa_op_with_type.
+
+2017-10-08 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/rs6000.md (conditional branch): Clean up formatting.
+ Remove empty default arguments. Use a brace block as output
+ statement.
+ (conditional return): Ditto.
+ (jump): Ditto.
+ (indirect_jump): Ditto. Use b%T0 instead of bctr/blr.
+ (tablejump, tablejumpsi, tablejumpdi, *tablejump<mode>_internal1):
+ Ditto.
+ (group_ending_nop): Ditto.
+ (doloop_end): Ditto.
+ (ctr<mode>, ctr<mode>_internal1, ctr<mode>_internal2): Ditto.
+ (splitters for those): Ditto.
+
+2017-10-08 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/rs6000-string.c (expand_strncmp_align_check): Invert
+ a conditional jump (and the compare for it) so that pc_rtx is the
+ last operand.
+ * config/rs6000/rs6000.c (rs6000_legitimate_combined_insn): Adjust
+ for the deleted and renamed ctr<mode>_internal[234] patterns.
+ * config/rs6000/rs6000.md: Delete second conditional branch pattern.
+ Delete second conditional return pattern.
+ (ctr<mode>_internal2): Delete this second bdnz pattern.
+ (ctr<mode>_internal3): Rename to ctr<mode>_internal2.
+ (ctr<mode>_internal4): Delete this second bdz pattern.
+
+2017-10-08 Eric Botcazou <ebotcazou@adacore.com>
+
+ * tree-outof-ssa.h (ssaexpand): Add partitions_for_undefined_values.
+ (always_initialized_rtx_for_ssa_name_p): New predicate.
+ * tree-outof-ssa.c (remove_ssa_form): Initialize new field of SA.
+ (finish_out_of_ssa): Free new field of SA.
+ * tree-ssa-coalesce.h (get_undefined_value_partitions): Declare.
+ * tree-ssa-coalesce.c: Include tree-ssa.h.
+ (get_parm_default_def_partitions): Remove extern keyword.
+ (get_undefined_value_partitions): New function.
+ * expr.c (expand_expr_real_1) <expand_decl_rtl>: For a SSA_NAME, do
+ not set SUBREG_PROMOTED_VAR_P on the sub-register if it may contain
+ uninitialized bits.
+ * loop-iv.c (iv_get_reaching_def): Disqualify all subregs.
+
+2017-10-08 Eric Botcazou <ebotcazou@adacore.com>
+
+ * builtins.def (BUILT_IN_SETJMP): Revert latest change.
+
+2017-10-08 Jan Hubicka <hubicka@ucw.cz>
+
+ * config/i386/i386.c (ix86_expand_set_or_movmem): Disable 512bit loops
+ for targets that preffer 128bit.
+
+2017-10-08 Jan Hubicka <hubicka@ucw.cz>
+
+ * config/i386/i386.c (has_dispatch): Disable for Ryzen.
+
+2017-10-08 Olivier Hainque <hainque@adacore.com>
+
+ * config/arm/arm.c (arm_set_return_address): Use MEM_VOLATILE_P
+ on the target mem instead of RTX_FRAME_RELATED_P on the insn to
+ prevent DSE.
+ (thumb_set_return_address): Likewise.
+
+2017-10-08 Olivier Hainque <hainque@adacore.com>
+
+ * common/config/arm/arm-common.c (arm_except_unwind_info):
+ Handle DWARF2_UNWIND_INFO.
+
+2017-10-07 Michael Collison <michael.collison@arm.com>
+
+ * config/aarch64/aarch64.md (*aarch64_reg_<optab>_minus<mode>3):
+ New pattern.
+
+2017-10-07 Eric Botcazou <ebotcazou@adacore.com>
+
+ * builtins.def (BUILT_IN_SETJMP): Declare as library builtin instead
+ of GCC builtin if DONT_USE_BUILTIN_SETJMP is defined.
+ * except.c (sjlj_emit_function_enter): If DONT_USE_BUILTIN_SETJMP is
+ defined, force the creation of a new block for a dispatch label.
+
+2017-10-07 Jan Hubicka <hubicka@ucw.cz>
+
+ * invoke.texi (Wsuggest-attribute=cold): Document.
+ * common.opt (Wsuggest-attribute=cold): New
+ * ipa-pure-const.c (warn_function_cold): New function.
+ * predict.c (compute_function_frequency): Use it.
+ * predict.h (warn_function_cold): Declare.
+
+2017-10-06 Jan Hubicka <hubicka@ucw.cz>
+
+ * tree-switch-conversion.c (do_jump_if_equal, emit_cmp_and_jump_insns):
+ Update profile.
+
+2017-10-06 Martin Liska <mliska@suse.cz>
+
+ * sanopt.c (struct sanopt_tree_triplet_hash): Remove inline
+ keyword for member functions.
+ (struct sanopt_tree_couple): New struct.
+ (struct sanopt_tree_couple_hash): New function.
+ (struct sanopt_ctx): Add new hash_map.
+ (has_dominating_ubsan_ptr_check): New function.
+ (record_ubsan_ptr_check_stmt): Likewise.
+ (maybe_optimize_ubsan_ptr_ifn): Likewise.
+ (sanopt_optimize_walker): Handle IFN_UBSAN_PTR.
+ (pass_sanopt::execute): Handle also SANITIZE_POINTER_OVERFLOW.
+
+2017-10-06 Sudakshina Das <sudi.das@arm.com>
+
+ PR target/82440
+ * config/aarch64/predicates.md (aarch64_reg_or_orr_imm): Only call
+ aarch64_simd_valid_immediate on CONST_VECTORs.
+ (aarch64_reg_or_bic_imm): Likewise.
+
+2017-10-06 Wilco Dijkstra <wdijkstr@arm.com>
+
+ PR rtl-optimization/82396
+ * haifa-sched.c (ready_sort_real): Disable qsort checking.
+
+2017-10-06 Sebastian Pop <sebpop@gmail.com>
+
+ * graphite-dependences.c (scop_get_reads): Move code to...
+ (scop_get_must_writes): Move code to...
+ (scop_get_may_writes): Move code to...
+ (scop_get_reads_and_writes): ... here.
+ (scop_get_dependences): Call scop_get_reads_and_writes.
+
+2017-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/82434
+ * fold-const.h (can_native_encode_type_p,
+ can_native_encode_string_p): Remove.
+ * fold-const.c (native_encode_int): Formatting fixes. If ptr is NULL,
+ don't encode anything, just return what would be otherwise returned.
+ (native_encode_fixed, native_encode_complex, native_encode_vector):
+ Likewise.
+ (native_encode_string): Likewise. Inline by hand
+ can_native_encode_string_p.
+ (can_native_encode_type_p): Remove.
+ (can_native_encode_string_p): Remove.
+ * tree-vect-stmts.c (vectorizable_store): Instead of testing just
+ STRING_CSTs using can_native_encode_string_p, test all
+ CONSTANT_CLASS_P values using native_encode_expr with NULL ptr.
+ * gimple-ssa-store-merging.c (encode_tree_to_bitpos): Remove last
+ argument from native_encode_expr.
+ (rhs_valid_for_store_merging_p): Use native_encode_expr with NULL ptr.
+ (pass_store_merging::execute): Don't unnecessarily look for 3 stmts,
+ but just 2.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82397
+ * tree-vect-data-refs.c (dr_group_sort_cmp): Do not use
+ operand_equal_p but rely on data_ref_compare_tree for detecting
+ equalities.
+ (vect_analyze_data_ref_accesses): Use data_ref_compare_tree
+ to match up with dr_group_sort_cmp.
+
+2017-10-06 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ PR target/82322
+ * config/s390/s390-builtins.def (s390_vfi): Define new overloaded
+ builtin.
+ * config/s390/s390-builtin-types.def: Regenerate.
+
+2017-10-06 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ PR target/82317
+ * config/s390/s390-builtin-types.def: Regenerate.
+ * config/s390/s390-builtins.def (s390_vfmaxdb_4, s390_vfmindb_4):
+ Change flag from B_VXE to B_VX.
+ (s390_vec_min_dbl): Remove B_VXE flag.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c: Include ssa.h and tree-ssa.h.
+ (translate_isl_ast_to_gimple::translate_pending_phi_nodes,
+ translate_isl_ast_to_gimple::is_valid_rename,
+ translate_isl_ast_to_gimple::get_rename,
+ translate_isl_ast_to_gimple::get_def_bb_for_const,
+ translate_isl_ast_to_gimple::get_new_name,
+ translate_isl_ast_to_gimple::collect_all_ssa_names,
+ translate_isl_ast_to_gimple::copy_loop_phi_args,
+ translate_isl_ast_to_gimple::collect_all_ssa_names,
+ translate_isl_ast_to_gimple::copy_loop_phi_args,
+ translate_isl_ast_to_gimple::copy_loop_phi_nodes,
+ translate_isl_ast_to_gimple::add_close_phis_to_merge_points,
+ translate_isl_ast_to_gimple::add_close_phis_to_outer_loops,
+ translate_isl_ast_to_gimple::copy_loop_close_phi_args,
+ translate_isl_ast_to_gimple::copy_loop_close_phi_nodes,
+ translate_isl_ast_to_gimple::copy_cond_phi_args,
+ translate_isl_ast_to_gimple::copy_cond_phi_nodes,
+ translate_isl_ast_to_gimple::edge_for_new_close_phis,
+ translate_isl_ast_to_gimple::add_phi_arg_for_new_expr,
+ translate_isl_ast_to_gimple::rename_uses,
+ translate_isl_ast_to_gimple::rename_all_uses): Remove.
+ (translate_isl_ast_to_gimple::get_rename_from_scev): Simplify.
+ (set_rename_for_each_def): Likewise.
+ (graphite_copy_stmts_from_block): Handle debug stmt resetting
+ here. Handle rewriting SCEV analyzable uses here.
+ (copy_bb_and_scalar_dependences): Generate code for PHI
+ copy-in/outs.
+ (graphite_regenerate_ast_isl): Adjust.
+ * graphite-scop-detection.c (trivially_empty_bb_p): Move to sese.[ch].
+ (add_write, add_read): New functions.
+ (build_cross_bb_scalars_def): Use it and simplify.
+ (build_cross_bb_scalars_use): Likewise.
+ (graphite_find_cross_bb_scalar_vars): Inline into...
+ (try_generate_gimple_bb): ...here. Add dependences for PHIs,
+ simulating out-of-SSA. Compute liveout and add dependencies.
+ (build_scops): Force an empty entry block.
+ * sese.h (sese_info_t::liveout, sese_info_t::debug_liveout): New
+ members.
+ (sese_build_liveouts): Declare.
+ (sese_trivially_empty_bb_p): Likewise.
+ * sese.c (sese_build_liveouts_bb): Properly handle PHIs,
+ compute liveout and debug_liveout.
+ (sese_bad_liveouts_use): Remove.
+ (sese_reset_debug_liveouts_bb): Likewise.
+ (sese_reset_debug_liveouts): Rewrite in terms of debug_liveout.
+ (sese_build_liveouts): Build liveout and debug_liveout and store
+ it in region.
+ (new_sese_info): Adjust.
+ (free_sese_info): Likewise.
+ (sese_insert_phis_for_liveouts): Reset debug stmts from here,
+ do not build liveout here.
+ (move_sese_in_condition): Adjust region entry.
+ (scev_analyzable_p): Match up with chrec_apply requirements.
+ (sese_trivially_empty_bb_p): New.
+ * tree-into-ssa.c (get_reaching_def): Properly support generating
+ default-defs for incremental rewrite of anonymous names.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ * graphite-sese-to-poly.c (extract_affine): For casts increasing
+ precision do not perform modulo reduction.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82436
+ * tree-vect-slp.c (vect_supported_load_permutation_p): More
+ conservatively choose the vectorization factor when checking
+ whether we can perform the required load permutation.
+ (vect_transform_slp_perm_load): Assert when we may not fail.
+
+2017-10-05 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * config/rs6000/sysv4.h (SUBTARGET_OVERRIDE_OPTIONS): Correct error
+ message for incompatible -msdata=* and -mcall-* options.
+
+2017-10-05 Jan Hubicka <hubicka@ucw.cz>
+
+ * config/i386/i386.c (ia32_multipass_dfa_lookahead): Default to issue
+ rate for post-reload scheduling.
+
+2017-10-05 Tamar Christina <tamar.christina@arm.com>
+
+ * doc/sourcebuild.texi (vect_sizes_16B_8B, vect_sizes_32B_16B): New.
+
+2017-10-05 Jan Hubicka <hubicka@ucw.cz>
+
+ * config/i386/i386.c (znver1_cost): Set branch_cost to 3 (instead of 2)
+ to improve monte carlo in scimark.
+
+2017-10-05 Jan Hubicka <hubicka@ucw.cz>
+
+ * config/i386/i386.c (ix86_size_cost, i386_cost, i486_cost,
+ pentium_cost, lakemont_cost, pentiumpro_cost, geode_cost, k6_cost,
+ athlon_cost, k8_cost, amdfam10_cost, btver1_cost, btver2_cost,
+ pentium4_cost, nocona_cost): Set reassociation width to 1.
+ (bdver1_cost, bdver2_cost, bdver3_cost, bdver4_cost): Set reassociation
+ width to 2 for fp operations and 1 otherwise.
+ (znver1_cost): Set scalar reassoc width to 4 and vector to 3 and 6
+ for int and fp.
+ (atom_cost): Set reassociation width to 2.
+ (slm_cost, generic_cost): Set fp reassociation width
+ to 2 and 1 otherwise.
+ (intel_cost): Set fp reassociation width to 4 and 1 otherwise.
+ (core_cost): Set fp reassociation width to 4 and vector to 2.
+ (ix86_reassociation_width): Rewrite using cost table; special case
+ plus/minus on Zen; honor X86_TUNE_SSE_SPLIT_REGS
+ and TARGET_AVX128_OPTIMAL.
+ * config/i386/i386.h (processor_costs): Add
+ reassoc_int, reassoc_fp, reassoc_vec_int, reassoc_vec_fp.
+ (TARGET_VECTOR_PARALLEL_EXECUTION, TARGET_REASSOC_INT_TO_PARALLEL,
+ TARGET_REASSOC_FP_TO_PARALLEL): Remove.
+ * x86-tune.def (X86_TUNE_REASSOC_INT_TO_PARALLEL): Remove.
+ (X86_TUNE_REASSOC_FP_TO_PARALLEL): Remove.
+ (X86_TUNE_VECTOR_PARALLEL_EXECUTION): Remove.
+
+2017-10-05 Nathan Sidwell <nathan@acm.org>
+
+ * doc/invoke.texi (Wparentheses): Document C++ MVP behaviour.
+
+2017-10-05 Tamar Christina <tamar.christina@arm.com>
+
+ * config/arm/arm.c (arm_test_fpu_data): New.
+ (arm_run_selftests): Call arm_test_fpu_data.
+
+2017-10-04 Nathan Sidwell <nathan@acm.org>
+
+ * toplev.c (toplev::main): Remove excess parens on pretty_printer
+ decl.
+ * caller-save.c (insert_save): Remove excess parens on TO_SAVE parm.
+
+2017-10-04 Sudakshina Das <sudi.das@arm.com>
+
+ * config/aarch64/aarch64-protos.h (enum simd_immediate_check): New
+ check type for aarch64_simd_valid_immediate.
+ (aarch64_output_simd_mov_immediate): Update prototype.
+ (aarch64_simd_valid_immediate): Update prototype.
+ * config/aarch64/aarch64-simd.md (orr<mode>3): modified pattern to add
+ support for ORR-immediate.
+ (and<mode>3): modified pattern to add support for BIC-immediate.
+ * config/aarch64/aarch64.c (aarch64_simd_valid_immediate): Function
+ now checks for valid immediate for BIC and ORR based on new enum
+ argument.
+ (aarch64_output_simd_mov_immediate): Function now used to output
+ BIC/ORR imm as well based on new enum argument.
+ * config/aarch64/constraints.md (Do): New vector immediate constraint.
+ (Db) : Likewise.
+ * config/aarch64/predicates.md (aarch64_reg_or_orr_imm): New predicate.
+ (aarch64_reg_or_bic_imm): Likewise.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/vx-builtins.md ("vec_mergeh<mode>")
+ ("vec_mergel<mode>"): Change mode iterator to V_128_NOSINGLE.
+
+2017-10-04 Wilco Dijkstra <wdijkstr@arm.com>
+
+ Revert r253399:
+
+ PR rtl-optimization/82396
+ * haifa-sched.c (autopref_multipass_init): Simplify
+ initialization.
+ (autopref_rank_data): Simplify sort order.
+ * sched-int.h (autopref_multipass_data_): Remove
+ multi_mem_insn_p, min_offset and max_offset.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * doc/sourcebuild.texi: Document vect_peeling_profitable.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * doc/sourcebuild.texi: Document vect_intdouble_cvt and
+ vect_doubleint_cvt.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * doc/sourcebuild.texi: Document vect_long_mult.
+
+2017-10-04 Richard Sandiford <richard.sandiford@linaro.org>
+
+ PR tree-optimization/82413
+ * fold-const.c (build_range_check): Use widest_int when comparing
+ the maximum ETYPE value with HIGH.
+
+2017-10-04 Wilco Dijkstra <wdijkstr@arm.com>
+
+ PR rtl-optimization/82396
+ * haifa-sched.c (autopref_multipass_init): Simplify
+ initialization.
+ (autopref_rank_data): Simplify sort order.
+ * sched-int.h (autopref_multipass_data_): Remove
+ multi_mem_insn_p, min_offset and max_offset.
+
+2017-10-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/82381
+ * tree-ssa-reassoc.c (sort_by_operand_rank): Check for different
+ oeN->rank first. Return 1 or -1 if one op is SSA_NAME and the other
+ is not.
+
+ PR tree-optimization/82374
+ * omp-low.c (create_omp_child_function): Copy DECL_ATTRIBUTES,
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION,
+ DECL_FUNCTION_SPECIFIC_TARGET and DECL_FUNCTION_VERSIONED from
+ current_function_decl to the new decl.
+
+2017-10-03 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/rs6000-builtin.def (BU_FLOAT128_2_HW): Define new
+ helper macro for IEEE float128 hardware built-in functions.
+ (SQRTF128_ODD): Add built-in functions with the round-to-odd
+ semantics.
+ (TRUNCF128_ODD): Likewise.
+ (ADDF128_ODD): Likewise.
+ (SUBF128_ODD): Likewise.
+ (MULF128_ODD): Likewise.
+ (DIVF128_ODD): Likewise.
+ (FMAF128_ODD): Likewise.
+ * config/rs6000/rs6000.md (UNSPEC_ROUND_TO_ODD): Rename to
+ UNSPEC_TRUNC_ROUND_TO_ODD.
+ (UNSPEC_TRUNC_ROUND_TO_ODD): Likewise.
+ (UNSPEC_ADD_ROUND_TO_ODD): New unspec codes for the IEEE 128-bit
+ floating point round to odd instructions.
+ (UNSPEC_SUB_ROUND_TO_ODD): Likewise.
+ (UNSPEC_MUL_ROUND_TO_ODD): Likewise.
+ (UNSPEC_DIV_ROUND_TO_ODD): Likewise.
+ (UNSPEC_FMA_ROUND_TO_ODD): Likewise.
+ (UNSPEC_SQRT_ROUND_TO_ODD): Likewise.
+ (trunc<mode>sf2_hw): Change the truncate with round to odd
+ expansion to use UNSPEC_TRUNC_ROUND_TO_ODD.
+ (add<mode>3_odd): Add insns for IEEE 128-bit floating point round
+ to odd hardware instructions.
+ (sub<mode>3_odd): Likewise.
+ (mul<mode>3_odd): Likewise.
+ (div<mode>3_odd): Likewise.
+ (sqrt<mode>2_odd): Likewise.
+ (fma<mode>4_odd): Likewise.
+ (fms<mode>4_odd): Likewise.
+ (nfma<mode>4_odd): Likewise.
+ (nfms<mode>4_odd): Likewise.
+ (trunc<mode>df2_odd): Change the truncate with round to odd
+ expansion to use UNSPEC_TRUNC_ROUND_TO_ODD. Add a generator
+ function.
+ * doc/extend.texi (PowerPC built-in functions): Update documentation
+ for existing IEEE float128-bit built-in functions. Add built-in
+ functions that generate the IEEE 128-bit floating point round to
+ odd instructions.
+
+2017-10-03 Segher Boessenkool <segher@kernel.crashing.org>
+
+ PR rtl-optimization/77729
+ * simplify-rtx.c (simplify_binary_operation_1): Delete the (X&C1)|C2
+ to (X&(C1&~C2))|C2 transformations.
+
+2017-10-03 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/82363
+ * tree-sra.c (propagate_subaccesses_across_link): In unrecoverable
+ mismatch, mark lacc written regardless of racc.
+
+2017-10-03 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/82381
+ * tree-ssa-reassoc.c (sort_by_operand_rank): Don't check
+ stmt_to_insert nor wheather SSA_NAMEs are default defs.
+ Return 1 or -1 if one of bba and bbb is NULL. If bb_rank is equal,
+ fallthrough into reassoc_stmt_dominates_stmt_p.
+
+ PR target/82386
+ * combine.c (combine_instructions): Don't combine in unreachable
+ basic blocks.
+
+2017-08-18 Peter Bergner <bergner@vnet.ibm.com>
+
+ PR target/80210
+ * config/rs6000/rs6000.c (rs6000_option_override_internal): Rewrite
+ function to not use the have_cpu variable. Do not set cpu_index,
+ rs6000_cpu_index or rs6000_tune_index if we end up using TARGET_DEFAULT
+ or the default cpu.
+ (rs6000_valid_attribute_p): Remove duplicate initializations of
+ old_optimize and func_optimize.
+ (rs6000_pragma_target_parse): Call rs6000_activate_target_options ().
+ (rs6000_activate_target_options): Make global.
+ * config/rs6000/rs6000-protos.h (rs6000_activate_target_options): Add
+ prototype.
+
+2017-10-02 Jakub Jelinek <jakub@redhat.com>
+
+ * tree-dfa.c (get_ref_base_and_extent): Set *pmax_size to -1
+ if *poffset + *pmax_size overflows in HOST_WIDE_INT.
+ Set *poffset to 0 and *psize and *pmax_size to -1 if
+ *poffset + *psize overflows in HOST_WIDE_INT.
+
+ PR tree-optimization/82387
+ PR tree-optimization/82388
+ PR tree-optimization/82389
+ * tree-ssa-dse.c (dse_classify_store): Test byte_tracking_enabled
+ instead of live_bytes non-NULL.
+
+2017-10-02 Georg-Johann Lay <avr@gjlay.de>
+
+ PR target/41076
+ * confg/avr/avr.md (*iorhi3.ashift8-ext.zerox): Add "r,r,0"
+ alternative.
+
+2017-10-02 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c (set_codegen_error): With
+ -fchecking and --param graphite-allow-codegen-errors=0 ICE.
+ * params.def (PARAM_GRAPHITE_ALLOW_CODEGEN_ERRORS): New param.
+
+2017-10-02 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * tree.h (wi::int_traits <const_tree>::decompose): Assert that the
+ requested precision matches the type's.
+ * calls.c (alloc_max_size): Calculate the new candidate size as
+ a widest_int and use wi::to_widest when comparing it with the
+ current candidate size.
+ * gimple-ssa-warn-alloca.c (pass_walloca::execute): Compare with
+ zero rather than integer_zero_node.
+ * match.pd: Check for a no-op conversion before using wi::add
+ rather than after. Use tree_to_uhwi when summing small shift
+ counts into an unsigned int.
+
+2017-10-02 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ PR target/71307
+ * config/aarch64/aarch64.h (POINTER_AND_FP_REGS): New reg class.
+ (REG_CLASS_NAMES, REG_CLASS_CONTENTS): Update accordingly.
+ * config/aarch64/aarch64.c (aarch64_class_max_nregs): Handle
+ POINTER_AND_FP_REGS.
+
+2017-10-02 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82355
+ * graphite-isl-ast-to-gimple.c (build_iv_mapping): Also build
+ a mapping for the enclosing loop but avoid generating one for
+ the loop tree root.
+ (copy_bb_and_scalar_dependences): Remove premature codegen
+ error on PHIs in blocks duplicated into multiple places.
+ * graphite-scop-detection.c
+ (scop_detection::stmt_has_simple_data_refs_p): For a loop not
+ in the region use it as loop and nest to analyze the DR in.
+ (try_generate_gimple_bb): Likewise.
+ * graphite-sese-to-poly.c (extract_affine_chrec): Adjust.
+ (add_loop_constraints): For blocks in a loop not in the region
+ create a dimension with a single iteration.
+ * sese.h (gbb_loop_at_index): Remove assert.
+
+2017-10-01 Kevin Buettner <kevinb@redhat.com>
+
+ * omp-expand.c (adjust_context_scope): New function.
+ (expand_parallel_call): Call adjust_context_scope.
+
+2017-10-01 Jeff Law <law@redhat.com>
+
+ * tree-ssa-dom.c (optimize_stmt): Make this a method within the
+ dom_opt_dom_walker class with direct access to private members.
+ Add comments. Call test_for_singularity.
+ (dom_opt_dom_walker::before_dom_children): Corresponding changes.
+ (dom_opt_dom_walker::after_dom_children): Do not lazily initialize
+ m_dummy_cond anymore.
+ (class dom_opt_dom_walker): Initialize m_dummy_cond member in the
+ class ctor.
+ (pass_dominator:execute): Build the dummy_cond here and pass it
+ to the dom_opt_dom_walker ctor.
+ (test_for_singularity): New function.
+
+2017-09-30 Krister Walfridsson <krister.walfridsson@gmail.com>
+ Maya Rashish <coypu@sdf.org>
+
+ * config.gcc (*-*-netbsd*): New variable nbsd_tm_file containing
+ netbsd.h, netbsd-stdint.h, and netbsd-elf.h.
+ (alpha*-*-netbsd*) Use nbsd_tm_file.
+ (arm*-*-netbsdelf*) Likewise.
+ (i[34567]86-*-netbsdelf*) Likewise.
+ (x86_64-*-netbsd*) Likewise.
+ (mips*-*-netbsd*) Likewise.
+ (powerpc-*-netbsd*) Likewise.
+ (sh*-*-netbsd*) Likewise.
+ (sparc-*-netbsdelf*) Likewise.
+ (sparc64-*-netbsd*) Likewise.
+ (m68k*-*-netbsdelf*) Use nbsd_tm_file and add CHAR_FAST8/SHORT_FAST16
+ to tm_defines.
+ (vax-*-netbsdelf*) Likewise.
+ * config/netbsd-stdint.h (INT_FAST8_TYPE): Check CHAR_FAST8.
+ (UINT_FAST8_TYPE) Likewise.
+ (INT_FAST16_TYPE) Check CHAR_FAST16.
+ (UINT_FAST16_TYPE) Likewise.
+
+2017-09-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82361
+ * config/i386/i386.md
+ (TARGET_USE_8BIT_IDIV zext divmodsi4 splitter): New define_split.
+ (divmodsi4_zext_1, divmodsi4_zext_2, *divmodsi4_zext_1,
+ *divmodsi4_zext_2): New define_insn_and_split.
+ (*divmodsi4_noext_zext_1, *divmodsi4_noext_zext_2): New define_insn.
+ (TARGET_USE_8BIT_IDIV zext udivmodsi4 splitter): New define_split.
+ (udivmodsi4_zext_1, udivmodsi4_zext_2, *udivmodsi4_zext_1,
+ *udivmodsi4_zext_2, *udivmodsi4_pow2_zext_1, *udivmodsi4_pow2_zext_2):
+ New define_insn_and_split.
+ (*udivmodsi4_noext_zext_1, *udivmodsi4_noext_zext_2): New define_insn.
+ * config/i386/i386.c (ix86_split_idivmod): Handle operands[0] or
+ operands[1] having DImode when mode is SImode.
+
+ * config/i386/i386.c (ix86_split_idivmod): Use mode instead of
+ always SImode for DIV and MOD in REG_EQUAL notes.
+
+2017-09-29 Yury Gribov <tetra2005@gmail.com>
+
+ PR middle-end/82319
+ * match.pd: Fix handling of NaNs in pattern.
+
+2017-09-29 Jeff Law <law@redhat.com>
+
+ * sbitmap.c (bitmap_bit_in_range_p): New function.
+ * sbitmap.h (bitmap_bit_in_range_p): Prototype.
+ * tree-ssa-dse.c (live_bytes_read): New function.
+ (dse_classify_store): Ignore reads of dead bytes.
+
+ * config/i386/i386.c (ix86_adjust_stack_and_probe_stack_clash): Fix
+ typos and whitespace errors.
+ * config/i386/predicates.md (address_no_seg_operand): Likewise.
+ * config/s390/s390.c (s390_emit_prologue): Likewise.
+
+2017-09-29 Vladimir Makarov <vmakarov@redhat.com>
+
+ PR target/81481
+ * ira-costs.c (scan_one_insn): Don't take into account PIC equiv
+ with a symbol for LRA.
+
+2017-09-29 Vladimir Makarov <vmakarov@redhat.com>
+
+ PR rtl-optimization/82338
+ * lra-constraints.c (inherit_in_ebb): Check usage_insns check.
+
+2017-09-29 Alexander Monakov <amonakov@ispras.ru>
+
+ * genmodes.c (calc_wider_mode): Suppress qsort macro.
+ * system.h [CHECKING_P] (qsort): Redirect to qsort_chk.
+ (qsort_chk): Declare.
+ * vec.c [CHECKING_P] (qsort_chk_error): New static function.
+ (qsort_chk): New function.
+
+2017-09-29 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ PR tree-optimization/82337
+ * gimple-ssa-strength-reduction.c (find_phi_def): Don't record a
+ phi definition if the PHI result appears in an abnormal PHI.
+ (find_basis_for_base_expr): Don't record a basis if the LHS of the
+ basis appears in an abnormal PHI.
+
+2017-09-29 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c
+ (translate_isl_ast_to_gimple::set_codegen_error): New function.
+ (binary_op_to_tree): Use it.
+ (get_rename_from_scev): Likewise.
+ (copy_loop_phi_nodes): Likewise.
+ (copy_bb_and_scalar_dependences): Likewise.
+ (translate_pending_phi_nodes): Likewise.
+
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82339
+ * config/i386/i386.md (*movdi_internal peephole2): New -Os peephole
+ for movabsq $(i32 << shift), r64.
+
+2017-09-28 Uros Bizjak <ubizjak@gmail.com>
+
+ * config/i386/i386.c (ix86_print_operand_address_as): Do not check
+ index when encoding %esp as %rsp to avoid 0x67 prefix.
+
+2017-09-28 Sergey Shalnov <Sergey.Shalnov@intel.com>
+
+ * config/i386/i386.md (*movsf_internal, *movdf_internal):
+ Return 256-bit AVX modes for TARGET_PREFER_AVX256.
+
+2017-09-28 Thomas Preud'homme <thomas.preudhomme@arm.com>
+
+ * config/arm/arm.c (arm_option_override): Forbid ARMv8-M Security
+ Extensions with more than 16 double VFP registers.
+ (cmse_nonsecure_entry_clear_before_return): Remove second entry of
+ to_clear_mask and all code related to it. Replace the remaining
+ entry by a sbitmap and adapt code accordingly.
+
+2017-09-28 Henry Linjamäki <henry.linjamaki@parmance.com>
+
+ * brig-builtins.def: Change pure attributes to const.
+
+2017-09-28 Joseph Myers <joseph@codesourcery.com>
+
+ * config.gcc (default_gnu_indirect_function): Default to yes for
+ sparc*-*-linux* with glibc.
+
+2017-09-28 Joseph Myers <joseph@codesourcery.com>
+
+ * config/aarch64/aarch64.c (aarch64_elf_asm_constructor)
+ (aarch64_elf_asm_destructor): Pass SECTION_NOTYPE to get_section
+ when creating .init_array and .fini_array sections with priority
+ specified.
+
+2017-09-27 Christophe Lyon <christophe.lyon@linaro.org>
+
+ PR target/71727
+ * config/aarch64/aarch64.c
+ (aarch64_builtin_support_vector_misalignment): Always return false
+ when misalignment is unknown.
+
+2017-09-27 Kelvin Nilsen <kelvin@gcc.gnu.org>
+
+ * config/rs6000/rs6000-p8swap.c (const_load_sequence_p): Revise
+ this function to return false if the definition used by the swap
+ instruction is artificial, or if the memory address from which the
+ constant value is loaded is not represented by a base address held
+ in a register or if the base address register is a frame or stack
+ pointer. Additionally, return false if the base address of the
+ loaded constant is a SYMBOL_REF but is not considered to be a
+ constant.
+ (replace_swapped_load_constant): New function.
+ (rs6000_analyze_swaps): Add a new pass to replace a swap of a
+ loaded constant vector with a load of a swapped constant vector.
+
+2017-09-27 Carl Love <cel@us.ibm.com>
+
+ * config/rs6000/rs6000-builtin.def (BU_FP_1MISC_1): Add define macro.
+ (FCTID, FCTIW): Add BU_FP_MISC_1 macro expansion for builtins.
+ * config/rs6000/rs6000.md (lrintsfsi2): Add define_insn for the
+ fctiw instruction.
+
+2017-09-27 Alexander Monakov <amonakov@ispras.ru>
+
+ * haifa-sched.c (autopref_rank_for_schedule): Order 'irrelevant' insns
+ first, always call autopref_rank_data otherwise.
+
+2017-09-27 Richard Biener <rguenther@suse.de>
+
+ * graphite-scop-detection.c (find_scop_parameters): Move
+ loop bound handling ...
+ (gather_bbs::before_dom_children): ... here, avoiding the need
+ to build scop_info->loop_nest.
+ (record_loop_in_sese): Remove.
+ * sese.h (sese_info_t::loop_nest): Remove.
+ * sese.c (new_sese_info): Do not allocate loop_nest.
+ (free_sese_info): Do not free loop_nest.
+
+2017-09-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82159
+ * gimplify.c (gimplify_modify_expr): Don't optimize away zero sized
+ lhs from calls if the lhs has addressable type.
+
+2017-09-27 Richard Biener <rguenther@suse.de>
+
+ * graphite.h (scop::max_alias_set): New member.
+ * graphite-scop-detection.c: Remove references to non-existing
+ --param in comments.
+ (build_alias_sets): Record the maximum alias set used for drs.
+ (build_scops): Support zero as unlimited for
+ --param graphite-max-arrays-per-scop.
+ * graphite-sese-to-poly.c (add_scalar_version_numbers): Remove
+ and inline into ...
+ (build_poly_sr_1): ... here. Compute alias set based on the
+ maximum alias set used for drs rather than
+ PARAM_GRAPHITE_MAX_ARRAYS_PER_SCOP
+
+2017-09-27 Richard Biener <rguenther@suse.de>
+
+ * graphite-optimize-isl.c (get_schedule_for_node_st): Allow
+ --param loop-block-tile-size=0 to disable tiling.
+
+2017-09-27 Richard Biener <rguenther@suse.de>
+
+ * doc/invoke.texi (graphite-max-bbs-per-function): Remove.
+ (graphite-max-nb-scop-params): Document special value zero.
+ * domwalk.h (dom_walker::STOP): New symbolical constant.
+ (dom_walker::dom_walker): Add optional parameter for bb to
+ RPO mapping.
+ (dom_walker::~dom_walker): Declare.
+ (dom_walker::before_dom_children): Document STOP return value.
+ (dom_walker::m_user_bb_to_rpo): New member.
+ (dom_walker::m_bb_to_rpo): Likewise.
+ * domwalk.c (dom_walker::dom_walker): Compute bb to RPO
+ mapping here if not provided by the user.
+ (dom_walker::~dom_walker): Free bb to RPO mapping if not
+ provided by the user.
+ (dom_walker::STOP): Define.
+ (dom_walker::walk): Do not compute bb to RPO mapping here.
+ Support STOP return value from before_dom_children to stop
+ walking.
+ * graphite-optimize-isl.c (optimize_isl): If the schedule
+ is the same still generate code if -fgraphite-identity
+ or -floop-parallelize-all are given.
+ * graphite-scop-detection.c: Include cfganal.h.
+ (gather_bbs::gather_bbs): Get and pass through bb to RPO
+ mapping.
+ (gather_bbs::before_dom_children): Return STOP for BBs
+ not in the region.
+ (build_scops): Compute bb to RPO mapping and pass it to
+ the domwalk. Treat --param graphite-max-nb-scop-params=0
+ as not limiting the number of params.
+ * graphite.c (graphite_initialize): Remove limit on the
+ number of basic-blocks in a function.
+ * params.def (PARAM_GRAPHITE_MAX_BBS_PER_FUNCTION): Remove.
+ (PARAM_GRAPHITE_MAX_NB_SCOP_PARAMS): Adjust to documented
+ default value of 10.
+
+2017-09-26 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/vsx.md (peephole for optimizing move SF to GPR):
+ Adjust code to eliminate needing to do the shift right 32-bits
+ operation after XSCVDPSPN.
+
+2017-09-26 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ * match.pd ((X / Y) == 0 -> X < Y): New pattern.
+ ((X / Y) != 0 -> X >= Y): Likewise.
+
+2017-09-26 Carl Love <cel@us.ibm.com>
+
+ * config/rs6000/rs6000-c.c (P9V_BUILTIN_VEC_XL_LEN_R,
+ P9V_BUILTIN_VEC_XST_LEN_R): Add support for builtins
+ vector unsigned char vec_xl_len_r (unsigned char *, size_t);
+ void vec_xst_len_r (vector unsigned char, unsigned char *, size_t);
+ * config/rs6000/altivec.h (vec_xl_len_r, vec_xst_len_r): Add defines.
+ * config/rs6000/rs6000-builtin.def (XL_LEN_R, XST_LEN_R): Add
+ definitions and overloading.
+ * config/rs6000/rs6000.c (altivec_expand_builtin): Add case
+ statement for P9V_BUILTIN_XST_LEN_R.
+ (altivec_init_builtins): Add def_builtin for P9V_BUILTIN_STXVLL.
+ * config/rs6000/vsx.md (lxvll, stxvll, xl_len_r, xst_len_r): Add
+ define_expand and define_insn for the instructions and builtins.
+ * doc/extend.texi: Update the built-in documentation file for the new
+ built-in functions.
+ * config/rs6000/altivec.md (altivec_lvsl_reg, altivec_lvsr_reg): Add
+ define_insn for the instructions
+
+2017-09-26 Krister Walfridsson <krister.walfridsson@gmail.com>
+
+ PR target/39570
+ * gcc/config/netbsd-protos.h: New file.
+ * gcc/config/netbsd.c: New file.
+ * gcc/config/netbsd.h (SUBTARGET_INIT_BUILTINS): Define.
+ * gcc/config/t-netbsd: New file.
+ * gcc/config.gcc (tm_p_file): Add netbsd-protos.h.
+ (tmake_file) Add t-netbsd.
+ (extra_objs) Add netbsd.o.
+
+2017-09-26 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/82143
+ PR fortran/82324
+ * doc/sourcebuild.texi: Document fortran_real_10 and fortran_real_16.
+
+2017-09-26 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * config/rs6000/rs6000.md (extendsi<mode>2): Add a splitter to do
+ sign extension from a vector register to a GPR by doing a 32-bit
+ direct move and then an EXTSW.
+ (extendsi<mode>2 splitter): Likewise.
+ (movsi_from_sf): Adjust code to eliminate doing a 32-bit shift
+ right or vector extract after doing XSCVDPSPN. Use
+ zero_extendsidi2 instead of p8_mfvsrd_4_disf to move the value to
+ the GPRs.
+ (movdi_from_sf_zero_ext): Likewise.
+ (reload_gpr_from_vsxsf): Likewise.
+ (p8_mfvsrd_4_disf): Delete, no longer used.
+ (movsi_from_df): Optimize converting a DFmode to a SFmode, and
+ then needing to move the SFmode to a GPR to use the XSCVDPSP
+ instruction instead of FRSP and XSCVDPSPN.
+ * config/rs6000/vsx.md (vsx_xscvspdp_scalar2): Move insn so that
+ it is adjacent to the other XSCVSPDP insns.
+ (vsx_xscvdpsp_scalar): Use "ww" constraint instead of "f" to allow
+ SFmode to be in traditional Altivec registers.
+ (vsx_xscvdpspn): Eliminate useless alternative constraint.
+ (vsx_xscvspdpn): Likewise.
+ (vsx_xscvspdpn_scalar): Likewise.
+
+2017-09-26 Martin Jambor <mjambor@suse.cz>
+
+ * tree-sra.c (compare_access_positions): Put integral types first,
+ stabilize sorting of integral types, remove conditions putting
+ non-full-precision integers last.
+ (sort_and_splice_var_accesses): Disable scalarization if a
+ non-integert would be represented by a non-full-precision integer.
+
+2017-09-26 Joseph Myers <joseph@codesourcery.com>
+
+ * config/microblaze/linux.h (TARGET_ASM_FILE_END): Likewise.
+ * config/pa/pa.h (NEED_INDICATE_EXEC_STACK): Likewise.
+ * config/pa/pa-linux.h (NEED_INDICATE_EXEC_STACK): Likewise.
+ * config/pa/pa.c (pa_hpux_file_end): Rename to pa_file_end.
+ Define unconditionally, with [ASM_OUTPUT_EXTERNAL_REAL]
+ conditionals inside the function instead of around it. Call
+ file_end_indicate_exec_stack if NEED_INDICATE_EXEC_STACK.
+ (TARGET_ASM_FILE_END): Define unconditionally to pa_file_end.
+
+2017-09-26 Richard Biener <rguenther@suse.de>
+
+ * graphite-scop-detection.c (scop_detection::build_scop_depth): Rewrite,
+ fold in ...
+ (scop_detection::build_scop_breadth): ... this. Removed.
+ (scop_detection::loop_is_valid_in_scop): Fold into single caller.
+ (scop_detection::harmful_stmt_in_bb): Likewise.
+ (scop_detection::graphite_can_represent_stmt): Likewise.
+ (scop_detection::loop_body_is_valid_scop): Likewise. Remove recursion.
+ (scop_detection::can_represent_loop): Remove recursion, fold in ...
+ (scop_detection::can_represent_loop_1): ... this. Removed.
+ (scop_detection::harmful_loop_in_region): Simplify after inlining
+ the above and remove more quadraticness.
+ (build_scops): Adjust.
+ * tree-data-ref.c (loop_nest_has_data_refs): Remove pointless
+ quadraticness.
+
+2017-09-26 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82267
+ * config/i386/i386.c (ix86_print_operand_address_as): Only test
+ REGNO (base) == SP_REG if base is a REG.
+
+ PR middle-end/35691
+ * tree-ssa-reassoc.c (update_range_test): Dump r->exp each time
+ if it is different SSA_NAME.
+ (optimize_range_tests_cmp_bitwise): New function.
+ (optimize_range_tests): Call it.
+
+2017-09-26 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82321
+ * graphite.c (canonicalize_loop_closed_ssa): Properly check
+ for the def being inside the loop.
+
+2017-09-26 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/vx-builtins.md ("vmslg"): Add missing operand in
+ assembler output.
+ * config/s390/s390-builtins.def: Fix constraint on op4.
+
+2017-09-26 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/s390.c (s390_expand_vec_compare): Use the new mode
+ independent expanders.
+ * config/s390/vector.md ("vec_cmpuneq", "vec_cmpltgt")
+ ("vec_ordered", "vec_unordered"): New expanders.
+
+2017-09-26 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/s390.c (s390_preferred_simd_mode): Return V4SFmode
+ for SFmode.
+
+2017-09-26 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/vector.md ("vec_unpacks_low_v16qi"): Rename to
+ vec_unpacks_lo_v16qi.
+ ("vec_unpacku_low_v16qi"): Rename to vec_unpacku_lo_v16qi.
+
+2017-09-26 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/vector.md ("vec_unpacks_lo_v4sf")
+ ("vec_unpacks_hi_v4sf", "vec_unpacks_lo_v2df")
+ ("vec_unpacks_hi_v2df", "vec_pack_trunc_v2df"): New expanders.
+
+2017-09-26 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/predicates.md ("const_shift_by_byte_operand"): New
+ predicate.
+ * config/s390/vector.md ("*vec_srb<mode>"): Change modes to V_128
+ and V16QI.
+ ("*vec_slb<mode>"): New insn pattern.
+ ("vec_shr_<mode>"): New expander.
+ * config/s390/vx-builtins.md ("vec_slb<mode>"): Turn into expander
+ and force the shift count operand to V16QImode.
+ ("vec_srb<mode>"): Set shift count mode to V16QI.
+
+2017-09-26 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * config/s390/vector.md ("vec_widen_umult_lo_<mode>")
+ ("vec_widen_umult_hi_<mode>", "vec_widen_smult_lo_<mode>")
+ ("vec_widen_smult_hi_<mode>"): New expander definitions.
+
+2017-09-26 Richard Earnshaw <rearnsha@arm.com>
+
+ PR target/82175
+ * config/arm/arm.h (DRIVER_SELF_SPECS): Separate sub-rules with commas.
+
+2017-09-26 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82320
+ * tree-ssa-sccvn.c (set_ssa_val_to): Changing undef to undef
+ isn't a change.
+
+2017-09-25 Jeff Law <law@redhat.com>
+
+ * config/rs6000/rs6000-protos.h (output_probe_stack_range): Update
+ prototype for new argument.
+ * config/rs6000/rs6000.c (rs6000_emit_allocate_stack_1): New function,
+ mostly extracted from rs6000_emit_allocate_stack.
+ (rs6000_emit_probe_stack_range_stack_clash): New function.
+ (rs6000_emit_allocate_stack): Call
+ rs6000_emit_probe_stack_range_stack_clash as needed.
+ (rs6000_emit_probe_stack_range): Add additional argument
+ to call to gen_probe_stack_range{si,di}.
+ (output_probe_stack_range): New.
+ (output_probe_stack_range_1): Renamed from output_probe_stack_range.
+ (output_probe_stack_range_stack_clash): New.
+ (rs6000_emit_prologue): Emit notes into dump file as requested.
+ * rs6000.md (allocate_stack): Handle -fstack-clash-protection.
+ (probe_stack_range<P:mode>): Operand 0 is now early-clobbered.
+ Add additional operand and pass it to output_probe_stack_range.
+
+2017-09-25 Bin Cheng <bin.cheng@arm.com>
+
+ PR tree-optimization/82163
+ * tree-ssa-loop-manip.h (verify_loop_closed_ssa): New parameter.
+ (checking_verify_loop_closed_ssa): New parameter.
+ * tree-ssa-loop-manip.c (check_loop_closed_ssa_use): Delete.
+ (check_loop_closed_ssa_stmt): Delete.
+ (check_loop_closed_ssa_def, check_loop_closed_ssa_bb): New functions.
+ (verify_loop_closed_ssa): Check loop closed ssa form for LOOP.
+ (tree_transform_and_unroll_loop): Check loop closed ssa form only for
+ changed loops.
+
+2017-09-25 Pekka Jaaskelainen <pekka@parmance.com>
+
+ * brig-builtins.def: Treat HSAIL barrier builtins as
+ setjmp/longjump style functions.
+
+2017-09-25 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * target.def (constant_alignment): New hook.
+ * defaults.h (CONSTANT_ALIGNMENT): Delete.
+ * doc/tm.texi.in (CONSTANT_ALIGNMENT): Replace with...
+ (TARGET_CONSTANT_ALIGNMENT): ...this new hook.
+ * doc/tm.texi: Regenerate.
+ * targhooks.h (default_constant_alignment): Declare.
+ (constant_alignment_word_strings): Likewise.
+ * targhooks.c (default_constant_alignment): New function.
+ (constant_alignment_word_strings): Likewise.
+ * builtins.c (get_object_alignment_2): Use targetm.constant_alignment
+ instead of CONSTANT_ALIGNMENT.
+ * varasm.c (align_variable, get_variable_align, build_constant_desc)
+ (force_const_mem): Likewise.
+ * config/aarch64/aarch64.h (CONSTANT_ALIGNMENT): Delete.
+ * config/aarch64/aarch64.c (aarch64_constant_alignment): New function.
+ (aarch64_classify_address): Call it instead of CONSTANT_ALIGNMENT.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/alpha/alpha.h (CONSTANT_ALIGNMENT): Delete commented-out
+ definition.
+ * config/arc/arc.h (CONSTANT_ALIGNMENT): Delete.
+ * config/arc/arc.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/arm/arm.h (CONSTANT_ALIGNMENT_FACTOR): Delete.
+ (CONSTANT_ALIGNMENT): Likewise.
+ * config/arm/arm.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (arm_constant_alignment): New function.
+ * config/bfin/bfin.h (CONSTANT_ALIGNMENT): Delete.
+ * config/bfin/bfin.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/cr16/cr16.h (CONSTANT_ALIGNMENT): Delete.
+ * config/cr16/cr16.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/cris/cris.h (CONSTANT_ALIGNMENT): Delete.
+ * config/cris/cris.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (cris_constant_alignment): New function.
+ * config/epiphany/epiphany.h (CONSTANT_ALIGNMENT): Delete.
+ * config/epiphany/epiphany.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (epiphany_constant_alignment): New function.
+ * config/fr30/fr30.h (CONSTANT_ALIGNMENT): Delete.
+ * config/fr30/fr30.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/frv/frv.h (CONSTANT_ALIGNMENT): Delete.
+ * config/frv/frv.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/ft32/ft32.h (CONSTANT_ALIGNMENT): Delete.
+ * config/ft32/ft32.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/i386/i386.h (CONSTANT_ALIGNMENT): Delete.
+ * config/i386/i386-protos.h (ix86_constant_alignment): Delete.
+ * config/i386/i386.c (ix86_constant_alignment): Make static.
+ Use the same interface as the target hook.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/ia64/ia64.h (CONSTANT_ALIGNMENT): Delete.
+ * config/ia64/ia64.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/iq2000/iq2000.h (CONSTANT_ALIGNMENT): Delete.
+ * config/iq2000/iq2000.c (iq2000_constant_alignment): New function.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/lm32/lm32.h (CONSTANT_ALIGNMENT): Delete.
+ * config/lm32/lm32.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/m32r/m32r.h (CONSTANT_ALIGNMENT): Delete.
+ * config/m32r/m32r.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/mcore/mcore.h (CONSTANT_ALIGNMENT): Delete.
+ * config/mcore/mcore.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/microblaze/microblaze.h (CONSTANT_ALIGNMENT): Delete.
+ * config/microblaze/microblaze.c (microblaze_constant_alignment):
+ New function.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/mips/mips.h (CONSTANT_ALIGNMENT): Delete.
+ * config/mips/mips.c (mips_constant_alignment): New function.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/mmix/mmix.h (CONSTANT_ALIGNMENT): Delete.
+ * config/mmix/mmix-protos.h (mmix_constant_alignment): Delete.
+ * config/mmix/mmix.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (mmix_constant_alignment): Make static. Use the same interface
+ as the target hook.
+ * config/moxie/moxie.h (CONSTANT_ALIGNMENT): Delete.
+ * config/moxie/moxie.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/nios2/nios2.h (CONSTANT_ALIGNMENT): Delete.
+ * config/nios2/nios2.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/pa/pa.h (CONSTANT_ALIGNMENT): Delete.
+ * config/pa/pa.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/powerpcspe/powerpcspe.h (CONSTANT_ALIGNMENT): Delete.
+ * config/powerpcspe/powerpcspe.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (rs6000_constant_alignment): New function.
+ * config/riscv/riscv.h (CONSTANT_ALIGNMENT): Delete.
+ * config/riscv/riscv.c (riscv_constant_alignment): New function.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/rs6000/rs6000.h (CONSTANT_ALIGNMENT): Delete.
+ * config/rs6000/rs6000.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (rs6000_constant_alignment): New function.
+ * config/s390/s390.h (CONSTANT_ALIGNMENT): Delete.
+ * config/s390/s390.c (s390_constant_alignment): New function.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/sh/sh.h (CONSTANT_ALIGNMENT): Delete.
+ * config/sh/sh.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/sparc/sparc.h (CONSTANT_ALIGNMENT): Delete.
+ * config/sparc/sparc.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (sparc_constant_alignment): New function.
+ * config/spu/spu.h (CONSTANT_ALIGNMENT): Delete.
+ * config/spu/spu.c (spu_constant_alignment): New function.
+ (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ * config/stormy16/stormy16.h (CONSTANT_ALIGNMENT): Delete.
+ * config/stormy16/stormy16.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/tilegx/tilegx.h (CONSTANT_ALIGNMENT): Delete.
+ * config/tilegx/tilegx.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/tilepro/tilepro.h (CONSTANT_ALIGNMENT): Delete.
+ * config/tilepro/tilepro.c (TARGET_CONSTANT_ALIGNMENT): Redefine to
+ constant_alignment_word_strings.
+ * config/visium/visium.h (CONSTANT_ALIGNMENT): Delete.
+ * config/visium/visium.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (visium_constant_alignment): New function.
+ * config/xtensa/xtensa.h (CONSTANT_ALIGNMENT): Delete.
+ * config/xtensa/xtensa.c (TARGET_CONSTANT_ALIGNMENT): Redefine.
+ (xtensa_constant_alignment): New function.
+ * system.h (CONSTANT_ALIGNMENT): Poison.
+
+2017-09-25 Will Schmidt <will_schmidt@vnet.ibm.com>
+
+ * config/rs6000/rs6000.c (rs6000_gimple_fold_builtin): Add handling
+ for early folding of vector stores (ALTIVEC_BUILTIN_ST_*).
+ (rs6000_builtin_valid_without_lhs): New helper function.
+ * config/rs6000/rs6000-c.c (altivec_resolve_overloaded_builtin):
+ Remove obsoleted code for handling ALTIVEC_BUILTIN_VEC_ST.
+
+2017-09-25 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * target.h (vec_perm_indices): Use unsigned short rather than
+ unsigned char.
+ (auto_vec_perm_indices): Likewise.
+ * config/aarch64/aarch64.c (aarch64_vectorize_vec_perm_const_ok):
+ Use unsigned int rather than unsigned char.
+ * config/arm/arm.c (arm_vectorize_vec_perm_const_ok): Likewise.
+
+2017-09-25 Richard Biener <rguenther@suse.de>
+
+ * cfgloop.h (sort_sibling_loops): Declare.
+ * cfgloop.c (sort_sibling_loops_cmp): New helper.
+ (sort_sibling_loops): New function sorting the sibling loop list
+ in RPO order.
+ * graphite.c (graphite_transform_loops): Sort sibling loops.
+
+2017-09-25 Richard Sandiford <richard.sandifird@linaro.org>
+
+ * target.def (vec_perm_const_ok): Change sel parameter to
+ vec_perm_indices.
+ * optabs-query.c (can_vec_perm_p): Update accordingly.
+ * doc/tm.texi: Regenerate.
+ * config/aarch64/aarch64.c (expand_vec_perm_d): Change perm to
+ auto_vec_perm_indices and remove separate nelt field.
+ (aarch64_evpc_trn, aarch64_evpc_uzp, aarch64_evpc_zip)
+ (aarch64_evpc_ext, aarch64_evpc_rev, aarch64_evpc_dup)
+ (aarch64_evpc_tbl, aarch64_expand_vec_perm_const_1)
+ (aarch64_expand_vec_perm_const): Update accordingly.
+ (aarch64_vectorize_vec_perm_const_ok): Likewise. Change sel
+ to vec_perm_indices.
+ * config/arm/arm.c (expand_vec_perm_d): Change perm to
+ auto_vec_perm_indices and remove separate nelt field.
+ (arm_evpc_neon_vuzp, arm_evpc_neon_vzip, arm_evpc_neon_vrev)
+ (arm_evpc_neon_vtrn, arm_evpc_neon_vext, arm_evpc_neon_vtbl)
+ (arm_expand_vec_perm_const_1, arm_expand_vec_perm_const): Update
+ accordingly.
+ (arm_vectorize_vec_perm_const_ok): Likewise. Change sel
+ to vec_perm_indices.
+ * config/i386/i386.c (ix86_vectorize_vec_perm_const_ok): Change
+ sel to vec_perm_indices.
+ * config/ia64/ia64.c (ia64_vectorize_vec_perm_const_ok): Likewise.
+ * config/mips/mips.c (mips_vectorize_vec_perm_const_ok): Likewise.
+ * config/powerpcspe/powerpcspe.c (rs6000_vectorize_vec_perm_const_ok):
+ Likewise.
+ * config/rs6000/rs6000.c (rs6000_vectorize_vec_perm_const_ok):
+ Likewise.
+
+2017-09-25 Pierre-Marie de Rodat <derodat@adacore.com>
+
+ PR debug/82155
+ * dwarf2out.c (dwarf2out_early_global_decl): Call dwarf2out_decl
+ on the FUNCTION_DECL function context if it has a DIE that is a
+ declaration.
+
+2017-09-25 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82285
+ * tree-vect-patterns.c (vect_recog_bool_pattern): Also handle
+ enumeral types.
+
+2017-09-25 Tom de Vries <tom@codesourcery.com>
+
+ PR target/80035
+ PR target/81069
+ * config/nvptx/nvptx.c (nvptx_output_call_insn): Add exit after call to
+ noreturn function.
+
+2017-09-25 Richard Biener <rguenther@suse.de>
+
+ * graphite-optimize-isl.c (optimize_isl): Fail and dump if
+ ISL errors other than isl_error_quota happen. Dump if the
+ schedule is the same.
+ * graphite-sese-to-poly.c (build_poly_scop): Fail on ISL
+ errors instead of aborting inside ISL.
+
+2017-09-25 Iain Sandoe <iain@codesourcery.com>
+
+ PR target/80556
+ * config/i386/darwin.h (REAL_LIB_SPEC): New; put libSystem ahead
+ of libgcc_eh for m64.
+ * config/i386/darwin64.h: Likewise.
+
+2017-09-25 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/82144
+ * dwarf2out.c (gen_enumeration_type_die): Do not add alignment
+ attribute for incomplete types nor twice for complete ones.
+
+2017-09-24 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/82267
+ * config/i386/i386.c (ix86_print_operand_address_as): Encode
+ %esp as %rsp to avoid 0x67 prefix if there is no index or base
+ register.
+
+2017-09-23 Uros Bizjak <ubizjak@gmail.com>
+
+ PR bootstrap/82306
+ * config/i386/i386.opt (mprefer-avx256): Use
+ ix86_target_flags variable.
+ * config/i386/i386.c (ix86_target_string): Move
+ -mprefer-avx256 to flag2_opts.
+
+2017-09-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/35691
+ * match.pd: Simplify x == -1 & y == -1 into (x & y) == -1
+ and x != -1 | y != -1 into (x & y) != -1.
+
+2017-09-22 Steve Ellcey <sellcey@cavium.com>
+
+ * config.gcc: Add new case statement to set
+ default_gnu_indirect_function. Remove it from x86_64-*-linux*,
+ i[34567]86-*, powerpc*-*-linux*spe*, powerpc*-*-linux*, s390-*-linux*,
+ s390x-*-linux* case statements. Added aarch64 to the list of
+ supported architectures.
+
+2017-09-22 Richard Sandiford <richard.sandiford@linaro.org>
+
+ PR tree-optimization/82289
+ * tree-vect-data-refs.c (vect_get_peeling_costs_all_drs): Check
+ STMT_VINFO_RELEVANT_P.
+
+2017-09-22 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * tree-vrp.c (extract_range_from_multiplicative_op_1): Assert
+ for VR_RANGE only; don't allow VR_ANTI_RANGE.
+ (extract_range_from_binary_expr_1): Don't call
+ extract_range_from_multiplicative_op_1 if !range_int_cst_p.
+
+2017-09-22 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * target.def (preferred_vector_alignment): New hook.
+ * doc/tm.texi.in (TARGET_VECTORIZE_PREFERRED_VECTOR_ALIGNMENT): New
+ hook.
+ * doc/tm.texi: Regenerate.
+ * targhooks.h (default_preferred_vector_alignment): Declare.
+ * targhooks.c (default_preferred_vector_alignment): New function.
+ * tree-vectorizer.h (dataref_aux): Add a target_alignment field.
+ Expand commentary.
+ (DR_TARGET_ALIGNMENT): New macro.
+ (aligned_access_p): Update commentary.
+ (vect_known_alignment_in_bytes): New function.
+ * tree-vect-data-refs.c (vect_calculate_required_alignment): New
+ function.
+ (vect_compute_data_ref_alignment): Set DR_TARGET_ALIGNMENT.
+ Calculate the misalignment based on the target alignment rather than
+ the vector size.
+ (vect_update_misalignment_for_peel): Use DR_TARGET_ALIGMENT
+ rather than TYPE_ALIGN / BITS_PER_UNIT to update the misalignment.
+ (vect_enhance_data_refs_alignment): Mask the byte misalignment with
+ the target alignment, rather than masking the element misalignment
+ with the number of elements in a vector. Also use the target
+ alignment when calculating the maximum number of peels.
+ (vect_find_same_alignment_drs): Use vect_calculate_required_alignment
+ instead of TYPE_ALIGN_UNIT.
+ (vect_duplicate_ssa_name_ptr_info): Remove stmt_info parameter.
+ Measure DR_MISALIGNMENT relative to DR_TARGET_ALIGNMENT.
+ (vect_create_addr_base_for_vector_ref): Update call accordingly.
+ (vect_create_data_ref_ptr): Likewise.
+ (vect_setup_realignment): Realign by ANDing with
+ -DR_TARGET_MISALIGNMENT.
+ * tree-vect-loop-manip.c (vect_gen_prolog_loop_niters): Calculate
+ the number of peels based on DR_TARGET_ALIGNMENT.
+ * tree-vect-stmts.c (get_group_load_store_type): Compare the gap
+ with the guaranteed alignment boundary when deciding whether
+ overrun is OK.
+ (vectorizable_mask_load_store): Interpret DR_MISALIGNMENT
+ relative to DR_TARGET_ALIGNMENT instead of TYPE_ALIGN_UNIT.
+ (ensure_base_align): Remove stmt_info parameter. Get the
+ target base alignment from DR_TARGET_ALIGNMENT.
+ (vectorizable_store): Update call accordingly. Interpret
+ DR_MISALIGNMENT relative to DR_TARGET_ALIGNMENT instead of
+ TYPE_ALIGN_UNIT.
+ (vectorizable_load): Likewise.
+
+2017-09-22 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * tree-vectorizer.h (vect_get_scalar_dr_size): New function.
+ * tree-vect-data-refs.c (vect_update_misalignment_for_peel): Use it.
+ (vect_enhance_data_refs_alignment): Likewise.
+
+2017-09-22 Richard Earnshaw <richard.earnshaw@arm.com>
+
+ * config/arm/parsecpu.awk (fatal): Note that we've encountered an
+ error. Only quit immediately if parsing is complete.
+ (BEGIN): Initialize fatal_err and parse_done.
+ (begin fpu, end fpu): Check number of arguments.
+ (begin arch, end arch): Likewise.
+ (begin cpu, end cpu): Likewise.
+ (cname, tune for, tune flags, architecture, fpu, option): Likewise.
+ (optalias): Likewise.
+
+2017-09-22 Richard Earnshaw <richard.earnshaw@arm.com>
+
+ * config.gcc (arm*-*-*): Don't add arm-isa.h to tm_p_file.
+ * config/arm/arm-isa.h: Delete. Move definitions to ...
+ * arm-cpus.in: ... here. Use new feature and fgroup values.
+ * config/arm/arm.c (arm_option_override): Use lower case for feature
+ bit names.
+ * config/arm/arm.h (TARGET_HARD_FLOAT): Likewise.
+ (TARGET_VFP3, TARGET_VFP5, TARGET_FMA): Likewise.
+ * config/arm/parsecpu.awk (END): Add new command 'isa'.
+ (isa_pfx): Delete.
+ (print_isa_bits_for): New function.
+ (gen_isa): New function.
+ (gen_comm_data): Use print_isa_bits_for.
+ (define feature): New keyword.
+ (define fgroup): New keyword.
+ * config/arm/t-arm (TM_H): Remove.
+ (GTM_H): Add arm-isa.h.
+ (arm-isa.h): Add rule to generate file.
+ * common/config/arm/arm-common.c: (arm_canon_arch_option): Use lower
+ case for feature bit names.
+
+2017-09-22 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c (graphite_verify): Inline into
+ single caller.
+ (graphite_regenerate_ast_isl): Do not reset SCEV. Move debug
+ print of no dependency loops ...
+ * graphite.c (graphite_transform_loops): ... here.
+ (canonicalize_loop_closed_ssa_form): Work from inner to outer
+ loops.
+ (same_close_phi_node, remove_duplicate_close_phi,
+ make_close_phi_nodes_unique, defined_in_loop_p): Fold into ...
+ (canonicalize_loop_closed_ssa): ... here and simplify.
+ * graphite-optimize-isl.c: Include tree-vectorizer.h.
+ (optimize_isl): Use dump_printf_loc to tell when we stopped
+ optimizing because of an ISL timeout.
+
+2017-09-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82291
+ * tree-if-conv.c (predicate_mem_writes): Make sure to
+ remove writes in blocks predicated with false.
+
+2017-09-22 Richard Biener <rguenther@suse.de>
+
+ * sese.c: Include cfganal.h.
+ (if_region_set_false_region): Remove.
+ (create_if_region_on_edge): Likewise.
+ (move_sese_in_condition): Re-implement without destroying
+ dominators.
+
+2017-09-22 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c (translate_pending_phi_nodes):
+ Verify both BBs contain loop PHI nodes before dispatching to
+ copy_loop_phi_args.
+ (graphite_regenerate_ast_isl): Do not recompute dominators,
+ do not verify three times. Restructure for clarity.
+ * graphite-scop-detection.c (same_close_phi_node,
+ remove_duplicate_close_phi, make_close_phi_nodes_unique,
+ defined_in_loop_p, canonicalize_loop_closed_ssa,
+ canonicalize_loop_closed_ssa_form): Simplify, remove excess
+ checking and SSA rewrite, move to ...
+ * graphite.c: ... here. Include ssa.h and tree-ssa-loop-manip.h.
+ (graphite_initialize): Do not pass in ctx, do not reset the
+ SCEV cache, compute only dominators.
+ (graphite_transform_loops): Allocate ISL ctx after
+ graphite_initialize. Call canonicalize_loop_closed_ssa_form.
+ Maintain post-dominators only around build_scops.
+ * sese.c (if_region_set_false_region): Make static. Free
+ and recompute dominators.
+ (move_sese_in_condition): Assert we don't get called with
+ post-dominators computed.
+ * sese.h (if_region_set_false_region): Remove.
+
+2017-09-22 Sergey Shalnov <sergey.shalnov@intel.com>
+
+ * config/i386/sse.md ("mov<mode>_internal"): Use <sseinsnmode>
+ mode attribute for TARGET_AVX512VL.
+
+2017-09-21 Sergey Shalnov <sergey.shalnov@intel.com>
+
+ * config/i386/i386.opt (mprefer-avx256): New option.
+ * config/i386/i386.c (ix86_target_string): Add -mprefer-avx256
+ to flag_opts.
+ (ix86_preferred_simd_mode): Return 256-bit AVX modes
+ for TARGET_PREFER_AVX256.
+ * doc/invoke.texi (x86 Options): Document -mprefer-avx256.
+
+2017-09-21 Jeff Law <law@redhat.com>
+
+ * config/i386/i386.c (ix86_adjust_stack_and_probe_stack_clash):
+ Fix dump output if the only stack space is for pushed registers.
+
+2017-09-21 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * config/spu/spu.c (spu_sched_adjust_cost): Update after renaming
+ of insn_cost.
+
+2017-09-21 Martin Sebor <msebor@redhat.com>
+
+ PR c/81882
+ * doc/extend.texi (attribute ifunc): Avoid relying on ill-formed
+ code (in C++) or code that triggers warnings.
+
+2017-09-21 Eric Botcazou <ebotcazou@adacore.com>
+
+ * stor-layout.c (bit_from_pos): Do not distribute the conversion.
+
+2017-09-21 Segher Boessenkool <segher@kernel.crashing.org>
+
+ * haifa-sched.c: Rename insn_cost to insn_sched_cost.
+ * sched-rgn.c: Ditto.
+ * sel-sched-ir.c: Ditto.
+
+2017-09-21 Alexander Monakov <amonakov@ispras.ru>
+
+ * toplev.h (set_random_seed): Adjust return type.
+ * toplev.c (init_local_tick): Move eager initialization of random_seed
+ to get_random_seed. Adjust comment.
+ (init_random_seed): Inline to get_random_seed, delete.
+ (get_random_seed): Initialize random_seed lazily.
+ (set_random_seed): Do not return previous value.
+ (print_switch_value): Do not call get_random_seed.
+
+2017-09-21 Evgeny Kudryashov <kudryashov@ispras.ru>
+
+ * cgraph.c (delete_function_version): New, broken out from...
+ (cgraph_node::delete_function_version): ...here. Rename to
+ cgraph_node::delete_function_version_by_decl. Update all uses.
+ (cgraph_node::remove): Call delete_function_version.
+
+2017-09-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/81715
+ * tree-inline.c (expand_call_inline): Emit clobber stmts for
+ VAR_DECLs to which addressable non-volatile parameters are mapped
+ and for id->retvar after the return value assignment. Clear
+ id->retval and id->retbnd after inlining.
+
+2017-09-21 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82276
+ PR tree-optimization/82244
+ * tree-vrp.c (build_assert_expr_for): Set
+ SSA_NAME_OCCURS_IN_ABNORMAL_PHI if the variable we assert on
+ has it set.
+ (remove_range_assertions): Revert earlier change.
+
+2017-09-21 Wilco Dijkstra <wdijkstr@arm.com>
+
+ PR target/71951
+ * config/aarch64/aarch64.h (LIBGCC2_UNWIND_ATTRIBUTE): Define.
+
+2017-09-21 Richard Biener <rguenther@suse.de>
+
+ * graphite-isl-ast-to-gimple.c (graphite_regenerate_ast_isl):
+ Restore valid IL after code generation errors.
+ * graphite.c (graphite_transform_loops): Diagnose code
+ generation issues as MSG_MISSED_OPTIMIZATION and continue
+ with processing SCOPs.
+
+2017-09-21 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * calls.c (compute_argument_addresses): Use simplify_gen_binary
+ rather than choosing between plus_constant and gen_rtx_<CODE>.
+ * expr.c (emit_push_insn): Likewise.
+ (expand_expr_real_2): Likewise.
+
+2017-09-21 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * loop-unroll.c (split_iv): Call copy_rtx on the step.
+
+2017-09-21 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * tree.c (find_atomic_core_type): Check tree_fits_uhwi_p before
+ calling tree_to_uhwi.
+
+2017-09-21 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * tree-ssa-ccp.c (get_value_for_expr): Use a positive test for
+ INTEGER_CST rather than a negative test for ADDR_EXPR.
+
+2017-09-21 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * tree-vrp.c (extract_range_from_binary_expr_1): Check
+ int_cst_rangeN before calling value_range_constant_singleton (&vrN).
+
+2017-09-21 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/71351
+ * graphite-isl-ast-to-gimple.c (translate_isl_ast_to_gimple::
+ graphite_create_new_loop_guard): Remove, fold remaining parts
+ into caller ...
+ (translate_isl_ast_node_for): ... here and simplify.
+
+2017-09-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82260
+ * config/i386/i386.md (*movqi_internal): Replace (=q,q) alternative
+ with (=Q,Q), (=R,R) and (=r,r) alternatives, only enable the
+ latter two for 64-bit, renumber alternatives, for -Os imov (=q,n)
+ alternative always use QI mode, for -Os imov (=R,R) alternative
+ always use SI mode, for imov (=Q,Q) or (=r,r) alternatives
+ ignore -Os.
+
+2017-09-20 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+ Jeff Law <law@redhat.com>
+
+ * config/s390/s390.c (MIN_UNROLL_PROBES): Define.
+ (allocate_stack_space): New function, partially extracted from
+ s390_emit_prologue.
+ (s390_emit_prologue): Track offset to most recent stack probe.
+ Code to allocate space moved into allocate_stack_space.
+ Dump actions when no stack is allocated.
+ (s390_prologue_plus_offset): New function.
+ (s390_emit_stack_probe): Likewise.
+
+2017-09-20 Alexandre Oliva <aoliva@redhat.com>
+
+ * common.opt (Wa, Wl, Wp, g, gz=): Add
+ RejectNegative.
+ (gno-column-info): Remove.
+ (gcolumn-info): Drop RejectNegative.
+ (gno-): New prefix.
+ (gno-record-gcc-switches): Remove.
+ (grecord-gcc-switches): Drop RejectNegative.
+ (gno-split-dwarf): Remove.
+ (gsplit-dwarf): Drop RejectNegative.
+ (gno-strict-dwarf): Remove.
+ (gstrict-dwarf): Drop RejectNegative.
+ * config/darwin.opt (gfull, gused): Add RejectNegative.
+ * dwarf2out.c (gen_producer_string): Drop
+ gno-record-gcc-switches handler.
+ * optc-gen.awk: Add g to prefixes with negative forms.
+ * opts-common.c (remapping_prefix_p): New.
+ (find_opt): Check it.
+ (generate_canonical_option): Test g prefix.
+ (option_map): Add -gno- mapping.
+ (add_misspelling_candidates): Check remapping_prefix_p.
+
+2017-09-20 Jeff Law <law@redhat.com>
+
+ * config/powerpcspe/powerpcspe.c (rs6000_expand_prologue): Fix
+ thinko in stack clash protection support.
+
+ * explow.c (compute_stack_clash_protection_loop_data): Use
+ CONST_INT_P instead of explicit test. Verify object is a
+ CONST_INT_P before looking at INTVAL.
+ (anti_adjust_stack_and_probe_stack_clash): Use CONST_INT_P
+ instead of explicit test.
+
+2017-09-20 Segher Boessenkool <segher@kernel.crashing.org>
+
+ PR target/77687
+ * config/rs6000/rs6000.md (stack_restore_tie): Store to a scratch
+ address instead of to r1 and r11.
+
+2017-09-20 Sebastian Peryt <sebastian.peryt@intel.com>
+
+ * config.gcc: Support "knm".
+ * config/i386/driver-i386.c (host_detect_local_cpu): Detect "knm".
+ * config/i386/i386-c.c (ix86_target_macros_internal): Handle
+ PROCESSOR_KNM.
+ * config/i386/i386.c (m_KNM): Define.
+ (processor_target_table): Add "knm".
+ (PTA_KNM): Define.
+ (ix86_option_override_internal): Add "knm".
+ (ix86_issue_rate): Add PROCESSOR_KNM.
+ (ix86_adjust_cost): Ditto.
+ (ia32_multipass_dfa_lookahead): Ditto.
+ (get_builtin_code_for_version): Handle PROCESSOR_KNM.
+ (fold_builtin_cpu): Add M_INTEL_KNM.
+ * config/i386/i386.h (processor_costs): Define TARGET_KNM.
+ (processor_type): Add PROCESSOR_KNM.
+ * config/i386/x86-tune.def: Add m_KNM.
+ * doc/invoke.texi: Add knm as x86 -march=/-mtune= CPU type.
+
+2017-09-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/80213
+ * graphite-scop-detection.c (trivially_empty_bb_p): Labels
+ are allowed in empty BBs as well.
+ (canonicalize_loop_closed_ssa): Also look for other complex
+ edges.
+ (scop_detection::get_sese): Include the loop-closed PHI block
+ in loop SESEs.
+ (scop_detection::merge_sese): Remove code adding extra blocks.
+ (scop_detection::region_has_one_loop): Adjust for get_sese changes.
+ (build_scops): Assert the final returned scop is invalid.
+
+2017-09-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82264
+ * tree-ssa-sccvn.c (vn_phi_eq): Use safe_dyn_cast to check
+ for GIMPLE_CONDs.
+ (vn_phi_lookup): Likewise.
+ (vn_phi_insert): Likewise.
- * config/i386/i386.md (*scc_bt<mode>): New insn_and_split pattern.
- (*scc_bt<mode>_1): Ditto.
- (*scc_bt<mode>_mask): Ditto.
+2017-09-20 Jakub Jelinek <jakub@redhat.com>
+
+ * dwarf2out.c (tree_add_const_value_attribute): For INTEGER_CST
+ that fits into uhwi or shwi, add DW_AT_const_value regardless
+ of early_dwarf without going through RTL, using add_AT_unsigned
+ or add_AT_int.
+
+ * dwarf2out.c (DEBUG_LTO_DWO_INFO_SECTION): Reorder defines.
+ (DEBUG_LTO_ABBREV_SECTION): Likewise.
+ (DEBUG_LTO_MACINFO_SECTION): Likewise.
+ (DEBUG_MACRO_SECTION): Likewise.
+ (DEBUG_LTO_MACRO_SECTION): Likewise.
+ (DEBUG_STR_DWO_SECTION): Likewise.
+ (DEBUG_LTO_STR_DWO_SECTION): Likewise.
+ (DEBUG_LTO_LINE_SECTION): Drop .dwo suffix from the name.
+ (DEBUG_LTO_DWO_LINE_SECTION): Define.
+ (DEBUG_LTO_LINE_STR_SECTION): Define.
+ (init_sections_and_labels): Initialize debug_line_str_section
+ variable. Initialize debug_loc_section for -gdwarf-5 to
+ DEBUG_LOCLISTS_SECTION. Formatting fixes.
+
+2017-09-20 Richard Biener <rguenther@suse.de>
+
+ * graphite-sese-to-poly.c (extract_affine): Properly handle
+ POINTER_PLUS_EXPR, BIT_NOT_EXPR and conversion to signed.
+
+2017-09-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/81373
+ * graphite-scop-detection.c (build_cross_bb_scalars_def):
+ Force SESE live-out defs to be handled even if they are
+ scev_analyzable_p.
+
+2017-09-19 Jeff Law <law@redhat.com>
+
+ * combine-stack-adj.c (combine_stack_adjustments_for_block): Do
+ nothing for stack adjustments with REG_STACK_CHECK.
+ * sched-deps.c (parse_add_or_inc): Reject insns with
+ REG_STACK_CHECK from dependency breaking.
+ * config/i386/i386.c (pro_epilogue_adjust_stack): Return insn.
+ (ix86_adjust_satck_and_probe_stack_clash): Add REG_STACK_NOTEs.
+ * reg-notes.def (STACK_CHECK): New note.
+
+ * config/i386/i386.c (ix86_adjust_stack_and_probe_stack_clash): New.
+ (ix86_expand_prologue): Dump stack clash info as needed.
+ Call ix86_adjust_stack_and_probe_stack_clash as needed.
+
+ * function.c (dump_stack_clash_frame_info): New function.
+ * function.h (dump_stack_clash_frame_info): Prototype.
+ (enum stack_clash_probes): New enum.
+
+ * config/alpha/alpha.c (alpha_expand_prologue): Also check
+ flag_stack_clash_protection.
+ * config/arm/arm.c (arm_compute_static_chain_stack_bytes): Likewise.
+ (arm_expand_prologue, thumb1_expand_prologue): Likewise.
+ (arm_frame_pointer_required): Likewise.
+ * config/ia64/ia64.c (ia64_compute_frame_size): Likewise.
+ (ia64_expand_prologue): Likewise.
+ * config/mips/mips.c (mips_expand_prologue): Likewise.
+ * config/powerpcspe/powerpcspe.c (rs6000_expand_prologue): Likewise.
+ * config/sparc/sparc.c (sparc_expand_prologue): Likewise.
+ (sparc_flat_expand_prologue): Likewise.
+ * config/spu/spu.c (spu_expand_prologue): Likewise.
+
+ * explow.c: Include "params.h".
+ (anti_adjust_stack_and_probe_stack_clash): New function.
+ (get_stack_check_protect): Likewise.
+ (compute_stack_clash_protection_loop_data): Likewise.
+ (emit_stack_clash_protection_loop_start): Likewise.
+ (emit_stack_clash_protection_loop_end): Likewise.
+ (allocate_dynamic_stack_space): Use get_stack_check_protect.
+ Use anti_adjust_stack_and_probe_stack_clash.
+ * explow.h (compute_stack_clash_protection_loop_data): Prototype.
+ (emit_stack_clash_protection_loop_start): Likewise.
+ (emit_stack_clash_protection_loop_end): Likewise.
+ * rtl.h (get_stack_check_protect): Prototype.
+ * target.def (stack_clash_protection_final_dynamic_probe): New hook.
+ * targhooks.c (default_stack_clash_protection_final_dynamic_probe): New.
+ * targhooks.h (default_stack_clash_protection_final_dynamic_probe):
+ Prototype.
+ * doc/tm.texi.in (TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE):
+ Add @hook.
+ * doc/tm.texi: Rebuilt.
+ * config/aarch64/aarch64.c (aarch64_expand_prologue): Use
+ get_stack_check_protect.
+ * config/alpha/alpha.c (alpha_expand_prologue): Likewise.
+ * config/arm/arm.c (arm_expand_prologue): Likewise.
+ (arm_frame_pointer_required): Likewise.
+ * config/i386/i386.c (ix86_expand_prologue): Likewise.
+ * config/ia64/ia64.c (ia64_expand_prologue): Likewise.
+ * config/mips/mips.c (mips_expand_prologue): Likewise.
+ * config/powerpcspe/powerpcspe.c (rs6000_emit_prologue): Likewise.
+ * config/rs6000/rs6000.c (rs6000_emit_prologue): Likewise.
+ * config/sparc/sparc.c (sparc_expand_prologue): Likewise.
+ (sparc_flat_expand_prologue): Likewise.
+
+ * common.opt (-fstack-clash-protection): New option.
+ * flag-types.h (enum stack_check_type): Note difference between
+ -fstack-check= and -fstack-clash-protection.
+ * params.def (PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE): New PARAM.
+ (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL): Likewise.
+ * toplev.c (process_options): Issue warnings/errors for cases
+ not handled with -fstack-clash-protection.
+ * doc/invoke.texi (-fstack-clash-protection): Document new option.
+ (-fstack-check): Note additional problem with -fstack-check=generic.
+ Note that -fstack-check is primarily for Ada and refer users
+ to -fstack-clash-protection for stack-clash-protection.
+ Document new params for stack clash protection.
2017-09-19 Uros Bizjak <ubizjak@gmail.com>
@@ -188,8 +4457,8 @@
2017-09-17 Daniel Santos <daniel.santos@pobox.com>
- config/i386/i386.c: (xlogue_layout::STUB_NAME_MAX_LEN): Increase to 20
- bytes.
+ * config/i386/i386.c (xlogue_layout::STUB_NAME_MAX_LEN):
+ Increase to 20 bytes.
(xlogue_layout::s_stub_names): Add an additional size-2 diminsion.
(xlogue_layout::get_stub_name): Modify to select the appropairate sse
or avx version of the stub.
diff --git a/gcc/DATESTAMP b/gcc/DATESTAMP
index b46c5f0..39319a6 100644
--- a/gcc/DATESTAMP
+++ b/gcc/DATESTAMP
@@ -1 +1 @@
-20170920
+20171024
diff --git a/gcc/Makefile.in b/gcc/Makefile.in
index 0bde7ac..2809619 100644
--- a/gcc/Makefile.in
+++ b/gcc/Makefile.in
@@ -1568,6 +1568,7 @@ OBJS = \
tree-vrp.o \
tree.o \
typed-splay-tree.o \
+ unique-ptr-tests.o \
valtrack.o \
value-prof.o \
var-tracking.o \
@@ -4135,8 +4136,7 @@ TAGS: lang.tags
../include/*.h ../libiberty/*.c \
../libcpp/*.c ../libcpp/include/*.h \
--language=none --regex="/\(char\|unsigned int\|int\|bool\|void\|HOST_WIDE_INT\|enum [A-Za-z_0-9]+\) [*]?\([A-Za-z_0-9]+\)/\2/" common.opt \
- --language=none --regex="/\(DEF_RTL_EXPR\|DEFTREECODE\|DEFGSCODE\).*(\([A-Za-z_0-9]+\)/\2/" rtl.def tree.def gimple.def \
- --language=none --regex="/DEFTIMEVAR (\([A-Za-z_0-9]+\)/\1/" timevar.def \
+ --language=none --regex="/\(DEF_RTL_EXPR\|DEFTREECODE\|DEFGSCODE\|DEFTIMEVAR\|DEFPARAM\|DEFPARAMENUM5\)[ ]?(\([A-Za-z_0-9]+\)/\2/" rtl.def tree.def gimple.def timevar.def params.def \
; \
etags --include TAGS.sub $$incs)
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index b90a262..9a6147d 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,1438 @@
+2017-10-21 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/Makefile.in: Remove bogus settings for VxWorks.
+
+2017-10-21 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/utils.c (pad_type_hash): Use hashval_t for hash value.
+ (convert): Do not use an unchecked conversion for converting from a
+ type to another type padding it.
+
+2017-10-20 Doug Rupp <rupp@adacore.com>
+
+ * libgnarl/s-osinte__linux.ads (Relative_Timed_Wait): Add variable
+ needed for using monotonic clock.
+ * libgnarl/s-taprop__linux.adb: Revert previous monotonic clock
+ changes.
+ * libgnarl/s-taprop__linux.adb, s-taprop__posix.adb: Unify and factor
+ out monotonic clock related functions body.
+ (Timed_Sleep, Timed_Delay, Montonic_Clock, RT_Resolution,
+ Compute_Deadline): Move to...
+ * libgnarl/s-tpopmo.adb: ... here. New separate package body.
+
+2017-10-20 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_util.adb (Is_Controlling_Limited_Procedure): Handle properly the
+ case where the controlling formal is an anonymous access to interface
+ type.
+ * exp_ch9.adb (Extract_Dispatching_Call): If controlling actual is an
+ access type, handle properly the the constructed dereference that
+ designates the object used in the rewritten synchronized call.
+ (Parameter_Block_Pack): If the type of the actual is by-copy, its
+ generated declaration in the parameter block does not need an
+ initialization even if the type is a null-excluding access type,
+ because it will be initialized with the value of the actual later on.
+ (Parameter_Block_Pack): Do not add controlling actual to parameter
+ block when its type is by-copy.
+
+2017-10-20 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch8.adb (Update_Use_Clause_Chain): Add sanity check to verify
+ scope stack traversal into the context clause.
+
+2017-10-20 Bob Duff <duff@adacore.com>
+
+ * sinfo.ads: Fix a comment typo.
+
+2017-10-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * doc/gnat_ugn/building_executable_programs_with_gnat.rst (-flto): Add
+ warning against usage in conjunction with -gnatn.
+ (-fdump-xref): Delete entry.
+ * doc/gnat_ugn/gnat_utility_programs.rst (--ext): Remove mention of
+ -fdump-xref switch.
+ * gnat_ugn.texi: Regenerate.
+
+2017-10-20 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_type.adb, exp_util.adb, sem_util.adb, sem_dim.adb, sem_elab.adb:
+ Minor reformatting.
+
+2017-10-20 Yannick Moy <moy@adacore.com>
+
+ * sem_dim.adb (Analyze_Dimension_Binary_Op): Accept with a warning to
+ compare a dimensioned expression with a literal.
+ (Dim_Warning_For_Numeric_Literal): Do not issue a warning for the
+ special value zero.
+ * doc/gnat_ugn/gnat_and_program_execution.rst: Update description of
+ dimensionality system in GNAT.
+ * gnat_ugn.texi: Regenerate.
+
+2017-10-20 Yannick Moy <moy@adacore.com>
+
+ * sem_ch6.adb (Analyze_Expression_Function.Freeze_Expr_Types): Remove
+ inadequate silencing of errors.
+ * sem_util.adb (Check_Part_Of_Reference): Do not issue an error when
+ checking the subprogram body generated from an expression function,
+ when this is done as part of the preanalysis done on expression
+ functions, as the subprogram body may not yet be attached in the AST.
+ The error if any will be issued later during the analysis of the body.
+ (Is_Aliased_View): Trivial rewrite with Is_Formal_Object.
+
+2017-10-20 Arnaud Charlet <charlet@adacore.com>
+
+ * sem_ch8.adb (Update_Chain_In_Scope): Add missing [-gnatwu] marker for
+ warning on ineffective use clause.
+
+2017-10-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * exp_ch11.ads (Warn_If_No_Local_Raise): Declare.
+ * exp_ch11.adb (Expand_Exception_Handlers): Use Warn_If_No_Local_Raise
+ to issue the warning on the absence of local raise.
+ (Possible_Local_Raise): Do not issue the warning for Call_Markers.
+ (Warn_If_No_Local_Raise): New procedure to issue the warning on the
+ absence of local raise.
+ * sem_elab.adb: Add with and use clauses for Exp_Ch11.
+ (Record_Elaboration_Scenario): Call Possible_Local_Raise in the cases
+ where a scenario could give rise to raising Program_Error.
+ * sem_elab.adb: Typo fixes.
+ * fe.h (Warn_If_No_Local_Raise): Declare.
+ * gcc-interface/gigi.h (get_exception_label): Change return type.
+ * gcc-interface/trans.c (gnu_constraint_error_label_stack): Change to
+ simple vector of Entity_Id.
+ (gnu_storage_error_label_stack): Likewise.
+ (gnu_program_error_label_stack): Likewise.
+ (gigi): Adjust to above changes.
+ (Raise_Error_to_gnu): Likewise.
+ (gnat_to_gnu) <N_Goto_Statement>: Set TREE_USED on the label.
+ (N_Push_Constraint_Error_Label): Push the label onto the stack.
+ (N_Push_Storage_Error_Label): Likewise.
+ (N_Push_Program_Error_Label): Likewise.
+ (N_Pop_Constraint_Error_Label): Pop the label from the stack and issue
+ a warning on the absence of local raise.
+ (N_Pop_Storage_Error_Label): Likewise.
+ (N_Pop_Program_Error_Label): Likewise.
+ (push_exception_label_stack): Delete.
+ (get_exception_label): Change return type to Entity_Id and adjust.
+ * gcc-interface/utils2.c (build_goto_raise): Change type of first
+ parameter to Entity_Id and adjust. Set TREE_USED on the label.
+ (build_call_raise): Adjust calls to get_exception_label and also
+ build_goto_raise.
+ (build_call_raise_column): Likewise.
+ (build_call_raise_range): Likewise.
+ * doc/gnat_ugn/building_executable_programs_with_gnat.rst (-gnatw.x):
+ Document actual default behavior.
+
+2017-10-20 Piotr Trojanek <trojanek@adacore.com>
+
+ * einfo.ads: Minor consistent punctuation in comment. All numbered
+ items in the comment of Is_Internal are now terminated with a period.
+
+2017-10-20 Piotr Trojanek <trojanek@adacore.com>
+
+ * exp_util.adb (Build_Temporary): Mark created temporary entity as
+ internal.
+
+2017-10-20 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_type.adb (In_Generic_Actual): Simplified.
+
+2017-10-20 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch12.adb (Check_Formal_Package_Instance): Add sanity check to
+ verify a renaming exists for a generic formal before comparing it to
+ the actual as defaulted formals will not have a renamed_object.
+
+2017-10-20 Javier Miranda <miranda@adacore.com>
+
+ * exp_ch6.adb (Replace_Returns): Fix wrong management of
+ N_Block_Statement nodes.
+
+2017-10-20 Bob Duff <duff@adacore.com>
+
+ * exp_aggr.adb (Initialize_Array_Component): Avoid adjusting a
+ component of an array aggregate if it is initialized by a
+ build-in-place function call.
+ * exp_ch6.adb (Is_Build_In_Place_Result_Type): Use -gnatd.9 to disable
+ bip for nonlimited types.
+ * debug.adb: Document -gnatd.9.
+
+2017-10-20 Bob Duff <duff@adacore.com>
+
+ * sem_ch12.adb: Remove redundant setting of Parent.
+
+2017-10-20 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sem_ch4.adb (Find_Concatenation_Types): Filter out operators if one
+ of the operands is a string literal.
+
+2017-10-20 Bob Duff <duff@adacore.com>
+
+ * einfo.ads: Comment fix.
+
+2017-10-20 Clement Fumex <fumex@adacore.com>
+
+ * switch-c.adb: Remove -gnatwm from the switches triggered by -gnateC.
+
+2017-10-20 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_dim.adb (Extract_Power): Accept dimension values that are not
+ non-negative integers when the dimensioned base type is an Integer
+ type.
+
+2017-10-20 Bob Duff <duff@adacore.com>
+
+ * sinfo.ads, sinfo.adb (Alloc_For_BIP_Return): New flag to indicate
+ that an allocator came from a b-i-p return statement.
+ * exp_ch4.adb (Expand_Allocator_Expression): Avoid adjusting the return
+ object of a nonlimited build-in-place function call.
+ * exp_ch6.adb (Expand_N_Extended_Return_Statement): Set the
+ Alloc_For_BIP_Return flag on generated allocators.
+ * sem_ch5.adb (Analyze_Assignment): Move Assert to where it can't fail.
+ If the N_Assignment_Statement has been transformed into something else,
+ then Should_Transform_BIP_Assignment won't work.
+ * exp_ch3.adb (Expand_N_Object_Declaration): A previous revision said,
+ "Remove Adjust if we're building the return object of an extended
+ return statement in place." Back out that part of the change, because
+ the Alloc_For_BIP_Return flag is now used for that.
+
+2017-10-19 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb (Is_Build_In_Place_Result_Type): Fix silly bug -- "Typ"
+ should be "T". Handle case of a subtype of a class-wide type.
+
+2017-10-19 Bob Duff <duff@adacore.com>
+
+ * exp_util.adb: (Process_Statements_For_Controlled_Objects): Clarify
+ which node kinds can legitimately be ignored, and raise Program_Error
+ for others.
+
+2017-10-19 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_elab.adb (Compilation_Unit): Handle the case of a subprogram
+ instantiation that acts as a compilation unit.
+ (Find_Code_Unit): Reimplemented.
+ (Find_Top_Unit): Reimplemented.
+ (Find_Unit_Entity): New routine.
+ (Process_Instantiation_SPARK): Correct the elaboration requirement a
+ package instantiation imposes on a unit.
+
+2017-10-19 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb (Is_Build_In_Place_Result_Type): Enable build-in-place
+ for a narrow set of controlled types.
+
+2017-10-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * sinput.ads (Line_Start): Add pragma Inline.
+ * widechar.ads (Is_Start_Of_Wide_Char): Likewise.
+
+2017-10-19 Bob Duff <duff@adacore.com>
+
+ * exp_attr.adb (Expand_N_Attribute_Reference): Disable
+ Make_Build_In_Place_Call_... for F(...)'Old, where F(...) is a
+ build-in-place function call so that the temp is declared in the right
+ place.
+
+2017-10-18 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc-interface/misc.c (gnat_tree_size): Move around.
+
+ * gcc-interface/utils.c (max_size): Deal with SSA names.
+
+2017-10-17 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc-interface/misc.c (gnat_tree_size): New function.
+ (LANG_HOOKS_TREE_SIZE): Redefine.
+
+2017-10-14 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_elab.adb (In_Preelaborated_Context): A generic package subject to
+ Remote_Call_Interface is not a suitable preelaboratd context when the
+ call appears in the package body.
+
+2017-10-14 Eric Botcazou <ebotcazou@adacore.com>
+
+ * layout.ads (Set_Elem_Alignment): Add Align parameter defaulted to 0.
+ * layout.adb (Set_Elem_Alignment): Likewise. Use M name as maximum
+ alignment for consistency. If Align is non-zero, use the minimum of
+ Align and M for the alignment.
+ * cstand.adb (Build_Float_Type): Use Set_Elem_Alignment instead of
+ setting the alignment directly.
+
+2017-10-14 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_prag.adb (Analyze_Pragma, case Check): Defer evaluation of the
+ optional string in an Assert pragma until the expansion of the pragma
+ has rewritten it as a conditional statement, so that the string
+ argument is only evaluaed if the assertion fails. This is mandated by
+ RM 11.4.2.
+
+2017-10-14 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * debug.adb: Switch -gnatd.v and associated flag are now used to
+ enforce the SPARK rules for elaboration in SPARK code.
+ * sem_elab.adb: Describe switch -gnatd.v.
+ (Process_Call): Verify the SPARK rules only when -gnatd.v is in effect.
+ (Process_Instantiation): Verify the SPARK rules only when -gnatd.v is
+ in effect.
+ (Process_Variable_Assignment): Clarify why variable assignments are
+ processed reglardless of whether -gnatd.v is in effect.
+ * doc/gnat_ugn/elaboration_order_handling_in_gnat.rst: Update the
+ sections on elaboration code and compilation switches.
+ * gnat_ugn.texi: Regenerate.
+
+2017-10-14 Gary Dismukes <dismukes@adacore.com>
+
+ * exp_util.adb, freeze.adb, sem_aggr.adb, sem_util.ads, sem_util.adb,
+ sem_warn.adb: Minor reformattings.
+
+2017-10-14 Ed Schonberg <schonberg@adacore.com>
+
+ * doc/gnat_rm/implementation_defined_aspects.rst: Add documentation
+ for reverse iteration over formal containers.
+ * gnat_rm.texi: Regenerate.
+
+2017-10-14 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_elab.adb (Ensure_Dynamic_Prior_Elaboration): Renamed to
+ Ensure_Prior_Elaboration_Dynamic for consistency reasons.
+ (Ensure_Static_Prior_Elaboration): Renamed to
+ Ensure_Prior_Elaboration_Static for consistency reasons.
+ (Info_Variable_Reference): Renamed to Info_Variable_Read in order to
+ reflect its new purpose.
+ (Is_Initialized): New routine.
+ (Is_Suitable_Variable_Reference): Renamed to Is_Suitable_Variable_Read
+ in order to reflect its new purpose.
+ (Is_Variable_Read): New routine.
+ (Output_Variable_Reference): Renamed to Output_Variable_Read in order
+ to reflect its new purpose.
+ (Process_Variable_Assignment): This routine now acts as a top level
+ dispatcher for variable assignments.
+ (Process_Variable_Assignment_Ada): New routine.
+ (Process_Variable_Assignment_SPARK): New routine.
+ (Process_Variable_Reference): Renamed to Process_Variable_Read in order
+ to reflects its new purpose. A reference to a variable is now suitable
+ for ABE processing only when it is a read. The logic in the routine now
+ reflects the latest SPARK elaboration rules.
+
+2017-10-14 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch8.adb (Analyze_Subprogram_Renaming): Modify condition that
+ triggers marking on formal subprograms.
+
+2017-10-14 Javier Miranda <miranda@adacore.com>
+
+ * checks.adb (Ensure_Valid): Do not skip adding the validity check on
+ renamings of objects that come from the sources.
+
+2017-10-14 Eric Botcazou <ebotcazou@adacore.com>
+
+ * cstand.adb (Build_Float_Type): Move down Siz parameter, add Align
+ parameter and set the alignment of the type to Align.
+ (Copy_Float_Type): Adjust call to Build_Float_Type.
+ (Register_Float_Type): Add pragma Unreferenced for Precision. Adjust
+ call to Build_Float_Type and do not set RM_Size and Alignment.
+
+2017-10-14 Patrick Bernardi <bernardi@adacore.com>
+
+ * Makefile.rtl (GNATRTL_NONTASKING_OBJ): Add s-soliin to
+ GNATRTL_NONTASKING_OBJ.
+
+2017-10-14 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb (Is_Build_In_Place_Result_Type): Include code for
+ enabling b-i-p for nonlimited controlled types (but disabled).
+
+2017-10-14 Justin Squirek <squirek@adacore.com>
+
+ * sem_elab.adb (Is_Suitable_Variable_Assignment): Replace call to
+ Has_Warnings_Off with Warnings_Off.
+
+2017-10-14 Piotr Trojanek <trojanek@adacore.com>
+
+ * sinfo.ads (Generic_Parent): Remove wrong (possibly obsolete) comment.
+
+2017-10-14 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_ch3.adb (Analyze_Declarations): Analyze the contract of an
+ enclosing package at the end of the visible declarations.
+ * sem_prag.adb (Analyze_Initialization_Item): Suppress the analysis of
+ an initialization item which is undefined due to some illegality.
+
+2017-10-14 Patrick Bernardi <bernardi@adacore.com>
+
+ * ali.adb: Add new ALI line 'T' to read the number of tasks contain
+ within each unit that require a default-sized primary and secondary
+ stack to be generated by the binder.
+ (Scan_ALI): Scan new 'T' lines.
+ * ali.ads: Add Primary_Stack_Count and Sec_Stack_Count to Unit_Record.
+ * bindgen.adb (Gen_Output_File): Count the number of default-sized
+ stacks within the closure that are to be created by the binder.
+ (Gen_Adainit, Gen_Output_File_Ada): Generate default-sized secondary
+ stacks and record these in System.Secodnary_Stack.
+ (Resolve_Binder_Options): Check if System.Secondary_Stack is in the
+ closure of the program being bound.
+ * bindusg.adb (Display): Add "-Q" switch. Remove rouge "--RTS" comment.
+ * exp_ch3.adb (Count_Default_Sized_Task_Stacks): New routine.
+ (Expand_N_Object_Declaration): Count the number of default-sized stacks
+ used by task objects contained within the object whose declaration is
+ being expanded. Only performed when either the restrictions
+ No_Implicit_Heap_Allocations or No_Implicit_Task_Allocations are in
+ effect.
+ * exp_ch9.adb (Create_Secondary_Stack_For_Task): New routine.
+ (Expand_N_Task_Type_Declaration): Create a secondary stack as part of
+ the expansion of a task type if the size of the stack is known at
+ run-time and the restrictions No_Implicit_Heap_Allocations or
+ No_Implicit_Task_Allocations are in effect.
+ (Make_Task_Create_Call): If using a restricted profile provide
+ secondary stack parameter: either the statically created stack or null.
+ * lib-load.adb (Create_Dummy_Package_Unit, Load_Unit,
+ Load_Main_Source): Include Primary_Stack_Count and Sec_Stack_Count in
+ Unit_Record initialization expressions.
+ * lib-writ.adb (Add_Preprocessing_Dependency,
+ Ensure_System_Dependency): Include Primary_Stack_Count and
+ Sec_Stack_Count in Unit_Record initialization expression.
+ (Write_ALI): Write T lines.
+ (Write_Unit_Information): Do not output 'T' lines if there are no
+ stacks for the binder to generate.
+ * lib-writ.ads: Updated library information documentation to include
+ new T line entry.
+ * lib.adb (Increment_Primary_Stack_Count): New routine.
+ (Increment_Sec_Stack_Count): New routine.
+ (Primary_Stack_Count): New routine.
+ (Sec_Stack_Count): New routine.
+ * lib.ads: Add Primary_Stack_Count and Sec_Stack_Count components to
+ Unit_Record and updated documentation.
+ (Increment_Primary_Stack_Count): New routine along with pragma Inline.
+ (Increment_Sec_Stack_Count): New routine along with pragma Inline.
+ (Primary_Stack_Count): New routine along with pragma Inline.
+ (Sec_Stack_Count): New routine along with pragma Inline.
+ * opt.ads: New constant No_Stack_Size. Flag Default_Stack_Size
+ redefined. New flag Default_Sec_Stack_Size and
+ Quantity_Of_Default_Size_Sec_Stacks.
+ * rtfinal.c Fixed erroneous comment.
+ * rtsfind.ads: Moved RE_Default_Secondary_Stack_Size from
+ System.Secondary_Stack to System.Parameters. Add RE_SS_Stack.
+ * sem_util.adb (Number_Of_Elements_In_Array): New routine.
+ * sem_util.ads (Number_Of_Elements_In_Array): New routine.
+ * switch-b.adb (Scan_Binder_Switches): Scan "-Q" switch.
+ * libgnarl/s-solita.adb (Get_Sec_Stack_Addr): Removed routine.
+ (Set_Sec_Stack_Addr): Removed routine.
+ (Get_Sec_Stack): New routine.
+ (Set_Sec_Stack): New routine.
+ (Init_Tasking_Soft_Links): Update System.Soft_Links reference to
+ reflect new procedure and global names.
+ * libgnarl/s-taprop__linux.adb, libgnarl/s-taprop__mingw.adb,
+ libgnarl/s-taprop__posix.adb, libgnarl/s-taprop__solaris.adb,
+ libgnarl/s-taprop__vxworks.adb (Register_Foreign_Thread): Update
+ parameter profile to allow the secondary stack size to be specified.
+ * libgnarl/s-tarest.adb (Create_Restricted_Task): Update the parameter
+ profile to include Sec_Stack_Address. Update Tasking.Initialize_ATCB
+ call to remove Secondary_Stack_Size reference. Add secondary stack
+ address and size to SSL.Create_TSD call.
+ (Task_Wrapper): Remove secondary stack creation.
+ * libgnarl/s-tarest.ads (Create_Restricted_Task,
+ Create_Restricted_Task_Sequential): Update parameter profile to include
+ Sec_Stack_Address and clarify the Size parameter.
+ * libgnarl/s-taskin.adb (Initialize_ATCB): Remove Secondary_Stack_Size
+ from profile and body.
+ (Initialize): Remove Secondary_Stack_Size from Initialize_ATCB call.
+ * libgnarl/s-taskin.ads: Removed component Secondary_Stack_Size from
+ Common_ATCB.
+ (Initialize_ATCB): Update the parameter profile to remove
+ Secondary_Stack_Size.
+ * libgnarl/s-tassta.adb (Create_Task): Updated parameter profile and
+ call to Initialize_ATCB. Add secondary stack address and size to
+ SSL.Create_TSD call, and catch any storage exception from the call.
+ (Finalize_Global_Tasks): Update System.Soft_Links references to reflect
+ new subprogram and component names.
+ (Task_Wrapper): Remove secondary stack creation.
+ (Vulnerable_Complete_Master): Update to reflect TSD changes.
+ * libgnarl/s-tassta.ads: Reformat comments.
+ (Create_Task): Update parameter profile.
+ * libgnarl/s-tporft.adb (Register_Foreign_Thread): Update parameter
+ profile to include secondary stack size. Remove secondary size
+ parameter from Initialize_ATCB call and add it to Create_TSD call.
+ * libgnat/s-parame.adb, libgnat/s-parame__rtems.adb,
+ libgnat/s-parame__vxworks.adb (Default_Sec_Stack_Size): New routine.
+ * libgnat/s-parame.ads, libgnat/s-parame__ae653.ads,
+ libgnat/s-parame__hpux.ads, libgnat/s-parame__vxworks.ads: Remove type
+ Percentage. Remove constants Dynamic, Sec_Stack_Percentage and
+ Sec_Stack_Dynamic. Add constant Runtime_Default_Sec_Stack_Size and
+ Sec_Stack_Dynamic.
+ (Default_Sec_Stack_Size): New routine.
+ * libgnat/s-secsta.adb, libgnat/s-secsta.ads: New implementation. Is
+ now Preelaborate.
+ * libgnat/s-soflin.adb: Removed unused with-clauses. With
+ System.Soft_Links.Initialize to initialize non-tasking TSD.
+ (Create_TSD): Update parameter profile. Initialize the TSD and
+ unconditionally call SS_Init.
+ (Destroy_TSD): Update SST.SS_Free call.
+ (Get_Sec_Stack_Addr_NT, Get_Sec_Stack_Addr_Soft, Set_Sec_Stack_Addr_NT,
+ Set_Sec_Stack_Addr_Soft): Remove routines.
+ (Get_Sec_Stack_NT, Get_Sec_Stack_Soft, Set_Sec_Stack_NT,
+ Set_Sec_Stack_Soft): Add routines.
+ (NT_TSD): Move to private part of package specification.
+ * libgnat/s-soflin.ads: New types Get_Stack_Call and Set_Stack_Call
+ with suppressed access checks. Renamed *_Sec_Stack_Addr_* routines and
+ objects to *_Sec_Stack_*. TSD: removed warning suppression and
+ component intialization. Changed Sec_Stack_Addr to Sec_Stack_Ptr.
+ (Create_TSD): Update parameter profile.
+ (NT_TSD): Move to private section from body.
+ * libgnat/s-soliin.adb, libgnat/s-soliin.ads: New files.
+ * libgnat/s-thread.ads (Thread_Body_Enter): Update parameter profile.
+ * libgnat/s-thread__ae653.adb (Get_Sec_Stack_Addr, Set_Sec_Stack_Addr):
+ Remove routine.
+ (Get_Sec_Stack, Set_Sec_Stack): Add routine.
+ (Thread_Body_Enter): Update parameter profile and body to adapt to new
+ System.Secondary_Stack.
+ (Init_RTS): Update body for new System.Soft_Links names.
+ * gcc-interface/Make-lang.in (GNAT_ADA_OBJS, GNATBIND_OBJS): Add
+ s-soliin.o.
+
+2017-10-10 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * gcc-interface/decl.c (annotate_value): Use wi::to_wide when
+ operating on trees as wide_ints.
+
+2017-10-09 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_unit.adb (Find_Enclosing_Scope): Do not treat a block statement
+ as a scoping construct when it is byproduct of exception handling.
+
+2017-10-09 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sinfo.ads: Update table Is_Syntactic_Field to reflect the nature of
+ semantic field Target of node N_Call_Marker.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_res.adb (Resolve_Allocator): Reject properly an allocator that
+ attempts to copy a limited value, when the allocator is the expression
+ in an expression function.
+
+2017-10-09 Joel Brobecker <brobecker@adacore.com>
+
+ * doc/share/conf.py: Tell the style checker that this is a Python
+ fragment, and therefore that pyflakes should not be run to validate
+ this file.
+
+2017-10-09 Eric Botcazou <ebotcazou@adacore.com>
+
+ * einfo.ads (Is_Boolean_Type): Add pragma Inline.
+ (Is_Entity_Name): Likewise.
+ (Is_String_Type): Likewise.
+ * sem_type.adb (Full_View_Covers): Do not test Is_Private_Type here
+ and remove useless comparisons on the base types.
+ (Covers): Use simple tests for Standard_Void_Type. Move up cheap tests
+ on T2. Always test Is_Private_Type before Full_View_Covers.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * exp_ch4.adb: Minor refactoring.
+
+2017-10-09 Javier Miranda <miranda@adacore.com>
+
+ * sem_ch3.adb (Replace_Components): Browse the list of discriminants,
+ not components.
+
+2017-10-09 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_elab.adb (Static_Elaboration_Checks): Elaboration requirements
+ are verified only in the static model.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch5.adb (Analyze_Iterator_Specification,
+ Check_Reverse_Iteration): Check that the domain of iteration supports
+ reverse iteration when it is a formal container. This requires the
+ presence of a Previous primitive in the Iterable aspect.
+ * sem_ch13.adb (Resolve_Iterable_Operation): Verify legality of
+ primitives Last and Previous to support reverse iteration over formal
+ containers.
+ (Validate_Iterable_Aspect): Add check for reverse iteration operations.
+ * exp_ch5.adb (Build_Formal_Container_Iteration): Add proper expansion
+ for reverse iteration using primitives Last and Previous in generated
+ loop.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_util.adb (Subprogram_Name): If this is a child unit, use the name
+ of the Defining_Program_Unit_Name, which is an identifier, in order to
+ construct the string for the fully qualified name.
+
+2017-10-09 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch3.adb: Rename Uses_Unseen_Priv into
+ Contains_Lib_Incomplete_Type.
+
+2017-10-09 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_aggr.adb, sem_spark.adb, adabkend.adb, exp_ch5.adb, frontend.adb,
+ sem_ch12.adb, fmap.adb, exp_ch6.adb, exp_spark.adb, lib-load.adb,
+ exp_ch9.adb, osint.adb, exp_disp.adb, sem_ch8.adb, sem_ch8.ads,
+ prepcomp.adb, gnat1drv.adb, atree.adb, sinput-l.adb, targparm.adb,
+ sem_ch10.adb, par-ch8.adb: Minor reformatting.
+
+2017-10-09 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_elab.adb (Is_Suitable_Access): This scenario is now only relevant
+ in the static model.
+ (Is_Suitable_Variable_Assignment): This scenario is now only relevant
+ in the static model.
+ (Is_Suitable_Variable_Reference): This scenario is now only relevant in
+ the static model.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch3.adb (Analyze_Declarations): In ASIS mode, resolve aspect
+ expressions when the enclosing scope is a subprogram body and the next
+ declaration is a body that freezes entities previously declared in the
+ scope.
+
+2017-10-09 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch8.adb (Analyze_Use_Package): Remove checking of mixture between
+ ghost packages and living packages in use clauses.
+ (Use_One_Type, Note_Redundant_Use): Correct warning messages
+
+2017-10-09 Justin Squirek <squirek@adacore.com>
+
+ * osint.ads: Document new parameter FD for Read_Source_File.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * exp_util.adb (Make_Predicate_Call): If the type of the expression to
+ which the predicate check applies is tagged, convert the expression to
+ that type. This is in most cases a no-op, but is relevant if the
+ expression is clas-swide, because the predicate function being invoked
+ is not a primitive of the type and cannot take a class-wide actual.
+
+2017-10-09 Gary Dismukes <dismukes@adacore.com>
+
+ * exp_disp.adb: Minor reformatting.
+
+2017-10-09 Arnaud Charlet <charlet@adacore.com>
+
+ * sem_warn.adb (Warn_On_Unreferenced_Entity): Fix typo.
+
+2017-10-09 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_elab.adb (Install_ABE_Check): Do not generate an ABE check for
+ GNATprove.
+ (Install_ABE_Failure): Do not generate an ABE failure for GNATprove.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb: (Make_Build_In_Place_Call_In_Object_Declaration): Return
+ immediately if the call has already been processed (by a previous call
+ to Make_Build_In_Place_Call_In_Anonymous_Context).
+ * sem_elab.adb: Minor typo fixes.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch13.adb (Replace_Type_Ref): In the expression for a dynamic
+ predicate, do not replace an identifier that matches the type if the
+ identifier is a selector in a selected component, because this
+ indicates a reference to some homograph of the type itself, and not to
+ the current occurence in the predicate.
+
+2017-10-09 Eric Botcazou <ebotcazou@adacore.com>
+
+ * repinfo.adb (List_Record_Layout): Tweak formatting.
+ (Write_Val): Remove superfluous spaces in back-end layout mode.
+
+2017-10-09 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_res.adb (Property_Error): Remove.
+ (Resolve_Actuals): check for SPARK RM 7.1.3(10) rewritten to match the
+ current wording of the rule.
+
+2017-10-09 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch3.adb (Analyze_Declarations): Add check for ghost packages
+ before analyzing a given scope due to an expression function.
+ (Uses_Unseen_Lib_Unit_Priv): Rename to Uses_Unseen_Priv.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb (Make_Build_In_Place_Call_In_Object_Declaration): Use
+ Defining_Identifier (Obj_Decl) in two places, because it might have
+ changed.
+ * exp_ch6.adb (Make_Build_In_Place_Call_In_Allocator): Deal with cases
+ involving 'Input on (not visibly) derived types.
+
+2017-10-09 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * atree.adb: Add new soft link Rewriting_Proc.
+ (Rewrite): Invoke the subprogram attached to the rewriting soft link.
+ (Set_Rewriting_Proc): New routine.
+ * attree.ads: Add new access-to-subprogram type Rewrite_Proc.
+ (Set_Rewriting_Proc): New routine.
+ * checks.adb (Install_Primitive_Elaboration_Check): Use 'E' character
+ for *E*laboration flag to maintain consistency with other elaboration
+ flag generating subprograms.
+ * debug.adb: Document the new usage of flag -gnatdL.
+ * einfo.adb: Node19 is now used as Receiving_Entry. Node39 is now used
+ as Protected_Subprogram. Flag148 is now used as
+ Is_Elaboration_Checks_OK_Id. Flag302 is now used as
+ Is_Initial_Condition_Procedure.
+ (Is_Elaboration_Checks_OK_Id): New routine.
+ (Is_Initial_Condition_Procedure): New routine.
+ (Protected_Subprogram): New routine.
+ (Receiving_Entry): New routine.
+ (SPARK_Pragma): Update assertion.
+ (SPARK_Pragma_Inherited): Update assertion.
+ (Suppress_Elaboration_Warnings): Removed.
+ (Set_Is_Elaboration_Checks_OK_Id): New routine.
+ (Set_Is_Initial_Condition_Procedure): New routine.
+ (Set_Protected_Subprogram): New routine.
+ (Set_Receiving_Entry): New routine.
+ (Set_SPARK_Pragma): Update assertion.
+ (Set_SPARK_Pragma_Inherited): Update assertion.
+ (Write_Entity_Flags): Update the output for Flag148 and Flag302.
+ (Write_Field19_Name): Add output for Receiving_Entry.
+ (Write_Field39_Name): Add output for Protected_Subprogram.
+ (Write_Field40_Name): Update the output for SPARK_Pragma.
+ * einfo.ads: New attributes Is_Elaboration_Checks_OK_Id,
+ Is_Initial_Condition_Procedure, Protected_Subprogram, Receiving_Entry.
+ Remove attribute Suppress_Elaboration_Warnings. Update the stricture
+ of various entities.
+ (Is_Elaboration_Checks_OK_Id): New routine along with pragma Inline.
+ (Is_Initial_Condition_Procedure): New routine along with pragma Inline.
+ (Protected_Subprogram): New routine along with pragma Inline.
+ (Receiving_Entry): New routine along with pragma Inline.
+ (Suppress_Elaboration_Warnings): Removed.
+ (Set_Is_Elaboration_Checks_OK_Id): New routine along with pragma
+ Inline.
+ (Set_Is_Initial_Condition_Procedure): New routine along with pragma
+ Inline.
+ (Set_Protected_Subprogram): New routine along with pragma Inline.
+ (Set_Receiving_Entry): New routine along with pragma Inline.
+ (Set_Suppress_Elaboration_Warnings): Removed.
+ * exp_ch3.adb (Build_Init_Procedure): Use name _Finalizer to maintain
+ consistency with other finalizer generating subprograms.
+ (Default_Initialize_Object): Mark the block which wraps the call to
+ finalize as being part of initialization.
+ * exp_ch7.adb (Expand_N_Package_Declaration): Directly expand pragma
+ Initial_Condition.
+ (Expand_N_Package_Body): Directly expand pragma Initial_Condition.
+ (Next_Suitable_Statement): Update the comment on usage. Skip over call
+ markers generated by the ABE mechanism.
+ * exp_ch9.adb (Activation_Call_Loc): New routine.
+ (Add_Accept): Link the accept procedure to the original entry.
+ (Build_Protected_Sub_Specification): Link the protected or unprotected
+ version to the original subprogram.
+ (Build_Task_Activation_Call): Code cleanup. Use a source location which
+ is very close to the "begin" or "end" keywords when generating the
+ activation call.
+ * exp_prag.adb (Expand_Pragma_Initial_Condition): Reimplemented.
+ * exp_spark.adb (Expand_SPARK): Use Expand_SPARK_N_Loop_Statement to
+ process loops.
+ (Expand_SPARK_N_Loop_Statement): New routine.
+ (Expand_SPARK_N_Object_Declaration): Code cleanup. Partially insert the
+ call to the Default_Initial_Condition procedure.
+ (Expand_SPARK_Op_Ne): Renamed to Expand_SPARK_N_Op_Ne.
+ * exp_util.adb (Build_DIC_Procedure_Body): Capture the SPARK_Mode in
+ effect.
+ (Build_DIC_Procedure_Declaration): Capture the SPARK_Mode in effect.
+ (Insert_Actions): Add processing for N_Call_Marker.
+ (Kill_Dead_Code): Explicitly kill an elaboration scenario.
+ * exp_util.ads (Make_Invariant_Call): Update the comment on usage.
+ * frontend.adb: Initialize Sem_Elab. Process all saved top level
+ elaboration scenarios for ABE issues.
+ * gcc-interface/trans.c (gnat_to_gnu): Add processing for N_Call_Marker
+ nodes.
+ * lib.adb (Earlier_In_Extended_Unit): New variant.
+ * sem.adb (Analyze): Ignore N_Call_Marker nodes.
+ (Preanalysis_Active): New routine.
+ * sem.ads (Preanalysis_Active): New routine.
+ * sem_attr.adb (Analyze_Access_Attribute): Save certain
+ elaboration-related attributes. Save the scenario for ABE processing.
+ * sem_ch3.adb (Analyze_Object_Declaration): Save the SPARK mode in
+ effect. Save certain elaboration-related attributes.
+ * sem_ch5.adb (Analyze_Assignment): Save certain elaboration-related
+ attributes. Save the scenario for ABE processing.
+ * sem_ch6.adb (Analyze_Abstract_Subprogram_Declaration): Save the SPARK
+ mode in effect. Save certain elaboration-related attributes.
+ (Analyze_Subprogram_Body_Helper): Skip N_Call_Marker nodes when
+ locating the first real statement.
+ (Analyze_Subprogram_Declaration): Save the SPARK mode in effect. Save
+ certain elaboration-related attributes.
+ * sem_ch7.adb (Analyze_Package_Declaration): Do not suppress
+ elaboration warnings.
+ * sem_ch8.adb (Attribute_Renaming): Mark a subprogram body which was
+ generated for purposes of wrapping an attribute used as a generic
+ actual.
+ (Find_Direct_Name): Save certain elaboration-related attributes. Save
+ the scenario for ABE processing.
+ (Find_Expanded_Name): Save certain elaboration-related attributes. Save
+ the scenario for ABE processing.
+ * sem_ch9.adb (Analyze_Entry_Declaration): Save certain
+ elaboration-related attributes.
+ (Analyze_Requeue): Save certain elaboration-related attributes. Save
+ the scenario for ABE processing.
+ (Analyze_Single_Task_Declaration): Save certain elaboration-related
+ attributes.
+ (Analyze_Task_Type_Declaration): Save certain elaboration-related
+ attributes.
+ * sem_ch12.adb (Analyze_Generic_Package_Declaration): Save certain
+ elaboration-related attributes.
+ (Analyze_Generic_Subprogram_Declaration): Save the SPARK mode in
+ effect. Save certain elaboration-related attributes.
+ (Analyze_Package_Instantiation): Save certain elaboration-related
+ attributes. Save the scenario for ABE processing. Create completing
+ bodies in case the instantiation results in a guaranteed ABE.
+ (Analyze_Subprogram_Instantiation): Save certain elaboration-related
+ attributes Save the scenario for ABE processing. Create a completing
+ body in case the instantiation results in a guaranteed ABE.
+ (Provide_Completing_Bodies): New routine.
+ * sem_elab.ads: Brand new implementation.
+ * sem_prag.adb (Analyze_Pragma, cases Elaborate, Elaborate_All,
+ Elaborate_Body): Do not suppress elaboration warnings.
+ * sem_res.adb (Make_Call_Into_Operator): Set the parent field of the
+ operator.
+ (Resolve_Call): Save certain elaboration-related attributes. Save the
+ scenario for ABE processing.
+ (Resolve_Entity_Name): Do not perform any ABE processing here.
+ (Resolve_Entry_Call): Inherit certain attributes from the original call.
+ * sem_util.adb (Begin_Keyword_Location): New routine.
+ (Defining_Entity): Update the parameter profile. Add processing for
+ concurrent subunits that are rewritten as null statements.
+ (End_Keyword_Location): New routine.
+ (Find_Enclosing_Scope): New routine.
+ (In_Instance_Visible_Part): Code cleanup.
+ (In_Subtree): Update the parameter profile. Add new version.
+ (Is_Preelaborable_Aggregate): New routine.
+ (Is_Preelaborable_Construct): New routine.
+ (Mark_Elaboration_Attributes): New routine.
+ (Scope_Within): Update the parameter profile.
+ (Scope_Within_Or_Same): Update the parameter profile.
+ * sem_util.ads (Begin_Keyword_Location): New routine.
+ (Defining_Entity): Update the parameter profile and the comment on
+ usage.
+ (End_Keyword_Location): New routine.
+ (Find_Enclosing_Scope): New routine.
+ (In_Instance_Visible_Part): Update the parameter profile.
+ (In_Subtree): Update the parameter profile. Add new version.
+ (Is_Preelaborable_Aggregate): New routine.
+ (Is_Preelaborable_Construct): New routine.
+ (Mark_Elaboration_Attributes): New routine.
+ (Scope_Within): Update the parameter profile and the comment on usage.
+ (Scope_Within_Or_Same): Update the parameter profile and the comment on
+ usage.
+ * sem_warn.adb (Check_Infinite_Loop_Warning): Use Has_Condition_Actions
+ to determine whether a loop has meaningful condition actions.
+ (Has_Condition_Actions): New routine.
+ * sinfo.adb (ABE_Is_Certain): Removed.
+ (Is_Declaration_Level_Node): New routine.
+ (Is_Dispatching_Call): New routine.
+ (Is_Elaboration_Checks_OK_Node): New routine.
+ (Is_Initialization_Block): New routine.
+ (Is_Known_Guaranteed_ABE): New routine.
+ (Is_Recorded_Scenario): New routine.
+ (Is_Source_Call): New routine.
+ (Is_SPARK_Mode_On_Node): New routine.
+ (No_Elaboration_Check): Removed.
+ (Target): New routine.
+ (Was_Attribute_Reference): New routine.
+ (Set_ABE_Is_Certain): Removed.
+ (Set_Is_Declaration_Level_Node): New routine.
+ (Set_Is_Dispatching_Call): New routine.
+ (Set_Is_Elaboration_Checks_OK_Node): New routine.
+ (Set_Is_Initialization_Block): New routine.
+ (Set_Is_Known_Guaranteed_ABE): New routine.
+ (Set_Is_Recorded_Scenario): New routine.
+ (Set_Is_Source_Call): New routine.
+ (Set_Is_SPARK_Mode_On_Node): New routine.
+ (Set_No_Elaboration_Check): Removed.
+ (Set_Target): New routine.
+ (Set_Was_Attribute_Reference): New routine.
+ * sinfo.ads: Remove attribute ABE_Is_Certain. Attribute
+ Do_Discriminant_Check now utilizes Flag3. Attribute
+ No_Side_Effect_Removal now utilizes Flag17. Add new node
+ N_Call_Marker. Update the structure of various nodes.
+ (ABE_Is_Certain): Removed along with pragma Inline.
+ (Is_Declaration_Level_Node): New routine along with pragma Inline.
+ (Is_Dispatching_Call): New routine along with pragma Inline.
+ (Is_Elaboration_Checks_OK_Node): New routine along with pragma Inline.
+ (Is_Initialization_Block): New routine along with pragma Inline.
+ (Is_Known_Guaranteed_ABE): New routine along with pragma Inline.
+ (Is_Recorded_Scenario): New routine along with pragma Inline.
+ (Is_Source_Call): New routine along with pragma Inline.
+ (Is_SPARK_Mode_On_Node): New routine along with pragma Inline.
+ (No_Elaboration_Check): Removed along with pragma Inline.
+ (Target): New routine along with pragma Inline.
+ (Was_Attribute_Reference): New routine along with pragma Inline.
+ (Set_ABE_Is_Certain): Removed along with pragma Inline.
+ (Set_Is_Declaration_Level_Node): New routine along with pragma Inline.
+ (Set_Is_Dispatching_Call): New routine along with pragma Inline.
+ (Set_Is_Elaboration_Checks_OK_Node): New routine along with pragma
+ Inline.
+ (Set_Is_Initialization_Block): New routine along with pragma Inline.
+ (Set_Is_Known_Guaranteed_ABE): New routine along with pragma Inline.
+ (Set_Is_Recorded_Scenario): New routine along with pragma Inline.
+ (Set_Is_Source_Call): New routine along with pragma Inline.
+ (Set_Is_SPARK_Mode_On_Node): New routine along with pragma Inline.
+ (Set_No_Elaboration_Check): Removed along with pragma Inline.
+ (Set_Target): New routine along with pragma Inline.
+ (Set_Was_Attribute_Reference): New routine along with pragma Inline.
+ * sprint.adb (Sprint_Node_Actual): Add an entry for N_Call_Marker.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * exp_ch7.adb (Create_Finalizer): Suppress checks within the finalizer.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * freeze.ads: Minor comment fixed.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb: (Make_Build_In_Place_Call_In_Object_Declaration): Take
+ care of unchecked conversions in addition to regular conversions. This
+ takes care of a case where a type is derived from a private untagged
+ type that is completed by a tagged controlled type.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * exp_disp.adb (Build_Class_Wide_Check, Replace_Formals): When
+ rewriting a class-wide condition, handle properly the case where the
+ controlling argument of the operation to which the condition applies is
+ an access to a tagged type, and the condition includes a dispatching
+ call with an implicit dereference.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb: (Make_Build_In_Place_Call_In_Object_Declaration): Remove
+ the code at the end of this procedure that was setting the type of a
+ class-wide object to the specific type returned by a function call.
+ Treat this case as indefinite instead.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch4.adb (Try_Class_Wide_Operation, Traverse_Homonyms):
+ Suppress spurious ambiguity error when two traversals of the homonym
+ chain (first directly, and then through an examination of relevant
+ interfaces) retrieve the same operation, when other irrelevant homonyms
+ of the operatioh are also present.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_util.adb (Object_Access_Level): If the object is the return
+ statement of an expression function, return the level of the function.
+ This is relevant when the object involves an implicit conversion
+ between access types and the expression function is a completion, which
+ forces the analysis of the expression before rewriting it as a body, so
+ that freeze nodes can appear in the proper scope.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * atree.adb: Make nnd apply to everything "interesting", including
+ Rewrite. Remove rrd.
+
+2017-10-09 Javier Miranda <miranda@adacore.com>
+
+ * exp_ch3.adb (Expand_N_Object_Declaration): Avoid never-ending loop
+ processing the declaration of the dummy object internally created by
+ Make_DT to compute the offset to the top of components referencing
+ secondary dispatch tables.
+ (Initialize_Tag): Do not initialize the offset-to-top field if it has
+ been initialized initialized.
+ * exp_disp.ads (Building_Static_Secondary_DT): New subprogram.
+ * exp_disp.adb (Building_Static_Secondary_DT): New subprogram.
+ (Make_DT): Create a dummy constant object if we can statically build
+ secondary dispatch tables.
+ (Make_Secondary_DT): For statically allocated secondary dispatch tables
+ use the dummy object to compute the offset-to-top field value by means
+ of the attribute 'Position.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb (Expand_N_Extended_Return_Statement): Add self-checking
+ code so if BIPAlloc is not passed in, it will likely raise
+ Program_Error instead of cause miscellaneous chaos.
+ (Is_Build_In_Place_Result_Type): Return False if not Expander_Active,
+ as for the other Is_B-I-P... functions.
+ * sem_aggr.adb (Resolve_Extension_Aggregate): For an extension
+ aggregate whose ancestor part is a build-in-place call returning a
+ nonlimited type, transform the assignment to the ancestor part to use a
+ temp.
+ * sem_ch3.adb (Build_Itype_Reference): Handle the case where we're
+ creating an Itype for a library unit entity.
+ (Check_Initialization): Avoid spurious error message on
+ internally-generated call.
+ * sem_ch5.adb (Analyze_Assignment): Handle the case where the
+ right-hand side is a build-in-place call. This didn't happen when b-i-p
+ was only for limited types.
+ * sem_ch6.adb (Create_Extra_Formals): Remove assumption that b-i-p
+ implies >= Ada 2005.
+ * sem_ch7.adb (Scan_Subprogram_Refs): Avoid traversing the same nodes
+ repeatedly.
+ * sem_util.adb (Next_Actual): Handle case of build-in-place call.
+
+2017-10-09 Arnaud Charlet <charlet@adacore.com>
+
+ * doc/gnat_ugn/gnat_and_program_execution.rst: Minor edit.
+
+2017-10-09 Piotr Trojanek <trojanek@adacore.com>
+
+ * libgnarl/s-taprob.adb: Minor whitespace fix.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * namet.ads: Minor comment fix.
+
+2017-10-09 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_aux.adb (Unit_Declaration_Node): Detect protected declarations,
+ just like other program units listed in Ada RM 10.1(1).
+
+2017-10-09 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch8.adb (Update_Chain_In_Scope): Modify warning messages.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch12.adb (Analyze_Associations, Check_Generic_Parent): If an
+ actual for a formal package is an instantiation of a child unit, create
+ a freeze node for the instance of the parent if it appears in the same
+ scope and is not frozen yet.
+
+2017-10-09 Pierre-Marie de Rodat <derodat@adacore.com>
+
+ * exp_atag.ads, libgnat/a-tags.adb, libgnat/a-tags.ads: Enhance
+ in-source documentation for tagged types's Offset_To_Top.
+
+2017-10-09 Bob Duff <duff@adacore.com>
+
+ * exp_ch3.adb (Build_Assignment): Parameter name N was somewhat
+ confusing. Same for N_Loc. Remove assumption that b-i-p implies
+ limited. This is for the case of a function call that occurs as the
+ default for a record component.
+ (Expand_N_Object_Declaration): Deal with the case where expansion has
+ created an object declaration initialized with something like
+ F(...)'Reference.
+ * exp_ch3.adb: Minor reformatting.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * exp_attr.adb (Expand_Attribute_Reference, case 'Valid): The prefix of
+ the attribute is an object, but it may appear within a conversion. The
+ object itself must be retrieved when generating the range test that
+ implements the validity check on a scalar type.
+
+2017-10-05 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR ada/82393
+ * mingw32.h (_O_U8TEXT, _O_U16TEXT, _O_WTEXT): Delete.
+ * sysdep.c (__gnat_set_mode ): Use DJGPP version for Cygwin.
+
+2017-10-02 Eric Botcazou <ebotcazou@adacore.com>
+ Pierre-Marie de Rodat <derodat@adacore.com>
+
+ PR ada/82384
+ * libgnarl/s-linux__x32.ads (suseconds_t): New subtype.
+ (time_t): Change from derived type to subtype.
+ (timeval): Use suseconds_t for tv_usec.
+ * libgnarl/s-osinte__x32.adb (To_Timespec): Remove use type clause.
+
+2017-10-02 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * gcc-interface/decl.c (annotate_value): Use wi::to_widest when
+ handling the form (plus/mult (convert @0) @1).
+
+2017-09-29 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb (Expand_Call_Helper): Replace with code more similar to
+ what we had before.
+ (Make_Build_In_Place_Call_In_Object_Declaration): Back out previous
+ change. Set the Etype in the class-wide case. This fixes a regression
+ in the libadalang test suite.
+
+2017-09-29 Joel Brobecker <brobecker@adacore.com>
+
+ * doc/gnat_ugn/building_executable_programs_with_gnat.rst,
+ doc/gnat_ugn/the_gnat_compilation_model.rst: Avoid use of single colon
+ in comment markup.
+ * gnat_ugn.texi: Regenerate.
+
+2017-09-29 Justin Squirek <squirek@adacore.com>
+
+ * ali-util.adb, comperr.adb, cprint.adb, errout.adb, fmap.adb,
+ fname-sf.adb, frontend.adb, lib-xref-spark_specific.adb, gnat1drv.adb,
+ gnatls.adb, lib.adb, lib-load.adb, lib-writ.adb, prepcomp.adb,
+ sinput-d.adb, sinput-l.adb, sprint.adb, targparm.adb: Update comparison
+ for checking source file status and error message and/or call to
+ Read_Source_File.
+ * libgnat/s-os_lib.ads: Add new potential value constant for
+ uninitialized file descriptors.
+ * osint.adb, osint.ads (Read_Source_File): Add extra parameter to
+ return result of IO to encompass a read access failure in addition to a
+ file-not-found error.
+
+2017-09-29 Bob Duff <duff@adacore.com>
+
+ * exp_ch6.adb (Expand_Call_Helper): Handle case of build-in-place
+ functions returning nonlimited types. Allow for qualified expressions
+ and type conversions.
+ (Expand_N_Extended_Return_Statement): Correct the computation of
+ Func_Bod to allow for child units.
+ (Expand_Simple_Function_Return): Remove assumption that b-i-p implies
+ limited (initialization of In_Place_Expansion), and implies >= Ada
+ 2005.
+ (Is_Build_In_Place_Result_Type): New function to accompany
+ Is_Build_In_Place_Function and Is_Build_In_Place_Function_Call, because
+ sometimes we just have the type on our hands, not the function. For
+ now, does the same thing as the old version, so build-in-place is
+ disabled for nonlimited types, except that you can use -gnatd.9 to
+ enable it.
+ * exp_ch6.ads (Is_Build_In_Place_Result_Type): New function to
+ accompany Is_Build_In_Place_Function and
+ Is_Build_In_Place_Function_Call, because sometimes we just have the
+ type on our hands, not the function.
+ (Make_Build_In_Place_Call_In_...): Handle nonlimited build-in-place
+ cases.
+ (Make_Build_In_Place_Call_In_Object_Declaration): Remove the
+ questionable code at the end that was setting the Etype.
+ * exp_aggr.adb (Is_Build_In_Place_Aggregate_Return): New function to
+ determine whether "return (...agg...);" is returning from a
+ build-in-place function.
+ (Initialize_Ctrl_Array_Component, Initialize_Ctrl_Record_Component):
+ Remove assumption that b-i-p implies limited (initialization of
+ In_Place_Expansion).
+ (Build_Record_Aggr_Code): AI-287: fix comment; it can't be wrapped in
+ an unchecked conversion. Add assertions.
+ (Convert_Aggr_In_Object_Decl): Establish_Transient_Scope -- no need for
+ secondary stack here, just because the type needs finalization. That
+ code is obsolete.
+ (Convert_To_Assignments): Only set Unc_Decl if Nkind (N) = N_Aggregate.
+ For "return (...agg...);" don't assume b-i-p implies limited.
+ Needs_Finalization does not imply secondary stack.
+ (Expand_Array_Aggregate): Named notation. Reverse the sense of
+ Component_OK_For_Backend -- more readability with fewer double
+ negatives.
+ * exp_attr.adb (Expand_N_Attribute_Reference): Remove assumptions that
+ b-i-p implies >= Ada 2005.
+ * exp_ch3.adb (Expand_N_Object_Declaration): Remove assumptions that
+ b-i-p implies >= Ada 2005. Remove Adjust if we're building the return
+ object of an extended return statement in place.
+ * exp_ch4.adb (Expand_Allocator_Expression, Expand_N_Indexed_Component,
+ Expand_N_Selected_Component, Expand_N_Slice): Remove assumptions that
+ b-i-p implies >= Ada 2005.
+ * exp_ch5.adb (Expand_N_Assignment_Statement): Remove assumption that
+ b-i-p implies >= Ada 2005.
+ * exp_ch7.adb: Comment fix.
+ * exp_ch8.adb (Expand_N_Object_Renaming_Declaration): Remove
+ assumptions that b-i-p implies >= Ada 2005.
+ * exp_disp.adb (Expand_Interface_Actuals): Remove assumptions that
+ b-i-p implies >= Ada 2005.
+ * exp_util.adb (Build_Allocate_Deallocate_Proc): Look at Storage_Pool
+ (Expr), in case Pool_Id is not set.
+ (Initialized_By_Aliased_BIP_Func_Call): Handle case where the call is
+ qualified or converted.
+ (Is_Secondary_Stack_BIP_Func_Call): Don't check if Nkind (Selector_Name
+ (Param)) = N_Identifier; that's all it could be.
+ * sinfo.ads: Comment fixes.
+ * snames.ads-tmpl: Comment fixes.
+ * debug.adb: Add flag gnatd.9, to enable the build-in-place machinery.
+
+2017-09-29 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch8.adb (Mark_Use_Clauses): Add recursive call to properly handle
+ all cases related to marking entity identifiers.
+
+2017-09-29 Vasiliy Fofanov <fofanov@adacore.com>
+
+ * adaint.c (win32_wait): Properly handle error and take into account
+ the WIN32 limitation on the number of simultaneous wait objects.
+
+2017-09-29 Vasiliy Fofanov <fofanov@adacore.com>
+
+ * cal.c: Minor proofreading.
+
+2017-09-29 Vasiliy Fofanov <fofanov@adacore.com>
+
+ * doc/gnat_ugn/gnat_utility_programs.rst: Minor formatting fix.
+ * gnat_ugn.texi: Regenerate.
+
+2017-09-29 Bob Duff <duff@adacore.com>
+
+ * lib-xref.ads: Comment fix.
+
+2017-09-29 Bob Duff <duff@adacore.com>
+
+ * exp_aggr.adb: Remove calls to Set_No_Ctrl_Actions for discriminants.
+ Discriminants can't need finalization.
+
+2017-09-29 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch6.adb (Analyze_Expression_Function): Do not emit freeze nodes
+ for types in expression if the function is within a generic unit.
+ * sem_res.adb (Resolve): In a generic context do not freeze an
+ expression, unless it is an entity. This exception is solely for the
+ purpose of detecting illegal uses of deferred constants in generic
+ units.
+ * sem_res.adb: Minor reformatting.
+
+2017-09-29 Justin Squirek <squirek@adacore.com>
+
+ * sem_ch8.adb (Note_Redundant_Use): Add guard to protect against false
+ redundant warnings.
+
+2017-09-29 Yannick Moy <moy@adacore.com>
+
+ * sinput-c.adb: Remove unused with-clause on Ada.Unchecked_Conversion.
+
+2017-09-29 Eric Botcazou <ebotcazou@adacore.com>
+
+ * doc/gnat_rm/representation_clauses_and_pragmas.rst: Minor rewording.
+ * doc/gnat_rm/implementation_defined_pragmas.rst (Optimize_Alignment):
+ Document the effect of pragma Optimize_Alignment (Space) on non-packed
+ record types.
+ * gnat_rm.texi: Regenerate.
+
+2017-09-25 Justin Squirek <squirek@adacore.com>
+
+ * aspects.adb, bindgen.adb, clean.adb, erroutc.adb, exp_ch13.adb,
+ exp_dbug.adb, exp_unst.adb, exp_util.adb, frontend.adb, gnat1drv.adb,
+ gnatdll.adb, gnatlink.adb, gnatls.adb, gnatname.adb, gnatxref.adb,
+ gnatfind.adb, libgnat/a-cfhama.ads, libgnat/a-exetim__mingw.adb,
+ libgnat/a-strmap.adb, libgnat/a-teioed.adb, libgnat/g-alvety.ads,
+ libgnat/g-expect.adb, libgnat/g-regist.adb, libgnat/g-socket.adb,
+ libgnat/g-socthi__mingw.ads, libgnat/s-stausa.adb,
+ libgnat/s-tsmona__linux.adb, libgnat/s-tsmona__mingw.adb,
+ libgnarl/s-taenca.adb, libgnarl/s-tassta.adb, libgnarl/s-tarest.adb,
+ libgnarl/s-tpobop.adb, make.adb, makeusg.adb, namet.adb, output.ads,
+ put_scos.adb, repinfo.adb, rtsfind.adb, scn.ads, sem_attr.adb,
+ sem_aux.ads, sem_warn.ads, targparm.adb, xr_tabls.adb, xref_lib.adb:
+ Removal of ineffective use-clauses.
+ * exp_ch9.adb (Is_Simple_Barrier_Name): Check for false positives with
+ constant folded barriers.
+ * ghost.adb, sprint.adb, sem_ch10.adb, sem_warn.adb: Change access to
+ Subtype_Marks and Names list in use-clause nodes to their new singular
+ counterparts (e.g. Subtype_Mark, Name).
+ * par.adb, par-ch8.adb (Append_Use_Clause): Created to set
+ Prev_Ids and More_Ids in use-clause nodes.
+ (P_Use_Clause): Modify to take a list as a parameter.
+ (P_Use_Package_Clause, P_Use_Type_Clause): Divide names and
+ subtype_marks within an aggregate use-clauses into individual clauses.
+ * par-ch3.adb, par-ch10.adb, par-ch12.adb: Trivally modify call to
+ P_Use_Clause to match its new behavior.
+ * sem.adb (Analyze): Mark use clauses for non-overloaded entities.
+ * sem_ch4.adb (Try_One_Interp): Add sanity check to handle previous
+ errors.
+ * sem_ch6.adb (Analyze_Generic_Subprogram_Body,
+ Analyze_Subprogram_Body_Helper): Update use clause chain at the end of
+ the declarative region.
+ * sem_ch7.adb (Analyze_Package_Body_Helper): Update use clause chain
+ after analysis (Analyze_Package_Specification): Update use clause chain
+ when there is no body.
+ * sem_ch8.ads, sem_ch8.adb (Analyze_Use_Package, Analyze_Use_Type): Add
+ parameter to determine weither the installation of scopes should also
+ propagate on the use-clause "chain".
+ (Mark_Use_Clauses): Created to traverse use-clause chains and determine
+ what constitutes a valid "use" of a clause.
+ (Update_Use_Clause_Chain): Created to aggregate common machinary used
+ to clean up use-clause chains (and warn on ineffectiveness) at the end
+ of declaritive regions.
+ * sem_ch8.adb (Analyze_Package_Name): Created to perform analysis on a
+ package name from a use-package clause.
+ (Analyze_Package_Name_List): Created to perform analysis on a list of
+ package names (similar to Analyze_Package_Name).
+ (Find_Most_Prev): Created to traverse to the beginning of a given
+ use-clause chain.
+ (Most_Decendant_Use_Clause): Create to identify which clause from a
+ given set is highest in scope (not always the most prev).
+ (Use_One_Package, Use_One_Type): Major cleanup and reorganization to
+ handle the new chaining algorithm, also many changes related to
+ redundant clauses. A new parameter has also been added to force
+ installation to handle certain cases.
+ * sem_ch9.adb (Analyze_Entry_Body, Analyze_Protected_Body,
+ Analyze_Task_Body): Mark use clauses on relevant entities.
+ * sem_ch10.adb, sem_ch10.ads (Install_Context_Clauses,
+ Install_Parents): Add parameter to determine weither the installation
+ of scopes should also propagate on the use-clause "chain".
+ * sem_ch12.adb (Inline_Instance_Body): Add flag in call to
+ Install_Context to avoid redundant chaining of use-clauses.
+ * sem_ch13.adb: Minor reformatting.
+ * sem_res.adb (Resolve): Mark use clauses on operators.
+ (Resolve_Call, Resolve_Entity_Name): Mark use clauses on relevant
+ entities.
+ * sinfo.adb, sinfo.ads (Is_Effective_Use_Clause,
+ Set_Is_Effective_Use_Clause): Add new flag to N_Use_Clause nodes to
+ represent any given clause's usage/reference/necessity.
+ (Prev_Use_Clause, Set_Prev_Use_Clause): Add new field to N_Use_Clause
+ nodes to allow loose chaining of redundant clauses.
+ (Set_Used_Operations, Set_Subtype_Mark, Set_Prev_Ids, Set_Names,
+ Set_More_Ids, Set_Name): Modify set procedure calls to reflect
+ reorganization in node fields.
+ * types.ads (Source_File_Index): Adjust index bounds.
+ (No_Access_To_Source_File): New constant.
+
+2017-09-25 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch13.adb (Analyze_One_Aspect): In ASIS mode make a full copy of
+ the expression to be used in the generated attribute specification
+ (rather than relocating it) to avoid resolving a potentially malformed
+ tree when the expression is resolved through an ASIS-specific call to
+ Resolve_Aspect_Expressions. This manifests itself as a crash on a
+ function with parameter associations.
+
+2017-09-25 Yannick Moy <moy@adacore.com>
+
+ * exp_spark.adb (Expand_SPARK_Indexed_Component,
+ Expand_SPARK_Selected_Component): New procedures to insert explicit
+ dereference if required.
+ (Expand_SPARK): Call the new procedures.
+
+2017-09-25 Patrick Bernardi <bernardi@adacore.com>
+
+ * libgnat/a-stwiun.adb, libgnat/s-stchop__vxworks.adb,
+ libgnat/g-socthi__vxworks.ads, libgnat/a-stzunb.adb,
+ libgnat/a-strunb.adb, libgnarl/s-osinte__lynxos178.adb,
+ libgnarl/s-intman__vxworks.adb, libgnarl/s-osinte__darwin.adb,
+ libgnarl/a-exetim__darwin.adb: Removed ineffective use-clauses.
+
+2017-09-25 Vasiliy Fofanov <fofanov@adacore.com>
+
+ * adaint.c (win32_wait): Properly handle error and take into account
+ the WIN32 limitation on the number of simultaneous wait objects.
+
+2017-09-25 Yannick Moy <moy@adacore.com>
+
+ * sem_ch3.adb (Constant_Redeclaration): Do not insert a call to the
+ invariant procedure in GNATprove mode.
+ * sem_ch5.adb (Analyze_Assignment): Likewise.
+
+2017-09-25 Piotr Trojanek <trojanek@adacore.com>
+
+ * adabkend.adb (Call_Back_End): Fix wording of "front-end" and
+ "back-end" in comments.
+
+2017-09-25 Ed Schonberg <schonberg@adacore.com>
+
+ * exp_ch6.adb (Expand_Call_Helper): The extra accessibility check in a
+ call that appears in a classwide precondition and that mentions an
+ access formal of the subprogram, must use the accessibility level of
+ the actual in the call. This is one case in which a reference to a
+ formal parameter appears outside of the body of the subprogram.
+
+2017-09-25 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_res.adb (Replace_Actual_Discriminants): Replace a discriminant
+ for GNATprove.
+ (Resolve_Entry): Clean up predicate
+
+2017-09-25 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * sem_prag.adb (Analyze_Constituent): Raise Unrecoverable_Error rather
+ than Program_Error because U_E is more in line with respect to the
+ intended behavior.
+
+2017-09-25 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch13.adb (Resolve_Aspect_Expressions): The expression for aspect
+ Storage_Size does not freeze, and thus can include references to
+ deferred constants.
+
+2017-09-25 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * exp_spark.adb (Expand_SPARK_Potential_Renaming): Do not process a
+ reference when it appears within a pragma of no significance to SPARK.
+ (In_Insignificant_Pragma): New routine.
+ * sem_prag.ads: Add new table Pragma_Significant_In_SPARK.
+
+2017-09-25 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch12.adb (Analyze_Associations, case N_Formal_Package): If the
+ actual is a renaming, indicate that it is the renamed package that must
+ be frozen before the instantiation.
+
+2017-09-25 Yannick Moy <moy@adacore.com>
+
+ * doc/gnat_ugn/gnat_and_program_execution.rst: Fix typo in description
+ of dimensionality system in GNAT UG.
+ * gnat_ugn.texi: Regenerate.
+
+2017-09-25 Yannick Moy <moy@adacore.com>
+
+ * gnat1drv.adb: Call Check_Safe_Pointers from the frontend in
+ GNATprove_Mode when switch -gnatdF used.
+
+2017-09-25 Piotr Trojanek <trojanek@adacore.com>
+
+ * adabkend.adb (Call_Back_End): Reset Current_Error_Node when starting
+ the backend.
+
+2017-09-25 Javier Miranda <miranda@adacore.com>
+
+ * exp_imgv.adb (Expand_Image_Attribute): Disable the optimized
+ expansion of user-defined enumeration types when the generation of
+ names for enumeration literals is suppressed.
+
+2017-09-25 Gary Dismukes <dismukes@adacore.com>
+
+ * libgnarl/s-taprop__linux.adb: Minor reformatting.
+
+2017-09-25 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch13.adb (Resolve_Aspect_Expressions): Do not resolve identifiers
+ that appear as selector names of parameter associations, as these are
+ never resolved by visibility.
+
+2017-09-25 Justin Squirek <squirek@adacore.com>
+
+ * sem_res.adb (Resolve_Entry): Generate reference for index entities.
+
+2017-09-25 Doug Rupp <rupp@adacore.com>
+
+ * libgnarl/s-taprop__linux.adb (Compute_Base_Monotonic_Clock): Refine.
+
+2017-09-25 Javier Miranda <miranda@adacore.com>
+
+ * exp_imgv.adb (Is_User_Defined_Enumeration_Type): New subprogram.
+ (Expand_User_Defined_Enumeration_Image): New subprogram.
+ (Expand_Image_Attribute): Enable speed-optimized expansion of
+ user-defined enumeration types when we are compiling with optimizations
+ enabled.
+
+2017-09-25 Piotr Trojanek <trojanek@adacore.com>
+
+ * sem_util.adb (Has_Null_Abstract_State): Remove, as an exactly same
+ routine is already provided by Einfo.
+ * einfo.adb (Has_Null_Abstract_State): Replace with the body from
+ Sem_Util, which had better comments and avoided double calls to
+ Abstract_State.
+
+2017-09-25 Bob Duff <duff@adacore.com>
+
+ * exp_ch3.adb: Rename Comp_Type_Simple to be Comp_Simple_Init.
+
+2017-09-25 Doug Rupp <rupp@adacore.com>
+
+ * libgnarl/s-taprop__linux.adb (Base_Monotonic_Clock): New variable.
+ (Compute_Base_Monotonic_Clock): New function.
+ (Timed_Sleep): Adjust to use Base_Monotonic_Clock.
+ (Timed_Delay): Likewise.
+ (Monotonic_Clock): Likewise.
+ * s-oscons-tmplt.c (CLOCK_MONOTONIC): Use on Linux.
+
+2017-09-25 Ed Schonberg <schonberg@adacore.com>
+
+ * sem_ch12.adb (Save_References_In_Aggregate): Small correction to
+ previous change.
+
+2017-09-25 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * exp_ch5.adb, sem_ch4.adb, sem_ch13.adb, sem_attr.adb, exp_ch3.adb:
+ Minor reformatting.
+
+2017-09-20 Alexandre Oliva <aoliva@redhat.com>
+
+ * gcc-interface/lang.opt (gant, gnatO, gnat): Add RejectNegative.
+
2017-09-18 Bob Duff <duff@adacore.com>
* sem_ch4.adb (Complete_Object_Operation): Do not insert 'Access for
diff --git a/gcc/ada/Makefile.rtl b/gcc/ada/Makefile.rtl
index 021da82..ed43ae5 100644
--- a/gcc/ada/Makefile.rtl
+++ b/gcc/ada/Makefile.rtl
@@ -659,6 +659,7 @@ GNATRTL_NONTASKING_OBJS= \
s-sequio$(objext) \
s-shasto$(objext) \
s-soflin$(objext) \
+ s-soliin$(objext) \
s-spsufi$(objext) \
s-stache$(objext) \
s-stalib$(objext) \
diff --git a/gcc/ada/adabkend.adb b/gcc/ada/adabkend.adb
index 7eee887..ae0218e 100644
--- a/gcc/ada/adabkend.adb
+++ b/gcc/ada/adabkend.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2001-2016, AdaCore --
+-- Copyright (C) 2001-2017, AdaCore --
-- --
-- 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- --
@@ -22,6 +22,7 @@
-- This is the version of the Back_End package for back ends written in Ada
+with Atree; use Atree;
with Debug;
with Lib;
with Opt; use Opt;
@@ -56,6 +57,13 @@ package body Adabkend is
Write_Eol;
end if;
+ -- The front end leaves the Current_Error_Node at a location that is
+ -- meaningless and confusing when emitting bug boxes from the back end.
+ -- Reset the global variable in order to emit "No source file position
+ -- information available" messages on back end crashes.
+
+ Current_Error_Node := Empty;
+
Driver (Lib.Cunit (Types.Main_Unit));
end Call_Back_End;
@@ -83,7 +91,7 @@ package body Adabkend is
--
-- If the switch is not valid, control will not return. The switches
-- must still be scanned to skip the "-o" arguments, or internal GCC
- -- switches, which may be safely ignored by other back-ends.
+ -- switches, which may be safely ignored by other back ends.
----------------------------
-- Scan_Back_End_Switches --
@@ -243,7 +251,7 @@ package body Adabkend is
else
Add_Src_Search_Dir (Argv);
- -- Add directory to lib search so that back-end can take as
+ -- Add directory to lib search so that back end can take as
-- input ALI files if needed. Otherwise this won't have any
-- impact on the compiler.
diff --git a/gcc/ada/adaint.c b/gcc/ada/adaint.c
index b1da3e2..10325b0 100644
--- a/gcc/ada/adaint.c
+++ b/gcc/ada/adaint.c
@@ -2551,6 +2551,7 @@ win32_wait (int *status)
DWORD res;
int hl_len;
int found;
+ int pos;
START_WAIT:
@@ -2563,7 +2564,15 @@ win32_wait (int *status)
/* -------------------- critical section -------------------- */
EnterCS();
+ /* ??? We can't wait for more than MAXIMUM_WAIT_OBJECTS due to a Win32
+ limitation */
+ if (plist_length < MAXIMUM_WAIT_OBJECTS)
hl_len = plist_length;
+ else
+ {
+ errno = EINVAL;
+ return -1;
+ }
#ifdef CERT
hl = (HANDLE *) xmalloc (sizeof (HANDLE) * hl_len);
@@ -2586,6 +2595,13 @@ win32_wait (int *status)
res = WaitForMultipleObjects (hl_len, hl, FALSE, INFINITE);
+ /* If there was an error, exit now */
+ if (res == WAIT_FAILED)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
/* if the ProcListEvt has been signaled then the list of processes has been
updated to add or remove a handle, just loop over */
@@ -2596,9 +2612,17 @@ win32_wait (int *status)
goto START_WAIT;
}
- h = hl[res - WAIT_OBJECT_0];
+ /* Handle two distinct groups of return codes: finished waits and abandoned
+ waits */
+
+ if (res < WAIT_ABANDONED_0)
+ pos = res - WAIT_OBJECT_0;
+ else
+ pos = res - WAIT_ABANDONED_0;
+
+ h = hl[pos];
GetExitCodeProcess (h, &exitcode);
- pid = pidl [res - WAIT_OBJECT_0];
+ pid = pidl [pos];
found = __gnat_win32_remove_handle (h, -1);
diff --git a/gcc/ada/ali-util.adb b/gcc/ada/ali-util.adb
index 40e2276..ea4e856 100644
--- a/gcc/ada/ali-util.adb
+++ b/gcc/ada/ali-util.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2014, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -148,7 +148,7 @@ package body ALI.Util is
Source_Index := Sinput.C.Load_File (Get_Name_String (Full_Name));
- if Source_Index = No_Source_File then
+ if Source_Index <= No_Source_File then
return Checksum_Error;
end if;
diff --git a/gcc/ada/ali.adb b/gcc/ada/ali.adb
index 2b1d472..959b305 100644
--- a/gcc/ada/ali.adb
+++ b/gcc/ada/ali.adb
@@ -58,6 +58,7 @@ package body ALI is
'Z' => True, -- implicit with from instantiation
'C' => True, -- SCO information
'F' => True, -- SPARK cross-reference information
+ 'T' => True, -- task stack information
others => False);
--------------------
@@ -842,7 +843,7 @@ package body ALI is
if Read_Xref then
Ignore :=
- ('U' | 'W' | 'Y' | 'Z' | 'D' | 'X' => False, others => True);
+ ('T' | 'U' | 'W' | 'Y' | 'Z' | 'D' | 'X' => False, others => True);
-- Read_Lines parameter given
@@ -1744,6 +1745,8 @@ package body ALI is
UL.Elaborate_Body_Desirable := False;
UL.Optimize_Alignment := 'O';
UL.Has_Finalizer := False;
+ UL.Primary_Stack_Count := 0;
+ UL.Sec_Stack_Count := 0;
if Debug_Flag_U then
Write_Str (" ----> reading unit ");
@@ -2096,6 +2099,28 @@ package body ALI is
Units.Table (Units.Last).Last_With := Withs.Last;
Units.Table (Units.Last).Last_Arg := Args.Last;
+ -- Scan out task stack information for the unit if present
+
+ Check_Unknown_Line;
+
+ if C = 'T' then
+ if Ignore ('T') then
+ Skip_Line;
+
+ else
+ Checkc (' ');
+ Skip_Space;
+
+ Units.Table (Units.Last).Primary_Stack_Count := Get_Nat;
+ Skip_Space;
+ Units.Table (Units.Last).Sec_Stack_Count := Get_Nat;
+ Skip_Space;
+ Skip_Eol;
+ end if;
+
+ C := Getc;
+ end if;
+
-- If there are linker options lines present, scan them
Name_Len := 0;
diff --git a/gcc/ada/ali.ads b/gcc/ada/ali.ads
index e15a1c4..3fa4d99 100644
--- a/gcc/ada/ali.ads
+++ b/gcc/ada/ali.ads
@@ -388,11 +388,19 @@ package ALI is
-- together as possible.
Optimize_Alignment : Character;
- -- Optimize_Alignment setting. Set to L/S/T/O for OL/OS/OT/OO present
+ -- Optimize_Alignment setting. Set to L/S/T/O for OL/OS/OT/OO present.
Has_Finalizer : Boolean;
-- Indicates whether a package body or a spec has a library-level
-- finalization routine.
+
+ Primary_Stack_Count : Int;
+ -- Indicates the number of task objects declared in this unit that have
+ -- default sized primary stacks.
+
+ Sec_Stack_Count : Int;
+ -- Indicates the number of task objects declared in this unit that have
+ -- default sized secondary stacks.
end record;
package Units is new Table.Table (
diff --git a/gcc/ada/aspects.adb b/gcc/ada/aspects.adb
index d5ec072..821f4b5 100644
--- a/gcc/ada/aspects.adb
+++ b/gcc/ada/aspects.adb
@@ -35,7 +35,7 @@ with Nlists; use Nlists;
with Sinfo; use Sinfo;
with Tree_IO; use Tree_IO;
-with GNAT.HTable; use GNAT.HTable;
+with GNAT.HTable;
package body Aspects is
diff --git a/gcc/ada/atree.adb b/gcc/ada/atree.adb
index 16feee0..1a7e36c 100644
--- a/gcc/ada/atree.adb
+++ b/gcc/ada/atree.adb
@@ -56,6 +56,9 @@ package body Atree is
Reporting_Proc : Report_Proc := null;
-- Record argument to last call to Set_Reporting_Proc
+ Rewriting_Proc : Rewrite_Proc := null;
+ -- This soft link captures the procedure invoked during a node rewrite
+
---------------
-- Debugging --
---------------
@@ -73,11 +76,12 @@ package body Atree is
-- ww := 12345
-- and set a breakpoint on New_Node_Breakpoint (nickname "nn"). Continue.
- -- Either way, gnat1 will stop when node 12345 is created
-
- -- The second method is much faster
+ -- Either way, gnat1 will stop when node 12345 is created, or certain other
+ -- interesting operations are performed, such as Rewrite. To see exactly
+ -- which operations, search for "pragma Debug" below.
- -- Similarly, rr and rrd allow breaking on rewriting of a given node
+ -- The second method is much faster if the amount of Ada code being
+ -- compiled is large.
ww : Node_Id'Base := Node_Id'First - 1;
pragma Export (Ada, ww); -- trick the optimizer
@@ -103,24 +107,8 @@ package body Atree is
-- If Node = Watch_Node, this prints out the new node and calls
-- New_Node_Breakpoint. Otherwise, does nothing.
- procedure rr;
- pragma Export (Ada, rr);
- procedure Rewrite_Breakpoint renames rr;
- -- This doesn't do anything interesting; it's just for setting breakpoint
- -- on as explained above.
-
- procedure rrd (Old_Node, New_Node : Node_Id);
- pragma Export (Ada, rrd);
- procedure Rewrite_Debugging_Output
- (Old_Node, New_Node : Node_Id) renames rrd;
- -- For debugging. If debugging is turned on, Rewrite calls this. If debug
- -- flag N is turned on, this prints out the new node.
- --
- -- If Old_Node = Watch_Node, this prints out the old and new nodes and
- -- calls Rewrite_Breakpoint. Otherwise, does nothing.
-
procedure Node_Debug_Output (Op : String; N : Node_Id);
- -- Common code for nnd and rrd, writes Op followed by information about N
+ -- Called by nnd; writes Op followed by information about N
procedure Print_Statistics;
pragma Export (Ada, Print_Statistics);
@@ -751,6 +739,9 @@ package body Atree is
Save_Link : constant Union_Id := Nodes.Table (Destination).Link;
begin
+ pragma Debug (New_Node_Debugging_Output (Source));
+ pragma Debug (New_Node_Debugging_Output (Destination));
+
Nodes.Table (Destination) := Nodes.Table (Source);
Nodes.Table (Destination).In_List := Save_In_List;
Nodes.Table (Destination).Link := Save_Link;
@@ -1319,16 +1310,6 @@ package body Atree is
Ekind_In (Ekind (E), V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V11);
end Ekind_In;
- ------------------------
- -- Set_Reporting_Proc --
- ------------------------
-
- procedure Set_Reporting_Proc (P : Report_Proc) is
- begin
- pragma Assert (Reporting_Proc = null);
- Reporting_Proc := P;
- end Set_Reporting_Proc;
-
------------------
-- Error_Posted --
------------------
@@ -1348,6 +1329,9 @@ package body Atree is
Temp_Flg : Flags_Byte;
begin
+ pragma Debug (New_Node_Debugging_Output (E1));
+ pragma Debug (New_Node_Debugging_Output (E2));
+
pragma Assert (True
and then Has_Extension (E1)
and then Has_Extension (E2)
@@ -1420,8 +1404,10 @@ package body Atree is
begin
pragma Assert (not (Has_Extension (Node)));
+
Result := Allocate_Initialize_Node (Node, With_Extension => True);
pragma Debug (Debug_Extend_Node);
+
return Result;
end Extend_Node;
@@ -1695,8 +1681,8 @@ package body Atree is
Current_Error_Node := Ent;
end if;
- Nodes.Table (Ent).Nkind := New_Node_Kind;
- Nodes.Table (Ent).Sloc := New_Sloc;
+ Nodes.Table (Ent).Nkind := New_Node_Kind;
+ Nodes.Table (Ent).Sloc := New_Sloc;
pragma Debug (New_Node_Debugging_Output (Ent));
-- Mark the new entity as Ghost depending on the current Ghost region
@@ -1718,6 +1704,7 @@ package body Atree is
begin
pragma Assert (New_Node_Kind not in N_Entity);
+
Nod := Allocate_Initialize_Node (Empty, With_Extension => False);
Nodes.Table (Nod).Nkind := New_Node_Kind;
Nodes.Table (Nod).Sloc := New_Sloc;
@@ -1746,7 +1733,6 @@ package body Atree is
begin
Write_Str ("Watched node ");
Write_Int (Int (Watch_Node));
- Write_Str (" created");
Write_Eol;
end nn;
@@ -1759,7 +1745,7 @@ package body Atree is
begin
if Debug_Flag_N or else Node_Is_Watched then
- Node_Debug_Output ("Allocate", N);
+ Node_Debug_Output ("Node", N);
if Node_Is_Watched then
New_Node_Breakpoint;
@@ -2164,6 +2150,9 @@ package body Atree is
and not Has_Extension (New_Node)
and not Nodes.Table (New_Node).In_List);
+ pragma Debug (New_Node_Debugging_Output (Old_Node));
+ pragma Debug (New_Node_Debugging_Output (New_Node));
+
-- Do copy, preserving link and in list status and required flags
Copy_Node (Source => New_Node, Destination => Old_Node);
@@ -2214,7 +2203,9 @@ package body Atree is
(not Has_Extension (Old_Node)
and not Has_Extension (New_Node)
and not Nodes.Table (New_Node).In_List);
- pragma Debug (Rewrite_Debugging_Output (Old_Node, New_Node));
+
+ pragma Debug (New_Node_Debugging_Output (Old_Node));
+ pragma Debug (New_Node_Debugging_Output (New_Node));
if Nkind (Old_Node) in N_Subexpr then
Old_Paren_Count := Paren_Count (Old_Node);
@@ -2262,37 +2253,13 @@ package body Atree is
if Reporting_Proc /= null then
Reporting_Proc.all (Target => Old_Node, Source => New_Node);
end if;
- end Rewrite;
- -------------------------
- -- Rewrite_Breakpoint --
- -------------------------
+ -- Invoke the rewriting procedure (if available)
- procedure rr is
- begin
- Write_Str ("Watched node ");
- Write_Int (Int (Watch_Node));
- Write_Str (" rewritten");
- Write_Eol;
- end rr;
-
- ------------------------------
- -- Rewrite_Debugging_Output --
- ------------------------------
-
- procedure rrd (Old_Node, New_Node : Node_Id) is
- Node_Is_Watched : constant Boolean := Old_Node = Watch_Node;
-
- begin
- if Debug_Flag_N or else Node_Is_Watched then
- Node_Debug_Output ("Rewrite", Old_Node);
- Node_Debug_Output ("into", New_Node);
-
- if Node_Is_Watched then
- Rewrite_Breakpoint;
- end if;
+ if Rewriting_Proc /= null then
+ Rewriting_Proc.all (Target => Old_Node, Source => New_Node);
end if;
- end rrd;
+ end Rewrite;
------------------
-- Set_Analyzed --
@@ -2429,6 +2396,16 @@ package body Atree is
Nodes.Table (N).Link := Union_Id (Val);
end Set_Parent;
+ ------------------------
+ -- Set_Reporting_Proc --
+ ------------------------
+
+ procedure Set_Reporting_Proc (Proc : Report_Proc) is
+ begin
+ pragma Assert (Reporting_Proc = null);
+ Reporting_Proc := Proc;
+ end Set_Reporting_Proc;
+
--------------
-- Set_Sloc --
--------------
@@ -2439,6 +2416,16 @@ package body Atree is
Nodes.Table (N).Sloc := Val;
end Set_Sloc;
+ ------------------------
+ -- Set_Rewriting_Proc --
+ ------------------------
+
+ procedure Set_Rewriting_Proc (Proc : Rewrite_Proc) is
+ begin
+ pragma Assert (Rewriting_Proc = null);
+ Rewriting_Proc := Proc;
+ end Set_Rewriting_Proc;
+
----------
-- Sloc --
----------
diff --git a/gcc/ada/atree.ads b/gcc/ada/atree.ads
index 5ed81e6..bf0da16 100644
--- a/gcc/ada/atree.ads
+++ b/gcc/ada/atree.ads
@@ -572,10 +572,15 @@ package Atree is
type Report_Proc is access procedure (Target : Node_Id; Source : Node_Id);
- procedure Set_Reporting_Proc (P : Report_Proc);
+ procedure Set_Reporting_Proc (Proc : Report_Proc);
-- Register a procedure that is invoked when a node is allocated, replaced
-- or rewritten.
+ type Rewrite_Proc is access procedure (Target : Node_Id; Source : Node_Id);
+
+ procedure Set_Rewriting_Proc (Proc : Rewrite_Proc);
+ -- Register a procedure that is invoked when a node is rewritten
+
type Traverse_Result is (Abandon, OK, OK_Orig, Skip);
-- This is the type of the result returned by the Process function passed
-- to Traverse_Func and Traverse_Proc. See below for details.
@@ -4231,25 +4236,26 @@ package Atree is
-- for extending components are completely unused.
type Flags_Byte is record
- Flag0 : Boolean;
+ Flag0 : Boolean;
-- Note: we don't use Flag0 at the moment. To put Flag0 into use
-- requires some awkward work in Treeprs (treeprs.adt), so for the
-- moment we don't use it.
- Flag1 : Boolean;
- Flag2 : Boolean;
- Flag3 : Boolean;
+ Flag1 : Boolean;
+ Flag2 : Boolean;
+ Flag3 : Boolean;
-- These flags are used in the usual manner in Sinfo and Einfo
- Is_Ignored_Ghost_Node : Boolean;
- -- Flag denoting whether the node is subject to pragma Ghost with
- -- policy Ignore. The name of the flag should be Flag4, however this
- -- requires changing the names of all remaining 300+ flags.
+ -- The flags listed below use explicit names because following the
+ -- FlagXXX convention would mean reshuffling of over 300+ flags.
Check_Actuals : Boolean;
-- Flag set to indicate that the marked node is subject to the check
- -- for writable actuals. See xxx for more details. Again it would be
- -- more uniform to use some Flagx here, but that would be disruptive.
+ -- for writable actuals.
+
+ Is_Ignored_Ghost_Node : Boolean;
+ -- Flag denoting whether the node is subject to pragma Ghost with
+ -- policy Ignore.
Spare2 : Boolean;
Spare3 : Boolean;
diff --git a/gcc/ada/bindgen.adb b/gcc/ada/bindgen.adb
index 59b43e0..e3d875b 100644
--- a/gcc/ada/bindgen.adb
+++ b/gcc/ada/bindgen.adb
@@ -35,19 +35,17 @@ with Osint.B; use Osint.B;
with Output; use Output;
with Rident; use Rident;
with Stringt; use Stringt;
-with Table; use Table;
+with Table;
with Targparm; use Targparm;
with Types; use Types;
-with System.OS_Lib; use System.OS_Lib;
+with System.OS_Lib;
with System.WCh_Con; use System.WCh_Con;
with GNAT.Heap_Sort_A; use GNAT.Heap_Sort_A;
with GNAT.HTable;
package body Bindgen is
- use Binde.Unit_Id_Tables;
-
Statement_Buffer : String (1 .. 1000);
-- Buffer used for constructing output statements
@@ -61,6 +59,14 @@ package body Bindgen is
Num_Elab_Calls : Nat := 0;
-- Number of generated calls to elaboration routines
+ Num_Primary_Stacks : Int := 0;
+ -- Number of default-sized primary stacks the binder needs to allocate for
+ -- task objects declared in the program.
+
+ Num_Sec_Stacks : Int := 0;
+ -- Number of default-sized primary stacks the binder needs to allocate for
+ -- task objects declared in the program.
+
System_Restrictions_Used : Boolean := False;
-- Flag indicating whether the unit System.Restrictions is in the closure
-- of the partition. This is set by Resolve_Binder_Options, and is used
@@ -76,6 +82,12 @@ package body Bindgen is
-- domains just before calling the main procedure from the environment
-- task.
+ System_Secondary_Stack_Used : Boolean := False;
+ -- Flag indicating whether the unit System.Secondary_Stack is in the
+ -- closure of the partition. This is set by Resolve_Binder_Options, and
+ -- is used to initialize the package in cases where the run-time brings
+ -- in package but the secondary stack is not used.
+
System_Tasking_Restricted_Stages_Used : Boolean := False;
-- Flag indicating whether the unit System.Tasking.Restricted.Stages is in
-- the closure of the partition. This is set by Resolve_Binder_Options,
@@ -181,8 +193,11 @@ package body Bindgen is
-- Exception_Tracebacks_Symbolic : Integer;
-- Detect_Blocking : Integer;
-- Default_Stack_Size : Integer;
+ -- Default_Secondary_Stack_Size : System.Parameters.Size_Type;
-- Leap_Seconds_Support : Integer;
-- Main_CPU : Integer;
+ -- Default_Sized_SS_Pool : System.Address;
+ -- Binder_Sec_Stacks_Count : Natural;
-- Main_Priority is the priority value set by pragma Priority in the main
-- program. If no such pragma is present, the value is -1.
@@ -263,6 +278,9 @@ package body Bindgen is
-- Default_Stack_Size is the default stack size used when creating an Ada
-- task with no explicit Storage_Size clause.
+ -- Default_Secondary_Stack_Size is the default secondary stack size used
+ -- when creating an Ada task with no explicit Secondary_Stack_Size clause.
+
-- Leap_Seconds_Support denotes whether leap seconds have been enabled or
-- disabled. A value of zero indicates that leap seconds are turned "off",
-- while a value of one signifies "on" status.
@@ -270,6 +288,14 @@ package body Bindgen is
-- Main_CPU is the processor set by pragma CPU in the main program. If no
-- such pragma is present, the value is -1.
+ -- Default_Sized_SS_Pool is set to the address of the default-sized
+ -- secondary stacks array generated by the binder. This pool of stacks is
+ -- generated when either the restriction No_Implicit_Heap_Allocations
+ -- or No_Implicit_Task_Allocations is active.
+
+ -- Binder_Sec_Stacks_Count is the number of generated secondary stacks in
+ -- the Default_Sized_SS_Pool.
+
procedure WBI (Info : String) renames Osint.B.Write_Binder_Info;
-- Convenient shorthand used throughout
@@ -556,6 +582,32 @@ package body Bindgen is
WBI (" procedure Start_Slave_CPUs;");
WBI (" pragma Import (C, Start_Slave_CPUs," &
" ""__gnat_start_slave_cpus"");");
+ WBI ("");
+ end if;
+
+ -- A restricted run-time may attempt to initialize the main task's
+ -- secondary stack even if the stack is not used. Consequently,
+ -- the binder needs to initialize Binder_Sec_Stacks_Count anytime
+ -- System.Secondary_Stack is in the enclosure of the partition.
+
+ if System_Secondary_Stack_Used then
+ WBI (" Binder_Sec_Stacks_Count : Natural;");
+ WBI (" pragma Import (Ada, Binder_Sec_Stacks_Count, " &
+ """__gnat_binder_ss_count"");");
+ WBI ("");
+ end if;
+
+ if Sec_Stack_Used then
+ WBI (" Default_Secondary_Stack_Size : " &
+ "System.Parameters.Size_Type;");
+ WBI (" pragma Import (C, Default_Secondary_Stack_Size, " &
+ """__gnat_default_ss_size"");");
+
+ WBI (" Default_Sized_SS_Pool : System.Address;");
+ WBI (" pragma Import (Ada, Default_Sized_SS_Pool, " &
+ """__gnat_default_ss_pool"");");
+
+ WBI ("");
end if;
WBI (" begin");
@@ -590,6 +642,50 @@ package body Bindgen is
WBI (" null;");
end if;
+ -- Generate default-sized secondary stack pool and set secondary
+ -- stack globals.
+
+ if Sec_Stack_Used then
+
+ -- Elaborate the body of the binder to initialize the default-
+ -- sized secondary stack pool.
+
+ WBI ("");
+ WBI (" " & Get_Ada_Main_Name & "'Elab_Body;");
+
+ -- Generate the default-sized secondary stack pool and set the
+ -- related secondary stack globals.
+
+ Set_String (" Default_Secondary_Stack_Size := ");
+
+ if Opt.Default_Sec_Stack_Size /= Opt.No_Stack_Size then
+ Set_Int (Opt.Default_Sec_Stack_Size);
+ else
+ Set_String ("System.Parameters.Runtime_Default_Sec_Stack_Size");
+ end if;
+
+ Set_Char (';');
+ Write_Statement_Buffer;
+
+ Set_String (" Binder_Sec_Stacks_Count := ");
+ Set_Int (Num_Sec_Stacks);
+ Set_Char (';');
+ Write_Statement_Buffer;
+
+ WBI (" Default_Sized_SS_Pool := " &
+ "Sec_Default_Sized_Stacks'Address;");
+ WBI ("");
+
+ -- When a restricted run-time initializes the main task's secondary
+ -- stack but the program does not use it, no secondary stack is
+ -- generated. Binder_Sec_Stacks_Count is set to zero so the run-time
+ -- is aware that the lack of pre-allocated secondary stack is
+ -- expected.
+
+ elsif System_Secondary_Stack_Used then
+ WBI (" Binder_Sec_Stacks_Count := 0;");
+ end if;
+
-- Normal case (standard library not suppressed). Set all global values
-- used by the run time.
@@ -649,6 +745,10 @@ package body Bindgen is
WBI (" Default_Stack_Size : Integer;");
WBI (" pragma Import (C, Default_Stack_Size, " &
"""__gl_default_stack_size"");");
+ WBI (" Default_Secondary_Stack_Size : " &
+ "System.Parameters.Size_Type;");
+ WBI (" pragma Import (C, Default_Secondary_Stack_Size, " &
+ """__gnat_default_ss_size"");");
WBI (" Leap_Seconds_Support : Integer;");
WBI (" pragma Import (C, Leap_Seconds_Support, " &
"""__gl_leap_seconds_support"");");
@@ -732,6 +832,18 @@ package body Bindgen is
& """__gnat_freeze_dispatching_domains"");");
end if;
+ -- Secondary stack global variables
+
+ WBI (" Binder_Sec_Stacks_Count : Natural;");
+ WBI (" pragma Import (Ada, Binder_Sec_Stacks_Count, " &
+ """__gnat_binder_ss_count"");");
+
+ WBI (" Default_Sized_SS_Pool : System.Address;");
+ WBI (" pragma Import (Ada, Default_Sized_SS_Pool, " &
+ """__gnat_default_ss_pool"");");
+
+ WBI ("");
+
-- Start of processing for Adainit
WBI (" begin");
@@ -872,9 +984,51 @@ package body Bindgen is
WBI (" Bind_Env_Addr := Bind_Env'Address;");
end if;
- -- Generate call to Install_Handler
-
WBI ("");
+
+ -- Generate default-sized secondary stack pool and set secondary
+ -- stack globals.
+
+ if Sec_Stack_Used then
+
+ -- Elaborate the body of the binder to initialize the default-
+ -- sized secondary stack pool.
+
+ WBI (" " & Get_Ada_Main_Name & "'Elab_Body;");
+
+ -- Generate the default-sized secondary stack pool and set the
+ -- related secondary stack globals.
+
+ Set_String (" Default_Secondary_Stack_Size := ");
+
+ if Opt.Default_Sec_Stack_Size /= Opt.No_Stack_Size then
+ Set_Int (Opt.Default_Sec_Stack_Size);
+ else
+ Set_String ("System.Parameters.Runtime_Default_Sec_Stack_Size");
+ end if;
+
+ Set_Char (';');
+ Write_Statement_Buffer;
+
+ Set_String (" Binder_Sec_Stacks_Count := ");
+ Set_Int (Num_Sec_Stacks);
+ Set_Char (';');
+ Write_Statement_Buffer;
+
+ Set_String (" Default_Sized_SS_Pool := ");
+
+ if Num_Sec_Stacks > 0 then
+ Set_String ("Sec_Default_Sized_Stacks'Address;");
+ else
+ Set_String ("System.Null_Address;");
+ end if;
+
+ Write_Statement_Buffer;
+ WBI ("");
+ end if;
+
+ -- Generate call to Runtime_Initialize
+
WBI (" Runtime_Initialize (1);");
end if;
@@ -890,17 +1044,6 @@ package body Bindgen is
Write_Statement_Buffer;
end if;
- -- Generate assignment of default secondary stack size if set
-
- if Sec_Stack_Used and then Default_Sec_Stack_Size /= -1 then
- WBI ("");
- Set_String (" System.Secondary_Stack.");
- Set_String ("Default_Secondary_Stack_Size := ");
- Set_Int (Opt.Default_Sec_Stack_Size);
- Set_Char (';');
- Write_Statement_Buffer;
- end if;
-
-- Initialize stack limit variable of the environment task if the stack
-- check method is stack limit and stack check is enabled.
@@ -2046,6 +2189,26 @@ package body Bindgen is
end if;
end loop;
+ -- Count the number of statically allocated stacks to be generated by
+ -- the binder. If the user has specified the number of default-sized
+ -- secondary stacks, use that number. Otherwise start the count at one
+ -- as the binder is responsible for creating a secondary stack for the
+ -- main task.
+
+ if Opt.Quantity_Of_Default_Size_Sec_Stacks /= -1 then
+ Num_Sec_Stacks := Quantity_Of_Default_Size_Sec_Stacks;
+ elsif Sec_Stack_Used then
+ Num_Sec_Stacks := 1;
+ end if;
+
+ for J in Units.First .. Units.Last loop
+ Num_Primary_Stacks :=
+ Num_Primary_Stacks + Units.Table (J).Primary_Stack_Count;
+
+ Num_Sec_Stacks :=
+ Num_Sec_Stacks + Units.Table (J).Sec_Stack_Count;
+ end loop;
+
-- Generate output file in appropriate language
Gen_Output_File_Ada (Filename, Elab_Order);
@@ -2116,9 +2279,11 @@ package body Bindgen is
WBI ("with System.Scalar_Values;");
end if;
- -- Generate with of System.Secondary_Stack if active
+ -- Generate withs of System.Secondary_Stack and System.Parameters to
+ -- allow the generation of the default-sized secondary stack pool.
- if Sec_Stack_Used and then Default_Sec_Stack_Size /= -1 then
+ if Sec_Stack_Used then
+ WBI ("with System.Parameters;");
WBI ("with System.Secondary_Stack;");
end if;
@@ -2158,10 +2323,10 @@ package body Bindgen is
end if;
end if;
- -- Define exit status. Again in normal mode, this is in the
- -- run-time library, and is initialized there, but in the
- -- configurable runtime case, the variable is declared and
- -- initialized in this file.
+ -- Define exit status. Again in normal mode, this is in the run-time
+ -- library, and is initialized there, but in the configurable
+ -- run-time case, the variable is declared and initialized in this
+ -- file.
WBI ("");
@@ -2360,6 +2525,29 @@ package body Bindgen is
Gen_Elab_Externals (Elab_Order);
+ -- Generate default-sized secondary stacks pool. At least one stack is
+ -- created and assigned to the environment task if secondary stacks are
+ -- used by the program.
+
+ if Sec_Stack_Used then
+ Set_String (" Sec_Default_Sized_Stacks");
+ Set_String (" : array (1 .. ");
+ Set_Int (Num_Sec_Stacks);
+ Set_String (") of aliased System.Secondary_Stack.SS_Stack (");
+
+ if Opt.Default_Sec_Stack_Size /= No_Stack_Size then
+ Set_Int (Opt.Default_Sec_Stack_Size);
+ else
+ Set_String ("System.Parameters.Runtime_Default_Sec_Stack_Size");
+ end if;
+
+ Set_String (");");
+ Write_Statement_Buffer;
+ WBI ("");
+ end if;
+
+ -- Generate reference
+
if not CodePeer_Mode then
if not Suppress_Standard_Library_On_Target then
@@ -2391,8 +2579,8 @@ package body Bindgen is
if not Suppress_Standard_Library_On_Target then
- -- The B.1(39) implementation advice says that the adainit
- -- and adafinal routines should be idempotent. Generate a flag to
+ -- The B.1(39) implementation advice says that the adainit and
+ -- adafinal routines should be idempotent. Generate a flag to
-- ensure that. This is not needed if we are suppressing the
-- standard library since it would never be referenced.
@@ -2875,6 +3063,11 @@ package body Bindgen is
Check_Package (System_Restrictions_Used, "system.restrictions%s");
+ -- Ditto for the use of System.Secondary_Stack
+
+ Check_Package
+ (System_Secondary_Stack_Used, "system.secondary_stack%s");
+
-- Ditto for use of an SMP bareboard runtime
Check_Package (System_BB_CPU_Primitives_Multiprocessors_Used,
diff --git a/gcc/ada/bindusg.adb b/gcc/ada/bindusg.adb
index 6cf7710..7c17f93 100644
--- a/gcc/ada/bindusg.adb
+++ b/gcc/ada/bindusg.adb
@@ -210,6 +210,11 @@ package body Bindusg is
Write_Line
(" -P Generate binder file suitable for CodePeer");
+ -- Line for Q switch
+
+ Write_Line
+ (" -Qnnn Generate nnn default-sized secondary stacks");
+
-- Line for -r switch
Write_Line
@@ -309,8 +314,6 @@ package body Bindusg is
Write_Line
(" -z No main subprogram (zero main)");
- -- Line for --RTS
-
-- Line for -Z switch
Write_Line
diff --git a/gcc/ada/cal.c b/gcc/ada/cal.c
index 14921dc..05e4953 100644
--- a/gcc/ada/cal.c
+++ b/gcc/ada/cal.c
@@ -6,7 +6,7 @@
* *
* C Implementation File *
* *
- * Copyright (C) 1992-2014, Free Software Foundation, Inc. *
+ * Copyright (C) 1992-2017, 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- *
@@ -29,10 +29,10 @@
* *
****************************************************************************/
-/* This file contains those routines named by Import pragmas in package */
+/* This file contains routines marked with pragmas Import in package */
/* GNAT.Calendar. It is used to do Duration to timeval conversion. */
-/* These are simple wrappers function to abstract the fact that the C */
-/* struct timeval fields type are not normalized (they are generally */
+/* These are simple wrapper functions to abstract the fact that the C */
+/* struct timeval fields are not normalized (they are generally */
/* defined as int or long values). */
#if defined (__vxworks)
diff --git a/gcc/ada/checks.adb b/gcc/ada/checks.adb
index 8a542ad..b2c26ca 100644
--- a/gcc/ada/checks.adb
+++ b/gcc/ada/checks.adb
@@ -5398,8 +5398,10 @@ package body Checks is
elsif Checks_May_Be_Suppressed (E) then
if Is_Check_Suppressed (E, Elaboration_Check) then
return True;
+
elsif Dynamic_Elaboration_Checks then
return Is_Check_Suppressed (E, All_Checks);
+
else
return False;
end if;
@@ -5408,8 +5410,10 @@ package body Checks is
if Scope_Suppress.Suppress (Elaboration_Check) then
return True;
+
elsif Dynamic_Elaboration_Checks then
return Scope_Suppress.Suppress (All_Checks);
+
else
return False;
end if;
@@ -5936,6 +5940,10 @@ package body Checks is
-- In addition, we force a check if Force_Validity_Checks is set
elsif not Comes_From_Source (Expr)
+ and then not
+ (Nkind (Expr) = N_Identifier
+ and then Present (Renamed_Object (Entity (Expr)))
+ and then Comes_From_Source (Renamed_Object (Entity (Expr))))
and then not Force_Validity_Checks
and then (Nkind (Expr) /= N_Unchecked_Type_Conversion
or else Kill_Range_Check (Expr))
@@ -7927,7 +7935,7 @@ package body Checks is
Flag_Id :=
Make_Defining_Identifier (Loc,
- Chars => New_External_Name (Chars (Subp_Id), 'F', -1));
+ Chars => New_External_Name (Chars (Subp_Id), 'E', -1));
Set_Is_Frozen (Flag_Id);
-- Insert the declaration of the elaboration flag in front of the
@@ -7936,7 +7944,7 @@ package body Checks is
Push_Scope (Scope (Subp_Id));
-- Generate:
- -- F : Boolean := False;
+ -- E : Boolean := False;
Insert_Action (Subp_Decl,
Make_Object_Declaration (Loc,
@@ -7986,7 +7994,7 @@ package body Checks is
end if;
-- Generate:
- -- F := True;
+ -- E := True;
Insert_After_And_Analyze (Set_Ins,
Make_Assignment_Statement (Loc,
@@ -8060,12 +8068,14 @@ package body Checks is
-- since it clearly was not overridden at any point). For a predefined
-- check, we test the specific flag. For a user defined check, we check
-- the All_Checks flag. The Overflow flag requires special handling to
- -- deal with the General vs Assertion case
+ -- deal with the General vs Assertion case.
if C = Overflow_Check then
return Overflow_Checks_Suppressed (Empty);
+
elsif C in Predefined_Check_Id then
return Scope_Suppress.Suppress (C);
+
else
return Scope_Suppress.Suppress (All_Checks);
end if;
diff --git a/gcc/ada/clean.adb b/gcc/ada/clean.adb
index 2b3d033..891575e 100644
--- a/gcc/ada/clean.adb
+++ b/gcc/ada/clean.adb
@@ -31,7 +31,7 @@ with Osint; use Osint;
with Osint.M; use Osint.M;
with Switch; use Switch;
with Table;
-with Targparm; use Targparm;
+with Targparm;
with Types; use Types;
with Ada.Command_Line; use Ada.Command_Line;
diff --git a/gcc/ada/comperr.adb b/gcc/ada/comperr.adb
index 1b5aa3e..e76081c 100644
--- a/gcc/ada/comperr.adb
+++ b/gcc/ada/comperr.adb
@@ -253,6 +253,7 @@ package body Comperr is
-- we use the contents of this file at this point.
declare
+ FD : File_Descriptor;
Lo : Source_Ptr;
Hi : Source_Ptr;
Src : Source_Buffer_Ptr;
@@ -261,7 +262,7 @@ package body Comperr is
Namet.Unlock;
Name_Buffer (1 .. 12) := "gnat_bug.box";
Name_Len := 12;
- Read_Source_File (Name_Enter, 0, Hi, Src);
+ Read_Source_File (Name_Enter, 0, Hi, Src, FD);
-- If we get a Src file, we use it
@@ -457,7 +458,7 @@ package body Comperr is
-- If parsing was not successful, no Main_Unit is available, so return
-- immediately.
- if Main_Source_File = No_Source_File then
+ if Main_Source_File <= No_Source_File then
return;
end if;
diff --git a/gcc/ada/cstand.adb b/gcc/ada/cstand.adb
index fe480be..e45c054 100644
--- a/gcc/ada/cstand.adb
+++ b/gcc/ada/cstand.adb
@@ -62,15 +62,22 @@ package body CStand is
-----------------------
procedure Build_Float_Type
- (E : Entity_Id;
- Siz : Int;
- Rep : Float_Rep_Kind;
- Digs : Int);
+ (E : Entity_Id;
+ Digs : Int;
+ Rep : Float_Rep_Kind;
+ Siz : Int;
+ Align : Int);
-- Procedure to build standard predefined float base type. The first
- -- parameter is the entity for the type, and the second parameter is the
- -- size in bits. The third parameter indicates the kind of representation
- -- to be used. The fourth parameter is the digits value. Each type
+ -- parameter is the entity for the type. The second parameter is the
+ -- digits value. The third parameter indicates the representation to
+ -- be used for the type. The fourth parameter is the size in bits.
+ -- The fifth parameter is the alignment in storage units. Each type
-- is added to the list of predefined floating point types.
+ --
+ -- Note that both RM_Size and Esize are set to the specified size, i.e.
+ -- we do not set the RM_Size to the precision passed by the back end.
+ -- This is consistent with the semantics of 'Size specified in the RM
+ -- because we cannot pack components of the type tighter than this size.
procedure Build_Signed_Integer_Type (E : Entity_Id; Siz : Nat);
-- Procedure to build standard predefined signed integer subtype. The
@@ -189,10 +196,11 @@ package body CStand is
----------------------
procedure Build_Float_Type
- (E : Entity_Id;
- Siz : Int;
- Rep : Float_Rep_Kind;
- Digs : Int)
+ (E : Entity_Id;
+ Digs : Int;
+ Rep : Float_Rep_Kind;
+ Siz : Int;
+ Align : Int)
is
begin
Set_Type_Definition (Parent (E),
@@ -201,10 +209,10 @@ package body CStand is
Set_Ekind (E, E_Floating_Point_Type);
Set_Etype (E, E);
- Set_Float_Rep (E, Rep);
- Init_Size (E, Siz);
- Set_Elem_Alignment (E);
Init_Digits_Value (E, Digs);
+ Set_Float_Rep (E, Rep);
+ Init_Size (E, Siz);
+ Set_Elem_Alignment (E, Align);
Set_Float_Bounds (E);
Set_Is_Frozen (E);
Set_Is_Public (E);
@@ -295,8 +303,9 @@ package body CStand is
procedure Copy_Float_Type (To : Entity_Id; From : Entity_Id) is
begin
- Build_Float_Type (To, UI_To_Int (Esize (From)), Float_Rep (From),
- UI_To_Int (Digits_Value (From)));
+ Build_Float_Type
+ (To, UI_To_Int (Digits_Value (From)), Float_Rep (From),
+ UI_To_Int (Esize (From)), UI_To_Int (Alignment (From)));
end Copy_Float_Type;
----------------------
@@ -2065,15 +2074,17 @@ package body CStand is
Size : Positive;
Alignment : Natural)
is
+ pragma Unreferenced (Precision);
+ -- See Build_Float_Type for the rationale
+
Ent : constant Entity_Id := New_Standard_Entity;
begin
Set_Defining_Identifier (New_Node (N_Full_Type_Declaration, Stloc), Ent);
Make_Name (Ent, Name);
Set_Scope (Ent, Standard_Standard);
- Build_Float_Type (Ent, Int (Size), Float_Rep, Pos (Digs));
- Set_RM_Size (Ent, UI_From_Int (Int (Precision)));
- Set_Alignment (Ent, UI_From_Int (Int (Alignment / 8)));
+ Build_Float_Type
+ (Ent, Pos (Digs), Float_Rep, Int (Size), Int (Alignment / 8));
if No (Back_End_Float_Types) then
Back_End_Float_Types := New_Elmt_List;
diff --git a/gcc/ada/debug.adb b/gcc/ada/debug.adb
index 77afd4b..442ce08 100644
--- a/gcc/ada/debug.adb
+++ b/gcc/ada/debug.adb
@@ -75,7 +75,7 @@ package body Debug is
-- dI Inhibit internal name numbering in gnatG listing
-- dJ Prepend subprogram name in messages
-- dK Kill all error messages
- -- dL Output trace information on elaboration checking
+ -- dL Ignore external calls from instances for elaboration
-- dM Assume all variables are modified (no current values)
-- dN No file name information in exception messages
-- dO Output immediate error messages
@@ -112,7 +112,7 @@ package body Debug is
-- d.s Strict secondary stack management
-- d.t Disable static allocation of library level dispatch tables
-- d.u Enable Modify_Tree_For_C (update tree for c)
- -- d.v
+ -- d.v Enforce SPARK elaboration rules in SPARK code
-- d.w Do not check for infinite loops
-- d.x No exception handlers
-- d.y Disable implicit pragma Elaborate_All on task bodies
@@ -163,7 +163,7 @@ package body Debug is
-- d.6 Do not avoid declaring unreferenced types in C code
-- d.7
-- d.8
- -- d.9
+ -- d.9 Disable build-in-place for nonlimited types
-- Debug flags for binder (GNATBIND)
@@ -414,10 +414,9 @@ package body Debug is
-- of all error messages. It is used in regression tests where the
-- error messages are target dependent and irrelevant.
- -- dL Output trace information on elaboration checking. This debug
- -- switch causes output to be generated showing each call or
- -- instantiation as it is checked, and the progress of the recursive
- -- trace through elaboration calls at compile time.
+ -- dL The compiler ignores calls in instances and invoke subprograms
+ -- which are external to the instance for the static elaboration
+ -- model. This switch is orthogonal to d.G.
-- dM Assume all variables have been modified, and ignore current value
-- indications. This debug flag disconnects the tracking of constant
@@ -601,6 +600,13 @@ package body Debug is
-- d.u Sets Modify_Tree_For_C mode in which tree is modified to make it
-- easier to generate code using a C compiler.
+ -- d.v This flag enforces the elaboration rules defined in the SPARK
+ -- Reference Manual, chapter 7.7, to all SPARK code within a unit. As
+ -- a result, constructs which violate the rules in chapter 7.7 are no
+ -- longer accepted, even if the implementation is able to statically
+ -- ensure that accepting these constructs does not introduce the
+ -- possibility of failing an elaboration check.
+
-- d.w This flag turns off the scanning of loops to detect possible
-- infinite loops.
@@ -664,7 +670,8 @@ package body Debug is
-- d.G Previously the compiler ignored calls via generic formal parameters
-- when doing the analysis for the static elaboration model. This is
-- now fixed, but we provide this debug flag to revert to the previous
- -- situation of ignoring such calls to aid in transition.
+ -- situation of ignoring such calls to aid in transition. This switch
+ -- is orthogonal to dL.
-- d.H Sets ASIS_GNSA_Mode to True. This signals the front end to suppress
-- the call to gigi in ASIS_Mode.
@@ -820,6 +827,9 @@ package body Debug is
-- referenced by the generated C code. This debug flag restores the
-- output of all the types.
+ -- d.9 Enable build-in-place for function calls returning some nonlimited
+ -- types.
+
------------------------------------------
-- Documentation for Binder Debug Flags --
------------------------------------------
diff --git a/gcc/ada/doc/gnat_rm/implementation_defined_aspects.rst b/gcc/ada/doc/gnat_rm/implementation_defined_aspects.rst
index be7338f..c601822 100644
--- a/gcc/ada/doc/gnat_rm/implementation_defined_aspects.rst
+++ b/gcc/ada/doc/gnat_rm/implementation_defined_aspects.rst
@@ -302,11 +302,15 @@ Aspect Iterable
This aspect provides a light-weight mechanism for loops and quantified
expressions over container types, without the overhead imposed by the tampering
checks of standard Ada 2012 iterators. The value of the aspect is an aggregate
-with four named components: ``First``, ``Next``, ``Has_Element``, and ``Element`` (the
-last one being optional). When only 3 components are specified, only the
-``for .. in`` form of iteration over cursors is available. When all 4 components
-are specified, both this form and the ``for .. of`` form of iteration over
-elements are available. The following is a typical example of use:
+with six named components, or which the last three are optional: ``First``,
+ ``Next``, ``Has_Element``,``Element``, ``Last``, and ``Previous``.
+When only the first three components are specified, only the
+``for .. in`` form of iteration over cursors is available. When ``Element``
+is specified, both this form and the ``for .. of`` form of iteration over
+elements are available. If the last two components are specified, reverse
+iterations over the container can be specified (analogous to what can be done
+over predefined containers that support the Reverse_Iterator interface).
+The following is a typical example of use:
.. code-block:: ada
diff --git a/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst b/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst
index 3053013..1281758 100644
--- a/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst
+++ b/gcc/ada/doc/gnat_rm/implementation_defined_pragmas.rst
@@ -4120,6 +4120,9 @@ Specifying SPACE also disables alignment promotions for standalone objects,
which occur when the compiler increases the alignment of a specific object
without changing the alignment of its type.
+Specifying SPACE also disables component reordering in unpacked record types,
+which can result in larger sizes in order to meet alignment requirements.
+
Specifying TIME causes larger default alignments to be chosen in the case of
small types with sizes that are not a power of 2. For example, consider:
diff --git a/gcc/ada/doc/gnat_rm/representation_clauses_and_pragmas.rst b/gcc/ada/doc/gnat_rm/representation_clauses_and_pragmas.rst
index 8ff5224..5ad8e03 100644
--- a/gcc/ada/doc/gnat_rm/representation_clauses_and_pragmas.rst
+++ b/gcc/ada/doc/gnat_rm/representation_clauses_and_pragmas.rst
@@ -64,7 +64,7 @@ values are as follows:
* *Records*.
- For the normal non-packed case, the alignment of a record is equal to
+ For the normal unpacked case, the alignment of a record is equal to
the maximum alignment of any of its components. For tagged records, this
includes the implicit access type used for the tag. If a pragma ``Pack``
is used and all components are packable (see separate section on pragma
diff --git a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst
index ec152f2..b6447d0 100644
--- a/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst
+++ b/gcc/ada/doc/gnat_ugn/building_executable_programs_with_gnat.rst
@@ -559,7 +559,7 @@ You may specify any of the following switches to ``gnatmake``:
-f, it is equivalent to calling the compiler directly. Note that using
-u with a project file and no main has a special meaning.
-.. --Comment:
+.. --Comment
(See :ref:`Project_Files_and_Main_Subprograms`.)
@@ -1243,21 +1243,13 @@ Alphabetical List of All Switches
:file:`scos.adb`.
-.. index:: -fdump-xref (gcc)
-
-:switch:`-fdump-xref`
- Generates cross reference information in GLI files for C and C++ sources.
- The GLI files have the same syntax as the ALI files for Ada, and can be used
- for source navigation in IDEs and on the command line using e.g. gnatxref
- and the :switch:`--ext=gli` switch.
-
-
.. index:: -flto (gcc)
:switch:`-flto[={n}]`
Enables Link Time Optimization. This switch must be used in conjunction
- with the traditional :switch:`-Ox` switches and instructs the compiler to
- defer most optimizations until the link stage. The advantage of this
+ with the :switch:`-Ox` switches (but not with the :switch:`-gnatn` switch
+ since it is a full replacement for the latter) and instructs the compiler
+ to defer most optimizations until the link stage. The advantage of this
approach is that the compiler can do a whole-program analysis and choose
the best interprocedural optimization strategy based on a complete view
of the program, instead of a fragmentary view with the usual approach.
@@ -3898,8 +3890,8 @@ of the pragma in the :title:`GNAT_Reference_manual`).
This switch activates warnings for exception usage when pragma Restrictions
(No_Exception_Propagation) is in effect. Warnings are given for implicit or
explicit exception raises which are not covered by a local handler, and for
- exception handlers which do not cover a local raise. The default is that these
- warnings are not given.
+ exception handlers which do not cover a local raise. The default is that
+ these warnings are given for units that contain exception handlers.
:switch:`-gnatw.X`
diff --git a/gcc/ada/doc/gnat_ugn/elaboration_order_handling_in_gnat.rst b/gcc/ada/doc/gnat_ugn/elaboration_order_handling_in_gnat.rst
index 688dd99..c45d3fc 100644
--- a/gcc/ada/doc/gnat_ugn/elaboration_order_handling_in_gnat.rst
+++ b/gcc/ada/doc/gnat_ugn/elaboration_order_handling_in_gnat.rst
@@ -17,1855 +17,1806 @@ Elaboration Order Handling in GNAT
.. index:: Order of elaboration
.. index:: Elaboration control
-This appendix describes the handling of elaboration code in Ada and
-in GNAT, and discusses how the order of elaboration of program units can
-be controlled in GNAT, either automatically or with explicit programming
-features.
+This appendix describes the handling of elaboration code in Ada and GNAT, and
+discusses how the order of elaboration of program units can be controlled in
+GNAT, either automatically or with explicit programming features.
.. _Elaboration_Code:
Elaboration Code
================
-Ada provides rather general mechanisms for executing code at elaboration
-time, that is to say before the main program starts executing. Such code arises
-in three contexts:
+Ada defines the term *execution* as the process by which a construct achieves
+its run-time effect. This process is also referred to as **elaboration** for
+declarations and *evaluation* for expressions.
-* *Initializers for variables*
+The execution model in Ada allows for certain sections of an Ada program to be
+executed prior to execution of the program itself, primarily with the intent of
+initializing data. These sections are referred to as **elaboration code**.
+Elaboration code is executed as follows:
- Variables declared at the library level, in package specs or bodies, can
- require initialization that is performed at elaboration time, as in:
+* All partitions of an Ada program are executed in parallel with one another,
+ possibly in a separate address space, and possibly on a separate computer.
- .. code-block:: ada
+* The execution of a partition involves running the environment task for that
+ partition.
- Sqrt_Half : Float := Sqrt (0.5);
+* The environment task executes all elaboration code (if available) for all
+ units within that partition. This code is said to be executed at
+ **elaboration time**.
-* *Package initialization code*
+* The environment task executes the Ada program (if available) for that
+ partition.
- Code in a ``begin`` ... `` end`` section at the outer level of a package body is
- executed as part of the package body elaboration code.
+In addition to the Ada terminology, this appendix defines the following terms:
-* *Library level task allocators*
+* *Scenario*
- Tasks that are declared using task allocators at the library level
- start executing immediately and hence can execute at elaboration time.
+ A construct that is elaborated or executed by elaboration code is referred to
+ as an *elaboration scenario* or simply a **scenario**. GNAT recognizes the
+ following scenarios:
-Subprogram calls are possible in any of these contexts, which means that
-any arbitrary part of the program may be executed as part of the elaboration
-code. It is even possible to write a program which does all its work at
-elaboration time, with a null main program, although stylistically this
-would usually be considered an inappropriate way to structure
-a program.
+ - ``'Access`` of entries, operators, and subprograms
-An important concern arises in the context of elaboration code:
-we have to be sure that it is executed in an appropriate order. What we
-have is a series of elaboration code sections, potentially one section
-for each unit in the program. It is important that these execute
-in the correct order. Correctness here means that, taking the above
-example of the declaration of ``Sqrt_Half``,
-if some other piece of
-elaboration code references ``Sqrt_Half``,
-then it must run after the
-section of elaboration code that contains the declaration of
-``Sqrt_Half``.
+ - Activation of tasks
-There would never be any order of elaboration problem if we made a rule
-that whenever you |with| a unit, you must elaborate both the spec and body
-of that unit before elaborating the unit doing the |withing|:
+ - Calls to entries, operators, and subprograms
-.. code-block:: ada
+ - Instantiations of generic templates
- with Unit_1;
- package Unit_2 is ...
+* *Target*
-would require that both the body and spec of ``Unit_1`` be elaborated
-before the spec of ``Unit_2``. However, a rule like that would be far too
-restrictive. In particular, it would make it impossible to have routines
-in separate packages that were mutually recursive.
+ A construct elaborated by a scenario is referred to as *elaboration target*
+ or simply **target**. GNAT recognizes the following targets:
-You might think that a clever enough compiler could look at the actual
-elaboration code and determine an appropriate correct order of elaboration,
-but in the general case, this is not possible. Consider the following
-example.
+ - For ``'Access`` of entries, operators, and subprograms, the target is the
+ entry, operator, or subprogram being aliased.
-In the body of ``Unit_1``, we have a procedure ``Func_1``
-that references
-the variable ``Sqrt_1``, which is declared in the elaboration code
-of the body of ``Unit_1``:
+ - For activation of tasks, the target is the task body
-.. code-block:: ada
+ - For calls to entries, operators, and subprograms, the target is the entry,
+ operator, or subprogram being invoked.
- Sqrt_1 : Float := Sqrt (0.1);
+ - For instantiations of generic templates, the target is the generic template
+ being instantiated.
-The elaboration code of the body of ``Unit_1`` also contains:
+Elaboration code may appear in two distinct contexts:
-.. code-block:: ada
+* *Library level*
- if expression_1 = 1 then
- Q := Unit_2.Func_2;
- end if;
+ A scenario appears at the library level when it is encapsulated by a package
+ [body] compilation unit, ignoring any other package [body] declarations in
+ between.
-``Unit_2`` is exactly parallel,
-it has a procedure ``Func_2`` that references
-the variable ``Sqrt_2``, which is declared in the elaboration code of
-the body ``Unit_2``:
+ ::
-.. code-block:: ada
+ with Server;
+ package Client is
+ procedure Proc;
- Sqrt_2 : Float := Sqrt (0.1);
+ package Nested is
+ Val : ... := Server.Func;
+ end Nested;
+ end Client;
-The elaboration code of the body of ``Unit_2`` also contains:
+ In the example above, the call to ``Server.Func`` is an elaboration scenario
+ because it appears at the library level of package ``Client``. Note that the
+ declaration of package ``Nested`` is ignored according to the definition
+ given above. As a result, the call to ``Server.Func`` will be executed when
+ the spec of unit ``Client`` is elaborated.
-.. code-block:: ada
+* *Package body statements*
- if expression_2 = 2 then
- Q := Unit_1.Func_1;
- end if;
+ A scenario appears within the statement sequence of a package body when it is
+ bounded by the region starting from the ``begin`` keyword of the package body
+ and ending at the ``end`` keyword of the package body.
-Now the question is, which of the following orders of elaboration is
-acceptable:
+ ::
+
+ package body Client is
+ procedure Proc is
+ begin
+ ...
+ end Proc;
+ begin
+ Proc;
+ end Client;
+
+ In the example above, the call to ``Proc`` is an elaboration scenario because
+ it appears within the statement sequence of package body ``Client``. As a
+ result, the call to ``Proc`` will be executed when the body of ``Client`` is
+ elaborated.
+
+.. _Elaboration_Order:
+
+Elaboration Order
+=================
+
+The sequence by which the elaboration code of all units within a partition is
+executed is referred to as **elaboration order**.
+
+Within a single unit, elaboration code is executed in sequential order.
+
+::
+
+ package body Client is
+ Result : ... := Server.Func;
+
+ procedure Proc is
+ package Inst is new Server.Gen;
+ begin
+ Inst.Eval (Result);
+ end Proc;
+ begin
+ Proc;
+ end Client;
+
+In the example above, the elaboration order within package body ``Client`` is
+as follows:
+
+1. The object declaration of ``Result`` is elaborated.
+
+ * Function ``Server.Func`` is invoked.
+
+2. The subprogram body of ``Proc`` is elaborated.
+
+3. Procedure ``Proc`` is invoked.
+
+ * Generic unit ``Server.Gen`` is instantiated as ``Inst``.
+
+ * Instance ``Inst`` is elaborated.
+
+ * Procedure ``Inst.Eval`` is invoked.
+
+The elaboration order of all units within a partition depends on the following
+factors:
+
+* |withed| units
+
+* purity of units
+
+* preelaborability of units
+
+* presence of elaboration control pragmas
+
+A program may have several elaboration orders depending on its structure.
+
+::
+
+ package Server is
+ function Func (Index : Integer) return Integer;
+ end Server;
::
- Spec of Unit_1
- Spec of Unit_2
- Body of Unit_1
- Body of Unit_2
+ package body Server is
+ Results : array (1 .. 5) of Integer := (1, 2, 3, 4, 5);
+
+ function Func (Index : Integer) return Integer is
+ begin
+ return Results (Index);
+ end Func;
+ end Server;
+
+::
-or
+ with Server;
+ package Client is
+ Val : constant Integer := Server.Func (3);
+ end Client;
::
- Spec of Unit_2
- Spec of Unit_1
- Body of Unit_2
- Body of Unit_1
-
-If you carefully analyze the flow here, you will see that you cannot tell
-at compile time the answer to this question.
-If ``expression_1`` is not equal to 1,
-and ``expression_2`` is not equal to 2,
-then either order is acceptable, because neither of the function calls is
-executed. If both tests evaluate to true, then neither order is acceptable
-and in fact there is no correct order.
-
-If one of the two expressions is true, and the other is false, then one
-of the above orders is correct, and the other is incorrect. For example,
-if ``expression_1`` /= 1 and ``expression_2`` = 2,
-then the call to ``Func_1``
-will occur, but not the call to ``Func_2.``
-This means that it is essential
-to elaborate the body of ``Unit_1`` before
-the body of ``Unit_2``, so the first
-order of elaboration is correct and the second is wrong.
-
-By making ``expression_1`` and ``expression_2``
-depend on input data, or perhaps
-the time of day, we can make it impossible for the compiler or binder
-to figure out which of these expressions will be true, and hence it
-is impossible to guarantee a safe order of elaboration at run time.
+ with Client;
+ procedure Main is begin null; end Main;
+
+The following elaboration order exhibits a fundamental problem referred to as
+*access-before-elaboration* or simply **ABE**.
+
+::
+
+ spec of Server
+ spec of Client
+ body of Server
+ body of Main
+
+The elaboration of ``Server``'s spec materializes function ``Func``, making it
+callable. The elaboration of ``Client``'s spec elaborates the declaration of
+``Val``. This invokes function ``Server.Func``, however the body of
+``Server.Func`` has not been elaborated yet because ``Server``'s body comes
+after ``Client``'s spec in the elaboration order. As a result, the value of
+constant ``Val`` is now undefined.
+
+Without any guarantees from the language, an undetected ABE problem may hinder
+proper initialization of data, which in turn may lead to undefined behavior at
+run time. To prevent such ABE problems, Ada employs dynamic checks in the same
+vein as index or null exclusion checks. A failed ABE check raises exception
+``Program_Error``.
+
+The following elaboration order avoids the ABE problem and the program can be
+successfully elaborated.
+
+::
+
+ spec of Server
+ body of Server
+ spec of Client
+ body of Main
+
+Ada states that a total elaboration order must exist, but it does not define
+what this order is. A compiler is thus tasked with choosing a suitable
+elaboration order which satisfies the dependencies imposed by |with| clauses,
+unit categorization, and elaboration control pragmas. Ideally an order which
+avoids ABE problems should be chosen, however a compiler may not always find
+such an order due to complications with respect to control and data flow.
.. _Checking_the_Elaboration_Order:
Checking the Elaboration Order
==============================
-In some languages that involve the same kind of elaboration problems,
-e.g., Java and C++, the programmer needs to take these
-ordering problems into account, and it is common to
-write a program in which an incorrect elaboration order gives
-surprising results, because it references variables before they
-are initialized.
-Ada is designed to be a safe language, and a programmer-beware approach is
-clearly not sufficient. Consequently, the language provides three lines
-of defense:
+To avoid placing the entire elaboration order burden on the programmer, Ada
+provides three lines of defense:
+
+* *Static semantics*
-* *Standard rules*
+ Static semantic rules restrict the possible choice of elaboration order. For
+ instance, if unit Client |withs| unit Server, then the spec of Server is
+ always elaborated prior to Client. The same principle applies to child units
+ - the spec of a parent unit is always elaborated prior to the child unit.
- Some standard rules restrict the possible choice of elaboration
- order. In particular, if you |with| a unit, then its spec is always
- elaborated before the unit doing the |with|. Similarly, a parent
- spec is always elaborated before the child spec, and finally
- a spec is always elaborated before its corresponding body.
+* *Dynamic semantics*
-.. index:: Elaboration checks
-.. index:: Checks, elaboration
+ Dynamic checks are performed at run time, to ensure that a target is
+ elaborated prior to a scenario that executes it, thus avoiding ABE problems.
+ A failed run-time check raises exception ``Program_Error``. The following
+ restrictions apply:
-* *Dynamic elaboration checks*
+ - *Restrictions on calls*
- Dynamic checks are made at run time, so that if some entity is accessed
- before it is elaborated (typically by means of a subprogram call)
- then the exception (``Program_Error``) is raised.
+ An entry, operator, or subprogram can be called from elaboration code only
+ when the corresponding body has been elaborated.
+
+ - *Restrictions on instantiations*
+
+ A generic unit can be instantiated by elaboration code only when the
+ corresponding body has been elaborated.
+
+ - *Restrictions on task activation*
+
+ A task can be activated by elaboration code only when the body of the
+ associated task type has been elaborated.
+
+ The restrictions above can be summarized by the following rule:
+
+ *If a target has a body, then this body must be elaborated prior to the
+ execution of the scenario that invokes, instantiates, or activates the
+ target.*
* *Elaboration control*
- Facilities are provided for the programmer to specify the desired order
- of elaboration.
-
-Let's look at these facilities in more detail. First, the rules for
-dynamic checking. One possible rule would be simply to say that the
-exception is raised if you access a variable which has not yet been
-elaborated. The trouble with this approach is that it could require
-expensive checks on every variable reference. Instead Ada has two
-rules which are a little more restrictive, but easier to check, and
-easier to state:
-
-* *Restrictions on calls*
-
- A subprogram can only be called at elaboration time if its body
- has been elaborated. The rules for elaboration given above guarantee
- that the spec of the subprogram has been elaborated before the
- call, but not the body. If this rule is violated, then the
- exception ``Program_Error`` is raised.
-
-* *Restrictions on instantiations*
-
- A generic unit can only be instantiated if the body of the generic
- unit has been elaborated. Again, the rules for elaboration given above
- guarantee that the spec of the generic unit has been elaborated
- before the instantiation, but not the body. If this rule is
- violated, then the exception ``Program_Error`` is raised.
-
-The idea is that if the body has been elaborated, then any variables
-it references must have been elaborated; by checking for the body being
-elaborated we guarantee that none of its references causes any
-trouble. As we noted above, this is a little too restrictive, because a
-subprogram that has no non-local references in its body may in fact be safe
-to call. However, it really would be unsafe to rely on this, because
-it would mean that the caller was aware of details of the implementation
-in the body. This goes against the basic tenets of Ada.
-
-A plausible implementation can be described as follows.
-A Boolean variable is associated with each subprogram
-and each generic unit. This variable is initialized to False, and is set to
-True at the point body is elaborated. Every call or instantiation checks the
-variable, and raises ``Program_Error`` if the variable is False.
-
-Note that one might think that it would be good enough to have one Boolean
-variable for each package, but that would not deal with cases of trying
-to call a body in the same package as the call
-that has not been elaborated yet.
-Of course a compiler may be able to do enough analysis to optimize away
-some of the Boolean variables as unnecessary, and GNAT indeed
-does such optimizations, but still the easiest conceptual model is to
-think of there being one variable per subprogram.
-
-.. _Controlling_the_Elaboration_Order:
-
-Controlling the Elaboration Order
-=================================
+ Pragmas are provided for the programmer to specify the desired elaboration
+ order.
-In the previous section we discussed the rules in Ada which ensure
-that ``Program_Error`` is raised if an incorrect elaboration order is
-chosen. This prevents erroneous executions, but we need mechanisms to
-specify a correct execution and avoid the exception altogether.
-To achieve this, Ada provides a number of features for controlling
-the order of elaboration. We discuss these features in this section.
+.. _Controlling_the_Elaboration_Order_in_Ada:
-First, there are several ways of indicating to the compiler that a given
-unit has no elaboration problems:
+Controlling the Elaboration Order in Ada
+========================================
-* *packages that do not require a body*
+Ada provides several idioms and pragmas to aid the programmer with specifying
+the desired elaboration order and avoiding ABE problems altogether.
- A library package that does not require a body does not permit
- a body (this rule was introduced in Ada 95).
- Thus if we have a such a package, as in:
+* *Packages without a body*
- .. code-block:: ada
+ A library package which does not require a completing body does not suffer
+ from ABE problems.
- package Definitions is
- generic
- type m is new integer;
- package Subp is
- type a is array (1 .. 10) of m;
- type b is array (1 .. 20) of m;
- end Subp;
- end Definitions;
+ ::
- A package that |withs| ``Definitions`` may safely instantiate
- ``Definitions.Subp`` because the compiler can determine that there
- definitely is no package body to worry about in this case
+ package Pack is
+ generic
+ type Element is private;
+ package Containers is
+ type Element_Array is array (1 .. 10) of Element;
+ end Containers;
+ end Pack;
+
+ In the example above, package ``Pack`` does not require a body because it
+ does not contain any constructs which require completion in a body. As a
+ result, generic ``Pack.Containers`` can be instantiated without encountering
+ any ABE problems.
.. index:: pragma Pure
* *pragma Pure*
- This pragma places sufficient restrictions on a unit to guarantee that
- no call to any subprogram in the unit can result in an
- elaboration problem. This means that the compiler does not need
- to worry about the point of elaboration of such units, and in
- particular, does not need to check any calls to any subprograms
- in this unit.
+ Pragma ``Pure`` places sufficient restrictions on a unit to guarantee that no
+ scenario within the unit can result in an ABE problem.
.. index:: pragma Preelaborate
* *pragma Preelaborate*
- This pragma places slightly less stringent restrictions on a unit than
- does pragma Pure,
- but these restrictions are still sufficient to ensure that there
- are no elaboration problems with any calls to the unit.
+ Pragma ``Preelaborate`` is slightly less restrictive than pragma ``Pure``,
+ but still strong enough to prevent ABE problems within a unit.
.. index:: pragma Elaborate_Body
* *pragma Elaborate_Body*
- This pragma requires that the body of a unit be elaborated immediately
- after its spec. Suppose a unit ``A`` has such a pragma,
- and unit ``B`` does
- a |with| of unit ``A``. Recall that the standard rules require
- the spec of unit ``A``
- to be elaborated before the |withing| unit; given the pragma in
- ``A``, we also know that the body of ``A``
- will be elaborated before ``B``, so
- that calls to ``A`` are safe and do not need a check.
-
- Note that, unlike pragma ``Pure`` and pragma ``Preelaborate``,
- the use of ``Elaborate_Body`` does not guarantee that the program is
- free of elaboration problems, because it may not be possible
- to satisfy the requested elaboration order.
- Let's go back to the example with ``Unit_1`` and ``Unit_2``.
- If a programmer marks ``Unit_1`` as ``Elaborate_Body``,
- and not ``Unit_2,`` then the order of
- elaboration will be::
-
- Spec of Unit_2
- Spec of Unit_1
- Body of Unit_1
- Body of Unit_2
-
- Now that means that the call to ``Func_1`` in ``Unit_2``
- need not be checked,
- it must be safe. But the call to ``Func_2`` in
- ``Unit_1`` may still fail if
- ``Expression_1`` is equal to 1,
- and the programmer must still take
- responsibility for this not being the case.
-
- If all units carry a pragma ``Elaborate_Body``, then all problems are
- eliminated, except for calls entirely within a body, which are
- in any case fully under programmer control. However, using the pragma
- everywhere is not always possible.
- In particular, for our ``Unit_1``/`Unit_2` example, if
- we marked both of them as having pragma ``Elaborate_Body``, then
- clearly there would be no possible elaboration order.
-
-The above pragmas allow a server to guarantee safe use by clients, and
-clearly this is the preferable approach. Consequently a good rule
-is to mark units as ``Pure`` or ``Preelaborate`` if possible,
-and if this is not possible,
-mark them as ``Elaborate_Body`` if possible.
-As we have seen, there are situations where neither of these
-three pragmas can be used.
-So we also provide methods for clients to control the
-order of elaboration of the servers on which they depend:
-
-.. index:: pragma Elaborate
-
-* *pragma Elaborate (unit)*
-
- This pragma is placed in the context clause, after a |with| clause,
- and it requires that the body of the named unit be elaborated before
- the unit in which the pragma occurs. The idea is to use this pragma
- if the current unit calls at elaboration time, directly or indirectly,
- some subprogram in the named unit.
-
-
-.. index:: pragma Elaborate_All
-
-* *pragma Elaborate_All (unit)*
-
- This is a stronger version of the Elaborate pragma. Consider the
- following example::
-
- Unit A |withs| unit B and calls B.Func in elab code
- Unit B |withs| unit C, and B.Func calls C.Func
-
-
- Now if we put a pragma ``Elaborate (B)``
- in unit ``A``, this ensures that the
- body of ``B`` is elaborated before the call, but not the
- body of ``C``, so
- the call to ``C.Func`` could still cause ``Program_Error`` to
- be raised.
-
- The effect of a pragma ``Elaborate_All`` is stronger, it requires
- not only that the body of the named unit be elaborated before the
- unit doing the |with|, but also the bodies of all units that the
- named unit uses, following |with| links transitively. For example,
- if we put a pragma ``Elaborate_All (B)`` in unit ``A``,
- then it requires not only that the body of ``B`` be elaborated before ``A``,
- but also the body of ``C``, because ``B`` |withs| ``C``.
-
-We are now in a position to give a usage rule in Ada for avoiding
-elaboration problems, at least if dynamic dispatching and access to
-subprogram values are not used. We will handle these cases separately
-later.
-
-The rule is simple:
-
-*If a unit has elaboration code that can directly or
-indirectly make a call to a subprogram in a |withed| unit, or instantiate
-a generic package in a |withed| unit,
-then if the |withed| unit does not have
-pragma ``Pure`` or ``Preelaborate``, then the client should have
-a pragma ``Elaborate_All``for the |withed| unit.**
-
-By following this rule a client is
-assured that calls can be made without risk of an exception.
-
-For generic subprogram instantiations, the rule can be relaxed to
-require only a pragma ``Elaborate`` since elaborating the body
-of a subprogram cannot cause any transitive elaboration (we are
-not calling the subprogram in this case, just elaborating its
-declaration).
-
-If this rule is not followed, then a program may be in one of four
-states:
-
-* *No order exists*
-
- No order of elaboration exists which follows the rules, taking into
- account any ``Elaborate``, ``Elaborate_All``,
- or ``Elaborate_Body`` pragmas. In
- this case, an Ada compiler must diagnose the situation at bind
- time, and refuse to build an executable program.
-
-* *One or more orders exist, all incorrect*
+ Pragma ``Elaborate_Body`` requires that the body of a unit is elaborated
+ immediately after its spec. This restriction guarantees that no client
+ scenario can execute a server target before the target body has been
+ elaborated because the spec and body are effectively "glued" together.
- One or more acceptable elaboration orders exist, and all of them
- generate an elaboration order problem. In this case, the binder
- can build an executable program, but ``Program_Error`` will be raised
- when the program is run.
+ ::
-* *Several orders exist, some right, some incorrect*
+ package Server is
+ pragma Elaborate_Body;
- One or more acceptable elaboration orders exists, and some of them
- work, and some do not. The programmer has not controlled
- the order of elaboration, so the binder may or may not pick one of
- the correct orders, and the program may or may not raise an
- exception when it is run. This is the worst case, because it means
- that the program may fail when moved to another compiler, or even
- another version of the same compiler.
+ function Func return Integer;
+ end Server;
-* *One or more orders exists, all correct*
+ ::
- One ore more acceptable elaboration orders exist, and all of them
- work. In this case the program runs successfully. This state of
- affairs can be guaranteed by following the rule we gave above, but
- may be true even if the rule is not followed.
+ package body Server is
+ function Func return Integer is
+ begin
+ ...
+ end Func;
+ end Server;
-Note that one additional advantage of following our rules on the use
-of ``Elaborate`` and ``Elaborate_All``
-is that the program continues to stay in the ideal (all orders OK) state
-even if maintenance
-changes some bodies of some units. Conversely, if a program that does
-not follow this rule happens to be safe at some point, this state of affairs
-may deteriorate silently as a result of maintenance changes.
+ ::
-You may have noticed that the above discussion did not mention
-the use of ``Elaborate_Body``. This was a deliberate omission. If you
-|with| an ``Elaborate_Body`` unit, it still may be the case that
-code in the body makes calls to some other unit, so it is still necessary
-to use ``Elaborate_All`` on such units.
+ with Server;
+ package Client is
+ Val : constant Integer := Server.Func;
+ end Client;
+ In the example above, pragma ``Elaborate_Body`` guarantees the following
+ elaboration order:
-.. _Controlling_Elaboration_in_GNAT_-_Internal_Calls:
+ ::
-Controlling Elaboration in GNAT - Internal Calls
-================================================
+ spec of Server
+ body of Server
+ spec of Client
-In the case of internal calls, i.e., calls within a single package, the
-programmer has full control over the order of elaboration, and it is up
-to the programmer to elaborate declarations in an appropriate order. For
-example writing:
+ because the spec of ``Server`` must be elaborated prior to ``Client`` by
+ virtue of the |with| clause, and in addition the body of ``Server`` must be
+ elaborated immediately after the spec of ``Server``.
-.. code-block:: ada
+ Removing pragma ``Elaborate_Body`` could result in the following incorrect
+ elaboration order:
- function One return Float;
-
- Q : Float := One;
+ ::
- function One return Float is
- begin
- return 1.0;
- end One;
-
-will obviously raise ``Program_Error`` at run time, because function
-One will be called before its body is elaborated. In this case GNAT will
-generate a warning that the call will raise ``Program_Error``::
-
- 1. procedure y is
- 2. function One return Float;
- 3.
- 4. Q : Float := One;
- |
- >>> warning: cannot call "One" before body is elaborated
- >>> warning: Program_Error will be raised at run time
-
- 5.
- 6. function One return Float is
- 7. begin
- 8. return 1.0;
- 9. end One;
- 10.
- 11. begin
- 12. null;
- 13. end;
-
-
-Note that in this particular case, it is likely that the call is safe, because
-the function ``One`` does not access any global variables.
-Nevertheless in Ada, we do not want the validity of the check to depend on
-the contents of the body (think about the separate compilation case), so this
-is still wrong, as we discussed in the previous sections.
-
-The error is easily corrected by rearranging the declarations so that the
-body of ``One`` appears before the declaration containing the call
-(note that in Ada 95 as well as later versions of the Ada standard,
-declarations can appear in any order, so there is no restriction that
-would prevent this reordering, and if we write:
-
-.. code-block:: ada
-
- function One return Float;
-
- function One return Float is
- begin
- return 1.0;
- end One;
-
- Q : Float := One;
-
-then all is well, no warning is generated, and no
-``Program_Error`` exception
-will be raised.
-Things are more complicated when a chain of subprograms is executed:
-
-.. code-block:: ada
-
- function A return Integer;
- function B return Integer;
- function C return Integer;
-
- function B return Integer is begin return A; end;
- function C return Integer is begin return B; end;
-
- X : Integer := C;
-
- function A return Integer is begin return 1; end;
-
-Now the call to ``C``
-at elaboration time in the declaration of ``X`` is correct, because
-the body of ``C`` is already elaborated,
-and the call to ``B`` within the body of
-``C`` is correct, but the call
-to ``A`` within the body of ``B`` is incorrect, because the body
-of ``A`` has not been elaborated, so ``Program_Error``
-will be raised on the call to ``A``.
-In this case GNAT will generate a
-warning that ``Program_Error`` may be
-raised at the point of the call. Let's look at the warning::
-
- 1. procedure x is
- 2. function A return Integer;
- 3. function B return Integer;
- 4. function C return Integer;
- 5.
- 6. function B return Integer is begin return A; end;
- |
- >>> warning: call to "A" before body is elaborated may
- raise Program_Error
- >>> warning: "B" called at line 7
- >>> warning: "C" called at line 9
-
- 7. function C return Integer is begin return B; end;
- 8.
- 9. X : Integer := C;
- 10.
- 11. function A return Integer is begin return 1; end;
- 12.
- 13. begin
- 14. null;
- 15. end;
-
-
-Note that the message here says 'may raise', instead of the direct case,
-where the message says 'will be raised'. That's because whether
-``A`` is
-actually called depends in general on run-time flow of control.
-For example, if the body of ``B`` said
-
-.. code-block:: ada
-
- function B return Integer is
- begin
- if some-condition-depending-on-input-data then
- return A;
- else
- return 1;
- end if;
- end B;
-
-then we could not know until run time whether the incorrect call to A would
-actually occur, so ``Program_Error`` might
-or might not be raised. It is possible for a compiler to
-do a better job of analyzing bodies, to
-determine whether or not ``Program_Error``
-might be raised, but it certainly
-couldn't do a perfect job (that would require solving the halting problem
-and is provably impossible), and because this is a warning anyway, it does
-not seem worth the effort to do the analysis. Cases in which it
-would be relevant are rare.
-
-In practice, warnings of either of the forms given
-above will usually correspond to
-real errors, and should be examined carefully and eliminated.
-In the rare case where a warning is bogus, it can be suppressed by any of
-the following methods:
-
-* Compile with the :switch:`-gnatws` switch set
-
-* Suppress ``Elaboration_Check`` for the called subprogram
-
-* Use pragma ``Warnings_Off`` to turn warnings off for the call
-
-For the internal elaboration check case,
-GNAT by default generates the
-necessary run-time checks to ensure
-that ``Program_Error`` is raised if any
-call fails an elaboration check. Of course this can only happen if a
-warning has been issued as described above. The use of pragma
-``Suppress (Elaboration_Check)`` may (but is not guaranteed to) suppress
-some of these checks, meaning that it may be possible (but is not
-guaranteed) for a program to be able to call a subprogram whose body
-is not yet elaborated, without raising a ``Program_Error`` exception.
-
-
-.. _Controlling_Elaboration_in_GNAT_-_External_Calls:
-
-Controlling Elaboration in GNAT - External Calls
-================================================
-
-The previous section discussed the case in which the execution of a
-particular thread of elaboration code occurred entirely within a
-single unit. This is the easy case to handle, because a programmer
-has direct and total control over the order of elaboration, and
-furthermore, checks need only be generated in cases which are rare
-and which the compiler can easily detect.
-The situation is more complex when separate compilation is taken into account.
-Consider the following:
-
-.. code-block:: ada
-
- package Math is
- function Sqrt (Arg : Float) return Float;
- end Math;
-
- package body Math is
- function Sqrt (Arg : Float) return Float is
- begin
- ...
- end Sqrt;
- end Math;
-
- with Math;
- package Stuff is
- X : Float := Math.Sqrt (0.5);
- end Stuff;
-
- with Stuff;
- procedure Main is
- begin
- ...
- end Main;
-
-where ``Main`` is the main program. When this program is executed, the
-elaboration code must first be executed, and one of the jobs of the
-binder is to determine the order in which the units of a program are
-to be elaborated. In this case we have four units: the spec and body
-of ``Math``,
-the spec of ``Stuff`` and the body of ``Main``).
-In what order should the four separate sections of elaboration code
-be executed?
-
-There are some restrictions in the order of elaboration that the binder
-can choose. In particular, if unit U has a |with|
-for a package ``X``, then you
-are assured that the spec of ``X``
-is elaborated before U , but you are
-not assured that the body of ``X``
-is elaborated before U.
-This means that in the above case, the binder is allowed to choose the
-order::
+ spec of Server
+ spec of Client
+ body of Server
+
+ where ``Client`` invokes ``Server.Func``, but the body of ``Server.Func`` has
+ not been elaborated yet.
+
+The pragmas outlined above allow a server unit to guarantee safe elaboration
+use by client units. Thus it is a good rule to mark units as ``Pure`` or
+``Preelaborate``, and if this is not possible, mark them as ``Elaborate_Body``.
+
+There are however situations where ``Pure``, ``Preelaborate``, and
+``Elaborate_Body`` are not applicable. Ada provides another set of pragmas for
+use by client units to help ensure the elaboration safety of server units they
+depend on.
+
+.. index:: pragma Elaborate (Unit)
+
+* *pragma Elaborate (Unit)*
+
+ Pragma ``Elaborate`` can be placed in the context clauses of a unit, after a
+ |with| clause. It guarantees that both the spec and body of its argument will
+ be elaborated prior to the unit with the pragma. Note that other unrelated
+ units may be elaborated in between the spec and the body.
+
+ ::
+
+ package Server is
+ function Func return Integer;
+ end Server;
+
+ ::
+
+ package body Server is
+ function Func return Integer is
+ begin
+ ...
+ end Func;
+ end Server;
+
+ ::
+
+ with Server;
+ pragma Elaborate (Server);
+ package Client is
+ Val : constant Integer := Server.Func;
+ end Client;
+
+ In the example above, pragma ``Elaborate`` guarantees the following
+ elaboration order:
+
+ ::
+
+ spec of Server
+ body of Server
+ spec of Client
+
+ Removing pragma ``Elaborate`` could result in the following incorrect
+ elaboration order:
+
+ ::
+
+ spec of Server
+ spec of Client
+ body of Server
+
+ where ``Client`` invokes ``Server.Func``, but the body of ``Server.Func``
+ has not been elaborated yet.
+
+.. index:: pragma Elaborate_All (Unit)
+
+* *pragma Elaborate_All (Unit)*
+
+ Pragma ``Elaborate_All`` is placed in the context clauses of a unit, after
+ a |with| clause. It guarantees that both the spec and body of its argument
+ will be elaborated prior to the unit with the pragma, as well as all units
+ |withed| by the spec and body of the argument, recursively. Note that other
+ unrelated units may be elaborated in between the spec and the body.
+
+ ::
+
+ package Math is
+ function Factorial (Val : Natural) return Natural;
+ end Math;
+
+ ::
+
+ package body Math is
+ function Factorial (Val : Natural) return Natural is
+ begin
+ ...;
+ end Factorial;
+ end Math;
+
+ ::
+
+ package Computer is
+ type Operation_Kind is (None, Op_Factorial);
+
+ function Compute
+ (Val : Natural;
+ Op : Operation_Kind) return Natural;
+ end Computer;
+
+ ::
+
+ with Math;
+ package body Computer is
+ function Compute
+ (Val : Natural;
+ Op : Operation_Kind) return Natural
+ is
+ if Op = Op_Factorial then
+ return Math.Factorial (Val);
+ end if;
+
+ return 0;
+ end Compute;
+ end Computer;
+
+ ::
+
+ with Computer;
+ pragma Elaborate_All (Computer);
+ package Client is
+ Val : constant Natural :=
+ Computer.Compute (123, Computer.Op_Factorial);
+ end Client;
+
+ In the example above, pragma ``Elaborate_All`` can result in the following
+ elaboration order:
+
+ ::
spec of Math
- spec of Stuff
body of Math
- body of Main
-
-but that's not good, because now the call to ``Math.Sqrt``
-that happens during
-the elaboration of the ``Stuff``
-spec happens before the body of ``Math.Sqrt`` is
-elaborated, and hence causes ``Program_Error`` exception to be raised.
-At first glance, one might say that the binder is misbehaving, because
-obviously you want to elaborate the body of something you |with| first, but
-that is not a general rule that can be followed in all cases. Consider
-
-.. code-block:: ada
-
- package X is ...
-
- package Y is ...
-
- with X;
- package body Y is ...
-
- with Y;
- package body X is ...
-
-This is a common arrangement, and, apart from the order of elaboration
-problems that might arise in connection with elaboration code, this works fine.
-A rule that says that you must first elaborate the body of anything you
-|with| cannot work in this case:
-the body of ``X`` |withs| ``Y``,
-which means you would have to
-elaborate the body of ``Y`` first, but that |withs| ``X``,
-which means
-you have to elaborate the body of ``X`` first, but ... and we have a
-loop that cannot be broken.
-
-It is true that the binder can in many cases guess an order of elaboration
-that is unlikely to cause a ``Program_Error``
-exception to be raised, and it tries to do so (in the
-above example of ``Math/Stuff/Spec``, the GNAT binder will
-by default
-elaborate the body of ``Math`` right after its spec, so all will be well).
-
-However, a program that blindly relies on the binder to be helpful can
-get into trouble, as we discussed in the previous sections, so GNAT
-provides a number of facilities for assisting the programmer in
-developing programs that are robust with respect to elaboration order.
-
-
-.. _Default_Behavior_in_GNAT_-_Ensuring_Safety:
-
-Default Behavior in GNAT - Ensuring Safety
-==========================================
-
-The default behavior in GNAT ensures elaboration safety. In its
-default mode GNAT implements the
-rule we previously described as the right approach. Let's restate it:
-
-*If a unit has elaboration code that can directly or indirectly make a
-call to a subprogram in a |withed| unit, or instantiate a generic
-package in a |withed| unit, then if the |withed| unit
-does not have pragma ``Pure`` or ``Preelaborate``, then the client should have an
-``Elaborate_All`` pragma for the |withed| unit.*
-
-*In the case of instantiating a generic subprogram, it is always
-sufficient to have only an ``Elaborate`` pragma for the
-|withed| unit.*
-
-By following this rule a client is assured that calls and instantiations
-can be made without risk of an exception.
-
-In this mode GNAT traces all calls that are potentially made from
-elaboration code, and puts in any missing implicit ``Elaborate``
-and ``Elaborate_All`` pragmas.
-The advantage of this approach is that no elaboration problems
-are possible if the binder can find an elaboration order that is
-consistent with these implicit ``Elaborate`` and
-``Elaborate_All`` pragmas. The
-disadvantage of this approach is that no such order may exist.
-
-If the binder does not generate any diagnostics, then it means that it has
-found an elaboration order that is guaranteed to be safe. However, the binder
-may still be relying on implicitly generated ``Elaborate`` and
-``Elaborate_All`` pragmas so portability to other compilers than GNAT is not
-guaranteed.
-
-If it is important to guarantee portability, then the compilations should
-use the :switch:`-gnatel`
-(info messages for elaboration pragmas) switch. This will cause info messages
-to be generated indicating the missing ``Elaborate`` and
-``Elaborate_All`` pragmas.
-Consider the following source program:
-
-.. code-block:: ada
-
- with k;
- package j is
- m : integer := k.r;
- end;
-
-where it is clear that there
-should be a pragma ``Elaborate_All``
-for unit ``k``. An implicit pragma will be generated, and it is
-likely that the binder will be able to honor it. However, if you want
-to port this program to some other Ada compiler than GNAT.
-it is safer to include the pragma explicitly in the source. If this
-unit is compiled with the :switch:`-gnatel`
-switch, then the compiler outputs an information message::
-
- 1. with k;
- 2. package j is
- 3. m : integer := k.r;
- |
- >>> info: call to "r" may raise Program_Error
- >>> info: missing pragma Elaborate_All for "k"
-
- 4. end;
-
-and these messages can be used as a guide for supplying manually
-the missing pragmas. It is usually a bad idea to use this
-option during development. That's because it will tell you when
-you need to put in a pragma, but cannot tell you when it is time
-to take it out. So the use of pragma ``Elaborate_All`` may lead to
-unnecessary dependencies and even false circularities.
-
-This default mode is more restrictive than the Ada Reference
-Manual, and it is possible to construct programs which will compile
-using the dynamic model described there, but will run into a
-circularity using the safer static model we have described.
-
-Of course any Ada compiler must be able to operate in a mode
-consistent with the requirements of the Ada Reference Manual,
-and in particular must have the capability of implementing the
-standard dynamic model of elaboration with run-time checks.
-
-In GNAT, this standard mode can be achieved either by the use of
-the :switch:`-gnatE` switch on the compiler (``gcc`` or
-``gnatmake``) command, or by the use of the configuration pragma:
-
-.. code-block:: ada
-
- pragma Elaboration_Checks (DYNAMIC);
-
-Either approach will cause the unit affected to be compiled using the
-standard dynamic run-time elaboration checks described in the Ada
-Reference Manual. The static model is generally preferable, since it
-is clearly safer to rely on compile and link time checks rather than
-run-time checks. However, in the case of legacy code, it may be
-difficult to meet the requirements of the static model. This
-issue is further discussed in
-:ref:`What_to_Do_If_the_Default_Elaboration_Behavior_Fails`.
-
-Note that the static model provides a strict subset of the allowed
-behavior and programs of the Ada Reference Manual, so if you do
-adhere to the static model and no circularities exist,
-then you are assured that your program will
-work using the dynamic model, providing that you remove any
-pragma Elaborate statements from the source.
-
-
-.. _Treatment_of_Pragma_Elaborate:
-
-Treatment of Pragma Elaborate
-=============================
-
-.. index:: Pragma Elaborate
-
-The use of ``pragma Elaborate``
-should generally be avoided in Ada 95 and Ada 2005 programs,
-since there is no guarantee that transitive calls
-will be properly handled. Indeed at one point, this pragma was placed
-in Annex J (Obsolescent Features), on the grounds that it is never useful.
-
-Now that's a bit restrictive. In practice, the case in which
-``pragma Elaborate`` is useful is when the caller knows that there
-are no transitive calls, or that the called unit contains all necessary
-transitive ``pragma Elaborate`` statements, and legacy code often
-contains such uses.
-
-Strictly speaking the static mode in GNAT should ignore such pragmas,
-since there is no assurance at compile time that the necessary safety
-conditions are met. In practice, this would cause GNAT to be incompatible
-with correctly written Ada 83 code that had all necessary
-``pragma Elaborate`` statements in place. Consequently, we made the
-decision that GNAT in its default mode will believe that if it encounters
-a ``pragma Elaborate`` then the programmer knows what they are doing,
-and it will trust that no elaboration errors can occur.
-
-The result of this decision is two-fold. First to be safe using the
-static mode, you should remove all ``pragma Elaborate`` statements.
-Second, when fixing circularities in existing code, you can selectively
-use ``pragma Elaborate`` statements to convince the static mode of
-GNAT that it need not generate an implicit ``pragma Elaborate_All``
-statement.
-
-When using the static mode with :switch:`-gnatwl`, any use of
-``pragma Elaborate`` will generate a warning about possible
-problems.
-
-
-.. _Elaboration_Issues_for_Library_Tasks:
-
-Elaboration Issues for Library Tasks
-====================================
-
-.. index:: Library tasks, elaboration issues
-
-.. index:: Elaboration of library tasks
-
-In this section we examine special elaboration issues that arise for
-programs that declare library level tasks.
-
-Generally the model of execution of an Ada program is that all units are
-elaborated, and then execution of the program starts. However, the
-declaration of library tasks definitely does not fit this model. The
-reason for this is that library tasks start as soon as they are declared
-(more precisely, as soon as the statement part of the enclosing package
-body is reached), that is to say before elaboration
-of the program is complete. This means that if such a task calls a
-subprogram, or an entry in another task, the callee may or may not be
-elaborated yet, and in the standard
-Reference Manual model of dynamic elaboration checks, you can even
-get timing dependent Program_Error exceptions, since there can be
-a race between the elaboration code and the task code.
-
-The static model of elaboration in GNAT seeks to avoid all such
-dynamic behavior, by being conservative, and the conservative
-approach in this particular case is to assume that all the code
-in a task body is potentially executed at elaboration time if
-a task is declared at the library level.
-
-This can definitely result in unexpected circularities. Consider
-the following example
-
-.. code-block:: ada
-
- package Decls is
- task Lib_Task is
- entry Start;
- end Lib_Task;
+ spec of Computer
+ body of Computer
+ spec of Client
- type My_Int is new Integer;
+ Note that there are several allowable suborders for the specs and bodies of
+ ``Math`` and ``Computer``, but the point is that these specs and bodies will
+ be elaborated prior to ``Client``.
- function Ident (M : My_Int) return My_Int;
- end Decls;
+ Removing pragma ``Elaborate_All`` could result in the following incorrect
+ elaboration order
- with Utils;
- package body Decls is
- task body Lib_Task is
- begin
- accept Start;
- Utils.Put_Val (2);
- end Lib_Task;
+ ::
- function Ident (M : My_Int) return My_Int is
+ spec of Math
+ spec of Computer
+ body of Computer
+ spec of Client
+ body of Math
+
+ where ``Client`` invokes ``Computer.Compute``, which in turn invokes
+ ``Math.Factorial``, but the body of ``Math.Factorial`` has not been
+ elaborated yet.
+
+All pragmas shown above can be summarized by the following rule:
+
+*If a client unit elaborates a server target directly or indirectly, then if
+the server unit requires a body and does not have pragma Pure, Preelaborate,
+or Elaborate_Body, then the client unit should have pragma Elaborate or
+Elaborate_All for the server unit.*
+
+If the rule outlined above is not followed, then a program may fall in one of
+the following states:
+
+* *No elaboration order exists*
+
+ In this case a compiler must diagnose the situation, and refuse to build an
+ executable program.
+
+* *One or more incorrect elaboration orders exist*
+
+ In this case a compiler can build an executable program, but
+ ``Program_Error`` will be raised when the program is run.
+
+* *Several elaboration orders exist, some correct, some incorrect*
+
+ In this case the programmer has not controlled the elaboration order. As a
+ result, a compiler may or may not pick one of the correct orders, and the
+ program may or may not raise ``Program_Error`` when it is run. This is the
+ worst possible state because the program may fail on another compiler, or
+ even another version of the same compiler.
+
+* *One or more correct orders exist*
+
+ In this case a compiler can build an executable program, and the program is
+ run successfully. This state may be guaranteed by following the outlined
+ rules, or may be the result of good program architecture.
+
+Note that one additional advantage of using ``Elaborate`` and ``Elaborate_All``
+is that the program continues to stay in the last state (one or more correct
+orders exist) even if maintenance changes the bodies of targets.
+
+.. _Controlling_the_Elaboration_Order_in_GNAT:
+
+Controlling the Elaboration Order in GNAT
+=========================================
+
+In addition to Ada semantics and rules synthesized from them, GNAT offers
+three elaboration models to aid the programmer with specifying the correct
+elaboration order and to diagnose elaboration problems.
+
+.. index:: Dynamic elaboration model
+
+* *Dynamic elaboration model*
+
+ This is the most permissive of the three elaboration models. When the
+ dynamic model is in effect, GNAT assumes that all code within all units in
+ a partition is elaboration code. GNAT performs very few diagnostics and
+ generates run-time checks to verify the elaboration order of a program. This
+ behavior is identical to that specified by the Ada Reference Manual. The
+ dynamic model is enabled with compiler switch :switch:`-gnatE`.
+
+.. index:: Static elaboration model
+
+* *Static elaboration model*
+
+ This is the middle ground of the three models. When the static model is in
+ effect, GNAT performs extensive diagnostics on a unit-by-unit basis for all
+ scenarios that elaborate or execute internal targets. GNAT also generates
+ run-time checks for all external targets and for all scenarios that may
+ exhibit ABE problems. Finally, GNAT installs implicit ``Elaborate`` and
+ ``Elaborate_All`` pragmas for server units based on the dependencies of
+ client units. The static model is the default model in GNAT.
+
+.. index:: SPARK elaboration model
+
+* *SPARK elaboration model*
+
+ This is the most conservative of the three models and enforces the SPARK
+ rules of elaboration as defined in the SPARK Reference Manual, section 7.7.
+ The SPARK model is in effect only when a scenario and a target reside in a
+ region subject to SPARK_Mode On, otherwise the dynamic or static model is in
+ effect.
+
+.. _Common_Elaboration_Model_Traits":
+
+Common Elaboration-model Traits
+===============================
+
+All three GNAT models are able to detect elaboration problems related to
+dispatching calls and a particular kind of ABE referred to as *guaranteed ABE*.
+
+* *Dispatching calls*
+
+ GNAT installs run-time checks for each primitive subprogram of each tagged
+ type defined in a partition on the assumption that a dispatching call
+ invoked at elaboration time will execute one of these primitives. As a
+ result, a dispatching call that executes a primitive whose body has not
+ been elaborated yet will raise exception ``Program_Error`` at run time. The
+ checks can be suppressed using pragma ``Suppress (Elaboration_Check)``.
+
+* *Guaranteed ABE*
+
+ A guaranteed ABE arises when the body of a target is not elaborated early
+ enough, and causes all scenarios that directly execute the target to fail.
+
+ ::
+
+ package body Guaranteed_ABE is
+ function ABE return Integer;
+
+ Val : constant Integer := ABE;
+
+ function ABE return Integer is
begin
- return M;
- end Ident;
- end Decls;
+ ...
+ end ABE;
+ end Guaranteed_ABE;
+
+ In the example above, the elaboration of ``Guaranteed_ABE``'s body elaborates
+ the declaration of ``Val``. This invokes function ``ABE``, however the body
+ of ``ABE`` has not been elaborated yet. GNAT emits similar diagnostics in all
+ three models:
+
+ ::
+
+ 1. package body Guaranteed_ABE is
+ 2. function ABE return Integer;
+ 3.
+ 4. Val : constant Integer := ABE;
+ |
+ >>> warning: cannot call "ABE" before body seen
+ >>> warning: Program_Error will be raised at run time
+
+ 5.
+ 6. function ABE return Integer is
+ 7. begin
+ 8. ...
+ 9. end ABE;
+ 10. end Guaranteed_ABE;
+
+Note that GNAT emits warnings rather than hard errors whenever it encounters an
+elaboration problem. This is because the elaboration model in effect may be too
+conservative, or a particular scenario may not be elaborated or executed due to
+data and control flow. The warnings can be suppressed with compiler switch
+:switch:`-gnatws`.
+
+.. _Dynamic_Elaboration_Model_in_GNAT:
+
+Dynamic Elaboration Model in GNAT
+=================================
- with Decls;
- package Utils is
- procedure Put_Val (Arg : Decls.My_Int);
- end Utils;
+The dynamic model assumes that all code within all units in a partition is
+elaboration code. As a result, run-time checks are installed for each scenario
+regardless of whether the target is internal or external. The checks can be
+suppressed using pragma ``Suppress (Elaboration_Check)``. This behavior is
+identical to that specified by the Ada Reference Manual. The following example
+showcases run-time checks installed by GNAT to verify the elaboration state of
+package ``Dynamic_Model``.
- with Text_IO;
- package body Utils is
- procedure Put_Val (Arg : Decls.My_Int) is
+::
+
+ with Server;
+ package body Dynamic_Model is
+ procedure API is
+ begin
+ ...
+ end API;
+
+ <check that the body of Server.Gen is elaborated>
+ package Inst is new Server.Gen;
+
+ T : Server.Task_Type;
+
+ begin
+ <check that the body of Server.Task_Type is elaborated>
+
+ <check that the body of Server.Proc is elaborated>
+ Server.Proc;
+ end Dynamic_Model;
+
+The checks verify that the body of a target has been successfully elaborated
+before a scenario activates, calls, or instantiates a target.
+
+Note that no scenario within package ``Dynamic_Model`` calls procedure ``API``.
+In fact, procedure ``API`` may not be invoked by elaboration code within the
+partition, however the dynamic model assumes that this can happen.
+
+The dynamic model emits very few diagnostics, but can make suggestions on
+missing ``Elaborate`` and ``Elaborate_All`` pragmas for library-level
+scenarios. This information is available when compiler switch :switch:`-gnatel`
+is in effect.
+
+::
+
+ 1. with Server;
+ 2. package body Dynamic_Model is
+ 3. Val : constant Integer := Server.Func;
+ |
+ >>> info: call to "Func" during elaboration
+ >>> info: missing pragma "Elaborate_All" for unit "Server"
+
+ 4. end Dynamic_Model;
+
+.. _Static_Elaboration_Model_in_GNAT:
+
+Static Elaboration Model in GNAT
+================================
+
+In contrast to the dynamic model, the static model is more precise in its
+analysis of elaboration code. The model makes a clear distinction between
+internal and external targets, and resorts to different diagnostics and
+run-time checks based on the nature of the target.
+
+* *Internal targets*
+
+ The static model performs extensive diagnostics on scenarios which elaborate
+ or execute internal targets. The warnings resulting from these diagnostics
+ are enabled by default, but can be suppressed using compiler switch
+ :switch:`-gnatws`.
+
+ ::
+
+ 1. package body Static_Model is
+ 2. generic
+ 3. with function Func return Integer;
+ 4. package Gen is
+ 5. Val : constant Integer := Func;
+ 6. end Gen;
+ 7.
+ 8. function ABE return Integer;
+ 9.
+ 10. function Cause_ABE return Boolean is
+ 11. package Inst is new Gen (ABE);
+ |
+ >>> warning: in instantiation at line 5
+ >>> warning: cannot call "ABE" before body seen
+ >>> warning: Program_Error may be raised at run time
+ >>> warning: body of unit "Static_Model" elaborated
+ >>> warning: function "Cause_ABE" called at line 16
+ >>> warning: function "ABE" called at line 5, instance at line 11
+
+ 12. begin
+ 13. ...
+ 14. end Cause_ABE;
+ 15.
+ 16. Val : constant Boolean := Cause_ABE;
+ 17.
+ 18. function ABE return Integer is
+ 19. begin
+ 20. ...
+ 21. end ABE;
+ 22. end Static_Model;
+
+ The example above illustrates an ABE problem within package ``Static_Model``,
+ which is hidden by several layers of indirection. The elaboration of package
+ body ``Static_Model`` elaborates the declaration of ``Val``. This invokes
+ function ``Cause_ABE``, which instantiates generic unit ``Gen`` as ``Inst``.
+ The elaboration of ``Inst`` invokes function ``ABE``, however the body of
+ ``ABE`` has not been elaborated yet.
+
+* *External targets*
+
+ The static model installs run-time checks to verify the elaboration status
+ of server targets only when the scenario that elaborates or executes that
+ target is part of the elaboration code of the client unit. The checks can be
+ suppressed using pragma ``Suppress (Elaboration_Check)``.
+
+ ::
+
+ with Server;
+ package body Static_Model is
+ generic
+ with function Func return Integer;
+ package Gen is
+ Val : constant Integer := Func;
+ end Gen;
+
+ function Call_Func return Boolean is
+ <check that the body of Server.Func is elaborated>
+ package Inst is new Gen (Server.Func);
begin
- Text_IO.Put_Line (Decls.My_Int'Image (Decls.Ident (Arg)));
- end Put_Val;
- end Utils;
+ ...
+ end Call_Func;
+
+ Val : constant Boolean := Call_Func;
+ end Static_Model;
+
+ In the example above, the elaboration of package body ``Static_Model``
+ elaborates the declaration of ``Val``. This invokes function ``Call_Func``,
+ which instantiates generic unit ``Gen`` as ``Inst``. The elaboration of
+ ``Inst`` invokes function ``Server.Func``. Since ``Server.Func`` is an
+ external target, GNAT installs a run-time check to verify that its body has
+ been elaborated.
+
+ In addition to checks, the static model installs implicit ``Elaborate`` and
+ ``Elaborate_All`` pragmas to guarantee safe elaboration use of server units.
+ This information is available when compiler switch :switch:`-gnatel` is in
+ effect.
+
+ ::
+
+ 1. with Server;
+ 2. package body Static_Model is
+ 3. generic
+ 4. with function Func return Integer;
+ 5. package Gen is
+ 6. Val : constant Integer := Func;
+ 7. end Gen;
+ 8.
+ 9. function Call_Func return Boolean is
+ 10. package Inst is new Gen (Server.Func);
+ |
+ >>> info: instantiation of "Gen" during elaboration
+ >>> info: in instantiation at line 6
+ >>> info: call to "Func" during elaboration
+ >>> info: in instantiation at line 6
+ >>> info: implicit pragma "Elaborate_All" generated for unit "Server"
+ >>> info: body of unit "Static_Model" elaborated
+ >>> info: function "Call_Func" called at line 15
+ >>> info: function "Func" called at line 6, instance at line 10
+
+ 11. begin
+ 12. ...
+ 13. end Call_Func;
+ 14.
+ 15. Val : constant Boolean := Call_Func;
+ |
+ >>> info: call to "Call_Func" during elaboration
+
+ 16. end Static_Model;
+
+ In the example above, the elaboration of package body ``Static_Model``
+ elaborates the declaration of ``Val``. This invokes function ``Call_Func``,
+ which instantiates generic unit ``Gen`` as ``Inst``. The elaboration of
+ ``Inst`` invokes function ``Server.Func``. Since ``Server.Func`` is an
+ external target, GNAT installs an implicit ``Elaborate_All`` pragma for unit
+ ``Server``. The pragma guarantees that both the spec and body of ``Server``,
+ along with any additional dependencies that ``Server`` may require, are
+ elaborated prior to the body of ``Static_Model``.
+
+.. _SPARK_Elaboration_Model_in_GNAT:
+
+SPARK Elaboration Model in GNAT
+===============================
+
+The SPARK model is identical to the static model in its handling of internal
+targets. The SPARK model, however, requires explicit ``Elaborate`` or
+``Elaborate_All`` pragmas to be present in the program when a target is
+external, and compiler switch :switch:`-gnatd.v` is in effect.
+
+::
+
+ 1. with Server;
+ 2. package body SPARK_Model with SPARK_Mode is
+ 3. Val : constant Integer := Server.Func;
+ |
+ >>> call to "Func" during elaboration in SPARK
+ >>> unit "SPARK_Model" requires pragma "Elaborate_All" for "Server"
+ >>> body of unit "SPARK_Model" elaborated
+ >>> function "Func" called at line 3
+
+ 4. end SPARK_Model;
+
+.. _Mixing_Elaboration_Models:
+
+Mixing Elaboration Models
+=========================
+
+It is possible to mix units compiled with a different elaboration model,
+however the following rules must be observed:
+
+* A client unit compiled with the dynamic model can only |with| a server unit
+ that meets at least one of the following criteria:
+
+ - The server unit is compiled with the dynamic model.
+
+ - The server unit is a GNAT implementation unit from the Ada, GNAT,
+ Interfaces, or System hierarchies.
+
+ - The server unit has pragma ``Pure`` or ``Preelaborate``.
- with Decls;
- procedure Main is
+ - The client unit has an explicit ``Elaborate_All`` pragma for the server
+ unit.
+
+These rules ensure that elaboration checks are not omitted. If the rules are
+violated, the binder emits a warning:
+
+::
+
+ warning: "x.ads" has dynamic elaboration checks and with's
+ warning: "y.ads" which has static elaboration checks
+
+The warnings can be suppressed by binder switch :switch:`-ws`.
+
+.. _Elaboration_Circularities:
+
+Elaboration Circularities
+=========================
+
+If the binder cannot find an acceptable elaboration order, it outputs detailed
+diagnostics describing an **elaboration circularity**.
+
+::
+
+ package Server is
+ function Func return Integer;
+ end Server;
+
+::
+
+ with Client;
+ package body Server is
+ function Func return Integer is
+ begin
+ ...
+ end Func;
+ end Server;
+
+::
+
+ with Server;
+ package Client is
+ Val : constant Integer := Server.Func;
+ end Client;
+
+::
+
+ with Client;
+ procedure Main is begin null; end Main;
+
+::
+
+ error: elaboration circularity detected
+ info: "server (body)" must be elaborated before "client (spec)"
+ info: reason: implicit Elaborate_All in unit "client (spec)"
+ info: recompile "client (spec)" with -gnatel for full details
+ info: "server (body)"
+ info: must be elaborated along with its spec:
+ info: "server (spec)"
+ info: which is withed by:
+ info: "client (spec)"
+ info: "client (spec)" must be elaborated before "server (body)"
+ info: reason: with clause
+
+In the example above, ``Client`` must be elaborated prior to ``Main`` by virtue
+of a |with| clause. The elaboration of ``Client`` invokes ``Server.Func``, and
+static model generates an implicit ``Elaborate_All`` pragma for ``Server``. The
+pragma implies that both the spec and body of ``Server``, along with any units
+they |with|, must be elaborated prior to ``Client``. However, ``Server``'s body
+|withs| ``Client``, implying that ``Client`` must be elaborated prior to
+``Server``. The end result is that ``Client`` must be elaborated prior to
+``Client``, and this leads to a circularity.
+
+.. _Resolving_Elaboration_Circularities:
+
+Resolving Elaboration Circularities
+===================================
+
+When faced with an elaboration circularity, a programmer has several options
+available.
+
+* *Fix the program*
+
+ The most desirable option from the point of view of long-term maintenance
+ is to rearrange the program so that the elaboration problems are avoided.
+ One useful technique is to place the elaboration code into separate child
+ packages. Another is to move some of the initialization code to explicitly
+ invoked subprograms, where the program controls the order of initialization
+ explicitly. Although this is the most desirable option, it may be impractical
+ and involve too much modification, especially in the case of complex legacy
+ code.
+
+* *Switch to more permissive elaboration model*
+
+ If the compilation was performed using the static model, enable the dynamic
+ model with compiler switch :switch:`-gnatE`. GNAT will no longer generate
+ implicit ``Elaborate`` and ``Elaborate_All`` pragmas, resulting in a behavior
+ identical to that specified by the Ada Reference Manual. The binder will
+ generate an executable program that may or may not raise ``Program_Error``,
+ and it is the programmer's responsibility to ensure that it does not raise
+ ``Program_Error``.
+
+* *Suppress all elaboration checks*
+
+ The drawback of run-time checks is that they generate overhead at run time,
+ both in space and time. If the programmer is absolutely sure that a program
+ will not raise an elaboration-related ``Program_Error``, then using the
+ pragma ``Suppress (Elaboration_Check)`` globally (as a configuration pragma)
+ will eliminate all run-time checks.
+
+* *Suppress elaboration checks selectively*
+
+ If a scenario cannot possibly lead to an elaboration ``Program_Error``,
+ and the binder nevertheless complains about implicit ``Elaborate`` and
+ ``Elaborate_All`` pragmas that lead to elaboration circularities, it
+ is possible to suppress the generation of implicit ``Elaborate`` and
+ ``Elaborate_All`` pragmas, as well as run-time checks. Clearly this can
+ be unsafe, and it is the responsibility of the programmer to make sure
+ that the resulting program has no elaboration anomalies. Pragma
+ ``Suppress (Elaboration_Check)`` can be used with different levels of
+ granularity to achieve these effects.
+
+ - *Target suppression*
+
+ When the pragma is placed in a declarative part, without a second argument
+ naming an entity, it will suppress implicit ``Elaborate`` and
+ ``Elaborate_All`` pragma generation, as well as run-time checks, on all
+ targets within the region.
+
+ ::
+
+ package Range_Suppress is
+ pragma Suppress (Elaboration_Check);
+
+ function Func return Integer;
+
+ generic
+ procedure Gen;
+
+ pragma Unsuppress (Elaboration_Check);
+
+ task type Tsk;
+ end Range_Suppress;
+
+ In the example above, a pair of Suppress/Unsuppress pragmas define a region
+ of suppression within package ``Range_Suppress``. As a result, no implicit
+ ``Elaborate`` and ``Elaborate_All`` pragmas, nor any run-time checks, will
+ be generated by callers of ``Func`` and instantiators of ``Gen``. Note that
+ task type ``Tsk`` is not within this region.
+
+ An alternative to the region-based suppression is to use multiple
+ ``Suppress`` pragmas with arguments naming specific entities for which
+ elaboration checks should be suppressed:
+
+ ::
+
+ package Range_Suppress is
+ function Func return Integer;
+ pragma Suppress (Elaboration_Check, Func);
+
+ generic
+ procedure Gen;
+ pragma Suppress (Elaboration_Check, Gen);
+
+ task type Tsk;
+ end Range_Suppress;
+
+ - *Scenario suppression*
+
+ When the pragma ``Suppress`` is placed in a declarative or statement
+ part, without an entity argument, it will suppress implicit ``Elaborate``
+ and ``Elaborate_All`` pragma generation, as well as run-time checks, on
+ all scenarios within the region.
+
+ ::
+
+ with Server;
+ package body Range_Suppress is
+ pragma Suppress (Elaboration_Check);
+
+ function Func return Integer is
+ begin
+ return Server.Func;
+ end Func;
+
+ procedure Gen is
+ begin
+ Server.Proc;
+ end Gen;
+
+ pragma Unsuppress (Elaboration_Check);
+
+ task body Tsk is
+ begin
+ Server.Proc;
+ end Tsk;
+ end Range_Suppress;
+
+ In the example above, a pair of Suppress/Unsuppress pragmas define a region
+ of suppression within package body ``Range_Suppress``. As a result, the
+ calls to ``Server.Func`` in ``Func`` and ``Server.Proc`` in ``Gen`` will
+ not generate any implicit ``Elaborate`` and ``Elaborate_All`` pragmas or
+ run-time checks.
+
+.. _Resolving_Task_Issues:
+
+Resolving Task Issues
+=====================
+
+The model of execution in Ada dictates that elaboration must first take place,
+and only then can the main program be started. Tasks which are activated during
+elaboration violate this model and may lead to serious concurrent problems at
+elaboration time.
+
+A task can be activated in two different ways:
+
+* The task is created by an allocator in which case it is activated immediately
+ after the allocator is evaluated.
+
+* The task is declared at the library level or within some nested master in
+ which case it is activated before starting execution of the statement
+ sequence of the master defining the task.
+
+Since the elaboration of a partition is performed by the environment task
+servicing that partition, any tasks activated during elaboration may be in
+a race with the environment task, and lead to unpredictable state and behavior.
+The static model seeks to avoid such interactions by assuming that all code in
+the task body is executed at elaboration time, if the task was activated by
+elaboration code.
+
+::
+
+ package Decls is
+ task Lib_Task is
+ entry Start;
+ end Lib_Task;
+
+ type My_Int is new Integer;
+
+ function Ident (M : My_Int) return My_Int;
+ end Decls;
+
+::
+
+ with Utils;
+ package body Decls is
+ task body Lib_Task is
begin
- Decls.Lib_Task.Start;
- end;
-
-If the above example is compiled in the default static elaboration
-mode, then a circularity occurs. The circularity comes from the call
-``Utils.Put_Val`` in the task body of ``Decls.Lib_Task``. Since
-this call occurs in elaboration code, we need an implicit pragma
-``Elaborate_All`` for ``Utils``. This means that not only must
-the spec and body of ``Utils`` be elaborated before the body
-of ``Decls``, but also the spec and body of any unit that is
-|withed| by the body of ``Utils`` must also be elaborated before
-the body of ``Decls``. This is the transitive implication of
-pragma ``Elaborate_All`` and it makes sense, because in general
-the body of ``Put_Val`` might have a call to something in a
-|withed| unit.
-
-In this case, the body of Utils (actually its spec) |withs|
-``Decls``. Unfortunately this means that the body of ``Decls``
-must be elaborated before itself, in case there is a call from the
-body of ``Utils``.
-
-Here is the exact chain of events we are worrying about:
-
-* In the body of ``Decls`` a call is made from within the body of a library
- task to a subprogram in the package ``Utils``. Since this call may
- occur at elaboration time (given that the task is activated at elaboration
- time), we have to assume the worst, i.e., that the
- call does happen at elaboration time.
-
-* This means that the body and spec of ``Util`` must be elaborated before
- the body of ``Decls`` so that this call does not cause an access before
- elaboration.
-
-* Within the body of ``Util``, specifically within the body of
- ``Util.Put_Val`` there may be calls to any unit |withed|
- by this package.
-
-* One such |withed| package is package ``Decls``, so there
- might be a call to a subprogram in ``Decls`` in ``Put_Val``.
- In fact there is such a call in this example, but we would have to
- assume that there was such a call even if it were not there, since
- we are not supposed to write the body of ``Decls`` knowing what
- is in the body of ``Utils``; certainly in the case of the
- static elaboration model, the compiler does not know what is in
- other bodies and must assume the worst.
-
-* This means that the spec and body of ``Decls`` must also be
- elaborated before we elaborate the unit containing the call, but
- that unit is ``Decls``! This means that the body of ``Decls``
- must be elaborated before itself, and that's a circularity.
-
-Indeed, if you add an explicit pragma ``Elaborate_All`` for ``Utils`` in
-the body of ``Decls`` you will get a true Ada Reference Manual
-circularity that makes the program illegal.
-
-In practice, we have found that problems with the static model of
-elaboration in existing code often arise from library tasks, so
-we must address this particular situation.
-
-Note that if we compile and run the program above, using the dynamic model of
-elaboration (that is to say use the :switch:`-gnatE` switch),
-then it compiles, binds,
-links, and runs, printing the expected result of 2. Therefore in some sense
-the circularity here is only apparent, and we need to capture
-the properties of this program that distinguish it from other library-level
-tasks that have real elaboration problems.
-
-We have four possible answers to this question:
-
-
-* Use the dynamic model of elaboration.
-
- If we use the :switch:`-gnatE` switch, then as noted above, the program works.
- Why is this? If we examine the task body, it is apparent that the task cannot
- proceed past the
- ``accept`` statement until after elaboration has been completed, because
- the corresponding entry call comes from the main program, not earlier.
- This is why the dynamic model works here. But that's really giving
- up on a precise analysis, and we prefer to take this approach only if we cannot
- solve the
- problem in any other manner. So let us examine two ways to reorganize
- the program to avoid the potential elaboration problem.
-
-* Split library tasks into separate packages.
-
- Write separate packages, so that library tasks are isolated from
- other declarations as much as possible. Let us look at a variation on
- the above program.
-
-
- .. code-block:: ada
-
- package Decls1 is
+ accept Start;
+ Utils.Put_Val (2);
+ end Lib_Task;
+
+ function Ident (M : My_Int) return My_Int is
+ begin
+ return M;
+ end Ident;
+ end Decls;
+
+::
+
+ with Decls;
+ package Utils is
+ procedure Put_Val (Arg : Decls.My_Int);
+ end Utils;
+
+::
+
+ with Ada.Text_IO; use Ada.Text_IO;
+ package body Utils is
+ procedure Put_Val (Arg : Decls.My_Int) is
+ begin
+ Put_Line (Arg'Img);
+ end Put_Val;
+ end Utils;
+
+::
+
+ with Decls;
+ procedure Main is
+ begin
+ Decls.Lib_Task.Start;
+ end Main;
+
+When the above example is compiled with the static model, an elaboration
+circularity arises:
+
+::
+
+ error: elaboration circularity detected
+ info: "decls (body)" must be elaborated before "decls (body)"
+ info: reason: implicit Elaborate_All in unit "decls (body)"
+ info: recompile "decls (body)" with -gnatel for full details
+ info: "decls (body)"
+ info: must be elaborated along with its spec:
+ info: "decls (spec)"
+ info: which is withed by:
+ info: "utils (spec)"
+ info: which is withed by:
+ info: "decls (body)"
+
+In the above example, ``Decls`` must be elaborated prior to ``Main`` by virtue
+of a with clause. The elaboration of ``Decls`` activates task ``Lib_Task``. The
+static model conservatibely assumes that all code within the body of
+``Lib_Task`` is executed, and generates an implicit ``Elaborate_All`` pragma
+for ``Units`` due to the call to ``Utils.Put_Val``. The pragma implies that
+both the spec and body of ``Utils``, along with any units they |with|,
+must be elaborated prior to ``Decls``. However, ``Utils``'s spec |withs|
+``Decls``, implying that ``Decls`` must be elaborated before ``Utils``. The end
+result is that ``Utils`` must be elaborated prior to ``Utils``, and this
+leads to a circularity.
+
+In reality, the example above will not exhibit an ABE problem at run time.
+When the body of task ``Lib_Task`` is activated, execution will wait for entry
+``Start`` to be accepted, and the call to ``Utils.Put_Val`` will not take place
+at elaboration time. Task ``Lib_Task`` will resume its execution after the main
+program is executed because ``Main`` performs a rendezvous with
+``Lib_Task.Start``, and at that point all units have already been elaborated.
+As a result, the static model may seem overly conservative, partly because it
+does not take control and data flow into account.
+
+When faced with a task elaboration circularity, a programmer has several
+options available:
+
+* *Use the dynamic model*
+
+ The dynamic model does not generate implicit ``Elaborate`` and
+ ``Elaborate_All`` pragmas. Instead, it will install checks prior to every
+ call in the example above, thus verifying the successful elaboration of
+ ``Utils.Put_Val`` in case the call to it takes place at elaboration time.
+ The dynamic model is enabled with compiler switch :switch:`-gnatE`.
+
+* *Isolate the tasks*
+
+ Relocating tasks in their own separate package could decouple them from
+ dependencies that would otherwise cause an elaboration circularity. The
+ example above can be rewritten as follows:
+
+ ::
+
+ package Decls1 is -- new
task Lib_Task is
entry Start;
end Lib_Task;
- end Decls1;
+ end Decls1;
+
+ ::
- with Utils;
- package body Decls1 is
+ with Utils;
+ package body Decls1 is -- new
task body Lib_Task is
begin
accept Start;
Utils.Put_Val (2);
end Lib_Task;
- end Decls1;
+ end Decls1;
+
+ ::
- package Decls2 is
+ package Decls2 is -- new
type My_Int is new Integer;
function Ident (M : My_Int) return My_Int;
- end Decls2;
+ end Decls2;
- with Utils;
- package body Decls2 is
+ ::
+
+ with Utils;
+ package body Decls2 is -- new
function Ident (M : My_Int) return My_Int is
begin
return M;
end Ident;
- end Decls2;
+ end Decls2;
+
+ ::
- with Decls2;
- package Utils is
+ with Decls2;
+ package Utils is
procedure Put_Val (Arg : Decls2.My_Int);
- end Utils;
+ end Utils;
+
+ ::
- with Text_IO;
- package body Utils is
+ with Ada.Text_IO; use Ada.Text_IO;
+ package body Utils is
procedure Put_Val (Arg : Decls2.My_Int) is
begin
- Text_IO.Put_Line (Decls2.My_Int'Image (Decls2.Ident (Arg)));
+ Put_Line (Arg'Img);
end Put_Val;
- end Utils;
-
- with Decls1;
- procedure Main is
- begin
- Decls1.Lib_Task.Start;
- end;
-
+ end Utils;
- All we have done is to split ``Decls`` into two packages, one
- containing the library task, and one containing everything else. Now
- there is no cycle, and the program compiles, binds, links and executes
- using the default static model of elaboration.
+ ::
-* Declare separate task types.
+ with Decls1;
+ procedure Main is
+ begin
+ Decls1.Lib_Task.Start;
+ end Main;
+
+* *Declare the tasks*
- A significant part of the problem arises because of the use of the
- single task declaration form. This means that the elaboration of
- the task type, and the elaboration of the task itself (i.e., the
- creation of the task) happen at the same time. A good rule
- of style in Ada is to always create explicit task types. By
- following the additional step of placing task objects in separate
- packages from the task type declaration, many elaboration problems
- are avoided. Here is another modified example of the example program:
+ The original example uses a single task declaration for ``Lib_Task``. An
+ explicit task type declaration and a properly placed task object could avoid
+ the dependencies that would otherwise cause an elaboration circularity. The
+ example can be rewritten as follows:
- .. code-block:: ada
+ ::
- package Decls is
- task type Lib_Task_Type is
+ package Decls is
+ task type Lib_Task is -- new
entry Start;
- end Lib_Task_Type;
+ end Lib_Task;
type My_Int is new Integer;
function Ident (M : My_Int) return My_Int;
- end Decls;
+ end Decls;
+
+ ::
- with Utils;
- package body Decls is
- task body Lib_Task_Type is
+ with Utils;
+ package body Decls is
+ task body Lib_Task is
begin
accept Start;
Utils.Put_Val (2);
- end Lib_Task_Type;
+ end Lib_Task;
function Ident (M : My_Int) return My_Int is
begin
return M;
end Ident;
- end Decls;
+ end Decls;
+
+ ::
- with Decls;
- package Utils is
+ with Decls;
+ package Utils is
procedure Put_Val (Arg : Decls.My_Int);
- end Utils;
+ end Utils;
+
+ ::
- with Text_IO;
- package body Utils is
+ with Ada.Text_IO; use Ada.Text_IO;
+ package body Utils is
procedure Put_Val (Arg : Decls.My_Int) is
begin
- Text_IO.Put_Line (Decls.My_Int'Image (Decls.Ident (Arg)));
+ Put_Line (Arg'Img);
end Put_Val;
- end Utils;
+ end Utils;
- with Decls;
- package Declst is
- Lib_Task : Decls.Lib_Task_Type;
- end Declst;
+ ::
- with Declst;
- procedure Main is
- begin
- Declst.Lib_Task.Start;
- end;
-
-
- What we have done here is to replace the ``task`` declaration in
- package ``Decls`` with a ``task type`` declaration. Then we
- introduce a separate package ``Declst`` to contain the actual
- task object. This separates the elaboration issues for
- the ``task type``
- declaration, which causes no trouble, from the elaboration issues
- of the task object, which is also unproblematic, since it is now independent
- of the elaboration of ``Utils``.
- This separation of concerns also corresponds to
- a generally sound engineering principle of separating declarations
- from instances. This version of the program also compiles, binds, links,
- and executes, generating the expected output.
-
-.. index:: No_Entry_Calls_In_Elaboration_Code restriction
-
-* Use No_Entry_Calls_In_Elaboration_Code restriction.
-
- The previous two approaches described how a program can be restructured
- to avoid the special problems caused by library task bodies. in practice,
- however, such restructuring may be difficult to apply to existing legacy code,
- so we must consider solutions that do not require massive rewriting.
-
- Let us consider more carefully why our original sample program works
- under the dynamic model of elaboration. The reason is that the code
- in the task body blocks immediately on the ``accept``
- statement. Now of course there is nothing to prohibit elaboration
- code from making entry calls (for example from another library level task),
- so we cannot tell in isolation that
- the task will not execute the accept statement during elaboration.
-
- However, in practice it is very unusual to see elaboration code
- make any entry calls, and the pattern of tasks starting
- at elaboration time and then immediately blocking on ``accept`` or
- ``select`` statements is very common. What this means is that
- the compiler is being too pessimistic when it analyzes the
- whole package body as though it might be executed at elaboration
- time.
-
- If we know that the elaboration code contains no entry calls, (a very safe
- assumption most of the time, that could almost be made the default
- behavior), then we can compile all units of the program under control
- of the following configuration pragma:
-
- .. code-block:: ada
-
- pragma Restrictions (No_Entry_Calls_In_Elaboration_Code);
-
- This pragma can be placed in the :file:`gnat.adc` file in the usual
- manner. If we take our original unmodified program and compile it
- in the presence of a :file:`gnat.adc` containing the above pragma,
- then once again, we can compile, bind, link, and execute, obtaining
- the expected result. In the presence of this pragma, the compiler does
- not trace calls in a task body, that appear after the first ``accept``
- or ``select`` statement, and therefore does not report a potential
- circularity in the original program.
-
- The compiler will check to the extent it can that the above
- restriction is not violated, but it is not always possible to do a
- complete check at compile time, so it is important to use this
- pragma only if the stated restriction is in fact met, that is to say
- no task receives an entry call before elaboration of all units is completed.
+ with Decls;
+ package Obj_Decls is -- new
+ Task_Obj : Decls.Lib_Task;
+ end Obj_Decls;
+ ::
-.. _Mixing_Elaboration_Models:
+ with Obj_Decls;
+ procedure Main is
+ begin
+ Obj_Decls.Task_Obj.Start; -- new
+ end Main;
-Mixing Elaboration Models
-=========================
+* *Use restriction No_Entry_Calls_In_Elaboration_Code*
+
+ The issue exhibited in the original example under this section revolves
+ around the body of ``Lib_Task`` blocking on an accept statement. There is
+ no rule to prevent elaboration code from performing entry calls, however in
+ practice this is highly unusual. In addition, the pattern of starting tasks
+ at elaboration time and then immediately blocking on accept or select
+ statements is quite common.
-So far, we have assumed that the entire program is either compiled
-using the dynamic model or static model, ensuring consistency. It
-is possible to mix the two models, but rules have to be followed
-if this mixing is done to ensure that elaboration checks are not
-omitted.
+ If a programmer knows that elaboration code will not perform any entry
+ calls, then the programmer can indicate that the static model should not
+ process the remainder of a task body once an accept or select statement has
+ been encountered. This behavior can be specified by a configuration pragma:
-The basic rule is that
-**a unit compiled with the static model cannot
-be |withed| by a unit compiled with the dynamic model**.
-The reason for this is that in the static model, a unit assumes that
-its clients guarantee to use (the equivalent of) pragma
-``Elaborate_All`` so that no elaboration checks are required
-in inner subprograms, and this assumption is violated if the
-client is compiled with dynamic checks.
+ ::
-The precise rule is as follows. A unit that is compiled with dynamic
-checks can only |with| a unit that meets at least one of the
-following criteria:
+ pragma Restrictions (No_Entry_Calls_In_Elaboration_Code);
+ In addition to the change in behavior with respect to task bodies, the
+ static model will verify that no entry calls take place at elaboration time.
-* The |withed| unit is itself compiled with dynamic elaboration
- checks (that is with the :switch:`-gnatE` switch.
+.. _Elaboration_Related_Compiler_Switches:
-* The |withed| unit is an internal GNAT implementation unit from
- the System, Interfaces, Ada, or GNAT hierarchies.
+Elaboration-related Compiler Switches
+=====================================
-* The |withed| unit has pragma Preelaborate or pragma Pure.
+GNAT has several switches that affect the elaboration model and consequently
+the elaboration order chosen by the binder.
-* The |withing| unit (that is the client) has an explicit pragma
- ``Elaborate_All`` for the |withed| unit.
+.. index:: -gnatdE (gnat)
+:switch:`-gnatdE`
+ Elaboration checks on predefined units
-If this rule is violated, that is if a unit with dynamic elaboration
-checks |withs| a unit that does not meet one of the above four
-criteria, then the binder (``gnatbind``) will issue a warning
-similar to that in the following example::
+ When this switch is in effect, GNAT will consider scenarios and targets that
+ come from the Ada, GNAT, Interfaces, and System hierarchies. This switch is
+ useful when a programmer has defined a custom grandchild of those packages.
- warning: "x.ads" has dynamic elaboration checks and with's
- warning: "y.ads" which has static elaboration checks
+.. index:: -gnatd.G (gnat)
-These warnings indicate that the rule has been violated, and that as a result
-elaboration checks may be missed in the resulting executable file.
-This warning may be suppressed using the :switch:`-ws` binder switch
-in the usual manner.
+:switch:`-gnatd.G`
+ Ignore calls through generic formal parameters for elaboration
-One useful application of this mixing rule is in the case of a subsystem
-which does not itself |with| units from the remainder of the
-application. In this case, the entire subsystem can be compiled with
-dynamic checks to resolve a circularity in the subsystem, while
-allowing the main application that uses this subsystem to be compiled
-using the more reliable default static model.
+ When this switch is in effect, GNAT will ignore calls that invoke generic
+ actual entries, operators, or subprograms via generic formal subprograms. As
+ a result, GNAT will not generate implicit ``Elaborate`` and ``Elaborate_All``
+ pragmas, and run-time checks for such calls. Note that this switch does not
+ overlap with :switch:`-gnatdL`.
+ ::
-.. _What_to_Do_If_the_Default_Elaboration_Behavior_Fails:
+ package body Ignore_Calls is
+ function ABE return Integer;
-What to Do If the Default Elaboration Behavior Fails
-====================================================
+ generic
+ with function Gen_Formal return Integer;
+ package Gen is
+ Val : constant Integer := Gen_Formal;
+ end Gen;
-If the binder cannot find an acceptable order, it outputs detailed
-diagnostics. For example::
+ package Inst is new Gen (ABE);
- error: elaboration circularity detected
- info: "proc (body)" must be elaborated before "pack (body)"
- info: reason: Elaborate_All probably needed in unit "pack (body)"
- info: recompile "pack (body)" with -gnatel
- info: for full details
- info: "proc (body)"
- info: is needed by its spec:
- info: "proc (spec)"
- info: which is withed by:
- info: "pack (body)"
- info: "pack (body)" must be elaborated before "proc (body)"
- info: reason: pragma Elaborate in unit "proc (body)"
+ function ABE return Integer is
+ begin
+ ...
+ end ABE;
+ end Ignore_Calls;
-In this case we have a cycle that the binder cannot break. On the one
-hand, there is an explicit pragma Elaborate in ``proc`` for
-``pack``. This means that the body of ``pack`` must be elaborated
-before the body of ``proc``. On the other hand, there is elaboration
-code in ``pack`` that calls a subprogram in ``proc``. This means
-that for maximum safety, there should really be a pragma
-Elaborate_All in ``pack`` for ``proc`` which would require that
-the body of ``proc`` be elaborated before the body of
-``pack``. Clearly both requirements cannot be satisfied.
-Faced with a circularity of this kind, you have three different options.
+ In the example above, the call to function ``ABE`` will be ignored because it
+ occurs during the elaboration of instance ``Inst``, through a call to generic
+ formal subprogram ``Gen_Formal``.
+.. index:: -gnatdL (gnat)
-* *Fix the program*
+:switch:`-gnatdL`
+ Ignore external calls from instances for elaboration
- The most desirable option from the point of view of long-term maintenance
- is to rearrange the program so that the elaboration problems are avoided.
- One useful technique is to place the elaboration code into separate
- child packages. Another is to move some of the initialization code to
- explicitly called subprograms, where the program controls the order
- of initialization explicitly. Although this is the most desirable option,
- it may be impractical and involve too much modification, especially in
- the case of complex legacy code.
-
-* *Perform dynamic checks*
-
- If the compilations are done using the :switch:`-gnatE`
- (dynamic elaboration check) switch, then GNAT behaves in a quite different
- manner. Dynamic checks are generated for all calls that could possibly result
- in raising an exception. With this switch, the compiler does not generate
- implicit ``Elaborate`` or ``Elaborate_All`` pragmas. The behavior then is
- exactly as specified in the :title:`Ada Reference Manual`.
- The binder will generate
- an executable program that may or may not raise ``Program_Error``, and then
- it is the programmer's job to ensure that it does not raise an exception. Note
- that it is important to compile all units with the switch, it cannot be used
- selectively.
-
-* *Suppress checks*
-
- The drawback of dynamic checks is that they generate a
- significant overhead at run time, both in space and time. If you
- are absolutely sure that your program cannot raise any elaboration
- exceptions, and you still want to use the dynamic elaboration model,
- then you can use the configuration pragma
- ``Suppress (Elaboration_Check)`` to suppress all such checks. For
- example this pragma could be placed in the :file:`gnat.adc` file.
-
-* *Suppress checks selectively*
-
- When you know that certain calls or instantiations in elaboration code cannot
- possibly lead to an elaboration error, and the binder nevertheless complains
- about implicit ``Elaborate`` and ``Elaborate_All`` pragmas that lead to
- elaboration circularities, it is possible to remove those warnings locally and
- obtain a program that will bind. Clearly this can be unsafe, and it is the
- responsibility of the programmer to make sure that the resulting program has no
- elaboration anomalies. The pragma ``Suppress (Elaboration_Check)`` can be
- used with different granularity to suppress warnings and break elaboration
- circularities:
-
- * Place the pragma that names the called subprogram in the declarative part
- that contains the call.
-
- * Place the pragma in the declarative part, without naming an entity. This
- disables warnings on all calls in the corresponding declarative region.
-
- * Place the pragma in the package spec that declares the called subprogram,
- and name the subprogram. This disables warnings on all elaboration calls to
- that subprogram.
-
- * Place the pragma in the package spec that declares the called subprogram,
- without naming any entity. This disables warnings on all elaboration calls to
- all subprograms declared in this spec.
-
- * Use Pragma Elaborate.
-
- As previously described in section :ref:`Treatment_of_Pragma_Elaborate`,
- GNAT in static mode assumes that a ``pragma`` Elaborate indicates correctly
- that no elaboration checks are required on calls to the designated unit.
- There may be cases in which the caller knows that no transitive calls
- can occur, so that a ``pragma Elaborate`` will be sufficient in a
- case where ``pragma Elaborate_All`` would cause a circularity.
-
- These five cases are listed in order of decreasing safety, and therefore
- require increasing programmer care in their application. Consider the
- following program:
-
- .. code-block:: ada
-
- package Pack1 is
- function F1 return Integer;
- X1 : Integer;
- end Pack1;
-
- package Pack2 is
- function F2 return Integer;
- function Pure (x : integer) return integer;
- -- pragma Suppress (Elaboration_Check, On => Pure); -- (3)
- -- pragma Suppress (Elaboration_Check); -- (4)
- end Pack2;
-
- with Pack2;
- package body Pack1 is
- function F1 return Integer is
- begin
- return 100;
- end F1;
- Val : integer := Pack2.Pure (11); -- Elab. call (1)
+ When this switch is in effect, GNAT will ignore calls that originate from
+ within an instance and directly target an entry, operator, or subprogram
+ defined outside the instance. As a result, GNAT will not generate implicit
+ ``Elaborate`` and ``Elaborate_All`` pragmas, and run-time checks for such
+ calls. Note that this switch does not overlap with :switch:`-gnatd.G`.
+
+ ::
+
+ package body Ignore_Calls is
+ function ABE return Integer;
+
+ generic
+ package Gen is
+ Val : constant Integer := ABE;
+ end Gen;
+
+ package Inst is new Gen;
+
+ function ABE return Integer is
begin
- declare
- -- pragma Suppress(Elaboration_Check, Pack2.F2); -- (1)
- -- pragma Suppress(Elaboration_Check); -- (2)
- begin
- X1 := Pack2.F2 + 1; -- Elab. call (2)
- end;
- end Pack1;
+ ...
+ end ABE;
+ end Ignore_Calls;
- with Pack1;
- package body Pack2 is
- function F2 return Integer is
- begin
- return Pack1.F1;
- end F2;
- function Pure (x : integer) return integer is
- begin
- return x ** 3 - 3 * x;
- end;
- end Pack2;
+ In the example above, the call to function ``ABE`` will be ignored because it
+ originates from within an instance and targets a subprogram defined outside
+ the instance.
+
+.. index:: -gnatd.o (gnat)
+
+:switch:`-gnatd.o`
+ Conservative elaboration order for indirect calls
+
+ When this switch is in effect, GNAT will treat ``'Access`` of an entry,
+ operator, or subprogram as an immediate call to that target. As a result,
+ GNAT will generate implicit ``Elaborate`` and ``Elaborate_All`` pragmas as
+ well as run-time checks for such attribute references.
+
+ ::
- with Pack1, Ada.Text_IO;
- procedure Proc3 is
+ 1. package body Attribute_Call is
+ 2. function Func return Integer;
+ 3. type Func_Ptr is access function return Integer;
+ 4.
+ 5. Ptr : constant Func_Ptr := Func'Access;
+ |
+ >>> warning: cannot call "Func" before body seen
+ >>> warning: Program_Error may be raised at run time
+ >>> warning: body of unit "Attribute_Call" elaborated
+ >>> warning: "Access" of "Func" taken at line 5
+ >>> warning: function "Func" called at line 5
+
+ 6.
+ 7. function Func return Integer is
+ 8. begin
+ 9. ...
+ 10. end Func;
+ 11. end Attribute_Call;
+
+ In the example above, the elaboration of declaration ``Ptr`` is assigned
+ ``Func'Access`` before the body of ``Func`` has been elaborated.
+
+.. index:: -gnatd.U (gnat)
+
+:switch:`-gnatd.U`
+ Ignore indirect calls for static elaboration
+
+ When this switch is in effect, GNAT will ignore ``'Access`` of an entry,
+ operator, or subprogram when the static model is in effect.
+
+.. index:: -gnatd.v (gnat)
+
+:switch:`-gnatd.v`
+ Enforce SPARK elaboration rules in SPARK code
+
+ When this switch is in effect, GNAT will enforce the SPARK rules of
+ elaboration as defined in the SPARK Reference Manual, section 7.7. As a
+ result, constructs which violate the SPARK elaboration rules are no longer
+ accepted, even if GNAT is able to statically ensure that these constructs
+ will not lead to ABE problems.
+
+.. index:: -gnatd.y (gnat)
+
+:switch:`-gnatd.y`
+ Disable implicit pragma Elaborate[_All] on task bodies
+
+ When this switch is in effect, GNAT will not generate ``Elaborate`` and
+ ``Elaborate_All`` pragmas if the need for the pragma came directly or
+ indirectly from a task body.
+
+ ::
+
+ with Server;
+ package body Disable_Task is
+ task T;
+
+ task body T is
begin
- Ada.Text_IO.Put_Line(Pack1.X1'Img); -- 101
- end Proc3;
-
- In the absence of any pragmas, an attempt to bind this program produces
- the following diagnostics::
-
- error: elaboration circularity detected
- info: "pack1 (body)" must be elaborated before "pack1 (body)"
- info: reason: Elaborate_All probably needed in unit "pack1 (body)"
- info: recompile "pack1 (body)" with -gnatel for full details
- info: "pack1 (body)"
- info: must be elaborated along with its spec:
- info: "pack1 (spec)"
- info: which is withed by:
- info: "pack2 (body)"
- info: which must be elaborated along with its spec:
- info: "pack2 (spec)"
- info: which is withed by:
- info: "pack1 (body)"
-
- The sources of the circularity are the two calls to ``Pack2.Pure`` and
- ``Pack2.F2`` in the body of ``Pack1``. We can see that the call to
- F2 is safe, even though F2 calls F1, because the call appears after the
- elaboration of the body of F1. Therefore the pragma (1) is safe, and will
- remove the warning on the call. It is also possible to use pragma (2)
- because there are no other potentially unsafe calls in the block.
-
- The call to ``Pure`` is safe because this function does not depend on the
- state of ``Pack2``. Therefore any call to this function is safe, and it
- is correct to place pragma (3) in the corresponding package spec.
-
- Finally, we could place pragma (4) in the spec of ``Pack2`` to disable
- warnings on all calls to functions declared therein. Note that this is not
- necessarily safe, and requires more detailed examination of the subprogram
- bodies involved. In particular, a call to ``F2`` requires that ``F1``
- be already elaborated.
-
-It is hard to generalize on which of these four approaches should be
-taken. Obviously if it is possible to fix the program so that the default
-treatment works, this is preferable, but this may not always be practical.
-It is certainly simple enough to use :switch:`-gnatE`
-but the danger in this case is that, even if the GNAT binder
-finds a correct elaboration order, it may not always do so,
-and certainly a binder from another Ada compiler might not. A
-combination of testing and analysis (for which the
-information messages generated with the :switch:`-gnatel`
-switch can be useful) must be used to ensure that the program is free
-of errors. One switch that is useful in this testing is the
-:switch:`-p` (pessimistic elaboration order) switch for ``gnatbind``.
-Normally the binder tries to find an order that has the best chance
-of avoiding elaboration problems. However, if this switch is used, the binder
-plays a devil's advocate role, and tries to choose the order that
-has the best chance of failing. If your program works even with this
-switch, then it has a better chance of being error free, but this is still
-not a guarantee.
-
-For an example of this approach in action, consider the C-tests (executable
-tests) from the ACATS suite. If these are compiled and run with the default
-treatment, then all but one of them succeed without generating any error
-diagnostics from the binder. However, there is one test that fails, and
-this is not surprising, because the whole point of this test is to ensure
-that the compiler can handle cases where it is impossible to determine
-a correct order statically, and it checks that an exception is indeed
-raised at run time.
-
-This one test must be compiled and run using the :switch:`-gnatE`
-switch, and then it passes. Alternatively, the entire suite can
-be run using this switch. It is never wrong to run with the dynamic
-elaboration switch if your code is correct, and we assume that the
-C-tests are indeed correct (it is less efficient, but efficiency is
-not a factor in running the ACATS tests.)
-
-
-.. _Elaboration_for_Indirect_Calls:
-
-Elaboration for Indirect Calls
-==============================
+ Server.Proc;
+ end T;
+ end Disable_Task;
+
+ In the example above, the activation of single task ``T`` invokes
+ ``Server.Proc``, which implies that ``Server`` requires ``Elaborate_All``,
+ however GNAT will not generate the pragma.
+
+.. index:: -gnatE (gnat)
+
+:switch:`-gnatE`
+ Dynamic elaboration checking mode enabled
+
+ When this switch is in effect, GNAT activates the dynamic elaboration model.
+
+.. index:: -gnatel (gnat)
+
+:switch:`-gnatel`
+ Turn on info messages on generated Elaborate[_All] pragmas
+
+ When this switch is in effect, GNAT will emit the following supplementary
+ information depending on the elaboration model in effect.
-.. index:: Dispatching calls
-.. index:: Indirect calls
+ - *Dynamic model*
-In rare cases, the static elaboration model fails to prevent
-dispatching calls to not-yet-elaborated subprograms. In such cases, we
-fall back to run-time checks; premature calls to any primitive
-operation of a tagged type before the body of the operation has been
-elaborated will raise ``Program_Error``.
+ GNAT will indicate missing ``Elaborate`` and ``Elaborate_All`` pragmas for
+ all library-level scenarios within the partition.
-Access-to-subprogram types, however, are handled conservatively in many
-cases. This was not true in earlier versions of the compiler; you can use
-the :switch:`-gnatd.U` debug switch to revert to the old behavior if the new
-conservative behavior causes elaboration cycles. Here, 'conservative' means
-that if you do ``P'Access`` during elaboration, the compiler will normally
-assume that you might call ``P`` indirectly during elaboration, so it adds an
-implicit ``pragma Elaborate_All`` on the library unit containing ``P``. The
-:switch:`-gnatd.U` switch is safe if you know there are no such calls. If the
-program worked before, it will continue to work with :switch:`-gnatd.U`. But beware
-that code modifications such as adding an indirect call can cause erroneous
-behavior in the presence of :switch:`-gnatd.U`.
+ - *Static model*
-These implicit Elaborate_All pragmas are not added in all cases, because
-they cause elaboration cycles in certain common code patterns. If you want
-even more conservative handling of P'Access, you can use the :switch:`-gnatd.o`
-switch.
+ GNAT will indicate all scenarios executed during elaboration. In addition,
+ it will provide detailed traceback when an implicit ``Elaborate`` or
+ ``Elaborate_All`` pragma is generated.
-See :file:`debug.adb` for documentation on the :switch:`-gnatd...` debug switches.
+ - *SPARK model*
+ GNAT will indicate how an elaboration requirement is met by the context of
+ a unit. This diagnostic requires compiler switch :switch:`-gnatd.v`.
+
+ ::
+
+ 1. with Server; pragma Elaborate_All (Server);
+ 2. package Client with SPARK_Mode is
+ 3. Val : constant Integer := Server.Func;
+ |
+ >>> info: call to "Func" during elaboration in SPARK
+ >>> info: "Elaborate_All" requirement for unit "Server" met by pragma at line 1
+
+ 4. end Client;
+
+.. index:: -gnatw.f (gnat)
+
+:switch:`-gnatw.f`
+ Turn on warnings for suspicious Subp'Access
+
+ When this switch is in effect, GNAT will treat ``'Access`` of an entry,
+ operator, or subprogram as a potential call to the target and issue warnings:
+
+ ::
+
+ 1. package body Attribute_Call is
+ 2. function Func return Integer;
+ 3. type Func_Ptr is access function return Integer;
+ 4.
+ 5. Ptr : constant Func_Ptr := Func'Access;
+ |
+ >>> warning: "Access" attribute of "Func" before body seen
+ >>> warning: possible Program_Error on later references
+ >>> warning: body of unit "Attribute_Call" elaborated
+ >>> warning: "Access" of "Func" taken at line 5
+
+ 6.
+ 7. function Func return Integer is
+ 8. begin
+ 9. ...
+ 10. end Func;
+ 11. end Attribute_Call;
+
+ In the example above, the elaboration of declaration ``Ptr`` is assigned
+ ``Func'Access`` before the body of ``Func`` has been elaborated.
.. _Summary_of_Procedures_for_Elaboration_Control:
Summary of Procedures for Elaboration Control
=============================================
-.. index:: Elaboration control
+A programmer should first compile the program with the default options, using
+none of the binder or compiler switches. If the binder succeeds in finding an
+elaboration order, then apart from possible cases involing dispatching calls
+and access-to-subprogram types, the program is free of elaboration errors.
+If it is important for the program to be portable to compilers other than GNAT,
+then the programmer should use compiler switch :switch:`-gnatel` and consider
+the messages about missing or implicitly created ``Elaborate`` and
+``Elaborate_All`` pragmas.
-First, compile your program with the default options, using none of
-the special elaboration-control switches. If the binder successfully
-binds your program, then you can be confident that, apart from issues
-raised by the use of access-to-subprogram types and dynamic dispatching,
-the program is free of elaboration errors. If it is important that the
-program be portable to other compilers than GNAT, then use the
-:switch:`-gnatel`
-switch to generate messages about missing ``Elaborate`` or
-``Elaborate_All`` pragmas, and supply the missing pragmas.
-
-If the program fails to bind using the default static elaboration
-handling, then you can fix the program to eliminate the binder
-message, or recompile the entire program with the
-:switch:`-gnatE` switch to generate dynamic elaboration checks,
-and, if you are sure there really are no elaboration problems,
-use a global pragma ``Suppress (Elaboration_Check)``.
-
-
-.. _Other_Elaboration_Order_Considerations:
-
-Other Elaboration Order Considerations
-======================================
-
-This section has been entirely concerned with the issue of finding a valid
-elaboration order, as defined by the Ada Reference Manual. In a case
-where several elaboration orders are valid, the task is to find one
-of the possible valid elaboration orders (and the static model in GNAT
-will ensure that this is achieved).
-
-The purpose of the elaboration rules in the Ada Reference Manual is to
-make sure that no entity is accessed before it has been elaborated. For
-a subprogram, this means that the spec and body must have been elaborated
-before the subprogram is called. For an object, this means that the object
-must have been elaborated before its value is read or written. A violation
-of either of these two requirements is an access before elaboration order,
-and this section has been all about avoiding such errors.
-
-In the case where more than one order of elaboration is possible, in the
-sense that access before elaboration errors are avoided, then any one of
-the orders is 'correct' in the sense that it meets the requirements of
-the Ada Reference Manual, and no such error occurs.
-
-However, it may be the case for a given program, that there are
-constraints on the order of elaboration that come not from consideration
-of avoiding elaboration errors, but rather from extra-lingual logic
-requirements. Consider this example:
-
-.. code-block:: ada
-
- with Init_Constants;
- package Constants is
- X : Integer := 0;
- Y : Integer := 0;
- end Constants;
-
- package Init_Constants is
- procedure P; --* require a body*
- end Init_Constants;
-
- with Constants;
- package body Init_Constants is
- procedure P is begin null; end;
- begin
- Constants.X := 3;
- Constants.Y := 4;
- end Init_Constants;
+If the binder reports an elaboration circularity, the programmer has several
+options:
- with Constants;
- package Calc is
- Z : Integer := Constants.X + Constants.Y;
- end Calc;
+* Ensure that warnings are enabled. This will allow the static model to output
+ trace information of elaboration issues. The trace information could shed
+ light on previously unforeseen dependencies, as well as their origins.
- with Calc;
- with Text_IO; use Text_IO;
- procedure Main is
- begin
- Put_Line (Calc.Z'Img);
- end Main;
+* Use switch :switch:`-gnatel` to obtain messages on generated implicit
+ ``Elaborate`` and ``Elaborate_All`` pragmas. The trace information could
+ indicate why a server unit must be elaborated prior to a client unit.
+
+* If the warnings produced by the static model indicate that a task is
+ involved, consider the options in the section on resolving task issues as
+ well as compiler switch :switch:`-gnatd.y`.
-In this example, there is more than one valid order of elaboration. For
-example both the following are correct orders::
+* If the warnings produced by the static model indicate that an generic
+ instantiations are involved, consider using compiler switches
+ :switch:`-gnatd.G` and :switch:`-gnatdL`.
- Init_Constants spec
- Constants spec
- Calc spec
- Init_Constants body
- Main body
+* If none of the steps outlined above resolve the circularity, recompile the
+ program using the dynamic model by using compiler switch :switch:`-gnatE`.
-and
+.. _Inspecting_the_Chosen_Elaboration_Order:
+
+Inspecting the Chosen Elaboration Order
+=======================================
+
+To see the elaboration order chosen by the binder, inspect the contents of file
+`b~xxx.adb`. On certain targets, this file appears as `b_xxx.adb`. The
+elaboration order appears as a sequence of calls to ``Elab_Body`` and
+``Elab_Spec``, interspersed with assignments to `Exxx` which indicates that a
+particular unit is elaborated. For example:
::
- Init_Constants spec
- Constants spec
- Init_Constants body
- Calc spec
- Main body
-
-There is no language rule to prefer one or the other, both are correct
-from an order of elaboration point of view. But the programmatic effects
-of the two orders are very different. In the first, the elaboration routine
-of ``Calc`` initializes ``Z`` to zero, and then the main program
-runs with this value of zero. But in the second order, the elaboration
-routine of ``Calc`` runs after the body of Init_Constants has set
-``X`` and ``Y`` and thus ``Z`` is set to 7 before ``Main`` runs.
-
-One could perhaps by applying pretty clever non-artificial intelligence
-to the situation guess that it is more likely that the second order of
-elaboration is the one desired, but there is no formal linguistic reason
-to prefer one over the other. In fact in this particular case, GNAT will
-prefer the second order, because of the rule that bodies are elaborated
-as soon as possible, but it's just luck that this is what was wanted
-(if indeed the second order was preferred).
-
-If the program cares about the order of elaboration routines in a case like
-this, it is important to specify the order required. In this particular
-case, that could have been achieved by adding to the spec of Calc:
-
-.. code-block:: ada
-
- pragma Elaborate_All (Constants);
-
-which requires that the body (if any) and spec of ``Constants``,
-as well as the body and spec of any unit |withed| by
-``Constants`` be elaborated before ``Calc`` is elaborated.
-
-Clearly no automatic method can always guess which alternative you require,
-and if you are working with legacy code that had constraints of this kind
-which were not properly specified by adding ``Elaborate`` or
-``Elaborate_All`` pragmas, then indeed it is possible that two different
-compilers can choose different orders.
-
-However, GNAT does attempt to diagnose the common situation where there
-are uninitialized variables in the visible part of a package spec, and the
-corresponding package body has an elaboration block that directly or
-indirectly initializes one or more of these variables. This is the situation
-in which a pragma Elaborate_Body is usually desirable, and GNAT will generate
-a warning that suggests this addition if it detects this situation.
-
-The ``gnatbind` :switch:`-p` switch may be useful in smoking
-out problems. This switch causes bodies to be elaborated as late as possible
-instead of as early as possible. In the example above, it would have forced
-the choice of the first elaboration order. If you get different results
-when using this switch, and particularly if one set of results is right,
-and one is wrong as far as you are concerned, it shows that you have some
-missing ``Elaborate`` pragmas. For the example above, we have the
-following output:
-
-.. code-block:: sh
-
- $ gnatmake -f -q main
- $ main
- 7
- $ gnatmake -f -q main -bargs -p
- $ main
- 0
-
-It is of course quite unlikely that both these results are correct, so
-it is up to you in a case like this to investigate the source of the
-difference, by looking at the two elaboration orders that are chosen,
-and figuring out which is correct, and then adding the necessary
-``Elaborate`` or ``Elaborate_All`` pragmas to ensure the desired order.
-
-
-.. _Determining_the_Chosen_Elaboration_Order:
-
-Determining the Chosen Elaboration Order
-========================================
+ System.Soft_Links'Elab_Body;
+ E14 := True;
+ System.Secondary_Stack'Elab_Body;
+ E18 := True;
+ System.Exception_Table'Elab_Body;
+ E24 := True;
+ Ada.Io_Exceptions'Elab_Spec;
+ E67 := True;
+ Ada.Tags'Elab_Spec;
+ Ada.Streams'Elab_Spec;
+ E43 := True;
+ Interfaces.C'Elab_Spec;
+ E69 := True;
+ System.Finalization_Root'Elab_Spec;
+ E60 := True;
+ System.Os_Lib'Elab_Body;
+ E71 := True;
+ System.Finalization_Implementation'Elab_Spec;
+ System.Finalization_Implementation'Elab_Body;
+ E62 := True;
+ Ada.Finalization'Elab_Spec;
+ E58 := True;
+ Ada.Finalization.List_Controller'Elab_Spec;
+ E76 := True;
+ System.File_Control_Block'Elab_Spec;
+ E74 := True;
+ System.File_Io'Elab_Body;
+ E56 := True;
+ Ada.Tags'Elab_Body;
+ E45 := True;
+ Ada.Text_Io'Elab_Spec;
+ Ada.Text_Io'Elab_Body;
+ E07 := True;
+
+Note also binder switch :switch:`-l`, which outputs the chosen elaboration
+order and provides a more readable form of the above:
+
+::
-To see the elaboration order that the binder chooses, you can look at
-the last part of the file:`b~xxx.adb` binder output file. Here is an example::
-
- System.Soft_Links'Elab_Body;
- E14 := True;
- System.Secondary_Stack'Elab_Body;
- E18 := True;
- System.Exception_Table'Elab_Body;
- E24 := True;
- Ada.Io_Exceptions'Elab_Spec;
- E67 := True;
- Ada.Tags'Elab_Spec;
- Ada.Streams'Elab_Spec;
- E43 := True;
- Interfaces.C'Elab_Spec;
- E69 := True;
- System.Finalization_Root'Elab_Spec;
- E60 := True;
- System.Os_Lib'Elab_Body;
- E71 := True;
- System.Finalization_Implementation'Elab_Spec;
- System.Finalization_Implementation'Elab_Body;
- E62 := True;
- Ada.Finalization'Elab_Spec;
- E58 := True;
- Ada.Finalization.List_Controller'Elab_Spec;
- E76 := True;
- System.File_Control_Block'Elab_Spec;
- E74 := True;
- System.File_Io'Elab_Body;
- E56 := True;
- Ada.Tags'Elab_Body;
- E45 := True;
- Ada.Text_Io'Elab_Spec;
- Ada.Text_Io'Elab_Body;
- E07 := True;
-
-Here Elab_Spec elaborates the spec
-and Elab_Body elaborates the body. The assignments to the :samp:`E{xx}` flags
-flag that the corresponding body is now elaborated.
-
-You can also ask the binder to generate a more
-readable list of the elaboration order using the
-:switch:`-l` switch when invoking the binder. Here is
-an example of the output generated by this switch::
-
- ada (spec)
- interfaces (spec)
- system (spec)
- system.case_util (spec)
- system.case_util (body)
- system.concat_2 (spec)
- system.concat_2 (body)
- system.concat_3 (spec)
- system.concat_3 (body)
- system.htable (spec)
- system.parameters (spec)
- system.parameters (body)
- system.crtl (spec)
- interfaces.c_streams (spec)
- interfaces.c_streams (body)
- system.restrictions (spec)
- system.restrictions (body)
- system.standard_library (spec)
- system.exceptions (spec)
- system.exceptions (body)
- system.storage_elements (spec)
- system.storage_elements (body)
- system.secondary_stack (spec)
- system.stack_checking (spec)
- system.stack_checking (body)
- system.string_hash (spec)
- system.string_hash (body)
- system.htable (body)
- system.strings (spec)
- system.strings (body)
- system.traceback (spec)
- system.traceback (body)
- system.traceback_entries (spec)
- system.traceback_entries (body)
- ada.exceptions (spec)
- ada.exceptions.last_chance_handler (spec)
- system.soft_links (spec)
- system.soft_links (body)
- ada.exceptions.last_chance_handler (body)
- system.secondary_stack (body)
- system.exception_table (spec)
- system.exception_table (body)
- ada.io_exceptions (spec)
- ada.tags (spec)
- ada.streams (spec)
- interfaces.c (spec)
- interfaces.c (body)
- system.finalization_root (spec)
- system.finalization_root (body)
- system.memory (spec)
- system.memory (body)
- system.standard_library (body)
- system.os_lib (spec)
- system.os_lib (body)
- system.unsigned_types (spec)
- system.stream_attributes (spec)
- system.stream_attributes (body)
- system.finalization_implementation (spec)
- system.finalization_implementation (body)
- ada.finalization (spec)
- ada.finalization (body)
- ada.finalization.list_controller (spec)
- ada.finalization.list_controller (body)
- system.file_control_block (spec)
- system.file_io (spec)
- system.file_io (body)
- system.val_uns (spec)
- system.val_util (spec)
- system.val_util (body)
- system.val_uns (body)
- system.wch_con (spec)
- system.wch_con (body)
- system.wch_cnv (spec)
- system.wch_jis (spec)
- system.wch_jis (body)
- system.wch_cnv (body)
- system.wch_stw (spec)
- system.wch_stw (body)
- ada.tags (body)
- ada.exceptions (body)
- ada.text_io (spec)
- ada.text_io (body)
- text_io (spec)
- gdbstr (body)
+ ada (spec)
+ interfaces (spec)
+ system (spec)
+ system.case_util (spec)
+ system.case_util (body)
+ system.concat_2 (spec)
+ system.concat_2 (body)
+ system.concat_3 (spec)
+ system.concat_3 (body)
+ system.htable (spec)
+ system.parameters (spec)
+ system.parameters (body)
+ system.crtl (spec)
+ interfaces.c_streams (spec)
+ interfaces.c_streams (body)
+ system.restrictions (spec)
+ system.restrictions (body)
+ system.standard_library (spec)
+ system.exceptions (spec)
+ system.exceptions (body)
+ system.storage_elements (spec)
+ system.storage_elements (body)
+ system.secondary_stack (spec)
+ system.stack_checking (spec)
+ system.stack_checking (body)
+ system.string_hash (spec)
+ system.string_hash (body)
+ system.htable (body)
+ system.strings (spec)
+ system.strings (body)
+ system.traceback (spec)
+ system.traceback (body)
+ system.traceback_entries (spec)
+ system.traceback_entries (body)
+ ada.exceptions (spec)
+ ada.exceptions.last_chance_handler (spec)
+ system.soft_links (spec)
+ system.soft_links (body)
+ ada.exceptions.last_chance_handler (body)
+ system.secondary_stack (body)
+ system.exception_table (spec)
+ system.exception_table (body)
+ ada.io_exceptions (spec)
+ ada.tags (spec)
+ ada.streams (spec)
+ interfaces.c (spec)
+ interfaces.c (body)
+ system.finalization_root (spec)
+ system.finalization_root (body)
+ system.memory (spec)
+ system.memory (body)
+ system.standard_library (body)
+ system.os_lib (spec)
+ system.os_lib (body)
+ system.unsigned_types (spec)
+ system.stream_attributes (spec)
+ system.stream_attributes (body)
+ system.finalization_implementation (spec)
+ system.finalization_implementation (body)
+ ada.finalization (spec)
+ ada.finalization (body)
+ ada.finalization.list_controller (spec)
+ ada.finalization.list_controller (body)
+ system.file_control_block (spec)
+ system.file_io (spec)
+ system.file_io (body)
+ system.val_uns (spec)
+ system.val_util (spec)
+ system.val_util (body)
+ system.val_uns (body)
+ system.wch_con (spec)
+ system.wch_con (body)
+ system.wch_cnv (spec)
+ system.wch_jis (spec)
+ system.wch_jis (body)
+ system.wch_cnv (body)
+ system.wch_stw (spec)
+ system.wch_stw (body)
+ ada.tags (body)
+ ada.exceptions (body)
+ ada.text_io (spec)
+ ada.text_io (body)
+ text_io (spec)
+ gdbstr (body)
diff --git a/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst b/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
index 952cc3d..8f9f37c 100644
--- a/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
+++ b/gcc/ada/doc/gnat_ugn/gnat_and_program_execution.rst
@@ -3513,7 +3513,7 @@ However, incorrect assignments such as:
.. code-block:: ada
Distance := 5.0;
- Distance := 5.0 * kg:
+ Distance := 5.0 * kg;
are rejected with the following diagnoses:
@@ -3556,7 +3556,7 @@ aspect.
.. index:: Dimension Vector (for a dimensioned subtype)
.. index:: Dimension aspect
.. index:: Dimension_System aspect
-
+
The ``Dimension`` aspect of a dimensioned subtype ``S`` defines a mapping
from the base type's Unit_Names to integer (or, more generally, rational)
values. This mapping is the *dimension vector* (also referred to as the
@@ -3575,8 +3575,8 @@ means that the unit is not used. For example:
end;
Here ``DV(Acc)`` = ``DV(Acceleration)`` =
-``(Meter=>1, Kilogram=>0, Second => -2, Ampere=>0, Kelvin=>0, Mole=>0, Candela => 0)``.
-Symbolically, we can express this as ``Meter / Second**2``.
+``(Meter=>1, Kilogram=>0, Second=>-2, Ampere=>0, Kelvin=>0, Mole=>0, Candela=>0)``.
+Symbolically, we can express this as ``Meter / Second**2``.
The dimension vector of an arithmetic expression is synthesized from the
dimension vectors of its components, with compile-time dimensionality checks
@@ -3593,7 +3593,7 @@ mathematical definitions for the vector operations that are used:
* :samp:`DV({op expr})`, where *op* is a unary operator, is :samp:`DV({expr})`
* :samp:`DV({expr1 op expr2})` where *op* is "+" or "-" is :samp:`DV({expr1})`
- provided that :samp:`DV({expr1})` = :samp:`DV({expr2})`.
+ provided that :samp:`DV({expr1})` = :samp:`DV({expr2})`.
If this condition is not met then the construct is illegal.
* :samp:`DV({expr1} * {expr2})` is :samp:`DV({expr1})` + :samp:`DV({expr2})`,
@@ -3611,20 +3611,26 @@ combine a dimensioned and dimensionless value. Thus an expression such as
``Acceleration``.
The dimensionality checks for relationals use the same rules as
-for "+" and "-"; thus
+for "+" and "-", except when comparing to a literal; thus
.. code-block:: ada
- acc > 10.0
+ acc > len
is equivalent to
.. code-block:: ada
- acc-10.0 > 0.0
+ acc-len > 0.0
+
+and is thus illegal, but
+
+ .. code-block:: ada
+
+ acc > 10.0
-and is thus illegal. Analogously a conditional expression
-requires the same dimension vector for each branch.
+is accepted with a warning. Analogously a conditional expression requires the
+same dimension vector for each branch (with no exception for literals).
The dimension vector of a type conversion :samp:`T({expr})` is defined
as follows, based on the nature of ``T``:
@@ -3648,7 +3654,7 @@ as follows, based on the nature of ``T``:
Thus, if *expr* is of a dimensioned subtype of ``T``, the conversion may
be regarded as a "view conversion" that preserves dimensionality.
- This rule makes it possible to write generic code that can be instantiated
+ This rule makes it possible to write generic code that can be instantiated
with compatible dimensioned subtypes. The generic unit will contain
conversions that will consequently be present in instantiations, but
conversions to the base type will preserve dimensionality and make it
@@ -3663,10 +3669,10 @@ as follows, based on the nature of ``T``:
The dimension vector for a type qualification :samp:`T'({expr})` is the same
as for the type conversion :samp:`T({expr})`.
-An assignment statement
+An assignment statement
.. code-block:: ada
-
+
Source := Target;
requires ``DV(Source)`` = ``DV(Target)``, and analogously for parameter
@@ -4093,9 +4099,8 @@ execution of this erroneous program:
``gnatmem`` makes use of the output created by the special version of
allocation and deallocation routines that record call information. This allows
it to obtain accurate dynamic memory usage history at a minimal cost to the
- execution speed. Note however, that ``gnatmem`` is not supported on all
- platforms (currently, it is supported on AIX, HP-UX, GNU/Linux, Solaris and
- Windows).
+ execution speed. Note however, that ``gnatmem`` is only supported on
+ GNU/Linux and Windows.
The ``gnatmem`` command has the form
diff --git a/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst b/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst
index 9136350..855bb8f 100644
--- a/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst
+++ b/gcc/ada/doc/gnat_ugn/gnat_utility_programs.rst
@@ -365,7 +365,7 @@ Switches for ``gnatls``
.. index:: --RTS (gnatls)
-:switch:`--RTS={rts-path}``
+:switch:`--RTS={rts-path}`
Specifies the default location of the runtime library. Same meaning as the
equivalent ``gnatmake`` flag (:ref:`Switches_for_gnatmake`).
@@ -586,9 +586,9 @@ The following switches are available for ``gnatxref``:
:switch:`--ext={extension}`
Specify an alternate ali file extension. The default is ``ali`` and other
- extensions (e.g. ``gli`` for C/C++ sources when using :switch:`-fdump-xref`)
- may be specified via this switch. Note that if this switch overrides the
- default, which means that only the new extension will be considered.
+ extensions (e.g. ``gli`` for C/C++ sources) may be specified via this switch.
+ Note that if this switch overrides the default, which means that only the
+ new extension will be considered.
.. index:: --RTS (gnatxref)
diff --git a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
index 8c3b074..248bf8e 100644
--- a/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
+++ b/gcc/ada/doc/gnat_ugn/the_gnat_compilation_model.rst
@@ -1569,7 +1569,7 @@ depend on a file that no longer exists. Such tools include
If you are using project file, a separate mechanism is provided using
project attributes.
-.. --Comment:
+.. --Comment
See :ref:`Specifying_Configuration_Pragmas` for more details.
diff --git a/gcc/ada/doc/share/conf.py b/gcc/ada/doc/share/conf.py
index 173648b..e6fafcf 100644
--- a/gcc/ada/doc/share/conf.py
+++ b/gcc/ada/doc/share/conf.py
@@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
+# Style_Check:Python_Fragment (meaning no pyflakes check)
#
# GNAT build configuration file
diff --git a/gcc/ada/einfo.adb b/gcc/ada/einfo.adb
index 21d8838..01d64f3 100644
--- a/gcc/ada/einfo.adb
+++ b/gcc/ada/einfo.adb
@@ -170,6 +170,7 @@ package body Einfo is
-- Extra_Accessibility_Of_Result Node19
-- Non_Limited_View Node19
-- Parent_Subtype Node19
+ -- Receiving_Entry Node19
-- Size_Check_Code Node19
-- Spec_Entity Node19
-- Underlying_Full_View Node19
@@ -275,6 +276,9 @@ package body Einfo is
-- Validated_Object Node36
-- Class_Wide_Clone Node38
+
+ -- Protected_Subprogram Node39
+
-- SPARK_Pragma Node40
-- Original_Protected_Subprogram Node41
@@ -449,7 +453,7 @@ package body Einfo is
-- Strict_Alignment Flag145
-- Is_Abstract_Type Flag146
-- Needs_Debug_Info Flag147
- -- Suppress_Elaboration_Warnings Flag148
+ -- Is_Elaboration_Checks_OK_Id Flag148
-- Is_Compilation_Unit Flag149
-- Has_Pragma_Elaborate_Body Flag150
@@ -619,7 +623,8 @@ package body Einfo is
-- Has_Private_Extension Flag300
-- Ignore_SPARK_Mode_Pragmas Flag301
- -- (unused) Flag302
+ -- Is_Initial_Condition_Procedure Flag302
+
-- (unused) Flag303
-- (unused) Flag304
-- (unused) Flag305
@@ -2237,6 +2242,17 @@ package body Einfo is
return Flag6 (Id);
end Is_Dispatching_Operation;
+ function Is_Elaboration_Checks_OK_Id (Id : E) return B is
+ begin
+ pragma Assert
+ (Ekind_In (Id, E_Constant, E_Variable)
+ or else Is_Entry (Id)
+ or else Is_Generic_Unit (Id)
+ or else Is_Subprogram (Id)
+ or else Is_Task_Type (Id));
+ return Flag148 (Id);
+ end Is_Elaboration_Checks_OK_Id;
+
function Is_Eliminated (Id : E) return B is
begin
return Flag124 (Id);
@@ -2364,6 +2380,12 @@ package body Einfo is
return Flag268 (Id);
end Is_Independent;
+ function Is_Initial_Condition_Procedure (Id : E) return B is
+ begin
+ pragma Assert (Ekind_In (Id, E_Function, E_Procedure));
+ return Flag302 (Id);
+ end Is_Initial_Condition_Procedure;
+
function Is_Inlined (Id : E) return B is
begin
return Flag11 (Id);
@@ -2371,7 +2393,7 @@ package body Einfo is
function Is_Inlined_Always (Id : E) return B is
begin
- pragma Assert (Ekind (Id) = E_Function or else Ekind (Id) = E_Procedure);
+ pragma Assert (Ekind_In (Id, E_Function, E_Procedure));
return Flag1 (Id);
end Is_Inlined_Always;
@@ -3084,10 +3106,18 @@ package body Einfo is
return Node22 (Id);
end Protected_Formal;
+ function Protected_Subprogram (Id : E) return N is
+ begin
+ pragma Assert (Ekind_In (Id, E_Function, E_Procedure));
+ return Node39 (Id);
+ end Protected_Subprogram;
+
function Protection_Object (Id : E) return E is
begin
- pragma Assert
- (Ekind_In (Id, E_Entry, E_Entry_Family, E_Function, E_Procedure));
+ pragma Assert (Ekind_In (Id, E_Entry,
+ E_Entry_Family,
+ E_Function,
+ E_Procedure));
return Node23 (Id);
end Protection_Object;
@@ -3096,6 +3126,12 @@ package body Einfo is
return Flag49 (Id);
end Reachable;
+ function Receiving_Entry (Id : E) return E is
+ begin
+ pragma Assert (Ekind (Id) = E_Procedure);
+ return Node19 (Id);
+ end Receiving_Entry;
+
function Referenced (Id : E) return B is
begin
return Flag156 (Id);
@@ -3306,6 +3342,9 @@ package body Einfo is
E_Task_Body,
E_Task_Type)
or else
+ Ekind_In (Id, E_Constant, -- object variants
+ E_Variable)
+ or else
Ekind_In (Id, E_Entry, -- overloadable variants
E_Entry_Family,
E_Function,
@@ -3319,7 +3358,7 @@ package body Einfo is
E_Package,
E_Package_Body)
or else
- Ekind (Id) = E_Variable); -- variable
+ Ekind (Id) = E_Void); -- special purpose
return Node40 (Id);
end SPARK_Pragma;
@@ -3330,7 +3369,10 @@ package body Einfo is
E_Protected_Type,
E_Task_Body,
E_Task_Type)
- or else
+ or else
+ Ekind_In (Id, E_Constant, -- object variants
+ E_Variable)
+ or else
Ekind_In (Id, E_Entry, -- overloadable variants
E_Entry_Family,
E_Function,
@@ -3344,7 +3386,7 @@ package body Einfo is
E_Package,
E_Package_Body)
or else
- Ekind (Id) = E_Variable); -- variable
+ Ekind (Id) = E_Void); -- special purpose
return Flag265 (Id);
end SPARK_Pragma_Inherited;
@@ -3444,11 +3486,6 @@ package body Einfo is
return Uint24 (Id);
end Subps_Index;
- function Suppress_Elaboration_Warnings (Id : E) return B is
- begin
- return Flag148 (Id);
- end Suppress_Elaboration_Warnings;
-
function Suppress_Initialization (Id : E) return B is
begin
pragma Assert (Is_Type (Id) or else Ekind (Id) = E_Variable);
@@ -5397,6 +5434,17 @@ package body Einfo is
Set_Flag6 (Id, V);
end Set_Is_Dispatching_Operation;
+ procedure Set_Is_Elaboration_Checks_OK_Id (Id : E; V : B := True) is
+ begin
+ pragma Assert
+ (Ekind_In (Id, E_Constant, E_Variable)
+ or else Is_Entry (Id)
+ or else Is_Generic_Unit (Id)
+ or else Is_Subprogram (Id)
+ or else Is_Task_Type (Id));
+ Set_Flag148 (Id, V);
+ end Set_Is_Elaboration_Checks_OK_Id;
+
procedure Set_Is_Eliminated (Id : E; V : B := True) is
begin
Set_Flag124 (Id, V);
@@ -5526,6 +5574,12 @@ package body Einfo is
Set_Flag268 (Id, V);
end Set_Is_Independent;
+ procedure Set_Is_Initial_Condition_Procedure (Id : E; V : B := True) is
+ begin
+ pragma Assert (Ekind_In (Id, E_Function, E_Procedure));
+ Set_Flag302 (Id, V);
+ end Set_Is_Initial_Condition_Procedure;
+
procedure Set_Is_Inlined (Id : E; V : B := True) is
begin
Set_Flag11 (Id, V);
@@ -5533,7 +5587,7 @@ package body Einfo is
procedure Set_Is_Inlined_Always (Id : E; V : B := True) is
begin
- pragma Assert (Ekind (Id) = E_Function or else Ekind (Id) = E_Procedure);
+ pragma Assert (Ekind_In (Id, E_Function, E_Procedure));
Set_Flag1 (Id, V);
end Set_Is_Inlined_Always;
@@ -6264,6 +6318,12 @@ package body Einfo is
Set_Node22 (Id, V);
end Set_Protected_Formal;
+ procedure Set_Protected_Subprogram (Id : E; V : E) is
+ begin
+ pragma Assert (Ekind_In (Id, E_Function, E_Procedure));
+ Set_Node39 (Id, V);
+ end Set_Protected_Subprogram;
+
procedure Set_Protection_Object (Id : E; V : E) is
begin
pragma Assert (Ekind_In (Id, E_Entry,
@@ -6278,6 +6338,12 @@ package body Einfo is
Set_Flag49 (Id, V);
end Set_Reachable;
+ procedure Set_Receiving_Entry (Id : E; V : E) is
+ begin
+ pragma Assert (Ekind (Id) = E_Procedure);
+ Set_Node19 (Id, V);
+ end Set_Receiving_Entry;
+
procedure Set_Referenced (Id : E; V : B := True) is
begin
Set_Flag156 (Id, V);
@@ -6491,7 +6557,10 @@ package body Einfo is
E_Protected_Type,
E_Task_Body,
E_Task_Type)
- or else
+ or else
+ Ekind_In (Id, E_Constant, -- object variants
+ E_Variable)
+ or else
Ekind_In (Id, E_Entry, -- overloadable variants
E_Entry_Family,
E_Function,
@@ -6505,7 +6574,7 @@ package body Einfo is
E_Package,
E_Package_Body)
or else
- Ekind (Id) = E_Variable); -- variable
+ Ekind (Id) = E_Void); -- special purpose
Set_Node40 (Id, V);
end Set_SPARK_Pragma;
@@ -6516,7 +6585,10 @@ package body Einfo is
E_Protected_Type,
E_Task_Body,
E_Task_Type)
- or else
+ or else
+ Ekind_In (Id, E_Constant, -- object variants
+ E_Variable)
+ or else
Ekind_In (Id, E_Entry, -- overloadable variants
E_Entry_Family,
E_Function,
@@ -6530,7 +6602,7 @@ package body Einfo is
E_Package,
E_Package_Body)
or else
- Ekind (Id) = E_Variable); -- variable
+ Ekind (Id) = E_Void); -- special purpose
Set_Flag265 (Id, V);
end Set_SPARK_Pragma_Inherited;
@@ -6639,11 +6711,6 @@ package body Einfo is
Set_Uint24 (Id, V);
end Set_Subps_Index;
- procedure Set_Suppress_Elaboration_Warnings (Id : E; V : B := True) is
- begin
- Set_Flag148 (Id, V);
- end Set_Suppress_Elaboration_Warnings;
-
procedure Set_Suppress_Initialization (Id : E; V : B := True) is
begin
pragma Assert (Is_Type (Id) or else Ekind (Id) = E_Variable);
@@ -7707,12 +7774,17 @@ package body Einfo is
-----------------------------
function Has_Null_Abstract_State (Id : E) return B is
- begin
pragma Assert (Ekind_In (Id, E_Generic_Package, E_Package));
+ States : constant Elist_Id := Abstract_States (Id);
+
+ begin
+ -- Check first available state of related package. A null abstract
+ -- state always appears as the sole element of the state list.
+
return
- Present (Abstract_States (Id))
- and then Is_Null_State (Node (First_Elmt (Abstract_States (Id))));
+ Present (States)
+ and then Is_Null_State (Node (First_Elmt (States)));
end Has_Null_Abstract_State;
---------------------------------
@@ -9557,6 +9629,7 @@ package body Einfo is
W ("Is_Discriminant_Check_Function", Flag264 (Id));
W ("Is_Dispatch_Table_Entity", Flag234 (Id));
W ("Is_Dispatching_Operation", Flag6 (Id));
+ W ("Is_Elaboration_Checks_OK_Id", Flag148 (Id));
W ("Is_Eliminated", Flag124 (Id));
W ("Is_Entry_Formal", Flag52 (Id));
W ("Is_Exception_Handler", Flag286 (Id));
@@ -9579,6 +9652,7 @@ package body Einfo is
W ("Is_Implementation_Defined", Flag254 (Id));
W ("Is_Imported", Flag24 (Id));
W ("Is_Independent", Flag268 (Id));
+ W ("Is_Initial_Condition_Procedure", Flag302 (Id));
W ("Is_Inlined", Flag11 (Id));
W ("Is_Inlined_Always", Flag1 (Id));
W ("Is_Instantiated", Flag126 (Id));
@@ -9691,7 +9765,6 @@ package body Einfo is
W ("Static_Elaboration_Desired", Flag77 (Id));
W ("Stores_Attribute_Old_Prefix", Flag270 (Id));
W ("Strict_Alignment", Flag145 (Id));
- W ("Suppress_Elaboration_Warnings", Flag148 (Id));
W ("Suppress_Initialization", Flag105 (Id));
W ("Suppress_Style_Checks", Flag165 (Id));
W ("Suppress_Value_Tracking_On_Call", Flag217 (Id));
@@ -10394,6 +10467,9 @@ package body Einfo is
when E_Record_Type =>
Write_Str ("Parent_Subtype");
+ when E_Procedure =>
+ Write_Str ("Receiving_Entry");
+
when E_Constant
| E_Variable
=>
@@ -11084,6 +11160,11 @@ package body Einfo is
procedure Write_Field39_Name (Id : Entity_Id) is
begin
case Ekind (Id) is
+ when E_Function
+ | E_Procedure
+ =>
+ Write_Str ("Protected_Subprogram");
+
when others =>
Write_Str ("Field39??");
end case;
@@ -11096,7 +11177,8 @@ package body Einfo is
procedure Write_Field40_Name (Id : Entity_Id) is
begin
case Ekind (Id) is
- when E_Entry
+ when E_Constant
+ | E_Entry
| E_Entry_Family
| E_Function
| E_Generic_Function
@@ -11112,6 +11194,7 @@ package body Einfo is
| E_Task_Body
| E_Task_Type
| E_Variable
+ | E_Void
=>
Write_Str ("SPARK_Pragma");
diff --git a/gcc/ada/einfo.ads b/gcc/ada/einfo.ads
index 13bf620..bfe14fc 100644
--- a/gcc/ada/einfo.ads
+++ b/gcc/ada/einfo.ads
@@ -1312,9 +1312,9 @@ package Einfo is
-- that represents an activation record pointer is an extra formal.
-- Extra_Formals (Node28)
--- Applies to subprograms and subprogram types, and also to entries
--- and entry families. Returns first extra formal of the subprogram
--- or entry. Returns Empty if there are no extra formals.
+-- Applies to subprograms, subprogram types, entries, and entry
+-- families. Returns first extra formal of the subprogram or entry.
+-- Returns Empty if there are no extra formals.
-- Finalization_Master (Node23) [root type only]
-- Defined in access-to-controlled or access-to-class-wide types. The
@@ -2198,13 +2198,6 @@ package Einfo is
-- Rep_Item chain mechanism, because a single pragma Import can apply
-- to multiple subprogram entities).
--- Incomplete_Actuals (Elist24)
--- Defined on package entities that are instances. Indicates the actuals
--- types in the instantiation that are limited views. If this list is
--- not empty, the instantiation, which appears in a package declaration,
--- is relocated to the corresponding package body, which must have a
--- corresponding nonlimited with_clause.
-
-- In_Package_Body (Flag48)
-- Defined in package entities. Set on the entity that denotes the
-- package (the defining occurrence of the package declaration) while
@@ -2218,6 +2211,13 @@ package Einfo is
-- the end of the package declaration. For objects it indicates that the
-- declaration of the object occurs in the private part of a package.
+-- Incomplete_Actuals (Elist24)
+-- Defined on package entities that are instances. Indicates the actuals
+-- types in the instantiation that are limited views. If this list is
+-- not empty, the instantiation, which appears in a package declaration,
+-- is relocated to the corresponding package body, which must have a
+-- corresponding nonlimited with_clause.
+
-- Initialization_Statements (Node28)
-- Defined in constants and variables. For a composite object initialized
-- initialized with an aggregate that has been converted to a sequence
@@ -2504,13 +2504,19 @@ package Einfo is
-- Is_Dynamic_Scope (synthesized)
-- Applies to all Entities. Returns True if the entity is a dynamic
--- scope (i.e. a block, subprogram, task_type, entry
--- or extended return statement).
+-- scope (i.e. a block, subprogram, task_type, entry or extended return
+-- statement).
+
+-- Is_Elaboration_Checks_OK_Id (Flag148)
+-- Defined in elaboration targets (see terminology in Sem_Elab). Set when
+-- the target appears in a region which is subject to elabled elaboration
+-- checks. Such targets are allowed to generate run-time conditional ABE
+-- checks or guaranteed ABE failures.
-- Is_Elementary_Type (synthesized)
--- Applies to all entities, true for all elementary types and
--- subtypes. Either Is_Composite_Type or Is_Elementary_Type (but
--- not both) is true of any type.
+-- Applies to all entities, true for all elementary types and subtypes.
+-- Either Is_Composite_Type or Is_Elementary_Type (but not both) is true
+-- of any type.
-- Is_Eliminated (Flag124)
-- Defined in type entities, subprogram entities, and object entities.
@@ -2703,6 +2709,10 @@ package Einfo is
-- and incomplete types, this flag is set in both the partial view and
-- the full view.
+-- Is_Initial_Condition_Procedure (Flag302)
+-- Defined in functions and procedures. Set for a generated procedure
+-- which verifies the assumption of pragma Initial_Condition at run time.
+
-- Is_Inlined (Flag11)
-- Defined in all entities. Set for functions and procedures which are
-- to be inlined. For subprograms created during expansion, this flag
@@ -2746,7 +2756,7 @@ package Einfo is
-- 1) Internal entities (such as temporaries generated for the result
-- of an inlined function call or dummy variables generated for the
-- debugger). Set to indicate that they need not be initialized, even
--- when scalars are initialized or normalized;
+-- when scalars are initialized or normalized.
--
-- 2) Predefined primitives of tagged types. Set to mark that they
-- have specific properties: first they are primitives even if they
@@ -3958,6 +3968,11 @@ package Einfo is
-- formal parameter in the unprotected version of the operation that
-- is created during expansion.
+-- Protected_Subprogram (Node39)
+-- Defined in functions and procedures. Set for the pair of subprograms
+-- which emulate the runtime semantics of a protected subprogram. Denotes
+-- the entity of the origial protected subprogram.
+
-- Protection_Object (Node23)
-- Applies to protected entries, entry families and subprograms. Denotes
-- the entity which is used to rename the _object component of protected
@@ -3967,6 +3982,11 @@ package Einfo is
-- Defined in labels. The flag is set over the range of statements in
-- which a goto to that label is legal.
+-- Receiving_Entry (Node19)
+-- Defined in procedures. Set for an internally generated procedure which
+-- wraps the original statements of an accept alternative. Designates the
+-- entity of the task entry being accepted.
+
-- Referenced (Flag156)
-- Defined in all entities. Set if the entity is referenced, except for
-- the case of an appearance of a simple variable that is not a renaming
@@ -4038,10 +4058,10 @@ package Einfo is
-- in a Relative_Deadline pragma for a task type.
-- Renamed_Entity (Node18)
--- Defined in exceptions, packages, subprograms, and generic units. Set
--- for entities that are defined by a renaming declaration. Denotes the
--- renamed entity, or transitively the ultimate renamed entity if
--- there is a chain of renaming declarations. Empty if no renaming.
+-- Defined in exception, generic unit, package, and subprogram entities.
+-- Set when the entity is defined by a renaming declaration. Denotes the
+-- renamed entity, or transitively the ultimate renamed entity if there
+-- is a chain of renaming declarations. Empty if no renaming.
-- Renamed_In_Spec (Flag231)
-- Defined in package entities. If a package renaming occurs within
@@ -4256,20 +4276,20 @@ package Einfo is
-- inherited, rather than a local one.
-- SPARK_Pragma (Node40)
--- Present in concurrent type, entry, operator, [generic] package,
--- package body, [generic] subprogram, subprogram body and variable
--- entities. Points to the N_Pragma node that applies to the initial
--- declaration or body. This is either set by a local SPARK_Mode pragma
--- or is inherited from the context (from an outer scope for the spec
--- case or from the spec for the body case). In the case where it is
--- inherited the flag SPARK_Pragma_Inherited is set. Empty if no
+-- Present in concurrent type, constant, entry, operator, [generic]
+-- package, package body, [generic] subprogram, subprogram body and
+-- variable entities. Points to the N_Pragma node that applies to the
+-- initial declaration or body. This is either set by a local SPARK_Mode
+-- pragma or is inherited from the context (from an outer scope for the
+-- spec case or from the spec for the body case). In the case where it
+-- is inherited the flag SPARK_Pragma_Inherited is set. Empty if no
-- SPARK_Mode pragma is applicable.
-- SPARK_Pragma_Inherited (Flag265)
--- Present in concurrent type, entry, operator, [generic] package,
--- package body, [generic] subprogram, subprogram body and variable
--- entities. Set if the SPARK_Pragma attribute points to a pragma that is
--- inherited, rather than a local one.
+-- Present in concurrent type, constant, entry, operator, [generic]
+-- package, package body, [generic] subprogram, subprogram body and
+-- variable entities. Set if the SPARK_Pragma attribute points to a
+-- pragma that is inherited, rather than a local one.
-- Spec_Entity (Node19)
-- Defined in package body entities. Points to corresponding package
@@ -4395,17 +4415,6 @@ package Einfo is
-- for the outer level subprogram, this is the starting index in the Subp
-- table for the entries for this subprogram.
--- Suppress_Elaboration_Warnings (Flag148)
--- Defined in all entities, can be set only for subprogram entities and
--- for variables. If this flag is set then Sem_Elab will not generate
--- elaboration warnings for the subprogram or variable. Suppression of
--- such warnings is automatic for subprograms for which elaboration
--- checks are suppressed (without the need to set this flag), but the
--- flag is also set for various internal entities (such as init procs)
--- which are known not to generate any possible access before
--- elaboration, and it is set on variables when a warning is given to
--- avoid multiple elaboration warnings for the same variable.
-
-- Suppress_Initialization (Flag105)
-- Defined in all variable, type and subtype entities. If set for a base
-- type, then the generation of initialization procedures is suppressed
@@ -5565,7 +5574,6 @@ package Einfo is
-- Referenced (Flag156)
-- Referenced_As_LHS (Flag36)
-- Referenced_As_Out_Parameter (Flag227)
- -- Suppress_Elaboration_Warnings (Flag148)
-- Suppress_Style_Checks (Flag165)
-- Suppress_Value_Tracking_On_Call (Flag217)
-- Used_As_Generic_Actual (Flag222)
@@ -5869,6 +5877,7 @@ package Einfo is
-- Encapsulating_State (Node32) (constants only)
-- Linker_Section_Pragma (Node33)
-- Contract (Node34) (constants only)
+ -- SPARK_Pragma (Node40) (constants only)
-- Has_Alignment_Clause (Flag46)
-- Has_Atomic_Components (Flag86)
-- Has_Biased_Representation (Flag139)
@@ -5878,6 +5887,7 @@ package Einfo is
-- Has_Thunks (Flag228) (constants only)
-- Has_Volatile_Components (Flag87)
-- Is_Atomic (Flag85)
+ -- Is_Elaboration_Checks_OK_Id (Flag148) (constants only)
-- Is_Eliminated (Flag124)
-- Is_Finalized_Transient (Flag252)
-- Is_Ignored_Transient (Flag295)
@@ -5889,6 +5899,7 @@ package Einfo is
-- Is_Volatile_Full_Access (Flag285)
-- Optimize_Alignment_Space (Flag241) (constants only)
-- Optimize_Alignment_Time (Flag242) (constants only)
+ -- SPARK_Pragma_Inherited (Flag265) (constants only)
-- Stores_Attribute_Old_Prefix (Flag270) (constants only)
-- Treat_As_Volatile (Flag41)
-- Address_Clause (synth)
@@ -5953,6 +5964,7 @@ package Einfo is
-- Entry_Accepted (Flag152)
-- Has_Expanded_Contract (Flag240)
-- Ignore_SPARK_Mode_Pragmas (Flag301)
+ -- Is_Elaboration_Checks_OK_Id (Flag148)
-- Is_Entry_Wrapper (Flag297)
-- Needs_No_Actuals (Flag22)
-- Sec_Stack_Needed_For_Return (Flag167)
@@ -6065,6 +6077,7 @@ package Einfo is
-- Contract (Node34)
-- Import_Pragma (Node35) (non-generic case only)
-- Class_Wide_Clone (Node38)
+ -- Protected_Subprogram (Node39) (non-generic case only)
-- SPARK_Pragma (Node40)
-- Original_Protected_Subprogram (Node41)
-- Body_Needed_For_SAL (Flag40)
@@ -6090,9 +6103,11 @@ package Einfo is
-- Is_DIC_Procedure (Flag132) (non-generic case only)
-- Is_Discrim_SO_Function (Flag176)
-- Is_Discriminant_Check_Function (Flag264)
+ -- Is_Elaboration_Checks_OK_Id (Flag148)
-- Is_Eliminated (Flag124)
-- Is_Generic_Actual_Subprogram (Flag274) (non-generic case only)
-- Is_Hidden_Non_Overridden_Subpgm (Flag2) (non-generic case only)
+ -- Is_Initial_Condition_Procedure (Flag302) (non-generic case only)
-- Is_Inlined_Always (Flag1) (non-generic case only)
-- Is_Instantiated (Flag126) (generic case only)
-- Is_Intrinsic_Subprogram (Flag64)
@@ -6238,6 +6253,7 @@ package Einfo is
-- Default_Expressions_Processed (Flag108)
-- Has_Nested_Subprogram (Flag282)
-- Ignore_SPARK_Mode_Pragmas (Flag301)
+ -- Is_Elaboration_Checks_OK_Id (Flag148)
-- Is_Intrinsic_Subprogram (Flag64)
-- Is_Machine_Code_Subprogram (Flag137)
-- Is_Primitive (Flag218)
@@ -6304,6 +6320,7 @@ package Einfo is
-- Ignore_SPARK_Mode_Pragmas (Flag301)
-- In_Package_Body (Flag48)
-- In_Use (Flag8)
+ -- Is_Elaboration_Checks_OK_Id (Flag148)
-- Is_Instantiated (Flag126)
-- Is_Private_Descendant (Flag53)
-- Is_Visible_Lib_Unit (Flag116)
@@ -6362,6 +6379,7 @@ package Einfo is
-- First_Entity (Node17)
-- Alias (Node18) (non-generic case only)
-- Renamed_Entity (Node18) (generic case only)
+ -- Receiving_Entry (Node19) (non-generic case only)
-- Last_Entity (Node20)
-- Interface_Name (Node21)
-- Scope_Depth_Value (Uint22)
@@ -6381,6 +6399,7 @@ package Einfo is
-- Contract (Node34)
-- Import_Pragma (Node35) (non-generic case only)
-- Class_Wide_Clone (Node38)
+ -- Protected_Subprogram (Node39) (non-generic case only)
-- SPARK_Pragma (Node40)
-- Original_Protected_Subprogram (Node41)
-- Body_Needed_For_SAL (Flag40)
@@ -6403,9 +6422,11 @@ package Einfo is
-- Is_Called (Flag102) (non-generic case only)
-- Is_Constructor (Flag76)
-- Is_DIC_Procedure (Flag132) (non-generic case only)
+ -- Is_Elaboration_Checks_OK_Id (Flag148)
-- Is_Eliminated (Flag124)
-- Is_Generic_Actual_Subprogram (Flag274) (non-generic case only)
-- Is_Hidden_Non_Overridden_Subpgm (Flag2) (non-generic case only)
+ -- Is_Initial_Condition_Procedure (Flag302) (non-generic case only)
-- Is_Inlined_Always (Flag1) (non-generic case only)
-- Is_Instantiated (Flag126) (generic case only)
-- Is_Interrupt_Handler (Flag89)
@@ -6614,6 +6635,7 @@ package Einfo is
-- Has_Master_Entity (Flag21)
-- Has_Storage_Size_Clause (Flag23) (base type only)
-- Ignore_SPARK_Mode_Pragmas (Flag301)
+ -- Is_Elaboration_Checks_OK_Id (Flag148)
-- SPARK_Aux_Pragma_Inherited (Flag266)
-- SPARK_Pragma_Inherited (Flag265)
-- First_Component (synth)
@@ -6662,6 +6684,7 @@ package Einfo is
-- Has_Size_Clause (Flag29)
-- Has_Volatile_Components (Flag87)
-- Is_Atomic (Flag85)
+ -- Is_Elaboration_Checks_OK_Id (Flag148)
-- Is_Eliminated (Flag124)
-- Is_Finalized_Transient (Flag252)
-- Is_Ignored_Transient (Flag295)
@@ -7179,6 +7202,7 @@ package Einfo is
function Is_Discriminant_Check_Function (Id : E) return B;
function Is_Dispatch_Table_Entity (Id : E) return B;
function Is_Dispatching_Operation (Id : E) return B;
+ function Is_Elaboration_Checks_OK_Id (Id : E) return B;
function Is_Eliminated (Id : E) return B;
function Is_Entry_Formal (Id : E) return B;
function Is_Entry_Wrapper (Id : E) return B;
@@ -7198,6 +7222,7 @@ package Einfo is
function Is_Implementation_Defined (Id : E) return B;
function Is_Imported (Id : E) return B;
function Is_Independent (Id : E) return B;
+ function Is_Initial_Condition_Procedure (Id : E) return B;
function Is_Inlined (Id : E) return B;
function Is_Inlined_Always (Id : E) return B;
function Is_Instantiated (Id : E) return B;
@@ -7322,8 +7347,10 @@ package Einfo is
function Private_View (Id : E) return N;
function Protected_Body_Subprogram (Id : E) return E;
function Protected_Formal (Id : E) return E;
+ function Protected_Subprogram (Id : E) return N;
function Protection_Object (Id : E) return E;
function Reachable (Id : E) return B;
+ function Receiving_Entry (Id : E) return E;
function Referenced (Id : E) return B;
function Referenced_As_LHS (Id : E) return B;
function Referenced_As_Out_Parameter (Id : E) return B;
@@ -7376,7 +7403,6 @@ package Einfo is
function String_Literal_Low_Bound (Id : E) return N;
function Subprograms_For_Type (Id : E) return L;
function Subps_Index (Id : E) return U;
- function Suppress_Elaboration_Warnings (Id : E) return B;
function Suppress_Initialization (Id : E) return B;
function Suppress_Style_Checks (Id : E) return B;
function Suppress_Value_Tracking_On_Call (Id : E) return B;
@@ -7868,6 +7894,7 @@ package Einfo is
procedure Set_Is_Discriminant_Check_Function (Id : E; V : B := True);
procedure Set_Is_Dispatch_Table_Entity (Id : E; V : B := True);
procedure Set_Is_Dispatching_Operation (Id : E; V : B := True);
+ procedure Set_Is_Elaboration_Checks_OK_Id (Id : E; V : B := True);
procedure Set_Is_Eliminated (Id : E; V : B := True);
procedure Set_Is_Entry_Formal (Id : E; V : B := True);
procedure Set_Is_Entry_Wrapper (Id : E; V : B := True);
@@ -7891,6 +7918,7 @@ package Einfo is
procedure Set_Is_Implementation_Defined (Id : E; V : B := True);
procedure Set_Is_Imported (Id : E; V : B := True);
procedure Set_Is_Independent (Id : E; V : B := True);
+ procedure Set_Is_Initial_Condition_Procedure (Id : E; V : B := True);
procedure Set_Is_Inlined (Id : E; V : B := True);
procedure Set_Is_Inlined_Always (Id : E; V : B := True);
procedure Set_Is_Instantiated (Id : E; V : B := True);
@@ -8015,8 +8043,10 @@ package Einfo is
procedure Set_Private_View (Id : E; V : N);
procedure Set_Protected_Body_Subprogram (Id : E; V : E);
procedure Set_Protected_Formal (Id : E; V : E);
+ procedure Set_Protected_Subprogram (Id : E; V : N);
procedure Set_Protection_Object (Id : E; V : E);
procedure Set_Reachable (Id : E; V : B := True);
+ procedure Set_Receiving_Entry (Id : E; V : E);
procedure Set_Referenced (Id : E; V : B := True);
procedure Set_Referenced_As_LHS (Id : E; V : B := True);
procedure Set_Referenced_As_Out_Parameter (Id : E; V : B := True);
@@ -8069,7 +8099,6 @@ package Einfo is
procedure Set_String_Literal_Low_Bound (Id : E; V : N);
procedure Set_Subprograms_For_Type (Id : E; V : L);
procedure Set_Subps_Index (Id : E; V : U);
- procedure Set_Suppress_Elaboration_Warnings (Id : E; V : B := True);
procedure Set_Suppress_Initialization (Id : E; V : B := True);
procedure Set_Suppress_Style_Checks (Id : E; V : B := True);
procedure Set_Suppress_Value_Tracking_On_Call (Id : E; V : B := True);
@@ -8690,6 +8719,7 @@ package Einfo is
pragma Inline (Is_Discriminant_Check_Function);
pragma Inline (Is_Dispatch_Table_Entity);
pragma Inline (Is_Dispatching_Operation);
+ pragma Inline (Is_Elaboration_Checks_OK_Id);
pragma Inline (Is_Elementary_Type);
pragma Inline (Is_Eliminated);
pragma Inline (Is_Entry);
@@ -8725,6 +8755,7 @@ package Einfo is
pragma Inline (Is_Incomplete_Or_Private_Type);
pragma Inline (Is_Incomplete_Type);
pragma Inline (Is_Independent);
+ pragma Inline (Is_Initial_Condition_Procedure);
pragma Inline (Is_Inlined);
pragma Inline (Is_Inlined_Always);
pragma Inline (Is_Instantiated);
@@ -8868,8 +8899,10 @@ package Einfo is
pragma Inline (Private_View);
pragma Inline (Protected_Body_Subprogram);
pragma Inline (Protected_Formal);
+ pragma Inline (Protected_Subprogram);
pragma Inline (Protection_Object);
pragma Inline (Reachable);
+ pragma Inline (Receiving_Entry);
pragma Inline (Referenced);
pragma Inline (Referenced_As_LHS);
pragma Inline (Referenced_As_Out_Parameter);
@@ -8922,7 +8955,6 @@ package Einfo is
pragma Inline (String_Literal_Low_Bound);
pragma Inline (Subprograms_For_Type);
pragma Inline (Subps_Index);
- pragma Inline (Suppress_Elaboration_Warnings);
pragma Inline (Suppress_Initialization);
pragma Inline (Suppress_Style_Checks);
pragma Inline (Suppress_Value_Tracking_On_Call);
@@ -9200,6 +9232,7 @@ package Einfo is
pragma Inline (Set_Is_Discriminant_Check_Function);
pragma Inline (Set_Is_Dispatch_Table_Entity);
pragma Inline (Set_Is_Dispatching_Operation);
+ pragma Inline (Set_Is_Elaboration_Checks_OK_Id);
pragma Inline (Set_Is_Eliminated);
pragma Inline (Set_Is_Entry_Formal);
pragma Inline (Set_Is_Entry_Wrapper);
@@ -9223,6 +9256,7 @@ package Einfo is
pragma Inline (Set_Is_Implementation_Defined);
pragma Inline (Set_Is_Imported);
pragma Inline (Set_Is_Independent);
+ pragma Inline (Set_Is_Initial_Condition_Procedure);
pragma Inline (Set_Is_Inlined);
pragma Inline (Set_Is_Inlined_Always);
pragma Inline (Set_Is_Instantiated);
@@ -9348,8 +9382,10 @@ package Einfo is
pragma Inline (Set_Private_View);
pragma Inline (Set_Protected_Body_Subprogram);
pragma Inline (Set_Protected_Formal);
+ pragma Inline (Set_Protected_Subprogram);
pragma Inline (Set_Protection_Object);
pragma Inline (Set_Reachable);
+ pragma Inline (Set_Receiving_Entry);
pragma Inline (Set_Referenced);
pragma Inline (Set_Referenced_As_LHS);
pragma Inline (Set_Referenced_As_Out_Parameter);
@@ -9402,7 +9438,6 @@ package Einfo is
pragma Inline (Set_String_Literal_Low_Bound);
pragma Inline (Set_Subprograms_For_Type);
pragma Inline (Set_Subps_Index);
- pragma Inline (Set_Suppress_Elaboration_Warnings);
pragma Inline (Set_Suppress_Initialization);
pragma Inline (Set_Suppress_Style_Checks);
pragma Inline (Set_Suppress_Value_Tracking_On_Call);
@@ -9435,9 +9470,12 @@ package Einfo is
pragma Inline (Base_Type);
pragma Inline (Is_Base_Type);
+ pragma Inline (Is_Boolean_Type);
pragma Inline (Is_Controlled);
+ pragma Inline (Is_Entity_Name);
pragma Inline (Is_Package_Or_Generic_Package);
pragma Inline (Is_Packed_Array);
+ pragma Inline (Is_String_Type);
pragma Inline (Is_Subprogram_Or_Generic_Subprogram);
pragma Inline (Is_Volatile);
pragma Inline (Is_Wrapper_Package);
diff --git a/gcc/ada/errout.adb b/gcc/ada/errout.adb
index ce99fd8..a402c68 100644
--- a/gcc/ada/errout.adb
+++ b/gcc/ada/errout.adb
@@ -1813,7 +1813,7 @@ package body Errout is
-- the Main_Source line is unknown (this happens in error situations,
-- e.g. when integrated preprocessing fails).
- if Main_Source_File /= No_Source_File then
+ if Main_Source_File > No_Source_File then
Write_Str (" ");
Write_Int (Num_Source_Lines (Main_Source_File));
@@ -1938,7 +1938,7 @@ package body Errout is
-- Source_Reference. This ensures outputting the proper name of
-- the source file in this situation.
- if Main_Source_File = No_Source_File
+ if Main_Source_File <= No_Source_File
or else Num_SRef_Pragmas (Main_Source_File) /= 0
then
Current_Error_Source_File := No_Source_File;
@@ -2045,7 +2045,7 @@ package body Errout is
-- Only write the header if Sfile is known
- if Sfile /= No_Source_File then
+ if Sfile > No_Source_File then
Write_Header (Sfile);
Write_Eol;
end if;
@@ -2066,7 +2066,7 @@ package body Errout is
-- Only output the listing if Sfile is known, to avoid
-- crashing the compiler.
- if Sfile /= No_Source_File then
+ if Sfile > No_Source_File then
for N in 1 .. Last_Source_Line (Sfile) loop
while E /= No_Error_Msg
and then Errors.Table (E).Deleted
@@ -2141,7 +2141,7 @@ package body Errout is
-- Output the header only when Main_Source_File is known
- if Main_Source_File /= No_Source_File then
+ if Main_Source_File > No_Source_File then
Write_Header (Main_Source_File);
end if;
diff --git a/gcc/ada/erroutc.adb b/gcc/ada/erroutc.adb
index f81d337..b77d53d 100644
--- a/gcc/ada/erroutc.adb
+++ b/gcc/ada/erroutc.adb
@@ -41,7 +41,7 @@ with Output; use Output;
with Sinput; use Sinput;
with Snames; use Snames;
with Stringt; use Stringt;
-with Targparm; use Targparm;
+with Targparm;
with Uintp; use Uintp;
with Widechar; use Widechar;
diff --git a/gcc/ada/exp_aggr.adb b/gcc/ada/exp_aggr.adb
index 2fa0dc5..86621a4 100644
--- a/gcc/ada/exp_aggr.adb
+++ b/gcc/ada/exp_aggr.adb
@@ -175,6 +175,10 @@ package body Exp_Aggr is
-- Local subprograms for Record Aggregate Expansion --
------------------------------------------------------
+ function Is_Build_In_Place_Aggregate_Return (N : Node_Id) return Boolean;
+ -- True if N is an aggregate (possibly qualified or converted) that is
+ -- being returned from a build-in-place function.
+
function Build_Record_Aggr_Code
(N : Node_Id;
Typ : Entity_Id;
@@ -186,10 +190,9 @@ package body Exp_Aggr is
-- types.
procedure Convert_To_Assignments (N : Node_Id; Typ : Entity_Id);
- -- N is an N_Aggregate or an N_Extension_Aggregate. Typ is the type of the
- -- aggregate (which can only be a record type, this procedure is only used
- -- for record types). Transform the given aggregate into a sequence of
- -- assignments performed component by component.
+ -- Transform a record aggregate into a sequence of assignments performed
+ -- component by component. N is an N_Aggregate or N_Extension_Aggregate.
+ -- Typ is the type of the record aggregate.
procedure Expand_Record_Aggregate
(N : Node_Id;
@@ -762,10 +765,10 @@ package body Exp_Aggr is
-- Checks 5 (if the component type is tagged, then we may need to do
-- tag adjustments. Perhaps this should be refined to check for any
-- component associations that actually need tag adjustment, similar
- -- to the test in Component_Not_OK_For_Backend for record aggregates
- -- with tagged components, but not clear whether it's worthwhile ???;
- -- in the case of virtual machines (no Tagged_Type_Expansion), object
- -- tags are handled implicitly).
+ -- to the test in Component_OK_For_Backend for record aggregates with
+ -- tagged components, but not clear whether it's worthwhile ???; in the
+ -- case of virtual machines (no Tagged_Type_Expansion), object tags are
+ -- handled implicitly).
if Is_Tagged_Type (Component_Type (Typ))
and then Tagged_Type_Expansion
@@ -1248,6 +1251,7 @@ package body Exp_Aggr is
if Finalization_OK
and then not Is_Limited_Type (Comp_Typ)
+ and then not Is_Build_In_Place_Function_Call (Init_Expr)
and then not
(Is_Array_Type (Comp_Typ)
and then Is_Controlled (Component_Type (Comp_Typ))
@@ -1347,7 +1351,7 @@ package body Exp_Aggr is
In_Place_Expansion :=
Nkind (Expr) = N_Function_Call
- and then not Is_Limited_Type (Comp_Typ);
+ and then not Is_Build_In_Place_Result_Type (Comp_Typ);
-- The initialization expression is a controlled function call.
-- Perform in-place removal of side effects to avoid creating a
@@ -2725,7 +2729,6 @@ package body Exp_Aggr is
Selector_Name => New_Occurrence_Of (Discr, Loc)),
Expression => New_Copy_Tree (Discr_Val));
- Set_No_Ctrl_Actions (Discr_Init);
Append_To (List, Discr_Init);
end if;
@@ -2763,7 +2766,6 @@ package body Exp_Aggr is
Name => Comp_Expr,
Expression => New_Copy_Tree (Discriminant_Value));
- Set_No_Ctrl_Actions (Instr);
Append_To (L, Instr);
Next_Discriminant (Discriminant);
@@ -2795,7 +2797,6 @@ package body Exp_Aggr is
Name => Comp_Expr,
Expression => New_Copy_Tree (Discriminant_Value));
- Set_No_Ctrl_Actions (Instr);
Append_To (L, Instr);
Next_Stored_Discriminant (Discriminant);
@@ -2834,7 +2835,7 @@ package body Exp_Aggr is
In_Place_Expansion :=
Nkind (Init_Expr) = N_Function_Call
- and then not Is_Limited_Type (Comp_Typ);
+ and then not Is_Build_In_Place_Result_Type (Comp_Typ);
-- The initialization expression is a controlled function call.
-- Perform in-place removal of side effects to avoid creating a
@@ -2970,7 +2971,10 @@ package body Exp_Aggr is
-- [Deep_]Adjust (Rec_Comp);
- if Finalization_OK and then not Is_Limited_Type (Comp_Typ) then
+ if Finalization_OK
+ and then not Is_Limited_Type (Comp_Typ)
+ and then not Is_Build_In_Place_Function_Call (Init_Expr)
+ then
Adj_Call :=
Make_Adjust_Call
(Obj_Ref => New_Copy_Tree (Rec_Comp),
@@ -3232,12 +3236,8 @@ package body Exp_Aggr is
-- Ada 2005 (AI-287): If the ancestor part is an aggregate of
-- limited type, a recursive call expands the ancestor. Note that
-- in the limited case, the ancestor part must be either a
- -- function call (possibly qualified, or wrapped in an unchecked
- -- conversion) or aggregate (definitely qualified).
-
- -- The ancestor part can also be a function call (that may be
- -- transformed into an explicit dereference) or a qualification
- -- of one such.
+ -- function call (possibly qualified) or aggregate (definitely
+ -- qualified).
elsif Is_Limited_Type (Etype (Ancestor))
and then Nkind_In (Unqualify (Ancestor), N_Aggregate,
@@ -3333,6 +3333,7 @@ package body Exp_Aggr is
if Needs_Finalization (Etype (Ancestor))
and then not Is_Limited_Type (Etype (Ancestor))
+ and then not Is_Build_In_Place_Function_Call (Ancestor)
then
Adj_Call :=
Make_Adjust_Call
@@ -3354,6 +3355,10 @@ package body Exp_Aggr is
Check_Ancestor_Discriminants (Init_Typ);
end if;
end if;
+
+ pragma Assert (Nkind (N) = N_Extension_Aggregate);
+ pragma Assert
+ (not (Ancestor_Is_Expression and Ancestor_Is_Subtype_Mark));
end;
-- Generate assignments of hidden discriminants. If the base type is
@@ -4076,10 +4081,7 @@ package body Exp_Aggr is
and then Ekind (Current_Scope) /= E_Return_Statement
and then not Is_Limited_Type (Typ)
then
- Establish_Transient_Scope
- (Aggr,
- Sec_Stack =>
- Is_Controlled (Typ) or else Has_Controlled_Component (Typ));
+ Establish_Transient_Scope (Aggr, Sec_Stack => False);
end if;
declare
@@ -4137,6 +4139,7 @@ package body Exp_Aggr is
Parent_Node : Node_Id;
begin
+ pragma Assert (Nkind_In (N, N_Aggregate, N_Extension_Aggregate));
pragma Assert (not Is_Static_Dispatch_Table_Aggregate (N));
pragma Assert (Is_Record_Type (Typ));
@@ -4144,10 +4147,9 @@ package body Exp_Aggr is
Parent_Kind := Nkind (Parent_Node);
if Parent_Kind = N_Qualified_Expression then
-
- -- Check if we are in a unconstrained declaration because in this
+ -- Check if we are in an unconstrained declaration because in this
-- case the current delayed expansion mechanism doesn't work when
- -- the declared object size depend on the initializing expr.
+ -- the declared object size depends on the initializing expr.
Parent_Node := Parent (Parent_Node);
Parent_Kind := Nkind (Parent_Node);
@@ -4155,8 +4157,10 @@ package body Exp_Aggr is
if Parent_Kind = N_Object_Declaration then
Unc_Decl :=
not Is_Entity_Name (Object_Definition (Parent_Node))
- or else Has_Discriminants
- (Entity (Object_Definition (Parent_Node)))
+ or else (Nkind (N) = N_Aggregate
+ and then
+ Has_Discriminants
+ (Entity (Object_Definition (Parent_Node))))
or else Is_Class_Wide_Type
(Entity (Object_Definition (Parent_Node)));
end if;
@@ -4198,11 +4202,7 @@ package body Exp_Aggr is
-- finalization of the return object (which is built in place
-- within the caller's scope).
- or else
- (Is_Limited_View (Typ)
- and then
- (Nkind (Parent (Parent_Node)) = N_Extended_Return_Statement
- or else Nkind (Parent_Node) = N_Simple_Return_Statement))
+ or else Is_Build_In_Place_Aggregate_Return (N)
then
Set_Expansion_Delayed (N);
return;
@@ -4217,7 +4217,7 @@ package body Exp_Aggr is
-- Should the condition be more restrictive ???
if Requires_Transient_Scope (Typ) and then not Inside_Init_Proc then
- Establish_Transient_Scope (N, Sec_Stack => Needs_Finalization (Typ));
+ Establish_Transient_Scope (N, Sec_Stack => False);
end if;
-- If the aggregate is nonlimited, create a temporary. If it is limited
@@ -6114,8 +6114,7 @@ package body Exp_Aggr is
-- for default initialization, e.g. with Initialize_Scalars.
if Requires_Transient_Scope (Typ) then
- Establish_Transient_Scope
- (N, Sec_Stack => Has_Controlled_Component (Typ));
+ Establish_Transient_Scope (N, Sec_Stack => False);
end if;
if Has_Default_Init_Comps (N) then
@@ -6254,7 +6253,7 @@ package body Exp_Aggr is
if Ekind (Current_Scope) = E_Loop
and then Nkind (Parent (Parent (N))) = N_Allocator
then
- Establish_Transient_Scope (N, False);
+ Establish_Transient_Scope (N, Sec_Stack => False);
end if;
Insert_Action (N, Tmp_Decl);
@@ -6649,14 +6648,14 @@ package body Exp_Aggr is
-- If the ancestor part is an expression, add a component association for
-- the parent field. If the type of the ancestor part is not the direct
- -- parent of the expected type, build recursively the needed ancestors.
- -- If the ancestor part is a subtype_mark, replace aggregate with a decla-
- -- ration for a temporary of the expected type, followed by individual
- -- assignments to the given components.
+ -- parent of the expected type, build recursively the needed ancestors.
+ -- If the ancestor part is a subtype_mark, replace aggregate with a
+ -- declaration for a temporary of the expected type, followed by
+ -- individual assignments to the given components.
procedure Expand_N_Extension_Aggregate (N : Node_Id) is
- Loc : constant Source_Ptr := Sloc (N);
A : constant Node_Id := Ancestor_Part (N);
+ Loc : constant Source_Ptr := Sloc (N);
Typ : constant Entity_Id := Etype (N);
begin
@@ -6712,7 +6711,7 @@ package body Exp_Aggr is
Static_Components : Boolean := True;
-- Flag to indicate whether all components are compile-time known,
-- and the aggregate can be constructed statically and handled by
- -- the back-end.
+ -- the back-end. Set to False by Component_OK_For_Backend.
procedure Build_Back_End_Aggregate;
-- Build a proper aggregate to be handled by the back-end
@@ -6725,7 +6724,7 @@ package body Exp_Aggr is
-- This returns true for N_Aggregate with Compile_Time_Known_Aggregate
-- set and constants whose expression is such an aggregate, recursively.
- function Component_Not_OK_For_Backend return Boolean;
+ function Component_OK_For_Backend return Boolean;
-- Check for presence of a component which makes it impossible for the
-- backend to process the aggregate, thus requiring the use of a series
-- of assignment statements. Cases checked for are a nested aggregate
@@ -6744,6 +6743,9 @@ package body Exp_Aggr is
-- in order to minimize elaboration code. This is one case where the
-- semantics of Ada complicate the analysis and lead to anomalies in
-- the gcc back-end if the aggregate is not expanded into assignments.
+ --
+ -- NOTE: This sets the global Static_Components to False in most, but
+ -- not all, cases when it returns False.
function Has_Per_Object_Constraint (L : List_Id) return Boolean;
-- Return True if any element of L has Has_Per_Object_Constraint set.
@@ -7046,7 +7048,7 @@ package body Exp_Aggr is
-- The ancestor part may be a nested aggregate that has
-- delayed expansion: recheck now.
- if Component_Not_OK_For_Backend then
+ if not Component_OK_For_Backend then
Convert_To_Assignments (N, Typ);
end if;
end;
@@ -7113,17 +7115,17 @@ package body Exp_Aggr is
end Compile_Time_Known_Composite_Value;
- ----------------------------------
- -- Component_Not_OK_For_Backend --
- ----------------------------------
+ ------------------------------
+ -- Component_OK_For_Backend --
+ ------------------------------
- function Component_Not_OK_For_Backend return Boolean is
+ function Component_OK_For_Backend return Boolean is
C : Node_Id;
Expr_Q : Node_Id;
begin
if No (Comps) then
- return False;
+ return True;
end if;
C := First (Comps);
@@ -7133,7 +7135,7 @@ package body Exp_Aggr is
-- and component is not ready for backend.
if Box_Present (C) then
- return True;
+ return False;
end if;
if Nkind (Expression (C)) = N_Qualified_Expression then
@@ -7142,7 +7144,7 @@ package body Exp_Aggr is
Expr_Q := Expression (C);
end if;
- -- Return true if the aggregate has any associations for tagged
+ -- Return False if the aggregate has any associations for tagged
-- components that may require tag adjustment.
-- These are cases where the source expression may have a tag that
@@ -7159,36 +7161,36 @@ package body Exp_Aggr is
and then Tagged_Type_Expansion
then
Static_Components := False;
- return True;
+ return False;
elsif Is_Delayed_Aggregate (Expr_Q) then
Static_Components := False;
- return True;
+ return False;
elsif Possible_Bit_Aligned_Component (Expr_Q) then
Static_Components := False;
- return True;
+ return False;
elsif Modify_Tree_For_C
and then Nkind (C) = N_Component_Association
and then Has_Per_Object_Constraint (Choices (C))
then
Static_Components := False;
- return True;
+ return False;
elsif Modify_Tree_For_C
and then Nkind (Expr_Q) = N_Identifier
and then Is_Array_Type (Etype (Expr_Q))
then
Static_Components := False;
- return True;
+ return False;
elsif Modify_Tree_For_C
and then Nkind (Expr_Q) = N_Type_Conversion
and then Is_Array_Type (Etype (Expr_Q))
then
Static_Components := False;
- return True;
+ return False;
end if;
if Is_Elementary_Type (Etype (Expr_Q)) then
@@ -7202,15 +7204,15 @@ package body Exp_Aggr is
if Is_Private_Type (Etype (Expr_Q))
and then Has_Discriminants (Etype (Expr_Q))
then
- return True;
+ return False;
end if;
end if;
Next (C);
end loop;
- return False;
- end Component_Not_OK_For_Backend;
+ return True;
+ end Component_OK_For_Backend;
-------------------------------
-- Has_Per_Object_Constraint --
@@ -7300,7 +7302,7 @@ package body Exp_Aggr is
-- Ada 2005 (AI-318-2): We need to convert to assignments if components
-- are build-in-place function calls. The assignments will each turn
-- into a build-in-place function call. If components are all static,
- -- we can pass the aggregate to the backend regardless of limitedness.
+ -- we can pass the aggregate to the back end regardless of limitedness.
-- Extension aggregates, aggregates in extended return statements, and
-- aggregates for C++ imported types must be expanded.
@@ -7317,7 +7319,7 @@ package body Exp_Aggr is
Convert_To_Assignments (N, Typ);
elsif not Size_Known_At_Compile_Time (Typ)
- or else Component_Not_OK_For_Backend
+ or else not Component_OK_For_Backend
or else not Static_Components
then
Convert_To_Assignments (N, Typ);
@@ -7352,7 +7354,7 @@ package body Exp_Aggr is
-- Check components
- elsif Component_Not_OK_For_Backend then
+ elsif not Component_OK_For_Backend then
Convert_To_Assignments (N, Typ);
-- If an ancestor is private, some components are not inherited and we
@@ -7457,6 +7459,33 @@ package body Exp_Aggr is
return False;
end Has_Default_Init_Comps;
+ ----------------------------------------
+ -- Is_Build_In_Place_Aggregate_Return --
+ ----------------------------------------
+
+ function Is_Build_In_Place_Aggregate_Return (N : Node_Id) return Boolean is
+ P : Node_Id := Parent (N);
+
+ begin
+ while Nkind (P) = N_Qualified_Expression loop
+ P := Parent (P);
+ end loop;
+
+ if Nkind (P) = N_Simple_Return_Statement then
+ null;
+
+ elsif Nkind (Parent (P)) = N_Extended_Return_Statement then
+ P := Parent (P);
+
+ else
+ return False;
+ end if;
+
+ return
+ Is_Build_In_Place_Function
+ (Return_Applies_To (Return_Statement_Entity (P)));
+ end Is_Build_In_Place_Aggregate_Return;
+
--------------------------
-- Is_Delayed_Aggregate --
--------------------------
diff --git a/gcc/ada/exp_atag.ads b/gcc/ada/exp_atag.ads
index d53466f..73af9a0 100644
--- a/gcc/ada/exp_atag.ads
+++ b/gcc/ada/exp_atag.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 2006-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 2006-2017, 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- --
@@ -147,7 +147,7 @@ package Exp_Atag is
--
-- Generates:
-- Offset_To_Top_Ptr
- -- (Address!(Tag_Ptr!(This).all) - Offset_To_Top_Offset)
+ -- (Address!(Tag_Ptr!(This).all) - Offset_To_Top_Offset).all
function Build_Set_Predefined_Prim_Op_Address
(Loc : Source_Ptr;
diff --git a/gcc/ada/exp_attr.adb b/gcc/ada/exp_attr.adb
index 9afb23b..70d39b7 100644
--- a/gcc/ada/exp_attr.adb
+++ b/gcc/ada/exp_attr.adb
@@ -1753,23 +1753,27 @@ package body Exp_Attr is
-- Ada 2005 (AI-318-02): If attribute prefix is a call to a build-in-
-- place function, then a temporary return object needs to be created
- -- and access to it must be passed to the function. Currently we limit
- -- such functions to those with inherently limited result subtypes, but
- -- eventually we plan to expand the functions that are treated as
- -- build-in-place to include other composite result types.
+ -- and access to it must be passed to the function.
- if Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (Pref)
- then
- Make_Build_In_Place_Call_In_Anonymous_Context (Pref);
+ if Is_Build_In_Place_Function_Call (Pref) then
+
+ -- If attribute is 'Old, the context is a postcondition, and
+ -- the temporary must go in the corresponding subprogram, not
+ -- the postcondition function or any created blocks, as when
+ -- the attribute appears in a quantified expression. This is
+ -- handled below in the expansion of the attribute.
+
+ if Attribute_Name (Parent (Pref)) = Name_Old then
+ null;
+ else
+ Make_Build_In_Place_Call_In_Anonymous_Context (Pref);
+ end if;
-- Ada 2005 (AI-318-02): Specialization of the previous case for prefix
-- containing build-in-place function calls whose returned object covers
-- interface types.
- elsif Ada_Version >= Ada_2005
- and then Present (Unqual_BIP_Iface_Function_Call (Pref))
- then
+ elsif Present (Unqual_BIP_Iface_Function_Call (Pref)) then
Make_Build_In_Place_Iface_Call_In_Anonymous_Context (Pref);
end if;
@@ -6519,7 +6523,9 @@ package body Exp_Attr is
begin
-- The prefix of attribute 'Valid should always denote an object
-- reference. The reference is either coming directly from source
- -- or is produced by validity check expansion.
+ -- or is produced by validity check expansion. The object may be
+ -- wrapped in a conversion in which case the call to Unqual_Conv
+ -- will yield it.
-- If the prefix denotes a variable which captures the value of
-- an object for validation purposes, use the variable in the
@@ -6530,7 +6536,7 @@ package body Exp_Attr is
-- if not Temp in ... then
if Is_Validation_Variable_Reference (Pref) then
- Temp := New_Occurrence_Of (Entity (Pref), Loc);
+ Temp := New_Occurrence_Of (Entity (Unqual_Conv (Pref)), Loc);
-- Otherwise the prefix is either a source object or a constant
-- produced by validity check expansion. Generate:
diff --git a/gcc/ada/exp_ch11.adb b/gcc/ada/exp_ch11.adb
index 8711c89..7941cbd 100644
--- a/gcc/ada/exp_ch11.adb
+++ b/gcc/ada/exp_ch11.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -64,7 +64,7 @@ package body Exp_Ch11 is
procedure Warn_If_No_Propagation (N : Node_Id);
-- Called for an exception raise that is not a local raise (and thus can
- -- not be optimized to a goto. Issues warning if No_Exception_Propagation
+ -- not be optimized to a goto). Issues warning if No_Exception_Propagation
-- restriction is set. N is the node for the raise or equivalent call.
---------------------------
@@ -998,15 +998,10 @@ package body Exp_Ch11 is
-- if a source generated handler was not the target of a local raise.
else
- if Restriction_Active (No_Exception_Propagation)
- and then not Has_Local_Raise (Handler)
+ if not Has_Local_Raise (Handler)
and then Comes_From_Source (Handler)
- and then Warn_On_Non_Local_Exception
then
- Warn_No_Exception_Propagation_Active (Handler);
- Error_Msg_N
- ("\?X?this handler can never be entered, "
- & "and has been removed", Handler);
+ Warn_If_No_Local_Raise (Handler);
end if;
if No_Exception_Propagation_Active then
@@ -1859,8 +1854,12 @@ package body Exp_Ch11 is
-- Otherwise, if the No_Exception_Propagation restriction is active
-- and the warning is enabled, generate the appropriate warnings.
+ -- ??? Do not do it for the Call_Marker nodes inserted by the ABE
+ -- mechanism because this generates too many false positives.
+
elsif Warn_On_Non_Local_Exception
and then Restriction_Active (No_Exception_Propagation)
+ and then Nkind (N) /= N_Call_Marker
then
Warn_No_Exception_Propagation_Active (N);
@@ -2155,6 +2154,22 @@ package body Exp_Ch11 is
end Get_RT_Exception_Name;
----------------------------
+ -- Warn_If_No_Local_Raise --
+ ----------------------------
+
+ procedure Warn_If_No_Local_Raise (N : Node_Id) is
+ begin
+ if Restriction_Active (No_Exception_Propagation)
+ and then Warn_On_Non_Local_Exception
+ then
+ Warn_No_Exception_Propagation_Active (N);
+
+ Error_Msg_N
+ ("\?X?this handler can never be entered, and has been removed", N);
+ end if;
+ end Warn_If_No_Local_Raise;
+
+ ----------------------------
-- Warn_If_No_Propagation --
----------------------------
diff --git a/gcc/ada/exp_ch11.ads b/gcc/ada/exp_ch11.ads
index cdd53de..99efdeb 100644
--- a/gcc/ada/exp_ch11.ads
+++ b/gcc/ada/exp_ch11.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2015, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -90,4 +90,9 @@ package Exp_Ch11 is
-- is a local handler marking that it has a local raise. E is the entity
-- of the corresponding exception.
+ procedure Warn_If_No_Local_Raise (N : Node_Id);
+ -- Called for an exception handler that is not the target of a local raise.
+ -- Issues warning if No_Exception_Propagation restriction is set. N is the
+ -- node for the handler.
+
end Exp_Ch11;
diff --git a/gcc/ada/exp_ch13.adb b/gcc/ada/exp_ch13.adb
index 0e0bbca..4637d04 100644
--- a/gcc/ada/exp_ch13.adb
+++ b/gcc/ada/exp_ch13.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -27,7 +27,7 @@ with Atree; use Atree;
with Checks; use Checks;
with Einfo; use Einfo;
with Exp_Ch3; use Exp_Ch3;
-with Exp_Ch6; use Exp_Ch6;
+with Exp_Ch6;
with Exp_Imgv; use Exp_Imgv;
with Exp_Tss; use Exp_Tss;
with Exp_Util; use Exp_Util;
diff --git a/gcc/ada/exp_ch3.adb b/gcc/ada/exp_ch3.adb
index 6e90fb6..043a02c 100644
--- a/gcc/ada/exp_ch3.adb
+++ b/gcc/ada/exp_ch3.adb
@@ -43,6 +43,7 @@ with Exp_Tss; use Exp_Tss;
with Exp_Util; use Exp_Util;
with Freeze; use Freeze;
with Ghost; use Ghost;
+with Lib; use Lib;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
@@ -516,11 +517,18 @@ package body Exp_Ch3 is
---------------------------
procedure Build_Array_Init_Proc (A_Type : Entity_Id; Nod : Node_Id) is
- Comp_Type : constant Entity_Id := Component_Type (A_Type);
- Comp_Type_Simple : constant Boolean :=
+ Comp_Type : constant Entity_Id := Component_Type (A_Type);
+ Comp_Simple_Init : constant Boolean :=
Needs_Simple_Initialization
- (Comp_Type, Consider_IS =>
+ (T => Comp_Type,
+ Consider_IS =>
not (Validity_Check_Copies and Is_Bit_Packed_Array (A_Type)));
+ -- True if the component needs simple initialization, based on its type,
+ -- plus the fact that we do not do simple initialization for components
+ -- of bit-packed arrays when validity checks are enabled, because the
+ -- initialization with deliberately out-of-range values would raise
+ -- Constraint_Error.
+
Body_Stmts : List_Id;
Has_Default_Init : Boolean;
Index_List : List_Id;
@@ -561,7 +569,7 @@ package body Exp_Ch3 is
Convert_To (Comp_Type,
Default_Aspect_Component_Value (First_Subtype (A_Type)))));
- elsif Comp_Type_Simple then
+ elsif Comp_Simple_Init then
Set_Assignment_OK (Comp);
return New_List (
Make_Assignment_Statement (Loc,
@@ -593,7 +601,7 @@ package body Exp_Ch3 is
-- the dummy Init_Proc needed for Initialize_Scalars processing.
if not Has_Non_Null_Base_Init_Proc (Comp_Type)
- and then not Comp_Type_Simple
+ and then not Comp_Simple_Init
and then not Has_Task (Comp_Type)
and then not Has_Default_Aspect (A_Type)
then
@@ -683,7 +691,7 @@ package body Exp_Ch3 is
-- init_proc.
Has_Default_Init := Has_Non_Null_Base_Init_Proc (Comp_Type)
- or else Comp_Type_Simple
+ or else Comp_Simple_Init
or else Has_Task (Comp_Type)
or else Has_Default_Aspect (A_Type);
@@ -1704,10 +1712,12 @@ package body Exp_Ch3 is
Rec_Type : Entity_Id;
Set_Tag : Entity_Id := Empty;
- function Build_Assignment (Id : Entity_Id; N : Node_Id) return List_Id;
- -- Build an assignment statement which assigns the default expression
- -- to its corresponding record component if defined. The left hand side
- -- of the assignment is marked Assignment_OK so that initialization of
+ function Build_Assignment
+ (Id : Entity_Id;
+ Default : Node_Id) return List_Id;
+ -- Build an assignment statement that assigns the default expression to
+ -- its corresponding record component if defined. The left-hand side of
+ -- the assignment is marked Assignment_OK so that initialization of
-- limited private records works correctly. This routine may also build
-- an adjustment call if the component is controlled.
@@ -1776,13 +1786,16 @@ package body Exp_Ch3 is
-- Build_Assignment --
----------------------
- function Build_Assignment (Id : Entity_Id; N : Node_Id) return List_Id is
- N_Loc : constant Source_Ptr := Sloc (N);
- Typ : constant Entity_Id := Underlying_Type (Etype (Id));
+ function Build_Assignment
+ (Id : Entity_Id;
+ Default : Node_Id) return List_Id
+ is
+ Default_Loc : constant Source_Ptr := Sloc (Default);
+ Typ : constant Entity_Id := Underlying_Type (Etype (Id));
Adj_Call : Node_Id;
- Exp : Node_Id := N;
- Kind : Node_Kind := Nkind (N);
+ Exp : Node_Id := Default;
+ Kind : Node_Kind := Nkind (Default);
Lhs : Node_Id;
Res : List_Id;
@@ -1800,6 +1813,7 @@ package body Exp_Ch3 is
function Replace_Discr_Ref (N : Node_Id) return Traverse_Result is
Val : Node_Id;
+
begin
if Is_Entity_Name (N)
and then Present (Entity (N))
@@ -1807,10 +1821,12 @@ package body Exp_Ch3 is
and then Present (Discriminal_Link (Entity (N)))
then
Val :=
- Make_Selected_Component (N_Loc,
- Prefix => New_Copy_Tree (Lhs),
- Selector_Name => New_Occurrence_Of
- (Discriminal_Link (Entity (N)), N_Loc));
+ Make_Selected_Component (Default_Loc,
+ Prefix => New_Copy_Tree (Lhs),
+ Selector_Name =>
+ New_Occurrence_Of
+ (Discriminal_Link (Entity (N)), Default_Loc));
+
if Present (Val) then
Rewrite (N, New_Copy_Tree (Val));
end if;
@@ -1822,11 +1838,13 @@ package body Exp_Ch3 is
procedure Replace_Discriminant_References is
new Traverse_Proc (Replace_Discr_Ref);
+ -- Start of processing for Build_Assignment
+
begin
Lhs :=
- Make_Selected_Component (N_Loc,
+ Make_Selected_Component (Default_Loc,
Prefix => Make_Identifier (Loc, Name_uInit),
- Selector_Name => New_Occurrence_Of (Id, N_Loc));
+ Selector_Name => New_Occurrence_Of (Id, Default_Loc));
Set_Assignment_OK (Lhs);
if Nkind (Exp) = N_Aggregate
@@ -1855,16 +1873,16 @@ package body Exp_Ch3 is
-- traversing the expression. ???
if Kind = N_Attribute_Reference
- and then Nam_In (Attribute_Name (N), Name_Unchecked_Access,
- Name_Unrestricted_Access)
- and then Is_Entity_Name (Prefix (N))
- and then Is_Type (Entity (Prefix (N)))
- and then Entity (Prefix (N)) = Rec_Type
+ and then Nam_In (Attribute_Name (Default), Name_Unchecked_Access,
+ Name_Unrestricted_Access)
+ and then Is_Entity_Name (Prefix (Default))
+ and then Is_Type (Entity (Prefix (Default)))
+ and then Entity (Prefix (Default)) = Rec_Type
then
Exp :=
- Make_Attribute_Reference (N_Loc,
+ Make_Attribute_Reference (Default_Loc,
Prefix =>
- Make_Identifier (N_Loc, Name_uInit),
+ Make_Identifier (Default_Loc, Name_uInit),
Attribute_Name => Name_Unrestricted_Access);
end if;
@@ -1888,33 +1906,33 @@ package body Exp_Ch3 is
if Is_Tagged_Type (Typ) and then Tagged_Type_Expansion then
Append_To (Res,
- Make_Assignment_Statement (N_Loc,
+ Make_Assignment_Statement (Default_Loc,
Name =>
- Make_Selected_Component (N_Loc,
+ Make_Selected_Component (Default_Loc,
Prefix =>
New_Copy_Tree (Lhs, New_Scope => Proc_Id),
Selector_Name =>
- New_Occurrence_Of (First_Tag_Component (Typ), N_Loc)),
+ New_Occurrence_Of
+ (First_Tag_Component (Typ), Default_Loc)),
Expression =>
Unchecked_Convert_To (RTE (RE_Tag),
New_Occurrence_Of
- (Node
- (First_Elmt
- (Access_Disp_Table (Underlying_Type (Typ)))),
- N_Loc))));
+ (Node (First_Elmt (Access_Disp_Table (Underlying_Type
+ (Typ)))),
+ Default_Loc))));
end if;
-- Adjust the component if controlled except if it is an aggregate
-- that will be expanded inline.
if Kind = N_Qualified_Expression then
- Kind := Nkind (Expression (N));
+ Kind := Nkind (Expression (Default));
end if;
if Needs_Finalization (Typ)
and then not (Nkind_In (Kind, N_Aggregate, N_Extension_Aggregate))
- and then not Is_Limited_View (Typ)
+ and then not Is_Build_In_Place_Function_Call (Exp)
then
Adj_Call :=
Make_Adjust_Call
@@ -2705,36 +2723,30 @@ package body Exp_Ch3 is
and then not Restriction_Active (No_Exception_Propagation)
then
declare
- DF_Call : Node_Id;
- DF_Id : Entity_Id;
+ DF_Id : Entity_Id;
begin
-- Create a local version of Deep_Finalize which has indication
-- of partial initialization state.
- DF_Id := Make_Temporary (Loc, 'F');
+ DF_Id :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_External_Name (Name_uFinalizer));
Append_To (Decls, Make_Local_Deep_Finalize (Rec_Type, DF_Id));
- DF_Call :=
- Make_Procedure_Call_Statement (Loc,
- Name => New_Occurrence_Of (DF_Id, Loc),
- Parameter_Associations => New_List (
- Make_Identifier (Loc, Name_uInit),
- New_Occurrence_Of (Standard_False, Loc)));
-
- -- Do not emit warnings related to the elaboration order when a
- -- controlled object is declared before the body of Finalize is
- -- seen.
-
- Set_No_Elaboration_Check (DF_Call);
-
Set_Exception_Handlers (Handled_Stmt_Node, New_List (
Make_Exception_Handler (Loc,
Exception_Choices => New_List (
Make_Others_Choice (Loc)),
Statements => New_List (
- DF_Call,
+ Make_Procedure_Call_Statement (Loc,
+ Name =>
+ New_Occurrence_Of (DF_Id, Loc),
+ Parameter_Associations => New_List (
+ Make_Identifier (Loc, Name_uInit),
+ New_Occurrence_Of (Standard_False, Loc))),
+
Make_Raise_Statement (Loc)))));
end;
else
@@ -5569,6 +5581,15 @@ package body Exp_Ch3 is
-- arithmetic might yield a meaningless value for the length of the
-- array, or its corresponding attribute.
+ procedure Count_Default_Sized_Task_Stacks
+ (Typ : Entity_Id;
+ Pri_Stacks : out Int;
+ Sec_Stacks : out Int);
+ -- Count the number of default-sized primary and secondary task stacks
+ -- required for task objects contained within type Typ. If the number of
+ -- task objects contained within the type is not known at compile time
+ -- the procedure will return the stack counts of zero.
+
procedure Default_Initialize_Object (After : Node_Id);
-- Generate all default initialization actions for object Def_Id. Any
-- new code is inserted after node After.
@@ -5761,6 +5782,119 @@ package body Exp_Ch3 is
end if;
end Check_Large_Modular_Array;
+ -------------------------------------
+ -- Count_Default_Sized_Task_Stacks --
+ -------------------------------------
+
+ procedure Count_Default_Sized_Task_Stacks
+ (Typ : Entity_Id;
+ Pri_Stacks : out Int;
+ Sec_Stacks : out Int)
+ is
+ Component : Entity_Id;
+
+ begin
+ -- To calculate the number of default-sized task stacks required for
+ -- an object of Typ, a depth-first recursive traversal of the AST
+ -- from the Typ entity node is undertaken. Only type nodes containing
+ -- task objects are visited.
+
+ Pri_Stacks := 0;
+ Sec_Stacks := 0;
+
+ if not Has_Task (Typ) then
+ return;
+ end if;
+
+ case Ekind (Typ) is
+ when E_Task_Subtype
+ | E_Task_Type
+ =>
+ -- A task type is found marking the bottom of the descent. If
+ -- the type has no representation aspect for the corresponding
+ -- stack then that stack is using the default size.
+
+ if Present (Get_Rep_Item (Typ, Name_Storage_Size)) then
+ Pri_Stacks := 0;
+ else
+ Pri_Stacks := 1;
+ end if;
+
+ if Present (Get_Rep_Item (Typ, Name_Secondary_Stack_Size)) then
+ Sec_Stacks := 0;
+ else
+ Sec_Stacks := 1;
+ end if;
+
+ when E_Array_Subtype
+ | E_Array_Type
+ =>
+ -- First find the number of default stacks contained within an
+ -- array component.
+
+ Count_Default_Sized_Task_Stacks
+ (Component_Type (Typ),
+ Pri_Stacks,
+ Sec_Stacks);
+
+ -- Then multiply the result by the size of the array
+
+ declare
+ Quantity : constant Int := Number_Of_Elements_In_Array (Typ);
+ -- Number_Of_Elements_In_Array is non-trival, consequently
+ -- its result is captured as an optimization.
+
+ begin
+ Pri_Stacks := Pri_Stacks * Quantity;
+ Sec_Stacks := Sec_Stacks * Quantity;
+ end;
+
+ when E_Protected_Subtype
+ | E_Protected_Type
+ | E_Record_Subtype
+ | E_Record_Type
+ =>
+ Component := First_Component_Or_Discriminant (Typ);
+
+ -- Recursively descend each component of the composite type
+ -- looking for tasks, but only if the component is marked as
+ -- having a task.
+
+ while Present (Component) loop
+ if Has_Task (Etype (Component)) then
+ declare
+ P : Int;
+ S : Int;
+
+ begin
+ Count_Default_Sized_Task_Stacks
+ (Etype (Component), P, S);
+ Pri_Stacks := Pri_Stacks + P;
+ Sec_Stacks := Sec_Stacks + S;
+ end;
+ end if;
+
+ Next_Component_Or_Discriminant (Component);
+ end loop;
+
+ when E_Limited_Private_Subtype
+ | E_Limited_Private_Type
+ | E_Record_Subtype_With_Private
+ | E_Record_Type_With_Private
+ =>
+ -- Switch to the full view of the private type to continue
+ -- search.
+
+ Count_Default_Sized_Task_Stacks
+ (Full_View (Typ), Pri_Stacks, Sec_Stacks);
+
+ -- Other types should not contain tasks
+
+ when others =>
+ raise Program_Error;
+ end case;
+ end Count_Default_Sized_Task_Stacks;
+
-------------------------------
-- Default_Initialize_Object --
-------------------------------
@@ -5798,6 +5932,7 @@ package body Exp_Ch3 is
Aggr_Init : Node_Id;
Comp_Init : List_Id := No_List;
+ Fin_Block : Node_Id;
Fin_Call : Node_Id;
Init_Stmts : List_Id := No_List;
Obj_Init : Node_Id := Empty;
@@ -5940,14 +6075,7 @@ package body Exp_Ch3 is
Skip_Self => True);
if Present (Fin_Call) then
-
- -- Do not emit warnings related to the elaboration order when a
- -- controlled object is declared before the body of Finalize is
- -- seen.
-
- Set_No_Elaboration_Check (Fin_Call);
-
- Append_To (Init_Stmts,
+ Fin_Block :=
Make_Block_Statement (Loc,
Declarations => No_List,
@@ -5962,7 +6090,14 @@ package body Exp_Ch3 is
Statements => New_List (
Fin_Call,
- Make_Raise_Statement (Loc)))))));
+ Make_Raise_Statement (Loc))))));
+
+ -- Signal the ABE mechanism that the block carries out
+ -- initialization actions.
+
+ Set_Is_Initialization_Block (Fin_Block);
+
+ Append_To (Init_Stmts, Fin_Block);
end if;
-- Otherwise finalization is not required, the initialization calls
@@ -6122,6 +6257,19 @@ package body Exp_Ch3 is
return;
end if;
+ -- No action needed for the internal imported dummy object added by
+ -- Make_DT to compute the offset of the components that reference
+ -- secondary dispatch tables; required to avoid never-ending loop
+ -- processing this internal object declaration.
+
+ if Tagged_Type_Expansion
+ and then Is_Internal (Def_Id)
+ and then Is_Imported (Def_Id)
+ and then Related_Type (Def_Id) = Implementation_Base_Type (Typ)
+ then
+ return;
+ end if;
+
-- First we do special processing for objects of a tagged type where
-- this is the point at which the type is frozen. The creation of the
-- dispatch table and the initialization procedure have to be deferred
@@ -6173,6 +6321,37 @@ package body Exp_Ch3 is
Check_Large_Modular_Array;
+ -- If No_Implicit_Heap_Allocations or No_Implicit_Task_Allocations
+ -- restrictions are active then default-sized secondary stacks are
+ -- generated by the binder and allocated by SS_Init. To provide the
+ -- binder the number of stacks to generate, the number of default-sized
+ -- stacks required for task objects contained within the object
+ -- declaration N is calculated here as it is at this point where
+ -- unconstrained types become constrained. The result is stored in the
+ -- enclosing unit's Unit_Record.
+
+ -- Note if N is an array object declaration that has an initialization
+ -- expression, a second object declaration for the initialization
+ -- expression is created by the compiler. To prevent double counting
+ -- of the stacks in this scenario, the stacks of the first array are
+ -- not counted.
+
+ if Has_Task (Typ)
+ and then not Restriction_Active (No_Secondary_Stack)
+ and then (Restriction_Active (No_Implicit_Heap_Allocations)
+ or else Restriction_Active (No_Implicit_Task_Allocations))
+ and then not (Ekind_In (Ekind (Typ), E_Array_Type, E_Array_Subtype)
+ and then (Has_Init_Expression (N)))
+ then
+ declare
+ PS_Count, SS_Count : Int := 0;
+ begin
+ Count_Default_Sized_Task_Stacks (Typ, PS_Count, SS_Count);
+ Increment_Primary_Stack_Count (PS_Count);
+ Increment_Sec_Stack_Count (SS_Count);
+ end;
+ end if;
+
-- Default initialization required, and no expression present
if No (Expr) then
@@ -6288,9 +6467,7 @@ package body Exp_Ch3 is
-- plan to expand the allowed forms of functions that are treated as
-- build-in-place.
- elsif Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (Expr_Q)
- then
+ elsif Is_Build_In_Place_Function_Call (Expr_Q) then
Make_Build_In_Place_Call_In_Object_Declaration (N, Expr_Q);
-- The previous call expands the expression initializing the
@@ -6299,6 +6476,23 @@ package body Exp_Ch3 is
return;
+ -- This is the same as the previous 'elsif', except that the call has
+ -- been transformed by other expansion activities into something like
+ -- F(...)'Reference.
+
+ elsif Nkind (Expr_Q) = N_Reference
+ and then Is_Build_In_Place_Function_Call (Prefix (Expr_Q))
+ and then not Is_Expanded_Build_In_Place_Call
+ (Unqual_Conv (Prefix (Expr_Q)))
+ then
+ Make_Build_In_Place_Call_In_Anonymous_Context (Prefix (Expr_Q));
+
+ -- The previous call expands the expression initializing the
+ -- built-in-place object into further code that will be analyzed
+ -- later. No further expansion needed here.
+
+ return;
+
-- Ada 2005 (AI-318-02): Specialization of the previous case for
-- expressions containing a build-in-place function call whose
-- returned object covers interface types, and Expr_Q has calls to
@@ -6306,9 +6500,7 @@ package body Exp_Ch3 is
-- in-place object to reference the secondary dispatch table of a
-- covered interface type.
- elsif Ada_Version >= Ada_2005
- and then Present (Unqual_BIP_Iface_Function_Call (Expr_Q))
- then
+ elsif Present (Unqual_BIP_Iface_Function_Call (Expr_Q)) then
Make_Build_In_Place_Iface_Call_In_Object_Declaration (N, Expr_Q);
-- The previous call expands the expression initializing the
@@ -6574,7 +6766,8 @@ package body Exp_Ch3 is
-- allocated in place, delay checks until assignments are
-- made, because the discriminants are not initialized.
- if Nkind (Expr) = N_Allocator and then No_Initialization (Expr)
+ if Nkind (Expr) = N_Allocator
+ and then No_Initialization (Expr)
then
null;
@@ -6606,11 +6799,9 @@ package body Exp_Ch3 is
-- the target is adjusted after the copy and attached to the
-- finalization list. However, no adjustment is done in the case
-- where the object was initialized by a call to a function whose
- -- result is built in place, since no copy occurred. (Eventually
- -- we plan to support in-place function results for some cases
- -- of nonlimited types. ???) Similarly, no adjustment is required
- -- if we are going to rewrite the object declaration into a
- -- renaming declaration.
+ -- result is built in place, since no copy occurred. Similarly, no
+ -- adjustment is required if we are going to rewrite the object
+ -- declaration into a renaming declaration.
if Needs_Finalization (Typ)
and then not Is_Limited_View (Typ)
@@ -6744,9 +6935,9 @@ package body Exp_Ch3 is
end if;
end if;
- -- Cases where the back end cannot handle the initialization directly
- -- In such cases, we expand an assignment that will be appropriately
- -- handled by Expand_N_Assignment_Statement.
+ -- Cases where the back end cannot handle the initialization
+ -- directly. In such cases, we expand an assignment that will
+ -- be appropriately handled by Expand_N_Assignment_Statement.
-- The exclusion of the unconstrained case is wrong, but for now it
-- is too much trouble ???
@@ -8349,10 +8540,13 @@ package body Exp_Ch3 is
-- Normal case: No discriminants in the parent type
else
- -- Don't need to set any value if this interface shares the
- -- primary dispatch table.
+ -- Don't need to set any value if the offset-to-top field is
+ -- statically set or if this interface shares the primary
+ -- dispatch table.
- if not Is_Ancestor (Iface, Typ, Use_Full_View => True) then
+ if not Building_Static_Secondary_DT (Typ)
+ and then not Is_Ancestor (Iface, Typ, Use_Full_View => True)
+ then
Append_To (Stmts_List,
Build_Set_Static_Offset_To_Top (Loc,
Iface_Tag => New_Occurrence_Of (Iface_Tag, Loc),
diff --git a/gcc/ada/exp_ch4.adb b/gcc/ada/exp_ch4.adb
index 61d00aa..abf6d63 100644
--- a/gcc/ada/exp_ch4.adb
+++ b/gcc/ada/exp_ch4.adb
@@ -793,14 +793,9 @@ package body Exp_Ch4 is
-- Ada 2005 (AI-318-02): If the initialization expression is a call
-- to a build-in-place function, then access to the allocated object
- -- must be passed to the function. Currently we limit such functions
- -- to those with constrained limited result subtypes, but eventually
- -- we plan to expand the allowed forms of functions that are treated
- -- as build-in-place.
+ -- must be passed to the function.
- if Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (Exp)
- then
+ if Is_Build_In_Place_Function_Call (Exp) then
Make_Build_In_Place_Call_In_Allocator (N, Exp);
Apply_Accessibility_Check (N, Built_In_Place => True);
return;
@@ -812,9 +807,7 @@ package body Exp_Ch4 is
-- in-place object to reference the secondary dispatch table of a
-- covered interface type.
- elsif Ada_Version >= Ada_2005
- and then Present (Unqual_BIP_Iface_Function_Call (Exp))
- then
+ elsif Present (Unqual_BIP_Iface_Function_Call (Exp)) then
Make_Build_In_Place_Iface_Call_In_Allocator (N, Exp);
Apply_Accessibility_Check (N, Built_In_Place => True);
return;
@@ -1076,12 +1069,15 @@ package body Exp_Ch4 is
-- object can be limited but not inherently limited if this allocator
-- came from a return statement (we're allocating the result on the
-- secondary stack). In that case, the object will be moved, so we do
- -- want to Adjust.
+ -- want to Adjust. However, if it's a nonlimited build-in-place
+ -- function call, Adjust is not wanted.
if Needs_Finalization (DesigT)
and then Needs_Finalization (T)
and then not Aggr_In_Place
and then not Is_Limited_View (T)
+ and then not Alloc_For_BIP_Return (N)
+ and then not Is_Build_In_Place_Function_Call (Expression (N))
then
-- An unchecked conversion is needed in the classwide case because
-- the designated type can be an ancestor of the subtype mark of
@@ -1223,14 +1219,9 @@ package body Exp_Ch4 is
-- Ada 2005 (AI-318-02): If the initialization expression is a call
-- to a build-in-place function, then access to the allocated object
- -- must be passed to the function. Currently we limit such functions
- -- to those with constrained limited result subtypes, but eventually
- -- we plan to expand the allowed forms of functions that are treated
- -- as build-in-place.
+ -- must be passed to the function.
- if Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (Exp)
- then
+ if Is_Build_In_Place_Function_Call (Exp) then
Make_Build_In_Place_Call_In_Allocator (N, Exp);
end if;
end if;
@@ -5463,12 +5454,10 @@ package body Exp_Ch4 is
Typ : constant Entity_Id := Etype (N);
Actions : List_Id;
- Cnn : Entity_Id;
Decl : Node_Id;
Expr : Node_Id;
New_If : Node_Id;
New_N : Node_Id;
- Ptr_Typ : Entity_Id;
begin
-- Check for MINIMIZED/ELIMINATED overflow mode
@@ -5572,65 +5561,67 @@ package body Exp_Ch4 is
Process_If_Case_Statements (N, Then_Actions (N));
Process_If_Case_Statements (N, Else_Actions (N));
- -- Generate:
- -- type Ann is access all Typ;
-
- Ptr_Typ := Make_Temporary (Loc, 'A');
+ declare
+ Cnn : constant Entity_Id := Make_Temporary (Loc, 'C', N);
+ Ptr_Typ : constant Entity_Id := Make_Temporary (Loc, 'A');
- Insert_Action (N,
- Make_Full_Type_Declaration (Loc,
- Defining_Identifier => Ptr_Typ,
- Type_Definition =>
- Make_Access_To_Object_Definition (Loc,
- All_Present => True,
- Subtype_Indication => New_Occurrence_Of (Typ, Loc))));
+ begin
+ -- Generate:
+ -- type Ann is access all Typ;
- -- Generate:
- -- Cnn : Ann;
+ Insert_Action (N,
+ Make_Full_Type_Declaration (Loc,
+ Defining_Identifier => Ptr_Typ,
+ Type_Definition =>
+ Make_Access_To_Object_Definition (Loc,
+ All_Present => True,
+ Subtype_Indication => New_Occurrence_Of (Typ, Loc))));
- Cnn := Make_Temporary (Loc, 'C', N);
+ -- Generate:
+ -- Cnn : Ann;
- Decl :=
- Make_Object_Declaration (Loc,
- Defining_Identifier => Cnn,
- Object_Definition => New_Occurrence_Of (Ptr_Typ, Loc));
+ Decl :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Cnn,
+ Object_Definition => New_Occurrence_Of (Ptr_Typ, Loc));
- -- Generate:
- -- if Cond then
- -- Cnn := <Thenx>'Unrestricted_Access;
- -- else
- -- Cnn := <Elsex>'Unrestricted_Access;
- -- end if;
+ -- Generate:
+ -- if Cond then
+ -- Cnn := <Thenx>'Unrestricted_Access;
+ -- else
+ -- Cnn := <Elsex>'Unrestricted_Access;
+ -- end if;
- New_If :=
- Make_Implicit_If_Statement (N,
- Condition => Relocate_Node (Cond),
- Then_Statements => New_List (
- Make_Assignment_Statement (Sloc (Thenx),
- Name => New_Occurrence_Of (Cnn, Sloc (Thenx)),
- Expression =>
- Make_Attribute_Reference (Loc,
- Prefix => Relocate_Node (Thenx),
- Attribute_Name => Name_Unrestricted_Access))),
+ New_If :=
+ Make_Implicit_If_Statement (N,
+ Condition => Relocate_Node (Cond),
+ Then_Statements => New_List (
+ Make_Assignment_Statement (Sloc (Thenx),
+ Name => New_Occurrence_Of (Cnn, Sloc (Thenx)),
+ Expression =>
+ Make_Attribute_Reference (Loc,
+ Prefix => Relocate_Node (Thenx),
+ Attribute_Name => Name_Unrestricted_Access))),
- Else_Statements => New_List (
- Make_Assignment_Statement (Sloc (Elsex),
- Name => New_Occurrence_Of (Cnn, Sloc (Elsex)),
- Expression =>
- Make_Attribute_Reference (Loc,
- Prefix => Relocate_Node (Elsex),
- Attribute_Name => Name_Unrestricted_Access))));
+ Else_Statements => New_List (
+ Make_Assignment_Statement (Sloc (Elsex),
+ Name => New_Occurrence_Of (Cnn, Sloc (Elsex)),
+ Expression =>
+ Make_Attribute_Reference (Loc,
+ Prefix => Relocate_Node (Elsex),
+ Attribute_Name => Name_Unrestricted_Access))));
- -- Preserve the original context for which the if statement is being
- -- generated. This is needed by the finalization machinery to prevent
- -- the premature finalization of controlled objects found within the
- -- if statement.
+ -- Preserve the original context for which the if statement is
+ -- being generated. This is needed by the finalization machinery
+ -- to prevent the premature finalization of controlled objects
+ -- found within the if statement.
- Set_From_Conditional_Expression (New_If);
+ Set_From_Conditional_Expression (New_If);
- New_N :=
- Make_Explicit_Dereference (Loc,
- Prefix => New_Occurrence_Of (Cnn, Loc));
+ New_N :=
+ Make_Explicit_Dereference (Loc,
+ Prefix => New_Occurrence_Of (Cnn, Loc));
+ end;
-- If the result is an unconstrained array and the if expression is in a
-- context other than the initializing expression of the declaration of
@@ -5651,6 +5642,7 @@ package body Exp_Ch4 is
then
declare
Cnn : constant Node_Id := Make_Temporary (Loc, 'C', N);
+
begin
Insert_Action (N,
Make_Object_Declaration (Loc,
@@ -5689,31 +5681,34 @@ package body Exp_Ch4 is
-- and replace the if expression by a reference to Cnn
- Cnn := Make_Temporary (Loc, 'C', N);
+ declare
+ Cnn : constant Node_Id := Make_Temporary (Loc, 'C', N);
- Decl :=
- Make_Object_Declaration (Loc,
- Defining_Identifier => Cnn,
- Object_Definition => New_Occurrence_Of (Typ, Loc));
+ begin
+ Decl :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Cnn,
+ Object_Definition => New_Occurrence_Of (Typ, Loc));
- New_If :=
- Make_Implicit_If_Statement (N,
- Condition => Relocate_Node (Cond),
+ New_If :=
+ Make_Implicit_If_Statement (N,
+ Condition => Relocate_Node (Cond),
- Then_Statements => New_List (
- Make_Assignment_Statement (Sloc (Thenx),
- Name => New_Occurrence_Of (Cnn, Sloc (Thenx)),
- Expression => Relocate_Node (Thenx))),
+ Then_Statements => New_List (
+ Make_Assignment_Statement (Sloc (Thenx),
+ Name => New_Occurrence_Of (Cnn, Sloc (Thenx)),
+ Expression => Relocate_Node (Thenx))),
- Else_Statements => New_List (
- Make_Assignment_Statement (Sloc (Elsex),
- Name => New_Occurrence_Of (Cnn, Sloc (Elsex)),
- Expression => Relocate_Node (Elsex))));
+ Else_Statements => New_List (
+ Make_Assignment_Statement (Sloc (Elsex),
+ Name => New_Occurrence_Of (Cnn, Sloc (Elsex)),
+ Expression => Relocate_Node (Elsex))));
- Set_Assignment_OK (Name (First (Then_Statements (New_If))));
- Set_Assignment_OK (Name (First (Else_Statements (New_If))));
+ Set_Assignment_OK (Name (First (Then_Statements (New_If))));
+ Set_Assignment_OK (Name (First (Else_Statements (New_If))));
- New_N := New_Occurrence_Of (Cnn, Loc);
+ New_N := New_Occurrence_Of (Cnn, Loc);
+ end;
-- Regular path using Expression_With_Actions
@@ -6572,18 +6567,14 @@ package body Exp_Ch4 is
-- Ada 2005 (AI-318-02): If the prefix is a call to a build-in-place
-- function, then additional actuals must be passed.
- if Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (P)
- then
+ if Is_Build_In_Place_Function_Call (P) then
Make_Build_In_Place_Call_In_Anonymous_Context (P);
-- Ada 2005 (AI-318-02): Specialization of the previous case for prefix
-- containing build-in-place function calls whose returned object covers
-- interface types.
- elsif Ada_Version >= Ada_2005
- and then Present (Unqual_BIP_Iface_Function_Call (P))
- then
+ elsif Present (Unqual_BIP_Iface_Function_Call (P)) then
Make_Build_In_Place_Iface_Call_In_Anonymous_Context (P);
end if;
@@ -10221,18 +10212,14 @@ package body Exp_Ch4 is
-- Ada 2005 (AI-318-02): If the prefix is a call to a build-in-place
-- function, then additional actuals must be passed.
- if Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (P)
- then
+ if Is_Build_In_Place_Function_Call (P) then
Make_Build_In_Place_Call_In_Anonymous_Context (P);
-- Ada 2005 (AI-318-02): Specialization of the previous case for prefix
-- containing build-in-place function calls whose returned object covers
-- interface types.
- elsif Ada_Version >= Ada_2005
- and then Present (Unqual_BIP_Iface_Function_Call (P))
- then
+ elsif Present (Unqual_BIP_Iface_Function_Call (P)) then
Make_Build_In_Place_Iface_Call_In_Anonymous_Context (P);
end if;
@@ -10587,18 +10574,14 @@ package body Exp_Ch4 is
-- Ada 2005 (AI-318-02): If the prefix is a call to a build-in-place
-- function, then additional actuals must be passed.
- if Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (Pref)
- then
+ if Is_Build_In_Place_Function_Call (Pref) then
Make_Build_In_Place_Call_In_Anonymous_Context (Pref);
-- Ada 2005 (AI-318-02): Specialization of the previous case for prefix
-- containing build-in-place function calls whose returned object covers
-- interface types.
- elsif Ada_Version >= Ada_2005
- and then Present (Unqual_BIP_Iface_Function_Call (Pref))
- then
+ elsif Present (Unqual_BIP_Iface_Function_Call (Pref)) then
Make_Build_In_Place_Iface_Call_In_Anonymous_Context (Pref);
end if;
diff --git a/gcc/ada/exp_ch5.adb b/gcc/ada/exp_ch5.adb
index e682bfd..9d2f652 100644
--- a/gcc/ada/exp_ch5.adb
+++ b/gcc/ada/exp_ch5.adb
@@ -75,10 +75,11 @@ package body Exp_Ch5 is
-- of formal container iterators.
function Convert_To_Iterable_Type
- (Container : Entity_Id; Loc : Source_Ptr) return Node_Id;
- -- Returns New_Occurrence_Of (Container), possibly converted to an
- -- ancestor type, if the type of Container inherited the Iterable
- -- aspect_specification from that ancestor.
+ (Container : Entity_Id;
+ Loc : Source_Ptr) return Node_Id;
+ -- Returns New_Occurrence_Of (Container), possibly converted to an ancestor
+ -- type, if the type of Container inherited the Iterable aspect from that
+ -- ancestor.
function Change_Of_Representation (N : Node_Id) return Boolean;
-- Determine if the right-hand side of assignment N is a type conversion
@@ -174,17 +175,30 @@ package body Exp_Ch5 is
Advance : out Node_Id;
New_Loop : out Node_Id)
is
- Loc : constant Source_Ptr := Sloc (N);
- Stats : constant List_Id := Statements (N);
- Typ : constant Entity_Id := Base_Type (Etype (Container));
- First_Op : constant Entity_Id :=
- Get_Iterable_Type_Primitive (Typ, Name_First);
- Next_Op : constant Entity_Id :=
- Get_Iterable_Type_Primitive (Typ, Name_Next);
+ Loc : constant Source_Ptr := Sloc (N);
+ Stats : constant List_Id := Statements (N);
+ Typ : constant Entity_Id := Base_Type (Etype (Container));
Has_Element_Op : constant Entity_Id :=
- Get_Iterable_Type_Primitive (Typ, Name_Has_Element);
+ Get_Iterable_Type_Primitive (Typ, Name_Has_Element);
+
+ First_Op : Entity_Id;
+ Next_Op : Entity_Id;
+
begin
+ -- Use the proper set of primitives depending on the direction of
+ -- iteration. The legality of a reverse iteration has been checked
+ -- during analysis.
+
+ if Reverse_Present (Iterator_Specification (Iteration_Scheme (N))) then
+ First_Op := Get_Iterable_Type_Primitive (Typ, Name_Last);
+ Next_Op := Get_Iterable_Type_Primitive (Typ, Name_Previous);
+
+ else
+ First_Op := Get_Iterable_Type_Primitive (Typ, Name_First);
+ Next_Op := Get_Iterable_Type_Primitive (Typ, Name_Next);
+ end if;
+
-- Declaration for Cursor
Init :=
@@ -197,7 +211,7 @@ package body Exp_Ch5 is
Parameter_Associations => New_List (
Convert_To_Iterable_Type (Container, Loc))));
- -- Statement that advances cursor in loop
+ -- Statement that advances (in the right direction) cursor in loop
Advance :=
Make_Assignment_Statement (Loc,
@@ -243,16 +257,21 @@ package body Exp_Ch5 is
------------------------------
function Convert_To_Iterable_Type
- (Container : Entity_Id; Loc : Source_Ptr) return Node_Id
+ (Container : Entity_Id;
+ Loc : Source_Ptr) return Node_Id
is
- Typ : constant Entity_Id := Base_Type (Etype (Container));
- Aspect : constant Node_Id := Find_Aspect (Typ, Aspect_Iterable);
- Result : Node_Id := New_Occurrence_Of (Container, Loc);
+ Typ : constant Entity_Id := Base_Type (Etype (Container));
+ Aspect : constant Node_Id := Find_Aspect (Typ, Aspect_Iterable);
+ Result : Node_Id;
+
begin
+ Result := New_Occurrence_Of (Container, Loc);
+
if Entity (Aspect) /= Typ then
- Result := Make_Type_Conversion (Loc,
- Subtype_Mark => New_Occurrence_Of (Entity (Aspect), Loc),
- Expression => Result);
+ Result :=
+ Make_Type_Conversion (Loc,
+ Subtype_Mark => New_Occurrence_Of (Entity (Aspect), Loc),
+ Expression => Result);
end if;
return Result;
@@ -1571,7 +1590,14 @@ package body Exp_Ch5 is
-- suppressed in this case). It is unnecessary but harmless in
-- other cases.
- if Has_Discriminants (L_Typ) then
+ -- Special case: no copy if the target has no discriminants
+
+ if Has_Discriminants (L_Typ)
+ and then Is_Unchecked_Union (Base_Type (L_Typ))
+ then
+ null;
+
+ elsif Has_Discriminants (L_Typ) then
F := First_Discriminant (R_Typ);
while Present (F) loop
@@ -2377,13 +2403,13 @@ package body Exp_Ch5 is
end;
end if;
- -- Build-in-place function call case. Note that we're not yet doing
- -- build-in-place for user-written assignment statements (the assignment
- -- here came from an aggregate.)
+ -- Build-in-place function call case. This is for assignment statements
+ -- that come from aggregate component associations or from init procs.
+ -- User-written assignment statements with b-i-p calls are handled
+ -- elsewhere.
- elsif Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (Rhs)
- then
+ elsif Is_Build_In_Place_Function_Call (Rhs) then
+ pragma Assert (not Comes_From_Source (N));
Make_Build_In_Place_Call_In_Assignment (N, Rhs);
elsif Is_Tagged_Type (Typ)
diff --git a/gcc/ada/exp_ch6.adb b/gcc/ada/exp_ch6.adb
index c2edde6..bca7e5d 100644
--- a/gcc/ada/exp_ch6.adb
+++ b/gcc/ada/exp_ch6.adb
@@ -712,7 +712,8 @@ package body Exp_Ch6 is
Stmt := First (Stmts);
while Present (Stmt) loop
if Nkind (Stmt) = N_Block_Statement then
- Replace_Returns (Param_Id, Statements (Stmt));
+ Replace_Returns (Param_Id,
+ Statements (Handled_Statement_Sequence (Stmt)));
elsif Nkind (Stmt) = N_Case_Statement then
declare
@@ -2251,7 +2252,12 @@ package body Exp_Ch6 is
procedure Expand_Call (N : Node_Id) is
Post_Call : List_Id;
+
begin
+ pragma Assert (Nkind_In (N, N_Entry_Call_Statement,
+ N_Function_Call,
+ N_Procedure_Call_Statement));
+
Expand_Call_Helper (N, Post_Call);
Insert_Post_Call_Actions (N, Post_Call);
end Expand_Call;
@@ -2998,12 +3004,26 @@ package body Exp_Ch6 is
if Prev_Orig /= Prev
and then Nkind (Prev) = N_Attribute_Reference
- and then
- Get_Attribute_Id (Attribute_Name (Prev)) = Attribute_Access
+ and then Get_Attribute_Id (Attribute_Name (Prev)) =
+ Attribute_Access
and then Is_Aliased_View (Prev_Orig)
then
Prev_Orig := Prev;
+ -- A class-wide precondition generates a test in which formals of
+ -- the subprogram are replaced by actuals that came from source.
+ -- In that case as well, the accessiblity comes from the actual.
+ -- This is the one case in which there are references to formals
+ -- outside of their subprogram.
+
+ elsif Prev_Orig /= Prev
+ and then Is_Entity_Name (Prev_Orig)
+ and then Present (Entity (Prev_Orig))
+ and then Is_Formal (Entity (Prev_Orig))
+ and then not In_Open_Scopes (Scope (Entity (Prev_Orig)))
+ then
+ Prev_Orig := Prev;
+
-- If the actual is a formal of an enclosing subprogram it is
-- the right entity, even if it is a rewriting. This happens
-- when the call is within an inherited condition or predicate.
@@ -4313,11 +4333,11 @@ package body Exp_Ch6 is
-- result from the secondary stack.
if Needs_Finalization (Etype (Subp)) then
- if not Is_Limited_View (Etype (Subp))
+ if not Is_Build_In_Place_Function_Call (Call_Node)
and then
(No (First_Formal (Subp))
- or else
- not Is_Concurrent_Record_Type (Etype (First_Formal (Subp))))
+ or else
+ not Is_Concurrent_Record_Type (Etype (First_Formal (Subp))))
then
Expand_Ctrl_Function_Call (Call_Node);
@@ -4326,14 +4346,14 @@ package body Exp_Ch6 is
-- intermediate result after its use.
elsif Is_Build_In_Place_Function_Call (Call_Node)
- and then
- Nkind_In (Parent (Call_Node), N_Attribute_Reference,
- N_Function_Call,
- N_Indexed_Component,
- N_Object_Renaming_Declaration,
- N_Procedure_Call_Statement,
- N_Selected_Component,
- N_Slice)
+ and then Nkind_In (Parent (Unqual_Conv (Call_Node)),
+ N_Attribute_Reference,
+ N_Function_Call,
+ N_Indexed_Component,
+ N_Object_Renaming_Declaration,
+ N_Procedure_Call_Statement,
+ N_Selected_Component,
+ N_Slice)
then
Establish_Transient_Scope (Call_Node, Sec_Stack => True);
end if;
@@ -4742,6 +4762,12 @@ package body Exp_Ch6 is
Func_Bod := Parent (Parent (Corresponding_Body (Func_Bod)));
end if;
+ if Nkind (Func_Bod) = N_Function_Specification then
+ Func_Bod := Parent (Func_Bod); -- one more level for child units
+ end if;
+
+ pragma Assert (Nkind (Func_Bod) = N_Subprogram_Body);
+
-- Create a flag to track the function state
Flag_Id := Make_Temporary (Loc, 'F');
@@ -4767,8 +4793,7 @@ package body Exp_Ch6 is
-- Build a simple_return_statement that returns the return object when
-- there is a statement sequence, or no expression, or the result will
-- be built in place. Note however that we currently do this for all
- -- composite cases, even though nonlimited composite results are not yet
- -- built in place (though we plan to do so eventually).
+ -- composite cases, even though not all are built in place.
if Present (HSS)
or else Is_Composite_Type (Ret_Typ)
@@ -5001,16 +5026,15 @@ package body Exp_Ch6 is
-- existing object for use as the return object. If the value
-- is two, then the return object must be allocated on the
-- secondary stack. Otherwise, the object must be allocated in
- -- a storage pool (currently only supported for the global
- -- heap, user-defined storage pools TBD ???). We generate an
- -- if statement to test the implicit allocation formal and
- -- initialize a local access value appropriately, creating
- -- allocators in the secondary stack and global heap cases.
- -- The special formal also exists and must be tested when the
- -- function has a tagged result, even when the result subtype
- -- is constrained, because in general such functions can be
- -- called in dispatching contexts and must be handled similarly
- -- to functions with a class-wide result.
+ -- a storage pool. We generate an if statement to test the
+ -- implicit allocation formal and initialize a local access
+ -- value appropriately, creating allocators in the secondary
+ -- stack and global heap cases. The special formal also exists
+ -- and must be tested when the function has a tagged result,
+ -- even when the result subtype is constrained, because in
+ -- general such functions can be called in dispatching contexts
+ -- and must be handled similarly to functions with a class-wide
+ -- result.
if not Is_Constrained (Ret_Typ)
or else Is_Tagged_Type (Underlying_Type (Ret_Typ))
@@ -5122,11 +5146,19 @@ package body Exp_Ch6 is
Set_No_Initialization (Heap_Allocator);
end if;
+ -- Set the flag indicating that the allocator came from
+ -- a build-in-place return statement, so we can avoid
+ -- adjusting the allocated object. Note that this flag
+ -- will be inherited by the copies made below.
+
+ Set_Alloc_For_BIP_Return (Heap_Allocator);
+
-- The Pool_Allocator is just like the Heap_Allocator,
-- except we set Storage_Pool and Procedure_To_Call so
-- it will use the user-defined storage pool.
Pool_Allocator := New_Copy_Tree (Heap_Allocator);
+ pragma Assert (Alloc_For_BIP_Return (Pool_Allocator));
-- Do not generate the renaming of the build-in-place
-- pool parameter on ZFP because the parameter is not
@@ -5168,6 +5200,7 @@ package body Exp_Ch6 is
else
SS_Allocator := New_Copy_Tree (Heap_Allocator);
+ pragma Assert (Alloc_For_BIP_Return (SS_Allocator));
-- The heap and pool allocators are marked as
-- Comes_From_Source since they correspond to an
@@ -5275,16 +5308,39 @@ package body Exp_Ch6 is
Temp_Typ => Ref_Type,
Func_Id => Func_Id,
Ret_Typ => Ret_Obj_Typ,
- Alloc_Expr => Heap_Allocator)))),
+ Alloc_Expr => Heap_Allocator))),
+
+ -- ???If all is well, we can put the following
+ -- 'elsif' in the 'else', but this is a useful
+ -- self-check in case caller and callee don't agree
+ -- on whether BIPAlloc and so on should be passed.
+
+ Make_Elsif_Part (Loc,
+ Condition =>
+ Make_Op_Eq (Loc,
+ Left_Opnd =>
+ New_Occurrence_Of (Obj_Alloc_Formal, Loc),
+ Right_Opnd =>
+ Make_Integer_Literal (Loc,
+ UI_From_Int (BIP_Allocation_Form'Pos
+ (User_Storage_Pool)))),
+
+ Then_Statements => New_List (
+ Pool_Decl,
+ Build_Heap_Allocator
+ (Temp_Id => Alloc_Obj_Id,
+ Temp_Typ => Ref_Type,
+ Func_Id => Func_Id,
+ Ret_Typ => Ret_Obj_Typ,
+ Alloc_Expr => Pool_Allocator)))),
+
+ -- Raise Program_Error if it's none of the above;
+ -- this is a compiler bug. ???PE_All_Guards_Closed
+ -- is bogus; we should have a new code.
Else_Statements => New_List (
- Pool_Decl,
- Build_Heap_Allocator
- (Temp_Id => Alloc_Obj_Id,
- Temp_Typ => Ref_Type,
- Func_Id => Func_Id,
- Ret_Typ => Ret_Obj_Typ,
- Alloc_Expr => Pool_Allocator)));
+ Make_Raise_Program_Error (Loc,
+ Reason => PE_All_Guards_Closed)));
-- If a separate initialization assignment was created
-- earlier, append that following the assignment of the
@@ -6370,9 +6426,9 @@ package body Exp_Ch6 is
end if;
end if;
- -- For the case of a simple return that does not come from an extended
- -- return, in the case of Ada 2005 where we are returning a limited
- -- type, we rewrite "return <expression>;" to be:
+ -- For the case of a simple return that does not come from an
+ -- extended return, in the case of build-in-place, we rewrite
+ -- "return <expression>;" to be:
-- return _anon_ : <return_subtype> := <expression>
@@ -6400,9 +6456,13 @@ package body Exp_Ch6 is
-- class-wide interface type, which is not a limited type, even though
-- the type of the expression may be.
+ pragma Assert
+ (Comes_From_Extended_Return_Statement (N)
+ or else not Is_Build_In_Place_Function_Call (Exp)
+ or else Is_Build_In_Place_Function (Scope_Id));
+
if not Comes_From_Extended_Return_Statement (N)
- and then Is_Limited_View (Etype (Expression (N)))
- and then Ada_Version >= Ada_2005
+ and then Is_Build_In_Place_Function (Scope_Id)
and then not Debug_Flag_Dot_L
-- The functionality of interface thunks is simple and it is always
@@ -6480,7 +6540,7 @@ package body Exp_Ch6 is
-- type that requires special processing (indicated by the fact that
-- it requires a cleanup scope for the secondary stack case).
- if Is_Limited_View (Exptyp)
+ if Is_Build_In_Place_Function (Scope_Id)
or else Is_Limited_Interface (Exptyp)
then
null;
@@ -7172,6 +7232,88 @@ package body Exp_Ch6 is
return False;
end Has_Unconstrained_Access_Discriminants;
+ -----------------------------------
+ -- Is_Build_In_Place_Result_Type --
+ -----------------------------------
+
+ function Is_Build_In_Place_Result_Type (Typ : Entity_Id) return Boolean is
+ begin
+ if not Expander_Active then
+ return False;
+ end if;
+
+ -- In Ada 2005 all functions with an inherently limited return type
+ -- must be handled using a build-in-place profile, including the case
+ -- of a function with a limited interface result, where the function
+ -- may return objects of nonlimited descendants.
+
+ if Is_Limited_View (Typ) then
+ return Ada_Version >= Ada_2005 and then not Debug_Flag_Dot_L;
+
+ else
+ if Debug_Flag_Dot_9 then
+ return False;
+ end if;
+
+ if Has_Interfaces (Typ) then
+ return False;
+ end if;
+
+ declare
+ T : Entity_Id := Typ;
+ begin
+ -- For T'Class, return True if it's True for T. This is necessary
+ -- because a class-wide function might say "return F (...)", where
+ -- F returns the corresponding specific type. We need a loop in
+ -- case T is a subtype of a class-wide type.
+
+ while Is_Class_Wide_Type (T) loop
+ T := Etype (T);
+ end loop;
+
+ -- If this is a generic formal type in an instance, return True if
+ -- it's True for the generic actual type.
+
+ if Nkind (Parent (T)) = N_Subtype_Declaration
+ and then Present (Generic_Parent_Type (Parent (T)))
+ then
+ T := Entity (Subtype_Indication (Parent (T)));
+
+ if Present (Full_View (T)) then
+ T := Full_View (T);
+ end if;
+ end if;
+
+ if Present (Underlying_Type (T)) then
+ T := Underlying_Type (T);
+ end if;
+
+ declare
+ Result : Boolean;
+ -- So we can stop here in the debugger
+ begin
+ -- ???For now, enable build-in-place for a very narrow set of
+ -- controlled types. Change "if True" to "if False" to
+ -- experiment more controlled types. Eventually, we would
+ -- like to enable build-in-place for all tagged types, all
+ -- types that need finalization, and all caller-unknown-size
+ -- types.
+
+ if True then
+ Result := Is_Controlled (T)
+ and then Present (Enclosing_Subprogram (T))
+ and then not Is_Compilation_Unit (Enclosing_Subprogram (T))
+ and then Ekind (Enclosing_Subprogram (T)) = E_Procedure;
+ else
+ Result := Is_Controlled (T);
+ end if;
+
+ return Result;
+ end;
+ end;
+ end if;
+ end Is_Build_In_Place_Result_Type;
+
--------------------------------
-- Is_Build_In_Place_Function --
--------------------------------
@@ -7202,19 +7344,9 @@ package body Exp_Ch6 is
-- intended to be compatible with the other language, but the build-
-- in place machinery can ensure that the object is not copied.
- if Has_Foreign_Convention (E) then
- return False;
-
- -- In Ada 2005 all functions with an inherently limited return type
- -- must be handled using a build-in-place profile, including the case
- -- of a function with a limited interface result, where the function
- -- may return objects of nonlimited descendants.
-
- else
- return Is_Limited_View (Etype (E))
- and then Ada_Version >= Ada_2005
- and then not Debug_Flag_Dot_L;
- end if;
+ return Is_Build_In_Place_Result_Type (Etype (E))
+ and then not Has_Foreign_Convention (E)
+ and then not Debug_Flag_Dot_L;
else
return False;
@@ -7242,34 +7374,34 @@ package body Exp_Ch6 is
-- may end up with a call that is neither resolved to an entity, nor
-- an indirect call.
- if not Expander_Active then
+ if not Expander_Active or else Nkind (Exp_Node) /= N_Function_Call then
return False;
end if;
- if Nkind (Exp_Node) /= N_Function_Call then
- return False;
-
- else
- if Is_Entity_Name (Name (Exp_Node)) then
- Function_Id := Entity (Name (Exp_Node));
-
- -- In the case of an explicitly dereferenced call, use the subprogram
- -- type generated for the dereference.
+ if Is_Entity_Name (Name (Exp_Node)) then
+ Function_Id := Entity (Name (Exp_Node));
- elsif Nkind (Name (Exp_Node)) = N_Explicit_Dereference then
- Function_Id := Etype (Name (Exp_Node));
+ -- In the case of an explicitly dereferenced call, use the subprogram
+ -- type generated for the dereference.
- -- This may be a call to a protected function.
+ elsif Nkind (Name (Exp_Node)) = N_Explicit_Dereference then
+ Function_Id := Etype (Name (Exp_Node));
- elsif Nkind (Name (Exp_Node)) = N_Selected_Component then
- Function_Id := Etype (Entity (Selector_Name (Name (Exp_Node))));
+ -- This may be a call to a protected function.
- else
- raise Program_Error;
- end if;
+ elsif Nkind (Name (Exp_Node)) = N_Selected_Component then
+ Function_Id := Etype (Entity (Selector_Name (Name (Exp_Node))));
- return Is_Build_In_Place_Function (Function_Id);
+ else
+ raise Program_Error;
end if;
+
+ declare
+ Result : constant Boolean := Is_Build_In_Place_Function (Function_Id);
+ -- So we can stop here in the debugger
+ begin
+ return Result;
+ end;
end Is_Build_In_Place_Function_Call;
-----------------------
@@ -7654,7 +7786,7 @@ package body Exp_Ch6 is
Function_Call : Node_Id)
is
Acc_Type : constant Entity_Id := Etype (Allocator);
- Loc : Source_Ptr;
+ Loc : constant Source_Ptr := Sloc (Function_Call);
Func_Call : Node_Id := Function_Call;
Ref_Func_Call : Node_Id;
Function_Id : Entity_Id;
@@ -7679,20 +7811,11 @@ package body Exp_Ch6 is
Func_Call := Expression (Func_Call);
end if;
- -- If the call has already been processed to add build-in-place actuals
- -- then return. This should not normally occur in an allocator context,
- -- but we add the protection as a defensive measure.
-
- if Is_Expanded_Build_In_Place_Call (Func_Call) then
- return;
- end if;
-
-- Mark the call as processed as a build-in-place call
+ pragma Assert (not Is_Expanded_Build_In_Place_Call (Func_Call));
Set_Is_Expanded_Build_In_Place_Call (Func_Call);
- Loc := Sloc (Function_Call);
-
if Is_Entity_Name (Name (Func_Call)) then
Function_Id := Entity (Name (Func_Call));
@@ -7713,6 +7836,8 @@ package body Exp_Ch6 is
Return_Obj_Access := Make_Temporary (Loc, 'R');
Set_Etype (Return_Obj_Access, Acc_Type);
+ Set_Can_Never_Be_Null (Acc_Type, False);
+ -- It gets initialized to null, so we can't have that
-- When the result subtype is constrained, the return object is
-- allocated on the caller side, and access to it is passed to the
@@ -7724,7 +7849,6 @@ package body Exp_Ch6 is
-- the characteristics of the full view.
if Is_Constrained (Underlying_Type (Result_Subt)) then
-
-- Replace the initialized allocator of form "new T'(Func (...))"
-- with an uninitialized allocator of form "new T", where T is the
-- result subtype of the called function. The call to the function
@@ -7747,10 +7871,17 @@ package body Exp_Ch6 is
Rewrite (Allocator, New_Allocator);
-- Initial value of the temp is the result of the uninitialized
- -- allocator
+ -- allocator. Unchecked_Convert is needed for T'Input where T is
+ -- derived from a controlled type.
Temp_Init := Relocate_Node (Allocator);
+ if Nkind_In
+ (Function_Call, N_Type_Conversion, N_Unchecked_Type_Conversion)
+ then
+ Temp_Init := Unchecked_Convert_To (Acc_Type, Temp_Init);
+ end if;
+
-- Indicate that caller allocates, and pass in the return object
Alloc_Form := Caller_Allocation;
@@ -7815,6 +7946,15 @@ package body Exp_Ch6 is
Rewrite
(Ref_Func_Call,
OK_Convert_To (Acc_Type, Ref_Func_Call));
+
+ -- If the types are incompatible, we need an unchecked conversion. Note
+ -- that the full types will be compatible, but the types not visibly
+ -- compatible.
+
+ elsif Nkind_In
+ (Function_Call, N_Type_Conversion, N_Unchecked_Type_Conversion)
+ then
+ Ref_Func_Call := Unchecked_Convert_To (Acc_Type, Ref_Func_Call);
end if;
declare
@@ -7826,7 +7966,8 @@ package body Exp_Ch6 is
-- caller-allocates case, this is overwriting the temp with its
-- initial value, which has no effect. In the callee-allocates case,
-- this is setting the temp to point to the object allocated by the
- -- callee.
+ -- callee. Unchecked_Convert is needed for T'Input where T is derived
+ -- from a controlled type.
Actions : List_Id;
-- Actions to be inserted. If there are no tasks, this is just the
@@ -7886,7 +8027,7 @@ package body Exp_Ch6 is
procedure Make_Build_In_Place_Call_In_Anonymous_Context
(Function_Call : Node_Id)
is
- Loc : Source_Ptr;
+ Loc : constant Source_Ptr := Sloc (Function_Call);
Func_Call : constant Node_Id := Unqual_Conv (Function_Call);
Function_Id : Entity_Id;
Result_Subt : Entity_Id;
@@ -7908,8 +8049,6 @@ package body Exp_Ch6 is
Set_Is_Expanded_Build_In_Place_Call (Func_Call);
- Loc := Sloc (Function_Call);
-
if Is_Entity_Name (Name (Func_Call)) then
Function_Id := Entity (Name (Func_Call));
@@ -8034,10 +8173,10 @@ package body Exp_Ch6 is
(Assign : Node_Id;
Function_Call : Node_Id)
is
- Lhs : constant Node_Id := Name (Assign);
- Func_Call : constant Node_Id := Unqual_Conv (Function_Call);
+ Func_Call : constant Node_Id := Unqual_Conv (Function_Call);
+ Lhs : constant Node_Id := Name (Assign);
+ Loc : constant Source_Ptr := Sloc (Function_Call);
Func_Id : Entity_Id;
- Loc : Source_Ptr;
Obj_Decl : Node_Id;
Obj_Id : Entity_Id;
Ptr_Typ : Entity_Id;
@@ -8046,20 +8185,11 @@ package body Exp_Ch6 is
Result_Subt : Entity_Id;
begin
- -- If the call has already been processed to add build-in-place actuals
- -- then return. This should not normally occur in an assignment context,
- -- but we add the protection as a defensive measure.
-
- if Is_Expanded_Build_In_Place_Call (Func_Call) then
- return;
- end if;
-
-- Mark the call as processed as a build-in-place call
+ pragma Assert (not Is_Expanded_Build_In_Place_Call (Func_Call));
Set_Is_Expanded_Build_In_Place_Call (Func_Call);
- Loc := Sloc (Function_Call);
-
if Is_Entity_Name (Name (Func_Call)) then
Func_Id := Entity (Name (Func_Call));
@@ -8117,6 +8247,14 @@ package body Exp_Ch6 is
New_Expr := Make_Reference (Loc, Relocate_Node (Func_Call));
+ -- Add a conversion if it's the wrong type
+
+ if Etype (New_Expr) /= Ptr_Typ then
+ New_Expr :=
+ Make_Unchecked_Type_Conversion (Loc,
+ New_Occurrence_Of (Ptr_Typ, Loc), New_Expr);
+ end if;
+
Obj_Id := Make_Temporary (Loc, 'R', New_Expr);
Set_Etype (Obj_Id, Ptr_Typ);
Set_Is_Known_Non_Null (Obj_Id);
@@ -8139,28 +8277,62 @@ package body Exp_Ch6 is
(Obj_Decl : Node_Id;
Function_Call : Node_Id)
is
- Obj_Def_Id : constant Entity_Id := Defining_Identifier (Obj_Decl);
- Encl_Func : constant Entity_Id := Enclosing_Subprogram (Obj_Def_Id);
- Loc : constant Source_Ptr := Sloc (Function_Call);
- Obj_Loc : constant Source_Ptr := Sloc (Obj_Decl);
+ function Get_Function_Id (Func_Call : Node_Id) return Entity_Id;
+ -- Get the value of Function_Id, below
+
+ ---------------------
+ -- Get_Function_Id --
+ ---------------------
+
+ function Get_Function_Id (Func_Call : Node_Id) return Entity_Id is
+ begin
+ if Is_Entity_Name (Name (Func_Call)) then
+ return Entity (Name (Func_Call));
+
+ elsif Nkind (Name (Func_Call)) = N_Explicit_Dereference then
+ return Etype (Name (Func_Call));
+
+ else
+ raise Program_Error;
+ end if;
+ end Get_Function_Id;
+
+ -- Local variables
+
+ Func_Call : constant Node_Id := Unqual_Conv (Function_Call);
+ Function_Id : constant Entity_Id := Get_Function_Id (Func_Call);
+ Loc : constant Source_Ptr := Sloc (Function_Call);
+ Obj_Loc : constant Source_Ptr := Sloc (Obj_Decl);
+ Obj_Def_Id : constant Entity_Id := Defining_Identifier (Obj_Decl);
+ Obj_Typ : constant Entity_Id := Etype (Obj_Def_Id);
+ Encl_Func : constant Entity_Id := Enclosing_Subprogram (Obj_Def_Id);
+ Result_Subt : constant Entity_Id := Etype (Function_Id);
Call_Deref : Node_Id;
Caller_Object : Node_Id;
Def_Id : Entity_Id;
+ Designated_Type : Entity_Id;
Fmaster_Actual : Node_Id := Empty;
- Func_Call : constant Node_Id := Unqual_Conv (Function_Call);
- Function_Id : Entity_Id;
Pool_Actual : Node_Id;
Ptr_Typ : Entity_Id;
Ptr_Typ_Decl : Node_Id;
Pass_Caller_Acc : Boolean := False;
Res_Decl : Node_Id;
- Result_Subt : Entity_Id;
+
+ Definite : constant Boolean :=
+ Caller_Known_Size (Func_Call, Result_Subt)
+ and then not Is_Class_Wide_Type (Obj_Typ);
+ -- In the case of "X : T'Class := F(...);", where F returns a
+ -- Caller_Known_Size (specific) tagged type, we treat it as
+ -- indefinite, because the code for the Definite case below sets the
+ -- initialization expression of the object to Empty, which would be
+ -- illegal Ada, and would cause gigi to misallocate X.
+
+ -- Start of processing for Make_Build_In_Place_Call_In_Object_Declaration
begin
-- If the call has already been processed to add build-in-place actuals
- -- then return. This should not normally occur in an object declaration,
- -- but we add the protection as a defensive measure.
+ -- then return.
if Is_Expanded_Build_In_Place_Call (Func_Call) then
return;
@@ -8170,246 +8342,239 @@ package body Exp_Ch6 is
Set_Is_Expanded_Build_In_Place_Call (Func_Call);
- if Is_Entity_Name (Name (Func_Call)) then
- Function_Id := Entity (Name (Func_Call));
-
- elsif Nkind (Name (Func_Call)) = N_Explicit_Dereference then
- Function_Id := Etype (Name (Func_Call));
+ -- Create an access type designating the function's result subtype.
+ -- We use the type of the original call because it may be a call to an
+ -- inherited operation, which the expansion has replaced with the parent
+ -- operation that yields the parent type. Note that this access type
+ -- must be declared before we establish a transient scope, so that it
+ -- receives the proper accessibility level.
+ if Is_Class_Wide_Type (Obj_Typ)
+ and then not Is_Interface (Obj_Typ)
+ and then not Is_Class_Wide_Type (Etype (Function_Call))
+ then
+ Designated_Type := Obj_Typ;
else
- raise Program_Error;
+ Designated_Type := Etype (Function_Call);
end if;
- Result_Subt := Etype (Function_Id);
-
- declare
- Definite : constant Boolean :=
- Caller_Known_Size (Func_Call, Result_Subt);
-
- begin
- -- Create an access type designating the function's result subtype.
- -- We use the type of the original call because it may be a call to
- -- an inherited operation, which the expansion has replaced with the
- -- parent operation that yields the parent type. Note that this
- -- access type must be declared before we establish a transient
- -- scope, so that it receives the proper accessibility level.
-
- Ptr_Typ := Make_Temporary (Loc, 'A');
- Ptr_Typ_Decl :=
- Make_Full_Type_Declaration (Loc,
- Defining_Identifier => Ptr_Typ,
- Type_Definition =>
- Make_Access_To_Object_Definition (Loc,
- All_Present => True,
- Subtype_Indication =>
- New_Occurrence_Of (Etype (Function_Call), Loc)));
-
- -- The access type and its accompanying object must be inserted after
- -- the object declaration in the constrained case, so that the
- -- function call can be passed access to the object. In the
- -- indefinite case, or if the object declaration is for a return
- -- object, the access type and object must be inserted before the
- -- object, since the object declaration is rewritten to be a renaming
- -- of a dereference of the access object. Note: we need to freeze
- -- Ptr_Typ explicitly, because the result object is in a different
- -- (transient) scope, so won't cause freezing.
-
- if Definite
- and then not Is_Return_Object (Defining_Identifier (Obj_Decl))
- then
- Insert_After_And_Analyze (Obj_Decl, Ptr_Typ_Decl);
- else
- Insert_Action (Obj_Decl, Ptr_Typ_Decl);
- end if;
-
- -- Force immediate freezing of Ptr_Typ because Res_Decl will be
- -- elaborated in an inner (transient) scope and thus won't cause
- -- freezing by itself.
-
- declare
- Ptr_Typ_Freeze_Ref : constant Node_Id :=
- New_Occurrence_Of (Ptr_Typ, Loc);
- begin
- Set_Parent (Ptr_Typ_Freeze_Ref, Ptr_Typ_Decl);
- Freeze_Expression (Ptr_Typ_Freeze_Ref);
- end;
-
- -- If the object is a return object of an enclosing build-in-place
- -- function, then the implicit build-in-place parameters of the
- -- enclosing function are simply passed along to the called function.
- -- (Unfortunately, this won't cover the case of extension aggregates
- -- where the ancestor part is a build-in-place indefinite function
- -- call that should be passed along the caller's parameters.
- -- Currently those get mishandled by reassigning the result of the
- -- call to the aggregate return object, when the call result should
- -- really be directly built in place in the aggregate and not in a
- -- temporary. ???)
-
- if Is_Return_Object (Defining_Identifier (Obj_Decl)) then
- Pass_Caller_Acc := True;
-
- -- When the enclosing function has a BIP_Alloc_Form formal then we
- -- pass it along to the callee (such as when the enclosing
- -- function has an unconstrained or tagged result type).
-
- if Needs_BIP_Alloc_Form (Encl_Func) then
- if RTE_Available (RE_Root_Storage_Pool_Ptr) then
- Pool_Actual :=
- New_Occurrence_Of
- (Build_In_Place_Formal
- (Encl_Func, BIP_Storage_Pool), Loc);
-
- -- The build-in-place pool formal is not built on e.g. ZFP
-
- else
- Pool_Actual := Empty;
- end if;
+ Ptr_Typ := Make_Temporary (Loc, 'A');
+ Ptr_Typ_Decl :=
+ Make_Full_Type_Declaration (Loc,
+ Defining_Identifier => Ptr_Typ,
+ Type_Definition =>
+ Make_Access_To_Object_Definition (Loc,
+ All_Present => True,
+ Subtype_Indication =>
+ New_Occurrence_Of (Designated_Type, Loc)));
+
+ -- The access type and its accompanying object must be inserted after
+ -- the object declaration in the constrained case, so that the function
+ -- call can be passed access to the object. In the indefinite case, or
+ -- if the object declaration is for a return object, the access type and
+ -- object must be inserted before the object, since the object
+ -- declaration is rewritten to be a renaming of a dereference of the
+ -- access object. Note: we need to freeze Ptr_Typ explicitly, because
+ -- the result object is in a different (transient) scope, so won't cause
+ -- freezing.
+
+ if Definite and then not Is_Return_Object (Obj_Def_Id) then
+ Insert_After_And_Analyze (Obj_Decl, Ptr_Typ_Decl);
+ else
+ Insert_Action (Obj_Decl, Ptr_Typ_Decl);
+ end if;
- Add_Unconstrained_Actuals_To_Build_In_Place_Call
- (Function_Call => Func_Call,
- Function_Id => Function_Id,
- Alloc_Form_Exp =>
- New_Occurrence_Of
- (Build_In_Place_Formal (Encl_Func, BIP_Alloc_Form), Loc),
- Pool_Actual => Pool_Actual);
+ -- Force immediate freezing of Ptr_Typ because Res_Decl will be
+ -- elaborated in an inner (transient) scope and thus won't cause
+ -- freezing by itself. It's not an itype, but it needs to be frozen
+ -- inside the current subprogram (see Freeze_Outside in freeze.adb).
+
+ Freeze_Itype (Ptr_Typ, Ptr_Typ_Decl);
+
+ -- If the object is a return object of an enclosing build-in-place
+ -- function, then the implicit build-in-place parameters of the
+ -- enclosing function are simply passed along to the called function.
+ -- (Unfortunately, this won't cover the case of extension aggregates
+ -- where the ancestor part is a build-in-place indefinite function
+ -- call that should be passed along the caller's parameters.
+ -- Currently those get mishandled by reassigning the result of the
+ -- call to the aggregate return object, when the call result should
+ -- really be directly built in place in the aggregate and not in a
+ -- temporary. ???)
+
+ if Is_Return_Object (Obj_Def_Id) then
+ Pass_Caller_Acc := True;
+
+ -- When the enclosing function has a BIP_Alloc_Form formal then we
+ -- pass it along to the callee (such as when the enclosing function
+ -- has an unconstrained or tagged result type).
+
+ if Needs_BIP_Alloc_Form (Encl_Func) then
+ if RTE_Available (RE_Root_Storage_Pool_Ptr) then
+ Pool_Actual :=
+ New_Occurrence_Of
+ (Build_In_Place_Formal
+ (Encl_Func, BIP_Storage_Pool), Loc);
- -- Otherwise, if enclosing function has a definite result subtype,
- -- then caller allocation will be used.
+ -- The build-in-place pool formal is not built on e.g. ZFP
else
- Add_Unconstrained_Actuals_To_Build_In_Place_Call
- (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
+ Pool_Actual := Empty;
end if;
- if Needs_BIP_Finalization_Master (Encl_Func) then
- Fmaster_Actual :=
+ Add_Unconstrained_Actuals_To_Build_In_Place_Call
+ (Function_Call => Func_Call,
+ Function_Id => Function_Id,
+ Alloc_Form_Exp =>
New_Occurrence_Of
- (Build_In_Place_Formal
- (Encl_Func, BIP_Finalization_Master), Loc);
- end if;
+ (Build_In_Place_Formal (Encl_Func, BIP_Alloc_Form), Loc),
+ Pool_Actual => Pool_Actual);
- -- Retrieve the BIPacc formal from the enclosing function and
- -- convert it to the access type of the callee's BIP_Object_Access
- -- formal.
+ -- Otherwise, if enclosing function has a definite result subtype,
+ -- then caller allocation will be used.
- Caller_Object :=
- Make_Unchecked_Type_Conversion (Loc,
- Subtype_Mark =>
- New_Occurrence_Of
- (Etype
- (Build_In_Place_Formal
- (Function_Id, BIP_Object_Access)),
- Loc),
- Expression =>
- New_Occurrence_Of
- (Build_In_Place_Formal (Encl_Func, BIP_Object_Access),
- Loc));
+ else
+ Add_Unconstrained_Actuals_To_Build_In_Place_Call
+ (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
+ end if;
- -- In the definite case, add an implicit actual to the function call
- -- that provides access to the declared object. An unchecked
- -- conversion to the (specific) result type of the function is
- -- inserted to handle the case where the object is declared with a
- -- class-wide type.
+ if Needs_BIP_Finalization_Master (Encl_Func) then
+ Fmaster_Actual :=
+ New_Occurrence_Of
+ (Build_In_Place_Formal
+ (Encl_Func, BIP_Finalization_Master), Loc);
+ end if;
- elsif Definite then
- Caller_Object :=
- Make_Unchecked_Type_Conversion (Loc,
- Subtype_Mark => New_Occurrence_Of (Result_Subt, Loc),
- Expression => New_Occurrence_Of (Obj_Def_Id, Loc));
+ -- Retrieve the BIPacc formal from the enclosing function and convert
+ -- it to the access type of the callee's BIP_Object_Access formal.
- -- When the function has a controlling result, an allocation-form
- -- parameter must be passed indicating that the caller is
- -- allocating the result object. This is needed because such a
- -- function can be called as a dispatching operation and must be
- -- treated similarly to functions with indefinite result subtypes.
+ Caller_Object :=
+ Make_Unchecked_Type_Conversion (Loc,
+ Subtype_Mark =>
+ New_Occurrence_Of
+ (Etype (Build_In_Place_Formal
+ (Function_Id, BIP_Object_Access)),
+ Loc),
+ Expression =>
+ New_Occurrence_Of
+ (Build_In_Place_Formal (Encl_Func, BIP_Object_Access),
+ Loc));
- Add_Unconstrained_Actuals_To_Build_In_Place_Call
- (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
+ -- In the definite case, add an implicit actual to the function call
+ -- that provides access to the declared object. An unchecked conversion
+ -- to the (specific) result type of the function is inserted to handle
+ -- the case where the object is declared with a class-wide type.
- -- The allocation for indefinite library-level objects occurs on the
- -- heap as opposed to the secondary stack. This accommodates DLLs
- -- where the secondary stack is destroyed after each library
- -- unload. This is a hybrid mechanism where a stack-allocated object
- -- lives on the heap.
+ elsif Definite then
+ Caller_Object :=
+ Make_Unchecked_Type_Conversion (Loc,
+ Subtype_Mark => New_Occurrence_Of (Result_Subt, Loc),
+ Expression => New_Occurrence_Of (Obj_Def_Id, Loc));
- elsif Is_Library_Level_Entity (Defining_Identifier (Obj_Decl))
- and then not Restriction_Active (No_Implicit_Heap_Allocations)
- then
- Add_Unconstrained_Actuals_To_Build_In_Place_Call
- (Func_Call, Function_Id, Alloc_Form => Global_Heap);
- Caller_Object := Empty;
+ -- When the function has a controlling result, an allocation-form
+ -- parameter must be passed indicating that the caller is allocating
+ -- the result object. This is needed because such a function can be
+ -- called as a dispatching operation and must be treated similarly to
+ -- functions with indefinite result subtypes.
- -- Create a finalization master for the access result type to
- -- ensure that the heap allocation can properly chain the object
- -- and later finalize it when the library unit goes out of scope.
+ Add_Unconstrained_Actuals_To_Build_In_Place_Call
+ (Func_Call, Function_Id, Alloc_Form => Caller_Allocation);
- if Needs_Finalization (Etype (Func_Call)) then
- Build_Finalization_Master
- (Typ => Ptr_Typ,
- For_Lib_Level => True,
- Insertion_Node => Ptr_Typ_Decl);
+ -- The allocation for indefinite library-level objects occurs on the
+ -- heap as opposed to the secondary stack. This accommodates DLLs where
+ -- the secondary stack is destroyed after each library unload. This is a
+ -- hybrid mechanism where a stack-allocated object lives on the heap.
- Fmaster_Actual :=
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Occurrence_Of (Finalization_Master (Ptr_Typ), Loc),
- Attribute_Name => Name_Unrestricted_Access);
- end if;
+ elsif Is_Library_Level_Entity (Obj_Def_Id)
+ and then not Restriction_Active (No_Implicit_Heap_Allocations)
+ then
+ Add_Unconstrained_Actuals_To_Build_In_Place_Call
+ (Func_Call, Function_Id, Alloc_Form => Global_Heap);
+ Caller_Object := Empty;
- -- In other indefinite cases, pass an indication to do the allocation
- -- on the secondary stack and set Caller_Object to Empty so that a
- -- null value will be passed for the caller's object address. A
- -- transient scope is established to ensure eventual cleanup of the
- -- result.
+ -- Create a finalization master for the access result type to ensure
+ -- that the heap allocation can properly chain the object and later
+ -- finalize it when the library unit goes out of scope.
- else
- Add_Unconstrained_Actuals_To_Build_In_Place_Call
- (Func_Call, Function_Id, Alloc_Form => Secondary_Stack);
- Caller_Object := Empty;
+ if Needs_Finalization (Etype (Func_Call)) then
+ Build_Finalization_Master
+ (Typ => Ptr_Typ,
+ For_Lib_Level => True,
+ Insertion_Node => Ptr_Typ_Decl);
- Establish_Transient_Scope (Obj_Decl, Sec_Stack => True);
+ Fmaster_Actual :=
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (Finalization_Master (Ptr_Typ), Loc),
+ Attribute_Name => Name_Unrestricted_Access);
end if;
- -- Pass along any finalization master actual, which is needed in the
- -- case where the called function initializes a return object of an
- -- enclosing build-in-place function.
+ -- In other indefinite cases, pass an indication to do the allocation on
+ -- the secondary stack and set Caller_Object to Empty so that a null
+ -- value will be passed for the caller's object address. A transient
+ -- scope is established to ensure eventual cleanup of the result.
- Add_Finalization_Master_Actual_To_Build_In_Place_Call
- (Func_Call => Func_Call,
- Func_Id => Function_Id,
- Master_Exp => Fmaster_Actual);
+ else
+ Add_Unconstrained_Actuals_To_Build_In_Place_Call
+ (Func_Call, Function_Id, Alloc_Form => Secondary_Stack);
+ Caller_Object := Empty;
- if Nkind (Parent (Obj_Decl)) = N_Extended_Return_Statement
- and then Has_Task (Result_Subt)
- then
- -- Here we're passing along the master that was passed in to this
- -- function.
+ Establish_Transient_Scope (Obj_Decl, Sec_Stack => True);
+ end if;
- Add_Task_Actuals_To_Build_In_Place_Call
- (Func_Call, Function_Id,
- Master_Actual =>
- New_Occurrence_Of
- (Build_In_Place_Formal (Encl_Func, BIP_Task_Master), Loc));
+ -- Pass along any finalization master actual, which is needed in the
+ -- case where the called function initializes a return object of an
+ -- enclosing build-in-place function.
- else
- Add_Task_Actuals_To_Build_In_Place_Call
- (Func_Call, Function_Id, Make_Identifier (Loc, Name_uMaster));
- end if;
+ Add_Finalization_Master_Actual_To_Build_In_Place_Call
+ (Func_Call => Func_Call,
+ Func_Id => Function_Id,
+ Master_Exp => Fmaster_Actual);
- Add_Access_Actual_To_Build_In_Place_Call
- (Func_Call,
- Function_Id,
- Caller_Object,
- Is_Access => Pass_Caller_Acc);
+ if Nkind (Parent (Obj_Decl)) = N_Extended_Return_Statement
+ and then Has_Task (Result_Subt)
+ then
+ -- Here we're passing along the master that was passed in to this
+ -- function.
- -- Finally, create an access object initialized to a reference to the
- -- function call. We know this access value cannot be null, so mark
- -- the entity accordingly to suppress the access check.
+ Add_Task_Actuals_To_Build_In_Place_Call
+ (Func_Call, Function_Id,
+ Master_Actual =>
+ New_Occurrence_Of
+ (Build_In_Place_Formal (Encl_Func, BIP_Task_Master), Loc));
- Def_Id := Make_Temporary (Loc, 'R', Func_Call);
- Set_Etype (Def_Id, Ptr_Typ);
- Set_Is_Known_Non_Null (Def_Id);
+ else
+ Add_Task_Actuals_To_Build_In_Place_Call
+ (Func_Call, Function_Id, Make_Identifier (Loc, Name_uMaster));
+ end if;
+
+ Add_Access_Actual_To_Build_In_Place_Call
+ (Func_Call,
+ Function_Id,
+ Caller_Object,
+ Is_Access => Pass_Caller_Acc);
+ -- Finally, create an access object initialized to a reference to the
+ -- function call. We know this access value cannot be null, so mark the
+ -- entity accordingly to suppress the access check.
+
+ Def_Id := Make_Temporary (Loc, 'R', Func_Call);
+ Set_Etype (Def_Id, Ptr_Typ);
+ Set_Is_Known_Non_Null (Def_Id);
+
+ if Nkind_In (Function_Call, N_Type_Conversion,
+ N_Unchecked_Type_Conversion)
+ then
+ Res_Decl :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Def_Id,
+ Constant_Present => True,
+ Object_Definition => New_Occurrence_Of (Ptr_Typ, Loc),
+ Expression =>
+ Make_Unchecked_Type_Conversion (Loc,
+ New_Occurrence_Of (Ptr_Typ, Loc),
+ Make_Reference (Loc, Relocate_Node (Func_Call))));
+ else
Res_Decl :=
Make_Object_Declaration (Loc,
Defining_Identifier => Def_Id,
@@ -8417,81 +8582,72 @@ package body Exp_Ch6 is
Object_Definition => New_Occurrence_Of (Ptr_Typ, Loc),
Expression =>
Make_Reference (Loc, Relocate_Node (Func_Call)));
+ end if;
- Insert_After_And_Analyze (Ptr_Typ_Decl, Res_Decl);
+ Insert_After_And_Analyze (Ptr_Typ_Decl, Res_Decl);
- -- If the result subtype of the called function is definite and is
- -- not itself the return expression of an enclosing BIP function,
- -- then mark the object as having no initialization.
+ -- If the result subtype of the called function is definite and is not
+ -- itself the return expression of an enclosing BIP function, then mark
+ -- the object as having no initialization.
- if Definite
- and then not Is_Return_Object (Defining_Identifier (Obj_Decl))
- then
- -- The related object declaration is encased in a transient block
- -- because the build-in-place function call contains at least one
- -- nested function call that produces a controlled transient
- -- temporary:
+ if Definite and then not Is_Return_Object (Obj_Def_Id) then
- -- Obj : ... := BIP_Func_Call (Ctrl_Func_Call);
+ -- The related object declaration is encased in a transient block
+ -- because the build-in-place function call contains at least one
+ -- nested function call that produces a controlled transient
+ -- temporary:
- -- Since the build-in-place expansion decouples the call from the
- -- object declaration, the finalization machinery lacks the
- -- context which prompted the generation of the transient
- -- block. To resolve this scenario, store the build-in-place call.
+ -- Obj : ... := BIP_Func_Call (Ctrl_Func_Call);
- if Scope_Is_Transient and then Node_To_Be_Wrapped = Obj_Decl then
- Set_BIP_Initialization_Call (Obj_Def_Id, Res_Decl);
- end if;
+ -- Since the build-in-place expansion decouples the call from the
+ -- object declaration, the finalization machinery lacks the context
+ -- which prompted the generation of the transient block. To resolve
+ -- this scenario, store the build-in-place call.
- Set_Expression (Obj_Decl, Empty);
- Set_No_Initialization (Obj_Decl);
+ if Scope_Is_Transient and then Node_To_Be_Wrapped = Obj_Decl then
+ Set_BIP_Initialization_Call (Obj_Def_Id, Res_Decl);
+ end if;
- -- In case of an indefinite result subtype, or if the call is the
- -- return expression of an enclosing BIP function, rewrite the object
- -- declaration as an object renaming where the renamed object is a
- -- dereference of <function_Call>'reference:
- --
- -- Obj : Subt renames <function_call>'Ref.all;
+ Set_Expression (Obj_Decl, Empty);
+ Set_No_Initialization (Obj_Decl);
- else
- Call_Deref :=
- Make_Explicit_Dereference (Obj_Loc,
- Prefix => New_Occurrence_Of (Def_Id, Obj_Loc));
-
- Rewrite (Obj_Decl,
- Make_Object_Renaming_Declaration (Obj_Loc,
- Defining_Identifier => Make_Temporary (Obj_Loc, 'D'),
- Subtype_Mark => New_Occurrence_Of (Result_Subt, Obj_Loc),
- Name => Call_Deref));
-
- Set_Renamed_Object (Defining_Identifier (Obj_Decl), Call_Deref);
-
- -- If the original entity comes from source, then mark the new
- -- entity as needing debug information, even though it's defined
- -- by a generated renaming that does not come from source, so that
- -- the Materialize_Entity flag will be set on the entity when
- -- Debug_Renaming_Declaration is called during analysis.
-
- if Comes_From_Source (Obj_Def_Id) then
- Set_Debug_Info_Needed (Defining_Identifier (Obj_Decl));
- end if;
+ -- In case of an indefinite result subtype, or if the call is the
+ -- return expression of an enclosing BIP function, rewrite the object
+ -- declaration as an object renaming where the renamed object is a
+ -- dereference of <function_Call>'reference:
+ --
+ -- Obj : Subt renames <function_call>'Ref.all;
- Analyze (Obj_Decl);
- Replace_Renaming_Declaration_Id
- (Obj_Decl, Original_Node (Obj_Decl));
+ else
+ Call_Deref :=
+ Make_Explicit_Dereference (Obj_Loc,
+ Prefix => New_Occurrence_Of (Def_Id, Obj_Loc));
+
+ Rewrite (Obj_Decl,
+ Make_Object_Renaming_Declaration (Obj_Loc,
+ Defining_Identifier => Make_Temporary (Obj_Loc, 'D'),
+ Subtype_Mark =>
+ New_Occurrence_Of (Designated_Type, Obj_Loc),
+ Name => Call_Deref));
+
+ -- At this point, Defining_Identifier (Obj_Decl) is no longer equal
+ -- to Obj_Def_Id.
+
+ Set_Renamed_Object (Defining_Identifier (Obj_Decl), Call_Deref);
+
+ -- If the original entity comes from source, then mark the new
+ -- entity as needing debug information, even though it's defined
+ -- by a generated renaming that does not come from source, so that
+ -- the Materialize_Entity flag will be set on the entity when
+ -- Debug_Renaming_Declaration is called during analysis.
+
+ if Comes_From_Source (Obj_Def_Id) then
+ Set_Debug_Info_Needed (Defining_Identifier (Obj_Decl));
end if;
- end;
-
- -- If the object entity has a class-wide Etype, then we need to change
- -- it to the result subtype of the function call, because otherwise the
- -- object will be class-wide without an explicit initialization and
- -- won't be allocated properly by the back end. It seems unclean to make
- -- such a revision to the type at this point, and we should try to
- -- improve this treatment when build-in-place functions with class-wide
- -- results are implemented. ???
- if Is_Class_Wide_Type (Etype (Defining_Identifier (Obj_Decl))) then
- Set_Etype (Defining_Identifier (Obj_Decl), Result_Subt);
+ Analyze (Obj_Decl);
+ Replace_Renaming_Declaration_Id
+ (Obj_Decl, Original_Node (Obj_Decl));
end if;
end Make_Build_In_Place_Call_In_Object_Declaration;
@@ -9179,7 +9335,7 @@ package body Exp_Ch6 is
then
On_Object_Declaration := True;
return
- Unqual_BIP_Function_Call (Expression (Parent (Entity (Expr))));
+ Unqual_BIP_Function_Call (Expression (Parent (Entity (Expr))));
-- Recurse to handle calls to displace the pointer to the object to
-- reference a secondary dispatch table.
@@ -9211,6 +9367,13 @@ package body Exp_Ch6 is
-- Start of processing for Unqual_BIP_Iface_Function_Call
begin
+ if Nkind (Expr) = N_Identifier and then No (Entity (Expr)) then
+
+ -- Can happen for X'Elab_Spec in the binder-generated file
+
+ return Empty;
+ end if;
+
return Unqual_BIP_Function_Call (Expr);
end Unqual_BIP_Iface_Function_Call;
diff --git a/gcc/ada/exp_ch6.ads b/gcc/ada/exp_ch6.ads
index c4fc3bc..530f615 100644
--- a/gcc/ada/exp_ch6.ads
+++ b/gcc/ada/exp_ch6.ads
@@ -117,25 +117,30 @@ package Exp_Ch6 is
-- The returned node is the root of the procedure body which will replace
-- the original function body, which is not needed for the C program.
+ function Is_Build_In_Place_Result_Type (Typ : Entity_Id) return Boolean;
+ -- Ada 2005 (AI-318-02): Returns True if functions returning the type use
+ -- build-in-place protocols. For inherently limited types, this must be
+ -- True in >= Ada 2005, and must be False in Ada 95. For other types, it
+ -- can be True or False, and the decision should be based on efficiency,
+ -- and should be the same for all language versions, so that mixed-dialect
+ -- programs will work.
+ --
+ -- For inherently limited types in Ada 2005, True means that calls will
+ -- actually be build-in-place in all cases. For other types, build-in-place
+ -- will be used when possible, but we need to make a copy at the call site
+ -- in some cases, notably assignment statements.
+
function Is_Build_In_Place_Function (E : Entity_Id) return Boolean;
-- Ada 2005 (AI-318-02): Returns True if E denotes a function, generic
- -- function, or access-to-function type whose result must be built in
- -- place; otherwise returns False. For Ada 2005, this is currently
- -- restricted to the set of functions whose result subtype is an inherently
- -- limited type. In Ada 95, this must be False for inherently limited
- -- result types (but currently returns False for all Ada 95 functions).
- -- Eventually we plan to support build-in-place for nonlimited types.
- -- Build-in-place is usually more efficient for large things, and less
- -- efficient for small things. However, we never use build-in-place if the
- -- convention is other than Ada, because that would disturb mixed-language
- -- programs. Note that for the non-inherently-limited cases, we must make
- -- the same decision for Ada 95 and 2005, so that mixed-dialect programs
- -- will work.
+ -- function, or access-to-function type for which
+ -- Is_Build_In_Place_Result_Type is True. However, we never use
+ -- build-in-place if the convention is other than Ada, because that would
+ -- disturb mixed-language programs.
function Is_Build_In_Place_Function_Call (N : Node_Id) return Boolean;
-- Ada 2005 (AI-318-02): Returns True if N denotes a call to a function
- -- that requires handling as a build-in-place call or is a qualified
- -- expression applied to such a call; otherwise returns False.
+ -- that requires handling as a build-in-place call (possibly qualified or
+ -- converted).
function Is_Null_Procedure (Subp : Entity_Id) return Boolean;
-- Predicate to recognize stubbed procedures and null procedures, which
@@ -212,7 +217,7 @@ package Exp_Ch6 is
(Obj_Decl : Node_Id;
Function_Call : Node_Id);
-- Ada 2005 (AI-318-02): Handle a call to a build-in-place function that
- -- occurs as the expression initializing an object declaration by passsing
+ -- occurs as the expression initializing an object declaration by passing
-- access to the declared object as an additional parameter of the function
-- call. Function_Call must denote an expression containing a BIP function
-- call and an enclosing call to Ada.Tags.Displace to displace the pointer
diff --git a/gcc/ada/exp_ch7.adb b/gcc/ada/exp_ch7.adb
index 2ca42de..713ba58 100644
--- a/gcc/ada/exp_ch7.adb
+++ b/gcc/ada/exp_ch7.adb
@@ -1955,7 +1955,7 @@ package body Exp_Ch7 is
Insert_After (Finalizer_Insert_Nod, Fin_Body);
end if;
- Analyze (Fin_Body);
+ Analyze (Fin_Body, Suppress => All_Checks);
end if;
end Create_Finalizer;
@@ -2605,8 +2605,8 @@ package body Exp_Ch7 is
-- procedures of types Init_Typ or Obj_Typ.
function Next_Suitable_Statement (Stmt : Node_Id) return Node_Id;
- -- Given a statement which is part of a list, return the next
- -- statement while skipping over dynamic elab checks.
+ -- Obtain the next statement which follows list member Stmt while
+ -- ignoring artifacts related to access-before-elaboration checks.
-----------------------------
-- Find_Last_Init_In_Block --
@@ -2725,16 +2725,22 @@ package body Exp_Ch7 is
-----------------------------
function Next_Suitable_Statement (Stmt : Node_Id) return Node_Id is
- Result : Node_Id := Next (Stmt);
+ Result : Node_Id;
begin
- -- Skip over access-before-elaboration checks
+ -- Skip call markers and Program_Error raises installed by the
+ -- ABE mechanism.
+
+ Result := Next (Stmt);
+ while Present (Result) loop
+ if not Nkind_In (Result, N_Call_Marker,
+ N_Raise_Program_Error)
+ then
+ exit;
+ end if;
- if Dynamic_Elaboration_Checks
- and then Nkind (Result) = N_Raise_Program_Error
- then
Result := Next (Result);
- end if;
+ end loop;
return Result;
end Next_Suitable_Statement;
@@ -4057,7 +4063,7 @@ package body Exp_Ch7 is
-- This procedure is called each time a transient block has to be inserted
-- that is to say for each call to a function with unconstrained or tagged
- -- result. It creates a new scope on the stack scope in order to enclose
+ -- result. It creates a new scope on the scope stack in order to enclose
-- all transient variables generated.
procedure Establish_Transient_Scope (N : Node_Id; Sec_Stack : Boolean) is
@@ -4463,7 +4469,7 @@ package body Exp_Ch7 is
-- This is done only for non-generic packages
if Ekind (Spec_Id) = E_Package then
- Push_Scope (Corresponding_Spec (N));
+ Push_Scope (Spec_Id);
-- Build dispatch tables of library level tagged types
@@ -4475,18 +4481,15 @@ package body Exp_Ch7 is
Build_Task_Activation_Call (N);
- -- When the package is subject to pragma Initial_Condition, the
- -- assertion expression must be verified at the end of the body
- -- statements.
+ -- Verify the run-time semantics of pragma Initial_Condition at the
+ -- end of the body statements.
- if Present (Get_Pragma (Spec_Id, Pragma_Initial_Condition)) then
- Expand_Pragma_Initial_Condition (N);
- end if;
+ Expand_Pragma_Initial_Condition (Spec_Id, N);
Pop_Scope;
end if;
- Set_Elaboration_Flag (N, Corresponding_Spec (N));
+ Set_Elaboration_Flag (N, Spec_Id);
Set_In_Package_Body (Spec_Id, False);
-- Set to encode entity names in package body before gigi is called
@@ -4601,14 +4604,10 @@ package body Exp_Ch7 is
Build_Task_Activation_Call (N);
end if;
- -- When the package is subject to pragma Initial_Condition and lacks
- -- a body, the assertion expression must be verified at the end of
- -- the visible declarations. Otherwise the check is performed at the
- -- end of the body statements (see Expand_N_Package_Body).
+ -- Verify the run-time semantics of pragma Initial_Condition at the
+ -- end of the private declarations when the package lacks a body.
- if Present (Get_Pragma (Id, Pragma_Initial_Condition)) then
- Expand_Pragma_Initial_Condition (N);
- end if;
+ Expand_Pragma_Initial_Condition (Id, N);
Pop_Scope;
end if;
diff --git a/gcc/ada/exp_ch8.adb b/gcc/ada/exp_ch8.adb
index ba0f7c2..08c6805 100644
--- a/gcc/ada/exp_ch8.adb
+++ b/gcc/ada/exp_ch8.adb
@@ -176,23 +176,16 @@ package body Exp_Ch8 is
-- Ada 2005 (AI-318-02): If the renamed object is a call to a build-in-
-- place function, then a temporary return object needs to be created
- -- and access to it must be passed to the function. Currently we limit
- -- such functions to those with inherently limited result subtypes, but
- -- eventually we plan to expand the functions that are treated as
- -- build-in-place to include other composite result types.
+ -- and access to it must be passed to the function.
- if Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (Nam)
- then
+ if Is_Build_In_Place_Function_Call (Nam) then
Make_Build_In_Place_Call_In_Anonymous_Context (Nam);
-- Ada 2005 (AI-318-02): Specialization of previous case for renaming
-- containing build-in-place function calls whose returned object covers
-- interface types.
- elsif Ada_Version >= Ada_2005
- and then Present (Unqual_BIP_Iface_Function_Call (Nam))
- then
+ elsif Present (Unqual_BIP_Iface_Function_Call (Nam)) then
Make_Build_In_Place_Iface_Call_In_Anonymous_Context (Nam);
end if;
diff --git a/gcc/ada/exp_ch9.adb b/gcc/ada/exp_ch9.adb
index 0cd4fde..063b812 100644
--- a/gcc/ada/exp_ch9.adb
+++ b/gcc/ada/exp_ch9.adb
@@ -52,7 +52,6 @@ with Sem_Ch6; use Sem_Ch6;
with Sem_Ch8; use Sem_Ch8;
with Sem_Ch9; use Sem_Ch9;
with Sem_Ch11; use Sem_Ch11;
-with Sem_Elab; use Sem_Elab;
with Sem_Eval; use Sem_Eval;
with Sem_Res; use Sem_Res;
with Sem_Util; use Sem_Util;
@@ -340,6 +339,14 @@ package body Exp_Ch9 is
-- same parameter names and the same resolved types, but with new entities
-- for the formals.
+ function Create_Secondary_Stack_For_Task (T : Node_Id) return Boolean;
+ -- Return whether a secondary stack for the task T should be created by the
+ -- expander. The secondary stack for a task will be created by the expander
+ -- if the size of the stack has been specified by the Secondary_Stack_Size
+ -- representation aspect and either the No_Implicit_Heap_Allocations or
+ -- No_Implicit_Task_Allocations restrictions are in effect and the
+ -- No_Secondary_Stack restriction is not.
+
procedure Debug_Private_Data_Declarations (Decls : List_Id);
-- Decls is a list which may contain the declarations created by Install_
-- Private_Data_Declarations. All generated entities are marked as needing
@@ -3841,6 +3848,12 @@ package body Exp_Ch9 is
Set_Original_Protected_Subprogram (New_Id, Def_Id);
end if;
+ -- Link the protected or unprotected version to the original subprogram
+ -- it emulates.
+
+ Set_Ekind (New_Id, Ekind (Def_Id));
+ Set_Protected_Subprogram (New_Id, Def_Id);
+
-- The unprotected operation carries the user code, and debugging
-- information must be generated for it, even though this spec does
-- not come from source. It is also convenient to allow gdb to step
@@ -4751,11 +4764,39 @@ package body Exp_Ch9 is
--------------------------------
procedure Build_Task_Activation_Call (N : Node_Id) is
- Loc : constant Source_Ptr := Sloc (N);
+ function Activation_Call_Loc return Source_Ptr;
+ -- Find a suitable source location for the activation call
+
+ -------------------------
+ -- Activation_Call_Loc --
+ -------------------------
+
+ function Activation_Call_Loc return Source_Ptr is
+ begin
+ -- The activation call must carry the location of the "end" keyword
+ -- when the context is a package declaration.
+
+ if Nkind (N) = N_Package_Declaration then
+ return End_Keyword_Location (N);
+
+ -- Otherwise the activation call must carry the location of the
+ -- "begin" keyword.
+
+ else
+ return Begin_Keyword_Location (N);
+ end if;
+ end Activation_Call_Loc;
+
+ -- Local variables
+
Chain : Entity_Id;
Call : Node_Id;
+ Loc : Source_Ptr;
Name : Node_Id;
- P : Node_Id;
+ Owner : Node_Id;
+ Stmt : Node_Id;
+
+ -- Start of processing for Build_Task_Activation_Call
begin
-- For sequential elaboration policy, all the tasks will be activated at
@@ -4763,105 +4804,107 @@ package body Exp_Ch9 is
if Partition_Elaboration_Policy = 'S' then
return;
- end if;
- -- Get the activation chain entity. Except in the case of a package
- -- body, this is in the node that was passed. For a package body, we
- -- have to find the corresponding package declaration node.
+ -- Do not create an activation call for a package spec if the package
+ -- has a completing body. The activation call will be inserted after
+ -- the "begin" of the body.
- if Nkind (N) = N_Package_Body then
- P := Corresponding_Spec (N);
- loop
- P := Parent (P);
- exit when Nkind (P) = N_Package_Declaration;
- end loop;
+ elsif Nkind (N) = N_Package_Declaration
+ and then Present (Corresponding_Body (N))
+ then
+ return;
+ end if;
- Chain := Activation_Chain_Entity (P);
+ -- Obtain the activation chain entity. Block statements, entry bodies,
+ -- subprogram bodies, and task bodies keep the entity in their nodes.
+ -- Package bodies on the other hand store it in the declaration of the
+ -- corresponding package spec.
- else
- Chain := Activation_Chain_Entity (N);
+ Owner := N;
+
+ if Nkind (Owner) = N_Package_Body then
+ Owner := Unit_Declaration_Node (Corresponding_Spec (Owner));
end if;
- if Present (Chain) then
- if Restricted_Profile then
- Name := New_Occurrence_Of
- (RTE (RE_Activate_Restricted_Tasks), Loc);
- else
- Name := New_Occurrence_Of
- (RTE (RE_Activate_Tasks), Loc);
- end if;
+ Chain := Activation_Chain_Entity (Owner);
- Call :=
- Make_Procedure_Call_Statement (Loc,
- Name => Name,
- Parameter_Associations =>
- New_List (Make_Attribute_Reference (Loc,
- Prefix => New_Occurrence_Of (Chain, Loc),
- Attribute_Name => Name_Unchecked_Access)));
+ -- Nothing to do when there are no tasks to activate. This is indicated
+ -- by a missing activation chain entity.
- if Nkind (N) = N_Package_Declaration then
- if Present (Corresponding_Body (N)) then
- null;
+ if No (Chain) then
+ return;
+ end if;
- elsif Present (Private_Declarations (Specification (N))) then
- Append (Call, Private_Declarations (Specification (N)));
+ -- The location of the activation call must be as close as possible to
+ -- the intended semantic location of the activation because the ABE
+ -- mechanism relies heavily on accurate locations.
- else
- Append (Call, Visible_Declarations (Specification (N)));
- end if;
+ Loc := Activation_Call_Loc;
- else
- if Present (Handled_Statement_Sequence (N)) then
+ if Restricted_Profile then
+ Name := New_Occurrence_Of (RTE (RE_Activate_Restricted_Tasks), Loc);
+ else
+ Name := New_Occurrence_Of (RTE (RE_Activate_Tasks), Loc);
+ end if;
- -- The call goes at the start of the statement sequence after
- -- the start of exception range label if one is present.
+ Call :=
+ Make_Procedure_Call_Statement (Loc,
+ Name => Name,
+ Parameter_Associations =>
+ New_List (Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Chain, Loc),
+ Attribute_Name => Name_Unchecked_Access)));
- declare
- Stm : Node_Id;
+ if Nkind (N) = N_Package_Declaration then
+ if Present (Private_Declarations (Specification (N))) then
+ Append (Call, Private_Declarations (Specification (N)));
+ else
+ Append (Call, Visible_Declarations (Specification (N)));
+ end if;
- begin
- Stm := First (Statements (Handled_Statement_Sequence (N)));
+ else
+ -- The call goes at the start of the statement sequence after the
+ -- start of exception range label if one is present.
- -- A special case, skip exception range label if one is
- -- present (from front end zcx processing).
+ if Present (Handled_Statement_Sequence (N)) then
+ Stmt := First (Statements (Handled_Statement_Sequence (N)));
- if Nkind (Stm) = N_Label and then Exception_Junk (Stm) then
- Next (Stm);
- end if;
+ -- A special case, skip exception range label if one is present
+ -- (from front end zcx processing).
- -- Another special case, if the first statement is a block
- -- from optimization of a local raise to a goto, then the
- -- call goes inside this block.
+ if Nkind (Stmt) = N_Label and then Exception_Junk (Stmt) then
+ Next (Stmt);
+ end if;
- if Nkind (Stm) = N_Block_Statement
- and then Exception_Junk (Stm)
- then
- Stm :=
- First (Statements (Handled_Statement_Sequence (Stm)));
- end if;
+ -- Another special case, if the first statement is a block from
+ -- optimization of a local raise to a goto, then the call goes
+ -- inside this block.
- -- Insertion point is after any exception label pushes,
- -- since we want it covered by any local handlers.
+ if Nkind (Stmt) = N_Block_Statement
+ and then Exception_Junk (Stmt)
+ then
+ Stmt := First (Statements (Handled_Statement_Sequence (Stmt)));
+ end if;
- while Nkind (Stm) in N_Push_xxx_Label loop
- Next (Stm);
- end loop;
+ -- Insertion point is after any exception label pushes, since we
+ -- want it covered by any local handlers.
- -- Now we have the proper insertion point
+ while Nkind (Stmt) in N_Push_xxx_Label loop
+ Next (Stmt);
+ end loop;
- Insert_Before (Stm, Call);
- end;
+ -- Now we have the proper insertion point
- else
- Set_Handled_Statement_Sequence (N,
- Make_Handled_Sequence_Of_Statements (Loc,
- Statements => New_List (Call)));
- end if;
- end if;
+ Insert_Before (Stmt, Call);
- Analyze (Call);
- Check_Task_Activation (N);
+ else
+ Set_Handled_Statement_Sequence (N,
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (Call)));
+ end if;
end if;
+
+ Analyze (Call);
end Build_Task_Activation_Call;
-------------------------------
@@ -5380,6 +5423,20 @@ package body Exp_Ch9 is
end Convert_Concurrent;
-------------------------------------
+ -- Create_Secondary_Stack_For_Task --
+ -------------------------------------
+
+ function Create_Secondary_Stack_For_Task (T : Node_Id) return Boolean is
+ begin
+ return
+ (Restriction_Active (No_Implicit_Heap_Allocations)
+ or else Restriction_Active (No_Implicit_Task_Allocations))
+ and then not Restriction_Active (No_Secondary_Stack)
+ and then Has_Rep_Item
+ (T, Name_Secondary_Stack_Size, Check_Parents => False);
+ end Create_Secondary_Stack_For_Task;
+
+ -------------------------------------
-- Debug_Private_Data_Declarations --
-------------------------------------
@@ -6006,6 +6063,15 @@ package body Exp_Ch9 is
-- reference will have been rewritten.
if Expander_Active then
+
+ -- The expanded name may have been constant folded in which case
+ -- the original node is not necessarily an entity name (e.g. an
+ -- indexed component).
+
+ if not Is_Entity_Name (Original_Node (N)) then
+ return False;
+ end if;
+
Renamed := Renamed_Object (Entity (Original_Node (N)));
return
@@ -10519,6 +10585,11 @@ package body Exp_Ch9 is
Make_Defining_Identifier (Eloc,
New_External_Name (Chars (Ename), 'A', Num_Accept));
+ -- Link the acceptor to the original receiving entry
+
+ Set_Ekind (PB_Ent, E_Procedure);
+ Set_Receiving_Entry (PB_Ent, Eent);
+
if Comes_From_Source (Alt) then
Set_Debug_Info_Needed (PB_Ent);
end if;
@@ -11663,6 +11734,7 @@ package body Exp_Ch9 is
Body_Decl : Node_Id;
Cdecls : List_Id;
Decl_Stack : Node_Id;
+ Decl_SS : Node_Id;
Elab_Decl : Node_Id;
Ent_Stack : Entity_Id;
Proc_Spec : Node_Id;
@@ -11890,6 +11962,57 @@ package body Exp_Ch9 is
end if;
+ -- Declare a static secondary stack if the conditions for a statically
+ -- generated stack are met.
+
+ if Create_Secondary_Stack_For_Task (TaskId) then
+ declare
+ Ritem : Node_Id;
+ Size_Expr : Node_Id;
+
+ begin
+ -- First extract the secondary stack size from the task type's
+ -- representation aspect.
+
+ Ritem :=
+ Get_Rep_Item
+ (TaskId, Name_Secondary_Stack_Size, Check_Parents => False);
+
+ -- Get Secondary_Stack_Size expression. Can be a pragma or aspect.
+
+ if Nkind (Ritem) = N_Pragma then
+ Size_Expr :=
+ Expression
+ (First (Pragma_Argument_Associations (Ritem)));
+ else
+ Size_Expr := Expression (Ritem);
+ end if;
+
+ pragma Assert (Compile_Time_Known_Value (Size_Expr));
+
+ -- Create the secondary stack for the task
+
+ Decl_SS :=
+ Make_Component_Declaration (Loc,
+ Defining_Identifier =>
+ Make_Defining_Identifier (Loc, Name_uSecondary_Stack),
+ Component_Definition =>
+ Make_Component_Definition (Loc,
+ Aliased_Present => True,
+ Subtype_Indication =>
+ Make_Subtype_Indication (Loc,
+ Subtype_Mark =>
+ New_Occurrence_Of (RTE (RE_SS_Stack), Loc),
+ Constraint =>
+ Make_Index_Or_Discriminant_Constraint (Loc,
+ Constraints => New_List (
+ Make_Integer_Literal (Loc,
+ Expr_Value (Size_Expr)))))));
+
+ Append_To (Cdecls, Decl_SS);
+ end;
+ end if;
+
-- Add components for entry families
Collect_Entry_Families (Loc, Cdecls, Size_Decl, Tasktyp);
@@ -12786,11 +12909,14 @@ package body Exp_Ch9 is
end if;
-- If the type of the dispatching object is an access type then return
- -- an explicit dereference.
+ -- an explicit dereference of a copy of the object, and note that
+ -- this is the controlling actual of the call.
if Is_Access_Type (Etype (Object)) then
- Object := Make_Explicit_Dereference (Sloc (N), Object);
+ Object :=
+ Make_Explicit_Dereference (Sloc (N), New_Copy_Tree (Object));
Analyze (Object);
+ Set_Is_Controlling_Actual (Object);
end if;
end Extract_Dispatching_Call;
@@ -14087,11 +14213,33 @@ package body Exp_Ch9 is
New_Occurrence_Of (Storage_Size_Variable (Ttyp), Loc));
end if;
- -- Secondary_Stack_Size parameter. Set Default_Secondary_Stack_Size
- -- unless there is a Secondary_Stack_Size rep item, in which case we
- -- take the value from the rep item. If the restriction
- -- No_Secondary_Stack is active then a size of 0 is passed regardless
- -- to prevent the allocation of the unused stack.
+ -- Secondary_Stack parameter used for restricted profiles
+
+ if Restricted_Profile then
+
+ -- If the secondary stack has been allocated by the expander then
+ -- pass its access pointer. Otherwise, pass null.
+
+ if Create_Secondary_Stack_For_Task (Ttyp) then
+ Append_To (Args,
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ Make_Selected_Component (Loc,
+ Prefix => Make_Identifier (Loc, Name_uInit),
+ Selector_Name =>
+ Make_Identifier (Loc, Name_uSecondary_Stack)),
+ Attribute_Name => Name_Unrestricted_Access));
+
+ else
+ Append_To (Args, Make_Null (Loc));
+ end if;
+ end if;
+
+ -- Secondary_Stack_Size parameter. Set RE_Unspecified_Size unless there
+ -- is a Secondary_Stack_Size rep item, in which case take the value from
+ -- the rep item. If the restriction No_Secondary_Stack is active then a
+ -- size of 0 is passed regardless to prevent the allocation of the
+ -- unused stack.
if Restriction_Active (No_Secondary_Stack) then
Append_To (Args, Make_Integer_Literal (Loc, 0));
@@ -14416,6 +14564,12 @@ package body Exp_Ch9 is
Object_Definition =>
New_Occurrence_Of (Etype (Formal), Loc)));
+ -- The object is initialized with an explicit assignment
+ -- later. Indicate that it does not need an initialization
+ -- to prevent spurious warnings if the type excludes null.
+
+ Set_No_Initialization (Last (Decls));
+
if Ekind (Formal) /= E_Out_Parameter then
-- Generate:
@@ -14432,15 +14586,22 @@ package body Exp_Ch9 is
Expression => New_Copy_Tree (Actual)));
end if;
- -- Generate:
+ -- If the actual is not controlling, generate:
+
-- Jnn'unchecked_access
- Append_To (Params,
- Make_Attribute_Reference (Loc,
- Attribute_Name => Name_Unchecked_Access,
- Prefix => New_Occurrence_Of (Temp_Nam, Loc)));
+ -- and add it to aggegate for access to formals. Note that
+ -- the actual may be by-copy but still be a controlling actual
+ -- if it is an access to class-wide interface.
+
+ if not Is_Controlling_Actual (Actual) then
+ Append_To (Params,
+ Make_Attribute_Reference (Loc,
+ Attribute_Name => Name_Unchecked_Access,
+ Prefix => New_Occurrence_Of (Temp_Nam, Loc)));
- Has_Param := True;
+ Has_Param := True;
+ end if;
-- The controlling parameter is omitted
diff --git a/gcc/ada/exp_dbug.adb b/gcc/ada/exp_dbug.adb
index 1b51d53..70c21c0 100644
--- a/gcc/ada/exp_dbug.adb
+++ b/gcc/ada/exp_dbug.adb
@@ -23,7 +23,7 @@
-- --
------------------------------------------------------------------------------
-with Alloc; use Alloc;
+with Alloc;
with Atree; use Atree;
with Debug; use Debug;
with Einfo; use Einfo;
diff --git a/gcc/ada/exp_disp.adb b/gcc/ada/exp_disp.adb
index 6719f2e..f3728f6 100644
--- a/gcc/ada/exp_disp.adb
+++ b/gcc/ada/exp_disp.adb
@@ -29,6 +29,7 @@ with Debug; use Debug;
with Einfo; use Einfo;
with Elists; use Elists;
with Errout; use Errout;
+with Expander; use Expander;
with Exp_Atag; use Exp_Atag;
with Exp_Ch6; use Exp_Ch6;
with Exp_CG; use Exp_CG;
@@ -300,6 +301,32 @@ package body Exp_Disp is
end Building_Static_DT;
----------------------------------
+ -- Building_Static_Secondary_DT --
+ ----------------------------------
+
+ function Building_Static_Secondary_DT (Typ : Entity_Id) return Boolean is
+ Full_Typ : Entity_Id := Typ;
+ Root_Typ : Entity_Id := Root_Type (Typ);
+
+ begin
+ -- Handle private types
+
+ if Present (Full_View (Typ)) then
+ Full_Typ := Full_View (Typ);
+ end if;
+
+ if Present (Full_View (Root_Typ)) then
+ Root_Typ := Full_View (Root_Typ);
+ end if;
+
+ return Building_Static_DT (Full_Typ)
+ and then not Is_Interface (Full_Typ)
+ and then Has_Interfaces (Full_Typ)
+ and then (Full_Typ = Root_Typ
+ or else not Is_Variable_Size_Record (Etype (Full_Typ)));
+ end Building_Static_Secondary_DT;
+
+ ----------------------------------
-- Build_Static_Dispatch_Tables --
----------------------------------
@@ -709,6 +736,18 @@ package body Exp_Disp is
if Is_Class_Wide_Type (Etype (F)) then
Set_Etype (N, Etype (F));
+
+ -- Conversely, if this is a controlling argument
+ -- (in a dispatching call in the condition) that is a
+ -- dereference, the source is an access-to-class-wide
+ -- type, so preserve the dispatching nature of the
+ -- call in the rewritten condition.
+
+ elsif Nkind (Parent (N)) = N_Explicit_Dereference
+ and then Is_Controlling_Actual (Parent (N))
+ then
+ Set_Controlling_Argument (Parent (Parent (N)),
+ Parent (N));
end if;
exit;
@@ -1640,9 +1679,7 @@ package body Exp_Disp is
-- interface conversion, so if this is a BIP call then we need
-- to handle it now.
- if Ada_Version >= Ada_2005
- and then Is_Build_In_Place_Function_Call (Actual)
- then
+ if Is_Build_In_Place_Function_Call (Actual) then
Make_Build_In_Place_Call_In_Anonymous_Context (Actual);
end if;
@@ -1695,11 +1732,10 @@ package body Exp_Disp is
if From_Limited_With (Actual_Typ) then
- -- If the type of the actual parameter comes from a
- -- limited with-clause and the non-limited view is already
- -- available, we replace the anonymous access type by
- -- a duplicate declaration whose designated type is the
- -- non-limited view.
+ -- If the type of the actual parameter comes from a limited
+ -- with_clause and the nonlimited view is already available,
+ -- we replace the anonymous access type by a duplicate
+ -- declaration whose designated type is the nonlimited view.
if Has_Non_Limited_View (Actual_DDT) then
Anon := New_Copy (Actual_Typ);
@@ -3757,6 +3793,11 @@ package body Exp_Disp is
DT_Aggr : constant Elist_Id := New_Elmt_List;
-- Entities marked with attribute Is_Dispatch_Table_Entity
+ Dummy_Object : Entity_Id := Empty;
+ -- Extra nonexistent object of type Typ internally used to compute the
+ -- offset to the components that reference secondary dispatch tables.
+ -- Used to statically allocate secondary dispatch tables.
+
procedure Check_Premature_Freezing
(Subp : Entity_Id;
Tagged_Type : Entity_Id;
@@ -3785,6 +3826,7 @@ package body Exp_Disp is
procedure Make_Secondary_DT
(Typ : Entity_Id;
Iface : Entity_Id;
+ Iface_Comp : Node_Id;
Suffix_Index : Int;
Num_Iface_Prims : Nat;
Iface_DT_Ptr : Entity_Id;
@@ -3943,6 +3985,7 @@ package body Exp_Disp is
procedure Make_Secondary_DT
(Typ : Entity_Id;
Iface : Entity_Id;
+ Iface_Comp : Node_Id;
Suffix_Index : Int;
Num_Iface_Prims : Nat;
Iface_DT_Ptr : Entity_Id;
@@ -4181,10 +4224,25 @@ package body Exp_Disp is
Prefix => New_Occurrence_Of (Predef_Prims, Loc),
Attribute_Name => Name_Address));
- -- Note: The correct value of Offset_To_Top will be set by the init
- -- subprogram
+ -- If the location of the component that references this secondary
+ -- dispatch table is variable then we have not declared the internal
+ -- dummy object; the value of Offset_To_Top will be set by the init
+ -- subprogram.
- Append_To (DT_Aggr_List, Make_Integer_Literal (Loc, 0));
+ if No (Dummy_Object) then
+ Append_To (DT_Aggr_List, Make_Integer_Literal (Loc, 0));
+
+ else
+ Append_To (DT_Aggr_List,
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ Make_Selected_Component (Loc,
+ Prefix =>
+ New_Occurrence_Of (Dummy_Object, Loc),
+ Selector_Name =>
+ New_Occurrence_Of (Iface_Comp, Loc)),
+ Attribute_Name => Name_Position));
+ end if;
-- Generate the Object Specific Data table required to dispatch calls
-- through synchronized interfaces.
@@ -4409,15 +4467,16 @@ package body Exp_Disp is
Append_Elmt (New_Node, DT_Aggr);
- -- Note: Secondary dispatch tables cannot be declared constant
- -- because the component Offset_To_Top is currently initialized
- -- by the IP routine.
+ -- Note: Secondary dispatch tables are declared constant only if
+ -- we can compute their offset field by means of the extra dummy
+ -- object; otherwise they cannot be declared constant and the
+ -- Offset_To_Top component is initialized by the IP routine.
Append_To (Result,
Make_Object_Declaration (Loc,
Defining_Identifier => Iface_DT,
Aliased_Present => True,
- Constant_Present => False,
+ Constant_Present => Present (Dummy_Object),
Object_Definition =>
Make_Subtype_Indication (Loc,
@@ -4680,6 +4739,94 @@ package body Exp_Disp is
end;
end if;
+ if Building_Static_Secondary_DT (Typ) then
+ declare
+ Cannot_Have_Null_Disc : Boolean := False;
+ Name_Dummy_Object : constant Name_Id :=
+ New_External_Name (Tname,
+ 'P', Suffix_Index => -1);
+ begin
+ Dummy_Object := Make_Defining_Identifier (Loc, Name_Dummy_Object);
+
+ -- Define the extra object imported and constant to avoid linker
+ -- errors (since this object is never declared). Required because
+ -- we implement RM 13.3(19) for exported and imported (variable)
+ -- objects by making them volatile.
+
+ Set_Is_Imported (Dummy_Object);
+ Set_Ekind (Dummy_Object, E_Constant);
+ Set_Is_True_Constant (Dummy_Object);
+ Set_Related_Type (Dummy_Object, Typ);
+
+ -- The scope must be set now to call Get_External_Name
+
+ Set_Scope (Dummy_Object, Current_Scope);
+
+ Get_External_Name (Dummy_Object);
+ Set_Interface_Name (Dummy_Object,
+ Make_String_Literal (Loc, Strval => String_From_Name_Buffer));
+
+ -- Ensure proper Sprint output of this implicit importation
+
+ Set_Is_Internal (Dummy_Object);
+
+ if not Has_Discriminants (Typ) then
+ Append_To (Result,
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Dummy_Object,
+ Constant_Present => True,
+ Object_Definition => New_Occurrence_Of (Typ, Loc)));
+ else
+ declare
+ Constr_List : constant List_Id := New_List;
+ Discrim : Node_Id;
+
+ begin
+ Discrim := First_Discriminant (Typ);
+ while Present (Discrim) loop
+ if Is_Discrete_Type (Etype (Discrim)) then
+ Append_To (Constr_List,
+ Make_Attribute_Reference (Loc,
+ Prefix =>
+ New_Occurrence_Of (Etype (Discrim), Loc),
+ Attribute_Name => Name_First));
+
+ else
+ pragma Assert (Is_Access_Type (Etype (Discrim)));
+ Cannot_Have_Null_Disc :=
+ Cannot_Have_Null_Disc
+ or else Can_Never_Be_Null (Etype (Discrim));
+ Append_To (Constr_List, Make_Null (Loc));
+ end if;
+
+ Next_Discriminant (Discrim);
+ end loop;
+
+ Append_To (Result,
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Dummy_Object,
+ Constant_Present => True,
+ Object_Definition =>
+ Make_Subtype_Indication (Loc,
+ Subtype_Mark => New_Occurrence_Of (Typ, Loc),
+ Constraint =>
+ Make_Index_Or_Discriminant_Constraint (Loc,
+ Constraints => Constr_List))));
+ end;
+ end if;
+
+ -- Given that the dummy object will not be declared at run time,
+ -- analyze its declaration with expansion disabled and warnings
+ -- and error messages ignored.
+
+ Expander_Mode_Save_And_Set (False);
+ Ignore_Errors_Enable := Ignore_Errors_Enable + 1;
+ Analyze (Last (Result), Suppress => All_Checks);
+ Ignore_Errors_Enable := Ignore_Errors_Enable - 1;
+ Expander_Mode_Restore;
+ end;
+ end if;
+
-- Ada 2005 (AI-251): Build the secondary dispatch tables
if Has_Interfaces (Typ) then
@@ -4704,11 +4851,12 @@ package body Exp_Disp is
Make_Secondary_DT
(Typ => Typ,
- Iface => Base_Type
- (Related_Type (Node (AI_Tag_Comp))),
+ Iface =>
+ Base_Type (Related_Type (Node (AI_Tag_Comp))),
+ Iface_Comp => Node (AI_Tag_Comp),
Suffix_Index => Suffix_Index,
- Num_Iface_Prims => UI_To_Int
- (DT_Entry_Count (Node (AI_Tag_Comp))),
+ Num_Iface_Prims =>
+ UI_To_Int (DT_Entry_Count (Node (AI_Tag_Comp))),
Iface_DT_Ptr => Node (AI_Tag_Elmt),
Predef_Prims_Ptr => Node (Next_Elmt (AI_Tag_Elmt)),
Build_Thunks => True,
@@ -4733,6 +4881,7 @@ package body Exp_Disp is
(Typ => Typ,
Iface => Base_Type
(Related_Type (Node (AI_Tag_Comp))),
+ Iface_Comp => Node (AI_Tag_Comp),
Suffix_Index => -1,
Num_Iface_Prims => UI_To_Int
(DT_Entry_Count (Node (AI_Tag_Comp))),
diff --git a/gcc/ada/exp_disp.ads b/gcc/ada/exp_disp.ads
index cfd4b78..cba4cac 100644
--- a/gcc/ada/exp_disp.ads
+++ b/gcc/ada/exp_disp.ads
@@ -174,6 +174,11 @@ package Exp_Disp is
pragma Inline (Building_Static_DT);
-- Returns true when building statically allocated dispatch tables
+ function Building_Static_Secondary_DT (Typ : Entity_Id) return Boolean;
+ pragma Inline (Building_Static_Secondary_DT);
+ -- Returns true when building statically allocated secondary dispatch
+ -- tables
+
procedure Build_Static_Dispatch_Tables (N : Node_Id);
-- N is a library level package declaration or package body. Build the
-- static dispatch table of the tagged types defined at library level. In
diff --git a/gcc/ada/exp_imgv.adb b/gcc/ada/exp_imgv.adb
index f42f94d..7877707 100644
--- a/gcc/ada/exp_imgv.adb
+++ b/gcc/ada/exp_imgv.adb
@@ -174,7 +174,7 @@ package body Exp_Imgv is
-- Expand_Image_Attribute --
----------------------------
- -- For all cases other than user defined enumeration types, the scheme
+ -- For all cases other than user-defined enumeration types, the scheme
-- is as follows. First we insert the following code:
-- Snn : String (1 .. rt'Width);
@@ -263,10 +263,176 @@ package body Exp_Imgv is
-- position of the enumeration value in the enumeration type.
procedure Expand_Image_Attribute (N : Node_Id) is
- Loc : constant Source_Ptr := Sloc (N);
- Exprs : constant List_Id := Expressions (N);
- Pref : constant Node_Id := Prefix (N);
- Expr : constant Node_Id := Relocate_Node (First (Exprs));
+ Loc : constant Source_Ptr := Sloc (N);
+ Exprs : constant List_Id := Expressions (N);
+ Expr : constant Node_Id := Relocate_Node (First (Exprs));
+ Pref : constant Node_Id := Prefix (N);
+
+ procedure Expand_User_Defined_Enumeration_Image;
+ -- Expand attribute 'Image in user-defined enumeration types, avoiding
+ -- string copy.
+
+ function Is_User_Defined_Enumeration_Type
+ (Typ : Entity_Id) return Boolean;
+ -- Return True if Typ is a user-defined enumeration type
+
+ -------------------------------------------
+ -- Expand_User_Defined_Enumeration_Image --
+ -------------------------------------------
+
+ procedure Expand_User_Defined_Enumeration_Image is
+ Ins_List : constant List_Id := New_List;
+ P1_Id : constant Entity_Id := Make_Temporary (Loc, 'P');
+ P2_Id : constant Entity_Id := Make_Temporary (Loc, 'P');
+ P3_Id : constant Entity_Id := Make_Temporary (Loc, 'P');
+ P4_Id : constant Entity_Id := Make_Temporary (Loc, 'P');
+ Ptyp : constant Entity_Id := Entity (Pref);
+ Rtyp : constant Entity_Id := Root_Type (Ptyp);
+ S1_Id : constant Entity_Id := Make_Temporary (Loc, 'S');
+
+ begin
+ -- Apply a validity check, since it is a bit drastic to get a
+ -- completely junk image value for an invalid value.
+
+ if not Expr_Known_Valid (Expr) then
+ Insert_Valid_Check (Expr);
+ end if;
+
+ -- Generate:
+ -- P1 : constant Natural := Pos;
+
+ Append_To (Ins_List,
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => P1_Id,
+ Object_Definition =>
+ New_Occurrence_Of (Standard_Natural, Loc),
+ Constant_Present => True,
+ Expression =>
+ Convert_To (Standard_Natural,
+ Make_Attribute_Reference (Loc,
+ Attribute_Name => Name_Pos,
+ Prefix => New_Occurrence_Of (Ptyp, Loc),
+ Expressions => New_List (Expr)))));
+
+ -- Compute the index of the string start, generating:
+ -- P2 : constant Natural := call_put_enumN (P1);
+
+ Append_To (Ins_List,
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => P2_Id,
+ Object_Definition =>
+ New_Occurrence_Of (Standard_Natural, Loc),
+ Constant_Present => True,
+ Expression =>
+ Convert_To (Standard_Natural,
+ Make_Indexed_Component (Loc,
+ Prefix =>
+ New_Occurrence_Of (Lit_Indexes (Rtyp), Loc),
+ Expressions =>
+ New_List (New_Occurrence_Of (P1_Id, Loc))))));
+
+ -- Compute the index of the next value, generating:
+ -- P3 : constant Natural := call_put_enumN (P1 + 1);
+
+ declare
+ Add_Node : constant Node_Id := New_Op_Node (N_Op_Add, Loc);
+
+ begin
+ Set_Left_Opnd (Add_Node, New_Occurrence_Of (P1_Id, Loc));
+ Set_Right_Opnd (Add_Node, Make_Integer_Literal (Loc, 1));
+
+ Append_To (Ins_List,
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => P3_Id,
+ Object_Definition =>
+ New_Occurrence_Of (Standard_Natural, Loc),
+ Constant_Present => True,
+ Expression =>
+ Convert_To (Standard_Natural,
+ Make_Indexed_Component (Loc,
+ Prefix =>
+ New_Occurrence_Of (Lit_Indexes (Rtyp), Loc),
+ Expressions =>
+ New_List (Add_Node)))));
+ end;
+
+ -- Generate:
+ -- S4 : String renames call_put_enumS (S2 .. S3 - 1);
+
+ declare
+ Sub_Node : constant Node_Id := New_Op_Node (N_Op_Subtract, Loc);
+
+ begin
+ Set_Left_Opnd (Sub_Node, New_Occurrence_Of (P3_Id, Loc));
+ Set_Right_Opnd (Sub_Node, Make_Integer_Literal (Loc, 1));
+
+ Append_To (Ins_List,
+ Make_Object_Renaming_Declaration (Loc,
+ Defining_Identifier => P4_Id,
+ Subtype_Mark =>
+ New_Occurrence_Of (Standard_String, Loc),
+ Name =>
+ Make_Slice (Loc,
+ Prefix =>
+ New_Occurrence_Of (Lit_Strings (Rtyp), Loc),
+ Discrete_Range =>
+ Make_Range (Loc,
+ Low_Bound => New_Occurrence_Of (P2_Id, Loc),
+ High_Bound => Sub_Node))));
+ end;
+
+ -- Generate:
+ -- subtype S1 is string (1 .. P3 - P2);
+
+ declare
+ HB : constant Node_Id := New_Op_Node (N_Op_Subtract, Loc);
+
+ begin
+ Set_Left_Opnd (HB, New_Occurrence_Of (P3_Id, Loc));
+ Set_Right_Opnd (HB, New_Occurrence_Of (P2_Id, Loc));
+
+ Append_To (Ins_List,
+ Make_Subtype_Declaration (Loc,
+ Defining_Identifier => S1_Id,
+ Subtype_Indication =>
+ Make_Subtype_Indication (Loc,
+ Subtype_Mark =>
+ New_Occurrence_Of (Standard_String, Loc),
+ Constraint =>
+ Make_Index_Or_Discriminant_Constraint (Loc,
+ Constraints => New_List (
+ Make_Range (Loc,
+ Low_Bound => Make_Integer_Literal (Loc, 1),
+ High_Bound => HB))))));
+ end;
+
+ -- Insert all the above declarations before N. We suppress checks
+ -- because everything is in range at this stage.
+
+ Insert_Actions (N, Ins_List, Suppress => All_Checks);
+
+ Rewrite (N,
+ Unchecked_Convert_To (S1_Id, New_Occurrence_Of (P4_Id, Loc)));
+
+ Analyze_And_Resolve (N, Standard_String);
+ end Expand_User_Defined_Enumeration_Image;
+
+ --------------------------------------
+ -- Is_User_Defined_Enumeration_Type --
+ --------------------------------------
+
+ function Is_User_Defined_Enumeration_Type
+ (Typ : Entity_Id) return Boolean is
+ begin
+ return Ekind (Typ) = E_Enumeration_Type
+ and then Typ /= Standard_Boolean
+ and then Typ /= Standard_Character
+ and then Typ /= Standard_Wide_Character
+ and then Typ /= Standard_Wide_Wide_Character;
+ end Is_User_Defined_Enumeration_Type;
+
+ -- Local variables
+
Imid : RE_Id;
Ptyp : Entity_Id;
Rtyp : Entity_Id;
@@ -288,6 +454,18 @@ package body Exp_Imgv is
if Is_Object_Image (Pref) then
Rewrite_Object_Image (N, Pref, Name_Image, Standard_String);
return;
+
+ -- Enable speed-optimized expansion of user-defined enumeration types
+ -- if we are compiling with optimizations enabled and enumeration type
+ -- literals are generated. Otherwise the call will be expanded into a
+ -- call to the runtime library.
+
+ elsif Optimization_Level > 0
+ and then not Global_Discard_Names
+ and then Is_User_Defined_Enumeration_Type (Root_Type (Entity (Pref)))
+ then
+ Expand_User_Defined_Enumeration_Image;
+ return;
end if;
Ptyp := Entity (Pref);
@@ -385,7 +563,7 @@ package body Exp_Imgv is
Imid := RE_Image_Floating_Point;
Tent := Standard_Long_Long_Float;
- -- Only other possibility is user defined enumeration type
+ -- Only other possibility is user-defined enumeration type
else
if Discard_Names (First_Subtype (Ptyp))
@@ -680,7 +858,7 @@ package body Exp_Imgv is
elsif Is_Real_Type (Rtyp) then
Vid := RE_Value_Real;
- -- Only other possibility is user defined enumeration type
+ -- Only other possibility is user-defined enumeration type
else
pragma Assert (Is_Enumeration_Type (Rtyp));
@@ -753,7 +931,7 @@ package body Exp_Imgv is
return;
end if;
- -- Fall through for all cases except user defined enumeration type
+ -- Fall through for all cases except user-defined enumeration type
-- and decimal types, with Vid set to the Id of the entity for the
-- Value routine and Args set to the list of parameters for the call.
@@ -1070,7 +1248,7 @@ package body Exp_Imgv is
-- because the base type is always static, and hence the expression
-- in the else is reduced to an integer literal.
- -- For user defined enumeration types, typ'Width expands into
+ -- For user-defined enumeration types, typ'Width expands into
-- Result_Type (Width_Enumeration_NN
-- (typS,
@@ -1195,7 +1373,7 @@ package body Exp_Imgv is
Analyze_And_Resolve (N, Typ);
return;
- -- User defined enumeration types
+ -- User-defined enumeration types
else
pragma Assert (Is_Enumeration_Type (Rtyp));
diff --git a/gcc/ada/exp_prag.adb b/gcc/ada/exp_prag.adb
index 57f60cd..dfed6af 100644
--- a/gcc/ada/exp_prag.adb
+++ b/gcc/ada/exp_prag.adb
@@ -42,6 +42,7 @@ with Restrict; use Restrict;
with Rident; use Rident;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
+with Sem_Aux; use Sem_Aux;
with Sem_Ch8; use Sem_Ch8;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
@@ -1447,82 +1448,287 @@ package body Exp_Prag is
-- Expand_Pragma_Initial_Condition --
-------------------------------------
- procedure Expand_Pragma_Initial_Condition (Spec_Or_Body : Node_Id) is
- Loc : constant Source_Ptr := Sloc (Spec_Or_Body);
+ procedure Expand_Pragma_Initial_Condition
+ (Pack_Id : Entity_Id;
+ N : Node_Id)
+ is
+ procedure Extract_Package_Body_Lists
+ (Pack_Body : Node_Id;
+ Body_List : out List_Id;
+ Call_List : out List_Id;
+ Spec_List : out List_Id);
+ -- Obtain the various declarative and statement lists of package body
+ -- Pack_Body needed to insert the initial condition procedure and the
+ -- call to it. The lists are as follows:
+ --
+ -- * Body_List - used to insert the initial condition procedure body
+ --
+ -- * Call_List - used to insert the call to the initial condition
+ -- procedure.
+ --
+ -- * Spec_List - used to insert the initial condition procedure spec
+
+ procedure Extract_Package_Declaration_Lists
+ (Pack_Decl : Node_Id;
+ Body_List : out List_Id;
+ Call_List : out List_Id;
+ Spec_List : out List_Id);
+ -- Obtain the various declarative lists of package declaration Pack_Decl
+ -- needed to insert the initial condition procedure and the call to it.
+ -- The lists are as follows:
+ --
+ -- * Body_List - used to insert the initial condition procedure body
+ --
+ -- * Call_List - used to insert the call to the initial condition
+ -- procedure.
+ --
+ -- * Spec_List - used to insert the initial condition procedure spec
+
+ --------------------------------
+ -- Extract_Package_Body_Lists --
+ --------------------------------
+
+ procedure Extract_Package_Body_Lists
+ (Pack_Body : Node_Id;
+ Body_List : out List_Id;
+ Call_List : out List_Id;
+ Spec_List : out List_Id)
+ is
+ Pack_Spec : constant Entity_Id := Corresponding_Spec (Pack_Body);
- Check : Node_Id;
- Expr : Node_Id;
- Init_Cond : Node_Id;
- List : List_Id;
- Pack_Id : Entity_Id;
+ Dummy_1 : List_Id;
+ Dummy_2 : List_Id;
+ HSS : Node_Id;
- begin
- if Nkind (Spec_Or_Body) = N_Package_Body then
- Pack_Id := Corresponding_Spec (Spec_Or_Body);
+ begin
+ pragma Assert (Present (Pack_Spec));
- if Present (Handled_Statement_Sequence (Spec_Or_Body)) then
- List := Statements (Handled_Statement_Sequence (Spec_Or_Body));
+ -- The different parts of the invariant procedure are inserted as
+ -- follows:
- -- The package body lacks statements, create an empty list
+ -- package Pack is package body Pack is
+ -- <IC spec> <IC body>
+ -- private begin
+ -- ... <IC call>
+ -- end Pack; end Pack;
- else
- List := New_List;
+ -- The initial condition procedure spec is inserted in the visible
+ -- declaration of the corresponding package spec.
+
+ Extract_Package_Declaration_Lists
+ (Pack_Decl => Unit_Declaration_Node (Pack_Spec),
+ Body_List => Dummy_1,
+ Call_List => Dummy_2,
+ Spec_List => Spec_List);
+
+ -- The initial condition procedure body is added to the declarations
+ -- of the package body.
+
+ Body_List := Declarations (Pack_Body);
- Set_Handled_Statement_Sequence (Spec_Or_Body,
- Make_Handled_Sequence_Of_Statements (Loc, Statements => List));
+ if No (Body_List) then
+ Body_List := New_List;
+ Set_Declarations (Pack_Body, Body_List);
end if;
- elsif Nkind (Spec_Or_Body) = N_Package_Declaration then
- Pack_Id := Defining_Entity (Spec_Or_Body);
+ -- The call to the initial condition procedure is inserted in the
+ -- statements of the package body.
- if Present (Visible_Declarations (Specification (Spec_Or_Body))) then
- List := Visible_Declarations (Specification (Spec_Or_Body));
+ HSS := Handled_Statement_Sequence (Pack_Body);
- -- The package lacks visible declarations, create an empty list
+ if No (HSS) then
+ HSS :=
+ Make_Handled_Sequence_Of_Statements (Sloc (Pack_Body),
+ Statements => New_List);
+ Set_Handled_Statement_Sequence (Pack_Body, HSS);
+ end if;
- else
- List := New_List;
+ Call_List := Statements (HSS);
+ end Extract_Package_Body_Lists;
+
+ ---------------------------------------
+ -- Extract_Package_Declaration_Lists --
+ ---------------------------------------
+
+ procedure Extract_Package_Declaration_Lists
+ (Pack_Decl : Node_Id;
+ Body_List : out List_Id;
+ Call_List : out List_Id;
+ Spec_List : out List_Id)
+ is
+ Pack_Spec : constant Node_Id := Specification (Pack_Decl);
+
+ begin
+ -- The different parts of the invariant procedure are inserted as
+ -- follows:
- Set_Visible_Declarations (Specification (Spec_Or_Body), List);
+ -- package Pack is
+ -- <IC spec>
+ -- <IC body>
+ -- private
+ -- <IC call>
+ -- end Pack;
+
+ -- The initial condition procedure spec and body are inserted in the
+ -- visible declarations of the package spec.
+
+ Body_List := Visible_Declarations (Pack_Spec);
+
+ if No (Body_List) then
+ Body_List := New_List;
+ Set_Visible_Declarations (Pack_Spec, Body_List);
+ end if;
+
+ Spec_List := Body_List;
+
+ -- The call to the initial procedure is inserted in the private
+ -- declarations of the package spec.
+
+ Call_List := Private_Declarations (Pack_Spec);
+
+ if No (Call_List) then
+ Call_List := New_List;
+ Set_Private_Declarations (Pack_Spec, Call_List);
end if;
+ end Extract_Package_Declaration_Lists;
+
+ -- Local variables
+
+ IC_Prag : constant Node_Id :=
+ Get_Pragma (Pack_Id, Pragma_Initial_Condition);
+
+ Body_List : List_Id;
+ Call : Node_Id;
+ Call_List : List_Id;
+ Call_Loc : Source_Ptr;
+ Expr : Node_Id;
+ Loc : Source_Ptr;
+ Proc_Body : Node_Id;
+ Proc_Body_Id : Entity_Id;
+ Proc_Decl : Node_Id;
+ Proc_Id : Entity_Id;
+ Spec_List : List_Id;
+
+ -- Start of processing for Expand_Pragma_Initial_Condition
+
+ begin
+ -- Nothing to do when the package is not subject to an Initial_Condition
+ -- pragma.
+
+ if No (IC_Prag) then
+ return;
+ end if;
+
+ Expr := Get_Pragma_Arg (First (Pragma_Argument_Associations (IC_Prag)));
+ Loc := Sloc (IC_Prag);
+
+ -- Nothing to do when the pragma or its argument are illegal because
+ -- there is no valid expression to check.
+
+ if Error_Posted (IC_Prag) or else Error_Posted (Expr) then
+ return;
+ end if;
+
+ -- Obtain the various lists of the context where the individual pieces
+ -- of the initial condition procedure are to be inserted.
+
+ if Nkind (N) = N_Package_Body then
+ Extract_Package_Body_Lists
+ (Pack_Body => N,
+ Body_List => Body_List,
+ Call_List => Call_List,
+ Spec_List => Spec_List);
+
+ elsif Nkind (N) = N_Package_Declaration then
+ Extract_Package_Declaration_Lists
+ (Pack_Decl => N,
+ Body_List => Body_List,
+ Call_List => Call_List,
+ Spec_List => Spec_List);
-- This routine should not be used on anything other than packages
else
- raise Program_Error;
+ pragma Assert (False);
+ return;
end if;
- Init_Cond := Get_Pragma (Pack_Id, Pragma_Initial_Condition);
+ Proc_Id :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_External_Name (Chars (Pack_Id), "Initial_Condition"));
- -- The caller should check whether the package is subject to pragma
- -- Initial_Condition.
+ Set_Ekind (Proc_Id, E_Procedure);
+ Set_Is_Initial_Condition_Procedure (Proc_Id);
- pragma Assert (Present (Init_Cond));
+ -- Generate:
+ -- procedure <Pack_Id>Initial_Condition;
- Expr :=
- Get_Pragma_Arg (First (Pragma_Argument_Associations (Init_Cond)));
+ Proc_Decl :=
+ Make_Subprogram_Declaration (Loc,
+ Make_Procedure_Specification (Loc,
+ Defining_Unit_Name => Proc_Id));
- -- The assertion expression was found to be illegal, do not generate the
- -- runtime check as it will repeat the illegality.
+ Append_To (Spec_List, Proc_Decl);
- if Error_Posted (Init_Cond) or else Error_Posted (Expr) then
- return;
+ -- The initial condition procedure requires debug info when initial
+ -- condition is subject to Source Coverage Obligations.
+
+ if Generate_SCO then
+ Set_Needs_Debug_Info (Proc_Id);
end if;
-- Generate:
- -- pragma Check (Initial_Condition, <Expr>);
+ -- procedure <Pack_Id>Initial_Condition is
+ -- begin
+ -- pragma Check (Initial_Condition, <Expr>);
+ -- end <Pack_Id>Initial_Condition;
+
+ Proc_Body :=
+ Make_Subprogram_Body (Loc,
+ Specification =>
+ Copy_Subprogram_Spec (Specification (Proc_Decl)),
+ Declarations => Empty_List,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (
+ Make_Pragma (Loc,
+ Chars => Name_Check,
+ Pragma_Argument_Associations => New_List (
+ Make_Pragma_Argument_Association (Loc,
+ Expression =>
+ Make_Identifier (Loc, Name_Initial_Condition)),
+ Make_Pragma_Argument_Association (Loc,
+ Expression => New_Copy_Tree (Expr)))))));
- Check :=
- Make_Pragma (Loc,
- Chars => Name_Check,
- Pragma_Argument_Associations => New_List (
- Make_Pragma_Argument_Association (Loc,
- Expression => Make_Identifier (Loc, Name_Initial_Condition)),
- Make_Pragma_Argument_Association (Loc,
- Expression => New_Copy_Tree (Expr))));
+ Append_To (Body_List, Proc_Body);
+
+ -- The initial condition procedure requires debug info when initial
+ -- condition is subject to Source Coverage Obligations.
+
+ Proc_Body_Id := Defining_Entity (Proc_Body);
+
+ if Generate_SCO then
+ Set_Needs_Debug_Info (Proc_Body_Id);
+ end if;
+
+ -- The location of the initial condition procedure call must be as close
+ -- as possible to the intended semantic location of the check because
+ -- the ABE mechanism relies heavily on accurate locations.
+
+ Call_Loc := End_Keyword_Location (N);
+
+ -- Generate:
+ -- <Pack_Id>Initial_Condition;
+
+ Call :=
+ Make_Procedure_Call_Statement (Call_Loc,
+ Name => New_Occurrence_Of (Proc_Id, Call_Loc));
+
+ Append_To (Call_List, Call);
- Append_To (List, Check);
- Analyze (Check);
+ Analyze (Proc_Decl);
+ Analyze (Proc_Body);
+ Analyze (Call);
end Expand_Pragma_Initial_Condition;
------------------------------------
diff --git a/gcc/ada/exp_prag.ads b/gcc/ada/exp_prag.ads
index 48d1c2f..9e5f042 100644
--- a/gcc/ada/exp_prag.ads
+++ b/gcc/ada/exp_prag.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2015, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -42,15 +42,11 @@ package Exp_Prag is
-- Subp_Id's body. All generated code is added to list Stmts. If Stmts is
-- No_List on entry, a new list is created.
- procedure Expand_Pragma_Initial_Condition (Spec_Or_Body : Node_Id);
- -- Generate a runtime check needed to verify the assumption of introduced
- -- by pragma Initial_Condition. Spec_Or_Body denotes the spec or body of
- -- the package where the pragma appears. The check is inserted according
- -- to the following precedence rules:
- -- 1) If the package has a body with a statement sequence, the check is
- -- inserted at the end of the statments.
- -- 2) If the package has a body, the check is inserted at the end of the
- -- body declarations.
- -- 3) The check is inserted at the end of the visible declarations.
+ procedure Expand_Pragma_Initial_Condition
+ (Pack_Id : Entity_Id;
+ N : Node_Id);
+ -- Verify the run-time semantics of pragma Initial_Condition when it
+ -- applies to package Pack_Id. N denotes the related package spec or
+ -- body.
end Exp_Prag;
diff --git a/gcc/ada/exp_spark.adb b/gcc/ada/exp_spark.adb
index 211fea3..5386fa6 100644
--- a/gcc/ada/exp_spark.adb
+++ b/gcc/ada/exp_spark.adb
@@ -36,6 +36,7 @@ with Nmake; use Nmake;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Eval; use Sem_Eval;
+with Sem_Prag; use Sem_Prag;
with Sem_Res; use Sem_Res;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
@@ -54,18 +55,27 @@ package body Exp_SPARK is
-- Replace occurrences of System'To_Address by calls to
-- System.Storage_Elements.To_Address
- procedure Expand_SPARK_Freeze_Type (E : Entity_Id);
+ procedure Expand_SPARK_N_Freeze_Type (E : Entity_Id);
-- Build the DIC procedure of a type when needed, if not already done
+ procedure Expand_SPARK_N_Indexed_Component (N : Node_Id);
+ -- Insert explicit dereference if required
+
+ procedure Expand_SPARK_N_Loop_Statement (N : Node_Id);
+ -- Perform loop statement-specific expansion
+
procedure Expand_SPARK_N_Object_Declaration (N : Node_Id);
-- Perform object-declaration-specific expansion
procedure Expand_SPARK_N_Object_Renaming_Declaration (N : Node_Id);
-- Perform name evaluation for a renamed object
- procedure Expand_SPARK_Op_Ne (N : Node_Id);
+ procedure Expand_SPARK_N_Op_Ne (N : Node_Id);
-- Rewrite operator /= based on operator = when defined explicitly
+ procedure Expand_SPARK_N_Selected_Component (N : Node_Id);
+ -- Insert explicit dereference if required
+
------------------
-- Expand_SPARK --
------------------
@@ -111,17 +121,7 @@ package body Exp_SPARK is
-- dealt with specially in GNATprove.
when N_Loop_Statement =>
- declare
- Scheme : constant Node_Id := Iteration_Scheme (N);
- begin
- if Present (Scheme)
- and then Present (Iterator_Specification (Scheme))
- and then
- Is_Iterator_Over_Array (Iterator_Specification (Scheme))
- then
- Expand_Iterator_Loop_Over_Array (N);
- end if;
- end;
+ Expand_SPARK_N_Loop_Statement (N);
when N_Object_Declaration =>
Expand_SPARK_N_Object_Declaration (N);
@@ -130,13 +130,19 @@ package body Exp_SPARK is
Expand_SPARK_N_Object_Renaming_Declaration (N);
when N_Op_Ne =>
- Expand_SPARK_Op_Ne (N);
+ Expand_SPARK_N_Op_Ne (N);
when N_Freeze_Entity =>
if Is_Type (Entity (N)) then
- Expand_SPARK_Freeze_Type (Entity (N));
+ Expand_SPARK_N_Freeze_Type (Entity (N));
end if;
+ when N_Indexed_Component =>
+ Expand_SPARK_N_Indexed_Component (N);
+
+ when N_Selected_Component =>
+ Expand_SPARK_N_Selected_Component (N);
+
-- In SPARK mode, no other constructs require expansion
when others =>
@@ -144,6 +150,21 @@ package body Exp_SPARK is
end case;
end Expand_SPARK;
+ --------------------------------
+ -- Expand_SPARK_N_Freeze_Type --
+ --------------------------------
+
+ procedure Expand_SPARK_N_Freeze_Type (E : Entity_Id) is
+ begin
+ -- When a DIC is inherited by a tagged type, it may need to be
+ -- specialized to the descendant type, hence build a separate DIC
+ -- procedure for it as done during regular expansion for compilation.
+
+ if Has_DIC (E) and then Is_Tagged_Type (E) then
+ Build_DIC_Procedure_Body (E, For_Freeze => True);
+ end if;
+ end Expand_SPARK_N_Freeze_Type;
+
----------------------------------------
-- Expand_SPARK_N_Attribute_Reference --
----------------------------------------
@@ -248,29 +269,54 @@ package body Exp_SPARK is
end if;
end Expand_SPARK_N_Attribute_Reference;
- ------------------------------
- -- Expand_SPARK_Freeze_Type --
- ------------------------------
+ -----------------------------------
+ -- Expand_SPARK_N_Loop_Statement --
+ -----------------------------------
+
+ procedure Expand_SPARK_N_Loop_Statement (N : Node_Id) is
+ Scheme : constant Node_Id := Iteration_Scheme (N);
- procedure Expand_SPARK_Freeze_Type (E : Entity_Id) is
begin
- -- When a DIC is inherited by a tagged type, it may need to be
- -- specialized to the descendant type, hence build a separate DIC
- -- procedure for it as done during regular expansion for compilation.
+ -- Loop iterations over arrays need to be expanded, to avoid getting
+ -- two names referring to the same object in memory (the array and the
+ -- iterator) in GNATprove, especially since both can be written (thus
+ -- possibly leading to interferences due to aliasing). No such problem
+ -- arises with quantified expressions over arrays, which are dealt with
+ -- specially in GNATprove.
+
+ if Present (Scheme)
+ and then Present (Iterator_Specification (Scheme))
+ and then Is_Iterator_Over_Array (Iterator_Specification (Scheme))
+ then
+ Expand_Iterator_Loop_Over_Array (N);
+ end if;
+ end Expand_SPARK_N_Loop_Statement;
- if Has_DIC (E) and then Is_Tagged_Type (E) then
- Build_DIC_Procedure_Body (E, For_Freeze => True);
+ --------------------------------------
+ -- Expand_SPARK_N_Indexed_Component --
+ --------------------------------------
+
+ procedure Expand_SPARK_N_Indexed_Component (N : Node_Id) is
+ Pref : constant Node_Id := Prefix (N);
+ Typ : constant Entity_Id := Etype (Pref);
+
+ begin
+ if Is_Access_Type (Typ) then
+ Insert_Explicit_Dereference (Pref);
+ Analyze_And_Resolve (Pref, Designated_Type (Typ));
end if;
- end Expand_SPARK_Freeze_Type;
+ end Expand_SPARK_N_Indexed_Component;
---------------------------------------
-- Expand_SPARK_N_Object_Declaration --
---------------------------------------
procedure Expand_SPARK_N_Object_Declaration (N : Node_Id) is
- Def_Id : constant Entity_Id := Defining_Identifier (N);
Loc : constant Source_Ptr := Sloc (N);
- Typ : constant Entity_Id := Etype (Def_Id);
+ Obj_Id : constant Entity_Id := Defining_Identifier (N);
+ Typ : constant Entity_Id := Etype (Obj_Id);
+
+ Call : Node_Id;
begin
-- If the object declaration denotes a variable without initialization
@@ -278,12 +324,19 @@ package body Exp_SPARK is
-- and analyze a dummy call to the DIC procedure of the type in order
-- to detect potential elaboration issues.
- if Comes_From_Source (Def_Id)
+ if Comes_From_Source (Obj_Id)
+ and then Ekind (Obj_Id) = E_Variable
and then Has_DIC (Typ)
and then Present (DIC_Procedure (Typ))
and then not Has_Init_Expression (N)
then
- Analyze (Build_DIC_Call (Loc, Def_Id, Typ));
+ Call := Build_DIC_Call (Loc, Obj_Id, Typ);
+
+ -- Partially insert the call into the tree by setting its parent
+ -- pointer.
+
+ Set_Parent (Call, N);
+ Analyze (Call);
end if;
end Expand_SPARK_N_Object_Declaration;
@@ -343,11 +396,11 @@ package body Exp_SPARK is
end if;
end Expand_SPARK_N_Object_Renaming_Declaration;
- ------------------------
- -- Expand_SPARK_Op_Ne --
- ------------------------
+ --------------------------
+ -- Expand_SPARK_N_Op_Ne --
+ --------------------------
- procedure Expand_SPARK_Op_Ne (N : Node_Id) is
+ procedure Expand_SPARK_N_Op_Ne (N : Node_Id) is
Typ : constant Entity_Id := Etype (Left_Opnd (N));
begin
@@ -361,18 +414,53 @@ package body Exp_SPARK is
else
Exp_Ch4.Expand_N_Op_Ne (N);
end if;
- end Expand_SPARK_Op_Ne;
+ end Expand_SPARK_N_Op_Ne;
-------------------------------------
-- Expand_SPARK_Potential_Renaming --
-------------------------------------
procedure Expand_SPARK_Potential_Renaming (N : Node_Id) is
+ function In_Insignificant_Pragma (Nod : Node_Id) return Boolean;
+ -- Determine whether arbitrary node Nod appears within a significant
+ -- pragma for SPARK.
+
+ -----------------------------
+ -- In_Insignificant_Pragma --
+ -----------------------------
+
+ function In_Insignificant_Pragma (Nod : Node_Id) return Boolean is
+ Par : Node_Id;
+
+ begin
+ -- Climb the parent chain looking for an enclosing pragma
+
+ Par := Nod;
+ while Present (Par) loop
+ if Nkind (Par) = N_Pragma then
+ return not Pragma_Significant_In_SPARK (Get_Pragma_Id (Par));
+
+ -- Prevent the search from going too far
+
+ elsif Is_Body_Or_Package_Declaration (Par) then
+ exit;
+ end if;
+
+ Par := Parent (Par);
+ end loop;
+
+ return False;
+ end In_Insignificant_Pragma;
+
+ -- Local variables
+
Loc : constant Source_Ptr := Sloc (N);
Obj_Id : constant Entity_Id := Entity (N);
Typ : constant Entity_Id := Etype (N);
Ren : Node_Id;
+ -- Start of processing for Expand_SPARK_Potential_Renaming
+
begin
-- Replace a reference to a renaming with the actual renamed object
@@ -381,12 +469,20 @@ package body Exp_SPARK is
if Present (Ren) then
+ -- Do not process a reference when it appears within a pragma of
+ -- no significance to SPARK. It is assumed that the replacement
+ -- will violate the semantics of the pragma and cause a spurious
+ -- error.
+
+ if In_Insignificant_Pragma (N) then
+ return;
+
-- Instantiations and inlining of subprograms employ "prologues"
-- which map actual to formal parameters by means of renamings.
-- Replace a reference to a formal by the corresponding actual
-- parameter.
- if Nkind (Ren) in N_Entity then
+ elsif Nkind (Ren) in N_Entity then
Rewrite (N, New_Occurrence_Of (Ren, Loc));
-- Otherwise the renamed object denotes a name
@@ -401,4 +497,31 @@ package body Exp_SPARK is
end if;
end Expand_SPARK_Potential_Renaming;
+ ---------------------------------------
+ -- Expand_SPARK_N_Selected_Component --
+ ---------------------------------------
+
+ procedure Expand_SPARK_N_Selected_Component (N : Node_Id) is
+ Pref : constant Node_Id := Prefix (N);
+ Typ : constant Entity_Id := Underlying_Type (Etype (Pref));
+
+ begin
+ if Present (Typ) and then Is_Access_Type (Typ) then
+
+ -- First set prefix type to proper access type, in case it currently
+ -- has a private (non-access) view of this type.
+
+ Set_Etype (Pref, Typ);
+
+ Insert_Explicit_Dereference (Pref);
+ Analyze_And_Resolve (Pref, Designated_Type (Typ));
+
+ if Ekind (Etype (Pref)) = E_Private_Subtype
+ and then Is_For_Access_Subtype (Etype (Pref))
+ then
+ Set_Etype (Pref, Base_Type (Etype (Pref)));
+ end if;
+ end if;
+ end Expand_SPARK_N_Selected_Component;
+
end Exp_SPARK;
diff --git a/gcc/ada/exp_unst.adb b/gcc/ada/exp_unst.adb
index 62d9d33..063b60f 100644
--- a/gcc/ada/exp_unst.adb
+++ b/gcc/ada/exp_unst.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2014-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 2014-2017, 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- --
@@ -31,7 +31,7 @@ with Lib; use Lib;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
-with Opt; use Opt;
+with Opt;
with Output; use Output;
with Rtsfind; use Rtsfind;
with Sem; use Sem;
diff --git a/gcc/ada/exp_util.adb b/gcc/ada/exp_util.adb
index b8c528e..8fdd8aa 100644
--- a/gcc/ada/exp_util.adb
+++ b/gcc/ada/exp_util.adb
@@ -52,6 +52,7 @@ with Sem_Ch8; use Sem_Ch8;
with Sem_Ch12; use Sem_Ch12;
with Sem_Ch13; use Sem_Ch13;
with Sem_Disp; use Sem_Disp;
+with Sem_Elab; use Sem_Elab;
with Sem_Eval; use Sem_Eval;
with Sem_Res; use Sem_Res;
with Sem_Type; use Sem_Type;
@@ -65,8 +66,7 @@ with Ttypes; use Ttypes;
with Urealp; use Urealp;
with Validsw; use Validsw;
-with GNAT.HTable; use GNAT.HTable;
-
+with GNAT.HTable;
package body Exp_Util is
---------------------------------------------------------
@@ -650,7 +650,10 @@ package body Exp_Util is
-- Do not process allocations on / deallocations from the secondary
-- stack.
- elsif Is_RTE (Pool_Id, RE_SS_Pool) then
+ elsif Is_RTE (Pool_Id, RE_SS_Pool)
+ or else (Nkind (Expr) = N_Allocator
+ and then Is_RTE (Storage_Pool (Expr), RE_SS_Pool))
+ then
return;
-- Optimize the case where we are using the default Global_Pool_Object,
@@ -1760,9 +1763,12 @@ package body Exp_Util is
-- Perform minor decoration in case the body is not analyzed
- Set_Ekind (Proc_Body_Id, E_Subprogram_Body);
- Set_Etype (Proc_Body_Id, Standard_Void_Type);
- Set_Scope (Proc_Body_Id, Current_Scope);
+ Set_Ekind (Proc_Body_Id, E_Subprogram_Body);
+ Set_Etype (Proc_Body_Id, Standard_Void_Type);
+ Set_Scope (Proc_Body_Id, Current_Scope);
+ Set_SPARK_Pragma (Proc_Body_Id, SPARK_Pragma (Proc_Id));
+ Set_SPARK_Pragma_Inherited
+ (Proc_Body_Id, SPARK_Pragma_Inherited (Proc_Id));
-- Link both spec and body to avoid generating duplicates
@@ -1902,17 +1908,19 @@ package body Exp_Util is
-- Perform minor decoration in case the declaration is not analyzed
- Set_Ekind (Proc_Id, E_Procedure);
- Set_Etype (Proc_Id, Standard_Void_Type);
- Set_Scope (Proc_Id, Current_Scope);
+ Set_Ekind (Proc_Id, E_Procedure);
+ Set_Etype (Proc_Id, Standard_Void_Type);
+ Set_Is_DIC_Procedure (Proc_Id);
+ Set_Scope (Proc_Id, Current_Scope);
+ Set_SPARK_Pragma (Proc_Id, SPARK_Mode_Pragma);
+ Set_SPARK_Pragma_Inherited (Proc_Id);
- Set_Is_DIC_Procedure (Proc_Id);
Set_DIC_Procedure (Work_Typ, Proc_Id);
-- The DIC procedure requires debug info when the assertion expression
-- is subject to Source Coverage Obligations.
- if Opt.Generate_SCO then
+ if Generate_SCO then
Set_Needs_Debug_Info (Proc_Id);
end if;
@@ -3384,7 +3392,7 @@ package body Exp_Util is
-- The invariant procedure requires debug info when the invariants are
-- subject to Source Coverage Obligations.
- if Opt.Generate_SCO then
+ if Generate_SCO then
Set_Needs_Debug_Info (Proc_Id);
end if;
@@ -7229,7 +7237,7 @@ package body Exp_Util is
null;
end if;
- -- Another special case, an attribute denoting a procedure call
+ -- Special case: an attribute denoting a procedure call
when N_Attribute_Reference =>
if Is_Procedure_Attribute_Name (Attribute_Name (P)) then
@@ -7247,6 +7255,14 @@ package body Exp_Util is
null;
end if;
+ -- Special case: a call marker
+
+ when N_Call_Marker =>
+ if Is_List_Member (P) then
+ Insert_List_Before_And_Analyze (P, Ins_Actions);
+ return;
+ end if;
+
-- A contract node should not belong to the tree
when N_Contract =>
@@ -7858,6 +7874,8 @@ package body Exp_Util is
Call := Prefix (Call);
end if;
+ Call := Unqual_Conv (Call);
+
if Is_Build_In_Place_Function_Call (Call) then
declare
Access_Nam : Name_Id := No_Name;
@@ -8680,9 +8698,7 @@ package body Exp_Util is
Param := First (Parameter_Associations (Call));
while Present (Param) loop
- if Nkind (Param) = N_Parameter_Association
- and then Nkind (Selector_Name (Param)) = N_Identifier
- then
+ if Nkind (Param) = N_Parameter_Association then
Formal := Selector_Name (Param);
Actual := Explicit_Actual_Parameter (Param);
@@ -8831,6 +8847,11 @@ package body Exp_Util is
if Present (N) then
Remove_Warning_Messages (N);
+ -- Update the internal structures of the ABE mechanism in case the
+ -- dead node is an elaboration scenario.
+
+ Kill_Elaboration_Scenario (N);
+
-- Generate warning if appropriate
if W then
@@ -9187,43 +9208,42 @@ package body Exp_Util is
Lo : constant Node_Id :=
New_Copy_Tree (String_Literal_Low_Bound (Literal_Typ));
Index : constant Entity_Id := Etype (Lo);
-
- Hi : Node_Id;
Length_Expr : constant Node_Id :=
Make_Op_Subtract (Loc,
- Left_Opnd =>
+ Left_Opnd =>
Make_Integer_Literal (Loc,
Intval => String_Literal_Length (Literal_Typ)),
- Right_Opnd =>
- Make_Integer_Literal (Loc, 1));
+ Right_Opnd => Make_Integer_Literal (Loc, 1));
+
+ Hi : Node_Id;
begin
Set_Analyzed (Lo, False);
- if Is_Integer_Type (Index) then
- Hi :=
- Make_Op_Add (Loc,
- Left_Opnd => New_Copy_Tree (Lo),
- Right_Opnd => Length_Expr);
- else
- Hi :=
- Make_Attribute_Reference (Loc,
- Attribute_Name => Name_Val,
- Prefix => New_Occurrence_Of (Index, Loc),
- Expressions => New_List (
- Make_Op_Add (Loc,
- Left_Opnd =>
- Make_Attribute_Reference (Loc,
- Attribute_Name => Name_Pos,
- Prefix => New_Occurrence_Of (Index, Loc),
- Expressions => New_List (New_Copy_Tree (Lo))),
- Right_Opnd => Length_Expr)));
- end if;
+ if Is_Integer_Type (Index) then
+ Hi :=
+ Make_Op_Add (Loc,
+ Left_Opnd => New_Copy_Tree (Lo),
+ Right_Opnd => Length_Expr);
+ else
+ Hi :=
+ Make_Attribute_Reference (Loc,
+ Attribute_Name => Name_Val,
+ Prefix => New_Occurrence_Of (Index, Loc),
+ Expressions => New_List (
+ Make_Op_Add (Loc,
+ Left_Opnd =>
+ Make_Attribute_Reference (Loc,
+ Attribute_Name => Name_Pos,
+ Prefix => New_Occurrence_Of (Index, Loc),
+ Expressions => New_List (New_Copy_Tree (Lo))),
+ Right_Opnd => Length_Expr)));
+ end if;
- return
- Make_Range (Loc,
- Low_Bound => Lo,
- High_Bound => Hi);
+ return
+ Make_Range (Loc,
+ Low_Bound => Lo,
+ High_Bound => Hi);
end Make_Literal_Range;
--------------------------
@@ -9284,10 +9304,22 @@ package body Exp_Util is
-- Case of calling normal predicate function
- Call :=
- Make_Function_Call (Loc,
- Name => New_Occurrence_Of (Func_Id, Loc),
- Parameter_Associations => New_List (Relocate_Node (Expr)));
+ -- If the type is tagged, the expression may be class-wide, in which
+ -- case it has to be converted to its root type, given that the
+ -- generated predicate function is not dispatching.
+
+ if Is_Tagged_Type (Typ) then
+ Call :=
+ Make_Function_Call (Loc,
+ Name => New_Occurrence_Of (Func_Id, Loc),
+ Parameter_Associations =>
+ New_List (Convert_To (Typ, Relocate_Node (Expr))));
+ else
+ Call :=
+ Make_Function_Call (Loc,
+ Name => New_Occurrence_Of (Func_Id, Loc),
+ Parameter_Associations => New_List (Relocate_Node (Expr)));
+ end if;
Restore_Ghost_Mode (Saved_GM);
@@ -10785,8 +10817,17 @@ package body Exp_Util is
Analyze (Block);
end if;
- when others =>
+ -- Could be e.g. a loop that was transformed into a block or null
+ -- statement. Do nothing for terminate alternatives.
+
+ when N_Block_Statement
+ | N_Null_Statement
+ | N_Terminate_Alternative
+ =>
null;
+
+ when others =>
+ raise Program_Error;
end case;
end Process_Statements_For_Controlled_Objects;
@@ -10937,7 +10978,8 @@ package body Exp_Util is
Related_Nod : Node_Id := Empty) return Entity_Id;
-- Create an external symbol of the form xxx_FIRST/_LAST if Related_Nod
-- is present (xxx is taken from the Chars field of Related_Nod),
- -- otherwise it generates an internal temporary.
+ -- otherwise it generates an internal temporary. The created temporary
+ -- entity is marked as internal.
---------------------
-- Build_Temporary --
@@ -10948,6 +10990,7 @@ package body Exp_Util is
Id : Character;
Related_Nod : Node_Id := Empty) return Entity_Id
is
+ Temp_Id : Entity_Id;
Temp_Nam : Name_Id;
begin
@@ -10960,13 +11003,17 @@ package body Exp_Util is
Temp_Nam := New_External_Name (Chars (Related_Id), "_LAST");
end if;
- return Make_Defining_Identifier (Loc, Temp_Nam);
+ Temp_Id := Make_Defining_Identifier (Loc, Temp_Nam);
-- Otherwise generate an internal temporary
else
- return Make_Temporary (Loc, Id, Related_Nod);
+ Temp_Id := Make_Temporary (Loc, Id, Related_Nod);
end if;
+
+ Set_Is_Internal (Temp_Id);
+
+ return Temp_Id;
end Build_Temporary;
-- Local variables
@@ -11217,7 +11264,7 @@ package body Exp_Util is
-- Exp_Ch2.Expand_Renaming). Otherwise the temporary must be
-- elaborated by gigi, and is of course not to be replaced in-line
-- by the expression it renames, which would defeat the purpose of
- -- removing the side-effect.
+ -- removing the side effect.
if Nkind_In (Exp, N_Selected_Component, N_Indexed_Component)
and then Has_Non_Standard_Rep (Etype (Prefix (Exp)))
@@ -12618,7 +12665,7 @@ package body Exp_Util is
and then Variable_Ref
then
-- Exception is a prefix that is the result of a previous removal
- -- of side-effects.
+ -- of side effects.
return Is_Entity_Name (Prefix (N))
and then not Comes_From_Source (Prefix (N))
diff --git a/gcc/ada/exp_util.ads b/gcc/ada/exp_util.ads
index 9950058..3fab6dd 100644
--- a/gcc/ada/exp_util.ads
+++ b/gcc/ada/exp_util.ads
@@ -856,11 +856,8 @@ package Exp_Util is
-- False means that it is not known if the value is positive or negative.
function Make_Invariant_Call (Expr : Node_Id) return Node_Id;
- -- Expr is an object of a type which Has_Invariants set (and which thus
- -- also has an Invariant_Procedure set). If invariants are enabled, this
- -- function returns a call to the Invariant procedure passing Expr as the
- -- argument, and returns it unanalyzed. If invariants are not enabled,
- -- returns a null statement.
+ -- Generate a call to the Invariant_Procedure associated with the type of
+ -- expression Expr. Expr is passed as an actual parameter in the call.
function Make_Predicate_Call
(Typ : Entity_Id;
diff --git a/gcc/ada/fe.h b/gcc/ada/fe.h
index 513cfa9..6b6d524 100644
--- a/gcc/ada/fe.h
+++ b/gcc/ada/fe.h
@@ -109,10 +109,12 @@ extern Nat Serious_Errors_Detected;
#define Get_Local_Raise_Call_Entity exp_ch11__get_local_raise_call_entity
#define Get_RT_Exception_Entity exp_ch11__get_rt_exception_entity
#define Get_RT_Exception_Name exp_ch11__get_rt_exception_name
+#define Warn_If_No_Local_Raise exp_ch11__warn_if_no_local_raise
extern Entity_Id Get_Local_Raise_Call_Entity (void);
extern Entity_Id Get_RT_Exception_Entity (int);
extern void Get_RT_Exception_Name (int);
+extern void Warn_If_No_Local_Raise (int);
/* exp_code: */
diff --git a/gcc/ada/fmap.adb b/gcc/ada/fmap.adb
index d517c2a..2b95dc7 100644
--- a/gcc/ada/fmap.adb
+++ b/gcc/ada/fmap.adb
@@ -175,6 +175,7 @@ package body Fmap is
----------------
procedure Initialize (File_Name : String) is
+ FD : File_Descriptor;
Src : Source_Buffer_Ptr;
Hi : Source_Ptr;
@@ -297,10 +298,15 @@ package body Fmap is
begin
Empty_Tables;
- Read_Source_File (Name_Enter (File_Name), 1, Hi, Src, Config);
+ Read_Source_File (Name_Enter (File_Name), 1, Hi, Src, FD, Config);
if Null_Source_Buffer_Ptr (Src) then
- Write_Str ("warning: could not read mapping file """);
+ if FD = Null_FD then
+ Write_Str ("warning: could not locate mapping file """);
+ else
+ Write_Str ("warning: no read access for mapping file """);
+ end if;
+
Write_Str (File_Name);
Write_Line ("""");
No_Mapping_File := True;
diff --git a/gcc/ada/fname-sf.adb b/gcc/ada/fname-sf.adb
index be115bc..53cc9d1 100644
--- a/gcc/ada/fname-sf.adb
+++ b/gcc/ada/fname-sf.adb
@@ -23,12 +23,13 @@
-- --
------------------------------------------------------------------------------
-with Casing; use Casing;
-with Fname; use Fname;
-with Fname.UF; use Fname.UF;
-with SFN_Scan; use SFN_Scan;
-with Osint; use Osint;
-with Types; use Types;
+with Casing; use Casing;
+with Fname; use Fname;
+with Fname.UF; use Fname.UF;
+with SFN_Scan; use SFN_Scan;
+with Osint; use Osint;
+with Types; use Types;
+with System.OS_Lib; use System.OS_Lib;
with Unchecked_Conversion;
@@ -61,11 +62,12 @@ package body Fname.SF is
-----------------------------------
procedure Read_Source_File_Name_Pragmas is
+ FD : File_Descriptor;
Src : Source_Buffer_Ptr;
Hi : Source_Ptr;
begin
- Read_Source_File (Name_Enter ("gnat.adc"), 1, Hi, Src);
+ Read_Source_File (Name_Enter ("gnat.adc"), 1, Hi, Src, FD);
if not Null_Source_Buffer_Ptr (Src) then
-- We need to strip off the trailing EOF that was added by
diff --git a/gcc/ada/freeze.adb b/gcc/ada/freeze.adb
index 794fdf3..a106d68 100644
--- a/gcc/ada/freeze.adb
+++ b/gcc/ada/freeze.adb
@@ -8450,7 +8450,7 @@ package body Freeze is
-- The analysis of the expression may generate insert actions,
-- which of course must not be executed. We wrap those actions
-- in a procedure that is not called, and later on eliminated.
- -- The following cases have no side-effects, and are analyzed
+ -- The following cases have no side effects, and are analyzed
-- directly.
if Nkind (Dcopy) = N_Identifier
diff --git a/gcc/ada/freeze.ads b/gcc/ada/freeze.ads
index 079d713..6ec74b4 100644
--- a/gcc/ada/freeze.ads
+++ b/gcc/ada/freeze.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -114,15 +114,15 @@ package Freeze is
-- Are always frozen at the point of declaration
- -- The flag Has_Delayed_Freeze is used for to indicate that delayed
- -- freezing is required. Usually the associated freeze node is allocated
- -- at the freezing point. One special exception occurs with anonymous
- -- base types, where the freeze node is preallocated at the point of
- -- declaration, so that the First_Subtype_Link field can be set.
+ -- The flag Has_Delayed_Freeze is used to indicate that delayed freezing
+ -- is required. Usually the associated freeze node is allocated at the
+ -- freezing point. One special exception occurs with anonymous base types,
+ -- where the freeze node is preallocated at the point of declaration, so
+ -- that the First_Subtype_Link field can be set.
Freezing_Library_Level_Tagged_Type : Boolean := False;
-- Flag used to indicate that we are freezing the primitives of a library
- -- level tagged types. Used to disable checks on premature freezing.
+ -- level tagged type. Used to disable checks on premature freezing.
-- More documentation needed??? why is this flag needed? what are these
-- checks? why do they need disabling in some cases?
diff --git a/gcc/ada/frontend.adb b/gcc/ada/frontend.adb
index 378aacd..828f6ff 100644
--- a/gcc/ada/frontend.adb
+++ b/gcc/ada/frontend.adb
@@ -38,7 +38,7 @@ with Ghost; use Ghost;
with Inline; use Inline;
with Lib; use Lib;
with Lib.Load; use Lib.Load;
-with Lib.Xref; use Lib.Xref;
+with Lib.Xref;
with Live; use Live;
with Namet; use Namet;
with Nlists; use Nlists;
@@ -49,21 +49,21 @@ with Prep;
with Prepcomp;
with Restrict; use Restrict;
with Rident; use Rident;
-with Rtsfind; use Rtsfind;
+with Rtsfind;
with Snames; use Snames;
with Sprint;
with Scn; use Scn;
with Sem; use Sem;
with Sem_Aux;
-with Sem_Ch8; use Sem_Ch8;
+with Sem_Ch8;
with Sem_SCIL;
with Sem_Elab; use Sem_Elab;
with Sem_Prag; use Sem_Prag;
-with Sem_Warn; use Sem_Warn;
+with Sem_Warn;
with Sinfo; use Sinfo;
with Sinput; use Sinput;
with Sinput.L; use Sinput.L;
-with SCIL_LL; use SCIL_LL;
+with SCIL_LL;
with Tbuild; use Tbuild;
with Types; use Types;
@@ -87,6 +87,7 @@ begin
Checks.Initialize;
Sem_Warn.Initialize;
Prep.Initialize;
+ Sem_Elab.Initialize;
if Generate_SCIL then
SCIL_LL.Initialize;
@@ -126,7 +127,7 @@ begin
-- Return immediately if the main source could not be found
- if Sinput.Main_Source_File = No_Source_File then
+ if Sinput.Main_Source_File <= No_Source_File then
return;
end if;
@@ -167,7 +168,7 @@ begin
-- Case of gnat.adc file present
- if Source_gnat_adc /= No_Source_File then
+ if Source_gnat_adc > No_Source_File then
-- Parse the gnat.adc file for configuration pragmas
@@ -214,7 +215,7 @@ begin
Source_Config_File := Load_Config_File (Config_Name);
- if Source_Config_File = No_Source_File then
+ if Source_Config_File <= No_Source_File then
Osint.Fail
("cannot find configuration pragmas file "
& Config_File_Names (Index).all);
@@ -423,8 +424,9 @@ begin
Instantiate_Bodies;
end if;
- -- Analyze inlined bodies and check elaboration rules in GNATprove
- -- mode as well as during compilation.
+ -- Analyze all inlined bodies, check access-before-elaboration
+ -- rules, and remove ignored Ghost code when generating code or
+ -- compiling for GNATprove.
if Operating_Mode = Generate_Code or else GNATprove_Mode then
if Inline_Processing_Required then
@@ -438,12 +440,24 @@ begin
Collect_Garbage_Entities;
end if;
- Check_Elab_Calls;
+ -- Examine all top level scenarios collected during analysis
+ -- and resolution. Diagnose conditional and guaranteed ABEs,
+ -- install run-time checks to catch ABEs, and guarantee the
+ -- prior elaboration of external units.
+
+ Check_Elaboration_Scenarios;
-- Remove any ignored Ghost code as it must not appear in the
-- executable.
Remove_Ignored_Ghost_Code;
+
+ -- Otherwise check the access-before-elaboration rules even when
+ -- previous errors were detected or the compilation is verifying
+ -- semantics.
+
+ else
+ Check_Elaboration_Scenarios;
end if;
-- At this stage we can unnest subprogram bodies if required
diff --git a/gcc/ada/gcc-interface/Make-lang.in b/gcc/ada/gcc-interface/Make-lang.in
index 113c84f..9c7b6e1 100644
--- a/gcc/ada/gcc-interface/Make-lang.in
+++ b/gcc/ada/gcc-interface/Make-lang.in
@@ -390,6 +390,7 @@ GNAT_ADA_OBJS = \
ada/libgnat/s-restri.o \
ada/libgnat/s-secsta.o \
ada/libgnat/s-soflin.o \
+ ada/libgnat/s-soliin.o \
ada/libgnat/s-sopco3.o \
ada/libgnat/s-sopco4.o \
ada/libgnat/s-sopco5.o \
@@ -579,6 +580,7 @@ GNATBIND_OBJS = \
ada/libgnat/s-restri.o \
ada/libgnat/s-secsta.o \
ada/libgnat/s-soflin.o \
+ ada/libgnat/s-soliin.o \
ada/libgnat/s-sopco3.o \
ada/libgnat/s-sopco4.o \
ada/libgnat/s-sopco5.o \
diff --git a/gcc/ada/gcc-interface/Makefile.in b/gcc/ada/gcc-interface/Makefile.in
index 2fa47ca..f2f0058 100644
--- a/gcc/ada/gcc-interface/Makefile.in
+++ b/gcc/ada/gcc-interface/Makefile.in
@@ -627,10 +627,10 @@ ifeq ($(strip $(filter-out %86 x86_64 wrs vxworks vxworks7,$(target_cpu) $(targe
ifeq ($(strip $(filter-out x86_64, $(target_cpu))),)
X86CPU=x86_64
- LIBGNAT_TARGET_PAIRS=s-atocou.adb<libgnat/s-atocou__builtin.adb
+ LIBGNAT_TARGET_PAIRS=$(X86_64_TARGET_PAIRS)
else
X86CPU=x86
- LIBGNAT_TARGET_PAIRS=s-atocou.adb<libgnat/s-atocou__x86.adb
+ LIBGNAT_TARGET_PAIRS=$(X86_TARGET_PAIRS)
endif
LIBGNAT_TARGET_PAIRS+= \
@@ -653,10 +653,7 @@ ifeq ($(strip $(filter-out %86 x86_64 wrs vxworks vxworks7,$(target_cpu) $(targe
g-socthi.ads<libgnat/g-socthi__vxworks.ads \
g-socthi.adb<libgnat/g-socthi__vxworks.adb \
g-stsifd.adb<libgnat/g-stsifd__sockets.adb \
- $(ATOMICS_TARGET_PAIRS) \
- $(CERTMATH_TARGET_PAIRS) \
- $(CERTMATH_TARGET_PAIRS_SQRT_FPU) \
- $(CERTMATH_TARGET_PAIRS_X86TRA)
+ $(ATOMICS_TARGET_PAIRS)
TOOLS_TARGET_PAIRS=indepsw.adb<indepsw-gnu.adb
@@ -745,8 +742,7 @@ ifeq ($(strip $(filter-out %86 x86_64 wrs vxworks vxworks7,$(target_cpu) $(targe
endif
endif
- EXTRA_GNATRTL_NONTASKING_OBJS += s-stchop.o \
- $(CERTMATH_GNATRTL_OBJS) $(CERTMATH_GNATRTL_X86TRA_OBJS)
+ EXTRA_GNATRTL_NONTASKING_OBJS += s-stchop.o
EXTRA_GNATRTL_TASKING_OBJS += i-vxinco.o s-vxwork.o s-vxwext.o
EXTRA_LIBGNAT_OBJS+=vx_stack_info.o
@@ -845,7 +841,7 @@ ifeq ($(strip $(filter-out arm% coff wrs vx%,$(target_cpu) $(target_vendor) $(ta
endif
endif
- EXTRA_GNATRTL_NONTASKING_OBJS=i-vxwork.o i-vxwoio.o $(CERTMATH_GNATRTL_OBJS) \
+ EXTRA_GNATRTL_NONTASKING_OBJS=i-vxwork.o i-vxwoio.o \
s-stchop.o
EXTRA_GNATRTL_TASKING_OBJS=i-vxinco.o s-vxwork.o s-vxwext.o
diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 7b30497..e0d7a5f 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -8070,7 +8070,7 @@ annotate_value (tree gnu_size)
can appear for discriminants in expressions for variants. */
if (tree_int_cst_sgn (gnu_size) < 0)
{
- tree t = wide_int_to_tree (sizetype, wi::neg (gnu_size));
+ tree t = wide_int_to_tree (sizetype, -wi::to_wide (gnu_size));
tcode = Negate_Expr;
ops[0] = UI_From_gnu (t);
}
@@ -8153,11 +8153,13 @@ annotate_value (tree gnu_size)
{
tree inner_op_op1 = TREE_OPERAND (inner_op, 1);
tree gnu_size_op1 = TREE_OPERAND (gnu_size, 1);
- wide_int op1;
+ widest_int op1;
if (TREE_CODE (gnu_size) == MULT_EXPR)
- op1 = wi::mul (inner_op_op1, gnu_size_op1);
+ op1 = (wi::to_widest (inner_op_op1)
+ * wi::to_widest (gnu_size_op1));
else
- op1 = wi::add (inner_op_op1, gnu_size_op1);
+ op1 = (wi::to_widest (inner_op_op1)
+ + wi::to_widest (gnu_size_op1));
ops[1] = UI_From_gnu (wide_int_to_tree (sizetype, op1));
ops[0] = annotate_value (TREE_OPERAND (inner_op, 0));
}
@@ -8172,7 +8174,8 @@ annotate_value (tree gnu_size)
if (TREE_CODE (TREE_OPERAND (gnu_size, 1)) == INTEGER_CST)
{
tree op1 = TREE_OPERAND (gnu_size, 1);
- wide_int signed_op1 = wi::sext (op1, TYPE_PRECISION (sizetype));
+ wide_int signed_op1 = wi::sext (wi::to_wide (op1),
+ TYPE_PRECISION (sizetype));
if (wi::neg_p (signed_op1))
{
op1 = wide_int_to_tree (sizetype, wi::neg (signed_op1));
diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h
index 4ddd0f0..a957de5 100644
--- a/gcc/ada/gcc-interface/gigi.h
+++ b/gcc/ada/gcc-interface/gigi.h
@@ -312,9 +312,9 @@ extern void post_error_ne_tree (const char *msg, Node_Id node, Entity_Id ent,
extern void post_error_ne_tree_2 (const char *msg, Node_Id node, Entity_Id ent,
tree t, int num);
-/* Return a label to branch to for the exception type in KIND or NULL_TREE
+/* Return a label to branch to for the exception type in KIND or Empty
if none. */
-extern tree get_exception_label (char kind);
+extern Entity_Id get_exception_label (char kind);
/* If nonzero, pretend we are allocating at global level. */
extern int force_global;
diff --git a/gcc/ada/gcc-interface/lang.opt b/gcc/ada/gcc-interface/lang.opt
index 241eafc..17c6dc8 100644
--- a/gcc/ada/gcc-interface/lang.opt
+++ b/gcc/ada/gcc-interface/lang.opt
@@ -81,15 +81,15 @@ Ada AdaWhy AdaSCIL
Make \"char\" signed by default.
gant
-Ada AdaWhy AdaSCIL Driver Joined Undocumented
+Ada AdaWhy AdaSCIL Driver Joined Undocumented RejectNegative
Catch typos.
gnatO
-Ada AdaWhy AdaSCIL Driver Separate
+Ada AdaWhy AdaSCIL Driver Separate RejectNegative
Set name of output ALI file (internal switch).
gnat
-Ada AdaWhy AdaSCIL Driver Joined
+Ada AdaWhy AdaSCIL Driver Joined RejectNegative
-gnat<options> Specify options to GNAT.
fbuiltin-printf
diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index 081a63a..7bdb380 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -1370,6 +1370,23 @@ gnat_init_ts (void)
MARK_TS_TYPED (EXIT_STMT);
}
+/* Return the size of a tree with CODE, which is a language-specific tree code
+ in category tcc_constant, tcc_exceptional or tcc_type. The default expects
+ never to be called. */
+
+static size_t
+gnat_tree_size (enum tree_code code)
+{
+ gcc_checking_assert (code >= NUM_TREE_CODES);
+ switch (code)
+ {
+ case UNCONSTRAINED_ARRAY_TYPE:
+ return sizeof (tree_type_non_common);
+ default:
+ gcc_unreachable ();
+ }
+}
+
/* Return the lang specific structure attached to NODE. Allocate it (cleared)
if needed. */
@@ -1387,6 +1404,8 @@ get_lang_specific (tree node)
#define LANG_HOOKS_NAME "GNU Ada"
#undef LANG_HOOKS_IDENTIFIER_SIZE
#define LANG_HOOKS_IDENTIFIER_SIZE sizeof (struct tree_identifier)
+#undef LANG_HOOKS_TREE_SIZE
+#define LANG_HOOKS_TREE_SIZE gnat_tree_size
#undef LANG_HOOKS_INIT
#define LANG_HOOKS_INIT gnat_init
#undef LANG_HOOKS_OPTION_LANG_MASK
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 18bf071..0e46e5a 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -211,9 +211,9 @@ typedef struct loop_info_d *loop_info;
static GTY(()) vec<loop_info, va_gc> *gnu_loop_stack;
/* The stacks for N_{Push,Pop}_*_Label. */
-static GTY(()) vec<tree, va_gc> *gnu_constraint_error_label_stack;
-static GTY(()) vec<tree, va_gc> *gnu_storage_error_label_stack;
-static GTY(()) vec<tree, va_gc> *gnu_program_error_label_stack;
+static vec<Entity_Id> gnu_constraint_error_label_stack;
+static vec<Entity_Id> gnu_storage_error_label_stack;
+static vec<Entity_Id> gnu_program_error_label_stack;
/* Map GNAT tree codes to GCC tree codes for simple expressions. */
static enum tree_code gnu_codes[Number_Node_Kinds];
@@ -226,7 +226,6 @@ static void record_code_position (Node_Id);
static void insert_code_for (Node_Id);
static void add_cleanup (tree, Node_Id);
static void add_stmt_list (List_Id);
-static void push_exception_label_stack (vec<tree, va_gc> **, Entity_Id);
static tree build_stmt_group (List_Id, bool);
static inline bool stmt_group_may_fallthru (void);
static enum gimplify_status gnat_gimplify_stmt (tree *);
@@ -647,9 +646,10 @@ gigi (Node_Id gnat_root,
gnat_install_builtins ();
vec_safe_push (gnu_except_ptr_stack, NULL_TREE);
- vec_safe_push (gnu_constraint_error_label_stack, NULL_TREE);
- vec_safe_push (gnu_storage_error_label_stack, NULL_TREE);
- vec_safe_push (gnu_program_error_label_stack, NULL_TREE);
+
+ gnu_constraint_error_label_stack.safe_push (Empty);
+ gnu_storage_error_label_stack.safe_push (Empty);
+ gnu_program_error_label_stack.safe_push (Empty);
/* Process any Pragma Ident for the main unit. */
if (Present (Ident_String (Main_Unit)))
@@ -5614,7 +5614,7 @@ Raise_Error_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
const bool with_extra_info
= Exception_Extra_Info
&& !No_Exception_Handlers_Set ()
- && !get_exception_label (kind);
+ && No (get_exception_label (kind));
tree gnu_result = NULL_TREE, gnu_cond = NULL_TREE;
/* The following processing is not required for correctness. Its purpose is
@@ -7271,8 +7271,9 @@ gnat_to_gnu (Node_Id gnat_node)
break;
case N_Goto_Statement:
- gnu_result
- = build1 (GOTO_EXPR, void_type_node, gnat_to_gnu (Name (gnat_node)));
+ gnu_expr = gnat_to_gnu (Name (gnat_node));
+ gnu_result = build1 (GOTO_EXPR, void_type_node, gnu_expr);
+ TREE_USED (gnu_expr) = 1;
break;
/***************************/
@@ -7492,30 +7493,36 @@ gnat_to_gnu (Node_Id gnat_node)
break;
case N_Push_Constraint_Error_Label:
- push_exception_label_stack (&gnu_constraint_error_label_stack,
- Exception_Label (gnat_node));
+ gnu_constraint_error_label_stack.safe_push (Exception_Label (gnat_node));
break;
case N_Push_Storage_Error_Label:
- push_exception_label_stack (&gnu_storage_error_label_stack,
- Exception_Label (gnat_node));
+ gnu_storage_error_label_stack.safe_push (Exception_Label (gnat_node));
break;
case N_Push_Program_Error_Label:
- push_exception_label_stack (&gnu_program_error_label_stack,
- Exception_Label (gnat_node));
+ gnu_program_error_label_stack.safe_push (Exception_Label (gnat_node));
break;
case N_Pop_Constraint_Error_Label:
- gnu_constraint_error_label_stack->pop ();
+ gnat_temp = gnu_constraint_error_label_stack.pop ();
+ if (Present (gnat_temp)
+ && !TREE_USED (gnat_to_gnu_entity (gnat_temp, NULL_TREE, false)))
+ Warn_If_No_Local_Raise (gnat_temp);
break;
case N_Pop_Storage_Error_Label:
- gnu_storage_error_label_stack->pop ();
+ gnat_temp = gnu_storage_error_label_stack.pop ();
+ if (Present (gnat_temp)
+ && !TREE_USED (gnat_to_gnu_entity (gnat_temp, NULL_TREE, false)))
+ Warn_If_No_Local_Raise (gnat_temp);
break;
case N_Pop_Program_Error_Label:
- gnu_program_error_label_stack->pop ();
+ gnat_temp = gnu_program_error_label_stack.pop ();
+ if (Present (gnat_temp)
+ && !TREE_USED (gnat_to_gnu_entity (gnat_temp, NULL_TREE, false)))
+ Warn_If_No_Local_Raise (gnat_temp);
break;
/******************************/
@@ -7688,6 +7695,15 @@ gnat_to_gnu (Node_Id gnat_node)
/* Added Nodes */
/****************/
+ /* Call markers are created by the ABE mechanism to capture the target of
+ a call along with other elaboration-related attributes which are either
+ unavailable of expensive to recompute. Call markers do not have static
+ and runtime semantics, and should be ignored. */
+
+ case N_Call_Marker:
+ gnu_result = alloc_stmt_list ();
+ break;
+
case N_Expression_With_Actions:
/* This construct doesn't define a scope so we don't push a binding
level around the statement list, but we wrap it in a SAVE_EXPR to
@@ -8020,20 +8036,6 @@ gnat_to_gnu_external (Node_Id gnat_node)
return gnu_result;
}
-/* Subroutine of above to push the exception label stack. GNU_STACK is
- a pointer to the stack to update and GNAT_LABEL, if present, is the
- label to push onto the stack. */
-
-static void
-push_exception_label_stack (vec<tree, va_gc> **gnu_stack, Entity_Id gnat_label)
-{
- tree gnu_label = (Present (gnat_label)
- ? gnat_to_gnu_entity (gnat_label, NULL_TREE, false)
- : NULL_TREE);
-
- vec_safe_push (*gnu_stack, gnu_label);
-}
-
/* Return true if the statement list STMT_LIST is empty. */
static bool
@@ -10217,28 +10219,28 @@ post_error_ne_tree_2 (const char *msg, Node_Id node, Entity_Id ent, tree t,
post_error_ne_tree (msg, node, ent, t);
}
-/* Return a label to branch to for the exception type in KIND or NULL_TREE
+/* Return a label to branch to for the exception type in KIND or Empty
if none. */
-tree
+Entity_Id
get_exception_label (char kind)
{
switch (kind)
{
case N_Raise_Constraint_Error:
- return gnu_constraint_error_label_stack->last ();
+ return gnu_constraint_error_label_stack.last ();
case N_Raise_Storage_Error:
- return gnu_storage_error_label_stack->last ();
+ return gnu_storage_error_label_stack.last ();
case N_Raise_Program_Error:
- return gnu_program_error_label_stack->last ();
+ return gnu_program_error_label_stack.last ();
default:
- break;
+ return Empty;
}
- return NULL_TREE;
+ gcc_unreachable ();
}
/* Return the decl for the current elaboration procedure. */
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 0419976..bfd3388 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -101,7 +101,7 @@ static tree handle_vector_type_attribute (tree *, tree, tree, int, bool *);
/* Fake handler for attributes we don't properly support, typically because
they'd require dragging a lot of the common-c front-end circuitry. */
-static tree fake_attribute_handler (tree *, tree, tree, int, bool *);
+static tree fake_attribute_handler (tree *, tree, tree, int, bool *);
/* Table of machine-independent internal attributes for Ada. We support
this minimal set of attributes to accommodate the needs of builtins. */
@@ -222,8 +222,9 @@ static GTY((deletable)) tree free_block_chain;
/* A hash table of padded types. It is modelled on the generic type
hash table in tree.c, which must thus be used as a reference. */
-struct GTY((for_user)) pad_type_hash {
- unsigned long hash;
+struct GTY((for_user)) pad_type_hash
+{
+ hashval_t hash;
tree type;
};
@@ -3595,6 +3596,10 @@ max_size (tree exp, bool max_p)
case tcc_constant:
return exp;
+ case tcc_exceptional:
+ gcc_assert (code == SSA_NAME);
+ return exp;
+
case tcc_vl_exp:
if (code == CALL_EXPR)
{
@@ -4245,10 +4250,13 @@ convert (tree type, tree expr)
return convert (type, TREE_OPERAND (expr, 0));
/* 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. */
+ is a record, do this as an unchecked conversion unless both types are
+ essentially the same. But first pad the expression if possible to
+ have the same size on both sides. */
if (ecode == RECORD_TYPE
- && CONTAINS_PLACEHOLDER_P (DECL_SIZE (TYPE_FIELDS (type))))
+ && CONTAINS_PLACEHOLDER_P (DECL_SIZE (TYPE_FIELDS (type)))
+ && TYPE_MAIN_VARIANT (etype)
+ != TYPE_MAIN_VARIANT (TREE_TYPE (TYPE_FIELDS (type))))
{
if (TREE_CODE (TYPE_SIZE (etype)) == INTEGER_CST)
expr = convert (maybe_pad_type (etype, TYPE_SIZE (type), 0, Empty,
diff --git a/gcc/ada/gcc-interface/utils2.c b/gcc/ada/gcc-interface/utils2.c
index 6f109c7..dcd4134 100644
--- a/gcc/ada/gcc-interface/utils2.c
+++ b/gcc/ada/gcc-interface/utils2.c
@@ -1787,9 +1787,10 @@ build_call_n_expr (tree fndecl, int n, ...)
MSG gives the exception's identity for the call to Local_Raise, if any. */
static tree
-build_goto_raise (tree label, int msg)
+build_goto_raise (Entity_Id gnat_label, int msg)
{
- tree gnu_result = build1 (GOTO_EXPR, void_type_node, label);
+ tree gnu_label = gnat_to_gnu_entity (gnat_label, NULL_TREE, false);
+ tree gnu_result = build1 (GOTO_EXPR, void_type_node, gnu_label);
Entity_Id local_raise = Get_Local_Raise_Call_Entity ();
/* If Local_Raise is present, build Local_Raise (Exception'Identity). */
@@ -1807,6 +1808,7 @@ build_goto_raise (tree label, int msg)
= build2 (COMPOUND_EXPR, void_type_node, gnu_call, gnu_result);
}
+ TREE_USED (gnu_label) = 1;
return gnu_result;
}
@@ -1859,13 +1861,13 @@ expand_sloc (Node_Id gnat_node, tree *filename, tree *line, tree *col)
tree
build_call_raise (int msg, Node_Id gnat_node, char kind)
{
+ Entity_Id gnat_label = get_exception_label (kind);
tree fndecl = gnat_raise_decls[msg];
- tree label = get_exception_label (kind);
tree filename, line;
/* If this is to be done as a goto, handle that case. */
- if (label)
- return build_goto_raise (label, msg);
+ if (Present (gnat_label))
+ return build_goto_raise (gnat_label, msg);
expand_sloc (gnat_node, &filename, &line, NULL);
@@ -1883,13 +1885,13 @@ build_call_raise (int msg, Node_Id gnat_node, char kind)
tree
build_call_raise_column (int msg, Node_Id gnat_node, char kind)
{
+ Entity_Id gnat_label = get_exception_label (kind);
tree fndecl = gnat_raise_decls_ext[msg];
- tree label = get_exception_label (kind);
tree filename, line, col;
/* If this is to be done as a goto, handle that case. */
- if (label)
- return build_goto_raise (label, msg);
+ if (Present (gnat_label))
+ return build_goto_raise (gnat_label, msg);
expand_sloc (gnat_node, &filename, &line, &col);
@@ -1908,13 +1910,13 @@ tree
build_call_raise_range (int msg, Node_Id gnat_node, char kind,
tree index, tree first, tree last)
{
+ Entity_Id gnat_label = get_exception_label (kind);
tree fndecl = gnat_raise_decls_ext[msg];
- tree label = get_exception_label (kind);
tree filename, line, col;
/* If this is to be done as a goto, handle that case. */
- if (label)
- return build_goto_raise (label, msg);
+ if (Present (gnat_label))
+ return build_goto_raise (gnat_label, msg);
expand_sloc (gnat_node, &filename, &line, &col);
diff --git a/gcc/ada/ghost.adb b/gcc/ada/ghost.adb
index 6640d6a..e7ca3bf 100644
--- a/gcc/ada/ghost.adb
+++ b/gcc/ada/ghost.adb
@@ -23,7 +23,7 @@
-- --
------------------------------------------------------------------------------
-with Alloc; use Alloc;
+with Alloc;
with Aspects; use Aspects;
with Atree; use Atree;
with Einfo; use Einfo;
@@ -1477,10 +1477,10 @@ package body Ghost is
begin
if Nkind (N) = N_Use_Package_Clause then
- Nam := First (Names (N));
+ Nam := Name (N);
elsif Nkind (N) = N_Use_Type_Clause then
- Nam := First (Subtype_Marks (N));
+ Nam := Subtype_Mark (N);
elsif Nkind (N) = N_With_Clause then
Nam := Name (N);
diff --git a/gcc/ada/gnat1drv.adb b/gcc/ada/gnat1drv.adb
index b493d53..4bf910b 100644
--- a/gcc/ada/gnat1drv.adb
+++ b/gcc/ada/gnat1drv.adb
@@ -23,36 +23,36 @@
-- --
------------------------------------------------------------------------------
-with Atree; use Atree;
-with Back_End; use Back_End;
+with Atree; use Atree;
+with Back_End; use Back_End;
with Checks;
with Comperr;
-with Csets; use Csets;
-with Debug; use Debug;
+with Csets;
+with Debug; use Debug;
with Elists;
-with Errout; use Errout;
+with Errout; use Errout;
with Exp_CG;
with Fmap;
-with Fname; use Fname;
-with Fname.UF; use Fname.UF;
+with Fname; use Fname;
+with Fname.UF; use Fname.UF;
with Frontend;
-with Ghost; use Ghost;
-with Gnatvsn; use Gnatvsn;
+with Ghost; use Ghost;
+with Gnatvsn; use Gnatvsn;
with Inline;
-with Lib; use Lib;
-with Lib.Writ; use Lib.Writ;
+with Lib; use Lib;
+with Lib.Writ; use Lib.Writ;
with Lib.Xref;
-with Namet; use Namet;
+with Namet; use Namet;
with Nlists;
-with Opt; use Opt;
-with Osint; use Osint;
-with Osint.C; use Osint.C;
-with Output; use Output;
+with Opt; use Opt;
+with Osint; use Osint;
+with Osint.C; use Osint.C;
+with Output; use Output;
with Par_SCO;
with Prepcomp;
-with Repinfo; use Repinfo;
+with Repinfo; use Repinfo;
with Restrict;
-with Rident; use Rident;
+with Rident; use Rident;
with Rtsfind;
with SCOs;
with Sem;
@@ -64,23 +64,23 @@ with Sem_Eval;
with Sem_SPARK; use Sem_SPARK;
with Sem_Type;
with Set_Targ;
-with Sinfo; use Sinfo;
-with Sinput.L; use Sinput.L;
-with Snames; use Snames;
-with Sprint; use Sprint;
+with Sinfo; use Sinfo;
+with Sinput.L; use Sinput.L;
+with Snames; use Snames;
+with Sprint; use Sprint;
with Stringt;
-with Stylesw; use Stylesw;
-with Targparm; use Targparm;
+with Stylesw; use Stylesw;
+with Targparm; use Targparm;
with Tbuild;
with Tree_Gen;
-with Treepr; use Treepr;
+with Treepr; use Treepr;
with Ttypes;
-with Types; use Types;
-with Uintp; use Uintp;
-with Uname; use Uname;
+with Types; use Types;
+with Uintp;
+with Uname; use Uname;
with Urealp;
with Usage;
-with Validsw; use Validsw;
+with Validsw; use Validsw;
with System.Assertions;
with System.OS_Lib;
@@ -852,7 +852,7 @@ procedure Gnat1drv is
-- pragma, to be used this way and to cause the body file to be
-- ignored in this context).
- if Src_Ind /= No_Source_File
+ if Src_Ind > No_Source_File
and then Source_File_Is_Body (Src_Ind)
then
Errout.Finalize (Last_Call => False);
@@ -1066,6 +1066,12 @@ begin
Write_Line ("cannot locate file system.ads");
raise Unrecoverable_Error;
+ elsif S = No_Access_To_Source_File then
+ Write_Line
+ ("fatal error, run-time library not installed correctly");
+ Write_Line ("no read access for file system.ads");
+ raise Unrecoverable_Error;
+
-- Read system.ads successfully, remember its source index
else
@@ -1141,7 +1147,7 @@ begin
-- Exit with errors if the main source could not be parsed
- if Sinput.Main_Source_File = No_Source_File then
+ if Sinput.Main_Source_File <= No_Source_File then
Errout.Finalize (Last_Call => True);
Errout.Output_Messages;
Exit_Program (E_Errors);
diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi
index 21b5c71..b042e2b 100644
--- a/gcc/ada/gnat_rm.texi
+++ b/gcc/ada/gnat_rm.texi
@@ -21,7 +21,7 @@
@copying
@quotation
-GNAT Reference Manual , Sep 13, 2017
+GNAT Reference Manual , Oct 14, 2017
AdaCore
@@ -5547,6 +5547,9 @@ Specifying SPACE also disables alignment promotions for standalone objects,
which occur when the compiler increases the alignment of a specific object
without changing the alignment of its type.
+Specifying SPACE also disables component reordering in unpacked record types,
+which can result in larger sizes in order to meet alignment requirements.
+
Specifying TIME causes larger default alignments to be chosen in the case of
small types with sizes that are not a power of 2. For example, consider:
@@ -9410,11 +9413,20 @@ that it is separately controllable using pragma @code{Assertion_Policy}.
This aspect provides a light-weight mechanism for loops and quantified
expressions over container types, without the overhead imposed by the tampering
checks of standard Ada 2012 iterators. The value of the aspect is an aggregate
-with four named components: @code{First}, @code{Next}, @code{Has_Element}, and @code{Element} (the
-last one being optional). When only 3 components are specified, only the
-@code{for .. in} form of iteration over cursors is available. When all 4 components
-are specified, both this form and the @code{for .. of} form of iteration over
-elements are available. The following is a typical example of use:
+with six named components, or which the last three are optional: @code{First},
+
+@quotation
+
+@code{Next}, @code{Has_Element},`@w{`}Element`@w{`}, @code{Last}, and @code{Previous}.
+@end quotation
+
+When only the first three components are specified, only the
+@code{for .. in} form of iteration over cursors is available. When @code{Element}
+is specified, both this form and the @code{for .. of} form of iteration over
+elements are available. If the last two components are specified, reverse
+iterations over the container can be specified (analogous to what can be done
+over predefined containers that support the Reverse_Iterator interface).
+The following is a typical example of use:
@example
type List is private with
@@ -18099,7 +18111,7 @@ will be as described for elementary types, e.g. a packed array of length
@item
@emph{Records}.
-For the normal non-packed case, the alignment of a record is equal to
+For the normal unpacked case, the alignment of a record is equal to
the maximum alignment of any of its components. For tagged records, this
includes the implicit access type used for the tag. If a pragma @code{Pack}
is used and all components are packable (see separate section on pragma
diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi
index a572de0..9475067 100644
--- a/gcc/ada/gnat_ugn.texi
+++ b/gcc/ada/gnat_ugn.texi
@@ -21,7 +21,7 @@
@copying
@quotation
-GNAT User's Guide for Native Platforms , Sep 13, 2017
+GNAT User's Guide for Native Platforms , Oct 20, 2017
AdaCore
@@ -529,19 +529,21 @@ Mac OS Topics
Elaboration Order Handling in GNAT
* Elaboration Code::
+* Elaboration Order::
* Checking the Elaboration Order::
-* Controlling the Elaboration Order::
-* Controlling Elaboration in GNAT - Internal Calls::
-* Controlling Elaboration in GNAT - External Calls::
-* Default Behavior in GNAT - Ensuring Safety::
-* Treatment of Pragma Elaborate::
-* Elaboration Issues for Library Tasks::
+* Controlling the Elaboration Order in Ada::
+* Controlling the Elaboration Order in GNAT::
+* Common Elaboration-model Traits::
+* Dynamic Elaboration Model in GNAT::
+* Static Elaboration Model in GNAT::
+* SPARK Elaboration Model in GNAT::
* Mixing Elaboration Models::
-* What to Do If the Default Elaboration Behavior Fails::
-* Elaboration for Indirect Calls::
+* Elaboration Circularities::
+* Resolving Elaboration Circularities::
+* Resolving Task Issues::
+* Elaboration-related Compiler Switches::
* Summary of Procedures for Elaboration Control::
-* Other Elaboration Order Considerations::
-* Determining the Chosen Elaboration Order::
+* Inspecting the Chosen Elaboration Order::
Inline Assembler
@@ -3193,7 +3195,7 @@ depend on a file that no longer exists. Such tools include
If you are using project file, a separate mechanism is provided using
project attributes.
-@c --Comment:
+@c --Comment
@c See :ref:`Specifying_Configuration_Pragmas` for more details.
@node Generating Object Files,Source Dependencies,Configuration Pragmas,The GNAT Compilation Model
@@ -7925,7 +7927,7 @@ Unique. Recompile at most the main files. It implies -c. Combined with
-u with a project file and no main has a special meaning.
@end table
-@c --Comment:
+@c --Comment
@c (See :ref:`Project_Files_and_Main_Subprograms`.)
@geindex -U (gnatmake)
@@ -8807,19 +8809,6 @@ in the compiler sources for details in files @code{scos.ads} and
@code{scos.adb}.
@end table
-@geindex -fdump-xref (gcc)
-
-
-@table @asis
-
-@item @code{-fdump-xref}
-
-Generates cross reference information in GLI files for C and C++ sources.
-The GLI files have the same syntax as the ALI files for Ada, and can be used
-for source navigation in IDEs and on the command line using e.g. gnatxref
-and the @code{--ext=gli} switch.
-@end table
-
@geindex -flto (gcc)
@@ -8828,8 +8817,9 @@ and the @code{--ext=gli} switch.
@item @code{-flto[=@emph{n}]}
Enables Link Time Optimization. This switch must be used in conjunction
-with the traditional @code{-Ox} switches and instructs the compiler to
-defer most optimizations until the link stage. The advantage of this
+with the @code{-Ox} switches (but not with the @code{-gnatn} switch
+since it is a full replacement for the latter) and instructs the compiler
+to defer most optimizations until the link stage. The advantage of this
approach is that the compiler can do a whole-program analysis and choose
the best interprocedural optimization strategy based on a complete view
of the program, instead of a fragmentary view with the usual approach.
@@ -12472,8 +12462,8 @@ should not complain at you.
This switch activates warnings for exception usage when pragma Restrictions
(No_Exception_Propagation) is in effect. Warnings are given for implicit or
explicit exception raises which are not covered by a local handler, and for
-exception handlers which do not cover a local raise. The default is that these
-warnings are not given.
+exception handlers which do not cover a local raise. The default is that
+these warnings are given for units that contain exception handlers.
@item @code{-gnatw.X}
@@ -17654,7 +17644,7 @@ Add @code{dir} at the beginning of the project search dir.
@table @asis
-@item @code{--RTS=@emph{rts-path}`}
+@item @code{--RTS=@emph{rts-path}}
Specifies the default location of the runtime library. Same meaning as the
equivalent @code{gnatmake} flag (@ref{dc,,Switches for gnatmake}).
@@ -17947,9 +17937,9 @@ Do not look for library files in the system default directory.
@item @code{--ext=@emph{extension}}
Specify an alternate ali file extension. The default is @code{ali} and other
-extensions (e.g. @code{gli} for C/C++ sources when using @code{-fdump-xref})
-may be specified via this switch. Note that if this switch overrides the
-default, which means that only the new extension will be considered.
+extensions (e.g. @code{gli} for C/C++ sources) may be specified via this switch.
+Note that if this switch overrides the default, which means that only the
+new extension will be considered.
@end table
@geindex --RTS (gnatxref)
@@ -22773,7 +22763,7 @@ However, incorrect assignments such as:
@example
Distance := 5.0;
-Distance := 5.0 * kg:
+Distance := 5.0 * kg;
@end example
@end quotation
@@ -22854,7 +22844,7 @@ end;
@end quotation
Here @code{DV(Acc)} = @code{DV(Acceleration)} =
-@code{(Meter=>1, Kilogram=>0, Second => -2, Ampere=>0, Kelvin=>0, Mole=>0, Candela => 0)}.
+@code{(Meter=>1, Kilogram=>0, Second=>-2, Ampere=>0, Kelvin=>0, Mole=>0, Candela=>0)}.
Symbolically, we can express this as @code{Meter / Second**2}.
The dimension vector of an arithmetic expression is synthesized from the
@@ -22899,12 +22889,12 @@ combine a dimensioned and dimensionless value. Thus an expression such as
@code{Acceleration}.
The dimensionality checks for relationals use the same rules as
-for "+" and "-"; thus
+for "+" and "-", except when comparing to a literal; thus
@quotation
@example
-acc > 10.0
+acc > len
@end example
@end quotation
@@ -22913,12 +22903,21 @@ is equivalent to
@quotation
@example
-acc-10.0 > 0.0
+acc-len > 0.0
@end example
@end quotation
-and is thus illegal. Analogously a conditional expression
-requires the same dimension vector for each branch.
+and is thus illegal, but
+
+@quotation
+
+@example
+acc > 10.0
+@end example
+@end quotation
+
+is accepted with a warning. Analogously a conditional expression requires the
+same dimension vector for each branch (with no exception for literals).
The dimension vector of a type conversion @code{T(@emph{expr})} is defined
as follows, based on the nature of @code{T}:
@@ -27013,322 +27012,415 @@ elaboration code in your own application).
@geindex Elaboration control
-This appendix describes the handling of elaboration code in Ada and
-in GNAT, and discusses how the order of elaboration of program units can
-be controlled in GNAT, either automatically or with explicit programming
-features.
+This appendix describes the handling of elaboration code in Ada and GNAT, and
+discusses how the order of elaboration of program units can be controlled in
+GNAT, either automatically or with explicit programming features.
@menu
* Elaboration Code::
+* Elaboration Order::
* Checking the Elaboration Order::
-* Controlling the Elaboration Order::
-* Controlling Elaboration in GNAT - Internal Calls::
-* Controlling Elaboration in GNAT - External Calls::
-* Default Behavior in GNAT - Ensuring Safety::
-* Treatment of Pragma Elaborate::
-* Elaboration Issues for Library Tasks::
+* Controlling the Elaboration Order in Ada::
+* Controlling the Elaboration Order in GNAT::
+* Common Elaboration-model Traits::
+* Dynamic Elaboration Model in GNAT::
+* Static Elaboration Model in GNAT::
+* SPARK Elaboration Model in GNAT::
* Mixing Elaboration Models::
-* What to Do If the Default Elaboration Behavior Fails::
-* Elaboration for Indirect Calls::
+* Elaboration Circularities::
+* Resolving Elaboration Circularities::
+* Resolving Task Issues::
+* Elaboration-related Compiler Switches::
* Summary of Procedures for Elaboration Control::
-* Other Elaboration Order Considerations::
-* Determining the Chosen Elaboration Order::
+* Inspecting the Chosen Elaboration Order::
@end menu
-@node Elaboration Code,Checking the Elaboration Order,,Elaboration Order Handling in GNAT
+@node Elaboration Code,Elaboration Order,,Elaboration Order Handling in GNAT
@anchor{gnat_ugn/elaboration_order_handling_in_gnat elaboration-code}@anchor{22e}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id2}@anchor{22f}
@section Elaboration Code
-Ada provides rather general mechanisms for executing code at elaboration
-time, that is to say before the main program starts executing. Such code arises
-in three contexts:
+Ada defines the term @emph{execution} as the process by which a construct achieves
+its run-time effect. This process is also referred to as @strong{elaboration} for
+declarations and @emph{evaluation} for expressions.
+
+The execution model in Ada allows for certain sections of an Ada program to be
+executed prior to execution of the program itself, primarily with the intent of
+initializing data. These sections are referred to as @strong{elaboration code}.
+Elaboration code is executed as follows:
@itemize *
@item
-@emph{Initializers for variables}
+All partitions of an Ada program are executed in parallel with one another,
+possibly in a separate address space, and possibly on a separate computer.
-Variables declared at the library level, in package specs or bodies, can
-require initialization that is performed at elaboration time, as in:
+@item
+The execution of a partition involves running the environment task for that
+partition.
-@example
-Sqrt_Half : Float := Sqrt (0.5);
-@end example
+@item
+The environment task executes all elaboration code (if available) for all
+units within that partition. This code is said to be executed at
+@strong{elaboration time}.
+
+@item
+The environment task executes the Ada program (if available) for that
+partition.
+@end itemize
+
+In addition to the Ada terminology, this appendix defines the following terms:
+
+
+@itemize *
+
+@item
+@emph{Scenario}
+
+A construct that is elaborated or executed by elaboration code is referred to
+as an @emph{elaboration scenario} or simply a @strong{scenario}. GNAT recognizes the
+following scenarios:
+
+
+@itemize -
@item
-@emph{Package initialization code}
+@code{'Access} of entries, operators, and subprograms
+
+@item
+Activation of tasks
+
+@item
+Calls to entries, operators, and subprograms
+
+@item
+Instantiations of generic templates
+@end itemize
+
+@item
+@emph{Target}
+
+A construct elaborated by a scenario is referred to as @emph{elaboration target}
+or simply @strong{target}. GNAT recognizes the following targets:
-Code in a @code{begin} ... `@w{`} end`@w{`} section at the outer level of a package body is
-executed as part of the package body elaboration code.
+
+@itemize -
+
+@item
+For @code{'Access} of entries, operators, and subprograms, the target is the
+entry, operator, or subprogram being aliased.
+
+@item
+For activation of tasks, the target is the task body
@item
-@emph{Library level task allocators}
+For calls to entries, operators, and subprograms, the target is the entry,
+operator, or subprogram being invoked.
-Tasks that are declared using task allocators at the library level
-start executing immediately and hence can execute at elaboration time.
+@item
+For instantiations of generic templates, the target is the generic template
+being instantiated.
+@end itemize
@end itemize
-Subprogram calls are possible in any of these contexts, which means that
-any arbitrary part of the program may be executed as part of the elaboration
-code. It is even possible to write a program which does all its work at
-elaboration time, with a null main program, although stylistically this
-would usually be considered an inappropriate way to structure
-a program.
+Elaboration code may appear in two distinct contexts:
-An important concern arises in the context of elaboration code:
-we have to be sure that it is executed in an appropriate order. What we
-have is a series of elaboration code sections, potentially one section
-for each unit in the program. It is important that these execute
-in the correct order. Correctness here means that, taking the above
-example of the declaration of @code{Sqrt_Half},
-if some other piece of
-elaboration code references @code{Sqrt_Half},
-then it must run after the
-section of elaboration code that contains the declaration of
-@code{Sqrt_Half}.
-There would never be any order of elaboration problem if we made a rule
-that whenever you @emph{with} a unit, you must elaborate both the spec and body
-of that unit before elaborating the unit doing the @emph{with}ing:
+@itemize *
+
+@item
+@emph{Library level}
+
+A scenario appears at the library level when it is encapsulated by a package
+[body] compilation unit, ignoring any other package [body] declarations in
+between.
@example
-with Unit_1;
-package Unit_2 is ...
+with Server;
+package Client is
+ procedure Proc;
+
+ package Nested is
+ Val : ... := Server.Func;
+ end Nested;
+end Client;
@end example
-would require that both the body and spec of @code{Unit_1} be elaborated
-before the spec of @code{Unit_2}. However, a rule like that would be far too
-restrictive. In particular, it would make it impossible to have routines
-in separate packages that were mutually recursive.
+In the example above, the call to @code{Server.Func} is an elaboration scenario
+because it appears at the library level of package @code{Client}. Note that the
+declaration of package @code{Nested} is ignored according to the definition
+given above. As a result, the call to @code{Server.Func} will be executed when
+the spec of unit @code{Client} is elaborated.
-You might think that a clever enough compiler could look at the actual
-elaboration code and determine an appropriate correct order of elaboration,
-but in the general case, this is not possible. Consider the following
-example.
+@item
+@emph{Package body statements}
-In the body of @code{Unit_1}, we have a procedure @code{Func_1}
-that references
-the variable @code{Sqrt_1}, which is declared in the elaboration code
-of the body of @code{Unit_1}:
+A scenario appears within the statement sequence of a package body when it is
+bounded by the region starting from the @code{begin} keyword of the package body
+and ending at the @code{end} keyword of the package body.
@example
-Sqrt_1 : Float := Sqrt (0.1);
+package body Client is
+ procedure Proc is
+ begin
+ ...
+ end Proc;
+begin
+ Proc;
+end Client;
@end example
-The elaboration code of the body of @code{Unit_1} also contains:
+In the example above, the call to @code{Proc} is an elaboration scenario because
+it appears within the statement sequence of package body @code{Client}. As a
+result, the call to @code{Proc} will be executed when the body of @code{Client} is
+elaborated.
+@end itemize
+
+@node Elaboration Order,Checking the Elaboration Order,Elaboration Code,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat elaboration-order}@anchor{230}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id3}@anchor{231}
+@section Elaboration Order
+
+
+The sequence by which the elaboration code of all units within a partition is
+executed is referred to as @strong{elaboration order}.
+
+Within a single unit, elaboration code is executed in sequential order.
@example
-if expression_1 = 1 then
- Q := Unit_2.Func_2;
-end if;
+package body Client is
+ Result : ... := Server.Func;
+
+ procedure Proc is
+ package Inst is new Server.Gen;
+ begin
+ Inst.Eval (Result);
+ end Proc;
+begin
+ Proc;
+end Client;
@end example
-@code{Unit_2} is exactly parallel,
-it has a procedure @code{Func_2} that references
-the variable @code{Sqrt_2}, which is declared in the elaboration code of
-the body @code{Unit_2}:
+In the example above, the elaboration order within package body @code{Client} is
+as follows:
+
+
+@enumerate
+
+@item
+The object declaration of @code{Result} is elaborated.
+
+
+@itemize *
+
+@item
+Function @code{Server.Func} is invoked.
+@end itemize
+
+@item
+The subprogram body of @code{Proc} is elaborated.
+
+@item
+Procedure @code{Proc} is invoked.
+
+
+@itemize *
+
+@item
+Generic unit @code{Server.Gen} is instantiated as @code{Inst}.
+
+@item
+Instance @code{Inst} is elaborated.
+
+@item
+Procedure @code{Inst.Eval} is invoked.
+@end itemize
+@end enumerate
+
+The elaboration order of all units within a partition depends on the following
+factors:
+
+
+@itemize *
+
+@item
+@emph{with}ed units
+
+@item
+purity of units
+
+@item
+preelaborability of units
+
+@item
+presence of elaboration control pragmas
+@end itemize
+
+A program may have several elaboration orders depending on its structure.
@example
-Sqrt_2 : Float := Sqrt (0.1);
+package Server is
+ function Func (Index : Integer) return Integer;
+end Server;
@end example
-The elaboration code of the body of @code{Unit_2} also contains:
-
@example
-if expression_2 = 2 then
- Q := Unit_1.Func_1;
-end if;
+package body Server is
+ Results : array (1 .. 5) of Integer := (1, 2, 3, 4, 5);
+
+ function Func (Index : Integer) return Integer is
+ begin
+ return Results (Index);
+ end Func;
+end Server;
@end example
-Now the question is, which of the following orders of elaboration is
-acceptable:
+@example
+with Server;
+package Client is
+ Val : constant Integer := Server.Func (3);
+end Client;
+@end example
@example
-Spec of Unit_1
-Spec of Unit_2
-Body of Unit_1
-Body of Unit_2
+with Client;
+procedure Main is begin null; end Main;
@end example
-or
+The following elaboration order exhibits a fundamental problem referred to as
+@emph{access-before-elaboration} or simply @strong{ABE}.
@example
-Spec of Unit_2
-Spec of Unit_1
-Body of Unit_2
-Body of Unit_1
-@end example
-
-If you carefully analyze the flow here, you will see that you cannot tell
-at compile time the answer to this question.
-If @code{expression_1} is not equal to 1,
-and @code{expression_2} is not equal to 2,
-then either order is acceptable, because neither of the function calls is
-executed. If both tests evaluate to true, then neither order is acceptable
-and in fact there is no correct order.
-
-If one of the two expressions is true, and the other is false, then one
-of the above orders is correct, and the other is incorrect. For example,
-if @code{expression_1} /= 1 and @code{expression_2} = 2,
-then the call to @code{Func_1}
-will occur, but not the call to @code{Func_2.}
-This means that it is essential
-to elaborate the body of @code{Unit_1} before
-the body of @code{Unit_2}, so the first
-order of elaboration is correct and the second is wrong.
-
-By making @code{expression_1} and @code{expression_2}
-depend on input data, or perhaps
-the time of day, we can make it impossible for the compiler or binder
-to figure out which of these expressions will be true, and hence it
-is impossible to guarantee a safe order of elaboration at run time.
-
-@node Checking the Elaboration Order,Controlling the Elaboration Order,Elaboration Code,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat checking-the-elaboration-order}@anchor{230}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id3}@anchor{231}
-@section Checking the Elaboration Order
+spec of Server
+spec of Client
+body of Server
+body of Main
+@end example
+The elaboration of @code{Server}'s spec materializes function @code{Func}, making it
+callable. The elaboration of @code{Client}'s spec elaborates the declaration of
+@code{Val}. This invokes function @code{Server.Func}, however the body of
+@code{Server.Func} has not been elaborated yet because @code{Server}'s body comes
+after @code{Client}'s spec in the elaboration order. As a result, the value of
+constant @code{Val} is now undefined.
-In some languages that involve the same kind of elaboration problems,
-e.g., Java and C++, the programmer needs to take these
-ordering problems into account, and it is common to
-write a program in which an incorrect elaboration order gives
-surprising results, because it references variables before they
-are initialized.
-Ada is designed to be a safe language, and a programmer-beware approach is
-clearly not sufficient. Consequently, the language provides three lines
-of defense:
+Without any guarantees from the language, an undetected ABE problem may hinder
+proper initialization of data, which in turn may lead to undefined behavior at
+run time. To prevent such ABE problems, Ada employs dynamic checks in the same
+vein as index or null exclusion checks. A failed ABE check raises exception
+@code{Program_Error}.
+The following elaboration order avoids the ABE problem and the program can be
+successfully elaborated.
-@itemize *
+@example
+spec of Server
+body of Server
+spec of Client
+body of Main
+@end example
-@item
-@emph{Standard rules}
+Ada states that a total elaboration order must exist, but it does not define
+what this order is. A compiler is thus tasked with choosing a suitable
+elaboration order which satisfies the dependencies imposed by @emph{with} clauses,
+unit categorization, and elaboration control pragmas. Ideally an order which
+avoids ABE problems should be chosen, however a compiler may not always find
+such an order due to complications with respect to control and data flow.
-Some standard rules restrict the possible choice of elaboration
-order. In particular, if you @emph{with} a unit, then its spec is always
-elaborated before the unit doing the @emph{with}. Similarly, a parent
-spec is always elaborated before the child spec, and finally
-a spec is always elaborated before its corresponding body.
-@end itemize
+@node Checking the Elaboration Order,Controlling the Elaboration Order in Ada,Elaboration Order,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat id4}@anchor{232}@anchor{gnat_ugn/elaboration_order_handling_in_gnat checking-the-elaboration-order}@anchor{233}
+@section Checking the Elaboration Order
-@geindex Elaboration checks
-@geindex Checks
-@geindex elaboration
+To avoid placing the entire elaboration order burden on the programmer, Ada
+provides three lines of defense:
@itemize *
@item
-@emph{Dynamic elaboration checks}
+@emph{Static semantics}
-Dynamic checks are made at run time, so that if some entity is accessed
-before it is elaborated (typically by means of a subprogram call)
-then the exception (@code{Program_Error}) is raised.
+Static semantic rules restrict the possible choice of elaboration order. For
+instance, if unit Client @emph{with}s unit Server, then the spec of Server is
+always elaborated prior to Client. The same principle applies to child units
+- the spec of a parent unit is always elaborated prior to the child unit.
@item
-@emph{Elaboration control}
+@emph{Dynamic semantics}
-Facilities are provided for the programmer to specify the desired order
-of elaboration.
-@end itemize
-
-Let's look at these facilities in more detail. First, the rules for
-dynamic checking. One possible rule would be simply to say that the
-exception is raised if you access a variable which has not yet been
-elaborated. The trouble with this approach is that it could require
-expensive checks on every variable reference. Instead Ada has two
-rules which are a little more restrictive, but easier to check, and
-easier to state:
+Dynamic checks are performed at run time, to ensure that a target is
+elaborated prior to a scenario that executes it, thus avoiding ABE problems.
+A failed run-time check raises exception @code{Program_Error}. The following
+restrictions apply:
-@itemize *
+@itemize -
@item
@emph{Restrictions on calls}
-A subprogram can only be called at elaboration time if its body
-has been elaborated. The rules for elaboration given above guarantee
-that the spec of the subprogram has been elaborated before the
-call, but not the body. If this rule is violated, then the
-exception @code{Program_Error} is raised.
+An entry, operator, or subprogram can be called from elaboration code only
+when the corresponding body has been elaborated.
@item
@emph{Restrictions on instantiations}
-A generic unit can only be instantiated if the body of the generic
-unit has been elaborated. Again, the rules for elaboration given above
-guarantee that the spec of the generic unit has been elaborated
-before the instantiation, but not the body. If this rule is
-violated, then the exception @code{Program_Error} is raised.
+A generic unit can be instantiated by elaboration code only when the
+corresponding body has been elaborated.
+
+@item
+@emph{Restrictions on task activation}
+
+A task can be activated by elaboration code only when the body of the
+associated task type has been elaborated.
@end itemize
-The idea is that if the body has been elaborated, then any variables
-it references must have been elaborated; by checking for the body being
-elaborated we guarantee that none of its references causes any
-trouble. As we noted above, this is a little too restrictive, because a
-subprogram that has no non-local references in its body may in fact be safe
-to call. However, it really would be unsafe to rely on this, because
-it would mean that the caller was aware of details of the implementation
-in the body. This goes against the basic tenets of Ada.
-
-A plausible implementation can be described as follows.
-A Boolean variable is associated with each subprogram
-and each generic unit. This variable is initialized to False, and is set to
-True at the point body is elaborated. Every call or instantiation checks the
-variable, and raises @code{Program_Error} if the variable is False.
-
-Note that one might think that it would be good enough to have one Boolean
-variable for each package, but that would not deal with cases of trying
-to call a body in the same package as the call
-that has not been elaborated yet.
-Of course a compiler may be able to do enough analysis to optimize away
-some of the Boolean variables as unnecessary, and GNAT indeed
-does such optimizations, but still the easiest conceptual model is to
-think of there being one variable per subprogram.
-
-@node Controlling the Elaboration Order,Controlling Elaboration in GNAT - Internal Calls,Checking the Elaboration Order,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id4}@anchor{232}@anchor{gnat_ugn/elaboration_order_handling_in_gnat controlling-the-elaboration-order}@anchor{233}
-@section Controlling the Elaboration Order
-
-
-In the previous section we discussed the rules in Ada which ensure
-that @code{Program_Error} is raised if an incorrect elaboration order is
-chosen. This prevents erroneous executions, but we need mechanisms to
-specify a correct execution and avoid the exception altogether.
-To achieve this, Ada provides a number of features for controlling
-the order of elaboration. We discuss these features in this section.
-
-First, there are several ways of indicating to the compiler that a given
-unit has no elaboration problems:
+The restrictions above can be summarized by the following rule:
+
+@emph{If a target has a body, then this body must be elaborated prior to the
+execution of the scenario that invokes, instantiates, or activates the
+target.}
+
+@item
+@emph{Elaboration control}
+
+Pragmas are provided for the programmer to specify the desired elaboration
+order.
+@end itemize
+
+@node Controlling the Elaboration Order in Ada,Controlling the Elaboration Order in GNAT,Checking the Elaboration Order,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat controlling-the-elaboration-order-in-ada}@anchor{234}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id5}@anchor{235}
+@section Controlling the Elaboration Order in Ada
+
+
+Ada provides several idioms and pragmas to aid the programmer with specifying
+the desired elaboration order and avoiding ABE problems altogether.
@itemize *
@item
-@emph{packages that do not require a body}
+@emph{Packages without a body}
-A library package that does not require a body does not permit
-a body (this rule was introduced in Ada 95).
-Thus if we have a such a package, as in:
+A library package which does not require a completing body does not suffer
+from ABE problems.
@example
-package Definitions is
+package Pack is
generic
- type m is new integer;
- package Subp is
- type a is array (1 .. 10) of m;
- type b is array (1 .. 20) of m;
- end Subp;
-end Definitions;
+ type Element is private;
+ package Containers is
+ type Element_Array is array (1 .. 10) of Element;
+ end Containers;
+end Pack;
@end example
-A package that @emph{with}s @code{Definitions} may safely instantiate
-@code{Definitions.Subp} because the compiler can determine that there
-definitely is no package body to worry about in this case
+In the example above, package @code{Pack} does not require a body because it
+does not contain any constructs which require completion in a body. As a
+result, generic @code{Pack.Containers} can be instantiated without encountering
+any ABE problems.
@end itemize
@geindex pragma Pure
@@ -27339,12 +27431,8 @@ definitely is no package body to worry about in this case
@item
@emph{pragma Pure}
-This pragma places sufficient restrictions on a unit to guarantee that
-no call to any subprogram in the unit can result in an
-elaboration problem. This means that the compiler does not need
-to worry about the point of elaboration of such units, and in
-particular, does not need to check any calls to any subprograms
-in this unit.
+Pragma @code{Pure} places sufficient restrictions on a unit to guarantee that no
+scenario within the unit can result in an ABE problem.
@end itemize
@geindex pragma Preelaborate
@@ -27355,10 +27443,8 @@ in this unit.
@item
@emph{pragma Preelaborate}
-This pragma places slightly less stringent restrictions on a unit than
-does pragma Pure,
-but these restrictions are still sufficient to ensure that there
-are no elaboration problems with any calls to the unit.
+Pragma @code{Preelaborate} is slightly less restrictive than pragma @code{Pure},
+but still strong enough to prevent ABE problems within a unit.
@end itemize
@geindex pragma Elaborate_Body
@@ -27369,1509 +27455,1509 @@ are no elaboration problems with any calls to the unit.
@item
@emph{pragma Elaborate_Body}
-This pragma requires that the body of a unit be elaborated immediately
-after its spec. Suppose a unit @code{A} has such a pragma,
-and unit @code{B} does
-a @emph{with} of unit @code{A}. Recall that the standard rules require
-the spec of unit @code{A}
-to be elaborated before the @emph{with}ing unit; given the pragma in
-@code{A}, we also know that the body of @code{A}
-will be elaborated before @code{B}, so
-that calls to @code{A} are safe and do not need a check.
-
-Note that, unlike pragma @code{Pure} and pragma @code{Preelaborate},
-the use of @code{Elaborate_Body} does not guarantee that the program is
-free of elaboration problems, because it may not be possible
-to satisfy the requested elaboration order.
-Let's go back to the example with @code{Unit_1} and @code{Unit_2}.
-If a programmer marks @code{Unit_1} as @code{Elaborate_Body},
-and not @code{Unit_2,} then the order of
-elaboration will be:
-
-@example
-Spec of Unit_2
-Spec of Unit_1
-Body of Unit_1
-Body of Unit_2
-@end example
-
-Now that means that the call to @code{Func_1} in @code{Unit_2}
-need not be checked,
-it must be safe. But the call to @code{Func_2} in
-@code{Unit_1} may still fail if
-@code{Expression_1} is equal to 1,
-and the programmer must still take
-responsibility for this not being the case.
-
-If all units carry a pragma @code{Elaborate_Body}, then all problems are
-eliminated, except for calls entirely within a body, which are
-in any case fully under programmer control. However, using the pragma
-everywhere is not always possible.
-In particular, for our @code{Unit_1}/@cite{Unit_2} example, if
-we marked both of them as having pragma @code{Elaborate_Body}, then
-clearly there would be no possible elaboration order.
+Pragma @code{Elaborate_Body} requires that the body of a unit is elaborated
+immediately after its spec. This restriction guarantees that no client
+scenario can execute a server target before the target body has been
+elaborated because the spec and body are effectively "glued" together.
+
+@example
+package Server is
+ pragma Elaborate_Body;
+
+ function Func return Integer;
+end Server;
+@end example
+
+@example
+package body Server is
+ function Func return Integer is
+ begin
+ ...
+ end Func;
+end Server;
+@end example
+
+@example
+with Server;
+package Client is
+ Val : constant Integer := Server.Func;
+end Client;
+@end example
+
+In the example above, pragma @code{Elaborate_Body} guarantees the following
+elaboration order:
+
+@example
+spec of Server
+body of Server
+spec of Client
+@end example
+
+because the spec of @code{Server} must be elaborated prior to @code{Client} by
+virtue of the @emph{with} clause, and in addition the body of @code{Server} must be
+elaborated immediately after the spec of @code{Server}.
+
+Removing pragma @code{Elaborate_Body} could result in the following incorrect
+elaboration order:
+
+@example
+spec of Server
+spec of Client
+body of Server
+@end example
+
+where @code{Client} invokes @code{Server.Func}, but the body of @code{Server.Func} has
+not been elaborated yet.
@end itemize
-The above pragmas allow a server to guarantee safe use by clients, and
-clearly this is the preferable approach. Consequently a good rule
-is to mark units as @code{Pure} or @code{Preelaborate} if possible,
-and if this is not possible,
-mark them as @code{Elaborate_Body} if possible.
-As we have seen, there are situations where neither of these
-three pragmas can be used.
-So we also provide methods for clients to control the
-order of elaboration of the servers on which they depend:
+The pragmas outlined above allow a server unit to guarantee safe elaboration
+use by client units. Thus it is a good rule to mark units as @code{Pure} or
+@code{Preelaborate}, and if this is not possible, mark them as @code{Elaborate_Body}.
+
+There are however situations where @code{Pure}, @code{Preelaborate}, and
+@code{Elaborate_Body} are not applicable. Ada provides another set of pragmas for
+use by client units to help ensure the elaboration safety of server units they
+depend on.
-@geindex pragma Elaborate
+@geindex pragma Elaborate (Unit)
@itemize *
@item
-@emph{pragma Elaborate (unit)}
+@emph{pragma Elaborate (Unit)}
-This pragma is placed in the context clause, after a @emph{with} clause,
-and it requires that the body of the named unit be elaborated before
-the unit in which the pragma occurs. The idea is to use this pragma
-if the current unit calls at elaboration time, directly or indirectly,
-some subprogram in the named unit.
+Pragma @code{Elaborate} can be placed in the context clauses of a unit, after a
+@emph{with} clause. It guarantees that both the spec and body of its argument will
+be elaborated prior to the unit with the pragma. Note that other unrelated
+units may be elaborated in between the spec and the body.
+
+@example
+package Server is
+ function Func return Integer;
+end Server;
+@end example
+
+@example
+package body Server is
+ function Func return Integer is
+ begin
+ ...
+ end Func;
+end Server;
+@end example
+
+@example
+with Server;
+pragma Elaborate (Server);
+package Client is
+ Val : constant Integer := Server.Func;
+end Client;
+@end example
+
+In the example above, pragma @code{Elaborate} guarantees the following
+elaboration order:
+
+@example
+spec of Server
+body of Server
+spec of Client
+@end example
+
+Removing pragma @code{Elaborate} could result in the following incorrect
+elaboration order:
+
+@example
+spec of Server
+spec of Client
+body of Server
+@end example
+
+where @code{Client} invokes @code{Server.Func}, but the body of @code{Server.Func}
+has not been elaborated yet.
@end itemize
-@geindex pragma Elaborate_All
+@geindex pragma Elaborate_All (Unit)
@itemize *
@item
-@emph{pragma Elaborate_All (unit)}
+@emph{pragma Elaborate_All (Unit)}
-This is a stronger version of the Elaborate pragma. Consider the
-following example:
+Pragma @code{Elaborate_All} is placed in the context clauses of a unit, after
+a @emph{with} clause. It guarantees that both the spec and body of its argument
+will be elaborated prior to the unit with the pragma, as well as all units
+@emph{with}ed by the spec and body of the argument, recursively. Note that other
+unrelated units may be elaborated in between the spec and the body.
@example
-Unit A |withs| unit B and calls B.Func in elab code
-Unit B |withs| unit C, and B.Func calls C.Func
+package Math is
+ function Factorial (Val : Natural) return Natural;
+end Math;
@end example
-Now if we put a pragma @code{Elaborate (B)}
-in unit @code{A}, this ensures that the
-body of @code{B} is elaborated before the call, but not the
-body of @code{C}, so
-the call to @code{C.Func} could still cause @code{Program_Error} to
-be raised.
+@example
+package body Math is
+ function Factorial (Val : Natural) return Natural is
+ begin
+ ...;
+ end Factorial;
+end Math;
+@end example
-The effect of a pragma @code{Elaborate_All} is stronger, it requires
-not only that the body of the named unit be elaborated before the
-unit doing the @emph{with}, but also the bodies of all units that the
-named unit uses, following @emph{with} links transitively. For example,
-if we put a pragma @code{Elaborate_All (B)} in unit @code{A},
-then it requires not only that the body of @code{B} be elaborated before @code{A},
-but also the body of @code{C}, because @code{B} @emph{with}s @code{C}.
-@end itemize
+@example
+package Computer is
+ type Operation_Kind is (None, Op_Factorial);
+
+ function Compute
+ (Val : Natural;
+ Op : Operation_Kind) return Natural;
+end Computer;
+@end example
+
+@example
+with Math;
+package body Computer is
+ function Compute
+ (Val : Natural;
+ Op : Operation_Kind) return Natural
+ is
+ if Op = Op_Factorial then
+ return Math.Factorial (Val);
+ end if;
+
+ return 0;
+ end Compute;
+end Computer;
+@end example
-We are now in a position to give a usage rule in Ada for avoiding
-elaboration problems, at least if dynamic dispatching and access to
-subprogram values are not used. We will handle these cases separately
-later.
+@example
+with Computer;
+pragma Elaborate_All (Computer);
+package Client is
+ Val : constant Natural :=
+ Computer.Compute (123, Computer.Op_Factorial);
+end Client;
+@end example
-The rule is simple:
+In the example above, pragma @code{Elaborate_All} can result in the following
+elaboration order:
-@emph{If a unit has elaboration code that can directly or
-indirectly make a call to a subprogram in a |withed| unit, or instantiate
-a generic package in a |withed| unit,
-then if the |withed| unit does not have
-pragma `@w{`}Pure`@w{`} or `@w{`}Preelaborate`@w{`}, then the client should have
-a pragma `@w{`}Elaborate_All`@w{`}for the |withed| unit.*}
+@example
+spec of Math
+body of Math
+spec of Computer
+body of Computer
+spec of Client
+@end example
-By following this rule a client is
-assured that calls can be made without risk of an exception.
+Note that there are several allowable suborders for the specs and bodies of
+@code{Math} and @code{Computer}, but the point is that these specs and bodies will
+be elaborated prior to @code{Client}.
-For generic subprogram instantiations, the rule can be relaxed to
-require only a pragma @code{Elaborate} since elaborating the body
-of a subprogram cannot cause any transitive elaboration (we are
-not calling the subprogram in this case, just elaborating its
-declaration).
+Removing pragma @code{Elaborate_All} could result in the following incorrect
+elaboration order
-If this rule is not followed, then a program may be in one of four
-states:
+@example
+spec of Math
+spec of Computer
+body of Computer
+spec of Client
+body of Math
+@end example
+
+where @code{Client} invokes @code{Computer.Compute}, which in turn invokes
+@code{Math.Factorial}, but the body of @code{Math.Factorial} has not been
+elaborated yet.
+@end itemize
+
+All pragmas shown above can be summarized by the following rule:
+
+@emph{If a client unit elaborates a server target directly or indirectly, then if
+the server unit requires a body and does not have pragma Pure, Preelaborate,
+or Elaborate_Body, then the client unit should have pragma Elaborate or
+Elaborate_All for the server unit.}
+
+If the rule outlined above is not followed, then a program may fall in one of
+the following states:
@itemize *
@item
-@emph{No order exists}
+@emph{No elaboration order exists}
+
+In this case a compiler must diagnose the situation, and refuse to build an
+executable program.
+
+@item
+@emph{One or more incorrect elaboration orders exist}
-No order of elaboration exists which follows the rules, taking into
-account any @code{Elaborate}, @code{Elaborate_All},
-or @code{Elaborate_Body} pragmas. In
-this case, an Ada compiler must diagnose the situation at bind
-time, and refuse to build an executable program.
+In this case a compiler can build an executable program, but
+@code{Program_Error} will be raised when the program is run.
@item
-@emph{One or more orders exist, all incorrect}
+@emph{Several elaboration orders exist, some correct, some incorrect}
-One or more acceptable elaboration orders exist, and all of them
-generate an elaboration order problem. In this case, the binder
-can build an executable program, but @code{Program_Error} will be raised
-when the program is run.
+In this case the programmer has not controlled the elaboration order. As a
+result, a compiler may or may not pick one of the correct orders, and the
+program may or may not raise @code{Program_Error} when it is run. This is the
+worst possible state because the program may fail on another compiler, or
+even another version of the same compiler.
@item
-@emph{Several orders exist, some right, some incorrect}
+@emph{One or more correct orders exist}
+
+In this case a compiler can build an executable program, and the program is
+run successfully. This state may be guaranteed by following the outlined
+rules, or may be the result of good program architecture.
+@end itemize
+
+Note that one additional advantage of using @code{Elaborate} and @code{Elaborate_All}
+is that the program continues to stay in the last state (one or more correct
+orders exist) even if maintenance changes the bodies of targets.
+
+@node Controlling the Elaboration Order in GNAT,Common Elaboration-model Traits,Controlling the Elaboration Order in Ada,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat id6}@anchor{236}@anchor{gnat_ugn/elaboration_order_handling_in_gnat controlling-the-elaboration-order-in-gnat}@anchor{237}
+@section Controlling the Elaboration Order in GNAT
+
+
+In addition to Ada semantics and rules synthesized from them, GNAT offers
+three elaboration models to aid the programmer with specifying the correct
+elaboration order and to diagnose elaboration problems.
+
+@geindex Dynamic elaboration model
+
+
+@itemize *
+
+@item
+@emph{Dynamic elaboration model}
+
+This is the most permissive of the three elaboration models. When the
+dynamic model is in effect, GNAT assumes that all code within all units in
+a partition is elaboration code. GNAT performs very few diagnostics and
+generates run-time checks to verify the elaboration order of a program. This
+behavior is identical to that specified by the Ada Reference Manual. The
+dynamic model is enabled with compiler switch @code{-gnatE}.
+@end itemize
+
+@geindex Static elaboration model
-One or more acceptable elaboration orders exists, and some of them
-work, and some do not. The programmer has not controlled
-the order of elaboration, so the binder may or may not pick one of
-the correct orders, and the program may or may not raise an
-exception when it is run. This is the worst case, because it means
-that the program may fail when moved to another compiler, or even
-another version of the same compiler.
+
+@itemize *
@item
-@emph{One or more orders exists, all correct}
+@emph{Static elaboration model}
-One ore more acceptable elaboration orders exist, and all of them
-work. In this case the program runs successfully. This state of
-affairs can be guaranteed by following the rule we gave above, but
-may be true even if the rule is not followed.
+This is the middle ground of the three models. When the static model is in
+effect, GNAT performs extensive diagnostics on a unit-by-unit basis for all
+scenarios that elaborate or execute internal targets. GNAT also generates
+run-time checks for all external targets and for all scenarios that may
+exhibit ABE problems. Finally, GNAT installs implicit @code{Elaborate} and
+@code{Elaborate_All} pragmas for server units based on the dependencies of
+client units. The static model is the default model in GNAT.
@end itemize
-Note that one additional advantage of following our rules on the use
-of @code{Elaborate} and @code{Elaborate_All}
-is that the program continues to stay in the ideal (all orders OK) state
-even if maintenance
-changes some bodies of some units. Conversely, if a program that does
-not follow this rule happens to be safe at some point, this state of affairs
-may deteriorate silently as a result of maintenance changes.
+@geindex SPARK elaboration model
-You may have noticed that the above discussion did not mention
-the use of @code{Elaborate_Body}. This was a deliberate omission. If you
-@emph{with} an @code{Elaborate_Body} unit, it still may be the case that
-code in the body makes calls to some other unit, so it is still necessary
-to use @code{Elaborate_All} on such units.
-@node Controlling Elaboration in GNAT - Internal Calls,Controlling Elaboration in GNAT - External Calls,Controlling the Elaboration Order,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id5}@anchor{234}@anchor{gnat_ugn/elaboration_order_handling_in_gnat controlling-elaboration-in-gnat-internal-calls}@anchor{235}
-@section Controlling Elaboration in GNAT - Internal Calls
+@itemize *
+@item
+@emph{SPARK elaboration model}
-In the case of internal calls, i.e., calls within a single package, the
-programmer has full control over the order of elaboration, and it is up
-to the programmer to elaborate declarations in an appropriate order. For
-example writing:
+This is the most conservative of the three models and enforces the SPARK
+rules of elaboration as defined in the SPARK Reference Manual, section 7.7.
+The SPARK model is in effect only when a scenario and a target reside in a
+region subject to SPARK_Mode On, otherwise the dynamic or static model is in
+effect.
+@end itemize
+
+@node Common Elaboration-model Traits,Dynamic Elaboration Model in GNAT,Controlling the Elaboration Order in GNAT,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat common-elaboration-model-traits}@anchor{238}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id7}@anchor{239}
+@section Common Elaboration-model Traits
+
+
+All three GNAT models are able to detect elaboration problems related to
+dispatching calls and a particular kind of ABE referred to as @emph{guaranteed ABE}.
+
+
+@itemize *
+
+@item
+@emph{Dispatching calls}
+
+GNAT installs run-time checks for each primitive subprogram of each tagged
+type defined in a partition on the assumption that a dispatching call
+invoked at elaboration time will execute one of these primitives. As a
+result, a dispatching call that executes a primitive whose body has not
+been elaborated yet will raise exception @code{Program_Error} at run time. The
+checks can be suppressed using pragma @code{Suppress (Elaboration_Check)}.
+
+@item
+@emph{Guaranteed ABE}
+
+A guaranteed ABE arises when the body of a target is not elaborated early
+enough, and causes all scenarios that directly execute the target to fail.
@example
-function One return Float;
+package body Guaranteed_ABE is
+ function ABE return Integer;
-Q : Float := One;
+ Val : constant Integer := ABE;
-function One return Float is
-begin
- return 1.0;
-end One;
+ function ABE return Integer is
+ begin
+ ...
+ end ABE;
+end Guaranteed_ABE;
@end example
-will obviously raise @code{Program_Error} at run time, because function
-One will be called before its body is elaborated. In this case GNAT will
-generate a warning that the call will raise @code{Program_Error}:
+In the example above, the elaboration of @code{Guaranteed_ABE}'s body elaborates
+the declaration of @code{Val}. This invokes function @code{ABE}, however the body
+of @code{ABE} has not been elaborated yet. GNAT emits similar diagnostics in all
+three models:
@example
- 1. procedure y is
- 2. function One return Float;
- 3.
- 4. Q : Float := One;
- |
- >>> warning: cannot call "One" before body is elaborated
- >>> warning: Program_Error will be raised at run time
+1. package body Guaranteed_ABE is
+2. function ABE return Integer;
+3.
+4. Val : constant Integer := ABE;
+ |
+ >>> warning: cannot call "ABE" before body seen
+ >>> warning: Program_Error will be raised at run time
- 5.
- 6. function One return Float is
- 7. begin
- 8. return 1.0;
- 9. end One;
-10.
-11. begin
-12. null;
-13. end;
+5.
+6. function ABE return Integer is
+7. begin
+8. ...
+9. end ABE;
+10. end Guaranteed_ABE;
@end example
+@end itemize
+
+Note that GNAT emits warnings rather than hard errors whenever it encounters an
+elaboration problem. This is because the elaboration model in effect may be too
+conservative, or a particular scenario may not be elaborated or executed due to
+data and control flow. The warnings can be suppressed with compiler switch
+@code{-gnatws}.
+
+@node Dynamic Elaboration Model in GNAT,Static Elaboration Model in GNAT,Common Elaboration-model Traits,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat dynamic-elaboration-model-in-gnat}@anchor{23a}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id8}@anchor{23b}
+@section Dynamic Elaboration Model in GNAT
-Note that in this particular case, it is likely that the call is safe, because
-the function @code{One} does not access any global variables.
-Nevertheless in Ada, we do not want the validity of the check to depend on
-the contents of the body (think about the separate compilation case), so this
-is still wrong, as we discussed in the previous sections.
-The error is easily corrected by rearranging the declarations so that the
-body of @code{One} appears before the declaration containing the call
-(note that in Ada 95 as well as later versions of the Ada standard,
-declarations can appear in any order, so there is no restriction that
-would prevent this reordering, and if we write:
+The dynamic model assumes that all code within all units in a partition is
+elaboration code. As a result, run-time checks are installed for each scenario
+regardless of whether the target is internal or external. The checks can be
+suppressed using pragma @code{Suppress (Elaboration_Check)}. This behavior is
+identical to that specified by the Ada Reference Manual. The following example
+showcases run-time checks installed by GNAT to verify the elaboration state of
+package @code{Dynamic_Model}.
@example
-function One return Float;
+with Server;
+package body Dynamic_Model is
+ procedure API is
+ begin
+ ...
+ end API;
+
+ <check that the body of Server.Gen is elaborated>
+ package Inst is new Server.Gen;
+
+ T : Server.Task_Type;
-function One return Float is
begin
- return 1.0;
-end One;
+ <check that the body of Server.Task_Type is elaborated>
-Q : Float := One;
+ <check that the body of Server.Proc is elaborated>
+ Server.Proc;
+end Dynamic_Model;
@end example
-then all is well, no warning is generated, and no
-@code{Program_Error} exception
-will be raised.
-Things are more complicated when a chain of subprograms is executed:
+The checks verify that the body of a target has been successfully elaborated
+before a scenario activates, calls, or instantiates a target.
+
+Note that no scenario within package @code{Dynamic_Model} calls procedure @code{API}.
+In fact, procedure @code{API} may not be invoked by elaboration code within the
+partition, however the dynamic model assumes that this can happen.
+
+The dynamic model emits very few diagnostics, but can make suggestions on
+missing @code{Elaborate} and @code{Elaborate_All} pragmas for library-level
+scenarios. This information is available when compiler switch @code{-gnatel}
+is in effect.
@example
-function A return Integer;
-function B return Integer;
-function C return Integer;
+1. with Server;
+2. package body Dynamic_Model is
+3. Val : constant Integer := Server.Func;
+ |
+ >>> info: call to "Func" during elaboration
+ >>> info: missing pragma "Elaborate_All" for unit "Server"
+
+4. end Dynamic_Model;
+@end example
+
+@node Static Elaboration Model in GNAT,SPARK Elaboration Model in GNAT,Dynamic Elaboration Model in GNAT,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat static-elaboration-model-in-gnat}@anchor{23c}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id9}@anchor{23d}
+@section Static Elaboration Model in GNAT
+
-function B return Integer is begin return A; end;
-function C return Integer is begin return B; end;
+In contrast to the dynamic model, the static model is more precise in its
+analysis of elaboration code. The model makes a clear distinction between
+internal and external targets, and resorts to different diagnostics and
+run-time checks based on the nature of the target.
-X : Integer := C;
-function A return Integer is begin return 1; end;
+@itemize *
+
+@item
+@emph{Internal targets}
+
+The static model performs extensive diagnostics on scenarios which elaborate
+or execute internal targets. The warnings resulting from these diagnostics
+are enabled by default, but can be suppressed using compiler switch
+@code{-gnatws}.
+
+@example
+ 1. package body Static_Model is
+ 2. generic
+ 3. with function Func return Integer;
+ 4. package Gen is
+ 5. Val : constant Integer := Func;
+ 6. end Gen;
+ 7.
+ 8. function ABE return Integer;
+ 9.
+10. function Cause_ABE return Boolean is
+11. package Inst is new Gen (ABE);
+ |
+ >>> warning: in instantiation at line 5
+ >>> warning: cannot call "ABE" before body seen
+ >>> warning: Program_Error may be raised at run time
+ >>> warning: body of unit "Static_Model" elaborated
+ >>> warning: function "Cause_ABE" called at line 16
+ >>> warning: function "ABE" called at line 5, instance at line 11
+
+12. begin
+13. ...
+14. end Cause_ABE;
+15.
+16. Val : constant Boolean := Cause_ABE;
+17.
+18. function ABE return Integer is
+19. begin
+20. ...
+21. end ABE;
+22. end Static_Model;
+@end example
+
+The example above illustrates an ABE problem within package @code{Static_Model},
+which is hidden by several layers of indirection. The elaboration of package
+body @code{Static_Model} elaborates the declaration of @code{Val}. This invokes
+function @code{Cause_ABE}, which instantiates generic unit @code{Gen} as @code{Inst}.
+The elaboration of @code{Inst} invokes function @code{ABE}, however the body of
+@code{ABE} has not been elaborated yet.
+
+@item
+@emph{External targets}
+
+The static model installs run-time checks to verify the elaboration status
+of server targets only when the scenario that elaborates or executes that
+target is part of the elaboration code of the client unit. The checks can be
+suppressed using pragma @code{Suppress (Elaboration_Check)}.
+
+@example
+with Server;
+package body Static_Model is
+ generic
+ with function Func return Integer;
+ package Gen is
+ Val : constant Integer := Func;
+ end Gen;
+
+ function Call_Func return Boolean is
+ <check that the body of Server.Func is elaborated>
+ package Inst is new Gen (Server.Func);
+ begin
+ ...
+ end Call_Func;
+
+ Val : constant Boolean := Call_Func;
+end Static_Model;
@end example
-Now the call to @code{C}
-at elaboration time in the declaration of @code{X} is correct, because
-the body of @code{C} is already elaborated,
-and the call to @code{B} within the body of
-@code{C} is correct, but the call
-to @code{A} within the body of @code{B} is incorrect, because the body
-of @code{A} has not been elaborated, so @code{Program_Error}
-will be raised on the call to @code{A}.
-In this case GNAT will generate a
-warning that @code{Program_Error} may be
-raised at the point of the call. Let's look at the warning:
+In the example above, the elaboration of package body @code{Static_Model}
+elaborates the declaration of @code{Val}. This invokes function @code{Call_Func},
+which instantiates generic unit @code{Gen} as @code{Inst}. The elaboration of
+@code{Inst} invokes function @code{Server.Func}. Since @code{Server.Func} is an
+external target, GNAT installs a run-time check to verify that its body has
+been elaborated.
-@example
- 1. procedure x is
- 2. function A return Integer;
- 3. function B return Integer;
- 4. function C return Integer;
- 5.
- 6. function B return Integer is begin return A; end;
- |
- >>> warning: call to "A" before body is elaborated may
- raise Program_Error
- >>> warning: "B" called at line 7
- >>> warning: "C" called at line 9
+In addition to checks, the static model installs implicit @code{Elaborate} and
+@code{Elaborate_All} pragmas to guarantee safe elaboration use of server units.
+This information is available when compiler switch @code{-gnatel} is in
+effect.
- 7. function C return Integer is begin return B; end;
+@example
+ 1. with Server;
+ 2. package body Static_Model is
+ 3. generic
+ 4. with function Func return Integer;
+ 5. package Gen is
+ 6. Val : constant Integer := Func;
+ 7. end Gen;
8.
- 9. X : Integer := C;
-10.
-11. function A return Integer is begin return 1; end;
-12.
-13. begin
-14. null;
-15. end;
-@end example
+ 9. function Call_Func return Boolean is
+10. package Inst is new Gen (Server.Func);
+ |
+ >>> info: instantiation of "Gen" during elaboration
+ >>> info: in instantiation at line 6
+ >>> info: call to "Func" during elaboration
+ >>> info: in instantiation at line 6
+ >>> info: implicit pragma "Elaborate_All" generated for unit "Server"
+ >>> info: body of unit "Static_Model" elaborated
+ >>> info: function "Call_Func" called at line 15
+ >>> info: function "Func" called at line 6, instance at line 10
+
+11. begin
+12. ...
+13. end Call_Func;
+14.
+15. Val : constant Boolean := Call_Func;
+ |
+ >>> info: call to "Call_Func" during elaboration
+
+16. end Static_Model;
+@end example
+
+In the example above, the elaboration of package body @code{Static_Model}
+elaborates the declaration of @code{Val}. This invokes function @code{Call_Func},
+which instantiates generic unit @code{Gen} as @code{Inst}. The elaboration of
+@code{Inst} invokes function @code{Server.Func}. Since @code{Server.Func} is an
+external target, GNAT installs an implicit @code{Elaborate_All} pragma for unit
+@code{Server}. The pragma guarantees that both the spec and body of @code{Server},
+along with any additional dependencies that @code{Server} may require, are
+elaborated prior to the body of @code{Static_Model}.
+@end itemize
+
+@node SPARK Elaboration Model in GNAT,Mixing Elaboration Models,Static Elaboration Model in GNAT,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat id10}@anchor{23e}@anchor{gnat_ugn/elaboration_order_handling_in_gnat spark-elaboration-model-in-gnat}@anchor{23f}
+@section SPARK Elaboration Model in GNAT
+
-Note that the message here says 'may raise', instead of the direct case,
-where the message says 'will be raised'. That's because whether
-@code{A} is
-actually called depends in general on run-time flow of control.
-For example, if the body of @code{B} said
+The SPARK model is identical to the static model in its handling of internal
+targets. The SPARK model, however, requires explicit @code{Elaborate} or
+@code{Elaborate_All} pragmas to be present in the program when a target is
+external, and compiler switch @code{-gnatd.v} is in effect.
@example
-function B return Integer is
-begin
- if some-condition-depending-on-input-data then
- return A;
- else
- return 1;
- end if;
-end B;
-@end example
-
-then we could not know until run time whether the incorrect call to A would
-actually occur, so @code{Program_Error} might
-or might not be raised. It is possible for a compiler to
-do a better job of analyzing bodies, to
-determine whether or not @code{Program_Error}
-might be raised, but it certainly
-couldn't do a perfect job (that would require solving the halting problem
-and is provably impossible), and because this is a warning anyway, it does
-not seem worth the effort to do the analysis. Cases in which it
-would be relevant are rare.
-
-In practice, warnings of either of the forms given
-above will usually correspond to
-real errors, and should be examined carefully and eliminated.
-In the rare case where a warning is bogus, it can be suppressed by any of
-the following methods:
+1. with Server;
+2. package body SPARK_Model with SPARK_Mode is
+3. Val : constant Integer := Server.Func;
+ |
+ >>> call to "Func" during elaboration in SPARK
+ >>> unit "SPARK_Model" requires pragma "Elaborate_All" for "Server"
+ >>> body of unit "SPARK_Model" elaborated
+ >>> function "Func" called at line 3
+
+4. end SPARK_Model;
+@end example
+
+@node Mixing Elaboration Models,Elaboration Circularities,SPARK Elaboration Model in GNAT,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat mixing-elaboration-models}@anchor{240}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id11}@anchor{241}
+@section Mixing Elaboration Models
+
+
+It is possible to mix units compiled with a different elaboration model,
+however the following rules must be observed:
@itemize *
@item
-Compile with the @code{-gnatws} switch set
+A client unit compiled with the dynamic model can only @emph{with} a server unit
+that meets at least one of the following criteria:
+
+
+@itemize -
+
+@item
+The server unit is compiled with the dynamic model.
+
+@item
+The server unit is a GNAT implementation unit from the Ada, GNAT,
+Interfaces, or System hierarchies.
@item
-Suppress @code{Elaboration_Check} for the called subprogram
+The server unit has pragma @code{Pure} or @code{Preelaborate}.
@item
-Use pragma @code{Warnings_Off} to turn warnings off for the call
+The client unit has an explicit @code{Elaborate_All} pragma for the server
+unit.
+@end itemize
@end itemize
-For the internal elaboration check case,
-GNAT by default generates the
-necessary run-time checks to ensure
-that @code{Program_Error} is raised if any
-call fails an elaboration check. Of course this can only happen if a
-warning has been issued as described above. The use of pragma
-@code{Suppress (Elaboration_Check)} may (but is not guaranteed to) suppress
-some of these checks, meaning that it may be possible (but is not
-guaranteed) for a program to be able to call a subprogram whose body
-is not yet elaborated, without raising a @code{Program_Error} exception.
+These rules ensure that elaboration checks are not omitted. If the rules are
+violated, the binder emits a warning:
+
+@example
+warning: "x.ads" has dynamic elaboration checks and with's
+warning: "y.ads" which has static elaboration checks
+@end example
+
+The warnings can be suppressed by binder switch @code{-ws}.
-@node Controlling Elaboration in GNAT - External Calls,Default Behavior in GNAT - Ensuring Safety,Controlling Elaboration in GNAT - Internal Calls,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id6}@anchor{236}@anchor{gnat_ugn/elaboration_order_handling_in_gnat controlling-elaboration-in-gnat-external-calls}@anchor{237}
-@section Controlling Elaboration in GNAT - External Calls
+@node Elaboration Circularities,Resolving Elaboration Circularities,Mixing Elaboration Models,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat id12}@anchor{242}@anchor{gnat_ugn/elaboration_order_handling_in_gnat elaboration-circularities}@anchor{243}
+@section Elaboration Circularities
-The previous section discussed the case in which the execution of a
-particular thread of elaboration code occurred entirely within a
-single unit. This is the easy case to handle, because a programmer
-has direct and total control over the order of elaboration, and
-furthermore, checks need only be generated in cases which are rare
-and which the compiler can easily detect.
-The situation is more complex when separate compilation is taken into account.
-Consider the following:
+If the binder cannot find an acceptable elaboration order, it outputs detailed
+diagnostics describing an @strong{elaboration circularity}.
@example
-package Math is
- function Sqrt (Arg : Float) return Float;
-end Math;
+package Server is
+ function Func return Integer;
+end Server;
+@end example
-package body Math is
- function Sqrt (Arg : Float) return Float is
+@example
+with Client;
+package body Server is
+ function Func return Integer is
begin
- ...
- end Sqrt;
-end Math;
+ ...
+ end Func;
+end Server;
+@end example
-with Math;
-package Stuff is
- X : Float := Math.Sqrt (0.5);
-end Stuff;
+@example
+with Server;
+package Client is
+ Val : constant Integer := Server.Func;
+end Client;
+@end example
-with Stuff;
-procedure Main is
-begin
- ...
-end Main;
+@example
+with Client;
+procedure Main is begin null; end Main;
+@end example
+
+@example
+error: elaboration circularity detected
+info: "server (body)" must be elaborated before "client (spec)"
+info: reason: implicit Elaborate_All in unit "client (spec)"
+info: recompile "client (spec)" with -gnatel for full details
+info: "server (body)"
+info: must be elaborated along with its spec:
+info: "server (spec)"
+info: which is withed by:
+info: "client (spec)"
+info: "client (spec)" must be elaborated before "server (body)"
+info: reason: with clause
@end example
-where @code{Main} is the main program. When this program is executed, the
-elaboration code must first be executed, and one of the jobs of the
-binder is to determine the order in which the units of a program are
-to be elaborated. In this case we have four units: the spec and body
-of @code{Math},
-the spec of @code{Stuff} and the body of @code{Main}).
-In what order should the four separate sections of elaboration code
-be executed?
+In the example above, @code{Client} must be elaborated prior to @code{Main} by virtue
+of a @emph{with} clause. The elaboration of @code{Client} invokes @code{Server.Func}, and
+static model generates an implicit @code{Elaborate_All} pragma for @code{Server}. The
+pragma implies that both the spec and body of @code{Server}, along with any units
+they @emph{with}, must be elaborated prior to @code{Client}. However, @code{Server}'s body
+@emph{with}s @code{Client}, implying that @code{Client} must be elaborated prior to
+@code{Server}. The end result is that @code{Client} must be elaborated prior to
+@code{Client}, and this leads to a circularity.
-There are some restrictions in the order of elaboration that the binder
-can choose. In particular, if unit U has a @emph{with}
-for a package @code{X}, then you
-are assured that the spec of @code{X}
-is elaborated before U , but you are
-not assured that the body of @code{X}
-is elaborated before U.
-This means that in the above case, the binder is allowed to choose the
-order:
+@node Resolving Elaboration Circularities,Resolving Task Issues,Elaboration Circularities,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat id13}@anchor{244}@anchor{gnat_ugn/elaboration_order_handling_in_gnat resolving-elaboration-circularities}@anchor{245}
+@section Resolving Elaboration Circularities
+
+
+When faced with an elaboration circularity, a programmer has several options
+available.
+
+
+@itemize *
+
+@item
+@emph{Fix the program}
+
+The most desirable option from the point of view of long-term maintenance
+is to rearrange the program so that the elaboration problems are avoided.
+One useful technique is to place the elaboration code into separate child
+packages. Another is to move some of the initialization code to explicitly
+invoked subprograms, where the program controls the order of initialization
+explicitly. Although this is the most desirable option, it may be impractical
+and involve too much modification, especially in the case of complex legacy
+code.
+
+@item
+@emph{Switch to more permissive elaboration model}
+
+If the compilation was performed using the static model, enable the dynamic
+model with compiler switch @code{-gnatE}. GNAT will no longer generate
+implicit @code{Elaborate} and @code{Elaborate_All} pragmas, resulting in a behavior
+identical to that specified by the Ada Reference Manual. The binder will
+generate an executable program that may or may not raise @code{Program_Error},
+and it is the programmer's responsibility to ensure that it does not raise
+@code{Program_Error}.
+
+@item
+@emph{Suppress all elaboration checks}
+
+The drawback of run-time checks is that they generate overhead at run time,
+both in space and time. If the programmer is absolutely sure that a program
+will not raise an elaboration-related @code{Program_Error}, then using the
+pragma @code{Suppress (Elaboration_Check)} globally (as a configuration pragma)
+will eliminate all run-time checks.
+
+@item
+@emph{Suppress elaboration checks selectively}
+
+If a scenario cannot possibly lead to an elaboration @code{Program_Error},
+and the binder nevertheless complains about implicit @code{Elaborate} and
+@code{Elaborate_All} pragmas that lead to elaboration circularities, it
+is possible to suppress the generation of implicit @code{Elaborate} and
+@code{Elaborate_All} pragmas, as well as run-time checks. Clearly this can
+be unsafe, and it is the responsibility of the programmer to make sure
+that the resulting program has no elaboration anomalies. Pragma
+@code{Suppress (Elaboration_Check)} can be used with different levels of
+granularity to achieve these effects.
+
+
+@itemize -
+
+@item
+@emph{Target suppression}
+
+When the pragma is placed in a declarative part, without a second argument
+naming an entity, it will suppress implicit @code{Elaborate} and
+@code{Elaborate_All} pragma generation, as well as run-time checks, on all
+targets within the region.
@example
-spec of Math
-spec of Stuff
-body of Math
-body of Main
+package Range_Suppress is
+ pragma Suppress (Elaboration_Check);
+
+ function Func return Integer;
+
+ generic
+ procedure Gen;
+
+ pragma Unsuppress (Elaboration_Check);
+
+ task type Tsk;
+end Range_Suppress;
@end example
-but that's not good, because now the call to @code{Math.Sqrt}
-that happens during
-the elaboration of the @code{Stuff}
-spec happens before the body of @code{Math.Sqrt} is
-elaborated, and hence causes @code{Program_Error} exception to be raised.
-At first glance, one might say that the binder is misbehaving, because
-obviously you want to elaborate the body of something you @emph{with} first, but
-that is not a general rule that can be followed in all cases. Consider
-
-@example
-package X is ...
-
-package Y is ...
-
-with X;
-package body Y is ...
-
-with Y;
-package body X is ...
-@end example
-
-This is a common arrangement, and, apart from the order of elaboration
-problems that might arise in connection with elaboration code, this works fine.
-A rule that says that you must first elaborate the body of anything you
-@emph{with} cannot work in this case:
-the body of @code{X} @emph{with}s @code{Y},
-which means you would have to
-elaborate the body of @code{Y} first, but that @emph{with}s @code{X},
-which means
-you have to elaborate the body of @code{X} first, but ... and we have a
-loop that cannot be broken.
-
-It is true that the binder can in many cases guess an order of elaboration
-that is unlikely to cause a @code{Program_Error}
-exception to be raised, and it tries to do so (in the
-above example of @code{Math/Stuff/Spec}, the GNAT binder will
-by default
-elaborate the body of @code{Math} right after its spec, so all will be well).
-
-However, a program that blindly relies on the binder to be helpful can
-get into trouble, as we discussed in the previous sections, so GNAT
-provides a number of facilities for assisting the programmer in
-developing programs that are robust with respect to elaboration order.
-
-@node Default Behavior in GNAT - Ensuring Safety,Treatment of Pragma Elaborate,Controlling Elaboration in GNAT - External Calls,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id7}@anchor{238}@anchor{gnat_ugn/elaboration_order_handling_in_gnat default-behavior-in-gnat-ensuring-safety}@anchor{239}
-@section Default Behavior in GNAT - Ensuring Safety
-
-
-The default behavior in GNAT ensures elaboration safety. In its
-default mode GNAT implements the
-rule we previously described as the right approach. Let's restate it:
-
-@emph{If a unit has elaboration code that can directly or indirectly make a
-call to a subprogram in a |withed| unit, or instantiate a generic
-package in a |withed| unit, then if the |withed| unit
-does not have pragma `@w{`}Pure`@w{`} or `@w{`}Preelaborate`@w{`}, then the client should have an
-`@w{`}Elaborate_All`@w{`} pragma for the |withed| unit.}
-
-@emph{In the case of instantiating a generic subprogram, it is always
-sufficient to have only an `@w{`}Elaborate`@w{`} pragma for the
-|withed| unit.}
-
-By following this rule a client is assured that calls and instantiations
-can be made without risk of an exception.
-
-In this mode GNAT traces all calls that are potentially made from
-elaboration code, and puts in any missing implicit @code{Elaborate}
-and @code{Elaborate_All} pragmas.
-The advantage of this approach is that no elaboration problems
-are possible if the binder can find an elaboration order that is
-consistent with these implicit @code{Elaborate} and
-@code{Elaborate_All} pragmas. The
-disadvantage of this approach is that no such order may exist.
-
-If the binder does not generate any diagnostics, then it means that it has
-found an elaboration order that is guaranteed to be safe. However, the binder
-may still be relying on implicitly generated @code{Elaborate} and
-@code{Elaborate_All} pragmas so portability to other compilers than GNAT is not
-guaranteed.
-
-If it is important to guarantee portability, then the compilations should
-use the @code{-gnatel}
-(info messages for elaboration pragmas) switch. This will cause info messages
-to be generated indicating the missing @code{Elaborate} and
-@code{Elaborate_All} pragmas.
-Consider the following source program:
+In the example above, a pair of Suppress/Unsuppress pragmas define a region
+of suppression within package @code{Range_Suppress}. As a result, no implicit
+@code{Elaborate} and @code{Elaborate_All} pragmas, nor any run-time checks, will
+be generated by callers of @code{Func} and instantiators of @code{Gen}. Note that
+task type @code{Tsk} is not within this region.
+
+An alternative to the region-based suppression is to use multiple
+@code{Suppress} pragmas with arguments naming specific entities for which
+elaboration checks should be suppressed:
@example
-with k;
-package j is
- m : integer := k.r;
-end;
+package Range_Suppress is
+ function Func return Integer;
+ pragma Suppress (Elaboration_Check, Func);
+
+ generic
+ procedure Gen;
+ pragma Suppress (Elaboration_Check, Gen);
+
+ task type Tsk;
+end Range_Suppress;
@end example
-where it is clear that there
-should be a pragma @code{Elaborate_All}
-for unit @code{k}. An implicit pragma will be generated, and it is
-likely that the binder will be able to honor it. However, if you want
-to port this program to some other Ada compiler than GNAT.
-it is safer to include the pragma explicitly in the source. If this
-unit is compiled with the @code{-gnatel}
-switch, then the compiler outputs an information message:
-
-@example
-1. with k;
-2. package j is
-3. m : integer := k.r;
- |
- >>> info: call to "r" may raise Program_Error
- >>> info: missing pragma Elaborate_All for "k"
-
-4. end;
-@end example
-
-and these messages can be used as a guide for supplying manually
-the missing pragmas. It is usually a bad idea to use this
-option during development. That's because it will tell you when
-you need to put in a pragma, but cannot tell you when it is time
-to take it out. So the use of pragma @code{Elaborate_All} may lead to
-unnecessary dependencies and even false circularities.
-
-This default mode is more restrictive than the Ada Reference
-Manual, and it is possible to construct programs which will compile
-using the dynamic model described there, but will run into a
-circularity using the safer static model we have described.
-
-Of course any Ada compiler must be able to operate in a mode
-consistent with the requirements of the Ada Reference Manual,
-and in particular must have the capability of implementing the
-standard dynamic model of elaboration with run-time checks.
-
-In GNAT, this standard mode can be achieved either by the use of
-the @code{-gnatE} switch on the compiler (@code{gcc} or
-@code{gnatmake}) command, or by the use of the configuration pragma:
-
-@example
-pragma Elaboration_Checks (DYNAMIC);
-@end example
-
-Either approach will cause the unit affected to be compiled using the
-standard dynamic run-time elaboration checks described in the Ada
-Reference Manual. The static model is generally preferable, since it
-is clearly safer to rely on compile and link time checks rather than
-run-time checks. However, in the case of legacy code, it may be
-difficult to meet the requirements of the static model. This
-issue is further discussed in
-@ref{23a,,What to Do If the Default Elaboration Behavior Fails}.
-
-Note that the static model provides a strict subset of the allowed
-behavior and programs of the Ada Reference Manual, so if you do
-adhere to the static model and no circularities exist,
-then you are assured that your program will
-work using the dynamic model, providing that you remove any
-pragma Elaborate statements from the source.
-
-@node Treatment of Pragma Elaborate,Elaboration Issues for Library Tasks,Default Behavior in GNAT - Ensuring Safety,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat treatment-of-pragma-elaborate}@anchor{23b}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id8}@anchor{23c}
-@section Treatment of Pragma Elaborate
-
-
-@geindex Pragma Elaborate
-
-The use of @code{pragma Elaborate}
-should generally be avoided in Ada 95 and Ada 2005 programs,
-since there is no guarantee that transitive calls
-will be properly handled. Indeed at one point, this pragma was placed
-in Annex J (Obsolescent Features), on the grounds that it is never useful.
-
-Now that's a bit restrictive. In practice, the case in which
-@code{pragma Elaborate} is useful is when the caller knows that there
-are no transitive calls, or that the called unit contains all necessary
-transitive @code{pragma Elaborate} statements, and legacy code often
-contains such uses.
-
-Strictly speaking the static mode in GNAT should ignore such pragmas,
-since there is no assurance at compile time that the necessary safety
-conditions are met. In practice, this would cause GNAT to be incompatible
-with correctly written Ada 83 code that had all necessary
-@code{pragma Elaborate} statements in place. Consequently, we made the
-decision that GNAT in its default mode will believe that if it encounters
-a @code{pragma Elaborate} then the programmer knows what they are doing,
-and it will trust that no elaboration errors can occur.
-
-The result of this decision is two-fold. First to be safe using the
-static mode, you should remove all @code{pragma Elaborate} statements.
-Second, when fixing circularities in existing code, you can selectively
-use @code{pragma Elaborate} statements to convince the static mode of
-GNAT that it need not generate an implicit @code{pragma Elaborate_All}
-statement.
-
-When using the static mode with @code{-gnatwl}, any use of
-@code{pragma Elaborate} will generate a warning about possible
-problems.
+@item
+@emph{Scenario suppression}
+
+When the pragma @code{Suppress} is placed in a declarative or statement
+part, without an entity argument, it will suppress implicit @code{Elaborate}
+and @code{Elaborate_All} pragma generation, as well as run-time checks, on
+all scenarios within the region.
+
+@example
+with Server;
+package body Range_Suppress is
+ pragma Suppress (Elaboration_Check);
+
+ function Func return Integer is
+ begin
+ return Server.Func;
+ end Func;
+
+ procedure Gen is
+ begin
+ Server.Proc;
+ end Gen;
+
+ pragma Unsuppress (Elaboration_Check);
+
+ task body Tsk is
+ begin
+ Server.Proc;
+ end Tsk;
+end Range_Suppress;
+@end example
+
+In the example above, a pair of Suppress/Unsuppress pragmas define a region
+of suppression within package body @code{Range_Suppress}. As a result, the
+calls to @code{Server.Func} in @code{Func} and @code{Server.Proc} in @code{Gen} will
+not generate any implicit @code{Elaborate} and @code{Elaborate_All} pragmas or
+run-time checks.
+@end itemize
+@end itemize
-@node Elaboration Issues for Library Tasks,Mixing Elaboration Models,Treatment of Pragma Elaborate,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat elaboration-issues-for-library-tasks}@anchor{23d}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id9}@anchor{23e}
-@section Elaboration Issues for Library Tasks
+@node Resolving Task Issues,Elaboration-related Compiler Switches,Resolving Elaboration Circularities,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat id14}@anchor{246}@anchor{gnat_ugn/elaboration_order_handling_in_gnat resolving-task-issues}@anchor{247}
+@section Resolving Task Issues
-@geindex Library tasks
-@geindex elaboration issues
+The model of execution in Ada dictates that elaboration must first take place,
+and only then can the main program be started. Tasks which are activated during
+elaboration violate this model and may lead to serious concurrent problems at
+elaboration time.
-@geindex Elaboration of library tasks
+A task can be activated in two different ways:
-In this section we examine special elaboration issues that arise for
-programs that declare library level tasks.
-Generally the model of execution of an Ada program is that all units are
-elaborated, and then execution of the program starts. However, the
-declaration of library tasks definitely does not fit this model. The
-reason for this is that library tasks start as soon as they are declared
-(more precisely, as soon as the statement part of the enclosing package
-body is reached), that is to say before elaboration
-of the program is complete. This means that if such a task calls a
-subprogram, or an entry in another task, the callee may or may not be
-elaborated yet, and in the standard
-Reference Manual model of dynamic elaboration checks, you can even
-get timing dependent Program_Error exceptions, since there can be
-a race between the elaboration code and the task code.
+@itemize *
+
+@item
+The task is created by an allocator in which case it is activated immediately
+after the allocator is evaluated.
-The static model of elaboration in GNAT seeks to avoid all such
-dynamic behavior, by being conservative, and the conservative
-approach in this particular case is to assume that all the code
-in a task body is potentially executed at elaboration time if
-a task is declared at the library level.
+@item
+The task is declared at the library level or within some nested master in
+which case it is activated before starting execution of the statement
+sequence of the master defining the task.
+@end itemize
-This can definitely result in unexpected circularities. Consider
-the following example
+Since the elaboration of a partition is performed by the environment task
+servicing that partition, any tasks activated during elaboration may be in
+a race with the environment task, and lead to unpredictable state and behavior.
+The static model seeks to avoid such interactions by assuming that all code in
+the task body is executed at elaboration time, if the task was activated by
+elaboration code.
@example
package Decls is
- task Lib_Task is
- entry Start;
- end Lib_Task;
+ task Lib_Task is
+ entry Start;
+ end Lib_Task;
- type My_Int is new Integer;
+ type My_Int is new Integer;
- function Ident (M : My_Int) return My_Int;
+ function Ident (M : My_Int) return My_Int;
end Decls;
+@end example
+@example
with Utils;
package body Decls is
- task body Lib_Task is
- begin
- accept Start;
- Utils.Put_Val (2);
- end Lib_Task;
-
- function Ident (M : My_Int) return My_Int is
- begin
- return M;
- end Ident;
+ task body Lib_Task is
+ begin
+ accept Start;
+ Utils.Put_Val (2);
+ end Lib_Task;
+
+ function Ident (M : My_Int) return My_Int is
+ begin
+ return M;
+ end Ident;
end Decls;
+@end example
+@example
with Decls;
package Utils is
- procedure Put_Val (Arg : Decls.My_Int);
+ procedure Put_Val (Arg : Decls.My_Int);
end Utils;
+@end example
-with Text_IO;
+@example
+with Ada.Text_IO; use Ada.Text_IO;
package body Utils is
- procedure Put_Val (Arg : Decls.My_Int) is
- begin
- Text_IO.Put_Line (Decls.My_Int'Image (Decls.Ident (Arg)));
- end Put_Val;
+ procedure Put_Val (Arg : Decls.My_Int) is
+ begin
+ Put_Line (Arg'Img);
+ end Put_Val;
end Utils;
+@end example
+@example
with Decls;
procedure Main is
begin
Decls.Lib_Task.Start;
-end;
+end Main;
@end example
-If the above example is compiled in the default static elaboration
-mode, then a circularity occurs. The circularity comes from the call
-@code{Utils.Put_Val} in the task body of @code{Decls.Lib_Task}. Since
-this call occurs in elaboration code, we need an implicit pragma
-@code{Elaborate_All} for @code{Utils}. This means that not only must
-the spec and body of @code{Utils} be elaborated before the body
-of @code{Decls}, but also the spec and body of any unit that is
-@emph{with}ed by the body of @code{Utils} must also be elaborated before
-the body of @code{Decls}. This is the transitive implication of
-pragma @code{Elaborate_All} and it makes sense, because in general
-the body of @code{Put_Val} might have a call to something in a
-@emph{with}ed unit.
-
-In this case, the body of Utils (actually its spec) @emph{with}s
-@code{Decls}. Unfortunately this means that the body of @code{Decls}
-must be elaborated before itself, in case there is a call from the
-body of @code{Utils}.
-
-Here is the exact chain of events we are worrying about:
-
-
-@itemize *
-
-@item
-In the body of @code{Decls} a call is made from within the body of a library
-task to a subprogram in the package @code{Utils}. Since this call may
-occur at elaboration time (given that the task is activated at elaboration
-time), we have to assume the worst, i.e., that the
-call does happen at elaboration time.
-
-@item
-This means that the body and spec of @code{Util} must be elaborated before
-the body of @code{Decls} so that this call does not cause an access before
-elaboration.
+When the above example is compiled with the static model, an elaboration
+circularity arises:
-@item
-Within the body of @code{Util}, specifically within the body of
-@code{Util.Put_Val} there may be calls to any unit @emph{with}ed
-by this package.
-
-@item
-One such @emph{with}ed package is package @code{Decls}, so there
-might be a call to a subprogram in @code{Decls} in @code{Put_Val}.
-In fact there is such a call in this example, but we would have to
-assume that there was such a call even if it were not there, since
-we are not supposed to write the body of @code{Decls} knowing what
-is in the body of @code{Utils}; certainly in the case of the
-static elaboration model, the compiler does not know what is in
-other bodies and must assume the worst.
-
-@item
-This means that the spec and body of @code{Decls} must also be
-elaborated before we elaborate the unit containing the call, but
-that unit is @code{Decls}! This means that the body of @code{Decls}
-must be elaborated before itself, and that's a circularity.
-@end itemize
-
-Indeed, if you add an explicit pragma @code{Elaborate_All} for @code{Utils} in
-the body of @code{Decls} you will get a true Ada Reference Manual
-circularity that makes the program illegal.
+@example
+error: elaboration circularity detected
+info: "decls (body)" must be elaborated before "decls (body)"
+info: reason: implicit Elaborate_All in unit "decls (body)"
+info: recompile "decls (body)" with -gnatel for full details
+info: "decls (body)"
+info: must be elaborated along with its spec:
+info: "decls (spec)"
+info: which is withed by:
+info: "utils (spec)"
+info: which is withed by:
+info: "decls (body)"
+@end example
-In practice, we have found that problems with the static model of
-elaboration in existing code often arise from library tasks, so
-we must address this particular situation.
+In the above example, @code{Decls} must be elaborated prior to @code{Main} by virtue
+of a with clause. The elaboration of @code{Decls} activates task @code{Lib_Task}. The
+static model conservatibely assumes that all code within the body of
+@code{Lib_Task} is executed, and generates an implicit @code{Elaborate_All} pragma
+for @code{Units} due to the call to @code{Utils.Put_Val}. The pragma implies that
+both the spec and body of @code{Utils}, along with any units they @emph{with},
+must be elaborated prior to @code{Decls}. However, @code{Utils}'s spec @emph{with}s
+@code{Decls}, implying that @code{Decls} must be elaborated before @code{Utils}. The end
+result is that @code{Utils} must be elaborated prior to @code{Utils}, and this
+leads to a circularity.
-Note that if we compile and run the program above, using the dynamic model of
-elaboration (that is to say use the @code{-gnatE} switch),
-then it compiles, binds,
-links, and runs, printing the expected result of 2. Therefore in some sense
-the circularity here is only apparent, and we need to capture
-the properties of this program that distinguish it from other library-level
-tasks that have real elaboration problems.
+In reality, the example above will not exhibit an ABE problem at run time.
+When the body of task @code{Lib_Task} is activated, execution will wait for entry
+@code{Start} to be accepted, and the call to @code{Utils.Put_Val} will not take place
+at elaboration time. Task @code{Lib_Task} will resume its execution after the main
+program is executed because @code{Main} performs a rendezvous with
+@code{Lib_Task.Start}, and at that point all units have already been elaborated.
+As a result, the static model may seem overly conservative, partly because it
+does not take control and data flow into account.
-We have four possible answers to this question:
+When faced with a task elaboration circularity, a programmer has several
+options available:
@itemize *
@item
-Use the dynamic model of elaboration.
+@emph{Use the dynamic model}
-If we use the @code{-gnatE} switch, then as noted above, the program works.
-Why is this? If we examine the task body, it is apparent that the task cannot
-proceed past the
-@code{accept} statement until after elaboration has been completed, because
-the corresponding entry call comes from the main program, not earlier.
-This is why the dynamic model works here. But that's really giving
-up on a precise analysis, and we prefer to take this approach only if we cannot
-solve the
-problem in any other manner. So let us examine two ways to reorganize
-the program to avoid the potential elaboration problem.
+The dynamic model does not generate implicit @code{Elaborate} and
+@code{Elaborate_All} pragmas. Instead, it will install checks prior to every
+call in the example above, thus verifying the successful elaboration of
+@code{Utils.Put_Val} in case the call to it takes place at elaboration time.
+The dynamic model is enabled with compiler switch @code{-gnatE}.
@item
-Split library tasks into separate packages.
+@emph{Isolate the tasks}
-Write separate packages, so that library tasks are isolated from
-other declarations as much as possible. Let us look at a variation on
-the above program.
+Relocating tasks in their own separate package could decouple them from
+dependencies that would otherwise cause an elaboration circularity. The
+example above can be rewritten as follows:
@example
-package Decls1 is
- task Lib_Task is
- entry Start;
- end Lib_Task;
+package Decls1 is -- new
+ task Lib_Task is
+ entry Start;
+ end Lib_Task;
end Decls1;
+@end example
+@example
with Utils;
-package body Decls1 is
- task body Lib_Task is
- begin
- accept Start;
- Utils.Put_Val (2);
- end Lib_Task;
+package body Decls1 is -- new
+ task body Lib_Task is
+ begin
+ accept Start;
+ Utils.Put_Val (2);
+ end Lib_Task;
end Decls1;
+@end example
-package Decls2 is
- type My_Int is new Integer;
- function Ident (M : My_Int) return My_Int;
+@example
+package Decls2 is -- new
+ type My_Int is new Integer;
+ function Ident (M : My_Int) return My_Int;
end Decls2;
+@end example
+@example
with Utils;
-package body Decls2 is
- function Ident (M : My_Int) return My_Int is
- begin
- return M;
- end Ident;
+package body Decls2 is -- new
+ function Ident (M : My_Int) return My_Int is
+ begin
+ return M;
+ end Ident;
end Decls2;
+@end example
+@example
with Decls2;
package Utils is
- procedure Put_Val (Arg : Decls2.My_Int);
+ procedure Put_Val (Arg : Decls2.My_Int);
end Utils;
+@end example
-with Text_IO;
+@example
+with Ada.Text_IO; use Ada.Text_IO;
package body Utils is
- procedure Put_Val (Arg : Decls2.My_Int) is
- begin
- Text_IO.Put_Line (Decls2.My_Int'Image (Decls2.Ident (Arg)));
- end Put_Val;
+ procedure Put_Val (Arg : Decls2.My_Int) is
+ begin
+ Put_Line (Arg'Img);
+ end Put_Val;
end Utils;
+@end example
+@example
with Decls1;
procedure Main is
begin
Decls1.Lib_Task.Start;
-end;
+end Main;
@end example
-All we have done is to split @code{Decls} into two packages, one
-containing the library task, and one containing everything else. Now
-there is no cycle, and the program compiles, binds, links and executes
-using the default static model of elaboration.
-
@item
-Declare separate task types.
+@emph{Declare the tasks}
-A significant part of the problem arises because of the use of the
-single task declaration form. This means that the elaboration of
-the task type, and the elaboration of the task itself (i.e., the
-creation of the task) happen at the same time. A good rule
-of style in Ada is to always create explicit task types. By
-following the additional step of placing task objects in separate
-packages from the task type declaration, many elaboration problems
-are avoided. Here is another modified example of the example program:
+The original example uses a single task declaration for @code{Lib_Task}. An
+explicit task type declaration and a properly placed task object could avoid
+the dependencies that would otherwise cause an elaboration circularity. The
+example can be rewritten as follows:
@example
package Decls is
- task type Lib_Task_Type is
- entry Start;
- end Lib_Task_Type;
+ task type Lib_Task is -- new
+ entry Start;
+ end Lib_Task;
- type My_Int is new Integer;
+ type My_Int is new Integer;
- function Ident (M : My_Int) return My_Int;
+ function Ident (M : My_Int) return My_Int;
end Decls;
+@end example
+@example
with Utils;
package body Decls is
- task body Lib_Task_Type is
- begin
- accept Start;
- Utils.Put_Val (2);
- end Lib_Task_Type;
-
- function Ident (M : My_Int) return My_Int is
- begin
- return M;
- end Ident;
+ task body Lib_Task is
+ begin
+ accept Start;
+ Utils.Put_Val (2);
+ end Lib_Task;
+
+ function Ident (M : My_Int) return My_Int is
+ begin
+ return M;
+ end Ident;
end Decls;
+@end example
+@example
with Decls;
package Utils is
- procedure Put_Val (Arg : Decls.My_Int);
+ procedure Put_Val (Arg : Decls.My_Int);
end Utils;
+@end example
-with Text_IO;
+@example
+with Ada.Text_IO; use Ada.Text_IO;
package body Utils is
- procedure Put_Val (Arg : Decls.My_Int) is
- begin
- Text_IO.Put_Line (Decls.My_Int'Image (Decls.Ident (Arg)));
- end Put_Val;
+ procedure Put_Val (Arg : Decls.My_Int) is
+ begin
+ Put_Line (Arg'Img);
+ end Put_Val;
end Utils;
+@end example
+@example
with Decls;
-package Declst is
- Lib_Task : Decls.Lib_Task_Type;
-end Declst;
+package Obj_Decls is -- new
+ Task_Obj : Decls.Lib_Task;
+end Obj_Decls;
+@end example
-with Declst;
+@example
+with Obj_Decls;
procedure Main is
begin
- Declst.Lib_Task.Start;
-end;
+ Obj_Decls.Task_Obj.Start; -- new
+end Main;
+@end example
+
+@item
+@emph{Use restriction No_Entry_Calls_In_Elaboration_Code}
+
+The issue exhibited in the original example under this section revolves
+around the body of @code{Lib_Task} blocking on an accept statement. There is
+no rule to prevent elaboration code from performing entry calls, however in
+practice this is highly unusual. In addition, the pattern of starting tasks
+at elaboration time and then immediately blocking on accept or select
+statements is quite common.
+
+If a programmer knows that elaboration code will not perform any entry
+calls, then the programmer can indicate that the static model should not
+process the remainder of a task body once an accept or select statement has
+been encountered. This behavior can be specified by a configuration pragma:
+
+@example
+pragma Restrictions (No_Entry_Calls_In_Elaboration_Code);
@end example
-What we have done here is to replace the @code{task} declaration in
-package @code{Decls} with a @code{task type} declaration. Then we
-introduce a separate package @code{Declst} to contain the actual
-task object. This separates the elaboration issues for
-the @code{task type}
-declaration, which causes no trouble, from the elaboration issues
-of the task object, which is also unproblematic, since it is now independent
-of the elaboration of @code{Utils}.
-This separation of concerns also corresponds to
-a generally sound engineering principle of separating declarations
-from instances. This version of the program also compiles, binds, links,
-and executes, generating the expected output.
+In addition to the change in behavior with respect to task bodies, the
+static model will verify that no entry calls take place at elaboration time.
@end itemize
-@geindex No_Entry_Calls_In_Elaboration_Code restriction
+@node Elaboration-related Compiler Switches,Summary of Procedures for Elaboration Control,Resolving Task Issues,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat elaboration-related-compiler-switches}@anchor{248}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id15}@anchor{249}
+@section Elaboration-related Compiler Switches
-@itemize *
+GNAT has several switches that affect the elaboration model and consequently
+the elaboration order chosen by the binder.
-@item
-Use No_Entry_Calls_In_Elaboration_Code restriction.
+@geindex -gnatdE (gnat)
-The previous two approaches described how a program can be restructured
-to avoid the special problems caused by library task bodies. in practice,
-however, such restructuring may be difficult to apply to existing legacy code,
-so we must consider solutions that do not require massive rewriting.
-Let us consider more carefully why our original sample program works
-under the dynamic model of elaboration. The reason is that the code
-in the task body blocks immediately on the @code{accept}
-statement. Now of course there is nothing to prohibit elaboration
-code from making entry calls (for example from another library level task),
-so we cannot tell in isolation that
-the task will not execute the accept statement during elaboration.
+@table @asis
-However, in practice it is very unusual to see elaboration code
-make any entry calls, and the pattern of tasks starting
-at elaboration time and then immediately blocking on @code{accept} or
-@code{select} statements is very common. What this means is that
-the compiler is being too pessimistic when it analyzes the
-whole package body as though it might be executed at elaboration
-time.
+@item @code{-gnatdE}
-If we know that the elaboration code contains no entry calls, (a very safe
-assumption most of the time, that could almost be made the default
-behavior), then we can compile all units of the program under control
-of the following configuration pragma:
+Elaboration checks on predefined units
-@example
-pragma Restrictions (No_Entry_Calls_In_Elaboration_Code);
-@end example
+When this switch is in effect, GNAT will consider scenarios and targets that
+come from the Ada, GNAT, Interfaces, and System hierarchies. This switch is
+useful when a programmer has defined a custom grandchild of those packages.
+@end table
-This pragma can be placed in the @code{gnat.adc} file in the usual
-manner. If we take our original unmodified program and compile it
-in the presence of a @code{gnat.adc} containing the above pragma,
-then once again, we can compile, bind, link, and execute, obtaining
-the expected result. In the presence of this pragma, the compiler does
-not trace calls in a task body, that appear after the first @code{accept}
-or @code{select} statement, and therefore does not report a potential
-circularity in the original program.
-
-The compiler will check to the extent it can that the above
-restriction is not violated, but it is not always possible to do a
-complete check at compile time, so it is important to use this
-pragma only if the stated restriction is in fact met, that is to say
-no task receives an entry call before elaboration of all units is completed.
-@end itemize
+@geindex -gnatd.G (gnat)
-@node Mixing Elaboration Models,What to Do If the Default Elaboration Behavior Fails,Elaboration Issues for Library Tasks,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id10}@anchor{23f}@anchor{gnat_ugn/elaboration_order_handling_in_gnat mixing-elaboration-models}@anchor{240}
-@section Mixing Elaboration Models
+@table @asis
-So far, we have assumed that the entire program is either compiled
-using the dynamic model or static model, ensuring consistency. It
-is possible to mix the two models, but rules have to be followed
-if this mixing is done to ensure that elaboration checks are not
-omitted.
+@item @code{-gnatd.G}
-The basic rule is that
-@strong{a unit compiled with the static model cannot
-be |withed| by a unit compiled with the dynamic model}.
-The reason for this is that in the static model, a unit assumes that
-its clients guarantee to use (the equivalent of) pragma
-@code{Elaborate_All} so that no elaboration checks are required
-in inner subprograms, and this assumption is violated if the
-client is compiled with dynamic checks.
+Ignore calls through generic formal parameters for elaboration
-The precise rule is as follows. A unit that is compiled with dynamic
-checks can only @emph{with} a unit that meets at least one of the
-following criteria:
+When this switch is in effect, GNAT will ignore calls that invoke generic
+actual entries, operators, or subprograms via generic formal subprograms. As
+a result, GNAT will not generate implicit @code{Elaborate} and @code{Elaborate_All}
+pragmas, and run-time checks for such calls. Note that this switch does not
+overlap with @code{-gnatdL}.
+@example
+package body Ignore_Calls is
+ function ABE return Integer;
-@itemize *
+ generic
+ with function Gen_Formal return Integer;
+ package Gen is
+ Val : constant Integer := Gen_Formal;
+ end Gen;
-@item
-The @emph{with}ed unit is itself compiled with dynamic elaboration
-checks (that is with the @code{-gnatE} switch.
+ package Inst is new Gen (ABE);
-@item
-The @emph{with}ed unit is an internal GNAT implementation unit from
-the System, Interfaces, Ada, or GNAT hierarchies.
+ function ABE return Integer is
+ begin
+ ...
+ end ABE;
+end Ignore_Calls;
+@end example
-@item
-The @emph{with}ed unit has pragma Preelaborate or pragma Pure.
+In the example above, the call to function @code{ABE} will be ignored because it
+occurs during the elaboration of instance @code{Inst}, through a call to generic
+formal subprogram @code{Gen_Formal}.
+@end table
-@item
-The @emph{with}ing unit (that is the client) has an explicit pragma
-@code{Elaborate_All} for the @emph{with}ed unit.
-@end itemize
+@geindex -gnatdL (gnat)
+
+
+@table @asis
+
+@item @code{-gnatdL}
+
+Ignore external calls from instances for elaboration
-If this rule is violated, that is if a unit with dynamic elaboration
-checks @emph{with}s a unit that does not meet one of the above four
-criteria, then the binder (@code{gnatbind}) will issue a warning
-similar to that in the following example:
+When this switch is in effect, GNAT will ignore calls that originate from
+within an instance and directly target an entry, operator, or subprogram
+defined outside the instance. As a result, GNAT will not generate implicit
+@code{Elaborate} and @code{Elaborate_All} pragmas, and run-time checks for such
+calls. Note that this switch does not overlap with @code{-gnatd.G}.
@example
-warning: "x.ads" has dynamic elaboration checks and with's
-warning: "y.ads" which has static elaboration checks
+package body Ignore_Calls is
+ function ABE return Integer;
+
+ generic
+ package Gen is
+ Val : constant Integer := ABE;
+ end Gen;
+
+ package Inst is new Gen;
+
+ function ABE return Integer is
+ begin
+ ...
+ end ABE;
+end Ignore_Calls;
@end example
-These warnings indicate that the rule has been violated, and that as a result
-elaboration checks may be missed in the resulting executable file.
-This warning may be suppressed using the @code{-ws} binder switch
-in the usual manner.
+In the example above, the call to function @code{ABE} will be ignored because it
+originates from within an instance and targets a subprogram defined outside
+the instance.
+@end table
+
+@geindex -gnatd.o (gnat)
+
-One useful application of this mixing rule is in the case of a subsystem
-which does not itself @emph{with} units from the remainder of the
-application. In this case, the entire subsystem can be compiled with
-dynamic checks to resolve a circularity in the subsystem, while
-allowing the main application that uses this subsystem to be compiled
-using the more reliable default static model.
+@table @asis
-@node What to Do If the Default Elaboration Behavior Fails,Elaboration for Indirect Calls,Mixing Elaboration Models,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id11}@anchor{241}@anchor{gnat_ugn/elaboration_order_handling_in_gnat what-to-do-if-the-default-elaboration-behavior-fails}@anchor{23a}
-@section What to Do If the Default Elaboration Behavior Fails
+@item @code{-gnatd.o}
+Conservative elaboration order for indirect calls
-If the binder cannot find an acceptable order, it outputs detailed
-diagnostics. For example:
+When this switch is in effect, GNAT will treat @code{'Access} of an entry,
+operator, or subprogram as an immediate call to that target. As a result,
+GNAT will generate implicit @code{Elaborate} and @code{Elaborate_All} pragmas as
+well as run-time checks for such attribute references.
@example
-error: elaboration circularity detected
-info: "proc (body)" must be elaborated before "pack (body)"
-info: reason: Elaborate_All probably needed in unit "pack (body)"
-info: recompile "pack (body)" with -gnatel
-info: for full details
-info: "proc (body)"
-info: is needed by its spec:
-info: "proc (spec)"
-info: which is withed by:
-info: "pack (body)"
-info: "pack (body)" must be elaborated before "proc (body)"
-info: reason: pragma Elaborate in unit "proc (body)"
-@end example
-
-In this case we have a cycle that the binder cannot break. On the one
-hand, there is an explicit pragma Elaborate in @code{proc} for
-@code{pack}. This means that the body of @code{pack} must be elaborated
-before the body of @code{proc}. On the other hand, there is elaboration
-code in @code{pack} that calls a subprogram in @code{proc}. This means
-that for maximum safety, there should really be a pragma
-Elaborate_All in @code{pack} for @code{proc} which would require that
-the body of @code{proc} be elaborated before the body of
-@code{pack}. Clearly both requirements cannot be satisfied.
-Faced with a circularity of this kind, you have three different options.
+ 1. package body Attribute_Call is
+ 2. function Func return Integer;
+ 3. type Func_Ptr is access function return Integer;
+ 4.
+ 5. Ptr : constant Func_Ptr := Func'Access;
+ |
+ >>> warning: cannot call "Func" before body seen
+ >>> warning: Program_Error may be raised at run time
+ >>> warning: body of unit "Attribute_Call" elaborated
+ >>> warning: "Access" of "Func" taken at line 5
+ >>> warning: function "Func" called at line 5
+ 6.
+ 7. function Func return Integer is
+ 8. begin
+ 9. ...
+10. end Func;
+11. end Attribute_Call;
+@end example
-@itemize *
+In the example above, the elaboration of declaration @code{Ptr} is assigned
+@code{Func'Access} before the body of @code{Func} has been elaborated.
+@end table
-@item
-@emph{Fix the program}
+@geindex -gnatd.U (gnat)
-The most desirable option from the point of view of long-term maintenance
-is to rearrange the program so that the elaboration problems are avoided.
-One useful technique is to place the elaboration code into separate
-child packages. Another is to move some of the initialization code to
-explicitly called subprograms, where the program controls the order
-of initialization explicitly. Although this is the most desirable option,
-it may be impractical and involve too much modification, especially in
-the case of complex legacy code.
-@item
-@emph{Perform dynamic checks}
+@table @asis
-If the compilations are done using the @code{-gnatE}
-(dynamic elaboration check) switch, then GNAT behaves in a quite different
-manner. Dynamic checks are generated for all calls that could possibly result
-in raising an exception. With this switch, the compiler does not generate
-implicit @code{Elaborate} or @code{Elaborate_All} pragmas. The behavior then is
-exactly as specified in the @cite{Ada Reference Manual}.
-The binder will generate
-an executable program that may or may not raise @code{Program_Error}, and then
-it is the programmer's job to ensure that it does not raise an exception. Note
-that it is important to compile all units with the switch, it cannot be used
-selectively.
+@item @code{-gnatd.U}
-@item
-@emph{Suppress checks}
+Ignore indirect calls for static elaboration
-The drawback of dynamic checks is that they generate a
-significant overhead at run time, both in space and time. If you
-are absolutely sure that your program cannot raise any elaboration
-exceptions, and you still want to use the dynamic elaboration model,
-then you can use the configuration pragma
-@code{Suppress (Elaboration_Check)} to suppress all such checks. For
-example this pragma could be placed in the @code{gnat.adc} file.
+When this switch is in effect, GNAT will ignore @code{'Access} of an entry,
+operator, or subprogram when the static model is in effect.
+@end table
-@item
-@emph{Suppress checks selectively}
+@geindex -gnatd.v (gnat)
-When you know that certain calls or instantiations in elaboration code cannot
-possibly lead to an elaboration error, and the binder nevertheless complains
-about implicit @code{Elaborate} and @code{Elaborate_All} pragmas that lead to
-elaboration circularities, it is possible to remove those warnings locally and
-obtain a program that will bind. Clearly this can be unsafe, and it is the
-responsibility of the programmer to make sure that the resulting program has no
-elaboration anomalies. The pragma @code{Suppress (Elaboration_Check)} can be
-used with different granularity to suppress warnings and break elaboration
-circularities:
+@table @asis
-@itemize *
+@item @code{-gnatd.v}
-@item
-Place the pragma that names the called subprogram in the declarative part
-that contains the call.
+Enforce SPARK elaboration rules in SPARK code
-@item
-Place the pragma in the declarative part, without naming an entity. This
-disables warnings on all calls in the corresponding declarative region.
+When this switch is in effect, GNAT will enforce the SPARK rules of
+elaboration as defined in the SPARK Reference Manual, section 7.7. As a
+result, constructs which violate the SPARK elaboration rules are no longer
+accepted, even if GNAT is able to statically ensure that these constructs
+will not lead to ABE problems.
+@end table
-@item
-Place the pragma in the package spec that declares the called subprogram,
-and name the subprogram. This disables warnings on all elaboration calls to
-that subprogram.
+@geindex -gnatd.y (gnat)
-@item
-Place the pragma in the package spec that declares the called subprogram,
-without naming any entity. This disables warnings on all elaboration calls to
-all subprograms declared in this spec.
-@item
-Use Pragma Elaborate.
+@table @asis
-As previously described in section @ref{23b,,Treatment of Pragma Elaborate},
-GNAT in static mode assumes that a @code{pragma} Elaborate indicates correctly
-that no elaboration checks are required on calls to the designated unit.
-There may be cases in which the caller knows that no transitive calls
-can occur, so that a @code{pragma Elaborate} will be sufficient in a
-case where @code{pragma Elaborate_All} would cause a circularity.
-@end itemize
+@item @code{-gnatd.y}
-These five cases are listed in order of decreasing safety, and therefore
-require increasing programmer care in their application. Consider the
-following program:
+Disable implicit pragma Elaborate[_All] on task bodies
+
+When this switch is in effect, GNAT will not generate @code{Elaborate} and
+@code{Elaborate_All} pragmas if the need for the pragma came directly or
+indirectly from a task body.
@example
-package Pack1 is
- function F1 return Integer;
- X1 : Integer;
-end Pack1;
+with Server;
+package body Disable_Task is
+ task T;
-package Pack2 is
- function F2 return Integer;
- function Pure (x : integer) return integer;
- -- pragma Suppress (Elaboration_Check, On => Pure); -- (3)
- -- pragma Suppress (Elaboration_Check); -- (4)
-end Pack2;
+ task body T is
+ begin
+ Server.Proc;
+ end T;
+end Disable_Task;
+@end example
-with Pack2;
-package body Pack1 is
- function F1 return Integer is
- begin
- return 100;
- end F1;
- Val : integer := Pack2.Pure (11); -- Elab. call (1)
-begin
- declare
- -- pragma Suppress(Elaboration_Check, Pack2.F2); -- (1)
- -- pragma Suppress(Elaboration_Check); -- (2)
- begin
- X1 := Pack2.F2 + 1; -- Elab. call (2)
- end;
-end Pack1;
+In the example above, the activation of single task @code{T} invokes
+@code{Server.Proc}, which implies that @code{Server} requires @code{Elaborate_All},
+however GNAT will not generate the pragma.
+@end table
-with Pack1;
-package body Pack2 is
- function F2 return Integer is
- begin
- return Pack1.F1;
- end F2;
- function Pure (x : integer) return integer is
- begin
- return x ** 3 - 3 * x;
- end;
-end Pack2;
+@geindex -gnatE (gnat)
-with Pack1, Ada.Text_IO;
-procedure Proc3 is
-begin
- Ada.Text_IO.Put_Line(Pack1.X1'Img); -- 101
-end Proc3;
-@end example
-In the absence of any pragmas, an attempt to bind this program produces
-the following diagnostics:
+@table @asis
-@example
-error: elaboration circularity detected
-info: "pack1 (body)" must be elaborated before "pack1 (body)"
-info: reason: Elaborate_All probably needed in unit "pack1 (body)"
-info: recompile "pack1 (body)" with -gnatel for full details
-info: "pack1 (body)"
-info: must be elaborated along with its spec:
-info: "pack1 (spec)"
-info: which is withed by:
-info: "pack2 (body)"
-info: which must be elaborated along with its spec:
-info: "pack2 (spec)"
-info: which is withed by:
-info: "pack1 (body)"
-@end example
+@item @code{-gnatE}
-The sources of the circularity are the two calls to @code{Pack2.Pure} and
-@code{Pack2.F2} in the body of @code{Pack1}. We can see that the call to
-F2 is safe, even though F2 calls F1, because the call appears after the
-elaboration of the body of F1. Therefore the pragma (1) is safe, and will
-remove the warning on the call. It is also possible to use pragma (2)
-because there are no other potentially unsafe calls in the block.
+Dynamic elaboration checking mode enabled
-The call to @code{Pure} is safe because this function does not depend on the
-state of @code{Pack2}. Therefore any call to this function is safe, and it
-is correct to place pragma (3) in the corresponding package spec.
+When this switch is in effect, GNAT activates the dynamic elaboration model.
+@end table
-Finally, we could place pragma (4) in the spec of @code{Pack2} to disable
-warnings on all calls to functions declared therein. Note that this is not
-necessarily safe, and requires more detailed examination of the subprogram
-bodies involved. In particular, a call to @code{F2} requires that @code{F1}
-be already elaborated.
-@end itemize
+@geindex -gnatel (gnat)
-It is hard to generalize on which of these four approaches should be
-taken. Obviously if it is possible to fix the program so that the default
-treatment works, this is preferable, but this may not always be practical.
-It is certainly simple enough to use @code{-gnatE}
-but the danger in this case is that, even if the GNAT binder
-finds a correct elaboration order, it may not always do so,
-and certainly a binder from another Ada compiler might not. A
-combination of testing and analysis (for which the
-information messages generated with the @code{-gnatel}
-switch can be useful) must be used to ensure that the program is free
-of errors. One switch that is useful in this testing is the
-@code{-p} (pessimistic elaboration order) switch for @code{gnatbind}.
-Normally the binder tries to find an order that has the best chance
-of avoiding elaboration problems. However, if this switch is used, the binder
-plays a devil's advocate role, and tries to choose the order that
-has the best chance of failing. If your program works even with this
-switch, then it has a better chance of being error free, but this is still
-not a guarantee.
-
-For an example of this approach in action, consider the C-tests (executable
-tests) from the ACATS suite. If these are compiled and run with the default
-treatment, then all but one of them succeed without generating any error
-diagnostics from the binder. However, there is one test that fails, and
-this is not surprising, because the whole point of this test is to ensure
-that the compiler can handle cases where it is impossible to determine
-a correct order statically, and it checks that an exception is indeed
-raised at run time.
-
-This one test must be compiled and run using the @code{-gnatE}
-switch, and then it passes. Alternatively, the entire suite can
-be run using this switch. It is never wrong to run with the dynamic
-elaboration switch if your code is correct, and we assume that the
-C-tests are indeed correct (it is less efficient, but efficiency is
-not a factor in running the ACATS tests.)
-
-@node Elaboration for Indirect Calls,Summary of Procedures for Elaboration Control,What to Do If the Default Elaboration Behavior Fails,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id12}@anchor{242}@anchor{gnat_ugn/elaboration_order_handling_in_gnat elaboration-for-indirect-calls}@anchor{243}
-@section Elaboration for Indirect Calls
-
-
-@geindex Dispatching calls
-
-@geindex Indirect calls
-
-In rare cases, the static elaboration model fails to prevent
-dispatching calls to not-yet-elaborated subprograms. In such cases, we
-fall back to run-time checks; premature calls to any primitive
-operation of a tagged type before the body of the operation has been
-elaborated will raise @code{Program_Error}.
-
-Access-to-subprogram types, however, are handled conservatively in many
-cases. This was not true in earlier versions of the compiler; you can use
-the @code{-gnatd.U} debug switch to revert to the old behavior if the new
-conservative behavior causes elaboration cycles. Here, 'conservative' means
-that if you do @code{P'Access} during elaboration, the compiler will normally
-assume that you might call @code{P} indirectly during elaboration, so it adds an
-implicit @code{pragma Elaborate_All} on the library unit containing @code{P}. The
-@code{-gnatd.U} switch is safe if you know there are no such calls. If the
-program worked before, it will continue to work with @code{-gnatd.U}. But beware
-that code modifications such as adding an indirect call can cause erroneous
-behavior in the presence of @code{-gnatd.U}.
-
-These implicit Elaborate_All pragmas are not added in all cases, because
-they cause elaboration cycles in certain common code patterns. If you want
-even more conservative handling of P'Access, you can use the @code{-gnatd.o}
-switch.
-See @code{debug.adb} for documentation on the @code{-gnatd...} debug switches.
+@table @asis
-@node Summary of Procedures for Elaboration Control,Other Elaboration Order Considerations,Elaboration for Indirect Calls,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id13}@anchor{244}@anchor{gnat_ugn/elaboration_order_handling_in_gnat summary-of-procedures-for-elaboration-control}@anchor{245}
-@section Summary of Procedures for Elaboration Control
+@item @code{-gnatel}
+Turn on info messages on generated Elaborate[_All] pragmas
-@geindex Elaboration control
+When this switch is in effect, GNAT will emit the following supplementary
+information depending on the elaboration model in effect.
-First, compile your program with the default options, using none of
-the special elaboration-control switches. If the binder successfully
-binds your program, then you can be confident that, apart from issues
-raised by the use of access-to-subprogram types and dynamic dispatching,
-the program is free of elaboration errors. If it is important that the
-program be portable to other compilers than GNAT, then use the
-@code{-gnatel}
-switch to generate messages about missing @code{Elaborate} or
-@code{Elaborate_All} pragmas, and supply the missing pragmas.
-
-If the program fails to bind using the default static elaboration
-handling, then you can fix the program to eliminate the binder
-message, or recompile the entire program with the
-@code{-gnatE} switch to generate dynamic elaboration checks,
-and, if you are sure there really are no elaboration problems,
-use a global pragma @code{Suppress (Elaboration_Check)}.
-
-@node Other Elaboration Order Considerations,Determining the Chosen Elaboration Order,Summary of Procedures for Elaboration Control,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat id14}@anchor{246}@anchor{gnat_ugn/elaboration_order_handling_in_gnat other-elaboration-order-considerations}@anchor{247}
-@section Other Elaboration Order Considerations
-
-
-This section has been entirely concerned with the issue of finding a valid
-elaboration order, as defined by the Ada Reference Manual. In a case
-where several elaboration orders are valid, the task is to find one
-of the possible valid elaboration orders (and the static model in GNAT
-will ensure that this is achieved).
-
-The purpose of the elaboration rules in the Ada Reference Manual is to
-make sure that no entity is accessed before it has been elaborated. For
-a subprogram, this means that the spec and body must have been elaborated
-before the subprogram is called. For an object, this means that the object
-must have been elaborated before its value is read or written. A violation
-of either of these two requirements is an access before elaboration order,
-and this section has been all about avoiding such errors.
-
-In the case where more than one order of elaboration is possible, in the
-sense that access before elaboration errors are avoided, then any one of
-the orders is 'correct' in the sense that it meets the requirements of
-the Ada Reference Manual, and no such error occurs.
-
-However, it may be the case for a given program, that there are
-constraints on the order of elaboration that come not from consideration
-of avoiding elaboration errors, but rather from extra-lingual logic
-requirements. Consider this example:
-
-@example
-with Init_Constants;
-package Constants is
- X : Integer := 0;
- Y : Integer := 0;
-end Constants;
-
-package Init_Constants is
- procedure P; --* require a body*
-end Init_Constants;
-
-with Constants;
-package body Init_Constants is
- procedure P is begin null; end;
-begin
- Constants.X := 3;
- Constants.Y := 4;
-end Init_Constants;
-with Constants;
-package Calc is
- Z : Integer := Constants.X + Constants.Y;
-end Calc;
+@itemize -
-with Calc;
-with Text_IO; use Text_IO;
-procedure Main is
-begin
- Put_Line (Calc.Z'Img);
-end Main;
-@end example
+@item
+@emph{Dynamic model}
-In this example, there is more than one valid order of elaboration. For
-example both the following are correct orders:
+GNAT will indicate missing @code{Elaborate} and @code{Elaborate_All} pragmas for
+all library-level scenarios within the partition.
-@example
-Init_Constants spec
-Constants spec
-Calc spec
-Init_Constants body
-Main body
-@end example
+@item
+@emph{Static model}
+
+GNAT will indicate all scenarios executed during elaboration. In addition,
+it will provide detailed traceback when an implicit @code{Elaborate} or
+@code{Elaborate_All} pragma is generated.
-and
+@item
+@emph{SPARK model}
+
+GNAT will indicate how an elaboration requirement is met by the context of
+a unit. This diagnostic requires compiler switch @code{-gnatd.v}.
@example
-Init_Constants spec
-Constants spec
-Init_Constants body
-Calc spec
-Main body
+1. with Server; pragma Elaborate_All (Server);
+2. package Client with SPARK_Mode is
+3. Val : constant Integer := Server.Func;
+ |
+ >>> info: call to "Func" during elaboration in SPARK
+ >>> info: "Elaborate_All" requirement for unit "Server" met by pragma at line 1
+
+4. end Client;
@end example
+@end itemize
+@end table
+
+@geindex -gnatw.f (gnat)
-There is no language rule to prefer one or the other, both are correct
-from an order of elaboration point of view. But the programmatic effects
-of the two orders are very different. In the first, the elaboration routine
-of @code{Calc} initializes @code{Z} to zero, and then the main program
-runs with this value of zero. But in the second order, the elaboration
-routine of @code{Calc} runs after the body of Init_Constants has set
-@code{X} and @code{Y} and thus @code{Z} is set to 7 before @code{Main} runs.
-One could perhaps by applying pretty clever non-artificial intelligence
-to the situation guess that it is more likely that the second order of
-elaboration is the one desired, but there is no formal linguistic reason
-to prefer one over the other. In fact in this particular case, GNAT will
-prefer the second order, because of the rule that bodies are elaborated
-as soon as possible, but it's just luck that this is what was wanted
-(if indeed the second order was preferred).
+@table @asis
+
+@item @code{-gnatw.f}
-If the program cares about the order of elaboration routines in a case like
-this, it is important to specify the order required. In this particular
-case, that could have been achieved by adding to the spec of Calc:
+Turn on warnings for suspicious Subp'Access
+
+When this switch is in effect, GNAT will treat @code{'Access} of an entry,
+operator, or subprogram as a potential call to the target and issue warnings:
@example
-pragma Elaborate_All (Constants);
+ 1. package body Attribute_Call is
+ 2. function Func return Integer;
+ 3. type Func_Ptr is access function return Integer;
+ 4.
+ 5. Ptr : constant Func_Ptr := Func'Access;
+ |
+ >>> warning: "Access" attribute of "Func" before body seen
+ >>> warning: possible Program_Error on later references
+ >>> warning: body of unit "Attribute_Call" elaborated
+ >>> warning: "Access" of "Func" taken at line 5
+
+ 6.
+ 7. function Func return Integer is
+ 8. begin
+ 9. ...
+10. end Func;
+11. end Attribute_Call;
@end example
-which requires that the body (if any) and spec of @code{Constants},
-as well as the body and spec of any unit @emph{with}ed by
-@code{Constants} be elaborated before @code{Calc} is elaborated.
+In the example above, the elaboration of declaration @code{Ptr} is assigned
+@code{Func'Access} before the body of @code{Func} has been elaborated.
+@end table
+
+@node Summary of Procedures for Elaboration Control,Inspecting the Chosen Elaboration Order,Elaboration-related Compiler Switches,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat summary-of-procedures-for-elaboration-control}@anchor{24a}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id16}@anchor{24b}
+@section Summary of Procedures for Elaboration Control
-Clearly no automatic method can always guess which alternative you require,
-and if you are working with legacy code that had constraints of this kind
-which were not properly specified by adding @code{Elaborate} or
-@code{Elaborate_All} pragmas, then indeed it is possible that two different
-compilers can choose different orders.
-However, GNAT does attempt to diagnose the common situation where there
-are uninitialized variables in the visible part of a package spec, and the
-corresponding package body has an elaboration block that directly or
-indirectly initializes one or more of these variables. This is the situation
-in which a pragma Elaborate_Body is usually desirable, and GNAT will generate
-a warning that suggests this addition if it detects this situation.
+A programmer should first compile the program with the default options, using
+none of the binder or compiler switches. If the binder succeeds in finding an
+elaboration order, then apart from possible cases involing dispatching calls
+and access-to-subprogram types, the program is free of elaboration errors.
+If it is important for the program to be portable to compilers other than GNAT,
+then the programmer should use compiler switch @code{-gnatel} and consider
+the messages about missing or implicitly created @code{Elaborate} and
+@code{Elaborate_All} pragmas.
-The @code{gnatbind` :switch:`-p` switch may be useful in smoking
-out problems. This switch causes bodies to be elaborated as late as possible
-instead of as early as possible. In the example above, it would have forced
-the choice of the first elaboration order. If you get different results
-when using this switch, and particularly if one set of results is right,
-and one is wrong as far as you are concerned, it shows that you have some
-missing `@w{`}Elaborate} pragmas. For the example above, we have the
-following output:
+If the binder reports an elaboration circularity, the programmer has several
+options:
-@example
-$ gnatmake -f -q main
-$ main
- 7
-$ gnatmake -f -q main -bargs -p
-$ main
- 0
-@end example
-It is of course quite unlikely that both these results are correct, so
-it is up to you in a case like this to investigate the source of the
-difference, by looking at the two elaboration orders that are chosen,
-and figuring out which is correct, and then adding the necessary
-@code{Elaborate} or @code{Elaborate_All} pragmas to ensure the desired order.
+@itemize *
-@node Determining the Chosen Elaboration Order,,Other Elaboration Order Considerations,Elaboration Order Handling in GNAT
-@anchor{gnat_ugn/elaboration_order_handling_in_gnat determining-the-chosen-elaboration-order}@anchor{248}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id15}@anchor{249}
-@section Determining the Chosen Elaboration Order
+@item
+Ensure that warnings are enabled. This will allow the static model to output
+trace information of elaboration issues. The trace information could shed
+light on previously unforeseen dependencies, as well as their origins.
+@item
+Use switch @code{-gnatel} to obtain messages on generated implicit
+@code{Elaborate} and @code{Elaborate_All} pragmas. The trace information could
+indicate why a server unit must be elaborated prior to a client unit.
-To see the elaboration order that the binder chooses, you can look at
-the last part of the file:@cite{b~xxx.adb} binder output file. Here is an example:
+@item
+If the warnings produced by the static model indicate that a task is
+involved, consider the options in the section on resolving task issues as
+well as compiler switch @code{-gnatd.y}.
+
+@item
+If the warnings produced by the static model indicate that an generic
+instantiations are involved, consider using compiler switches
+@code{-gnatd.G} and @code{-gnatdL}.
+
+@item
+If none of the steps outlined above resolve the circularity, recompile the
+program using the dynamic model by using compiler switch @code{-gnatE}.
+@end itemize
+
+@node Inspecting the Chosen Elaboration Order,,Summary of Procedures for Elaboration Control,Elaboration Order Handling in GNAT
+@anchor{gnat_ugn/elaboration_order_handling_in_gnat inspecting-the-chosen-elaboration-order}@anchor{24c}@anchor{gnat_ugn/elaboration_order_handling_in_gnat id17}@anchor{24d}
+@section Inspecting the Chosen Elaboration Order
+
+
+To see the elaboration order chosen by the binder, inspect the contents of file
+@cite{b~xxx.adb}. On certain targets, this file appears as @cite{b_xxx.adb}. The
+elaboration order appears as a sequence of calls to @code{Elab_Body} and
+@code{Elab_Spec}, interspersed with assignments to @cite{Exxx} which indicates that a
+particular unit is elaborated. For example:
@example
System.Soft_Links'Elab_Body;
@@ -28909,14 +28995,8 @@ Ada.Text_Io'Elab_Body;
E07 := True;
@end example
-Here Elab_Spec elaborates the spec
-and Elab_Body elaborates the body. The assignments to the @code{E@emph{xx}} flags
-flag that the corresponding body is now elaborated.
-
-You can also ask the binder to generate a more
-readable list of the elaboration order using the
-@code{-l} switch when invoking the binder. Here is
-an example of the output generated by this switch:
+Note also binder switch @code{-l}, which outputs the chosen elaboration
+order and provides a more readable form of the above:
@example
ada (spec)
@@ -29006,7 +29086,7 @@ gdbstr (body)
@end example
@node Inline Assembler,GNU Free Documentation License,Elaboration Order Handling in GNAT,Top
-@anchor{gnat_ugn/inline_assembler inline-assembler}@anchor{10}@anchor{gnat_ugn/inline_assembler doc}@anchor{24a}@anchor{gnat_ugn/inline_assembler id1}@anchor{24b}
+@anchor{gnat_ugn/inline_assembler inline-assembler}@anchor{10}@anchor{gnat_ugn/inline_assembler doc}@anchor{24e}@anchor{gnat_ugn/inline_assembler id1}@anchor{24f}
@chapter Inline Assembler
@@ -29065,7 +29145,7 @@ and with assembly language programming.
@end menu
@node Basic Assembler Syntax,A Simple Example of Inline Assembler,,Inline Assembler
-@anchor{gnat_ugn/inline_assembler id2}@anchor{24c}@anchor{gnat_ugn/inline_assembler basic-assembler-syntax}@anchor{24d}
+@anchor{gnat_ugn/inline_assembler id2}@anchor{250}@anchor{gnat_ugn/inline_assembler basic-assembler-syntax}@anchor{251}
@section Basic Assembler Syntax
@@ -29181,7 +29261,7 @@ Intel: Destination first; for example @code{mov eax, 4}@w{ }
@node A Simple Example of Inline Assembler,Output Variables in Inline Assembler,Basic Assembler Syntax,Inline Assembler
-@anchor{gnat_ugn/inline_assembler a-simple-example-of-inline-assembler}@anchor{24e}@anchor{gnat_ugn/inline_assembler id3}@anchor{24f}
+@anchor{gnat_ugn/inline_assembler a-simple-example-of-inline-assembler}@anchor{252}@anchor{gnat_ugn/inline_assembler id3}@anchor{253}
@section A Simple Example of Inline Assembler
@@ -29330,7 +29410,7 @@ If there are no errors, @code{as} will generate an object file
@code{nothing.out}.
@node Output Variables in Inline Assembler,Input Variables in Inline Assembler,A Simple Example of Inline Assembler,Inline Assembler
-@anchor{gnat_ugn/inline_assembler id4}@anchor{250}@anchor{gnat_ugn/inline_assembler output-variables-in-inline-assembler}@anchor{251}
+@anchor{gnat_ugn/inline_assembler id4}@anchor{254}@anchor{gnat_ugn/inline_assembler output-variables-in-inline-assembler}@anchor{255}
@section Output Variables in Inline Assembler
@@ -29697,7 +29777,7 @@ end Get_Flags_3;
@end quotation
@node Input Variables in Inline Assembler,Inlining Inline Assembler Code,Output Variables in Inline Assembler,Inline Assembler
-@anchor{gnat_ugn/inline_assembler id5}@anchor{252}@anchor{gnat_ugn/inline_assembler input-variables-in-inline-assembler}@anchor{253}
+@anchor{gnat_ugn/inline_assembler id5}@anchor{256}@anchor{gnat_ugn/inline_assembler input-variables-in-inline-assembler}@anchor{257}
@section Input Variables in Inline Assembler
@@ -29786,7 +29866,7 @@ _increment__incr.1:
@end quotation
@node Inlining Inline Assembler Code,Other Asm Functionality,Input Variables in Inline Assembler,Inline Assembler
-@anchor{gnat_ugn/inline_assembler id6}@anchor{254}@anchor{gnat_ugn/inline_assembler inlining-inline-assembler-code}@anchor{255}
+@anchor{gnat_ugn/inline_assembler id6}@anchor{258}@anchor{gnat_ugn/inline_assembler inlining-inline-assembler-code}@anchor{259}
@section Inlining Inline Assembler Code
@@ -29857,7 +29937,7 @@ movl %esi,%eax
thus saving the overhead of stack frame setup and an out-of-line call.
@node Other Asm Functionality,,Inlining Inline Assembler Code,Inline Assembler
-@anchor{gnat_ugn/inline_assembler other-asm-functionality}@anchor{256}@anchor{gnat_ugn/inline_assembler id7}@anchor{257}
+@anchor{gnat_ugn/inline_assembler other-asm-functionality}@anchor{25a}@anchor{gnat_ugn/inline_assembler id7}@anchor{25b}
@section Other @code{Asm} Functionality
@@ -29872,7 +29952,7 @@ and @code{Volatile}, which inhibits unwanted optimizations.
@end menu
@node The Clobber Parameter,The Volatile Parameter,,Other Asm Functionality
-@anchor{gnat_ugn/inline_assembler the-clobber-parameter}@anchor{258}@anchor{gnat_ugn/inline_assembler id8}@anchor{259}
+@anchor{gnat_ugn/inline_assembler the-clobber-parameter}@anchor{25c}@anchor{gnat_ugn/inline_assembler id8}@anchor{25d}
@subsection The @code{Clobber} Parameter
@@ -29936,7 +30016,7 @@ Use 'register' name @code{memory} if you changed a memory location
@end itemize
@node The Volatile Parameter,,The Clobber Parameter,Other Asm Functionality
-@anchor{gnat_ugn/inline_assembler the-volatile-parameter}@anchor{25a}@anchor{gnat_ugn/inline_assembler id9}@anchor{25b}
+@anchor{gnat_ugn/inline_assembler the-volatile-parameter}@anchor{25e}@anchor{gnat_ugn/inline_assembler id9}@anchor{25f}
@subsection The @code{Volatile} Parameter
@@ -29972,7 +30052,7 @@ to @code{True} only if the compiler's optimizations have created
problems.
@node GNU Free Documentation License,Index,Inline Assembler,Top
-@anchor{share/gnu_free_documentation_license gnu-fdl}@anchor{1}@anchor{share/gnu_free_documentation_license doc}@anchor{25c}@anchor{share/gnu_free_documentation_license gnu-free-documentation-license}@anchor{25d}
+@anchor{share/gnu_free_documentation_license gnu-fdl}@anchor{1}@anchor{share/gnu_free_documentation_license doc}@anchor{260}@anchor{share/gnu_free_documentation_license gnu-free-documentation-license}@anchor{261}
@chapter GNU Free Documentation License
diff --git a/gcc/ada/gnatdll.adb b/gcc/ada/gnatdll.adb
index 94b39b8..736979a 100644
--- a/gcc/ada/gnatdll.adb
+++ b/gcc/ada/gnatdll.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1997-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1997-2017, 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- --
@@ -28,7 +28,7 @@
with Gnatvsn;
with MDLL.Fil; use MDLL.Fil;
-with MDLL.Utl; use MDLL.Utl;
+with MDLL.Utl;
with Switch; use Switch;
with Ada.Text_IO; use Ada.Text_IO;
@@ -41,8 +41,6 @@ with GNAT.Command_Line; use GNAT.Command_Line;
procedure Gnatdll is
- use type GNAT.OS_Lib.Argument_List;
-
procedure Syntax;
-- Print out usage
diff --git a/gcc/ada/gnatfind.adb b/gcc/ada/gnatfind.adb
index 0d030be..9e427ba 100644
--- a/gcc/ada/gnatfind.adb
+++ b/gcc/ada/gnatfind.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1998-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1998-2017, 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- --
@@ -27,7 +27,7 @@ with Opt;
with Osint; use Osint;
with Switch; use Switch;
with Types; use Types;
-with Xr_Tabls; use Xr_Tabls;
+with Xr_Tabls;
with Xref_Lib; use Xref_Lib;
with Ada.Command_Line; use Ada.Command_Line;
diff --git a/gcc/ada/gnatlink.adb b/gcc/ada/gnatlink.adb
index 073c2c9..5e290eb 100644
--- a/gcc/ada/gnatlink.adb
+++ b/gcc/ada/gnatlink.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1996-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1996-2017, 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- --
@@ -37,7 +37,7 @@ with Snames;
with Switch; use Switch;
with System; use System;
with Table;
-with Targparm; use Targparm;
+with Targparm;
with Types;
with Ada.Command_Line; use Ada.Command_Line;
diff --git a/gcc/ada/gnatls.adb b/gcc/ada/gnatls.adb
index a120ee4..f45305f 100644
--- a/gcc/ada/gnatls.adb
+++ b/gcc/ada/gnatls.adb
@@ -29,7 +29,7 @@ with ALI; use ALI;
with ALI.Util; use ALI.Util;
with Binderr; use Binderr;
with Butil; use Butil;
-with Csets; use Csets;
+with Csets;
with Fname; use Fname;
with Gnatvsn; use Gnatvsn;
with Make_Util; use Make_Util;
@@ -2097,6 +2097,7 @@ begin
if RTS_Specified = null then
declare
+ FD : File_Descriptor;
Text : Source_Buffer_Ptr;
Hi : Source_Ptr;
@@ -2104,7 +2105,7 @@ begin
Name_Buffer (1 .. 10) := "system.ads";
Name_Len := 10;
- Read_Source_File (Name_Find, Lo => 0, Hi => Hi, Src => Text);
+ Read_Source_File (Name_Find, 0, Hi, Text, FD);
if Null_Source_Buffer_Ptr (Text) then
No_Runtime := True;
diff --git a/gcc/ada/gnatname.adb b/gcc/ada/gnatname.adb
index 7540a1e..4a9973f 100644
--- a/gcc/ada/gnatname.adb
+++ b/gcc/ada/gnatname.adb
@@ -36,7 +36,7 @@ with Make_Util; use Make_Util;
with Namet; use Namet;
with Opt;
with Osint; use Osint;
-with Output; use Output;
+with Output;
with Switch; use Switch;
with Table;
with Tempdir;
diff --git a/gcc/ada/gnatxref.adb b/gcc/ada/gnatxref.adb
index c24fd49..e458d03 100644
--- a/gcc/ada/gnatxref.adb
+++ b/gcc/ada/gnatxref.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1998-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1998-2017, 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- --
@@ -27,11 +27,11 @@ with Opt;
with Osint; use Osint;
with Types; use Types;
with Switch; use Switch;
-with Xr_Tabls; use Xr_Tabls;
+with Xr_Tabls;
with Xref_Lib; use Xref_Lib;
with Ada.Command_Line; use Ada.Command_Line;
-with Ada.Strings.Fixed; use Ada.Strings.Fixed;
+with Ada.Strings.Fixed;
with Ada.Text_IO; use Ada.Text_IO;
with GNAT.Command_Line; use GNAT.Command_Line;
diff --git a/gcc/ada/gprep.adb b/gcc/ada/gprep.adb
index cc7e243..825a537 100644
--- a/gcc/ada/gprep.adb
+++ b/gcc/ada/gprep.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2002-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 2002-2017, 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- --
@@ -249,6 +249,10 @@ package body GPrep is
Fail ("unable to find definition file """
& Get_Name_String (Deffile_Name)
& """");
+ elsif Deffile = No_Access_To_Source_File then
+ Fail ("unabled to read definition file """
+ & Get_Name_String (Deffile_Name)
+ & """");
end if;
Scanner.Initialize_Scanner (Deffile);
@@ -514,6 +518,10 @@ package body GPrep is
Fail ("unable to find input file """
& Get_Name_String (Infile_Name)
& """");
+ elsif Infile = No_Access_To_Source_File then
+ Fail ("unable to read input file """
+ & Get_Name_String (Infile_Name)
+ & """");
end if;
-- Set Main_Source_File to the input file for the benefit of
diff --git a/gcc/ada/layout.adb b/gcc/ada/layout.adb
index 34c5b5d..52e8452 100644
--- a/gcc/ada/layout.adb
+++ b/gcc/ada/layout.adb
@@ -843,7 +843,7 @@ package body Layout is
-- Set_Elem_Alignment --
------------------------
- procedure Set_Elem_Alignment (E : Entity_Id) is
+ procedure Set_Elem_Alignment (E : Entity_Id; Align : Nat := 0) is
begin
-- Do not set alignment for packed array types, this is handled in the
-- backend.
@@ -869,15 +869,12 @@ package body Layout is
return;
end if;
- -- Here we calculate the alignment as the largest power of two multiple
- -- of System.Storage_Unit that does not exceed either the object size of
- -- the type, or the maximum allowed alignment.
+ -- We attempt to set the alignment in all the other cases
declare
S : Int;
A : Nat;
-
- Max_Alignment : Nat;
+ M : Nat;
begin
-- The given Esize may be larger that int'last because of a previous
@@ -908,7 +905,7 @@ package body Layout is
and then S = 8
and then Is_Floating_Point_Type (E)
then
- Max_Alignment := Ttypes.Target_Double_Float_Alignment;
+ M := Ttypes.Target_Double_Float_Alignment;
-- If the default alignment of "double" or larger scalar types is
-- specifically capped, enforce the cap.
@@ -917,18 +914,27 @@ package body Layout is
and then S >= 8
and then Is_Scalar_Type (E)
then
- Max_Alignment := Ttypes.Target_Double_Scalar_Alignment;
+ M := Ttypes.Target_Double_Scalar_Alignment;
-- Otherwise enforce the overall alignment cap
else
- Max_Alignment := Ttypes.Maximum_Alignment;
+ M := Ttypes.Maximum_Alignment;
end if;
- A := 1;
- while 2 * A <= Max_Alignment and then 2 * A <= S loop
- A := 2 * A;
- end loop;
+ -- We calculate the alignment as the largest power-of-two multiple
+ -- of System.Storage_Unit that does not exceed the object size of
+ -- the type and the maximum allowed alignment, if none was specified.
+ -- Otherwise we only cap it to the maximum allowed alignment.
+
+ if Align = 0 then
+ A := 1;
+ while 2 * A <= S and then 2 * A <= M loop
+ A := 2 * A;
+ end loop;
+ else
+ A := Nat'Min (Align, M);
+ end if;
-- If alignment is currently not set, then we can safely set it to
-- this new calculated value.
diff --git a/gcc/ada/layout.ads b/gcc/ada/layout.ads
index 57aa93e4..246970f 100644
--- a/gcc/ada/layout.ads
+++ b/gcc/ada/layout.ads
@@ -74,10 +74,11 @@ package Layout is
-- types, the RM_Size is simply set to zero. This routine also sets
-- the Is_Constrained flag in Def_Id.
- procedure Set_Elem_Alignment (E : Entity_Id);
+ procedure Set_Elem_Alignment (E : Entity_Id; Align : Nat := 0);
-- The front end always sets alignments for elementary types by calling
-- this procedure. Note that we have to do this for discrete types (since
-- the Alignment attribute is static), so we might as well do it for all
- -- elementary types, since the processing is the same.
+ -- elementary types, as the processing is the same. If Align is nonzero,
+ -- it is an external alignment setting that we must respect.
end Layout;
diff --git a/gcc/ada/lib-load.adb b/gcc/ada/lib-load.adb
index f509721..0b0ea7f 100644
--- a/gcc/ada/lib-load.adb
+++ b/gcc/ada/lib-load.adb
@@ -122,7 +122,7 @@ package body Lib.Load is
-- No change if we did not find the spec
- if X = No_Source_File then
+ if X <= No_Source_File then
return;
end if;
@@ -214,34 +214,36 @@ package body Lib.Load is
Unum := Units.Last;
Units.Table (Unum) :=
- (Cunit => Cunit,
- Cunit_Entity => Cunit_Entity,
- Dependency_Num => 0,
- Dynamic_Elab => False,
- Error_Location => Sloc (With_Node),
- Expected_Unit => Spec_Name,
- Fatal_Error => Error_Detected,
- Generate_Code => False,
- Has_RACW => False,
- Filler => False,
- Ident_String => Empty,
+ (Cunit => Cunit,
+ Cunit_Entity => Cunit_Entity,
+ Dependency_Num => 0,
+ Dynamic_Elab => False,
+ Error_Location => Sloc (With_Node),
+ Expected_Unit => Spec_Name,
+ Fatal_Error => Error_Detected,
+ Generate_Code => False,
+ Has_RACW => False,
+ Filler => False,
+ Ident_String => Empty,
Is_Predefined_Renaming => Ren_Name,
Is_Predefined_Unit => Pre_Name or Ren_Name,
Is_Internal_Unit => Pre_Name or Ren_Name or GNAT_Name,
Filler2 => False,
- Loading => False,
- Main_Priority => Default_Main_Priority,
- Main_CPU => Default_Main_CPU,
- Munit_Index => 0,
- No_Elab_Code_All => False,
- Serial_Number => 0,
- Source_Index => No_Source_File,
- Unit_File_Name => Fname,
- Unit_Name => Spec_Name,
- Version => 0,
- OA_Setting => 'O');
+ Loading => False,
+ Main_Priority => Default_Main_Priority,
+ Main_CPU => Default_Main_CPU,
+ Primary_Stack_Count => 0,
+ Sec_Stack_Count => 0,
+ Munit_Index => 0,
+ No_Elab_Code_All => False,
+ Serial_Number => 0,
+ Source_Index => No_Source_File,
+ Unit_File_Name => Fname,
+ Unit_Name => Spec_Name,
+ Version => 0,
+ OA_Setting => 'O');
Set_Comes_From_Source_Default (Save_CS);
Set_Error_Posted (Cunit_Entity);
@@ -326,48 +328,61 @@ package body Lib.Load is
Main_Source_File := Load_Source_File (Fname);
Current_Error_Source_File := Main_Source_File;
- if Main_Source_File /= No_Source_File then
+ if Main_Source_File > No_Source_File then
Version := Source_Checksum (Main_Source_File);
+
else
-- To avoid emitting a source location (since there is no file),
-- we write a custom error message instead of using the machinery
-- in errout.adb.
Set_Standard_Error;
- Write_Str ("file """ & Get_Name_String (Fname) & """ not found");
+
+ if Main_Source_File = No_Access_To_Source_File then
+ Write_Str
+ ("no read access for file """ & Get_Name_String (Fname)
+ & """");
+ else
+ Write_Str
+ ("file """ & Get_Name_String (Fname) & """ not found");
+ end if;
+
Write_Eol;
Set_Standard_Output;
end if;
Units.Table (Main_Unit) :=
- (Cunit => Empty,
- Cunit_Entity => Empty,
- Dependency_Num => 0,
- Dynamic_Elab => False,
- Error_Location => No_Location,
- Expected_Unit => No_Unit_Name,
- Fatal_Error => None,
- Generate_Code => False,
- Has_RACW => False,
- Filler => False,
- Ident_String => Empty,
+ (Cunit => Empty,
+ Cunit_Entity => Empty,
+ Dependency_Num => 0,
+ Dynamic_Elab => False,
+ Error_Location => No_Location,
+ Expected_Unit => No_Unit_Name,
+ Fatal_Error => None,
+ Generate_Code => False,
+ Has_RACW => False,
+ Filler => False,
+ Ident_String => Empty,
Is_Predefined_Renaming => Ren_Name,
Is_Predefined_Unit => Pre_Name or Ren_Name,
Is_Internal_Unit => Pre_Name or Ren_Name or GNAT_Name,
Filler2 => False,
- Loading => True,
- Main_Priority => Default_Main_Priority,
- Main_CPU => Default_Main_CPU,
- Munit_Index => 0,
- No_Elab_Code_All => False,
- Serial_Number => 0,
- Source_Index => Main_Source_File,
- Unit_File_Name => Fname,
- Unit_Name => No_Unit_Name,
- Version => Version,
- OA_Setting => 'O');
+ Loading => True,
+ Main_Priority => Default_Main_Priority,
+ Main_CPU => Default_Main_CPU,
+ Primary_Stack_Count => 0,
+ Sec_Stack_Count => 0,
+
+ Munit_Index => 0,
+ No_Elab_Code_All => False,
+ Serial_Number => 0,
+ Source_Index => Main_Source_File,
+ Unit_File_Name => Fname,
+ Unit_Name => No_Unit_Name,
+ Version => Version,
+ OA_Setting => 'O');
end if;
end Load_Main_Source;
@@ -716,36 +731,38 @@ package body Lib.Load is
-- File was found
- if Src_Ind /= No_Source_File then
+ if Src_Ind > No_Source_File then
Units.Table (Unum) :=
- (Cunit => Empty,
- Cunit_Entity => Empty,
- Dependency_Num => 0,
- Dynamic_Elab => False,
- Error_Location => Sloc (Error_Node),
- Expected_Unit => Uname_Actual,
- Fatal_Error => None,
- Generate_Code => False,
- Has_RACW => False,
- Filler => False,
- Ident_String => Empty,
+ (Cunit => Empty,
+ Cunit_Entity => Empty,
+ Dependency_Num => 0,
+ Dynamic_Elab => False,
+ Error_Location => Sloc (Error_Node),
+ Expected_Unit => Uname_Actual,
+ Fatal_Error => None,
+ Generate_Code => False,
+ Has_RACW => False,
+ Filler => False,
+ Ident_String => Empty,
Is_Predefined_Renaming => Ren_Name,
Is_Predefined_Unit => Pre_Name or Ren_Name,
Is_Internal_Unit => Pre_Name or Ren_Name or GNAT_Name,
Filler2 => False,
- Loading => True,
- Main_Priority => Default_Main_Priority,
- Main_CPU => Default_Main_CPU,
- Munit_Index => 0,
- No_Elab_Code_All => False,
- Serial_Number => 0,
- Source_Index => Src_Ind,
- Unit_File_Name => Fname,
- Unit_Name => Uname_Actual,
- Version => Source_Checksum (Src_Ind),
- OA_Setting => 'O');
+ Loading => True,
+ Main_Priority => Default_Main_Priority,
+ Main_CPU => Default_Main_CPU,
+ Primary_Stack_Count => 0,
+ Sec_Stack_Count => 0,
+ Munit_Index => 0,
+ No_Elab_Code_All => False,
+ Serial_Number => 0,
+ Source_Index => Src_Ind,
+ Unit_File_Name => Fname,
+ Unit_Name => Uname_Actual,
+ Version => Source_Checksum (Src_Ind),
+ OA_Setting => 'O');
-- Parse the new unit
@@ -824,7 +841,12 @@ package body Lib.Load is
else
if Debug_Flag_L then
- Write_Str (" file was not found, load failed");
+ if Src_Ind = No_Access_To_Source_File then
+ Write_Str (" no read access to file, load failed");
+ else
+ Write_Str (" file was not found, load failed");
+ end if;
+
Write_Eol;
end if;
@@ -857,7 +879,12 @@ package body Lib.Load is
else
Error_Msg_File_1 := Fname;
- Error_Msg ("file{ not found", Load_Msg_Sloc);
+
+ if Src_Ind = No_Access_To_Source_File then
+ Error_Msg ("no read access to file{", Load_Msg_Sloc);
+ else
+ Error_Msg ("file{ not found", Load_Msg_Sloc);
+ end if;
end if;
Write_Dependency_Chain;
@@ -983,7 +1010,7 @@ package body Lib.Load is
Unum : constant Unit_Number_Type := Get_Cunit_Unit_Number (U);
Fnum : constant Unit_Number_Type := Get_Cunit_Unit_Number (From);
begin
- if Source_Index (Fnum) /= No_Source_File then
+ if Source_Index (Fnum) > No_Source_File then
Units.Table (Unum).Version :=
Units.Table (Unum).Version
xor
diff --git a/gcc/ada/lib-writ.adb b/gcc/ada/lib-writ.adb
index 8c36957..47109b4 100644
--- a/gcc/ada/lib-writ.adb
+++ b/gcc/ada/lib-writ.adb
@@ -96,6 +96,8 @@ package body Lib.Writ is
Main_CPU => -1,
Munit_Index => 0,
No_Elab_Code_All => False,
+ Primary_Stack_Count => 0,
+ Sec_Stack_Count => 0,
Serial_Number => 0,
Version => 0,
Error_Location => No_Location,
@@ -157,6 +159,8 @@ package body Lib.Writ is
Main_CPU => -1,
Munit_Index => 0,
No_Elab_Code_All => False,
+ Primary_Stack_Count => 0,
+ Sec_Stack_Count => 0,
Serial_Number => 0,
Version => 0,
Error_Location => No_Location,
@@ -616,6 +620,19 @@ package body Lib.Writ is
Write_With_Lines;
+ -- Generate task stack lines
+
+ if Primary_Stack_Count (Unit_Num) > 0
+ or else Sec_Stack_Count (Unit_Num) > 0
+ then
+ Write_Info_Initiate ('T');
+ Write_Info_Char (' ');
+ Write_Info_Int (Primary_Stack_Count (Unit_Num));
+ Write_Info_Char (' ');
+ Write_Info_Int (Sec_Stack_Count (Unit_Num));
+ Write_Info_EOL;
+ end if;
+
-- Generate the linker option lines
for J in 1 .. Linker_Option_Lines.Last loop
@@ -1464,7 +1481,7 @@ package body Lib.Writ is
-- Normal case of a unit entry with a source index
- if Sind /= No_Source_File then
+ if Sind > No_Source_File then
Fname := File_Name (Sind);
-- Ensure that on platforms where the file names are not case
diff --git a/gcc/ada/lib-writ.ads b/gcc/ada/lib-writ.ads
index f113b0a..a959e94 100644
--- a/gcc/ada/lib-writ.ads
+++ b/gcc/ada/lib-writ.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -670,14 +670,33 @@ package Lib.Writ is
-- binder do the consistency check, but not include the unit in the
-- partition closure (unless it is properly With'ed somewhere).
+ -- --------------------
+ -- -- T Task Stacks --
+ -- --------------------
+
+ -- Following the W lines (if any, or the U line if not), is an optional
+ -- line that identifies the number of default-sized primary and secondary
+ -- stacks that the binder needs to create for the tasks declared within the
+ -- unit. For each compilation unit, a line is present in the form:
+
+ -- T primary-stack-quantity secondary-stack-quantity
+
+ -- The first parameter of T defines the number of task objects declared
+ -- in the unit that have no Storage_Size specified. The second parameter
+ -- defines the number of task objects declared in the unit that have no
+ -- Secondary_Stack_Size specified. These values are non-zero only if
+ -- the restrictions No_Implicit_Heap_Allocations or
+ -- No_Implicit_Task_Allocations are active.
+
-- -----------------------
-- -- L Linker_Options --
-- -----------------------
- -- Following the W lines (if any, or the U line if not), are an optional
- -- series of lines that indicates the usage of the pragma Linker_Options in
- -- the associated unit. For each appearance of a pragma Linker_Options (or
- -- Link_With) in the unit, a line is present with the form:
+ -- Following the T and W lines (if any, or the U line if not), are
+ -- an optional series of lines that indicates the usage of the pragma
+ -- Linker_Options in the associated unit. For each appearance of a pragma
+ -- Linker_Options (or Link_With) in the unit, a line is present with the
+ -- form:
-- L "string"
diff --git a/gcc/ada/lib-xref-spark_specific.adb b/gcc/ada/lib-xref-spark_specific.adb
index b6ddd93..4d22174 100644
--- a/gcc/ada/lib-xref-spark_specific.adb
+++ b/gcc/ada/lib-xref-spark_specific.adb
@@ -249,7 +249,7 @@ package body SPARK_Specific is
-- Source file could be inexistant as a result of an error, if option
-- gnatQ is used.
- if File = No_Source_File then
+ if File <= No_Source_File then
return;
end if;
diff --git a/gcc/ada/lib-xref.ads b/gcc/ada/lib-xref.ads
index ecb70b6..d421639 100644
--- a/gcc/ada/lib-xref.ads
+++ b/gcc/ada/lib-xref.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1998-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1998-2017, 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- --
@@ -611,7 +611,8 @@ package Lib.Xref is
Table_Name => "Name_Deferred_References");
procedure Process_Deferred_References;
- -- This procedure is called from Frontend to process these table entries
+ -- This procedure is called from Frontend to process these table entries.
+ -- It is also called from Sem_Warn.
function Has_Deferred_Reference (Ent : Entity_Id) return Boolean;
-- Determine whether arbitrary entity Ent has a pending reference in order
diff --git a/gcc/ada/lib.adb b/gcc/ada/lib.adb
index 16c8afc..02eb198 100644
--- a/gcc/ada/lib.adb
+++ b/gcc/ada/lib.adb
@@ -62,7 +62,9 @@ package body Lib is
Yes_After, -- S1 is in same extended unit as S2, and appears after it
No); -- S2 is not in same extended unit as S2
- function Check_Same_Extended_Unit (S1, S2 : Source_Ptr) return SEU_Result;
+ function Check_Same_Extended_Unit
+ (S1 : Source_Ptr;
+ S2 : Source_Ptr) return SEU_Result;
-- Used by In_Same_Extended_Unit and Earlier_In_Extended_Unit. Returns
-- value as described above.
@@ -176,6 +178,16 @@ package body Lib is
return Units.Table (U).OA_Setting;
end OA_Setting;
+ function Primary_Stack_Count (U : Unit_Number_Type) return Int is
+ begin
+ return Units.Table (U).Primary_Stack_Count;
+ end Primary_Stack_Count;
+
+ function Sec_Stack_Count (U : Unit_Number_Type) return Int is
+ begin
+ return Units.Table (U).Sec_Stack_Count;
+ end Sec_Stack_Count;
+
function Source_Index (U : Unit_Number_Type) return Source_File_Index is
begin
return Units.Table (U).Source_Index;
@@ -273,7 +285,10 @@ package body Lib is
-- Check_Same_Extended_Unit --
------------------------------
- function Check_Same_Extended_Unit (S1, S2 : Source_Ptr) return SEU_Result is
+ function Check_Same_Extended_Unit
+ (S1 : Source_Ptr;
+ S2 : Source_Ptr) return SEU_Result
+ is
Max_Iterations : constant Nat := Maximum_Instantiations * 2;
-- Limit to prevent a potential infinite loop
@@ -459,6 +474,7 @@ package body Lib is
-- Prevent looping forever
if Counter > Max_Iterations then
+
-- ??? Not quite right, but return a value to be able to generate
-- SCIL files and hope for the best.
@@ -502,11 +518,22 @@ package body Lib is
-- Earlier_In_Extended_Unit --
------------------------------
- function Earlier_In_Extended_Unit (S1, S2 : Source_Ptr) return Boolean is
+ function Earlier_In_Extended_Unit
+ (S1 : Source_Ptr;
+ S2 : Source_Ptr) return Boolean
+ is
begin
return Check_Same_Extended_Unit (S1, S2) = Yes_Before;
end Earlier_In_Extended_Unit;
+ function Earlier_In_Extended_Unit
+ (N1 : Node_Or_Entity_Id;
+ N2 : Node_Or_Entity_Id) return Boolean
+ is
+ begin
+ return Earlier_In_Extended_Unit (Sloc (N1), Sloc (N2));
+ end Earlier_In_Extended_Unit;
+
-----------------------
-- Exact_Source_Name --
-----------------------
@@ -626,7 +653,7 @@ package body Lib is
Source_File := Get_Source_File_Index (S);
if Unwind_Instances then
- while Template (Source_File) /= No_Source_File loop
+ while Template (Source_File) > No_Source_File loop
Source_File := Template (Source_File);
end loop;
end if;
@@ -747,7 +774,9 @@ package body Lib is
begin
return
Get_Code_Or_Source_Unit
- (S, Unwind_Instances => True, Unwind_Subunits => False);
+ (S => S,
+ Unwind_Instances => True,
+ Unwind_Subunits => False);
end Get_Source_Unit;
function Get_Source_Unit (N : Node_Or_Entity_Id) return Unit_Number_Type is
@@ -807,8 +836,7 @@ package body Lib is
-- Node may be in spec (or subunit etc) of main unit
else
- return
- In_Same_Extended_Unit (N, Cunit (Main_Unit));
+ return In_Same_Extended_Unit (N, Cunit (Main_Unit));
end if;
end In_Extended_Main_Code_Unit;
@@ -828,8 +856,7 @@ package body Lib is
-- Location may be in spec (or subunit etc) of main unit
else
- return
- In_Same_Extended_Unit (Loc, Sloc (Cunit (Main_Unit)));
+ return In_Same_Extended_Unit (Loc, Sloc (Cunit (Main_Unit)));
end if;
end In_Extended_Main_Code_Unit;
@@ -1010,6 +1037,26 @@ package body Lib is
return Get_Source_Unit (N1) = Get_Source_Unit (N2);
end In_Same_Source_Unit;
+ -----------------------------------
+ -- Increment_Primary_Stack_Count --
+ -----------------------------------
+
+ procedure Increment_Primary_Stack_Count (Increment : Int) is
+ PSC : Int renames Units.Table (Current_Sem_Unit).Primary_Stack_Count;
+ begin
+ PSC := PSC + Increment;
+ end Increment_Primary_Stack_Count;
+
+ -------------------------------
+ -- Increment_Sec_Stack_Count --
+ -------------------------------
+
+ procedure Increment_Sec_Stack_Count (Increment : Int) is
+ SSC : Int renames Units.Table (Current_Sem_Unit).Sec_Stack_Count;
+ begin
+ SSC := SSC + Increment;
+ end Increment_Sec_Stack_Count;
+
-----------------------------
-- Increment_Serial_Number --
-----------------------------
diff --git a/gcc/ada/lib.ads b/gcc/ada/lib.ads
index a5b9858..c968699 100644
--- a/gcc/ada/lib.ads
+++ b/gcc/ada/lib.ads
@@ -370,6 +370,20 @@ package Lib is
-- This is a character field containing L if Optimize_Alignment mode
-- was set locally, and O/T/S for Off/Time/Space default if not.
+ -- Primary_Stack_Count
+ -- The number of primary stacks belonging to tasks defined within the
+ -- unit that have no Storage_Size specified when the either restriction
+ -- No_Implicit_Heap_Allocations or No_Implicit_Task_Allocations is
+ -- active. Only used by the binder to generate stacks for these tasks
+ -- at bind time.
+
+ -- Sec_Stack_Count
+ -- The number of secondary stacks belonging to tasks defined within the
+ -- unit that have no Secondary_Stack_Size specified when the either
+ -- the No_Implicit_Heap_Allocations or No_Implicit_Task_Allocations
+ -- restrictions are active. Only used by the binder to generate stacks
+ -- for these tasks at bind time.
+
-- Serial_Number
-- This field holds a serial number used by New_Internal_Name to
-- generate unique temporary numbers on a unit by unit basis. The
@@ -441,15 +455,20 @@ package Lib is
function Generate_Code (U : Unit_Number_Type) return Boolean;
function Ident_String (U : Unit_Number_Type) return Node_Id;
function Has_RACW (U : Unit_Number_Type) return Boolean;
- function Is_Predefined_Renaming (U : Unit_Number_Type) return Boolean;
- function Is_Internal_Unit (U : Unit_Number_Type) return Boolean;
- function Is_Predefined_Unit (U : Unit_Number_Type) return Boolean;
+ function Is_Predefined_Renaming
+ (U : Unit_Number_Type) return Boolean;
+ function Is_Internal_Unit (U : Unit_Number_Type) return Boolean;
+ function Is_Predefined_Unit
+ (U : Unit_Number_Type) return Boolean;
function Loading (U : Unit_Number_Type) return Boolean;
function Main_CPU (U : Unit_Number_Type) return Int;
function Main_Priority (U : Unit_Number_Type) return Int;
function Munit_Index (U : Unit_Number_Type) return Nat;
function No_Elab_Code_All (U : Unit_Number_Type) return Boolean;
function OA_Setting (U : Unit_Number_Type) return Character;
+ function Primary_Stack_Count
+ (U : Unit_Number_Type) return Int;
+ function Sec_Stack_Count (U : Unit_Number_Type) return Int;
function Source_Index (U : Unit_Number_Type) return Source_File_Index;
function Unit_File_Name (U : Unit_Number_Type) return File_Name_Type;
function Unit_Name (U : Unit_Number_Type) return Unit_Name_Type;
@@ -481,13 +500,20 @@ package Lib is
-- avoid registering switches added automatically by the gcc driver at the
-- end of the command line.
- function Earlier_In_Extended_Unit (S1, S2 : Source_Ptr) return Boolean;
+ function Earlier_In_Extended_Unit
+ (S1 : Source_Ptr;
+ S2 : Source_Ptr) return Boolean;
-- Given two Sloc values for which In_Same_Extended_Unit is true, determine
-- if S1 appears before S2. Returns True if S1 appears before S2, and False
-- otherwise. The result is undefined if S1 and S2 are not in the same
-- extended unit. Note: this routine will not give reliable results if
-- called after Sprint has been called with -gnatD set.
+ function Earlier_In_Extended_Unit
+ (N1 : Node_Or_Entity_Id;
+ N2 : Node_Or_Entity_Id) return Boolean;
+ -- Same as above, but the inputs denote nodes or entities
+
procedure Enable_Switch_Storing;
-- Enable registration of switches by Store_Compilation_Switch. Used to
-- avoid registering switches added automatically by the gcc driver at the
@@ -655,6 +681,13 @@ package Lib is
-- source unit, the criterion being that Get_Source_Unit yields the
-- same value for each argument.
+ procedure Increment_Primary_Stack_Count (Increment : Int);
+ -- Increment the Primary_Stack_Count field for the current unit by
+ -- Increment.
+
+ procedure Increment_Sec_Stack_Count (Increment : Int);
+ -- Increment the Sec_Stack_Count field for the current unit by Increment
+
function Increment_Serial_Number return Nat;
-- Increment Serial_Number field for current unit, and return the
-- incremented value.
@@ -787,6 +820,8 @@ private
pragma Inline (Fatal_Error);
pragma Inline (Generate_Code);
pragma Inline (Has_RACW);
+ pragma Inline (Increment_Primary_Stack_Count);
+ pragma Inline (Increment_Sec_Stack_Count);
pragma Inline (Increment_Serial_Number);
pragma Inline (Loading);
pragma Inline (Main_CPU);
@@ -802,6 +837,8 @@ private
pragma Inline (Is_Predefined_Renaming);
pragma Inline (Is_Internal_Unit);
pragma Inline (Is_Predefined_Unit);
+ pragma Inline (Primary_Stack_Count);
+ pragma Inline (Sec_Stack_Count);
pragma Inline (Set_Loading);
pragma Inline (Set_Main_CPU);
pragma Inline (Set_Main_Priority);
@@ -815,28 +852,30 @@ private
-- The Units Table
type Unit_Record is record
- Unit_File_Name : File_Name_Type;
- Unit_Name : Unit_Name_Type;
- Munit_Index : Nat;
- Expected_Unit : Unit_Name_Type;
- Source_Index : Source_File_Index;
- Cunit : Node_Id;
- Cunit_Entity : Entity_Id;
- Dependency_Num : Int;
- Ident_String : Node_Id;
- Main_Priority : Int;
- Main_CPU : Int;
- Serial_Number : Nat;
- Version : Word;
- Error_Location : Source_Ptr;
- Fatal_Error : Fatal_Type;
- Generate_Code : Boolean;
- Has_RACW : Boolean;
- Dynamic_Elab : Boolean;
- No_Elab_Code_All : Boolean;
- Filler : Boolean;
- Loading : Boolean;
- OA_Setting : Character;
+ Unit_File_Name : File_Name_Type;
+ Unit_Name : Unit_Name_Type;
+ Munit_Index : Nat;
+ Expected_Unit : Unit_Name_Type;
+ Source_Index : Source_File_Index;
+ Cunit : Node_Id;
+ Cunit_Entity : Entity_Id;
+ Dependency_Num : Int;
+ Ident_String : Node_Id;
+ Main_Priority : Int;
+ Main_CPU : Int;
+ Primary_Stack_Count : Int;
+ Sec_Stack_Count : Int;
+ Serial_Number : Nat;
+ Version : Word;
+ Error_Location : Source_Ptr;
+ Fatal_Error : Fatal_Type;
+ Generate_Code : Boolean;
+ Has_RACW : Boolean;
+ Dynamic_Elab : Boolean;
+ No_Elab_Code_All : Boolean;
+ Filler : Boolean;
+ Loading : Boolean;
+ OA_Setting : Character;
Is_Predefined_Renaming : Boolean;
Is_Internal_Unit : Boolean;
@@ -849,36 +888,38 @@ private
-- written by Tree_Gen, we do not write uninitialized values to the file.
for Unit_Record use record
- Unit_File_Name at 0 range 0 .. 31;
- Unit_Name at 4 range 0 .. 31;
- Munit_Index at 8 range 0 .. 31;
- Expected_Unit at 12 range 0 .. 31;
- Source_Index at 16 range 0 .. 31;
- Cunit at 20 range 0 .. 31;
- Cunit_Entity at 24 range 0 .. 31;
- Dependency_Num at 28 range 0 .. 31;
- Ident_String at 32 range 0 .. 31;
- Main_Priority at 36 range 0 .. 31;
- Main_CPU at 40 range 0 .. 31;
- Serial_Number at 44 range 0 .. 31;
- Version at 48 range 0 .. 31;
- Error_Location at 52 range 0 .. 31;
- Fatal_Error at 56 range 0 .. 7;
- Generate_Code at 57 range 0 .. 7;
- Has_RACW at 58 range 0 .. 7;
- Dynamic_Elab at 59 range 0 .. 7;
- No_Elab_Code_All at 60 range 0 .. 7;
- Filler at 61 range 0 .. 7;
- OA_Setting at 62 range 0 .. 7;
- Loading at 63 range 0 .. 7;
-
- Is_Predefined_Renaming at 64 range 0 .. 7;
- Is_Internal_Unit at 65 range 0 .. 7;
- Is_Predefined_Unit at 66 range 0 .. 7;
- Filler2 at 67 range 0 .. 7;
+ Unit_File_Name at 0 range 0 .. 31;
+ Unit_Name at 4 range 0 .. 31;
+ Munit_Index at 8 range 0 .. 31;
+ Expected_Unit at 12 range 0 .. 31;
+ Source_Index at 16 range 0 .. 31;
+ Cunit at 20 range 0 .. 31;
+ Cunit_Entity at 24 range 0 .. 31;
+ Dependency_Num at 28 range 0 .. 31;
+ Ident_String at 32 range 0 .. 31;
+ Main_Priority at 36 range 0 .. 31;
+ Main_CPU at 40 range 0 .. 31;
+ Primary_Stack_Count at 44 range 0 .. 31;
+ Sec_Stack_Count at 48 range 0 .. 31;
+ Serial_Number at 52 range 0 .. 31;
+ Version at 56 range 0 .. 31;
+ Error_Location at 60 range 0 .. 31;
+ Fatal_Error at 64 range 0 .. 7;
+ Generate_Code at 65 range 0 .. 7;
+ Has_RACW at 66 range 0 .. 7;
+ Dynamic_Elab at 67 range 0 .. 7;
+ No_Elab_Code_All at 68 range 0 .. 7;
+ Filler at 69 range 0 .. 7;
+ OA_Setting at 70 range 0 .. 7;
+ Loading at 71 range 0 .. 7;
+
+ Is_Predefined_Renaming at 72 range 0 .. 7;
+ Is_Internal_Unit at 73 range 0 .. 7;
+ Is_Predefined_Unit at 74 range 0 .. 7;
+ Filler2 at 75 range 0 .. 7;
end record;
- for Unit_Record'Size use 68 * 8;
+ for Unit_Record'Size use 76 * 8;
-- This ensures that we did not leave out any fields
package Units is new Table.Table (
diff --git a/gcc/ada/libgnarl/a-exetim__darwin.adb b/gcc/ada/libgnarl/a-exetim__darwin.adb
index a417d91..cb3a55a 100644
--- a/gcc/ada/libgnarl/a-exetim__darwin.adb
+++ b/gcc/ada/libgnarl/a-exetim__darwin.adb
@@ -189,7 +189,6 @@ package body Ada.Execution_Time is
SC : out Ada.Real_Time.Seconds_Count;
TS : out Ada.Real_Time.Time_Span)
is
- use type Ada.Real_Time.Time;
begin
Ada.Real_Time.Split (Ada.Real_Time.Time (T), SC, TS);
end Split;
diff --git a/gcc/ada/libgnarl/a-exetim__mingw.adb b/gcc/ada/libgnarl/a-exetim__mingw.adb
index 264ba9d..7555b16 100644
--- a/gcc/ada/libgnarl/a-exetim__mingw.adb
+++ b/gcc/ada/libgnarl/a-exetim__mingw.adb
@@ -153,7 +153,6 @@ is
SC : out Ada.Real_Time.Seconds_Count;
TS : out Ada.Real_Time.Time_Span)
is
- use type Ada.Real_Time.Time;
begin
Ada.Real_Time.Split (Ada.Real_Time.Time (T), SC, TS);
end Split;
diff --git a/gcc/ada/libgnarl/s-intman__vxworks.adb b/gcc/ada/libgnarl/s-intman__vxworks.adb
index 67f7db3..62f9711 100644
--- a/gcc/ada/libgnarl/s-intman__vxworks.adb
+++ b/gcc/ada/libgnarl/s-intman__vxworks.adb
@@ -37,7 +37,6 @@
package body System.Interrupt_Management is
use System.OS_Interface;
- use type Interfaces.C.int;
-----------------------
-- Local Subprograms --
diff --git a/gcc/ada/libgnarl/s-linux__x32.ads b/gcc/ada/libgnarl/s-linux__x32.ads
index 823d806..ad9a7b9 100644
--- a/gcc/ada/libgnarl/s-linux__x32.ads
+++ b/gcc/ada/libgnarl/s-linux__x32.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 2013-2017, Free Software Foundation, Inc. --
+-- Copyright (C) 2013-2017, Free Software Foundation, Inc. --
--
-- --
-- GNARL is free software; you can redistribute it and/or modify it under --
@@ -45,8 +45,9 @@ package System.Linux is
-- Time --
----------
- type time_t is new Long_Long_Integer;
- subtype clockid_t is Interfaces.C.int;
+ subtype suseconds_t is Long_Long_Integer;
+ subtype time_t is Long_Long_Integer;
+ subtype clockid_t is Interfaces.C.int;
type timespec is record
tv_sec : time_t;
@@ -56,7 +57,7 @@ package System.Linux is
type timeval is record
tv_sec : time_t;
- tv_usec : Long_Long_Integer;
+ tv_usec : suseconds_t;
end record;
pragma Convention (C, timeval);
diff --git a/gcc/ada/libgnarl/s-osinte__darwin.adb b/gcc/ada/libgnarl/s-osinte__darwin.adb
index dcac8c0..880c9b4 100644
--- a/gcc/ada/libgnarl/s-osinte__darwin.adb
+++ b/gcc/ada/libgnarl/s-osinte__darwin.adb
@@ -39,7 +39,6 @@ with Interfaces.C.Extensions;
package body System.OS_Interface is
use Interfaces.C;
- use Interfaces.C.Extensions;
-----------------
-- To_Duration --
diff --git a/gcc/ada/libgnarl/s-osinte__linux.ads b/gcc/ada/libgnarl/s-osinte__linux.ads
index 87da7ff..a2ba537 100644
--- a/gcc/ada/libgnarl/s-osinte__linux.ads
+++ b/gcc/ada/libgnarl/s-osinte__linux.ads
@@ -448,6 +448,9 @@ package System.OS_Interface is
abstime : access timespec) return int;
pragma Import (C, pthread_cond_timedwait, "pthread_cond_timedwait");
+ Relative_Timed_Wait : constant Boolean := False;
+ -- pthread_cond_timedwait requires an absolute delay time
+
--------------------------
-- POSIX.1c Section 13 --
--------------------------
diff --git a/gcc/ada/libgnarl/s-osinte__lynxos178.adb b/gcc/ada/libgnarl/s-osinte__lynxos178.adb
index 50e9353..a6dc986 100644
--- a/gcc/ada/libgnarl/s-osinte__lynxos178.adb
+++ b/gcc/ada/libgnarl/s-osinte__lynxos178.adb
@@ -37,8 +37,6 @@ pragma Polling (Off);
package body System.OS_Interface is
- use Interfaces.C;
-
------------------
-- Current_CPU --
------------------
diff --git a/gcc/ada/libgnarl/s-osinte__x32.adb b/gcc/ada/libgnarl/s-osinte__x32.adb
index a2874be..6bb80cd 100644
--- a/gcc/ada/libgnarl/s-osinte__x32.adb
+++ b/gcc/ada/libgnarl/s-osinte__x32.adb
@@ -90,7 +90,6 @@ package body System.OS_Interface is
S : time_t;
F : Duration;
- use type System.Linux.time_t;
begin
S := time_t (Long_Long_Integer (D));
F := D - Duration (S);
diff --git a/gcc/ada/libgnarl/s-solita.adb b/gcc/ada/libgnarl/s-solita.adb
index bb38578..a5485aa 100644
--- a/gcc/ada/libgnarl/s-solita.adb
+++ b/gcc/ada/libgnarl/s-solita.adb
@@ -44,6 +44,7 @@ with Ada.Exceptions.Is_Null_Occurrence;
with System.Task_Primitives.Operations;
with System.Tasking;
with System.Stack_Checking;
+with System.Secondary_Stack;
package body System.Soft_Links.Tasking is
@@ -52,6 +53,8 @@ package body System.Soft_Links.Tasking is
use Ada.Exceptions;
+ use type System.Secondary_Stack.SS_Stack_Ptr;
+
use type System.Tasking.Task_Id;
use type System.Tasking.Termination_Handler;
@@ -71,8 +74,8 @@ package body System.Soft_Links.Tasking is
procedure Set_Jmpbuf_Address (Addr : Address);
-- Get/Set Jmpbuf_Address for current task
- function Get_Sec_Stack_Addr return Address;
- procedure Set_Sec_Stack_Addr (Addr : Address);
+ function Get_Sec_Stack return SST.SS_Stack_Ptr;
+ procedure Set_Sec_Stack (Stack : SST.SS_Stack_Ptr);
-- Get/Set location of current task's secondary stack
procedure Timed_Delay_T (Time : Duration; Mode : Integer);
@@ -93,14 +96,14 @@ package body System.Soft_Links.Tasking is
return STPO.Self.Common.Compiler_Data.Jmpbuf_Address;
end Get_Jmpbuf_Address;
- function Get_Sec_Stack_Addr return Address is
+ function Get_Sec_Stack return SST.SS_Stack_Ptr is
begin
- return Result : constant Address :=
- STPO.Self.Common.Compiler_Data.Sec_Stack_Addr
+ return Result : constant SST.SS_Stack_Ptr :=
+ STPO.Self.Common.Compiler_Data.Sec_Stack_Ptr
do
- pragma Assert (Result /= Null_Address);
+ pragma Assert (Result /= null);
end return;
- end Get_Sec_Stack_Addr;
+ end Get_Sec_Stack;
function Get_Stack_Info return Stack_Checking.Stack_Access is
begin
@@ -116,10 +119,10 @@ package body System.Soft_Links.Tasking is
STPO.Self.Common.Compiler_Data.Jmpbuf_Address := Addr;
end Set_Jmpbuf_Address;
- procedure Set_Sec_Stack_Addr (Addr : Address) is
+ procedure Set_Sec_Stack (Stack : SST.SS_Stack_Ptr) is
begin
- STPO.Self.Common.Compiler_Data.Sec_Stack_Addr := Addr;
- end Set_Sec_Stack_Addr;
+ STPO.Self.Common.Compiler_Data.Sec_Stack_Ptr := Stack;
+ end Set_Sec_Stack;
-------------------
-- Timed_Delay_T --
@@ -213,20 +216,20 @@ package body System.Soft_Links.Tasking is
SSL.Get_Jmpbuf_Address := Get_Jmpbuf_Address'Access;
SSL.Set_Jmpbuf_Address := Set_Jmpbuf_Address'Access;
- SSL.Get_Sec_Stack_Addr := Get_Sec_Stack_Addr'Access;
+ SSL.Get_Sec_Stack := Get_Sec_Stack'Access;
SSL.Get_Stack_Info := Get_Stack_Info'Access;
- SSL.Set_Sec_Stack_Addr := Set_Sec_Stack_Addr'Access;
+ SSL.Set_Sec_Stack := Set_Sec_Stack'Access;
SSL.Timed_Delay := Timed_Delay_T'Access;
SSL.Task_Termination_Handler := Task_Termination_Handler_T'Access;
-- No need to create a new secondary stack, since we will use the
-- default one created in s-secsta.adb.
- SSL.Set_Sec_Stack_Addr (SSL.Get_Sec_Stack_Addr_NT);
+ SSL.Set_Sec_Stack (SSL.Get_Sec_Stack_NT);
SSL.Set_Jmpbuf_Address (SSL.Get_Jmpbuf_Address_NT);
end if;
- pragma Assert (Get_Sec_Stack_Addr /= Null_Address);
+ pragma Assert (Get_Sec_Stack /= null);
end Init_Tasking_Soft_Links;
end System.Soft_Links.Tasking;
diff --git a/gcc/ada/libgnarl/s-taenca.adb b/gcc/ada/libgnarl/s-taenca.adb
index 1236194..dc5dcf0 100644
--- a/gcc/ada/libgnarl/s-taenca.adb
+++ b/gcc/ada/libgnarl/s-taenca.adb
@@ -42,7 +42,6 @@ package body System.Tasking.Entry_Calls is
package STPO renames System.Task_Primitives.Operations;
use Parameters;
- use Task_Primitives;
use Protected_Objects.Entries;
use Protected_Objects.Operations;
diff --git a/gcc/ada/libgnarl/s-taprob.adb b/gcc/ada/libgnarl/s-taprob.adb
index 517b92d..c4d33c5 100644
--- a/gcc/ada/libgnarl/s-taprob.adb
+++ b/gcc/ada/libgnarl/s-taprob.adb
@@ -75,7 +75,7 @@ package body System.Tasking.Protected_Objects is
begin
if Init_Priority = Unspecified_Priority then
- Init_Priority := System.Priority'Last;
+ Init_Priority := System.Priority'Last;
end if;
Initialize_Lock (Init_Priority, Object.L'Access);
diff --git a/gcc/ada/libgnarl/s-taprop__linux.adb b/gcc/ada/libgnarl/s-taprop__linux.adb
index cc49205..5da1082 100644
--- a/gcc/ada/libgnarl/s-taprop__linux.adb
+++ b/gcc/ada/libgnarl/s-taprop__linux.adb
@@ -137,6 +137,38 @@ package body System.Task_Primitives.Operations is
package body Specific is separate;
-- The body of this package is target specific
+ package Monotonic is
+
+ function Monotonic_Clock return Duration;
+ pragma Inline (Monotonic_Clock);
+ -- Returns "absolute" time, represented as an offset relative to "the
+ -- Epoch", which is Jan 1, 1970. This clock implementation is immune to
+ -- the system's clock changes.
+
+ function RT_Resolution return Duration;
+ pragma Inline (RT_Resolution);
+ -- Returns resolution of the underlying clock used to implement RT_Clock
+
+ procedure Timed_Sleep
+ (Self_ID : ST.Task_Id;
+ Time : Duration;
+ Mode : ST.Delay_Modes;
+ Reason : System.Tasking.Task_States;
+ Timedout : out Boolean;
+ Yielded : out Boolean);
+ -- Combination of Sleep (above) and Timed_Delay
+
+ procedure Timed_Delay
+ (Self_ID : ST.Task_Id;
+ Time : Duration;
+ Mode : ST.Delay_Modes);
+ -- Implement the semantics of the delay statement.
+ -- The caller should be abort-deferred and should not hold any locks.
+
+ end Monotonic;
+
+ package body Monotonic is separate;
+
----------------------------------
-- ATCB allocation/deallocation --
----------------------------------
@@ -148,11 +180,16 @@ package body System.Task_Primitives.Operations is
-- Support for foreign threads --
---------------------------------
- function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
- -- Allocate and Initialize a new ATCB for the current Thread
+ function Register_Foreign_Thread
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size) return Task_Id;
+ -- Allocate and initialize a new ATCB for the current Thread. The size of
+ -- the secondary stack can be optionally specified.
function Register_Foreign_Thread
- (Thread : Thread_Id) return Task_Id is separate;
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size)
+ return Task_Id is separate;
-----------------------
-- Local Subprograms --
@@ -182,6 +219,10 @@ package body System.Task_Primitives.Operations is
-- Note well: If this function or related code is modified, it should be
-- tested by hand, because automated testing doesn't exercise it.
+ -------------------------
+ -- Get_Ceiling_Support --
+ -------------------------
+
function Get_Ceiling_Support return Boolean is
Ceiling_Support : Boolean := False;
begin
@@ -578,54 +619,7 @@ package body System.Task_Primitives.Operations is
Mode : ST.Delay_Modes;
Reason : System.Tasking.Task_States;
Timedout : out Boolean;
- Yielded : out Boolean)
- is
- pragma Unreferenced (Reason);
-
- Base_Time : constant Duration := Monotonic_Clock;
- Check_Time : Duration := Base_Time;
- Abs_Time : Duration;
- Request : aliased timespec;
- Result : C.int;
-
- begin
- Timedout := True;
- Yielded := False;
-
- Abs_Time :=
- (if Mode = Relative
- then Duration'Min (Time, Max_Sensible_Delay) + Check_Time
- else Duration'Min (Check_Time + Max_Sensible_Delay, Time));
-
- if Abs_Time > Check_Time then
- Request := To_Timespec (Abs_Time);
-
- loop
- exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
-
- Result :=
- pthread_cond_timedwait
- (cond => Self_ID.Common.LL.CV'Access,
- mutex => (if Single_Lock
- then Single_RTS_Lock'Access
- else Self_ID.Common.LL.L'Access),
- abstime => Request'Access);
-
- Check_Time := Monotonic_Clock;
- exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
-
- if Result in 0 | EINTR then
-
- -- Somebody may have called Wakeup for us
-
- Timedout := False;
- exit;
- end if;
-
- pragma Assert (Result = ETIMEDOUT);
- end loop;
- end if;
- end Timed_Sleep;
+ Yielded : out Boolean) renames Monotonic.Timed_Sleep;
-----------------
-- Timed_Delay --
@@ -637,90 +631,19 @@ package body System.Task_Primitives.Operations is
procedure Timed_Delay
(Self_ID : Task_Id;
Time : Duration;
- Mode : ST.Delay_Modes)
- is
- Base_Time : constant Duration := Monotonic_Clock;
- Check_Time : Duration := Base_Time;
- Abs_Time : Duration;
- Request : aliased timespec;
-
- Result : C.int;
- pragma Warnings (Off, Result);
-
- begin
- if Single_Lock then
- Lock_RTS;
- end if;
-
- Write_Lock (Self_ID);
-
- Abs_Time :=
- (if Mode = Relative
- then Time + Check_Time
- else Duration'Min (Check_Time + Max_Sensible_Delay, Time));
-
- if Abs_Time > Check_Time then
- Request := To_Timespec (Abs_Time);
- Self_ID.Common.State := Delay_Sleep;
-
- loop
- exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
-
- Result :=
- pthread_cond_timedwait
- (cond => Self_ID.Common.LL.CV'Access,
- mutex => (if Single_Lock
- then Single_RTS_Lock'Access
- else Self_ID.Common.LL.L'Access),
- abstime => Request'Access);
-
- Check_Time := Monotonic_Clock;
- exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
-
- pragma Assert (Result in 0 | ETIMEDOUT | EINTR);
- end loop;
-
- Self_ID.Common.State := Runnable;
- end if;
-
- Unlock (Self_ID);
-
- if Single_Lock then
- Unlock_RTS;
- end if;
-
- Result := sched_yield;
- end Timed_Delay;
+ Mode : ST.Delay_Modes) renames Monotonic.Timed_Delay;
---------------------
-- Monotonic_Clock --
---------------------
- function Monotonic_Clock return Duration is
- TS : aliased timespec;
- Result : C.int;
- begin
- Result := clock_gettime
- (clock_id => OSC.CLOCK_RT_Ada, tp => TS'Unchecked_Access);
- pragma Assert (Result = 0);
-
- return To_Duration (TS);
- end Monotonic_Clock;
+ function Monotonic_Clock return Duration renames Monotonic.Monotonic_Clock;
-------------------
-- RT_Resolution --
-------------------
- function RT_Resolution return Duration is
- TS : aliased timespec;
- Result : C.int;
-
- begin
- Result := clock_getres (OSC.CLOCK_REALTIME, TS'Unchecked_Access);
- pragma Assert (Result = 0);
-
- return To_Duration (TS);
- end RT_Resolution;
+ function RT_Resolution return Duration renames Monotonic.RT_Resolution;
------------
-- Wakeup --
diff --git a/gcc/ada/libgnarl/s-taprop__mingw.adb b/gcc/ada/libgnarl/s-taprop__mingw.adb
index fa96651..b14444a 100644
--- a/gcc/ada/libgnarl/s-taprop__mingw.adb
+++ b/gcc/ada/libgnarl/s-taprop__mingw.adb
@@ -190,11 +190,16 @@ package body System.Task_Primitives.Operations is
-- Support for foreign threads --
---------------------------------
- function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
- -- Allocate and Initialize a new ATCB for the current Thread
+ function Register_Foreign_Thread
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size) return Task_Id;
+ -- Allocate and initialize a new ATCB for the current Thread. The size of
+ -- the secondary stack can be optionally specified.
function Register_Foreign_Thread
- (Thread : Thread_Id) return Task_Id is separate;
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size)
+ return Task_Id is separate;
----------------------------------
-- Condition Variable Functions --
diff --git a/gcc/ada/libgnarl/s-taprop__posix.adb b/gcc/ada/libgnarl/s-taprop__posix.adb
index 3efc1e0..d9ee078 100644
--- a/gcc/ada/libgnarl/s-taprop__posix.adb
+++ b/gcc/ada/libgnarl/s-taprop__posix.adb
@@ -145,6 +145,38 @@ package body System.Task_Primitives.Operations is
package body Specific is separate;
-- The body of this package is target specific
+ package Monotonic is
+
+ function Monotonic_Clock return Duration;
+ pragma Inline (Monotonic_Clock);
+ -- Returns "absolute" time, represented as an offset relative to "the
+ -- Epoch", which is Jan 1, 1970. This clock implementation is immune to
+ -- the system's clock changes.
+
+ function RT_Resolution return Duration;
+ pragma Inline (RT_Resolution);
+ -- Returns resolution of the underlying clock used to implement RT_Clock
+
+ procedure Timed_Sleep
+ (Self_ID : ST.Task_Id;
+ Time : Duration;
+ Mode : ST.Delay_Modes;
+ Reason : System.Tasking.Task_States;
+ Timedout : out Boolean;
+ Yielded : out Boolean);
+ -- Combination of Sleep (above) and Timed_Delay
+
+ procedure Timed_Delay
+ (Self_ID : ST.Task_Id;
+ Time : Duration;
+ Mode : ST.Delay_Modes);
+ -- Implement the semantics of the delay statement.
+ -- The caller should be abort-deferred and should not hold any locks.
+
+ end Monotonic;
+
+ package body Monotonic is separate;
+
----------------------------------
-- ATCB allocation/deallocation --
----------------------------------
@@ -156,11 +188,16 @@ package body System.Task_Primitives.Operations is
-- Support for foreign threads --
---------------------------------
- function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
- -- Allocate and Initialize a new ATCB for the current Thread
+ function Register_Foreign_Thread
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size) return Task_Id;
+ -- Allocate and initialize a new ATCB for the current Thread. The size of
+ -- the secondary stack can be optionally specified.
function Register_Foreign_Thread
- (Thread : Thread_Id) return Task_Id is separate;
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size)
+ return Task_Id is separate;
-----------------------
-- Local Subprograms --
@@ -178,18 +215,6 @@ package body System.Task_Primitives.Operations is
pragma Import (C,
GNAT_pthread_condattr_setup, "__gnat_pthread_condattr_setup");
- procedure Compute_Deadline
- (Time : Duration;
- Mode : ST.Delay_Modes;
- Check_Time : out Duration;
- Abs_Time : out Duration;
- Rel_Time : out Duration);
- -- Helper for Timed_Sleep and Timed_Delay: given a deadline specified by
- -- Time and Mode, compute the current clock reading (Check_Time), and the
- -- target absolute and relative clock readings (Abs_Time, Rel_Time). The
- -- epoch for Time depends on Mode; the epoch for Check_Time and Abs_Time
- -- is always that of CLOCK_RT_Ada.
-
-------------------
-- Abort_Handler --
-------------------
@@ -248,67 +273,6 @@ package body System.Task_Primitives.Operations is
end if;
end Abort_Handler;
- ----------------------
- -- Compute_Deadline --
- ----------------------
-
- procedure Compute_Deadline
- (Time : Duration;
- Mode : ST.Delay_Modes;
- Check_Time : out Duration;
- Abs_Time : out Duration;
- Rel_Time : out Duration)
- is
- begin
- Check_Time := Monotonic_Clock;
-
- -- Relative deadline
-
- if Mode = Relative then
- Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
-
- if Relative_Timed_Wait then
- Rel_Time := Duration'Min (Max_Sensible_Delay, Time);
- end if;
-
- pragma Warnings (Off);
- -- Comparison "OSC.CLOCK_RT_Ada = OSC.CLOCK_REALTIME" is compile
- -- time known.
-
- -- Absolute deadline specified using the tasking clock (CLOCK_RT_Ada)
-
- elsif Mode = Absolute_RT
- or else OSC.CLOCK_RT_Ada = OSC.CLOCK_REALTIME
- then
- pragma Warnings (On);
- Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
-
- if Relative_Timed_Wait then
- Rel_Time := Duration'Min (Max_Sensible_Delay, Time - Check_Time);
- end if;
-
- -- Absolute deadline specified using the calendar clock, in the
- -- case where it is not the same as the tasking clock: compensate for
- -- difference between clock epochs (Base_Time - Base_Cal_Time).
-
- else
- declare
- Cal_Check_Time : constant Duration := OS_Primitives.Clock;
- RT_Time : constant Duration :=
- Time + Check_Time - Cal_Check_Time;
-
- begin
- Abs_Time :=
- Duration'Min (Check_Time + Max_Sensible_Delay, RT_Time);
-
- if Relative_Timed_Wait then
- Rel_Time :=
- Duration'Min (Max_Sensible_Delay, RT_Time - Check_Time);
- end if;
- end;
- end if;
- end Compute_Deadline;
-
-----------------
-- Stack_Guard --
-----------------
@@ -595,60 +559,7 @@ package body System.Task_Primitives.Operations is
Mode : ST.Delay_Modes;
Reason : Task_States;
Timedout : out Boolean;
- Yielded : out Boolean)
- is
- pragma Unreferenced (Reason);
-
- Base_Time : Duration;
- Check_Time : Duration;
- Abs_Time : Duration;
- Rel_Time : Duration;
-
- Request : aliased timespec;
- Result : Interfaces.C.int;
-
- begin
- Timedout := True;
- Yielded := False;
-
- Compute_Deadline
- (Time => Time,
- Mode => Mode,
- Check_Time => Check_Time,
- Abs_Time => Abs_Time,
- Rel_Time => Rel_Time);
- Base_Time := Check_Time;
-
- if Abs_Time > Check_Time then
- Request :=
- To_Timespec (if Relative_Timed_Wait then Rel_Time else Abs_Time);
-
- loop
- exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
-
- Result :=
- pthread_cond_timedwait
- (cond => Self_ID.Common.LL.CV'Access,
- mutex => (if Single_Lock
- then Single_RTS_Lock'Access
- else Self_ID.Common.LL.L'Access),
- abstime => Request'Access);
-
- Check_Time := Monotonic_Clock;
- exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
-
- if Result = 0 or Result = EINTR then
-
- -- Somebody may have called Wakeup for us
-
- Timedout := False;
- exit;
- end if;
-
- pragma Assert (Result = ETIMEDOUT);
- end loop;
- end if;
- end Timed_Sleep;
+ Yielded : out Boolean) renames Monotonic.Timed_Sleep;
-----------------
-- Timed_Delay --
@@ -660,95 +571,19 @@ package body System.Task_Primitives.Operations is
procedure Timed_Delay
(Self_ID : Task_Id;
Time : Duration;
- Mode : ST.Delay_Modes)
- is
- Base_Time : Duration;
- Check_Time : Duration;
- Abs_Time : Duration;
- Rel_Time : Duration;
- Request : aliased timespec;
-
- Result : Interfaces.C.int;
- pragma Warnings (Off, Result);
-
- begin
- if Single_Lock then
- Lock_RTS;
- end if;
-
- Write_Lock (Self_ID);
-
- Compute_Deadline
- (Time => Time,
- Mode => Mode,
- Check_Time => Check_Time,
- Abs_Time => Abs_Time,
- Rel_Time => Rel_Time);
- Base_Time := Check_Time;
-
- if Abs_Time > Check_Time then
- Request :=
- To_Timespec (if Relative_Timed_Wait then Rel_Time else Abs_Time);
- Self_ID.Common.State := Delay_Sleep;
-
- loop
- exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
-
- Result :=
- pthread_cond_timedwait
- (cond => Self_ID.Common.LL.CV'Access,
- mutex => (if Single_Lock
- then Single_RTS_Lock'Access
- else Self_ID.Common.LL.L'Access),
- abstime => Request'Access);
-
- Check_Time := Monotonic_Clock;
- exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
-
- pragma Assert (Result = 0
- or else Result = ETIMEDOUT
- or else Result = EINTR);
- end loop;
-
- Self_ID.Common.State := Runnable;
- end if;
-
- Unlock (Self_ID);
-
- if Single_Lock then
- Unlock_RTS;
- end if;
-
- Result := sched_yield;
- end Timed_Delay;
+ Mode : ST.Delay_Modes) renames Monotonic.Timed_Delay;
---------------------
-- Monotonic_Clock --
---------------------
- function Monotonic_Clock return Duration is
- TS : aliased timespec;
- Result : Interfaces.C.int;
- begin
- Result := clock_gettime
- (clock_id => OSC.CLOCK_RT_Ada, tp => TS'Unchecked_Access);
- pragma Assert (Result = 0);
- return To_Duration (TS);
- end Monotonic_Clock;
+ function Monotonic_Clock return Duration renames Monotonic.Monotonic_Clock;
-------------------
-- RT_Resolution --
-------------------
- function RT_Resolution return Duration is
- TS : aliased timespec;
- Result : Interfaces.C.int;
- begin
- Result := clock_getres (OSC.CLOCK_REALTIME, TS'Unchecked_Access);
- pragma Assert (Result = 0);
-
- return To_Duration (TS);
- end RT_Resolution;
+ function RT_Resolution return Duration renames Monotonic.RT_Resolution;
------------
-- Wakeup --
diff --git a/gcc/ada/libgnarl/s-taprop__solaris.adb b/gcc/ada/libgnarl/s-taprop__solaris.adb
index e97662c..26d83e5 100644
--- a/gcc/ada/libgnarl/s-taprop__solaris.adb
+++ b/gcc/ada/libgnarl/s-taprop__solaris.adb
@@ -237,11 +237,16 @@ package body System.Task_Primitives.Operations is
-- Support for foreign threads --
---------------------------------
- function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
- -- Allocate and Initialize a new ATCB for the current Thread
+ function Register_Foreign_Thread
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size) return Task_Id;
+ -- Allocate and initialize a new ATCB for the current Thread. The size of
+ -- the secondary stack can be optionally specified.
function Register_Foreign_Thread
- (Thread : Thread_Id) return Task_Id is separate;
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size)
+ return Task_Id is separate;
------------
-- Checks --
diff --git a/gcc/ada/libgnarl/s-taprop__vxworks.adb b/gcc/ada/libgnarl/s-taprop__vxworks.adb
index b77fb10..83ebc22 100644
--- a/gcc/ada/libgnarl/s-taprop__vxworks.adb
+++ b/gcc/ada/libgnarl/s-taprop__vxworks.adb
@@ -149,11 +149,16 @@ package body System.Task_Primitives.Operations is
-- Support for foreign threads --
---------------------------------
- function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id;
- -- Allocate and Initialize a new ATCB for the current Thread
+ function Register_Foreign_Thread
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size) return Task_Id;
+ -- Allocate and initialize a new ATCB for the current Thread. The size of
+ -- the secondary stack can be optionally specified.
function Register_Foreign_Thread
- (Thread : Thread_Id) return Task_Id is separate;
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size)
+ return Task_Id is separate;
-----------------------
-- Local Subprograms --
diff --git a/gcc/ada/libgnarl/s-tarest.adb b/gcc/ada/libgnarl/s-tarest.adb
index 4bf2df6..7b9f260 100644
--- a/gcc/ada/libgnarl/s-tarest.adb
+++ b/gcc/ada/libgnarl/s-tarest.adb
@@ -47,12 +47,6 @@ with Ada.Exceptions;
with System.Task_Primitives.Operations;
with System.Soft_Links.Tasking;
-with System.Storage_Elements;
-
-with System.Secondary_Stack;
-pragma Elaborate_All (System.Secondary_Stack);
--- Make sure the body of Secondary_Stack is elaborated before calling
--- Init_Tasking_Soft_Links. See comments for this routine for explanation.
with System.Soft_Links;
-- Used for the non-tasking routines (*_NT) that refer to global data. They
@@ -65,14 +59,11 @@ package body System.Tasking.Restricted.Stages is
package STPO renames System.Task_Primitives.Operations;
package SSL renames System.Soft_Links;
- package SSE renames System.Storage_Elements;
- package SST renames System.Secondary_Stack;
use Ada.Exceptions;
use Parameters;
use Task_Primitives.Operations;
- use Task_Info;
Tasks_Activation_Chain : Task_Id;
-- Chain of all the tasks to activate
@@ -116,17 +107,18 @@ package body System.Tasking.Restricted.Stages is
-- This should only be called by the Task_Wrapper procedure.
procedure Create_Restricted_Task
- (Priority : Integer;
- Stack_Address : System.Address;
- Size : System.Parameters.Size_Type;
- Secondary_Stack_Size : System.Parameters.Size_Type;
- Task_Info : System.Task_Info.Task_Info_Type;
- CPU : Integer;
- State : Task_Procedure_Access;
- Discriminants : System.Address;
- Elaborated : Access_Boolean;
- Task_Image : String;
- Created_Task : Task_Id);
+ (Priority : Integer;
+ Stack_Address : System.Address;
+ Stack_Size : System.Parameters.Size_Type;
+ Sec_Stack_Address : System.Secondary_Stack.SS_Stack_Ptr;
+ Sec_Stack_Size : System.Parameters.Size_Type;
+ Task_Info : System.Task_Info.Task_Info_Type;
+ CPU : Integer;
+ State : Task_Procedure_Access;
+ Discriminants : System.Address;
+ Elaborated : Access_Boolean;
+ Task_Image : String;
+ Created_Task : Task_Id);
-- Code shared between Create_Restricted_Task (the concurrent version) and
-- Create_Restricted_Task_Sequential. See comment of the former in the
-- specification of this package.
@@ -206,54 +198,6 @@ package body System.Tasking.Restricted.Stages is
--
-- DO NOT delete ID. As noted, it is needed on some targets.
- function Secondary_Stack_Size return Storage_Elements.Storage_Offset;
- -- Returns the size of the secondary stack for the task. For fixed
- -- secondary stacks, the function will return the ATCB field
- -- Secondary_Stack_Size if it is not set to Unspecified_Size,
- -- otherwise a percentage of the stack is reserved using the
- -- System.Parameters.Sec_Stack_Percentage property.
-
- -- Dynamic secondary stacks are allocated in System.Soft_Links.
- -- Create_TSD and thus the function returns 0 to suppress the
- -- creation of the fixed secondary stack in the primary stack.
-
- --------------------------
- -- Secondary_Stack_Size --
- --------------------------
-
- function Secondary_Stack_Size return Storage_Elements.Storage_Offset is
- use System.Storage_Elements;
- use System.Secondary_Stack;
-
- begin
- if Parameters.Sec_Stack_Dynamic then
- return 0;
-
- elsif Self_ID.Common.Secondary_Stack_Size = Unspecified_Size then
- return (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size
- * SSE.Storage_Offset (Sec_Stack_Percentage) / 100);
- else
- -- Use the size specified by aspect Secondary_Stack_Size padded
- -- by the amount of space used by the stack data structure.
-
- return Storage_Offset (Self_ID.Common.Secondary_Stack_Size) +
- Storage_Offset (Minimum_Secondary_Stack_Size);
- end if;
- end Secondary_Stack_Size;
-
- Secondary_Stack : aliased Storage_Elements.Storage_Array
- (1 .. Secondary_Stack_Size);
- for Secondary_Stack'Alignment use Standard'Maximum_Alignment;
- -- This is the secondary stack data. Note that it is critical that this
- -- have maximum alignment, since any kind of data can be allocated here.
-
- pragma Warnings (Off);
- Secondary_Stack_Address : System.Address := Secondary_Stack'Address;
- pragma Warnings (On);
- -- Address of secondary stack. In the fixed secondary stack case, this
- -- value is not modified, causing a warning, hence the bracketing with
- -- Warnings (Off/On).
-
Cause : Cause_Of_Termination := Normal;
-- Indicates the reason why this task terminates. Normal corresponds to
-- a task terminating due to completing the last statement of its body.
@@ -267,15 +211,7 @@ package body System.Tasking.Restricted.Stages is
-- execution of its task body, then EO will contain the associated
-- exception occurrence. Otherwise, it will contain Null_Occurrence.
- -- Start of processing for Task_Wrapper
-
begin
- if not Parameters.Sec_Stack_Dynamic then
- Self_ID.Common.Compiler_Data.Sec_Stack_Addr :=
- Secondary_Stack'Address;
- SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last));
- end if;
-
-- Initialize low-level TCB components, that cannot be initialized by
-- the creator.
@@ -540,17 +476,18 @@ package body System.Tasking.Restricted.Stages is
----------------------------
procedure Create_Restricted_Task
- (Priority : Integer;
- Stack_Address : System.Address;
- Size : System.Parameters.Size_Type;
- Secondary_Stack_Size : System.Parameters.Size_Type;
- Task_Info : System.Task_Info.Task_Info_Type;
- CPU : Integer;
- State : Task_Procedure_Access;
- Discriminants : System.Address;
- Elaborated : Access_Boolean;
- Task_Image : String;
- Created_Task : Task_Id)
+ (Priority : Integer;
+ Stack_Address : System.Address;
+ Stack_Size : System.Parameters.Size_Type;
+ Sec_Stack_Address : System.Secondary_Stack.SS_Stack_Ptr;
+ Sec_Stack_Size : System.Parameters.Size_Type;
+ Task_Info : System.Task_Info.Task_Info_Type;
+ CPU : Integer;
+ State : Task_Procedure_Access;
+ Discriminants : System.Address;
+ Elaborated : Access_Boolean;
+ Task_Image : String;
+ Created_Task : Task_Id)
is
Self_ID : constant Task_Id := STPO.Self;
Base_Priority : System.Any_Priority;
@@ -609,8 +546,7 @@ package body System.Tasking.Restricted.Stages is
Initialize_ATCB
(Self_ID, State, Discriminants, Self_ID, Elaborated, Base_Priority,
- Base_CPU, null, Task_Info, Size, Secondary_Stack_Size,
- Created_Task, Success);
+ Base_CPU, null, Task_Info, Stack_Size, Created_Task, Success);
-- If we do our job right then there should never be any failures, which
-- was probably said about the Titanic; so just to be safe, let's retain
@@ -640,25 +576,31 @@ package body System.Tasking.Restricted.Stages is
Unlock_RTS;
end if;
- -- Create TSD as early as possible in the creation of a task, since it
- -- may be used by the operation of Ada code within the task.
+ -- Create TSD as early as possible in the creation of a task, since
+ -- it may be used by the operation of Ada code within the task. If the
+ -- compiler has not allocated a secondary stack, a stack will be
+ -- allocated fromt the binder generated pool.
- SSL.Create_TSD (Created_Task.Common.Compiler_Data);
+ SSL.Create_TSD
+ (Created_Task.Common.Compiler_Data,
+ Sec_Stack_Address,
+ Sec_Stack_Size);
end Create_Restricted_Task;
procedure Create_Restricted_Task
- (Priority : Integer;
- Stack_Address : System.Address;
- Size : System.Parameters.Size_Type;
- Secondary_Stack_Size : System.Parameters.Size_Type;
- Task_Info : System.Task_Info.Task_Info_Type;
- CPU : Integer;
- State : Task_Procedure_Access;
- Discriminants : System.Address;
- Elaborated : Access_Boolean;
- Chain : in out Activation_Chain;
- Task_Image : String;
- Created_Task : Task_Id)
+ (Priority : Integer;
+ Stack_Address : System.Address;
+ Stack_Size : System.Parameters.Size_Type;
+ Sec_Stack_Address : System.Secondary_Stack.SS_Stack_Ptr;
+ Sec_Stack_Size : System.Parameters.Size_Type;
+ Task_Info : System.Task_Info.Task_Info_Type;
+ CPU : Integer;
+ State : Task_Procedure_Access;
+ Discriminants : System.Address;
+ Elaborated : Access_Boolean;
+ Chain : in out Activation_Chain;
+ Task_Image : String;
+ Created_Task : Task_Id)
is
begin
if Partition_Elaboration_Policy = 'S' then
@@ -669,14 +611,14 @@ package body System.Tasking.Restricted.Stages is
-- sequential, activation must be deferred.
Create_Restricted_Task_Sequential
- (Priority, Stack_Address, Size, Secondary_Stack_Size,
- Task_Info, CPU, State, Discriminants, Elaborated,
+ (Priority, Stack_Address, Stack_Size, Sec_Stack_Address,
+ Sec_Stack_Size, Task_Info, CPU, State, Discriminants, Elaborated,
Task_Image, Created_Task);
else
Create_Restricted_Task
- (Priority, Stack_Address, Size, Secondary_Stack_Size,
- Task_Info, CPU, State, Discriminants, Elaborated,
+ (Priority, Stack_Address, Stack_Size, Sec_Stack_Address,
+ Sec_Stack_Size, Task_Info, CPU, State, Discriminants, Elaborated,
Task_Image, Created_Task);
-- Append this task to the activation chain
@@ -691,22 +633,24 @@ package body System.Tasking.Restricted.Stages is
---------------------------------------
procedure Create_Restricted_Task_Sequential
- (Priority : Integer;
- Stack_Address : System.Address;
- Size : System.Parameters.Size_Type;
- Secondary_Stack_Size : System.Parameters.Size_Type;
- Task_Info : System.Task_Info.Task_Info_Type;
- CPU : Integer;
- State : Task_Procedure_Access;
- Discriminants : System.Address;
- Elaborated : Access_Boolean;
- Task_Image : String;
- Created_Task : Task_Id) is
+ (Priority : Integer;
+ Stack_Address : System.Address;
+ Stack_Size : System.Parameters.Size_Type;
+ Sec_Stack_Address : System.Secondary_Stack.SS_Stack_Ptr;
+ Sec_Stack_Size : System.Parameters.Size_Type;
+ Task_Info : System.Task_Info.Task_Info_Type;
+ CPU : Integer;
+ State : Task_Procedure_Access;
+ Discriminants : System.Address;
+ Elaborated : Access_Boolean;
+ Task_Image : String;
+ Created_Task : Task_Id)
+ is
begin
- Create_Restricted_Task (Priority, Stack_Address, Size,
- Secondary_Stack_Size, Task_Info,
- CPU, State, Discriminants, Elaborated,
- Task_Image, Created_Task);
+ Create_Restricted_Task
+ (Priority, Stack_Address, Stack_Size, Sec_Stack_Address,
+ Sec_Stack_Size, Task_Info, CPU, State, Discriminants, Elaborated,
+ Task_Image, Created_Task);
-- Append this task to the activation chain
diff --git a/gcc/ada/libgnarl/s-tarest.ads b/gcc/ada/libgnarl/s-tarest.ads
index ccc5683..e51fa58 100644
--- a/gcc/ada/libgnarl/s-tarest.ads
+++ b/gcc/ada/libgnarl/s-tarest.ads
@@ -43,8 +43,9 @@
-- The restricted GNARLI is also composed of System.Protected_Objects and
-- System.Protected_Objects.Single_Entry
-with System.Task_Info;
with System.Parameters;
+with System.Secondary_Stack;
+with System.Task_Info;
package System.Tasking.Restricted.Stages is
pragma Elaborate_Body;
@@ -128,33 +129,38 @@ package System.Tasking.Restricted.Stages is
-- by the binder generated code, before calling elaboration code.
procedure Create_Restricted_Task
- (Priority : Integer;
- Stack_Address : System.Address;
- Size : System.Parameters.Size_Type;
- Secondary_Stack_Size : System.Parameters.Size_Type;
- Task_Info : System.Task_Info.Task_Info_Type;
- CPU : Integer;
- State : Task_Procedure_Access;
- Discriminants : System.Address;
- Elaborated : Access_Boolean;
- Chain : in out Activation_Chain;
- Task_Image : String;
- Created_Task : Task_Id);
+ (Priority : Integer;
+ Stack_Address : System.Address;
+ Stack_Size : System.Parameters.Size_Type;
+ Sec_Stack_Address : System.Secondary_Stack.SS_Stack_Ptr;
+ Sec_Stack_Size : System.Parameters.Size_Type;
+ Task_Info : System.Task_Info.Task_Info_Type;
+ CPU : Integer;
+ State : Task_Procedure_Access;
+ Discriminants : System.Address;
+ Elaborated : Access_Boolean;
+ Chain : in out Activation_Chain;
+ Task_Image : String;
+ Created_Task : Task_Id);
-- Compiler interface only. Do not call from within the RTS.
-- This must be called to create a new task, when the partition
-- elaboration policy is not specified (or is concurrent).
--
-- Priority is the task's priority (assumed to be in the
- -- System.Any_Priority'Range)
+ -- System.Any_Priority'Range).
--
-- Stack_Address is the start address of the stack associated to the task,
-- in case it has been preallocated by the compiler; it is equal to
-- Null_Address when the stack needs to be allocated by the underlying
-- operating system.
--
- -- Size is the stack size of the task to create
+ -- Stack_Size is the stack size of the task to create.
+ --
+ -- Sec_Stack_Address is the pointer to the secondary stack created by the
+ -- compiler. If null, the secondary stack is either allocated by the binder
+ -- or the run-time.
--
- -- Secondary_Stack_Size is the secondary stack size of the task to create
+ -- Secondary_Stack_Size is the secondary stack size of the task to create.
--
-- Task_Info is the task info associated with the created task, or
-- Unspecified_Task_Info if none.
@@ -164,7 +170,7 @@ package System.Tasking.Restricted.Stages is
-- checks are performed when analyzing the pragma, and dynamic ones are
-- performed before setting the affinity at run time.
--
- -- State is the compiler generated task's procedure body
+ -- State is the compiler generated task's procedure body.
--
-- Discriminants is a pointer to a limited record whose discriminants are
-- those of the task to create. This parameter should be passed as the
@@ -182,20 +188,21 @@ package System.Tasking.Restricted.Stages is
--
-- Created_Task is the resulting task.
--
- -- This procedure can raise Storage_Error if the task creation fails
+ -- This procedure can raise Storage_Error if the task creation fails.
procedure Create_Restricted_Task_Sequential
- (Priority : Integer;
- Stack_Address : System.Address;
- Size : System.Parameters.Size_Type;
- Secondary_Stack_Size : System.Parameters.Size_Type;
- Task_Info : System.Task_Info.Task_Info_Type;
- CPU : Integer;
- State : Task_Procedure_Access;
- Discriminants : System.Address;
- Elaborated : Access_Boolean;
- Task_Image : String;
- Created_Task : Task_Id);
+ (Priority : Integer;
+ Stack_Address : System.Address;
+ Stack_Size : System.Parameters.Size_Type;
+ Sec_Stack_Address : System.Secondary_Stack.SS_Stack_Ptr;
+ Sec_Stack_Size : System.Parameters.Size_Type;
+ Task_Info : System.Task_Info.Task_Info_Type;
+ CPU : Integer;
+ State : Task_Procedure_Access;
+ Discriminants : System.Address;
+ Elaborated : Access_Boolean;
+ Task_Image : String;
+ Created_Task : Task_Id);
-- Compiler interface only. Do not call from within the RTS.
-- This must be called to create a new task, when the sequential partition
-- elaboration policy is used.
diff --git a/gcc/ada/libgnarl/s-taskin.adb b/gcc/ada/libgnarl/s-taskin.adb
index 462e229..d9fc6e3 100644
--- a/gcc/ada/libgnarl/s-taskin.adb
+++ b/gcc/ada/libgnarl/s-taskin.adb
@@ -96,7 +96,6 @@ package body System.Tasking is
Domain : Dispatching_Domain_Access;
Task_Info : System.Task_Info.Task_Info_Type;
Stack_Size : System.Parameters.Size_Type;
- Secondary_Stack_Size : System.Parameters.Size_Type;
T : Task_Id;
Success : out Boolean)
is
@@ -147,7 +146,6 @@ package body System.Tasking is
T.Common.Specific_Handler := null;
T.Common.Debug_Events := (others => False);
T.Common.Task_Image_Len := 0;
- T.Common.Secondary_Stack_Size := Secondary_Stack_Size;
if T.Common.Parent = null then
@@ -244,7 +242,6 @@ package body System.Tasking is
Domain => System_Domain,
Task_Info => Task_Info.Unspecified_Task_Info,
Stack_Size => 0,
- Secondary_Stack_Size => Parameters.Unspecified_Size,
T => T,
Success => Success);
pragma Assert (Success);
diff --git a/gcc/ada/libgnarl/s-taskin.ads b/gcc/ada/libgnarl/s-taskin.ads
index cd53cf9..7c8b44b 100644
--- a/gcc/ada/libgnarl/s-taskin.ads
+++ b/gcc/ada/libgnarl/s-taskin.ads
@@ -37,12 +37,12 @@
with Ada.Exceptions;
with Ada.Unchecked_Conversion;
+with System.Multiprocessors;
with System.Parameters;
-with System.Task_Info;
with System.Soft_Links;
-with System.Task_Primitives;
with System.Stack_Usage;
-with System.Multiprocessors;
+with System.Task_Info;
+with System.Task_Primitives;
package System.Tasking is
pragma Preelaborate;
@@ -702,13 +702,6 @@ package System.Tasking is
-- need to do different things depending on the situation.
--
-- Protection: Self.L
-
- Secondary_Stack_Size : System.Parameters.Size_Type;
- -- Secondary_Stack_Size is the size of the secondary stack for the
- -- task. Defined here since it is the responsibility of the task to
- -- creates its own secondary stack.
- --
- -- Protected: Only accessed by Self
end record;
---------------------------------------
@@ -1173,7 +1166,6 @@ package System.Tasking is
Domain : Dispatching_Domain_Access;
Task_Info : System.Task_Info.Task_Info_Type;
Stack_Size : System.Parameters.Size_Type;
- Secondary_Stack_Size : System.Parameters.Size_Type;
T : Task_Id;
Success : out Boolean);
-- Initialize fields of the TCB for task T, and link into global TCB
diff --git a/gcc/ada/libgnarl/s-tassta.adb b/gcc/ada/libgnarl/s-tassta.adb
index 346e5bf..518a02c 100644
--- a/gcc/ada/libgnarl/s-tassta.adb
+++ b/gcc/ada/libgnarl/s-tassta.adb
@@ -71,14 +71,13 @@ package body System.Tasking.Stages is
package STPO renames System.Task_Primitives.Operations;
package SSL renames System.Soft_Links;
package SSE renames System.Storage_Elements;
- package SST renames System.Secondary_Stack;
use Ada.Exceptions;
use Parameters;
+ use Secondary_Stack;
use Task_Primitives;
use Task_Primitives.Operations;
- use Task_Info;
-----------------------
-- Local Subprograms --
@@ -466,7 +465,7 @@ package body System.Tasking.Stages is
procedure Create_Task
(Priority : Integer;
- Size : System.Parameters.Size_Type;
+ Stack_Size : System.Parameters.Size_Type;
Secondary_Stack_Size : System.Parameters.Size_Type;
Task_Info : System.Task_Info.Task_Info_Type;
CPU : Integer;
@@ -605,8 +604,7 @@ package body System.Tasking.Stages is
end if;
Initialize_ATCB (Self_ID, State, Discriminants, P, Elaborated,
- Base_Priority, Base_CPU, Domain, Task_Info, Size,
- Secondary_Stack_Size, T, Success);
+ Base_Priority, Base_CPU, Domain, Task_Info, Stack_Size, T, Success);
if not Success then
Free (T);
@@ -693,10 +691,18 @@ package body System.Tasking.Stages is
Dispatching_Domain_Tasks (Base_CPU) + 1;
end if;
- -- Create TSD as early as possible in the creation of a task, since it
- -- may be used by the operation of Ada code within the task.
+ -- Create the secondary stack for the task as early as possible during
+ -- in the creation of a task, since it may be used by the operation of
+ -- Ada code within the task.
+
+ begin
+ SSL.Create_TSD (T.Common.Compiler_Data, null, Secondary_Stack_Size);
+ exception
+ when others =>
+ Initialization.Undefer_Abort_Nestable (Self_ID);
+ raise Storage_Error with "Secondary stack could not be allocated";
+ end;
- SSL.Create_TSD (T.Common.Compiler_Data);
T.Common.Activation_Link := Chain.T_ID;
Chain.T_ID := T;
Created_Task := T;
@@ -915,8 +921,8 @@ package body System.Tasking.Stages is
SSL.Unlock_Task := SSL.Task_Unlock_NT'Access;
SSL.Get_Jmpbuf_Address := SSL.Get_Jmpbuf_Address_NT'Access;
SSL.Set_Jmpbuf_Address := SSL.Set_Jmpbuf_Address_NT'Access;
- SSL.Get_Sec_Stack_Addr := SSL.Get_Sec_Stack_Addr_NT'Access;
- SSL.Set_Sec_Stack_Addr := SSL.Set_Sec_Stack_Addr_NT'Access;
+ SSL.Get_Sec_Stack := SSL.Get_Sec_Stack_NT'Access;
+ SSL.Set_Sec_Stack := SSL.Set_Sec_Stack_NT'Access;
SSL.Check_Abort_Status := SSL.Check_Abort_Status_NT'Access;
SSL.Get_Stack_Info := SSL.Get_Stack_Info_NT'Access;
@@ -1015,7 +1021,6 @@ package body System.Tasking.Stages is
-- at-end handler that the compiler generates.
procedure Task_Wrapper (Self_ID : Task_Id) is
- use type SSE.Storage_Offset;
use System.Standard_Library;
use System.Stack_Usage;
@@ -1028,53 +1033,6 @@ package body System.Tasking.Stages is
Use_Alternate_Stack : constant Boolean := Alternate_Stack_Size /= 0;
-- Whether to use above alternate signal stack for stack overflows
- function Secondary_Stack_Size return Storage_Elements.Storage_Offset;
- -- Returns the size of the secondary stack for the task. For fixed
- -- secondary stacks, the function will return the ATCB field
- -- Secondary_Stack_Size if it is not set to Unspecified_Size,
- -- otherwise a percentage of the stack is reserved using the
- -- System.Parameters.Sec_Stack_Percentage property.
-
- -- Dynamic secondary stacks are allocated in System.Soft_Links.
- -- Create_TSD and thus the function returns 0 to suppress the
- -- creation of the fixed secondary stack in the primary stack.
-
- --------------------------
- -- Secondary_Stack_Size --
- --------------------------
-
- function Secondary_Stack_Size return Storage_Elements.Storage_Offset is
- use System.Storage_Elements;
- use System.Secondary_Stack;
-
- begin
- if Parameters.Sec_Stack_Dynamic then
- return 0;
-
- elsif Self_ID.Common.Secondary_Stack_Size = Unspecified_Size then
- return (Self_ID.Common.Compiler_Data.Pri_Stack_Info.Size
- * SSE.Storage_Offset (Sec_Stack_Percentage) / 100);
- else
- -- Use the size specified by aspect Secondary_Stack_Size padded
- -- by the amount of space used by the stack data structure.
-
- return Storage_Offset (Self_ID.Common.Secondary_Stack_Size) +
- Storage_Offset (SST.Minimum_Secondary_Stack_Size);
- end if;
- end Secondary_Stack_Size;
-
- Secondary_Stack : aliased Storage_Elements.Storage_Array
- (1 .. Secondary_Stack_Size);
- for Secondary_Stack'Alignment use Standard'Maximum_Alignment;
- -- Actual area allocated for secondary stack. Note that it is critical
- -- that this have maximum alignment, since any kind of data can be
- -- allocated here.
-
- Secondary_Stack_Address : System.Address := Secondary_Stack'Address;
- -- Address of secondary stack. In the fixed secondary stack case, this
- -- value is not modified, causing a warning, hence the bracketing with
- -- Warnings (Off/On). But why is so much *more* bracketed???
-
SEH_Table : aliased SSE.Storage_Array (1 .. 8);
-- Structured Exception Registration table (2 words)
@@ -1138,14 +1096,6 @@ package body System.Tasking.Stages is
Debug.Master_Hook
(Self_ID, Self_ID.Common.Parent, Self_ID.Master_of_Task);
- -- Assume a size of the stack taken at this stage
-
- if not Parameters.Sec_Stack_Dynamic then
- Self_ID.Common.Compiler_Data.Sec_Stack_Addr :=
- Secondary_Stack'Address;
- SST.SS_Init (Secondary_Stack_Address, Integer (Secondary_Stack'Last));
- end if;
-
if Use_Alternate_Stack then
Self_ID.Common.Task_Alternate_Stack := Task_Alternate_Stack'Address;
end if;
@@ -1199,15 +1149,6 @@ package body System.Tasking.Stages is
Stack_Base := Bottom_Of_Stack'Address;
- -- Also reduce the size of the stack to take into account the
- -- secondary stack array declared in this frame. This is for
- -- sure very conservative.
-
- if not Parameters.Sec_Stack_Dynamic then
- Pattern_Size :=
- Pattern_Size - Natural (Secondary_Stack_Size);
- end if;
-
-- Adjustments for inner frames
Pattern_Size := Pattern_Size -
@@ -1539,7 +1480,6 @@ package body System.Tasking.Stages is
pragma Import (Ada, To_Stderr, "__gnat_to_stderr");
use System.Soft_Links;
- use System.Standard_Library;
function To_Address is new
Ada.Unchecked_Conversion
@@ -1976,10 +1916,10 @@ package body System.Tasking.Stages is
then
Initialization.Task_Lock (Self_ID);
- -- If Sec_Stack_Addr is not null, it means that Destroy_TSD
+ -- If Sec_Stack_Ptr is not null, it means that Destroy_TSD
-- has not been called yet (case of an unactivated task).
- if T.Common.Compiler_Data.Sec_Stack_Addr /= Null_Address then
+ if T.Common.Compiler_Data.Sec_Stack_Ptr /= null then
SSL.Destroy_TSD (T.Common.Compiler_Data);
end if;
diff --git a/gcc/ada/libgnarl/s-tassta.ads b/gcc/ada/libgnarl/s-tassta.ads
index bc837fc..a1129a1 100644
--- a/gcc/ada/libgnarl/s-tassta.ads
+++ b/gcc/ada/libgnarl/s-tassta.ads
@@ -70,7 +70,7 @@ package System.Tasking.Stages is
-- tE : aliased boolean := false;
-- tZ : size_type := unspecified_size;
-- type tV (discr : integer) is limited record
- -- _task_id : task_id;
+ -- _task_id : task_id;
-- end record;
-- procedure tB (_task : access tV);
-- freeze tV [
@@ -168,7 +168,7 @@ package System.Tasking.Stages is
procedure Create_Task
(Priority : Integer;
- Size : System.Parameters.Size_Type;
+ Stack_Size : System.Parameters.Size_Type;
Secondary_Stack_Size : System.Parameters.Size_Type;
Task_Info : System.Task_Info.Task_Info_Type;
CPU : Integer;
@@ -187,31 +187,44 @@ package System.Tasking.Stages is
--
-- Priority is the task's priority (assumed to be in range of type
-- System.Any_Priority)
- -- Size is the stack size of the task to create
- -- Secondary_Stack_Size is the secondary stack size of the task to create
+ --
+ -- Stack_Size is the stack size of the task to create
+ --
+ -- Secondary_Stack_Size is the size of the secondary stack to be used by
+ -- the task.
+ --
-- Task_Info is the task info associated with the created task, or
-- Unspecified_Task_Info if none.
+ --
-- CPU is the task affinity. Passed as an Integer because the undefined
-- value is not in the range of CPU_Range. Static range checks are
-- performed when analyzing the pragma, and dynamic ones are performed
-- before setting the affinity at run time.
+ --
-- Relative_Deadline is the relative deadline associated with the created
-- task by means of a pragma Relative_Deadline, or 0.0 if none.
+ --
-- Domain is the dispatching domain associated with the created task by
-- means of a Dispatching_Domain pragma or aspect, or null if none.
+ --
-- State is the compiler generated task's procedure body
+ --
-- Discriminants is a pointer to a limited record whose discriminants
-- are those of the task to create. This parameter should be passed as
-- the single argument to State.
+ --
-- Elaborated is a pointer to a Boolean that must be set to true on exit
-- if the task could be successfully elaborated.
+ --
-- Chain is a linked list of task that needs to be created. On exit,
-- Created_Task.Activation_Link will be Chain.T_ID, and Chain.T_ID
-- will be Created_Task (e.g the created task will be linked at the front
-- of Chain).
+ --
-- Task_Image is a string created by the compiler that the
-- run time can store to ease the debugging and the
-- Ada.Task_Identification facility.
+ --
-- Created_Task is the resulting task.
--
-- This procedure can raise Storage_Error if the task creation failed.
diff --git a/gcc/ada/libgnarl/s-tpobop.adb b/gcc/ada/libgnarl/s-tpobop.adb
index 242fe45..251ae87 100644
--- a/gcc/ada/libgnarl/s-tpobop.adb
+++ b/gcc/ada/libgnarl/s-tpobop.adb
@@ -60,7 +60,6 @@ package body System.Tasking.Protected_Objects.Operations is
package STPO renames System.Task_Primitives.Operations;
use Parameters;
- use Task_Primitives;
use Ada.Exceptions;
use Entries;
diff --git a/gcc/ada/libgnarl/s-tpopmo.adb b/gcc/ada/libgnarl/s-tpopmo.adb
new file mode 100644
index 0000000..b6164aa
--- /dev/null
+++ b/gcc/ada/libgnarl/s-tpopmo.adb
@@ -0,0 +1,283 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT RUN-TIME LIBRARY (GNARL) COMPONENTS --
+-- --
+-- SYSTEM.TASK_PRIMITIVES.OPERATIONS.MONOTONIC --
+-- --
+-- B o d y --
+-- --
+-- Copyright (C) 1992-2017, Free Software Foundation, Inc. --
+-- --
+-- 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- --
+-- 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 --
+-- <http://www.gnu.org/licenses/>. --
+-- --
+-- GNARL was developed by the GNARL team at Florida State University. --
+-- Extensive contributions were provided by Ada Core Technologies, Inc. --
+-- --
+------------------------------------------------------------------------------
+
+-- This is the Monotonic version of this package for Posix and Linux targets.
+
+separate (System.Task_Primitives.Operations)
+package body Monotonic is
+
+ -----------------------
+ -- Local Subprograms --
+ -----------------------
+
+ procedure Compute_Deadline
+ (Time : Duration;
+ Mode : ST.Delay_Modes;
+ Check_Time : out Duration;
+ Abs_Time : out Duration;
+ Rel_Time : out Duration);
+ -- Helper for Timed_Sleep and Timed_Delay: given a deadline specified by
+ -- Time and Mode, compute the current clock reading (Check_Time), and the
+ -- target absolute and relative clock readings (Abs_Time, Rel_Time). The
+ -- epoch for Time depends on Mode; the epoch for Check_Time and Abs_Time
+ -- is always that of CLOCK_RT_Ada.
+
+ ---------------------
+ -- Monotonic_Clock --
+ ---------------------
+
+ function Monotonic_Clock return Duration is
+ TS : aliased timespec;
+ Result : Interfaces.C.int;
+ begin
+ Result := clock_gettime
+ (clock_id => OSC.CLOCK_RT_Ada, tp => TS'Unchecked_Access);
+ pragma Assert (Result = 0);
+
+ return To_Duration (TS);
+ end Monotonic_Clock;
+
+ -------------------
+ -- RT_Resolution --
+ -------------------
+
+ function RT_Resolution return Duration is
+ TS : aliased timespec;
+ Result : Interfaces.C.int;
+
+ begin
+ Result := clock_getres (OSC.CLOCK_REALTIME, TS'Unchecked_Access);
+ pragma Assert (Result = 0);
+
+ return To_Duration (TS);
+ end RT_Resolution;
+
+ ----------------------
+ -- Compute_Deadline --
+ ----------------------
+
+ procedure Compute_Deadline
+ (Time : Duration;
+ Mode : ST.Delay_Modes;
+ Check_Time : out Duration;
+ Abs_Time : out Duration;
+ Rel_Time : out Duration)
+ is
+ begin
+ Check_Time := Monotonic_Clock;
+
+ -- Relative deadline
+
+ if Mode = Relative then
+ Abs_Time := Duration'Min (Time, Max_Sensible_Delay) + Check_Time;
+
+ if Relative_Timed_Wait then
+ Rel_Time := Duration'Min (Max_Sensible_Delay, Time);
+ end if;
+
+ pragma Warnings (Off);
+ -- Comparison "OSC.CLOCK_RT_Ada = OSC.CLOCK_REALTIME" is compile
+ -- time known.
+
+ -- Absolute deadline specified using the tasking clock (CLOCK_RT_Ada)
+
+ elsif Mode = Absolute_RT
+ or else OSC.CLOCK_RT_Ada = OSC.CLOCK_REALTIME
+ then
+ pragma Warnings (On);
+ Abs_Time := Duration'Min (Check_Time + Max_Sensible_Delay, Time);
+
+ if Relative_Timed_Wait then
+ Rel_Time := Duration'Min (Max_Sensible_Delay, Time - Check_Time);
+ end if;
+
+ -- Absolute deadline specified using the calendar clock, in the
+ -- case where it is not the same as the tasking clock: compensate for
+ -- difference between clock epochs (Base_Time - Base_Cal_Time).
+
+ else
+ declare
+ Cal_Check_Time : constant Duration := OS_Primitives.Clock;
+ RT_Time : constant Duration :=
+ Time + Check_Time - Cal_Check_Time;
+
+ begin
+ Abs_Time :=
+ Duration'Min (Check_Time + Max_Sensible_Delay, RT_Time);
+
+ if Relative_Timed_Wait then
+ Rel_Time :=
+ Duration'Min (Max_Sensible_Delay, RT_Time - Check_Time);
+ end if;
+ end;
+ end if;
+ end Compute_Deadline;
+
+ -----------------
+ -- Timed_Sleep --
+ -----------------
+
+ -- This is for use within the run-time system, so abort is
+ -- assumed to be already deferred, and the caller should be
+ -- holding its own ATCB lock.
+
+ procedure Timed_Sleep
+ (Self_ID : ST.Task_Id;
+ Time : Duration;
+ Mode : ST.Delay_Modes;
+ Reason : System.Tasking.Task_States;
+ Timedout : out Boolean;
+ Yielded : out Boolean)
+ is
+ pragma Unreferenced (Reason);
+
+ Base_Time : Duration;
+ Check_Time : Duration;
+ Abs_Time : Duration;
+ Rel_Time : Duration;
+
+ Request : aliased timespec;
+ Result : Interfaces.C.int;
+
+ begin
+ Timedout := True;
+ Yielded := False;
+
+ Compute_Deadline
+ (Time => Time,
+ Mode => Mode,
+ Check_Time => Check_Time,
+ Abs_Time => Abs_Time,
+ Rel_Time => Rel_Time);
+ Base_Time := Check_Time;
+
+ if Abs_Time > Check_Time then
+ Request :=
+ To_Timespec (if Relative_Timed_Wait then Rel_Time else Abs_Time);
+
+ loop
+ exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
+
+ Result :=
+ pthread_cond_timedwait
+ (cond => Self_ID.Common.LL.CV'Access,
+ mutex => (if Single_Lock
+ then Single_RTS_Lock'Access
+ else Self_ID.Common.LL.L'Access),
+ abstime => Request'Access);
+
+ Check_Time := Monotonic_Clock;
+ exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
+
+ if Result in 0 | EINTR then
+
+ -- Somebody may have called Wakeup for us
+
+ Timedout := False;
+ exit;
+ end if;
+
+ pragma Assert (Result = ETIMEDOUT);
+ end loop;
+ end if;
+ end Timed_Sleep;
+
+ -----------------
+ -- Timed_Delay --
+ -----------------
+
+ -- This is for use in implementing delay statements, so we assume the
+ -- caller is abort-deferred but is holding no locks.
+
+ procedure Timed_Delay
+ (Self_ID : ST.Task_Id;
+ Time : Duration;
+ Mode : ST.Delay_Modes)
+ is
+ Base_Time : Duration;
+ Check_Time : Duration;
+ Abs_Time : Duration;
+ Rel_Time : Duration;
+ Request : aliased timespec;
+
+ Result : Interfaces.C.int;
+ pragma Warnings (Off, Result);
+
+ begin
+ if Single_Lock then
+ Lock_RTS;
+ end if;
+
+ Write_Lock (Self_ID);
+
+ Compute_Deadline
+ (Time => Time,
+ Mode => Mode,
+ Check_Time => Check_Time,
+ Abs_Time => Abs_Time,
+ Rel_Time => Rel_Time);
+ Base_Time := Check_Time;
+
+ if Abs_Time > Check_Time then
+ Request :=
+ To_Timespec (if Relative_Timed_Wait then Rel_Time else Abs_Time);
+ Self_ID.Common.State := Delay_Sleep;
+
+ loop
+ exit when Self_ID.Pending_ATC_Level < Self_ID.ATC_Nesting_Level;
+
+ Result :=
+ pthread_cond_timedwait
+ (cond => Self_ID.Common.LL.CV'Access,
+ mutex => (if Single_Lock
+ then Single_RTS_Lock'Access
+ else Self_ID.Common.LL.L'Access),
+ abstime => Request'Access);
+
+ Check_Time := Monotonic_Clock;
+ exit when Abs_Time <= Check_Time or else Check_Time < Base_Time;
+
+ pragma Assert (Result in 0 | ETIMEDOUT | EINTR);
+ end loop;
+
+ Self_ID.Common.State := Runnable;
+ end if;
+
+ Unlock (Self_ID);
+
+ if Single_Lock then
+ Unlock_RTS;
+ end if;
+
+ Result := sched_yield;
+ end Timed_Delay;
+
+end Monotonic;
diff --git a/gcc/ada/libgnarl/s-tporft.adb b/gcc/ada/libgnarl/s-tporft.adb
index 7b8a592..56eda26 100644
--- a/gcc/ada/libgnarl/s-tporft.adb
+++ b/gcc/ada/libgnarl/s-tporft.adb
@@ -29,16 +29,16 @@
-- --
------------------------------------------------------------------------------
-with System.Task_Info;
--- Use for Unspecified_Task_Info
-
-with System.Soft_Links;
--- used to initialize TSD for a C thread, in function Self
-
with System.Multiprocessors;
+with System.Soft_Links;
+with System.Task_Info;
separate (System.Task_Primitives.Operations)
-function Register_Foreign_Thread (Thread : Thread_Id) return Task_Id is
+function Register_Foreign_Thread
+ (Thread : Thread_Id;
+ Sec_Stack_Size : Size_Type := Unspecified_Size)
+ return Task_Id
+is
Local_ATCB : aliased Ada_Task_Control_Block (0);
Self_Id : Task_Id;
Succeeded : Boolean;
@@ -66,7 +66,7 @@ begin
(Self_Id, null, Null_Address, Null_Task,
Foreign_Task_Elaborated'Access,
System.Priority'First, System.Multiprocessors.Not_A_Specific_CPU, null,
- Task_Info.Unspecified_Task_Info, 0, 0, Self_Id, Succeeded);
+ Task_Info.Unspecified_Task_Info, 0, Self_Id, Succeeded);
Unlock_RTS;
pragma Assert (Succeeded);
@@ -92,7 +92,10 @@ begin
Self_Id.Common.Task_Alternate_Stack := Null_Address;
- System.Soft_Links.Create_TSD (Self_Id.Common.Compiler_Data);
+ -- Create the TSD for the task
+
+ System.Soft_Links.Create_TSD
+ (Self_Id.Common.Compiler_Data, null, Sec_Stack_Size);
Enter_Task (Self_Id);
diff --git a/gcc/ada/libgnat/a-cfhama.ads b/gcc/ada/libgnat/a-cfhama.ads
index e02accc..feaa3b1 100644
--- a/gcc/ada/libgnat/a-cfhama.ads
+++ b/gcc/ada/libgnat/a-cfhama.ads
@@ -808,8 +808,6 @@ private
type Map (Capacity : Count_Type; Modulus : Hash_Type) is
new HT_Types.Hash_Table_Type (Capacity, Modulus) with null record;
- use HT_Types;
-
Empty_Map : constant Map := (Capacity => 0, Modulus => 0, others => <>);
end Ada.Containers.Formal_Hashed_Maps;
diff --git a/gcc/ada/libgnat/a-strmap.adb b/gcc/ada/libgnat/a-strmap.adb
index a98556b..0f68f18 100644
--- a/gcc/ada/libgnat/a-strmap.adb
+++ b/gcc/ada/libgnat/a-strmap.adb
@@ -37,8 +37,6 @@
package body Ada.Strings.Maps is
- use Ada.Characters.Latin_1;
-
---------
-- "-" --
---------
diff --git a/gcc/ada/libgnat/a-strunb.adb b/gcc/ada/libgnat/a-strunb.adb
index 808e26a..0366806 100644
--- a/gcc/ada/libgnat/a-strunb.adb
+++ b/gcc/ada/libgnat/a-strunb.adb
@@ -35,8 +35,6 @@ with Ada.Unchecked_Deallocation;
package body Ada.Strings.Unbounded is
- use Ada.Finalization;
-
---------
-- "&" --
---------
diff --git a/gcc/ada/libgnat/a-stwiun.adb b/gcc/ada/libgnat/a-stwiun.adb
index 85bc494..2449822 100644
--- a/gcc/ada/libgnat/a-stwiun.adb
+++ b/gcc/ada/libgnat/a-stwiun.adb
@@ -35,8 +35,6 @@ with Ada.Unchecked_Deallocation;
package body Ada.Strings.Wide_Unbounded is
- use Ada.Finalization;
-
---------
-- "&" --
---------
diff --git a/gcc/ada/libgnat/a-stzunb.adb b/gcc/ada/libgnat/a-stzunb.adb
index 25c3b29..2492fec 100644
--- a/gcc/ada/libgnat/a-stzunb.adb
+++ b/gcc/ada/libgnat/a-stzunb.adb
@@ -35,8 +35,6 @@ with Ada.Unchecked_Deallocation;
package body Ada.Strings.Wide_Wide_Unbounded is
- use Ada.Finalization;
-
---------
-- "&" --
---------
diff --git a/gcc/ada/libgnat/a-tags.adb b/gcc/ada/libgnat/a-tags.adb
index 322f991..f3c2c0e 100644
--- a/gcc/ada/libgnat/a-tags.adb
+++ b/gcc/ada/libgnat/a-tags.adb
@@ -842,9 +842,21 @@ package body Ada.Tags is
begin
Curr_DT := DT (To_Tag_Ptr (This).all);
+ -- See the documentation of Dispatch_Table_Wrapper.Offset_To_Top
+
if Curr_DT.Offset_To_Top = SSE.Storage_Offset'Last then
+
+ -- The parent record type has variable-size components, so the
+ -- instance-specific offset is stored in the tagged record, right
+ -- after the reference to Curr_DT (which is a secondary dispatch
+ -- table).
+
return To_Storage_Offset_Ptr (This + Tag_Size).all;
+
else
+ -- The offset is compile-time known, so it is simply stored in the
+ -- Offset_To_Top field.
+
return Curr_DT.Offset_To_Top;
end if;
end Offset_To_Top;
diff --git a/gcc/ada/libgnat/a-tags.ads b/gcc/ada/libgnat/a-tags.ads
index 564ce20..a11cdd4 100644
--- a/gcc/ada/libgnat/a-tags.ads
+++ b/gcc/ada/libgnat/a-tags.ads
@@ -380,12 +380,21 @@ private
-- Prims_Ptr table.
Offset_To_Top : SSE.Storage_Offset;
- TSD : System.Address;
+ -- Offset between the _Tag field and the field that contains the
+ -- reference to this dispatch table. For primary dispatch tables it is
+ -- zero. For secondary dispatch tables: if the parent record type (if
+ -- any) has a compile-time-known size, then Offset_To_Top contains the
+ -- expected value, otherwise it contains SSE.Storage_Offset'Last and the
+ -- actual offset is to be found in the tagged record, right after the
+ -- field that contains the reference to this dispatch table. See the
+ -- implementation of Ada.Tags.Offset_To_Top for the corresponding logic.
+
+ TSD : System.Address;
Prims_Ptr : aliased Address_Array (1 .. Num_Prims);
-- The size of the Prims_Ptr array actually depends on the tagged type
-- to which it applies. For each tagged type, the expander computes the
- -- actual array size, allocates the Dispatch_Table record accordingly.
+ -- actual array size, allocating the Dispatch_Table record accordingly.
end record;
type Dispatch_Table_Ptr is access all Dispatch_Table_Wrapper;
diff --git a/gcc/ada/libgnat/a-teioed.adb b/gcc/ada/libgnat/a-teioed.adb
index 93e69f6..4260682 100644
--- a/gcc/ada/libgnat/a-teioed.adb
+++ b/gcc/ada/libgnat/a-teioed.adb
@@ -1019,7 +1019,6 @@ package body Ada.Text_IO.Editing is
-------------------
procedure Debug_Integer (Value : Integer; S : String) is
- use Ada.Text_IO; -- needed for >
begin
if Debug and then Value > 0 then
diff --git a/gcc/ada/libgnat/g-alvety.ads b/gcc/ada/libgnat/g-alvety.ads
index 623a5fc..a697e62 100644
--- a/gcc/ada/libgnat/g-alvety.ads
+++ b/gcc/ada/libgnat/g-alvety.ads
@@ -36,8 +36,6 @@ with GNAT.Altivec.Low_Level_Vectors;
package GNAT.Altivec.Vector_Types is
- use GNAT.Altivec.Low_Level_Vectors;
-
---------------------------------------------------
-- Vector type declarations [PIM-2.1 Data Types] --
---------------------------------------------------
diff --git a/gcc/ada/libgnat/g-expect.adb b/gcc/ada/libgnat/g-expect.adb
index 4435b6a..5546601 100644
--- a/gcc/ada/libgnat/g-expect.adb
+++ b/gcc/ada/libgnat/g-expect.adb
@@ -907,8 +907,6 @@ package body GNAT.Expect is
Status : not null access Integer;
Err_To_Out : Boolean := False) return String
is
- use GNAT.Expect;
-
Process : Process_Descriptor;
Output : String_Access := new String (1 .. 1024);
diff --git a/gcc/ada/libgnat/g-regist.adb b/gcc/ada/libgnat/g-regist.adb
index 5b097bb..02e07fd 100644
--- a/gcc/ada/libgnat/g-regist.adb
+++ b/gcc/ada/libgnat/g-regist.adb
@@ -184,9 +184,6 @@ package body GNAT.Registry is
Sub_Key : String;
Mode : Key_Mode := Read_Write) return HKEY
is
- use type REGSAM;
- use type DWORD;
-
REG_OPTION_NON_VOLATILE : constant := 16#0#;
C_Sub_Key : constant String := Sub_Key & ASCII.NUL;
@@ -425,8 +422,6 @@ package body GNAT.Registry is
Sub_Key : String;
Mode : Key_Mode := Read_Only) return HKEY
is
- use type REGSAM;
-
C_Sub_Key : constant String := Sub_Key & ASCII.NUL;
C_Mode : constant REGSAM := To_C_Mode (Mode);
@@ -456,7 +451,6 @@ package body GNAT.Registry is
Expand : Boolean := False) return String
is
use GNAT.Directory_Operations;
- use type LONG;
use type ULONG;
Value : String (1 .. Max_Value_Size);
diff --git a/gcc/ada/libgnat/g-socket.adb b/gcc/ada/libgnat/g-socket.adb
index 9b2ad7f..519776e 100644
--- a/gcc/ada/libgnat/g-socket.adb
+++ b/gcc/ada/libgnat/g-socket.adb
@@ -2175,7 +2175,6 @@ package body GNAT.Sockets is
Count : out Ada.Streams.Stream_Element_Count;
Flags : Request_Flag_Type := No_Request_Flag)
is
- use SOSC;
use Interfaces.C;
Res : ssize_t;
diff --git a/gcc/ada/libgnat/g-socthi__mingw.ads b/gcc/ada/libgnat/g-socthi__mingw.ads
index 48f5aeb..fa76172 100644
--- a/gcc/ada/libgnat/g-socthi__mingw.ads
+++ b/gcc/ada/libgnat/g-socthi__mingw.ads
@@ -48,8 +48,6 @@ package GNAT.Sockets.Thin is
package C renames Interfaces.C;
- use type System.CRTL.ssize_t;
-
function Socket_Errno return Integer;
-- Returns last socket error number
diff --git a/gcc/ada/libgnat/g-socthi__vxworks.ads b/gcc/ada/libgnat/g-socthi__vxworks.ads
index 9cb4018..ac8eddf 100644
--- a/gcc/ada/libgnat/g-socthi__vxworks.ads
+++ b/gcc/ada/libgnat/g-socthi__vxworks.ads
@@ -49,8 +49,6 @@ package GNAT.Sockets.Thin is
package C renames Interfaces.C;
- use type System.CRTL.ssize_t;
-
function Socket_Errno return Integer renames GNAT.OS_Lib.Errno;
-- Returns last socket error number
diff --git a/gcc/ada/libgnat/s-os_lib.ads b/gcc/ada/libgnat/s-os_lib.ads
index 5fba00a..813ed1a 100644
--- a/gcc/ada/libgnat/s-os_lib.ads
+++ b/gcc/ada/libgnat/s-os_lib.ads
@@ -191,6 +191,9 @@ package System.OS_Lib is
Invalid_FD : constant File_Descriptor := -1;
-- File descriptor returned when error in opening/creating file
+ Null_FD : constant File_Descriptor := -2;
+ -- Uninitialized file descriptor
+
procedure Close (FD : File_Descriptor; Status : out Boolean);
-- Close file referenced by FD. Status is False if the underlying service
-- failed. Reasons for failure include: disk full, disk quotas exceeded
diff --git a/gcc/ada/libgnat/s-parame.adb b/gcc/ada/libgnat/s-parame.adb
index 0f4d45f..359edac 100644
--- a/gcc/ada/libgnat/s-parame.adb
+++ b/gcc/ada/libgnat/s-parame.adb
@@ -50,6 +50,34 @@ package body System.Parameters is
end if;
end Adjust_Storage_Size;
+ ----------------------------
+ -- Default_Sec_Stack_Size --
+ ----------------------------
+
+ function Default_Sec_Stack_Size return Size_Type is
+ Default_SS_Size : Integer;
+ pragma Import (C, Default_SS_Size,
+ "__gnat_default_ss_size");
+ begin
+ -- There are two situations where the default secondary stack size is
+ -- set to zero:
+ --
+ -- * The user sets it to zero erroneously thinking it will disable
+ -- the secondary stack.
+ --
+ -- * Or more likely, we are building with an old compiler and
+ -- Default_SS_Size is never set.
+ --
+ -- In both case set the default secondary stack size to the run-time
+ -- default.
+
+ if Default_SS_Size > 0 then
+ return Size_Type (Default_SS_Size);
+ else
+ return Runtime_Default_Sec_Stack_Size;
+ end if;
+ end Default_Sec_Stack_Size;
+
------------------------
-- Default_Stack_Size --
------------------------
diff --git a/gcc/ada/libgnat/s-parame.ads b/gcc/ada/libgnat/s-parame.ads
index f48c7e0..60a5e99 100644
--- a/gcc/ada/libgnat/s-parame.ads
+++ b/gcc/ada/libgnat/s-parame.ads
@@ -64,20 +64,6 @@ package System.Parameters is
Unspecified_Size : constant Size_Type := Size_Type'First;
-- Value used to indicate that no size type is set
- subtype Percentage is Size_Type range -1 .. 100;
- Dynamic : constant Size_Type := -1;
- -- The secondary stack ratio is a constant between 0 and 100 which
- -- determines the percentage of the allocated task stack that is
- -- used by the secondary stack (the rest being the primary stack).
- -- The special value of minus one indicates that the secondary
- -- stack is to be allocated from the heap instead.
-
- Sec_Stack_Percentage : constant Percentage := Dynamic;
- -- This constant defines the handling of the secondary stack
-
- Sec_Stack_Dynamic : constant Boolean := Sec_Stack_Percentage = Dynamic;
- -- Convenient Boolean for testing for dynamic secondary stack
-
function Default_Stack_Size return Size_Type;
-- Default task stack size used if none is specified
@@ -94,15 +80,27 @@ package System.Parameters is
-- otherwise return given Size
Default_Env_Stack_Size : constant Size_Type := 8_192_000;
- -- Assumed size of the environment task, if no other information
- -- is available. This value is used when stack checking is
- -- enabled and no GNAT_STACK_LIMIT environment variable is set.
+ -- Assumed size of the environment task, if no other information is
+ -- available. This value is used when stack checking is enabled and
+ -- no GNAT_STACK_LIMIT environment variable is set.
Stack_Grows_Down : constant Boolean := True;
-- This constant indicates whether the stack grows up (False) or
-- down (True) in memory as functions are called. It is used for
-- proper implementation of the stack overflow check.
+ Runtime_Default_Sec_Stack_Size : constant Size_Type := 10 * 1024;
+ -- The run-time chosen default size for secondary stacks that may be
+ -- overriden by the user with the use of binder -D switch.
+
+ function Default_Sec_Stack_Size return Size_Type;
+ -- The default initial size for secondary stacks that reflects any user
+ -- specified default via the binder -D switch.
+
+ Sec_Stack_Dynamic : constant Boolean := True;
+ -- Indicates if secondary stacks can grow and shrink at run-time. If False,
+ -- the size of a secondary stack is fixed at the point of its creation.
+
----------------------------------------------
-- Characteristics of types in Interfaces.C --
----------------------------------------------
diff --git a/gcc/ada/libgnat/s-parame__ae653.ads b/gcc/ada/libgnat/s-parame__ae653.ads
index 8a787f0..42d438e 100644
--- a/gcc/ada/libgnat/s-parame__ae653.ads
+++ b/gcc/ada/libgnat/s-parame__ae653.ads
@@ -62,20 +62,6 @@ package System.Parameters is
Unspecified_Size : constant Size_Type := Size_Type'First;
-- Value used to indicate that no size type is set
- subtype Percentage is Size_Type range -1 .. 100;
- Dynamic : constant Size_Type := -1;
- -- The secondary stack ratio is a constant between 0 and 100 which
- -- determines the percentage of the allocated task stack that is
- -- used by the secondary stack (the rest being the primary stack).
- -- The special value of minus one indicates that the secondary
- -- stack is to be allocated from the heap instead.
-
- Sec_Stack_Percentage : constant Percentage := 25;
- -- This constant defines the handling of the secondary stack
-
- Sec_Stack_Dynamic : constant Boolean := Sec_Stack_Percentage = Dynamic;
- -- Convenient Boolean for testing for dynamic secondary stack
-
function Default_Stack_Size return Size_Type;
-- Default task stack size used if none is specified
@@ -103,6 +89,18 @@ package System.Parameters is
-- down (True) in memory as functions are called. It is used for
-- proper implementation of the stack overflow check.
+ Runtime_Default_Sec_Stack_Size : constant Size_Type := 10 * 1024;
+ -- The run-time chosen default size for secondary stacks that may be
+ -- overriden by the user with the use of binder -D switch.
+
+ function Default_Sec_Stack_Size return Size_Type;
+ -- The default size for secondary stacks that reflects any user specified
+ -- default via the binder -D switch.
+
+ Sec_Stack_Dynamic : constant Boolean := False;
+ -- Indicates if secondary stacks can grow and shrink at run-time. If False,
+ -- the size of a secondary stack is fixed at the point of its creation.
+
----------------------------------------------
-- Characteristics of types in Interfaces.C --
----------------------------------------------
diff --git a/gcc/ada/libgnat/s-parame__hpux.ads b/gcc/ada/libgnat/s-parame__hpux.ads
index f20cfbe..846b1655 100644
--- a/gcc/ada/libgnat/s-parame__hpux.ads
+++ b/gcc/ada/libgnat/s-parame__hpux.ads
@@ -62,20 +62,6 @@ package System.Parameters is
Unspecified_Size : constant Size_Type := Size_Type'First;
-- Value used to indicate that no size type is set
- subtype Percentage is Size_Type range -1 .. 100;
- Dynamic : constant Size_Type := -1;
- -- The secondary stack ratio is a constant between 0 and 100 which
- -- determines the percentage of the allocated task stack that is
- -- used by the secondary stack (the rest being the primary stack).
- -- The special value of minus one indicates that the secondary
- -- stack is to be allocated from the heap instead.
-
- Sec_Stack_Percentage : constant Percentage := Dynamic;
- -- This constant defines the handling of the secondary stack
-
- Sec_Stack_Dynamic : constant Boolean := Sec_Stack_Percentage = Dynamic;
- -- Convenient Boolean for testing for dynamic secondary stack
-
function Default_Stack_Size return Size_Type;
-- Default task stack size used if none is specified
@@ -101,6 +87,18 @@ package System.Parameters is
-- down (True) in memory as functions are called. It is used for
-- proper implementation of the stack overflow check.
+ Runtime_Default_Sec_Stack_Size : constant Size_Type := 10 * 1024;
+ -- The run-time chosen default size for secondary stacks that may be
+ -- overriden by the user with the use of binder -D switch.
+
+ function Default_Sec_Stack_Size return Size_Type;
+ -- The default initial size for secondary stacks that reflects any user
+ -- specified default via the binder -D switch.
+
+ Sec_Stack_Dynamic : constant Boolean := True;
+ -- Indicates if secondary stacks can grow and shrink at run-time. If False,
+ -- the size of a secondary stack is fixed at the point of its creation.
+
----------------------------------------------
-- Characteristics of Types in Interfaces.C --
----------------------------------------------
diff --git a/gcc/ada/libgnat/s-parame__rtems.adb b/gcc/ada/libgnat/s-parame__rtems.adb
index aa13114..5a19c43 100644
--- a/gcc/ada/libgnat/s-parame__rtems.adb
+++ b/gcc/ada/libgnat/s-parame__rtems.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1997-2009 Free Software Foundation, Inc. --
+-- Copyright (C) 1997-2017, 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- --
@@ -39,6 +39,35 @@ package body System.Parameters is
pragma Import (C, ada_pthread_minimum_stack_size,
"_ada_pthread_minimum_stack_size");
+ -------------------------
+ -- Adjust_Storage_Size --
+ -------------------------
+
+ function Adjust_Storage_Size (Size : Size_Type) return Size_Type is
+ begin
+ if Size = Unspecified_Size then
+ return Default_Stack_Size;
+
+ elsif Size < Minimum_Stack_Size then
+ return Minimum_Stack_Size;
+
+ else
+ return Size;
+ end if;
+ end Adjust_Storage_Size;
+
+ ----------------------------
+ -- Default_Sec_Stack_Size --
+ ----------------------------
+
+ function Default_Sec_Stack_Size return Size_Type is
+ Default_SS_Size : Integer;
+ pragma Import (C, Default_SS_Size,
+ "__gnat_default_ss_size");
+ begin
+ return Size_Type (Default_SS_Size);
+ end Default_Sec_Stack_Size;
+
------------------------
-- Default_Stack_Size --
------------------------
@@ -58,21 +87,4 @@ package body System.Parameters is
return Size_Type (ada_pthread_minimum_stack_size);
end Minimum_Stack_Size;
- -------------------------
- -- Adjust_Storage_Size --
- -------------------------
-
- function Adjust_Storage_Size (Size : Size_Type) return Size_Type is
- begin
- if Size = Unspecified_Size then
- return Default_Stack_Size;
-
- elsif Size < Minimum_Stack_Size then
- return Minimum_Stack_Size;
-
- else
- return Size;
- end if;
- end Adjust_Storage_Size;
-
end System.Parameters;
diff --git a/gcc/ada/libgnat/s-parame__vxworks.adb b/gcc/ada/libgnat/s-parame__vxworks.adb
index 325aa2e..97d74b6 100644
--- a/gcc/ada/libgnat/s-parame__vxworks.adb
+++ b/gcc/ada/libgnat/s-parame__vxworks.adb
@@ -48,6 +48,18 @@ package body System.Parameters is
end if;
end Adjust_Storage_Size;
+ ----------------------------
+ -- Default_Sec_Stack_Size --
+ ----------------------------
+
+ function Default_Sec_Stack_Size return Size_Type is
+ Default_SS_Size : Integer;
+ pragma Import (C, Default_SS_Size,
+ "__gnat_default_ss_size");
+ begin
+ return Size_Type (Default_SS_Size);
+ end Default_Sec_Stack_Size;
+
------------------------
-- Default_Stack_Size --
------------------------
diff --git a/gcc/ada/libgnat/s-parame__vxworks.ads b/gcc/ada/libgnat/s-parame__vxworks.ads
index 919361a..e395e01 100644
--- a/gcc/ada/libgnat/s-parame__vxworks.ads
+++ b/gcc/ada/libgnat/s-parame__vxworks.ads
@@ -62,20 +62,6 @@ package System.Parameters is
Unspecified_Size : constant Size_Type := Size_Type'First;
-- Value used to indicate that no size type is set
- subtype Percentage is Size_Type range -1 .. 100;
- Dynamic : constant Size_Type := -1;
- -- The secondary stack ratio is a constant between 0 and 100 which
- -- determines the percentage of the allocated task stack that is
- -- used by the secondary stack (the rest being the primary stack).
- -- The special value of minus one indicates that the secondary
- -- stack is to be allocated from the heap instead.
-
- Sec_Stack_Percentage : constant Percentage := Dynamic;
- -- This constant defines the handling of the secondary stack
-
- Sec_Stack_Dynamic : constant Boolean := Sec_Stack_Percentage = Dynamic;
- -- Convenient Boolean for testing for dynamic secondary stack
-
function Default_Stack_Size return Size_Type;
-- Default task stack size used if none is specified
@@ -103,6 +89,18 @@ package System.Parameters is
-- down (True) in memory as functions are called. It is used for
-- proper implementation of the stack overflow check.
+ Runtime_Default_Sec_Stack_Size : constant Size_Type := 10 * 1024;
+ -- The run-time chosen default size for secondary stacks that may be
+ -- overriden by the user with the use of binder -D switch.
+
+ function Default_Sec_Stack_Size return Size_Type;
+ -- The default initial size for secondary stacks that reflects any user
+ -- specified default via the binder -D switch.
+
+ Sec_Stack_Dynamic : constant Boolean := True;
+ -- Indicates if secondary stacks can grow and shrink at run-time. If False,
+ -- the size of a secondary stack is fixed at the point of its creation.
+
----------------------------------------------
-- Characteristics of types in Interfaces.C --
----------------------------------------------
diff --git a/gcc/ada/libgnat/s-resfil.ads b/gcc/ada/libgnat/s-resfil.ads
index fbb7f7af..1a24a99 100644
--- a/gcc/ada/libgnat/s-resfil.ads
+++ b/gcc/ada/libgnat/s-resfil.ads
@@ -29,8 +29,8 @@
-- --
------------------------------------------------------------------------------
--- This package provides facilities for getting command line arguments
--- from a text file, called a "response file".
+-- This package provides facilities for getting command-line arguments from
+-- a text file, called a "response file".
--
-- Using a response file allow passing a set of arguments to an executable
-- longer than the maximum allowed by the system on the command line.
diff --git a/gcc/ada/libgnat/s-secsta.adb b/gcc/ada/libgnat/s-secsta.adb
index 0449ee4..b39cf0d 100644
--- a/gcc/ada/libgnat/s-secsta.adb
+++ b/gcc/ada/libgnat/s-secsta.adb
@@ -31,203 +31,65 @@
pragma Compiler_Unit_Warning;
-with System.Soft_Links;
-with System.Parameters;
-
with Ada.Unchecked_Conversion;
with Ada.Unchecked_Deallocation;
+with System.Soft_Links;
package body System.Secondary_Stack is
package SSL renames System.Soft_Links;
- use type SSE.Storage_Offset;
use type System.Parameters.Size_Type;
- SS_Ratio_Dynamic : constant Boolean :=
- Parameters.Sec_Stack_Percentage = Parameters.Dynamic;
- -- There are two entirely different implementations of the secondary
- -- stack mechanism in this unit, and this Boolean is used to select
- -- between them (at compile time, so the generated code will contain
- -- only the code for the desired variant). If SS_Ratio_Dynamic is
- -- True, then the secondary stack is dynamically allocated from the
- -- heap in a linked list of chunks. If SS_Ration_Dynamic is False,
- -- then the secondary stack is allocated statically by grabbing a
- -- section of the primary stack and using it for this purpose.
-
- type Memory is array (SS_Ptr range <>) of SSE.Storage_Element;
- for Memory'Alignment use Standard'Maximum_Alignment;
- -- This is the type used for actual allocation of secondary stack
- -- areas. We require maximum alignment for all such allocations.
-
- ---------------------------------------------------------------
- -- Data Structures for Dynamically Allocated Secondary Stack --
- ---------------------------------------------------------------
-
- -- The following is a diagram of the data structures used for the
- -- case of a dynamically allocated secondary stack, where the stack
- -- is allocated as a linked list of chunks allocated from the heap.
-
- -- +------------------+
- -- | Next |
- -- +------------------+
- -- | | Last (200)
- -- | |
- -- | |
- -- | |
- -- | |
- -- | |
- -- | | First (101)
- -- +------------------+
- -- +----------> | | |
- -- | +--------- | ------+
- -- | ^ |
- -- | | |
- -- | | V
- -- | +------ | ---------+
- -- | | | |
- -- | +------------------+
- -- | | | Last (100)
- -- | | C |
- -- | | H |
- -- +-----------------+ | +------->| U |
- -- | Current_Chunk ----+ | | N |
- -- +-----------------+ | | K |
- -- | Top --------+ | | First (1)
- -- +-----------------+ +------------------+
- -- | Default_Size | | Prev |
- -- +-----------------+ +------------------+
- --
-
- type Chunk_Id (First, Last : SS_Ptr);
- type Chunk_Ptr is access all Chunk_Id;
-
- type Chunk_Id (First, Last : SS_Ptr) is record
- Prev, Next : Chunk_Ptr;
- Mem : Memory (First .. Last);
- end record;
-
- type Stack_Id is record
- Top : SS_Ptr;
- Default_Size : SSE.Storage_Count;
- Current_Chunk : Chunk_Ptr;
- end record;
-
- type Stack_Ptr is access Stack_Id;
- -- Pointer to record used to represent a dynamically allocated secondary
- -- stack descriptor for a secondary stack chunk.
-
procedure Free is new Ada.Unchecked_Deallocation (Chunk_Id, Chunk_Ptr);
-- Free a dynamically allocated chunk
- function To_Stack_Ptr is new
- Ada.Unchecked_Conversion (Address, Stack_Ptr);
- function To_Addr is new
- Ada.Unchecked_Conversion (Stack_Ptr, Address);
- -- Convert to and from address stored in task data structures
-
- --------------------------------------------------------------
- -- Data Structures for Statically Allocated Secondary Stack --
- --------------------------------------------------------------
-
- -- For the static case, the secondary stack is a single contiguous
- -- chunk of storage, carved out of the primary stack, and represented
- -- by the following data structure
-
- type Fixed_Stack_Id is record
- Top : SS_Ptr;
- -- Index of next available location in Mem. This is initialized to
- -- 0, and then incremented on Allocate, and Decremented on Release.
-
- Last : SS_Ptr;
- -- Length of usable Mem array, which is thus the index past the
- -- last available location in Mem. Mem (Last-1) can be used. This
- -- is used to check that the stack does not overflow.
-
- Max : SS_Ptr;
- -- Maximum value of Top. Initialized to 0, and then may be incremented
- -- on Allocate, but is never Decremented. The last used location will
- -- be Mem (Max - 1), so Max is the maximum count of used stack space.
-
- Mem : Memory (0 .. 0);
- -- This is the area that is actually used for the secondary stack.
- -- Note that the upper bound is a dummy value properly defined by
- -- the value of Last. We never actually allocate objects of type
- -- Fixed_Stack_Id, so the bounds declared here do not matter.
- end record;
-
- Dummy_Fixed_Stack : Fixed_Stack_Id;
- pragma Warnings (Off, Dummy_Fixed_Stack);
- -- Well it is not quite true that we never allocate an object of the
- -- type. This dummy object is allocated for the purpose of getting the
- -- offset of the Mem field via the 'Position attribute (such a nuisance
- -- that we cannot apply this to a field of a type).
-
- type Fixed_Stack_Ptr is access Fixed_Stack_Id;
- -- Pointer to record used to describe statically allocated sec stack
-
- function To_Fixed_Stack_Ptr is new
- Ada.Unchecked_Conversion (Address, Fixed_Stack_Ptr);
- -- Convert from address stored in task data structures
-
- ----------------------------------
- -- Minimum_Secondary_Stack_Size --
- ----------------------------------
-
- function Minimum_Secondary_Stack_Size return Natural is
- begin
- return Dummy_Fixed_Stack.Mem'Position;
- end Minimum_Secondary_Stack_Size;
-
- --------------
- -- Allocate --
- --------------
+ -----------------
+ -- SS_Allocate --
+ -----------------
procedure SS_Allocate
(Addr : out Address;
Storage_Size : SSE.Storage_Count)
is
- Max_Align : constant SS_Ptr := SS_Ptr (Standard'Maximum_Alignment);
- Max_Size : constant SS_Ptr :=
- ((SS_Ptr (Storage_Size) + Max_Align - 1) / Max_Align) *
- Max_Align;
-
+ Max_Align : constant SS_Ptr := SS_Ptr (Standard'Maximum_Alignment);
+ Mem_Request : constant SS_Ptr :=
+ ((SS_Ptr (Storage_Size) + Max_Align - 1) / Max_Align) *
+ Max_Align;
+ -- Round up Storage_Size to the nearest multiple of the max alignment
+ -- value for the target. This ensures efficient stack access.
+
+ Stack : constant SS_Stack_Ptr := SSL.Get_Sec_Stack.all;
begin
- -- Case of fixed allocation secondary stack
-
- if not SS_Ratio_Dynamic then
- declare
- Fixed_Stack : constant Fixed_Stack_Ptr :=
- To_Fixed_Stack_Ptr (SSL.Get_Sec_Stack_Addr.all);
+ -- Case of fixed secondary stack
- begin
- -- Check if max stack usage is increasing
+ if not SP.Sec_Stack_Dynamic then
+ -- Check if max stack usage is increasing
- if Fixed_Stack.Top + Max_Size > Fixed_Stack.Max then
+ if Stack.Top + Mem_Request > Stack.Max then
- -- If so, check if max size is exceeded
+ -- If so, check if the stack is exceeded, noting Stack.Top points
+ -- to the first free byte (so the value of Stack.Top on a fully
+ -- allocated stack will be Stack.Size + 1).
- if Fixed_Stack.Top + Max_Size > Fixed_Stack.Last then
- raise Storage_Error;
- end if;
+ if Stack.Top + Mem_Request > Stack.Size + 1 then
+ raise Storage_Error;
+ end if;
- -- Record new max usage
+ -- Record new max usage
- Fixed_Stack.Max := Fixed_Stack.Top + Max_Size;
- end if;
+ Stack.Max := Stack.Top + Mem_Request;
+ end if;
- -- Set resulting address and update top of stack pointer
+ -- Set resulting address and update top of stack pointer
- Addr := Fixed_Stack.Mem (Fixed_Stack.Top)'Address;
- Fixed_Stack.Top := Fixed_Stack.Top + Max_Size;
- end;
+ Addr := Stack.Internal_Chunk.Mem (Stack.Top)'Address;
+ Stack.Top := Stack.Top + Mem_Request;
- -- Case of dynamically allocated secondary stack
+ -- Case of dynamic secondary stack
else
declare
- Stack : constant Stack_Ptr :=
- To_Stack_Ptr (SSL.Get_Sec_Stack_Addr.all);
Chunk : Chunk_Ptr;
To_Be_Released_Chunk : Chunk_Ptr;
@@ -235,7 +97,7 @@ package body System.Secondary_Stack is
begin
Chunk := Stack.Current_Chunk;
- -- The Current_Chunk may not be the good one if a lot of release
+ -- The Current_Chunk may not be the best one if a lot of release
-- operations have taken place. Go down the stack if necessary.
while Chunk.First > Stack.Top loop
@@ -246,7 +108,7 @@ package body System.Secondary_Stack is
-- sufficient, if not, go to the next one and eventually create
-- the necessary room.
- while Chunk.Last - Stack.Top + 1 < Max_Size loop
+ while Chunk.Last - Stack.Top + 1 < Mem_Request loop
if Chunk.Next /= null then
-- Release unused non-first empty chunk
@@ -262,11 +124,11 @@ package body System.Secondary_Stack is
-- Create new chunk of default size unless it is not sufficient
-- to satisfy the current request.
- elsif SSE.Storage_Count (Max_Size) <= Stack.Default_Size then
+ elsif Mem_Request <= Stack.Size then
Chunk.Next :=
new Chunk_Id
(First => Chunk.Last + 1,
- Last => Chunk.Last + SS_Ptr (Stack.Default_Size));
+ Last => Chunk.Last + SS_Ptr (Stack.Size));
Chunk.Next.Prev := Chunk;
@@ -276,7 +138,7 @@ package body System.Secondary_Stack is
Chunk.Next :=
new Chunk_Id
(First => Chunk.Last + 1,
- Last => Chunk.Last + Max_Size);
+ Last => Chunk.Last + Mem_Request);
Chunk.Next.Prev := Chunk;
end if;
@@ -288,8 +150,15 @@ package body System.Secondary_Stack is
-- Resulting address is the address pointed by Stack.Top
Addr := Chunk.Mem (Stack.Top)'Address;
- Stack.Top := Stack.Top + Max_Size;
+ Stack.Top := Stack.Top + Mem_Request;
Stack.Current_Chunk := Chunk;
+
+ -- Record new max usage
+
+ if Stack.Top > Stack.Max then
+ Stack.Max := Stack.Top;
+ end if;
+
end;
end if;
end SS_Allocate;
@@ -298,40 +167,39 @@ package body System.Secondary_Stack is
-- SS_Free --
-------------
- procedure SS_Free (Stk : in out Address) is
+ procedure SS_Free (Stack : in out SS_Stack_Ptr) is
+ procedure Free is
+ new Ada.Unchecked_Deallocation (SS_Stack, SS_Stack_Ptr);
begin
- -- Case of statically allocated secondary stack, nothing to free
-
- if not SS_Ratio_Dynamic then
- return;
+ -- If using dynamic secondary stack, free any external chunks
- -- Case of dynamically allocated secondary stack
-
- else
+ if SP.Sec_Stack_Dynamic then
declare
- Stack : Stack_Ptr := To_Stack_Ptr (Stk);
Chunk : Chunk_Ptr;
procedure Free is
- new Ada.Unchecked_Deallocation (Stack_Id, Stack_Ptr);
+ new Ada.Unchecked_Deallocation (Chunk_Id, Chunk_Ptr);
begin
Chunk := Stack.Current_Chunk;
- while Chunk.Prev /= null loop
- Chunk := Chunk.Prev;
- end loop;
+ -- Go to top of linked list and free backwards. Do not free the
+ -- internal chunk as it is part of SS_Stack.
while Chunk.Next /= null loop
Chunk := Chunk.Next;
- Free (Chunk.Prev);
end loop;
- Free (Chunk);
- Free (Stack);
- Stk := Null_Address;
+ while Chunk.Prev /= null loop
+ Chunk := Chunk.Prev;
+ Free (Chunk.Next);
+ end loop;
end;
end if;
+
+ if Stack.Freeable then
+ Free (Stack);
+ end if;
end SS_Free;
----------------
@@ -339,17 +207,13 @@ package body System.Secondary_Stack is
----------------
function SS_Get_Max return Long_Long_Integer is
+ Stack : constant SS_Stack_Ptr := SSL.Get_Sec_Stack.all;
begin
- if SS_Ratio_Dynamic then
- return -1;
- else
- declare
- Fixed_Stack : constant Fixed_Stack_Ptr :=
- To_Fixed_Stack_Ptr (SSL.Get_Sec_Stack_Addr.all);
- begin
- return Long_Long_Integer (Fixed_Stack.Max);
- end;
- end if;
+ -- Stack.Max points to the first untouched byte in the stack, thus the
+ -- maximum number of bytes that have been allocated on the stack is one
+ -- less the value of Stack.Max.
+
+ return Long_Long_Integer (Stack.Max - 1);
end SS_Get_Max;
-------------
@@ -357,32 +221,25 @@ package body System.Secondary_Stack is
-------------
procedure SS_Info is
+ Stack : constant SS_Stack_Ptr := SSL.Get_Sec_Stack.all;
begin
Put_Line ("Secondary Stack information:");
-- Case of fixed secondary stack
- if not SS_Ratio_Dynamic then
- declare
- Fixed_Stack : constant Fixed_Stack_Ptr :=
- To_Fixed_Stack_Ptr (SSL.Get_Sec_Stack_Addr.all);
-
- begin
- Put_Line (" Total size : "
- & SS_Ptr'Image (Fixed_Stack.Last)
- & " bytes");
+ if not SP.Sec_Stack_Dynamic then
+ Put_Line (" Total size : "
+ & SS_Ptr'Image (Stack.Size)
+ & " bytes");
- Put_Line (" Current allocated space : "
- & SS_Ptr'Image (Fixed_Stack.Top)
- & " bytes");
- end;
+ Put_Line (" Current allocated space : "
+ & SS_Ptr'Image (Stack.Top - 1)
+ & " bytes");
- -- Case of dynamically allocated secondary stack
+ -- Case of dynamic secondary stack
else
declare
- Stack : constant Stack_Ptr :=
- To_Stack_Ptr (SSL.Get_Sec_Stack_Addr.all);
Nb_Chunks : Integer := 1;
Chunk : Chunk_Ptr := Stack.Current_Chunk;
@@ -414,7 +271,7 @@ package body System.Secondary_Stack is
& Integer'Image (Nb_Chunks));
Put_Line (" Default size of Chunks : "
- & SSE.Storage_Count'Image (Stack.Default_Size));
+ & SP.Size_Type'Image (Stack.Size));
end;
end if;
end SS_Info;
@@ -424,42 +281,86 @@ package body System.Secondary_Stack is
-------------
procedure SS_Init
- (Stk : in out Address;
- Size : Natural := Default_Secondary_Stack_Size)
+ (Stack : in out SS_Stack_Ptr;
+ Size : SP.Size_Type := SP.Unspecified_Size)
is
- begin
- -- Case of fixed size secondary stack
-
- if not SS_Ratio_Dynamic then
- declare
- Fixed_Stack : constant Fixed_Stack_Ptr :=
- To_Fixed_Stack_Ptr (Stk);
-
- begin
- Fixed_Stack.Top := 0;
- Fixed_Stack.Max := 0;
-
- if Size <= Dummy_Fixed_Stack.Mem'Position then
- Fixed_Stack.Last := 0;
- else
- Fixed_Stack.Last :=
- SS_Ptr (Size) - Dummy_Fixed_Stack.Mem'Position;
- end if;
- end;
-
- -- Case of dynamically allocated secondary stack
+ use Parameters;
- else
- declare
- Stack : Stack_Ptr;
- begin
- Stack := new Stack_Id;
- Stack.Current_Chunk := new Chunk_Id (1, SS_Ptr (Size));
- Stack.Top := 1;
- Stack.Default_Size := SSE.Storage_Count (Size);
- Stk := To_Addr (Stack);
- end;
+ Stack_Size : Size_Type;
+ begin
+ -- If Stack is not null then the stack has been allocated outside the
+ -- package (by the compiler or the user) and all that is left to do is
+ -- initialize the stack. Otherwise, SS_Init will allocate a secondary
+ -- stack from either the heap or the default-sized secondary stack pool
+ -- generated by the binder. In the later case, this pool is generated
+ -- only when the either No_Implicit_Heap_Allocations
+ -- or No_Implicit_Task_Allocations are active, and SS_Init will allocate
+ -- all requests for a secondary stack of Unspecified_Size from this
+ -- pool.
+
+ if Stack = null then
+ if Size = Unspecified_Size then
+ Stack_Size := Default_Sec_Stack_Size;
+ else
+ Stack_Size := Size;
+ end if;
+
+ if Size = Unspecified_Size
+ and then Binder_SS_Count > 0
+ and then Num_Of_Assigned_Stacks < Binder_SS_Count
+ then
+ -- The default-sized secondary stack pool is passed from the
+ -- binder to this package as an Address since it is not possible
+ -- to have a pointer to an array of unconstrained objects. A
+ -- pointer to the pool is obtainable via an unchecked conversion
+ -- to a constrained array of SS_Stacks that mirrors the one used
+ -- by the binder.
+
+ -- However, Ada understandably does not allow a local pointer to
+ -- a stack in the pool to be stored in a pointer outside of this
+ -- scope. While the conversion is safe in this case, since a view
+ -- of a global object is being used, using Unchecked_Access
+ -- would prevent users from specifying the restriction
+ -- No_Unchecked_Access whenever the secondary stack is used. As
+ -- a workaround, the local stack pointer is converted to a global
+ -- pointer via System.Address.
+
+ declare
+ type Stk_Pool_Array is array (1 .. Binder_SS_Count) of
+ aliased SS_Stack (Default_SS_Size);
+ type Stk_Pool_Access is access Stk_Pool_Array;
+
+ function To_Stack_Pool is new
+ Ada.Unchecked_Conversion (Address, Stk_Pool_Access);
+
+ pragma Warnings (Off);
+ function To_Global_Ptr is new
+ Ada.Unchecked_Conversion (Address, SS_Stack_Ptr);
+ pragma Warnings (On);
+ -- Suppress aliasing warning since the pointer we return will
+ -- be the only access to the stack.
+
+ Local_Stk_Address : System.Address;
+
+ begin
+ Num_Of_Assigned_Stacks := Num_Of_Assigned_Stacks + 1;
+
+ Local_Stk_Address :=
+ To_Stack_Pool
+ (Default_Sized_SS_Pool) (Num_Of_Assigned_Stacks)'Address;
+ Stack := To_Global_Ptr (Local_Stk_Address);
+ end;
+
+ Stack.Freeable := False;
+ else
+ Stack := new SS_Stack (Stack_Size);
+ Stack.Freeable := True;
+ end if;
end if;
+
+ Stack.Top := 1;
+ Stack.Max := 1;
+ Stack.Current_Chunk := Stack.Internal_Chunk'Access;
end SS_Init;
-------------
@@ -467,13 +368,9 @@ package body System.Secondary_Stack is
-------------
function SS_Mark return Mark_Id is
- Sstk : constant System.Address := SSL.Get_Sec_Stack_Addr.all;
+ Stack : constant SS_Stack_Ptr := SSL.Get_Sec_Stack.all;
begin
- if SS_Ratio_Dynamic then
- return (Sstk => Sstk, Sptr => To_Stack_Ptr (Sstk).Top);
- else
- return (Sstk => Sstk, Sptr => To_Fixed_Stack_Ptr (Sstk).Top);
- end if;
+ return (Sec_Stack => Stack, Sptr => Stack.Top);
end SS_Mark;
----------------
@@ -482,66 +379,7 @@ package body System.Secondary_Stack is
procedure SS_Release (M : Mark_Id) is
begin
- if SS_Ratio_Dynamic then
- To_Stack_Ptr (M.Sstk).Top := M.Sptr;
- else
- To_Fixed_Stack_Ptr (M.Sstk).Top := M.Sptr;
- end if;
+ M.Sec_Stack.Top := M.Sptr;
end SS_Release;
- -------------------------
- -- Package Elaboration --
- -------------------------
-
- -- Allocate a secondary stack for the main program to use
-
- -- We make sure that the stack has maximum alignment. Some systems require
- -- this (e.g. Sparc), and in any case it is a good idea for efficiency.
-
- Stack : aliased Stack_Id;
- for Stack'Alignment use Standard'Maximum_Alignment;
-
- Static_Secondary_Stack_Size : constant := 10 * 1024;
- -- Static_Secondary_Stack_Size must be static so that Chunk is allocated
- -- statically, and not via dynamic memory allocation.
-
- Chunk : aliased Chunk_Id (1, Static_Secondary_Stack_Size);
- for Chunk'Alignment use Standard'Maximum_Alignment;
- -- Default chunk used, unless gnatbind -D is specified with a value greater
- -- than Static_Secondary_Stack_Size.
-
-begin
- declare
- Chunk_Address : Address;
- Chunk_Access : Chunk_Ptr;
-
- begin
- if Default_Secondary_Stack_Size <= Static_Secondary_Stack_Size then
-
- -- Normally we allocate the secondary stack for the main program
- -- statically, using the default secondary stack size.
-
- Chunk_Access := Chunk'Access;
-
- else
- -- Default_Secondary_Stack_Size was increased via gnatbind -D, so we
- -- need to allocate a chunk dynamically.
-
- Chunk_Access :=
- new Chunk_Id (1, SS_Ptr (Default_Secondary_Stack_Size));
- end if;
-
- if SS_Ratio_Dynamic then
- Stack.Top := 1;
- Stack.Current_Chunk := Chunk_Access;
- Stack.Default_Size :=
- SSE.Storage_Offset (Default_Secondary_Stack_Size);
- System.Soft_Links.Set_Sec_Stack_Addr_NT (Stack'Address);
-
- else
- Chunk_Address := Chunk_Access.all'Address;
- SS_Init (Chunk_Address, Default_Secondary_Stack_Size);
- System.Soft_Links.Set_Sec_Stack_Addr_NT (Chunk_Address);
- end if;
- end;
end System.Secondary_Stack;
diff --git a/gcc/ada/libgnat/s-secsta.ads b/gcc/ada/libgnat/s-secsta.ads
index 534708d..ae5ec88 100644
--- a/gcc/ada/libgnat/s-secsta.ads
+++ b/gcc/ada/libgnat/s-secsta.ads
@@ -31,41 +31,27 @@
pragma Compiler_Unit_Warning;
+with System.Parameters;
with System.Storage_Elements;
package System.Secondary_Stack is
+ pragma Preelaborate;
+ package SP renames System.Parameters;
package SSE renames System.Storage_Elements;
- Default_Secondary_Stack_Size : Natural := 10 * 1024;
- -- Default size of a secondary stack. May be modified by binder -D switch
- -- which causes the binder to generate an appropriate assignment in the
- -- binder generated file.
+ type SS_Stack (Size : SP.Size_Type) is private;
+ -- Data structure for secondary stacks
- function Minimum_Secondary_Stack_Size return Natural;
- -- The minimum size of the secondary stack so that the internal
- -- requirements of the stack are met.
+ type SS_Stack_Ptr is access all SS_Stack;
+ -- Pointer to secondary stack objects
procedure SS_Init
- (Stk : in out Address;
- Size : Natural := Default_Secondary_Stack_Size);
- -- Initialize the secondary stack with a main stack of the given Size.
- --
- -- If System.Parameters.Sec_Stack_Percentage equals Dynamic, Stk is really
- -- an OUT parameter that will be allocated on the heap. Then all further
- -- allocations which do not overflow the main stack will not generate
- -- dynamic (de)allocation calls. If the main Stack overflows, a new
- -- chuck of at least the same size will be allocated and linked to the
- -- previous chunk.
- --
- -- Otherwise (Sec_Stack_Percentage between 0 and 100), Stk is an IN
- -- parameter that is already pointing to a Stack_Id. The secondary stack
- -- in this case is fixed, and any attempt to allocate more than the initial
- -- size will result in a Storage_Error being raised.
- --
- -- Note: the reason that Stk is passed is that SS_Init is called before
- -- the proper interface is established to obtain the address of the
- -- stack using System.Soft_Links.Get_Sec_Stack_Addr.
+ (Stack : in out SS_Stack_Ptr;
+ Size : SP.Size_Type := SP.Unspecified_Size);
+ -- Initialize the secondary stack Stack. If Stack is null allocate a stack
+ -- from the heap or from the default-sized secondary stack pool if the
+ -- pool exists and the requested size is Unspecified_Size.
procedure SS_Allocate
(Addr : out Address;
@@ -73,10 +59,9 @@ package System.Secondary_Stack is
-- Allocate enough space for a 'Storage_Size' bytes object with Maximum
-- alignment. The address of the allocated space is returned in Addr.
- procedure SS_Free (Stk : in out Address);
- -- Release the memory allocated for the Secondary Stack. That is
- -- to say, all the allocated chunks. Upon return, Stk will be set
- -- to System.Null_Address.
+ procedure SS_Free (Stack : in out SS_Stack_Ptr);
+ -- Release the memory allocated for the Stack. If the stack was statically
+ -- allocated the SS_Stack record is not freed.
type Mark_Id is private;
-- Type used to mark the stack for mark/release processing
@@ -85,17 +70,11 @@ package System.Secondary_Stack is
-- Return the Mark corresponding to the current state of the stack
procedure SS_Release (M : Mark_Id);
- -- Restore the state of the stack corresponding to the mark M. If an
- -- additional chunk have been allocated, it will never be freed during a
- -- ??? missing comment here
+ -- Restore the state of the stack corresponding to the mark M
function SS_Get_Max return Long_Long_Integer;
- -- Return maximum used space in storage units for the current secondary
- -- stack. For a dynamically allocated secondary stack, the returned
- -- result is always -1. For a statically allocated secondary stack,
- -- the returned value shows the largest amount of space allocated so
- -- far during execution of the program to the current secondary stack,
- -- i.e. the secondary stack for the current task.
+ -- Return the high water mark of the secondary stack for the current
+ -- secondary stack in bytes.
generic
with procedure Put_Line (S : String);
@@ -109,15 +88,142 @@ private
-- Unused entity that is just present to ease the sharing of the pool
-- mechanism for specific allocation/deallocation in the compiler
- type SS_Ptr is new SSE.Integer_Address;
- -- Stack pointer value for secondary stack
+ -------------------------------------
+ -- Secondary Stack Data Structures --
+ -------------------------------------
+
+ -- This package provides fixed and dynamically sized secondary stack
+ -- implementations centered around a common data structure SS_Stack. This
+ -- record contains an initial secondary stack allocation of the requested
+ -- size, and markers for the current top of the stack and the high-water
+ -- mark of the stack. A SS_Stack can be either pre-allocated outside the
+ -- package or SS_Init can allocate a stack from the heap or the
+ -- default-sized secondary stack from a pool generated by the binder.
+
+ -- For dynamically allocated secondary stacks, the stack can grow via a
+ -- linked list of stack chunks allocated from the heap. New chunks are
+ -- allocated once the initial static allocation and any existing chunks are
+ -- exhausted. The following diagram illustrated the data structures used
+ -- for a dynamically allocated secondary stack:
+ --
+ -- +------------------+
+ -- | Next |
+ -- +------------------+
+ -- | | Last (300)
+ -- | |
+ -- | |
+ -- | |
+ -- | |
+ -- | |
+ -- | | First (201)
+ -- +------------------+
+ -- +-----------------+ +------> | | |
+ -- | | (100) | +--------- | ------+
+ -- | | | ^ |
+ -- | | | | |
+ -- | | | | V
+ -- | | | +------ | ---------+
+ -- | | | | | |
+ -- | | | +------------------+
+ -- | | | | | Last (200)
+ -- | | | | C |
+ -- | | (1) | | H |
+ -- +-----------------+ | +---->| U |
+ -- | Current_Chunk ---------+ | | N |
+ -- +-----------------+ | | K |
+ -- | Top ------------+ | | First (101)
+ -- +-----------------+ +------------------+
+ -- | Size | | Prev |
+ -- +-----------------+ +------------------+
+ --
+ -- The implementation used by the runtime is controlled via the constant
+ -- System.Parameter.Sec_Stack_Dynamic. If True, the implementation is
+ -- permitted to grow the secondary stack at runtime. The implementation is
+ -- designed for the compiler to include only code to support the desired
+ -- secondary stack behavior.
+
+ subtype SS_Ptr is SP.Size_Type;
+ -- Stack pointer value for the current position within the secondary stack.
+ -- Size_Type is used as the base type since the Size discriminate of
+ -- SS_Stack forms the bounds of the internal memory array.
+
+ type Memory is array (SS_Ptr range <>) of SSE.Storage_Element;
+ for Memory'Alignment use Standard'Maximum_Alignment;
+ -- The region of memory that holds the stack itself. Requires maximum
+ -- alignment for efficient stack operations.
+
+ -- Chunk_Id
+
+ -- Chunk_Id is a contiguous block of dynamically allocated stack. First
+ -- and Last indicate the range of secondary stack addresses present in the
+ -- chunk. Chunk_Ptr points to a Chunk_Id block.
+
+ type Chunk_Id (First, Last : SS_Ptr);
+ type Chunk_Ptr is access all Chunk_Id;
+
+ type Chunk_Id (First, Last : SS_Ptr) is record
+ Prev, Next : Chunk_Ptr;
+ Mem : Memory (First .. Last);
+ end record;
+
+ -- Secondary stack data structure
+
+ type SS_Stack (Size : SP.Size_Type) is record
+ Top : SS_Ptr;
+ -- Index of next available location in the stack. Initialized to 1 and
+ -- then incremented on Allocate and decremented on Release.
+
+ Max : SS_Ptr;
+ -- Contains the high-water mark of Top. Initialized to 1 and then
+ -- may be incremented on Allocate but never decremented. Since
+ -- Top = Size + 1 represents a fully used stack, Max - 1 indicates
+ -- the size of the stack used in bytes.
+
+ Current_Chunk : Chunk_Ptr;
+ -- A link to the chunk containing the highest range of the stack
+
+ Freeable : Boolean;
+ -- Indicates if an object of this type can be freed
+
+ Internal_Chunk : aliased Chunk_Id (1, Size);
+ -- Initial memory allocation of the secondary stack
+ end record;
type Mark_Id is record
- Sstk : System.Address;
- Sptr : SS_Ptr;
+ Sec_Stack : SS_Stack_Ptr;
+ Sptr : SS_Ptr;
end record;
- -- A mark value contains the address of the secondary stack structure,
- -- as returned by System.Soft_Links.Get_Sec_Stack_Addr, and a stack
- -- pointer value corresponding to the point of the mark call.
+ -- Contains the pointer to the secondary stack object and the stack pointer
+ -- value corresponding to the top of the stack at the time of the mark
+ -- call.
+
+ ------------------------------------
+ -- Binder Allocated Stack Support --
+ ------------------------------------
+
+ -- When the No_Implicit_Heap_Allocations or No_Implicit_Task_Allocations
+ -- restrictions are in effect the binder statically generates secondary
+ -- stacks for tasks who are using default-sized secondary stack. Assignment
+ -- of these stacks to tasks is handled by SS_Init. The following variables
+ -- assist SS_Init and are defined here so the runtime does not depend on
+ -- the binder.
+
+ Binder_SS_Count : Natural;
+ pragma Export (Ada, Binder_SS_Count, "__gnat_binder_ss_count");
+ -- The number of default sized secondary stacks allocated by the binder
+
+ Default_SS_Size : SP.Size_Type;
+ pragma Export (Ada, Default_SS_Size, "__gnat_default_ss_size");
+ -- The default size for secondary stacks. Defined here and not in init.c/
+ -- System.Init because these locations are not present on ZFP or
+ -- Ravenscar-SFP run-times.
+
+ Default_Sized_SS_Pool : System.Address;
+ pragma Export (Ada, Default_Sized_SS_Pool, "__gnat_default_ss_pool");
+ -- Address to the secondary stack pool generated by the binder that
+ -- contains default sized stacks.
+
+ Num_Of_Assigned_Stacks : Natural := 0;
+ -- The number of currently allocated secondary stacks
end System.Secondary_Stack;
diff --git a/gcc/ada/libgnat/s-soflin.adb b/gcc/ada/libgnat/s-soflin.adb
index f604f4d..94ead03 100644
--- a/gcc/ada/libgnat/s-soflin.adb
+++ b/gcc/ada/libgnat/s-soflin.adb
@@ -35,25 +35,19 @@ pragma Polling (Off);
-- We must turn polling off for this unit, because otherwise we get an
-- infinite loop from the code within the Poll routine itself.
-with System.Parameters;
-
pragma Warnings (Off);
--- Disable warnings since System.Secondary_Stack is currently not Preelaborate
-with System.Secondary_Stack;
+-- Disable warnings as System.Soft_Links.Initialize is not Preelaborate. It is
+-- safe to with this unit as its elaboration routine will only be initializing
+-- NT_TSD, which is part of this package spec.
+with System.Soft_Links.Initialize;
pragma Warnings (On);
package body System.Soft_Links is
- package SST renames System.Secondary_Stack;
-
- NT_TSD : TSD;
- -- Note: we rely on the default initialization of NT_TSD
-
- -- Needed for Vx6Cert (Vx653mc) GOS cert and ravenscar-cert runtimes,
- -- VxMILS cert, ravenscar-cert and full runtimes, Vx 5 default runtime
Stack_Limit : aliased System.Address := System.Null_Address;
-
pragma Export (C, Stack_Limit, "__gnat_stack_limit");
+ -- Needed for Vx6Cert (Vx653mc) GOS cert and ravenscar-cert runtimes,
+ -- VxMILS cert, ravenscar-cert and full runtimes, Vx 5 default runtime
--------------------
-- Abort_Defer_NT --
@@ -125,14 +119,16 @@ package body System.Soft_Links is
-- Create_TSD --
----------------
- procedure Create_TSD (New_TSD : in out TSD) is
- use Parameters;
- SS_Ratio_Dynamic : constant Boolean := Sec_Stack_Percentage = Dynamic;
+ procedure Create_TSD
+ (New_TSD : in out TSD;
+ Sec_Stack : SST.SS_Stack_Ptr;
+ Sec_Stack_Size : System.Parameters.Size_Type)
+ is
begin
- if SS_Ratio_Dynamic then
- SST.SS_Init
- (New_TSD.Sec_Stack_Addr, SST.Default_Secondary_Stack_Size);
- end if;
+ New_TSD.Jmpbuf_Address := Null_Address;
+
+ New_TSD.Sec_Stack_Ptr := Sec_Stack;
+ SST.SS_Init (New_TSD.Sec_Stack_Ptr, Sec_Stack_Size);
end Create_TSD;
-----------------------
@@ -150,7 +146,7 @@ package body System.Soft_Links is
procedure Destroy_TSD (Old_TSD : in out TSD) is
begin
- SST.SS_Free (Old_TSD.Sec_Stack_Addr);
+ SST.SS_Free (Old_TSD.Sec_Stack_Ptr);
end Destroy_TSD;
---------------------
@@ -198,23 +194,23 @@ package body System.Soft_Links is
return Get_Jmpbuf_Address.all;
end Get_Jmpbuf_Address_Soft;
- ---------------------------
- -- Get_Sec_Stack_Addr_NT --
- ---------------------------
+ ----------------------
+ -- Get_Sec_Stack_NT --
+ ----------------------
- function Get_Sec_Stack_Addr_NT return Address is
+ function Get_Sec_Stack_NT return SST.SS_Stack_Ptr is
begin
- return NT_TSD.Sec_Stack_Addr;
- end Get_Sec_Stack_Addr_NT;
+ return NT_TSD.Sec_Stack_Ptr;
+ end Get_Sec_Stack_NT;
-----------------------------
- -- Get_Sec_Stack_Addr_Soft --
+ -- Get_Sec_Stack_Soft --
-----------------------------
- function Get_Sec_Stack_Addr_Soft return Address is
+ function Get_Sec_Stack_Soft return SST.SS_Stack_Ptr is
begin
- return Get_Sec_Stack_Addr.all;
- end Get_Sec_Stack_Addr_Soft;
+ return Get_Sec_Stack.all;
+ end Get_Sec_Stack_Soft;
-----------------------
-- Get_Stack_Info_NT --
@@ -254,23 +250,23 @@ package body System.Soft_Links is
Set_Jmpbuf_Address (Addr);
end Set_Jmpbuf_Address_Soft;
- ---------------------------
- -- Set_Sec_Stack_Addr_NT --
- ---------------------------
+ ----------------------
+ -- Set_Sec_Stack_NT --
+ ----------------------
- procedure Set_Sec_Stack_Addr_NT (Addr : Address) is
+ procedure Set_Sec_Stack_NT (Stack : SST.SS_Stack_Ptr) is
begin
- NT_TSD.Sec_Stack_Addr := Addr;
- end Set_Sec_Stack_Addr_NT;
+ NT_TSD.Sec_Stack_Ptr := Stack;
+ end Set_Sec_Stack_NT;
- -----------------------------
- -- Set_Sec_Stack_Addr_Soft --
- -----------------------------
+ ------------------------
+ -- Set_Sec_Stack_Soft --
+ ------------------------
- procedure Set_Sec_Stack_Addr_Soft (Addr : Address) is
+ procedure Set_Sec_Stack_Soft (Stack : SST.SS_Stack_Ptr) is
begin
- Set_Sec_Stack_Addr (Addr);
- end Set_Sec_Stack_Addr_Soft;
+ Set_Sec_Stack (Stack);
+ end Set_Sec_Stack_Soft;
------------------
-- Task_Lock_NT --
@@ -308,5 +304,4 @@ package body System.Soft_Links is
begin
null;
end Task_Unlock_NT;
-
end System.Soft_Links;
diff --git a/gcc/ada/libgnat/s-soflin.ads b/gcc/ada/libgnat/s-soflin.ads
index 402ea84..4242fce 100644
--- a/gcc/ada/libgnat/s-soflin.ads
+++ b/gcc/ada/libgnat/s-soflin.ads
@@ -40,11 +40,15 @@
pragma Compiler_Unit_Warning;
with Ada.Exceptions;
+with System.Parameters;
+with System.Secondary_Stack;
with System.Stack_Checking;
package System.Soft_Links is
pragma Preelaborate;
+ package SST renames System.Secondary_Stack;
+
subtype EOA is Ada.Exceptions.Exception_Occurrence_Access;
subtype EO is Ada.Exceptions.Exception_Occurrence;
@@ -89,6 +93,11 @@ package System.Soft_Links is
type Set_EO_Call is access procedure (Excep : EO);
pragma Favor_Top_Level (Set_EO_Call);
+ type Get_Stack_Call is access function return SST.SS_Stack_Ptr;
+ pragma Favor_Top_Level (Get_Stack_Call);
+ type Set_Stack_Call is access procedure (Stack : SST.SS_Stack_Ptr);
+ pragma Favor_Top_Level (Set_Stack_Call);
+
type Special_EO_Call is access
procedure (Excep : EO := Current_Target_Exception);
pragma Favor_Top_Level (Special_EO_Call);
@@ -118,6 +127,8 @@ package System.Soft_Links is
pragma Suppress (Access_Check, Set_Integer_Call);
pragma Suppress (Access_Check, Get_EOA_Call);
pragma Suppress (Access_Check, Set_EOA_Call);
+ pragma Suppress (Access_Check, Get_Stack_Call);
+ pragma Suppress (Access_Check, Set_Stack_Call);
pragma Suppress (Access_Check, Timed_Delay_Call);
pragma Suppress (Access_Check, Get_Stack_Access_Call);
pragma Suppress (Access_Check, Task_Name_Call);
@@ -228,11 +239,11 @@ package System.Soft_Links is
Get_Jmpbuf_Address : Get_Address_Call := Get_Jmpbuf_Address_NT'Access;
Set_Jmpbuf_Address : Set_Address_Call := Set_Jmpbuf_Address_NT'Access;
- function Get_Sec_Stack_Addr_NT return Address;
- procedure Set_Sec_Stack_Addr_NT (Addr : Address);
+ function Get_Sec_Stack_NT return SST.SS_Stack_Ptr;
+ procedure Set_Sec_Stack_NT (Stack : SST.SS_Stack_Ptr);
- Get_Sec_Stack_Addr : Get_Address_Call := Get_Sec_Stack_Addr_NT'Access;
- Set_Sec_Stack_Addr : Set_Address_Call := Set_Sec_Stack_Addr_NT'Access;
+ Get_Sec_Stack : Get_Stack_Call := Get_Sec_Stack_NT'Access;
+ Set_Sec_Stack : Set_Stack_Call := Set_Sec_Stack_NT'Access;
function Get_Current_Excep_NT return EOA;
@@ -320,19 +331,14 @@ package System.Soft_Links is
-- must be initialized to the tasks requested stack size before the task
-- can do its first stack check.
- pragma Warnings (Off);
- -- Needed because we are giving a non-static default to an object in
- -- a preelaborated unit, which is formally not permitted, but OK here.
-
- Jmpbuf_Address : System.Address := System.Null_Address;
+ Jmpbuf_Address : System.Address;
-- Address of jump buffer used to store the address of the current
-- longjmp/setjmp buffer for exception management. These buffers are
-- threaded into a stack, and the address here is the top of the stack.
-- A null address means that no exception handler is currently active.
- Sec_Stack_Addr : System.Address := System.Null_Address;
- pragma Warnings (On);
- -- Address of currently allocated secondary stack
+ Sec_Stack_Ptr : SST.SS_Stack_Ptr;
+ -- Pointer of the allocated secondary stack
Current_Excep : aliased EO;
-- Exception occurrence that contains the information for the current
@@ -344,7 +350,10 @@ package System.Soft_Links is
-- exception mechanism, organized as a stack with the most recent first.
end record;
- procedure Create_TSD (New_TSD : in out TSD);
+ procedure Create_TSD
+ (New_TSD : in out TSD;
+ Sec_Stack : SST.SS_Stack_Ptr;
+ Sec_Stack_Size : System.Parameters.Size_Type);
pragma Inline (Create_TSD);
-- Called from s-tassta when a new thread is created to perform
-- any required initialization of the TSD.
@@ -370,10 +379,10 @@ package System.Soft_Links is
pragma Inline (Get_Jmpbuf_Address_Soft);
pragma Inline (Set_Jmpbuf_Address_Soft);
- function Get_Sec_Stack_Addr_Soft return Address;
- procedure Set_Sec_Stack_Addr_Soft (Addr : Address);
- pragma Inline (Get_Sec_Stack_Addr_Soft);
- pragma Inline (Set_Sec_Stack_Addr_Soft);
+ function Get_Sec_Stack_Soft return SST.SS_Stack_Ptr;
+ procedure Set_Sec_Stack_Soft (Stack : SST.SS_Stack_Ptr);
+ pragma Inline (Get_Sec_Stack_Soft);
+ pragma Inline (Set_Sec_Stack_Soft);
-- The following is a dummy record designed to mimic Communication_Block as
-- defined in s-tpobop.ads:
@@ -396,4 +405,11 @@ package System.Soft_Links is
Comp_3 : Boolean;
end record;
+private
+ NT_TSD : TSD;
+ -- The task specific data for the main task when the Ada tasking run-time
+ -- is not used. It relies on the default initialization of NT_TSD. It is
+ -- placed here and not the body to ensure the default initialization does
+ -- not clobber the secondary stack initialization that occurs as part of
+ -- System.Soft_Links.Initialization.
end System.Soft_Links;
diff --git a/gcc/ada/libgnat/s-soliin.adb b/gcc/ada/libgnat/s-soliin.adb
new file mode 100644
index 0000000..5364e46
--- /dev/null
+++ b/gcc/ada/libgnat/s-soliin.adb
@@ -0,0 +1,47 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT COMPILER COMPONENTS --
+-- --
+-- S Y S T E M . S O F T _ L I N K S . I N I T I A L I Z E --
+-- --
+-- B o d y --
+-- --
+-- Copyright (C) 2017, 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 --
+-- <http://www.gnu.org/licenses/>. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+with System.Secondary_Stack;
+
+package body System.Soft_Links.Initialize is
+
+ package SSS renames System.Secondary_Stack;
+
+begin
+ -- Initialize the TSD of the main task
+
+ NT_TSD.Jmpbuf_Address := System.Null_Address;
+
+ -- Allocate and initialize the secondary stack for the main task
+
+ NT_TSD.Sec_Stack_Ptr := null;
+ SSS.SS_Init (NT_TSD.Sec_Stack_Ptr);
+end System.Soft_Links.Initialize;
diff --git a/gcc/ada/libgnat/s-soliin.ads b/gcc/ada/libgnat/s-soliin.ads
new file mode 100644
index 0000000..ba9cf74
--- /dev/null
+++ b/gcc/ada/libgnat/s-soliin.ads
@@ -0,0 +1,48 @@
+------------------------------------------------------------------------------
+-- --
+-- GNAT COMPILER COMPONENTS --
+-- --
+-- S Y S T E M . S O F T _ L I N K S . I N I T I A L I Z E --
+-- --
+-- S p e c --
+-- --
+-- Copyright (C) 2017, 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 --
+-- <http://www.gnu.org/licenses/>. --
+-- --
+-- GNAT was originally developed by the GNAT team at New York University. --
+-- Extensive contributions were provided by Ada Core Technologies Inc. --
+-- --
+------------------------------------------------------------------------------
+
+-- This package exists to initialize the TSD record of the main task and in
+-- the process, allocate and initialize the secondary stack for the main task.
+-- The initialization routine is contained within its own package because
+-- System.Soft_Links and System.Secondary_Stack are both Preelaborate packages
+-- that are the parents to other Preelaborate System packages.
+
+-- Ideally, the secondary stack would be set up via __gnat_runtime_initialize
+-- to have the secondary stack active as early as possible and to remove the
+-- awkwardness of System.Soft_Links depending on a non-Preelaborate package.
+-- However, as this procedure only exists from 2014, for bootstrapping
+-- purposes the elaboration mechanism is used instead to perform these
+-- functions.
+
+package System.Soft_Links.Initialize is
+ pragma Elaborate_Body;
+ -- Allow this package to have a body
+end System.Soft_Links.Initialize;
diff --git a/gcc/ada/libgnat/s-stausa.adb b/gcc/ada/libgnat/s-stausa.adb
index f652e7a..da5db75 100644
--- a/gcc/ada/libgnat/s-stausa.adb
+++ b/gcc/ada/libgnat/s-stausa.adb
@@ -35,7 +35,6 @@ with System.IO;
package body System.Stack_Usage is
use System.Storage_Elements;
- use System;
use System.IO;
use Interfaces;
diff --git a/gcc/ada/libgnat/s-stchop__vxworks.adb b/gcc/ada/libgnat/s-stchop__vxworks.adb
index 25b07db..99e0288 100644
--- a/gcc/ada/libgnat/s-stchop__vxworks.adb
+++ b/gcc/ada/libgnat/s-stchop__vxworks.adb
@@ -103,8 +103,6 @@ package body System.Stack_Checking.Operations is
--------------------------------------
procedure Set_Stack_Limit_For_Current_Task is
- use Interfaces.C;
-
type OS_Stack_Info is record
Size : Interfaces.C.int;
Base : System.Address;
diff --git a/gcc/ada/libgnat/s-thread.ads b/gcc/ada/libgnat/s-thread.ads
index cd4faae..185141b 100644
--- a/gcc/ada/libgnat/s-thread.ads
+++ b/gcc/ada/libgnat/s-thread.ads
@@ -42,10 +42,13 @@ with Ada.Unchecked_Conversion;
with Interfaces.C;
+with System.Secondary_Stack;
with System.Soft_Links;
package System.Threads is
+ package SST renames System.Secondary_Stack;
+
type ATSD is limited private;
-- Type of the Ada thread specific data. It contains datas needed
-- by the GNAT runtime.
@@ -71,8 +74,7 @@ package System.Threads is
-- wrapper in the APEX process registration package.
procedure Thread_Body_Enter
- (Sec_Stack_Address : System.Address;
- Sec_Stack_Size : Natural;
+ (Sec_Stack_Ptr : SST.SS_Stack_Ptr;
Process_ATSD_Address : System.Address);
-- Enter thread body, see above for details
diff --git a/gcc/ada/libgnat/s-thread__ae653.adb b/gcc/ada/libgnat/s-thread__ae653.adb
index ca87128..9e8b2ab 100644
--- a/gcc/ada/libgnat/s-thread__ae653.adb
+++ b/gcc/ada/libgnat/s-thread__ae653.adb
@@ -37,15 +37,11 @@ pragma Restrictions (No_Tasking);
-- will be checked by the binder.
with System.OS_Versions; use System.OS_Versions;
-with System.Secondary_Stack;
-pragma Elaborate_All (System.Secondary_Stack);
package body System.Threads is
use Interfaces.C;
- package SSS renames System.Secondary_Stack;
-
package SSL renames System.Soft_Links;
Current_ATSD : aliased System.Address := System.Null_Address;
@@ -94,17 +90,16 @@ package body System.Threads is
procedure Install_Handler;
pragma Import (C, Install_Handler, "__gnat_install_handler");
- function Get_Sec_Stack_Addr return Address;
+ function Get_Sec_Stack return SST.SS_Stack_Ptr;
- procedure Set_Sec_Stack_Addr (Addr : Address);
+ procedure Set_Sec_Stack (Stack : SST.SS_Stack_Ptr);
-----------------------
-- Thread_Body_Enter --
-----------------------
procedure Thread_Body_Enter
- (Sec_Stack_Address : System.Address;
- Sec_Stack_Size : Natural;
+ (Sec_Stack_Ptr : SST.SS_Stack_Ptr;
Process_ATSD_Address : System.Address)
is
-- Current_ATSD must already be a taskVar of taskIdSelf.
@@ -115,8 +110,8 @@ package body System.Threads is
begin
- TSD.Sec_Stack_Addr := Sec_Stack_Address;
- SSS.SS_Init (TSD.Sec_Stack_Addr, Sec_Stack_Size);
+ TSD.Sec_Stack_Ptr := Sec_Stack_Ptr;
+ SST.SS_Init (TSD.Sec_Stack_Ptr);
Current_ATSD := Process_ATSD_Address;
Install_Handler;
@@ -166,23 +161,23 @@ package body System.Threads is
pragma Assert (Result /= ERROR);
begin
- Main_ATSD.Sec_Stack_Addr := SSL.Get_Sec_Stack_Addr_NT;
+ Main_ATSD.Sec_Stack_Ptr := SSL.Get_Sec_Stack_NT;
Current_ATSD := Main_ATSD'Address;
Install_Handler;
- SSL.Get_Sec_Stack_Addr := Get_Sec_Stack_Addr'Access;
- SSL.Set_Sec_Stack_Addr := Set_Sec_Stack_Addr'Access;
+ SSL.Get_Sec_Stack := Get_Sec_Stack'Access;
+ SSL.Set_Sec_Stack := Set_Sec_Stack'Access;
end Init_RTS;
- ------------------------
- -- Get_Sec_Stack_Addr --
- ------------------------
+ -------------------
+ -- Get_Sec_Stack --
+ -------------------
- function Get_Sec_Stack_Addr return Address is
+ function Get_Sec_Stack return SST.SS_Stack_Ptr is
CTSD : constant ATSD_Access := From_Address (Current_ATSD);
begin
pragma Assert (CTSD /= null);
- return CTSD.Sec_Stack_Addr;
- end Get_Sec_Stack_Addr;
+ return CTSD.Sec_Stack_Ptr;
+ end Get_Sec_Stack;
--------------
-- Register --
@@ -229,16 +224,16 @@ package body System.Threads is
return Result;
end Register;
- ------------------------
- -- Set_Sec_Stack_Addr --
- ------------------------
+ -------------------
+ -- Set_Sec_Stack --
+ -------------------
- procedure Set_Sec_Stack_Addr (Addr : Address) is
+ procedure Set_Sec_Stack (Stack : SST.SS_Stack_Ptr) is
CTSD : constant ATSD_Access := From_Address (Current_ATSD);
begin
pragma Assert (CTSD /= null);
- CTSD.Sec_Stack_Addr := Addr;
- end Set_Sec_Stack_Addr;
+ CTSD.Sec_Stack_Ptr := Stack;
+ end Set_Sec_Stack;
begin
-- Initialize run-time library
diff --git a/gcc/ada/libgnat/s-tsmona__linux.adb b/gcc/ada/libgnat/s-tsmona__linux.adb
index 8c1f8b4..49b73b6 100644
--- a/gcc/ada/libgnat/s-tsmona__linux.adb
+++ b/gcc/ada/libgnat/s-tsmona__linux.adb
@@ -38,8 +38,6 @@ separate (System.Traceback.Symbolic)
package body Module_Name is
- use System;
-
pragma Linker_Options ("-ldl");
function Is_Shared_Lib (Base : Address) return Boolean;
diff --git a/gcc/ada/libgnat/s-tsmona__mingw.adb b/gcc/ada/libgnat/s-tsmona__mingw.adb
index 46c35cd..3205c0a 100644
--- a/gcc/ada/libgnat/s-tsmona__mingw.adb
+++ b/gcc/ada/libgnat/s-tsmona__mingw.adb
@@ -37,8 +37,6 @@ separate (System.Traceback.Symbolic)
package body Module_Name is
- use System;
-
---------------------------------
-- Build_Cache_For_All_Modules --
---------------------------------
diff --git a/gcc/ada/make.adb b/gcc/ada/make.adb
index cbd110d..6f12539 100644
--- a/gcc/ada/make.adb
+++ b/gcc/ada/make.adb
@@ -23,26 +23,26 @@
-- --
------------------------------------------------------------------------------
-with ALI; use ALI;
-with ALI.Util; use ALI.Util;
+with ALI; use ALI;
+with ALI.Util; use ALI.Util;
with Csets;
with Debug;
with Fmap;
with Fname; use Fname;
-with Fname.SF; use Fname.SF;
+with Fname.SF;
with Fname.UF; use Fname.UF;
with Gnatvsn; use Gnatvsn;
with Hostparm; use Hostparm;
with Makeusg;
with Make_Util; use Make_Util;
-with Namet; use Namet;
-with Opt; use Opt;
-with Osint.M; use Osint.M;
-with Osint; use Osint;
-with Output; use Output;
+with Namet; use Namet;
+with Opt; use Opt;
+with Osint.M; use Osint.M;
+with Osint; use Osint;
+with Output; use Output;
with SFN_Scan;
with Sinput;
-with Snames; use Snames;
+with Snames;
with Stringt;
pragma Warnings (Off);
@@ -52,7 +52,7 @@ pragma Warnings (On);
with Switch; use Switch;
with Switch.M; use Switch.M;
with Table;
-with Targparm; use Targparm;
+with Targparm;
with Tempdir;
with Types; use Types;
@@ -1772,7 +1772,7 @@ package body Make is
(Data : out Compilation_Data;
OK : out Boolean)
is
- Pid : Process_Id;
+ Pid : Process_Id;
begin
pragma Assert (Outstanding_Compiles > 0);
@@ -1790,7 +1790,7 @@ package body Make is
for J in Running_Compile'First .. Outstanding_Compiles loop
if Pid = Running_Compile (J).Pid then
- Data := Running_Compile (J);
+ Data := Running_Compile (J);
-- If a mapping file was used by this compilation, get its file
-- name for reuse by a subsequent compilation.
diff --git a/gcc/ada/makeusg.adb b/gcc/ada/makeusg.adb
index 73361de..e596f32 100644
--- a/gcc/ada/makeusg.adb
+++ b/gcc/ada/makeusg.adb
@@ -24,7 +24,7 @@
------------------------------------------------------------------------------
with Make_Util;
-with Osint; use Osint;
+with Osint;
with Output; use Output;
with Switch; use Switch;
with Usage;
diff --git a/gcc/ada/mingw32.h b/gcc/ada/mingw32.h
index cf2d9de..91f85f8 100644
--- a/gcc/ada/mingw32.h
+++ b/gcc/ada/mingw32.h
@@ -59,16 +59,6 @@
#endif
#include <windows.h>
-#ifndef _O_U8TEXT
-#define _O_U8TEXT _O_TEXT
-#endif
-#ifndef _O_U16TEXT
-#define _O_U16TEXT _O_TEXT
-#endif
-#ifndef _O_WTEXT
-#define _O_WTEXT _O_TEXT
-#endif
-
/* After including this file it is possible to use the character t as prefix
to routines. If GNAT_UNICODE_SUPPORT is defined then the unicode enabled
versions will be used. */
diff --git a/gcc/ada/namet.adb b/gcc/ada/namet.adb
index fd458a3..2dcbe1a 100644
--- a/gcc/ada/namet.adb
+++ b/gcc/ada/namet.adb
@@ -38,7 +38,7 @@ with Opt; use Opt;
with Output; use Output;
with System; use System;
with Tree_IO; use Tree_IO;
-with Widechar; use Widechar;
+with Widechar;
with Interfaces; use Interfaces;
diff --git a/gcc/ada/namet.ads b/gcc/ada/namet.ads
index 124f778..72ac8fa 100644
--- a/gcc/ada/namet.ads
+++ b/gcc/ada/namet.ads
@@ -477,7 +477,7 @@ package Namet is
-- Sets the Int value associated with the given name
function Is_Internal_Name (Id : Name_Id) return Boolean;
- -- Returns True if the name is an internal name (i.e. contains a character
+ -- Returns True if the name is an internal name, i.e. contains a character
-- for which Is_OK_Internal_Letter is true, or if the name starts or ends
-- with an underscore.
--
diff --git a/gcc/ada/opt.ads b/gcc/ada/opt.ads
index 687d1eb..96e2f3e 100644
--- a/gcc/ada/opt.ads
+++ b/gcc/ada/opt.ads
@@ -462,18 +462,21 @@ package Opt is
-- otherwise: "pragma Default_Storage_Pool (X);" applies, and
-- this points to the name X.
-- Push_Scope and Pop_Scope in Sem_Ch8 save and restore this value.
- Default_Stack_Size : Int := -1;
+
+ No_Stack_Size : constant := -1;
+
+ Default_Stack_Size : Int := No_Stack_Size;
-- GNATBIND
- -- Set to default primary stack size in units of bytes. Set by
- -- the -dnnn switch for the binder. A value of -1 indicates that no
- -- default was set by the binder.
+ -- Set to default primary stack size in units of bytes. Set by the -dnnn
+ -- switch for the binder. A value of No_Stack_Size indicates that
+ -- no default was set by the binder.
- Default_Sec_Stack_Size : Int := -1;
+ Default_Sec_Stack_Size : Int := No_Stack_Size;
-- GNATBIND
- -- Set to default secondary stack size in units of bytes. Set by
- -- the -Dnnn switch for the binder. A value of -1 indicates that no
- -- default was set by the binder, and that the default should be the
- -- initial value of System.Secondary_Stack.Default_Secondary_Stack_Size.
+ -- Set to default secondary stack size in units of bytes. Set by the -Dnnn
+ -- switch for the binder. A value of No_Stack_Size indicates that no
+ -- default was set by the binder and the run-time value should be used
+ -- instead.
Default_SSO : Character := ' ';
-- GNAT
@@ -1313,6 +1316,13 @@ package Opt is
-- Indicates if a project file is used or not. Set to In_Use by the first
-- SFNP pragma.
+ Quantity_Of_Default_Size_Sec_Stacks : Int := -1;
+ -- GNATBIND
+ -- The number of default sized secondary stacks that the binder should
+ -- generate. Allows ZFP users to have the binder generate extra stacks if
+ -- needed to support multithreaded applications. A value of -1 indicates
+ -- that no size was set by the binder.
+
Queuing_Policy : Character := ' ';
-- GNAT, GNATBIND
-- Set to ' ' for the default case (no queuing policy specified). Reset to
diff --git a/gcc/ada/osint.adb b/gcc/ada/osint.adb
index 105e866..14fbba5 100644
--- a/gcc/ada/osint.adb
+++ b/gcc/ada/osint.adb
@@ -2565,12 +2565,9 @@ package body Osint is
Lo : Source_Ptr;
Hi : out Source_Ptr;
Src : out Source_Buffer_Ptr;
+ FD : out File_Descriptor;
T : File_Type := Source)
is
- Source_File_FD : File_Descriptor;
- -- The file descriptor for the current source file. A negative value
- -- indicates failure to open the specified source file.
-
Len : Integer;
-- Length of file, assume no more than 2 gigabytes of source
@@ -2594,6 +2591,7 @@ package body Osint is
Fail ("Cannot find: " & Name_Buffer (1 .. Name_Len));
end if;
+ FD := Null_FD;
Src := null;
Hi := No_Location;
return;
@@ -2607,9 +2605,9 @@ package body Osint is
-- DOS or Unix mode files, and there is no point in wasting time on
-- text translation when it is not required.
- Source_File_FD := Open_Read (Name_Buffer'Address, Binary);
+ FD := Open_Read (Name_Buffer'Address, Binary);
- if Source_File_FD = Invalid_FD then
+ if FD = Invalid_FD then
Src := null;
Hi := No_Location;
return;
@@ -2645,7 +2643,7 @@ package body Osint is
-- Prepare to read data from the file
- Len := Integer (File_Length (Source_File_FD));
+ Len := Integer (File_Length (FD));
-- Set Hi so that length is one more than the physical length,
-- allowing for the extra EOF character at the end of the buffer
@@ -2665,7 +2663,7 @@ package body Osint is
Hi := Lo;
loop
- Actual_Len := Read (Source_File_FD, Var_Ptr (Hi)'Address, Len);
+ Actual_Len := Read (FD, Var_Ptr (Hi)'Address, Len);
Hi := Hi + Source_Ptr (Actual_Len);
exit when Actual_Len = Len or else Actual_Len <= 0;
end loop;
@@ -2676,7 +2674,7 @@ package body Osint is
-- Read is complete, get time stamp and close file and we are done
- Close (Source_File_FD, Status);
+ Close (FD, Status);
-- The status should never be False. But, if it is, what can we do?
-- So, we don't test it.
diff --git a/gcc/ada/osint.ads b/gcc/ada/osint.ads
index 2805bfe..b8edeec 100644
--- a/gcc/ada/osint.ads
+++ b/gcc/ada/osint.ads
@@ -401,10 +401,12 @@ package Osint is
Lo : Source_Ptr;
Hi : out Source_Ptr;
Src : out Source_Buffer_Ptr;
+ FD : out File_Descriptor;
T : File_Type := Source);
-- Allocates a Source_Buffer of appropriate length and then reads the
-- entire contents of the source file N into the buffer. The address of
- -- the allocated buffer is returned in Src.
+ -- the allocated buffer is returned in Src. FD is used for extended error
+ -- information in the case the read fails.
--
-- Each line of text is terminated by one of the sequences:
--
@@ -426,7 +428,11 @@ package Osint is
-- failure to find the file is a fatal error, an error message is output,
-- and program execution is terminated. Otherwise (for the case of a
-- subsidiary source loaded directly or indirectly using with), a file
- -- not found condition causes null to be set as the result value.
+ -- not found condition causes null to be set as the result value and a
+ -- value of No_Source_File (0) to be set as the FD value. In the related
+ -- case of a file with no read permissions the result is the same except FD
+ -- is set to No_Access_To_Source_File (-1). Upon success FD is set to a
+ -- positive Source_File_Index.
--
-- Note that the name passed to this function is the simple file name,
-- without any directory information. The implementation is responsible
diff --git a/gcc/ada/output.ads b/gcc/ada/output.ads
index 5fe0d44..21f69dd 100644
--- a/gcc/ada/output.ads
+++ b/gcc/ada/output.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2015, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -33,7 +33,7 @@
-- writing error messages and informational output. It is also used by the
-- debug source file output routines (see Sprint.Print_Debug_Line).
-with Hostparm; use Hostparm;
+with Hostparm;
with Types; use Types;
pragma Warnings (Off);
diff --git a/gcc/ada/par-ch10.adb b/gcc/ada/par-ch10.adb
index eca327b..1dd3b76 100644
--- a/gcc/ada/par-ch10.adb
+++ b/gcc/ada/par-ch10.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -970,7 +970,7 @@ package body Ch10 is
-- Processing for USE clause
elsif Token = Tok_Use then
- Append (P_Use_Clause, Item_List);
+ P_Use_Clause (Item_List);
-- Anything else is end of context clause
diff --git a/gcc/ada/par-ch12.adb b/gcc/ada/par-ch12.adb
index 52f687e..e603d9c 100644
--- a/gcc/ada/par-ch12.adb
+++ b/gcc/ada/par-ch12.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -167,7 +167,7 @@ package body Ch12 is
end if;
if Token = Tok_Use then
- Append (P_Use_Clause, Decls);
+ P_Use_Clause (Decls);
else
-- Parse a generic parameter declaration
diff --git a/gcc/ada/par-ch3.adb b/gcc/ada/par-ch3.adb
index 6553a95..54dd562 100644
--- a/gcc/ada/par-ch3.adb
+++ b/gcc/ada/par-ch3.adb
@@ -4411,7 +4411,7 @@ package body Ch3 is
when Tok_Use =>
Check_Bad_Layout;
- Append (P_Use_Clause, Decls);
+ P_Use_Clause (Decls);
Done := False;
when Tok_With =>
diff --git a/gcc/ada/par-ch8.adb b/gcc/ada/par-ch8.adb
index b4eaf8c..4dea281 100644
--- a/gcc/ada/par-ch8.adb
+++ b/gcc/ada/par-ch8.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1992-2013, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -34,8 +34,51 @@ package body Ch8 is
-- Local Subprograms --
-----------------------
- function P_Use_Package_Clause return Node_Id;
- function P_Use_Type_Clause return Node_Id;
+ procedure Append_Use_Clause
+ (Item_List : List_Id;
+ Use_Node : Node_Id;
+ Is_First : in out Boolean;
+ Is_Last : in out Boolean);
+ -- Append a use_clause to the Item_List, appropriately setting the Prev_Ids
+ -- and More_Ids flags for each split use node. The flags Is_First and
+ -- Is_Last track position of subtype_marks or names within the original
+ -- use_clause.
+
+ procedure P_Use_Package_Clause (Item_List : List_Id);
+ procedure P_Use_Type_Clause (Item_List : List_Id);
+
+ -----------------------
+ -- Append_Use_Clause --
+ -----------------------
+
+ procedure Append_Use_Clause
+ (Item_List : List_Id;
+ Use_Node : Node_Id;
+ Is_First : in out Boolean;
+ Is_Last : in out Boolean)
+ is
+ begin
+ if Token /= Tok_Comma then
+ if not Is_First then
+ Set_Prev_Ids (Use_Node);
+ end if;
+
+ Append (Use_Node, Item_List);
+ Is_Last := True;
+
+ else
+ Set_More_Ids (Use_Node);
+
+ if not Is_First then
+ Set_Prev_Ids (Use_Node);
+ else
+ Is_First := False;
+ end if;
+
+ Append (Use_Node, Item_List);
+ Scan; -- Past comma
+ end if;
+ end Append_Use_Clause;
---------------------
-- 8.4 Use Clause --
@@ -47,14 +90,14 @@ package body Ch8 is
-- Error recovery: cannot raise Error_Resync
- function P_Use_Clause return Node_Id is
+ procedure P_Use_Clause (Item_List : List_Id) is
begin
Scan; -- past USE
if Token = Tok_Type or else Token = Tok_All then
- return P_Use_Type_Clause;
+ P_Use_Type_Clause (Item_List);
else
- return P_Use_Package_Clause;
+ P_Use_Package_Clause (Item_List);
end if;
end P_Use_Clause;
@@ -68,26 +111,32 @@ package body Ch8 is
-- Error recovery: cannot raise Error_Resync
- function P_Use_Package_Clause return Node_Id is
+ procedure P_Use_Package_Clause (Item_List : List_Id) is
+ Is_First : Boolean := True;
+ Is_Last : Boolean := False;
Use_Node : Node_Id;
+ Use_Sloc : constant Source_Ptr := Prev_Token_Ptr;
begin
- Use_Node := New_Node (N_Use_Package_Clause, Prev_Token_Ptr);
- Set_Names (Use_Node, New_List);
-
if Token = Tok_Package then
Error_Msg_SC ("PACKAGE should not appear here");
- Scan; -- past PACKAGE
+ Scan; -- Past PACKAGE
end if;
+ -- Loop through names in a single use_package_clause, generating an
+ -- N_Use_Package_Clause node for each name encountered.
+
loop
- Append (P_Qualified_Simple_Name, Names (Use_Node));
- exit when Token /= Tok_Comma;
- Scan; -- past comma
+ Use_Node := New_Node (N_Use_Package_Clause, Use_Sloc);
+ Set_Name (Use_Node, P_Qualified_Simple_Name);
+
+ -- Locally chain each name's use-package node
+
+ Append_Use_Clause (Item_List, Use_Node, Is_First, Is_Last);
+ exit when Is_Last;
end loop;
TF_Semicolon;
- return Use_Node;
end P_Use_Package_Clause;
--------------------------
@@ -103,45 +152,54 @@ package body Ch8 is
-- Error recovery: cannot raise Error_Resync
- function P_Use_Type_Clause return Node_Id is
- Use_Node : Node_Id;
+ procedure P_Use_Type_Clause (Item_List : List_Id) is
+ Use_Sloc : constant Source_Ptr := Prev_Token_Ptr;
+
All_Present : Boolean;
- Use_Sloc : constant Source_Ptr := Prev_Token_Ptr;
+ Is_First : Boolean := True;
+ Is_Last : Boolean := False;
+ Use_Node : Node_Id;
begin
if Token = Tok_All then
Error_Msg_Ada_2012_Feature ("|`USE ALL TYPE`", Token_Ptr);
All_Present := True;
- Scan; -- past ALL
+ Scan; -- Past ALL
if Token /= Tok_Type then
Error_Msg_SC ("TYPE expected");
end if;
- else pragma Assert (Token = Tok_Type);
+ else
+ pragma Assert (Token = Tok_Type);
All_Present := False;
end if;
- Use_Node := New_Node (N_Use_Type_Clause, Use_Sloc);
- Set_All_Present (Use_Node, All_Present);
- Set_Subtype_Marks (Use_Node, New_List);
- Set_Used_Operations (Use_Node, No_Elist);
-
if Ada_Version = Ada_83 then
Error_Msg_SC ("(Ada 83) use type not allowed!");
end if;
- Scan; -- past TYPE
+ Scan; -- Past TYPE
+
+ -- Loop through subtype_marks in one use_type_clause, generating a
+ -- separate N_Use_Type_Clause node for each subtype_mark encountered.
loop
- Append (P_Subtype_Mark, Subtype_Marks (Use_Node));
+ Use_Node := New_Node (N_Use_Type_Clause, Use_Sloc);
+ Set_All_Present (Use_Node, All_Present);
+ Set_Used_Operations (Use_Node, No_Elist);
+
+ Set_Subtype_Mark (Use_Node, P_Subtype_Mark);
+
No_Constraint;
- exit when Token /= Tok_Comma;
- Scan; -- past comma
+
+ -- Locally chain each subtype_mark's use-type node
+
+ Append_Use_Clause (Item_List, Use_Node, Is_First, Is_Last);
+ exit when Is_Last;
end loop;
TF_Semicolon;
- return Use_Node;
end P_Use_Type_Clause;
-------------------------------
@@ -163,9 +221,9 @@ package body Ch8 is
-- Parsed by P_Identifier_Declarations (3.3.1)
- ----------------------------------------
+ -------------------------------------------
-- 8.5.2 Exception Renaming Declaration --
- ----------------------------------------
+ -------------------------------------------
-- Parsed by P_Identifier_Declarations (3.3.1)
diff --git a/gcc/ada/par.adb b/gcc/ada/par.adb
index 4145907..280d8a1 100644
--- a/gcc/ada/par.adb
+++ b/gcc/ada/par.adb
@@ -867,7 +867,7 @@ function Par (Configuration_Pragmas : Boolean) return List_Id is
-------------
package Ch8 is
- function P_Use_Clause return Node_Id;
+ procedure P_Use_Clause (Item_List : List_Id);
end Ch8;
-------------
diff --git a/gcc/ada/prepcomp.adb b/gcc/ada/prepcomp.adb
index cffb0ce..320d622 100644
--- a/gcc/ada/prepcomp.adb
+++ b/gcc/ada/prepcomp.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2003-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 2003-2017, 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- --
@@ -630,17 +630,16 @@ package body Prepcomp is
String_To_Name_Buffer (Current_Data.Deffile);
declare
- N : constant File_Name_Type := Name_Find;
- Deffile : constant Source_File_Index :=
- Load_Definition_File (N);
- Add_Deffile : Boolean := True;
- T : constant Nat := Total_Errors_Detected;
+ N : constant File_Name_Type := Name_Find;
+ Deffile : constant Source_File_Index := Load_Definition_File (N);
+ T : constant Nat := Total_Errors_Detected;
+
+ Add_Deffile : Boolean := True;
begin
- if Deffile = No_Source_File then
- Fail ("definition file """
- & Get_Name_String (N)
- & """ not found");
+ if Deffile <= No_Source_File then
+ Fail
+ ("definition file """ & Get_Name_String (N) & """ not found");
end if;
-- Initialize the preprocessor and set the characteristics of the
diff --git a/gcc/ada/put_scos.adb b/gcc/ada/put_scos.adb
index c420090..fa8a7a8 100644
--- a/gcc/ada/put_scos.adb
+++ b/gcc/ada/put_scos.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 2009-2014, Free Software Foundation, Inc. --
+-- Copyright (C) 2009-2017, 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- --
@@ -23,9 +23,9 @@
-- --
------------------------------------------------------------------------------
-with Namet; use Namet;
-with Opt; use Opt;
-with SCOs; use SCOs;
+with Namet;
+with Opt;
+with SCOs; use SCOs;
procedure Put_SCOs is
Current_SCO_Unit : SCO_Unit_Index := 0;
diff --git a/gcc/ada/repinfo.adb b/gcc/ada/repinfo.adb
index a62c48b..464b1b2 100644
--- a/gcc/ada/repinfo.adb
+++ b/gcc/ada/repinfo.adb
@@ -29,7 +29,7 @@
-- --
------------------------------------------------------------------------------
-with Alloc; use Alloc;
+with Alloc;
with Atree; use Atree;
with Casing; use Casing;
with Debug; use Debug;
@@ -45,7 +45,7 @@ with Sinput; use Sinput;
with Snames; use Snames;
with Stand; use Stand;
with Stringt; use Stringt;
-with Table; use Table;
+with Table;
with Uname; use Uname;
with Urealp; use Urealp;
@@ -1051,14 +1051,13 @@ package body Repinfo is
and then List_Representation_Info = 3
then
Spaces (Max_Spos_Length - 2);
- Write_Str ("bit offset");
+ Write_Str ("bit offset ");
if Starting_Position /= Uint_0
or else Starting_First_Bit /= Uint_0
then
- Write_Char (' ');
UI_Write (Starting_Position * SSU + Starting_First_Bit);
- Write_Str (" +");
+ Write_Str (" + ");
end if;
Write_Val (Bofs, Paren => True);
@@ -1686,27 +1685,18 @@ package body Repinfo is
Write_Str ("??");
else
- if Back_End_Layout then
- Write_Char (' ');
-
- if Paren then
- Write_Char ('(');
- List_GCC_Expression (Val);
- Write_Char (')');
- else
- List_GCC_Expression (Val);
- end if;
-
- Write_Char (' ');
+ if Paren then
+ Write_Char ('(');
+ end if;
+ if Back_End_Layout then
+ List_GCC_Expression (Val);
else
- if Paren then
- Write_Char ('(');
- Write_Name_Decoded (Chars (Get_Dynamic_SO_Entity (Val)));
- Write_Char (')');
- else
- Write_Name_Decoded (Chars (Get_Dynamic_SO_Entity (Val)));
- end if;
+ Write_Name_Decoded (Chars (Get_Dynamic_SO_Entity (Val)));
+ end if;
+
+ if Paren then
+ Write_Char (')');
end if;
end if;
diff --git a/gcc/ada/rtfinal.c b/gcc/ada/rtfinal.c
index 8f7e163..9398af3 100644
--- a/gcc/ada/rtfinal.c
+++ b/gcc/ada/rtfinal.c
@@ -6,7 +6,7 @@
* *
* C Implementation File *
* *
- * Copyright (C) 2014, Free Software Foundation, Inc. *
+ * Copyright (C) 2014-2017, 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- *
@@ -40,7 +40,7 @@ extern void __gnat_runtime_finalize (void);
at all, the intention is that this be replaced by system specific code
where finalization is required.
- Note that __gnat_runtime_initialize() is called in adafinal() */
+ Note that __gnat_runtime_finalize() is called in adafinal() */
extern int __gnat_rt_init_count;
/* see initialize.c */
diff --git a/gcc/ada/rtsfind.adb b/gcc/ada/rtsfind.adb
index 8bedff6..e3af27d 100644
--- a/gcc/ada/rtsfind.adb
+++ b/gcc/ada/rtsfind.adb
@@ -30,7 +30,7 @@ with Debug; use Debug;
with Einfo; use Einfo;
with Elists; use Elists;
with Errout; use Errout;
-with Exp_Dist; use Exp_Dist;
+with Exp_Dist;
with Fname; use Fname;
with Fname.UF; use Fname.UF;
with Ghost; use Ghost;
diff --git a/gcc/ada/rtsfind.ads b/gcc/ada/rtsfind.ads
index bdad252..c4d7d3c 100644
--- a/gcc/ada/rtsfind.ads
+++ b/gcc/ada/rtsfind.ads
@@ -1249,6 +1249,7 @@ package Rtsfind is
RE_Set_63, -- System.Pack_63
RE_Adjust_Storage_Size, -- System.Parameters
+ RE_Default_Secondary_Stack_Size, -- System.Parameters
RE_Default_Stack_Size, -- System.Parameters
RE_Garbage_Collected, -- System.Parameters
RE_Size_Type, -- System.Parameters
@@ -1424,12 +1425,12 @@ package Rtsfind is
RE_IS_Ilf, -- System.Scalar_Values
RE_IS_Ill, -- System.Scalar_Values
- RE_Default_Secondary_Stack_Size, -- System.Secondary_Stack
RE_Mark_Id, -- System.Secondary_Stack
RE_SS_Allocate, -- System.Secondary_Stack
RE_SS_Pool, -- System.Secondary_Stack
RE_SS_Mark, -- System.Secondary_Stack
RE_SS_Release, -- System.Secondary_Stack
+ RE_SS_Stack, -- System.Secondary_Stack
RE_Shared_Var_Lock, -- System.Shared_Storage
RE_Shared_Var_Unlock, -- System.Shared_Storage
@@ -2487,6 +2488,7 @@ package Rtsfind is
RE_Set_63 => System_Pack_63,
RE_Adjust_Storage_Size => System_Parameters,
+ RE_Default_Secondary_Stack_Size => System_Parameters,
RE_Default_Stack_Size => System_Parameters,
RE_Garbage_Collected => System_Parameters,
RE_Size_Type => System_Parameters,
@@ -2662,12 +2664,12 @@ package Rtsfind is
RE_IS_Ilf => System_Scalar_Values,
RE_IS_Ill => System_Scalar_Values,
- RE_Default_Secondary_Stack_Size => System_Secondary_Stack,
RE_Mark_Id => System_Secondary_Stack,
RE_SS_Allocate => System_Secondary_Stack,
RE_SS_Mark => System_Secondary_Stack,
RE_SS_Pool => System_Secondary_Stack,
RE_SS_Release => System_Secondary_Stack,
+ RE_SS_Stack => System_Secondary_Stack,
RE_Shared_Var_Lock => System_Shared_Storage,
RE_Shared_Var_Unlock => System_Shared_Storage,
diff --git a/gcc/ada/s-oscons-tmplt.c b/gcc/ada/s-oscons-tmplt.c
index 0ace0b6..444ad60 100644
--- a/gcc/ada/s-oscons-tmplt.c
+++ b/gcc/ada/s-oscons-tmplt.c
@@ -1440,7 +1440,8 @@ CND(CLOCK_FASTEST, "Fastest clock")
#endif
CND(CLOCK_THREAD_CPUTIME_ID, "Thread CPU clock")
-#if defined(__FreeBSD__) || (defined(_AIX) && defined(_AIXVERSION_530)) \
+#if defined(__linux__) || defined(__FreeBSD__) \
+ || (defined(_AIX) && defined(_AIXVERSION_530)) \
|| defined(__DragonFly__)
/** On these platforms use system provided monotonic clock instead of
** the default CLOCK_REALTIME. We then need to set up cond var attributes
diff --git a/gcc/ada/scn.ads b/gcc/ada/scn.ads
index 77ebadc..10e4ad3 100644
--- a/gcc/ada/scn.ads
+++ b/gcc/ada/scn.ads
@@ -29,7 +29,7 @@
with Casing; use Casing;
with Errout; use Errout;
with Scng;
-with Style; use Style;
+with Style; -- use Style;
with Types; use Types;
package Scn is
diff --git a/gcc/ada/sem.adb b/gcc/ada/sem.adb
index 35d0d48..aaa3ccb 100644
--- a/gcc/ada/sem.adb
+++ b/gcc/ada/sem.adb
@@ -612,6 +612,12 @@ package body Sem is
when N_With_Clause =>
Analyze_With_Clause (N);
+ -- A call to analyze a call marker is ignored because the node does
+ -- not have any static and run-time semantics.
+
+ when N_Call_Marker =>
+ null;
+
-- A call to analyze the Empty node is an error, but most likely it
-- is an error caused by an attempt to analyze a malformed piece of
-- tree caused by some other error, so if there have been any other
@@ -732,6 +738,18 @@ package body Sem is
Debug_A_Exit ("analyzing ", N, " (done)");
+ -- Mark relevant use-type and use-package clauses as effective using the
+ -- original node, because constant folding may have occurred and removed
+ -- references that need to be examined. If the node in question is
+ -- overloaded then this is deferred until resolution.
+
+ if Nkind (Original_Node (N)) in N_Op
+ and then Present (Entity (Original_Node (N)))
+ and then not Is_Overloaded (Original_Node (N))
+ then
+ Mark_Use_Clauses (Original_Node (N));
+ end if;
+
-- Now that we have analyzed the node, we call the expander to perform
-- possible expansion. We skip this for subexpressions, because we don't
-- have the type yet, and the expander will need to know the type before
@@ -1230,6 +1248,15 @@ package body Sem is
Scope_Stack.Locked := True;
end Lock;
+ ------------------------
+ -- Preanalysis_Active --
+ ------------------------
+
+ function Preanalysis_Active return Boolean is
+ begin
+ return not Full_Analysis and not Expander_Active;
+ end Preanalysis_Active;
+
----------------
-- Preanalyze --
----------------
diff --git a/gcc/ada/sem.ads b/gcc/ada/sem.ads
index fca920a..500f922 100644
--- a/gcc/ada/sem.ads
+++ b/gcc/ada/sem.ads
@@ -683,6 +683,10 @@ package Sem is
-- This function returns True if an explicit pragma Suppress for check C
-- is present in the package defining E.
+ function Preanalysis_Active return Boolean;
+ pragma Inline (Preanalysis_Active);
+ -- Determine whether preanalysis is active at the point of invocation
+
procedure Preanalyze (N : Node_Id);
-- Performs a pre-analysis of node N. During pre-analysis no expansion is
-- carried out for N or its children. For more info on pre-analysis read
diff --git a/gcc/ada/sem_aggr.adb b/gcc/ada/sem_aggr.adb
index c885ce9..6c29b38 100644
--- a/gcc/ada/sem_aggr.adb
+++ b/gcc/ada/sem_aggr.adb
@@ -30,6 +30,7 @@ with Einfo; use Einfo;
with Elists; use Elists;
with Errout; use Errout;
with Expander; use Expander;
+with Exp_Ch6; use Exp_Ch6;
with Exp_Tss; use Exp_Tss;
with Exp_Util; use Exp_Util;
with Freeze; use Freeze;
@@ -1593,7 +1594,7 @@ package body Sem_Aggr is
-- unless the expression covers a single component, or the
-- expander is inactive.
- -- In SPARK mode, expressions that can perform side-effects will
+ -- In SPARK mode, expressions that can perform side effects will
-- be recognized by the gnat2why back-end, and the whole
-- subprogram will be ignored. So semantic analysis can be
-- performed safely.
@@ -2932,6 +2933,11 @@ package body Sem_Aggr is
-- Verify that the type of the ancestor part is a non-private ancestor
-- of the expected type, which must be a type extension.
+ procedure Transform_BIP_Assignment (Typ : Entity_Id);
+ -- For an extension aggregate whose ancestor part is a build-in-place
+ -- call returning a nonlimited type, this is used to transform the
+ -- assignment to the ancestor part to use a temp.
+
----------------------------
-- Valid_Limited_Ancestor --
----------------------------
@@ -3013,6 +3019,26 @@ package body Sem_Aggr is
return False;
end Valid_Ancestor_Type;
+ ------------------------------
+ -- Transform_BIP_Assignment --
+ ------------------------------
+
+ procedure Transform_BIP_Assignment (Typ : Entity_Id) is
+ Loc : constant Source_Ptr := Sloc (N);
+ Def_Id : constant Entity_Id := Make_Temporary (Loc, 'Y', A);
+ Obj_Decl : constant Node_Id :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Def_Id,
+ Constant_Present => True,
+ Object_Definition => New_Occurrence_Of (Typ, Loc),
+ Expression => A,
+ Has_Init_Expression => True);
+ begin
+ Set_Etype (Def_Id, Typ);
+ Set_Ancestor_Part (N, New_Occurrence_Of (Def_Id, Loc));
+ Insert_Action (N, Obj_Decl);
+ end Transform_BIP_Assignment;
+
-- Start of processing for Resolve_Extension_Aggregate
begin
@@ -3081,7 +3107,7 @@ package body Sem_Aggr is
Get_First_Interp (A, I, It);
while Present (It.Typ) loop
- -- Only consider limited interpretations in the Ada 2005 case
+ -- Consider limited interpretations if Ada 2005 or higher
if Is_Tagged_Type (It.Typ)
and then (Ada_Version >= Ada_2005
@@ -3177,6 +3203,18 @@ package body Sem_Aggr is
Error_Msg_N ("ancestor part must be statically tagged", A);
else
+ -- We are using the build-in-place protocol, but we can't build
+ -- in place, because we need to call the function before
+ -- allocating the aggregate. Could do better for null
+ -- extensions, and maybe for nondiscriminated types.
+ -- This is wrong for limited, but those were wrong already.
+
+ if not Is_Limited_View (A_Type)
+ and then Is_Build_In_Place_Function_Call (A)
+ then
+ Transform_BIP_Assignment (A_Type);
+ end if;
+
Resolve_Record_Aggregate (N, Typ);
end if;
end if;
@@ -3567,7 +3605,7 @@ package body Sem_Aggr is
-- This is redundant if the others_choice covers only
-- one component (small optimization possible???), but
-- indispensable otherwise, because each one must be
- -- expanded individually to preserve side-effects.
+ -- expanded individually to preserve side effects.
-- Ada 2005 (AI-287): In case of default initialization
-- of components, we duplicate the corresponding default
@@ -3843,7 +3881,7 @@ package body Sem_Aggr is
-- expansion is delayed until the enclosing aggregate is expanded
-- into assignments. In that case, do not generate checks on the
-- expression, because they will be generated later, and will other-
- -- wise force a copy (to remove side-effects) that would leave a
+ -- wise force a copy (to remove side effects) that would leave a
-- dynamic-sized aggregate in the code, something that gigi cannot
-- handle.
@@ -4108,15 +4146,23 @@ package body Sem_Aggr is
begin
Assoc := First (Component_Associations (N));
while Present (Assoc) loop
- if List_Length (Choices (Assoc)) > 1 then
- Check_SPARK_05_Restriction
- ("component association in record aggregate must "
- & "contain a single choice", Assoc);
- end if;
+ if Nkind (Assoc) = N_Iterated_Component_Association then
+ Error_Msg_N
+ ("iterated component association can only appear in an "
+ & "array aggregate", N);
+ raise Unrecoverable_Error;
+
+ else
+ if List_Length (Choices (Assoc)) > 1 then
+ Check_SPARK_05_Restriction
+ ("component association in record aggregate must "
+ & "contain a single choice", Assoc);
+ end if;
- if Nkind (First (Choices (Assoc))) = N_Others_Choice then
- Check_SPARK_05_Restriction
- ("record aggregate cannot contain OTHERS", Assoc);
+ if Nkind (First (Choices (Assoc))) = N_Others_Choice then
+ Check_SPARK_05_Restriction
+ ("record aggregate cannot contain OTHERS", Assoc);
+ end if;
end if;
Assoc := Next (Assoc);
diff --git a/gcc/ada/sem_attr.adb b/gcc/ada/sem_attr.adb
index 9500b1a..5aef17d 100644
--- a/gcc/ada/sem_attr.adb
+++ b/gcc/ada/sem_attr.adb
@@ -28,7 +28,6 @@ with Ada.Characters.Latin_1; use Ada.Characters.Latin_1;
with Atree; use Atree;
with Casing; use Casing;
with Checks; use Checks;
-with Debug; use Debug;
with Einfo; use Einfo;
with Elists; use Elists;
with Errout; use Errout;
@@ -47,7 +46,7 @@ with Opt; use Opt;
with Restrict; use Restrict;
with Rident; use Rident;
with Rtsfind; use Rtsfind;
-with Sdefault; use Sdefault;
+with Sdefault;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
with Sem_Cat; use Sem_Cat;
@@ -806,6 +805,20 @@ package body Sem_Attr is
("prefix of % attribute cannot be enumeration literal");
end if;
+ -- Preserve relevant elaboration-related attributes of the context
+ -- which are no longer available or very expensive to recompute once
+ -- analysis, resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => N,
+ Checks => True,
+ Modes => True);
+
+ -- Save the scenario for later examination by the ABE Processing
+ -- phase.
+
+ Record_Elaboration_Scenario (N);
+
-- Case of access to subprogram
if Is_Entity_Name (P) and then Is_Overloadable (Entity (P)) then
@@ -860,14 +873,6 @@ package body Sem_Attr is
Kill_Current_Values;
end if;
- -- In the static elaboration model, treat the attribute reference
- -- as a call for elaboration purposes. Suppress this treatment
- -- under debug flag. In any case, we are all done.
-
- if not Dynamic_Elaboration_Checks and not Debug_Flag_Dot_UU then
- Check_Elab_Call (N);
- end if;
-
return;
-- Component is an operation of a protected type
@@ -11089,7 +11094,7 @@ package body Sem_Attr is
and then Is_Overloadable (Entity (P)))
and then not (Nkind (P) = N_Selected_Component
and then
- Is_Overloadable (Entity (Selector_Name (P))))
+ Is_Overloadable (Entity (Selector_Name (P))))
and then not Is_Aliased_View (P)
and then not In_Instance
and then not In_Inlined_Body
@@ -11133,8 +11138,8 @@ package body Sem_Attr is
-- 'Unrestricted_Access or in case of a subprogram.
if Is_Entity_Name (P)
- and then (Attr_Id = Attribute_Unrestricted_Access
- or else Is_Subprogram (Entity (P)))
+ and then (Attr_Id = Attribute_Unrestricted_Access
+ or else Is_Subprogram (Entity (P)))
then
Set_Address_Taken (Entity (P));
end if;
@@ -11797,6 +11802,15 @@ package body Sem_Attr is
end if;
end case;
+ -- Mark use clauses of the original prefix if the attribute is applied
+ -- to an entity.
+
+ if Nkind (Original_Node (P)) in N_Has_Entity
+ and then Present (Entity (Original_Node (P)))
+ then
+ Mark_Use_Clauses (Original_Node (P));
+ end if;
+
-- Normally the Freezing is done by Resolve but sometimes the Prefix
-- is not resolved, in which case the freezing must be done now.
diff --git a/gcc/ada/sem_aux.adb b/gcc/ada/sem_aux.adb
index 4f60f41..d34ed07 100644
--- a/gcc/ada/sem_aux.adb
+++ b/gcc/ada/sem_aux.adb
@@ -1693,6 +1693,7 @@ package body Sem_Aux is
and then Nkind (N) /= N_Package_Renaming_Declaration
and then Nkind (N) /= N_Procedure_Instantiation
and then Nkind (N) /= N_Protected_Body
+ and then Nkind (N) /= N_Protected_Type_Declaration
and then Nkind (N) /= N_Subprogram_Declaration
and then Nkind (N) /= N_Subprogram_Body
and then Nkind (N) /= N_Subprogram_Body_Stub
diff --git a/gcc/ada/sem_aux.ads b/gcc/ada/sem_aux.ads
index 2ab9ef6..7da7b41 100644
--- a/gcc/ada/sem_aux.ads
+++ b/gcc/ada/sem_aux.ads
@@ -38,7 +38,7 @@
-- content of entities in the tree, so this package is used for routines that
-- require more than minimal semantic knowledge.
-with Alloc; use Alloc;
+with Alloc;
with Namet; use Namet;
with Table;
with Types; use Types;
diff --git a/gcc/ada/sem_ch10.adb b/gcc/ada/sem_ch10.adb
index 6da229c..0616a20 100644
--- a/gcc/ada/sem_ch10.adb
+++ b/gcc/ada/sem_ch10.adb
@@ -138,9 +138,12 @@ package body Sem_Ch10 is
-- Check that the shadow entity is not already in the homonym chain, for
-- example through a limited_with clause in a parent unit.
- procedure Install_Context_Clauses (N : Node_Id);
+ procedure Install_Context_Clauses (N : Node_Id; Chain : Boolean := True);
-- Subsidiary to Install_Context and Install_Parents. Process all with
- -- and use clauses for current unit and its library unit if any.
+ -- and use clauses for current unit and its library unit if any. The flag
+ -- Chain is used to control the "chaining" or linking together of use-type
+ -- and use-package clauses to avoid circularities with reinstalling
+ -- clauses.
procedure Install_Limited_Context_Clauses (N : Node_Id);
-- Subsidiary to Install_Context. Process only limited with_clauses for
@@ -159,7 +162,10 @@ package body Sem_Ch10 is
-- is called when compiling the private part of a package, or installing
-- the private declarations of a parent unit.
- procedure Install_Parents (Lib_Unit : Node_Id; Is_Private : Boolean);
+ procedure Install_Parents
+ (Lib_Unit : Node_Id;
+ Is_Private : Boolean;
+ Chain : Boolean := True);
-- This procedure establishes the context for the compilation of a child
-- unit. If Lib_Unit is a child library spec then the context of the parent
-- is installed, and the parent itself made immediately visible, so that
@@ -168,7 +174,9 @@ package body Sem_Ch10 is
-- parents are loaded in the nested case. If Lib_Unit is a library body,
-- the only effect of Install_Parents is to install the private decls of
-- the parents, because the visible parent declarations will have been
- -- installed as part of the context of the corresponding spec.
+ -- installed as part of the context of the corresponding spec. The flag
+ -- Chain is used to control the "chaining" or linking of use-type and
+ -- use-package clauses to avoid circularities when installing context.
procedure Install_Siblings (U_Name : Entity_Id; N : Node_Id);
-- In the compilation of a child unit, a child of any of the ancestor
@@ -342,53 +350,45 @@ package body Sem_Ch10 is
then
-- Search through use clauses
- Use_Item := First (Names (Cont_Item));
- while Present (Use_Item) and then not Used loop
+ Use_Item := Name (Cont_Item);
- -- Case of a direct use of the one we are looking for
+ -- Case of a direct use of the one we are looking for
- if Entity (Use_Item) = Nam_Ent then
- Used := True;
+ if Entity (Use_Item) = Nam_Ent then
+ Used := True;
- -- Handle nested case, as in "with P; use P.Q.R"
+ -- Handle nested case, as in "with P; use P.Q.R"
- else
- declare
- UE : Node_Id;
-
- begin
- -- Loop through prefixes looking for match
+ else
+ declare
+ UE : Node_Id;
- UE := Use_Item;
- while Nkind (UE) = N_Expanded_Name loop
- if Same_Unit (Prefix (UE), Nam_Ent) then
- Used := True;
- exit;
- end if;
+ begin
+ -- Loop through prefixes looking for match
- UE := Prefix (UE);
- end loop;
- end;
- end if;
+ UE := Use_Item;
+ while Nkind (UE) = N_Expanded_Name loop
+ if Same_Unit (Prefix (UE), Nam_Ent) then
+ Used := True;
+ exit;
+ end if;
- Next (Use_Item);
- end loop;
+ UE := Prefix (UE);
+ end loop;
+ end;
+ end if;
-- USE TYPE clause
elsif Nkind (Cont_Item) = N_Use_Type_Clause
and then not Used_Type_Or_Elab
then
- Subt_Mark := First (Subtype_Marks (Cont_Item));
- while Present (Subt_Mark)
- and then not Used_Type_Or_Elab
- loop
- if Same_Unit (Prefix (Subt_Mark), Nam_Ent) then
- Used_Type_Or_Elab := True;
- end if;
-
- Next (Subt_Mark);
- end loop;
+ Subt_Mark := Subtype_Mark (Cont_Item);
+ if not Used_Type_Or_Elab
+ and then Same_Unit (Prefix (Subt_Mark), Nam_Ent)
+ then
+ Used_Type_Or_Elab := True;
+ end if;
-- Pragma Elaborate or Elaborate_All
@@ -426,7 +426,6 @@ package body Sem_Ch10 is
is
Nam_Ent : constant Entity_Id := Entity (Name (Clause));
Cont_Item : Node_Id;
- Use_Item : Node_Id;
begin
Used := False;
@@ -450,14 +449,9 @@ package body Sem_Ch10 is
if Nkind (Cont_Item) = N_Use_Package_Clause
and then not Used
then
- Use_Item := First (Names (Cont_Item));
- while Present (Use_Item) and then not Used loop
- if Entity (Use_Item) = Nam_Ent then
- Used := True;
- end if;
-
- Next (Use_Item);
- end loop;
+ if Entity (Name (Cont_Item)) = Nam_Ent then
+ Used := True;
+ end if;
-- Package with clause. Avoid processing self, implicitly
-- generated with clauses or limited with clauses. Note that
@@ -2103,7 +2097,6 @@ package body Sem_Ch10 is
procedure Analyze_Subunit_Context is
Item : Node_Id;
- Nam : Node_Id;
Unit_Name : Entity_Id;
begin
@@ -2154,18 +2147,10 @@ package body Sem_Ch10 is
end if;
elsif Nkind (Item) = N_Use_Package_Clause then
- Nam := First (Names (Item));
- while Present (Nam) loop
- Analyze (Nam);
- Next (Nam);
- end loop;
+ Analyze (Name (Item));
elsif Nkind (Item) = N_Use_Type_Clause then
- Nam := First (Subtype_Marks (Item));
- while Present (Nam) loop
- Analyze (Nam);
- Next (Nam);
- end loop;
+ Analyze (Subtype_Mark (Item));
end if;
Next (Item);
@@ -2212,7 +2197,7 @@ package body Sem_Ch10 is
Re_Install_Parents (Library_Unit (L), Scope (Scop));
end if;
- Install_Context (L);
+ Install_Context (L, False);
-- If the subunit occurs within a child unit, we must restore the
-- immediate visibility of any siblings that may occur in context.
@@ -2259,7 +2244,7 @@ package body Sem_Ch10 is
for J in reverse 1 .. Num_Scopes loop
U := Use_Clauses (J);
Scope_Stack.Table (Scope_Stack.Last - J + 1).First_Use_Clause := U;
- Install_Use_Clauses (U, Force_Installation => True);
+ Install_Use_Clauses (U);
end loop;
end Re_Install_Use_Clauses;
@@ -2383,7 +2368,7 @@ package body Sem_Ch10 is
end if;
Re_Install_Use_Clauses;
- Install_Context (N);
+ Install_Context (N, Chain => False);
-- Restore state of suppress flags for current body
@@ -3399,14 +3384,17 @@ package body Sem_Ch10 is
-- Install_Context --
---------------------
- procedure Install_Context (N : Node_Id) is
+ procedure Install_Context (N : Node_Id; Chain : Boolean := True) is
Lib_Unit : constant Node_Id := Unit (N);
begin
- Install_Context_Clauses (N);
+ Install_Context_Clauses (N, Chain);
if Is_Child_Spec (Lib_Unit) then
- Install_Parents (Lib_Unit, Private_Present (Parent (Lib_Unit)));
+ Install_Parents
+ (Lib_Unit => Lib_Unit,
+ Is_Private => Private_Present (Parent (Lib_Unit)),
+ Chain => Chain);
end if;
Install_Limited_Context_Clauses (N);
@@ -3416,7 +3404,7 @@ package body Sem_Ch10 is
-- Install_Context_Clauses --
-----------------------------
- procedure Install_Context_Clauses (N : Node_Id) is
+ procedure Install_Context_Clauses (N : Node_Id; Chain : Boolean := True) is
Lib_Unit : constant Node_Id := Unit (N);
Item : Node_Id;
Uname_Node : Entity_Id;
@@ -3567,12 +3555,12 @@ package body Sem_Ch10 is
-- Case of USE PACKAGE clause
elsif Nkind (Item) = N_Use_Package_Clause then
- Analyze_Use_Package (Item);
+ Analyze_Use_Package (Item, Chain);
-- Case of USE TYPE clause
elsif Nkind (Item) = N_Use_Type_Clause then
- Analyze_Use_Type (Item);
+ Analyze_Use_Type (Item, Chain);
-- case of PRAGMA
@@ -3602,7 +3590,7 @@ package body Sem_Ch10 is
or else (Nkind (Lib_Unit) = N_Subprogram_Body
and then not Acts_As_Spec (N))
then
- Install_Context (Library_Unit (N));
+ Install_Context (Library_Unit (N), Chain);
-- Only install private with-clauses of a spec that comes from
-- source, excluding specs created for a subprogram body that is
@@ -3716,7 +3704,6 @@ package body Sem_Ch10 is
Item : Node_Id;
Spec : Node_Id;
WEnt : Entity_Id;
- Nam : Node_Id;
E : Entity_Id;
E2 : Entity_Id;
@@ -3749,43 +3736,36 @@ package body Sem_Ch10 is
if Nkind (Item) = N_Use_Package_Clause then
- -- Traverse the list of packages
+ E := Entity (Name (Item));
- Nam := First (Names (Item));
- while Present (Nam) loop
- E := Entity (Nam);
+ pragma Assert (Present (Parent (E)));
- pragma Assert (Present (Parent (E)));
-
- if Nkind (Parent (E)) = N_Package_Renaming_Declaration
- and then Renamed_Entity (E) = WEnt
- then
- -- The unlimited view is visible through use clause and
- -- renamings. There is no need to generate the error
- -- message here because Is_Visible_Through_Renamings
- -- takes care of generating the precise error message.
+ if Nkind (Parent (E)) = N_Package_Renaming_Declaration
+ and then Renamed_Entity (E) = WEnt
+ then
+ -- The unlimited view is visible through use clause and
+ -- renamings. There is no need to generate the error
+ -- message here because Is_Visible_Through_Renamings
+ -- takes care of generating the precise error message.
- return;
+ return;
- elsif Nkind (Parent (E)) = N_Package_Specification then
+ elsif Nkind (Parent (E)) = N_Package_Specification then
- -- The use clause may refer to a local package.
- -- Check all the enclosing scopes.
+ -- The use clause may refer to a local package.
+ -- Check all the enclosing scopes.
- E2 := E;
- while E2 /= Standard_Standard and then E2 /= WEnt loop
- E2 := Scope (E2);
- end loop;
+ E2 := E;
+ while E2 /= Standard_Standard and then E2 /= WEnt loop
+ E2 := Scope (E2);
+ end loop;
- if E2 = WEnt then
- Error_Msg_N
- ("unlimited view visible through use clause ", W);
- return;
- end if;
+ if E2 = WEnt then
+ Error_Msg_N
+ ("unlimited view visible through use clause ", W);
+ return;
end if;
-
- Next (Nam);
- end loop;
+ end if;
end if;
Next (Item);
@@ -4088,7 +4068,11 @@ package body Sem_Ch10 is
-- Install_Parents --
---------------------
- procedure Install_Parents (Lib_Unit : Node_Id; Is_Private : Boolean) is
+ procedure Install_Parents
+ (Lib_Unit : Node_Id;
+ Is_Private : Boolean;
+ Chain : Boolean := True)
+ is
P : Node_Id;
E_Name : Entity_Id;
P_Name : Entity_Id;
@@ -4144,13 +4128,16 @@ package body Sem_Ch10 is
-- This is the recursive call that ensures all parents are loaded
if Is_Child_Spec (P) then
- Install_Parents (P,
- Is_Private or else Private_Present (Parent (Lib_Unit)));
+ Install_Parents
+ (Lib_Unit => P,
+ Is_Private =>
+ Is_Private or else Private_Present (Parent (Lib_Unit)),
+ Chain => Chain);
end if;
-- Now we can install the context for this parent
- Install_Context_Clauses (Parent_Spec (Lib_Unit));
+ Install_Context_Clauses (Parent_Spec (Lib_Unit), Chain);
Install_Limited_Context_Clauses (Parent_Spec (Lib_Unit));
Install_Siblings (P_Name, Parent (Lib_Unit));
diff --git a/gcc/ada/sem_ch10.ads b/gcc/ada/sem_ch10.ads
index d4b28cd..2843d9e 100644
--- a/gcc/ada/sem_ch10.ads
+++ b/gcc/ada/sem_ch10.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2015, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -34,10 +34,12 @@ package Sem_Ch10 is
procedure Analyze_Protected_Body_Stub (N : Node_Id);
procedure Analyze_Subunit (N : Node_Id);
- procedure Install_Context (N : Node_Id);
+ procedure Install_Context (N : Node_Id; Chain : Boolean := True);
-- Installs the entities from the context clause of the given compilation
-- unit into the visibility chains. This is done before analyzing a unit.
- -- For a child unit, install context of parents as well.
+ -- For a child unit, install context of parents as well. The flag Chain is
+ -- used to control the "chaining" or linking of use-type and use-package
+ -- clauses to avoid circularities when reinstalling context clauses.
procedure Install_Private_With_Clauses (P : Entity_Id);
-- Install the private with_clauses of a compilation unit, when compiling
diff --git a/gcc/ada/sem_ch12.adb b/gcc/ada/sem_ch12.adb
index 058809e..ac5035f 100644
--- a/gcc/ada/sem_ch12.adb
+++ b/gcc/ada/sem_ch12.adb
@@ -839,6 +839,10 @@ package body Sem_Ch12 is
-- entity is marked as having a limited_view actual when some actual is
-- a limited view. This is used to place the instance body properly.
+ procedure Provide_Completing_Bodies (N : Node_Id);
+ -- Generate completing bodies for all subprograms found within package or
+ -- subprogram declaration N.
+
procedure Remove_Parent (In_Body : Boolean := False);
-- Reverse effect after instantiation of child is complete
@@ -1903,7 +1907,8 @@ package body Sem_Ch12 is
-- body.
Explicit_Freeze_Check : declare
- Actual : constant Entity_Id := Entity (Match);
+ Actual : constant Entity_Id := Entity (Match);
+ Gen_Par : Entity_Id;
Needs_Freezing : Boolean;
S : Entity_Id;
@@ -1912,7 +1917,11 @@ package body Sem_Ch12 is
-- The actual may be an instantiation of a unit
-- declared in a previous instantiation. If that
-- one is also in the current compilation, it must
- -- itself be frozen before the actual.
+ -- itself be frozen before the actual. The actual
+ -- may be an instantiation of a generic child unit,
+ -- in which case the same applies to the instance
+ -- of the parent which must be frozen before the
+ -- actual.
-- Should this itself be recursive ???
--------------------------
@@ -1920,30 +1929,72 @@ package body Sem_Ch12 is
--------------------------
procedure Check_Generic_Parent is
- Par : Entity_Id;
+ Inst : constant Node_Id :=
+ Next (Unit_Declaration_Node (Actual));
+ Par : Entity_Id;
begin
- if Nkind (Parent (Actual)) =
- N_Package_Specification
+ Par := Empty;
+
+ if Nkind (Parent (Actual)) = N_Package_Specification
then
Par := Scope (Generic_Parent (Parent (Actual)));
- if Is_Generic_Instance (Par)
- and then Scope (Par) = Current_Scope
- and then
- (No (Freeze_Node (Par))
- or else
- not Is_List_Member (Freeze_Node (Par)))
+ if Is_Generic_Instance (Par) then
+ null;
+
+ -- If the actual is a child generic unit, check
+ -- whether the instantiation of the parent is
+ -- also local and must also be frozen now. We
+ -- must retrieve the instance node to locate the
+ -- parent instance if any.
+
+ elsif Ekind (Par) = E_Generic_Package
+ and then Is_Child_Unit (Gen_Par)
+ and then Ekind (Scope (Gen_Par)) =
+ E_Generic_Package
then
- Set_Has_Delayed_Freeze (Par);
- Append_Elmt (Par, Actuals_To_Freeze);
+ if Nkind (Inst) = N_Package_Instantiation
+ and then Nkind (Name (Inst)) =
+ N_Expanded_Name
+ then
+ -- Retrieve entity of parent instance
+
+ Par := Entity (Prefix (Name (Inst)));
+ end if;
+
+ else
+ Par := Empty;
end if;
end if;
+
+ if Present (Par)
+ and then Is_Generic_Instance (Par)
+ and then Scope (Par) = Current_Scope
+ and then
+ (No (Freeze_Node (Par))
+ or else
+ not Is_List_Member (Freeze_Node (Par)))
+ then
+ Set_Has_Delayed_Freeze (Par);
+ Append_Elmt (Par, Actuals_To_Freeze);
+ end if;
end Check_Generic_Parent;
-- Start of processing for Explicit_Freeze_Check
begin
+ if Present (Renamed_Entity (Actual)) then
+ Gen_Par :=
+ Generic_Parent (Specification
+ (Unit_Declaration_Node
+ (Renamed_Entity (Actual))));
+ else
+ Gen_Par :=
+ Generic_Parent (Specification
+ (Unit_Declaration_Node (Actual)));
+ end if;
+
if not Expander_Active
or else not Has_Completion (Actual)
or else not In_Same_Source_Unit (I_Node, Actual)
@@ -1980,8 +2031,23 @@ package body Sem_Ch12 is
if Needs_Freezing then
Check_Generic_Parent;
- Set_Has_Delayed_Freeze (Actual);
- Append_Elmt (Actual, Actuals_To_Freeze);
+
+ -- If the actual is a renaming of a proper
+ -- instance of the formal package, indicate
+ -- that it is the instance that must be frozen.
+
+ if Nkind (Parent (Actual)) =
+ N_Package_Renaming_Declaration
+ then
+ Set_Has_Delayed_Freeze
+ (Renamed_Entity (Actual));
+ Append_Elmt
+ (Renamed_Entity (Actual),
+ Actuals_To_Freeze);
+ else
+ Set_Has_Delayed_Freeze (Actual);
+ Append_Elmt (Actual, Actuals_To_Freeze);
+ end if;
end if;
end if;
end Explicit_Freeze_Check;
@@ -3482,6 +3548,14 @@ package body Sem_Ch12 is
Set_SPARK_Pragma_Inherited (Id);
Set_SPARK_Aux_Pragma_Inherited (Id);
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => Id,
+ Checks => True);
+
-- Analyze aspects now, so that generated pragmas appear in the
-- declarations before building and analyzing the generic copy.
@@ -3610,7 +3684,7 @@ package body Sem_Ch12 is
Create_Generic_Contract (N);
Spec := Specification (N);
- Id := Defining_Entity (Spec);
+ Id := Defining_Entity (Spec);
Generate_Definition (Id);
if Nkind (Id) = N_Defining_Operator_Symbol then
@@ -3637,14 +3711,27 @@ package body Sem_Ch12 is
Analyze_Generic_Formal_Part (N);
- Formals := Parameter_Specifications (Spec);
-
if Nkind (Spec) = N_Function_Specification then
Set_Ekind (Id, E_Generic_Function);
else
Set_Ekind (Id, E_Generic_Procedure);
end if;
+ -- Set SPARK_Mode from context
+
+ Set_SPARK_Pragma (Id, SPARK_Mode_Pragma);
+ Set_SPARK_Pragma_Inherited (Id);
+
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => Id,
+ Checks => True);
+
+ Formals := Parameter_Specifications (Spec);
+
if Present (Formals) then
Process_Formals (Formals, Spec);
end if;
@@ -3840,6 +3927,16 @@ package body Sem_Ch12 is
-- Start of processing for Analyze_Package_Instantiation
begin
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => N,
+ Checks => True,
+ Level => True,
+ Modes => True);
+
Check_SPARK_05_Restriction ("generic is not allowed", N);
-- Very first thing: check for Text_IO special unit in case we are
@@ -4502,19 +4599,26 @@ package body Sem_Ch12 is
Analyze (Act_Decl);
Set_Unit (Parent (N), N);
Set_Body_Required (Parent (N), False);
+ end if;
- -- We never need elaboration checks on instantiations, since by
- -- definition, the body instantiation is elaborated at the same
- -- time as the spec instantiation.
+ -- Save the scenario for later examination by the ABE Processing
+ -- phase.
- Set_Suppress_Elaboration_Warnings (Act_Decl_Id);
- Set_Kill_Elaboration_Checks (Act_Decl_Id);
- end if;
+ Record_Elaboration_Scenario (N);
+
+ -- The instantiation results in a guaranteed ABE
- Check_Elab_Instantiation (N);
+ if Is_Known_Guaranteed_ABE (N) and then Needs_Body then
+
+ -- Do not instantiate the corresponding body because gigi cannot
+ -- handle certain types of premature instantiations.
- if ABE_Is_Certain (N) and then Needs_Body then
Pending_Instantiations.Decrement_Last;
+
+ -- Create completing bodies for all subprogram declarations since
+ -- their real bodies will not be instantiated.
+
+ Provide_Completing_Bodies (Instance_Spec (N));
end if;
Check_Hidden_Child_Unit (N, Gen_Unit, Act_Decl_Id);
@@ -4826,7 +4930,7 @@ package body Sem_Ch12 is
end loop;
if Removed then
- Install_Context (Curr_Comp);
+ Install_Context (Curr_Comp, Chain => False);
if Present (Curr_Scope)
and then Is_Child_Unit (Curr_Scope)
@@ -4996,7 +5100,7 @@ package body Sem_Ch12 is
-- No point in inlining if ABE is inevitable
- and then not ABE_Is_Certain (N)
+ and then not Is_Known_Guaranteed_ABE (N)
-- Or if subprogram is eliminated
@@ -5182,12 +5286,7 @@ package body Sem_Ch12 is
Check_Eliminated (Act_Decl_Id);
Set_Is_Eliminated (Anon_Id, Is_Eliminated (Act_Decl_Id));
- -- In compilation unit case, kill elaboration checks on the
- -- instantiation, since they are never needed -- the body is
- -- instantiated at the same point as the spec.
-
if Nkind (Parent (N)) = N_Compilation_Unit then
- Set_Suppress_Elaboration_Warnings (Act_Decl_Id);
Set_Kill_Elaboration_Checks (Act_Decl_Id);
Set_Is_Compilation_Unit (Anon_Id);
@@ -5206,8 +5305,7 @@ package body Sem_Ch12 is
Valid_Operator_Definition (Act_Decl_Id);
end if;
- Set_Alias (Act_Decl_Id, Anon_Id);
- Set_Parent (Act_Decl_Id, Parent (Anon_Id));
+ Set_Alias (Act_Decl_Id, Anon_Id);
Set_Has_Completion (Act_Decl_Id);
Set_Related_Instance (Pack_Id, Act_Decl_Id);
@@ -5278,6 +5376,16 @@ package body Sem_Ch12 is
-- Start of processing for Analyze_Subprogram_Instantiation
begin
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => N,
+ Checks => True,
+ Level => True,
+ Modes => True);
+
Check_SPARK_05_Restriction ("generic is not allowed", N);
-- Very first thing: check for special Text_IO unit in case we are
@@ -5530,8 +5638,17 @@ package body Sem_Ch12 is
Set_Ignore_SPARK_Mode_Pragmas (Anon_Id);
end if;
- if not Is_Intrinsic_Subprogram (Gen_Unit) then
- Check_Elab_Instantiation (N);
+ -- Save the scenario for later examination by the ABE Processing
+ -- phase.
+
+ Record_Elaboration_Scenario (N);
+
+ -- The instantiation results in a guaranteed ABE. Create a completing
+ -- body for the subprogram declaration because the real body will not
+ -- be instantiated.
+
+ if Is_Known_Guaranteed_ABE (N) then
+ Provide_Completing_Bodies (Instance_Spec (N));
end if;
if Is_Dispatching_Operation (Act_Decl_Id)
@@ -6342,10 +6459,11 @@ package body Sem_Ch12 is
elsif Ekind (E1) = E_Package then
Check_Mismatch
(Ekind (E1) /= Ekind (E2)
- or else Renamed_Object (E1) /= Renamed_Object (E2));
+ or else (Present (Renamed_Object (E2))
+ and then Renamed_Object (E1) /=
+ Renamed_Object (E2)));
elsif Is_Overloadable (E1) then
-
-- Verify that the actual subprograms match. Note that actuals
-- that are attributes are rewritten as subprograms. If the
-- subprogram in the formal package is defaulted, no check is
@@ -8501,7 +8619,7 @@ package body Sem_Ch12 is
-- The parent was a premature instantiation. Insert freeze node at
-- the end the current declarative part.
- if ABE_Is_Certain (Get_Unit_Instantiation_Node (Par)) then
+ if Is_Known_Guaranteed_ABE (Get_Unit_Instantiation_Node (Par)) then
Insert_Freeze_Node_For_Instance (Inst_Node, F_Node);
-- Handle the following case:
@@ -13931,6 +14049,102 @@ package body Sem_Ch12 is
end if;
end Preanalyze_Actuals;
+ -------------------------------
+ -- Provide_Completing_Bodies --
+ -------------------------------
+
+ procedure Provide_Completing_Bodies (N : Node_Id) is
+ procedure Build_Completing_Body (Subp_Decl : Node_Id);
+ -- Generate the completing body for subprogram declaration Subp_Decl
+
+ procedure Provide_Completing_Bodies_In (Decls : List_Id);
+ -- Generating completing bodies for all subprograms found in declarative
+ -- list Decls.
+
+ ---------------------------
+ -- Build_Completing_Body --
+ ---------------------------
+
+ procedure Build_Completing_Body (Subp_Decl : Node_Id) is
+ Loc : constant Source_Ptr := Sloc (Subp_Decl);
+ Subp_Id : constant Entity_Id := Defining_Entity (Subp_Decl);
+ Spec : Node_Id;
+
+ begin
+ -- Nothing to do if the subprogram already has a completing body
+
+ if Present (Corresponding_Body (Subp_Decl)) then
+ return;
+
+ -- Mark the function as having a valid return statement even though
+ -- the body contains a single raise statement.
+
+ elsif Ekind (Subp_Id) = E_Function then
+ Set_Return_Present (Subp_Id);
+ end if;
+
+ -- Clone the specification to obtain new entities and reset the only
+ -- semantic field.
+
+ Spec := Copy_Subprogram_Spec (Specification (Subp_Decl));
+ Set_Generic_Parent (Spec, Empty);
+
+ -- Generate:
+ -- function Func ... return ... is
+ -- <or>
+ -- procedure Proc ... is
+ -- begin
+ -- raise Program_Error with "access before elaboration";
+ -- edn Proc;
+
+ Insert_After_And_Analyze (Subp_Decl,
+ Make_Subprogram_Body (Loc,
+ Specification => Spec,
+ Declarations => New_List,
+ Handled_Statement_Sequence =>
+ Make_Handled_Sequence_Of_Statements (Loc,
+ Statements => New_List (
+ Make_Raise_Program_Error (Loc,
+ Reason => PE_Access_Before_Elaboration)))));
+ end Build_Completing_Body;
+
+ ----------------------------------
+ -- Provide_Completing_Bodies_In --
+ ----------------------------------
+
+ procedure Provide_Completing_Bodies_In (Decls : List_Id) is
+ Decl : Node_Id;
+
+ begin
+ if Present (Decls) then
+ Decl := First (Decls);
+ while Present (Decl) loop
+ Provide_Completing_Bodies (Decl);
+ Next (Decl);
+ end loop;
+ end if;
+ end Provide_Completing_Bodies_In;
+
+ -- Local variables
+
+ Spec : Node_Id;
+
+ -- Start of processing for Provide_Completing_Bodies
+
+ begin
+ if Nkind (N) = N_Package_Declaration then
+ Spec := Specification (N);
+
+ Push_Scope (Defining_Entity (N));
+ Provide_Completing_Bodies_In (Visible_Declarations (Spec));
+ Provide_Completing_Bodies_In (Private_Declarations (Spec));
+ Pop_Scope;
+
+ elsif Nkind (N) = N_Subprogram_Declaration then
+ Build_Completing_Body (N);
+ end if;
+ end Provide_Completing_Bodies;
+
-------------------
-- Remove_Parent --
-------------------
@@ -15132,7 +15346,9 @@ package body Sem_Ch12 is
Nam := Make_Identifier (Loc, Chars (Typ));
if Is_Immediately_Visible (Scope (Typ))
- and then Current_Entity (Scope (Typ)) = Scope (Typ)
+ and then
+ (not In_Open_Scopes (Scope (Typ))
+ or else Current_Entity (Scope (Typ)) = Scope (Typ))
then
Nam :=
Make_Selected_Component (Loc,
diff --git a/gcc/ada/sem_ch13.adb b/gcc/ada/sem_ch13.adb
index 7a5c85d..564ff0d 100644
--- a/gcc/ada/sem_ch13.adb
+++ b/gcc/ada/sem_ch13.adb
@@ -2264,13 +2264,29 @@ package body Sem_Ch13 is
end if;
end if;
- -- Construct the attribute definition clause
-
- Aitem :=
- Make_Attribute_Definition_Clause (Loc,
- Name => Ent,
- Chars => Chars (Id),
- Expression => Relocate_Node (Expr));
+ -- Construct the attribute_definition_clause. The expression
+ -- in the aspect specification is simply shared with the
+ -- constructed attribute, because it will be fully analyzed
+ -- when the attribute is processed. However, in ASIS mode
+ -- the aspect expression itself is preanalyzed and resolved
+ -- to catch visibility errors that are otherwise caught
+ -- later, and we create a separate copy of the expression
+ -- to prevent analysis of a malformed tree (e.g. a function
+ -- call with parameter associations).
+
+ if ASIS_Mode then
+ Aitem :=
+ Make_Attribute_Definition_Clause (Loc,
+ Name => Ent,
+ Chars => Chars (Id),
+ Expression => New_Copy_Tree (Expr));
+ else
+ Aitem :=
+ Make_Attribute_Definition_Clause (Loc,
+ Name => Ent,
+ Chars => Chars (Id),
+ Expression => Relocate_Node (Expr));
+ end if;
-- If the address is specified, then we treat the entity as
-- referenced, to avoid spurious warnings. This is analogous
@@ -4399,15 +4415,6 @@ package body Sem_Ch13 is
if Present (Default_Element) then
Analyze (Default_Element);
-
- if Is_Entity_Name (Default_Element)
- and then not Covers (Entity (Default_Element), Ret_Type)
- and then False
- then
- Illegal_Indexing
- ("wrong return type for indexing function");
- return;
- end if;
end if;
-- For variable_indexing the return type must be a reference type
@@ -5094,8 +5101,8 @@ package body Sem_Ch13 is
or else Is_Array_Type (Etype (U_Ent)))
and then (Is_Record_Type (Etype (O_Ent))
or else Is_Array_Type (Etype (O_Ent)))
- and then Reverse_Storage_Order (Etype (U_Ent))
- /= Reverse_Storage_Order (Etype (O_Ent))
+ and then Reverse_Storage_Order (Etype (U_Ent)) /=
+ Reverse_Storage_Order (Etype (O_Ent))
then
Set_Treat_As_Volatile (U_Ent);
end if;
@@ -12654,10 +12661,18 @@ package body Sem_Ch13 is
return Skip;
- -- Otherwise do the replacement and we are done with this node
+ -- Otherwise do the replacement if this is not a qualified
+ -- reference to a homograph of the type itself. Note that the
+ -- current instance could not appear in such a context, e.g.
+ -- the prefix of a type conversion.
else
- Replace_Type_Reference (N);
+ if Nkind (Parent (N)) /= N_Selected_Component
+ or else N /= Selector_Name (Parent (N))
+ then
+ Replace_Type_Reference (N);
+ end if;
+
return Skip;
end if;
@@ -12666,7 +12681,7 @@ package body Sem_Ch13 is
elsif Nkind (N) = N_Selected_Component then
- -- If selector name is not our type, keeping going (we might still
+ -- If selector name is not our type, keep going (we might still
-- have an occurrence of the type in the prefix).
if Nkind (Selector_Name (N)) /= N_Identifier
@@ -12797,7 +12812,14 @@ package body Sem_Ch13 is
return Skip;
- elsif Nkind (N) = N_Identifier and then Chars (N) /= Chars (E) then
+ -- Resolve identifiers that are not selectors in parameter
+ -- associations (these are never resolved by visibility).
+
+ elsif Nkind (N) = N_Identifier
+ and then Chars (N) /= Chars (E)
+ and then (Nkind (Parent (N)) /= N_Parameter_Association
+ or else N /= Selector_Name (Parent (N)))
+ then
Find_Direct_Name (N);
-- In ASIS mode we must analyze overloaded identifiers to ensure
@@ -12905,6 +12927,14 @@ package body Sem_Ch13 is
Set_Must_Not_Freeze (Expr);
Preanalyze_Spec_Expression (Expr, E);
+ -- Ditto for Storage_Size. Any other aspects that carry
+ -- expressions that should not freeze ??? This is only
+ -- relevant to the misuse of deferred constants.
+
+ when Aspect_Storage_Size =>
+ Set_Must_Not_Freeze (Expr);
+ Preanalyze_Spec_Expression (Expr, Any_Integer);
+
when others =>
if Present (Expr) then
case Aspect_Argument (A_Id) is
@@ -13163,16 +13193,18 @@ package body Sem_Ch13 is
or else No (First_Formal (Entity (N)))
or else Etype (First_Formal (Entity (N))) /= Typ
then
- Error_Msg_N ("iterable primitive must be local function name "
- & "whose first formal is an iterable type", N);
+ Error_Msg_N
+ ("iterable primitive must be local function name whose first "
+ & "formal is an iterable type", N);
return;
end if;
Ent := Entity (N);
- F1 := First_Formal (Ent);
- if Nam = Name_First then
+ F1 := First_Formal (Ent);
- -- First (Container) => Cursor
+ if Nam = Name_First or else Nam = Name_Last then
+
+ -- First or Last (Container) => Cursor
if Etype (Ent) /= Cursor then
Error_Msg_N ("primitive for First must yield a curosr", N);
@@ -13191,11 +13223,25 @@ package body Sem_Ch13 is
Error_Msg_N ("no match for Next iterable primitive", N);
end if;
+ elsif Nam = Name_Previous then
+
+ -- Previous (Container, Cursor) => Cursor
+
+ F2 := Next_Formal (F1);
+
+ if Etype (F2) /= Cursor
+ or else Etype (Ent) /= Cursor
+ or else Present (Next_Formal (F2))
+ then
+ Error_Msg_N ("no match for Previous iterable primitive", N);
+ end if;
+
elsif Nam = Name_Has_Element then
-- Has_Element (Container, Cursor) => Boolean
F2 := Next_Formal (F1);
+
if Etype (F2) /= Cursor
or else Etype (Ent) /= Standard_Boolean
or else Present (Next_Formal (F2))
@@ -13212,15 +13258,14 @@ package body Sem_Ch13 is
then
Error_Msg_N ("no match for Element iterable primitive", N);
end if;
- null;
else
raise Program_Error;
end if;
else
- -- Overloaded case: find subprogram with proper signature.
- -- Caller will report error if no match is found.
+ -- Overloaded case: find subprogram with proper signature. Caller
+ -- will report error if no match is found.
declare
I : Interp_Index;
@@ -13992,6 +14037,7 @@ package body Sem_Ch13 is
Cursor : constant Entity_Id := Get_Cursor_Type (ASN, Typ);
First_Id : Entity_Id;
+ Last_Id : Entity_Id;
Next_Id : Entity_Id;
Has_Element_Id : Entity_Id;
Element_Id : Entity_Id;
@@ -14004,6 +14050,7 @@ package body Sem_Ch13 is
end if;
First_Id := Empty;
+ Last_Id := Empty;
Next_Id := Empty;
Has_Element_Id := Empty;
Element_Id := Empty;
@@ -14024,6 +14071,14 @@ package body Sem_Ch13 is
Resolve_Iterable_Operation (Expr, Cursor, Typ, Name_First);
First_Id := Entity (Expr);
+ elsif Chars (Prim) = Name_Last then
+ Resolve_Iterable_Operation (Expr, Cursor, Typ, Name_Last);
+ Last_Id := Entity (Expr);
+
+ elsif Chars (Prim) = Name_Previous then
+ Resolve_Iterable_Operation (Expr, Cursor, Typ, Name_Previous);
+ Last_Id := Entity (Expr);
+
elsif Chars (Prim) = Name_Next then
Resolve_Iterable_Operation (Expr, Cursor, Typ, Name_Next);
Next_Id := Entity (Expr);
@@ -14052,8 +14107,8 @@ package body Sem_Ch13 is
elsif No (Has_Element_Id) then
Error_Msg_N ("match for Has_Element primitive not found", ASN);
- elsif No (Element_Id) then
- null; -- Optional.
+ elsif No (Element_Id) or else No (Last_Id) then
+ null; -- optional
end if;
end Validate_Iterable_Aspect;
diff --git a/gcc/ada/sem_ch3.adb b/gcc/ada/sem_ch3.adb
index 2d9caca..1e3b78c 100644
--- a/gcc/ada/sem_ch3.adb
+++ b/gcc/ada/sem_ch3.adb
@@ -2211,6 +2211,12 @@ package body Sem_Ch3 is
-- contract expression. Full analysis of the expression is done when
-- the contract is processed.
+ function Contains_Lib_Incomplete_Type (Pkg : Entity_Id) return Boolean;
+ -- Check if a nested package has entities within it that rely on library
+ -- level private types where the full view has not been completed for
+ -- the purposes of checking if it is acceptable to freeze an expression
+ -- function at the point of declaration.
+
procedure Handle_Late_Controlled_Primitive (Body_Decl : Node_Id);
-- Determine whether Body_Decl denotes the body of a late controlled
-- primitive (either Initialize, Adjust or Finalize). If this is the
@@ -2231,11 +2237,8 @@ package body Sem_Ch3 is
procedure Resolve_Aspects;
-- Utility to resolve the expressions of aspects at the end of a list of
- -- declarations.
-
- function Uses_Unseen_Lib_Unit_Priv (Pkg : Entity_Id) return Boolean;
- -- Check if an inner package has entities within it that rely on library
- -- level private types where the full view has not been seen.
+ -- declarations, or before a declaration that freezes previous entities,
+ -- such as in a subprogram body.
-----------------
-- Adjust_Decl --
@@ -2397,6 +2400,40 @@ package body Sem_Ch3 is
end loop;
end Check_Entry_Contracts;
+ ----------------------------------
+ -- Contains_Lib_Incomplete_Type --
+ ----------------------------------
+
+ function Contains_Lib_Incomplete_Type (Pkg : Entity_Id) return Boolean is
+ Curr : Entity_Id;
+
+ begin
+ -- Avoid looking through scopes that do not meet the precondition of
+ -- Pkg not being within a library unit spec.
+
+ if not Is_Compilation_Unit (Pkg)
+ and then not Is_Generic_Instance (Pkg)
+ and then not In_Package_Body (Enclosing_Lib_Unit_Entity (Pkg))
+ then
+ -- Loop through all entities in the current scope to identify
+ -- an entity that depends on a private type.
+
+ Curr := First_Entity (Pkg);
+ loop
+ if Nkind (Curr) in N_Entity
+ and then Depends_On_Private (Curr)
+ then
+ return True;
+ end if;
+
+ exit when Last_Entity (Current_Scope) = Curr;
+ Curr := Next_Entity (Curr);
+ end loop;
+ end if;
+
+ return False;
+ end Contains_Lib_Incomplete_Type;
+
--------------------------------------
-- Handle_Late_Controlled_Primitive --
--------------------------------------
@@ -2540,40 +2577,6 @@ package body Sem_Ch3 is
end loop;
end Resolve_Aspects;
- -------------------------------
- -- Uses_Unseen_Lib_Unit_Priv --
- -------------------------------
-
- function Uses_Unseen_Lib_Unit_Priv (Pkg : Entity_Id) return Boolean is
- Curr : Entity_Id;
-
- begin
- -- Avoid looking through scopes that do not meet the precondition of
- -- Pkg not being within a library unit spec.
-
- if not Is_Compilation_Unit (Pkg)
- and then not Is_Generic_Instance (Pkg)
- and then not In_Package_Body (Enclosing_Lib_Unit_Entity (Pkg))
- then
- -- Loop through all entities in the current scope to identify
- -- an entity that depends on a private type.
-
- Curr := First_Entity (Pkg);
- loop
- if Nkind (Curr) in N_Entity
- and then Depends_On_Private (Curr)
- then
- return True;
- end if;
-
- exit when Last_Entity (Current_Scope) = Curr;
- Curr := Next_Entity (Curr);
- end loop;
- end if;
-
- return False;
- end Uses_Unseen_Lib_Unit_Priv;
-
-- Local variables
Context : Node_Id := Empty;
@@ -2747,14 +2750,16 @@ package body Sem_Ch3 is
-- not cause unwanted freezing at that point.
-- It is also necessary to check for a case where both an expression
- -- function is used and the current scope depends on an unseen
+ -- function is used and the current scope depends on an incomplete
-- private type from a library unit, otherwise premature freezing of
-- the private type will occur.
elsif not Analyzed (Next_Decl) and then Is_Body (Next_Decl)
and then ((Nkind (Next_Decl) /= N_Subprogram_Body
- or else not Was_Expression_Function (Next_Decl))
- or else not Uses_Unseen_Lib_Unit_Priv (Current_Scope))
+ or else not Was_Expression_Function (Next_Decl))
+ or else (not Is_Ignored_Ghost_Entity (Current_Scope)
+ and then not Contains_Lib_Incomplete_Type
+ (Current_Scope)))
then
-- When a controlled type is frozen, the expander generates stream
-- and controlled-type support routines. If the freeze is caused
@@ -2786,6 +2791,12 @@ package body Sem_Ch3 is
if Nkind (Next_Decl) = N_Subprogram_Body then
Handle_Late_Controlled_Primitive (Next_Decl);
end if;
+
+ else
+ -- In ASIS mode, if the next declaration is a body, complete
+ -- the analysis of declarations so far.
+
+ Resolve_Aspects;
end if;
Adjust_Decl;
@@ -2809,24 +2820,10 @@ package body Sem_Ch3 is
-- Analyze the contracts of packages and their bodies
- if Nkind (Context) = N_Package_Specification then
-
- -- When a package has private declarations, its contract must be
- -- analyzed at the end of the said declarations. This way both the
- -- analysis and freeze actions are properly synchronized in case
- -- of private type use within the contract.
-
- if L = Private_Declarations (Context) then
- Analyze_Package_Contract (Defining_Entity (Context));
-
- -- Otherwise the contract is analyzed at the end of the visible
- -- declarations.
-
- elsif L = Visible_Declarations (Context)
- and then No (Private_Declarations (Context))
- then
- Analyze_Package_Contract (Defining_Entity (Context));
- end if;
+ if Nkind (Context) = N_Package_Specification
+ and then L = Visible_Declarations (Context)
+ then
+ Analyze_Package_Contract (Defining_Entity (Context));
elsif Nkind (Context) = N_Package_Body then
Analyze_Package_Body_Contract (Defining_Entity (Context));
@@ -4709,6 +4706,20 @@ package body Sem_Ch3 is
end if;
end if;
+ -- Set the SPARK mode from the current context (may be overwritten later
+ -- with explicit pragma).
+
+ Set_SPARK_Pragma (Id, SPARK_Mode_Pragma);
+ Set_SPARK_Pragma_Inherited (Id);
+
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => Id,
+ Checks => True);
+
-- Initialize alignment and size and capture alignment setting
Init_Alignment (Id);
@@ -10230,10 +10241,11 @@ package body Sem_Ch3 is
Set_Is_Limited_Record (Def_Id, Is_Limited_Record (T));
if Has_Discrs
- and then not Is_Empty_Elmt_List (Elist)
- and then not For_Access
+ and then not Is_Empty_Elmt_List (Elist)
+ and then not For_Access
then
Create_Constrained_Components (Def_Id, Related_Nod, T, Elist);
+
elsif not For_Access then
Set_Cloned_Subtype (Def_Id, T);
end if;
@@ -10257,7 +10269,21 @@ package body Sem_Ch3 is
return;
else
Set_Itype (IR, Ityp);
- Insert_After (Nod, IR);
+
+ -- If Nod is a library unit entity, then Insert_After won't work,
+ -- because Nod is not a member of any list. Therefore, we use
+ -- Add_Global_Declaration in this case. This can happen if we have a
+ -- build-in-place library function.
+
+ if (Nkind (Nod) in N_Entity and then Is_Compilation_Unit (Nod))
+ or else
+ (Nkind (Nod) = N_Defining_Program_Unit_Name
+ and then Is_Compilation_Unit (Defining_Identifier (Nod)))
+ then
+ Add_Global_Declaration (IR);
+ else
+ Insert_After (Nod, IR);
+ end if;
end if;
end Build_Itype_Reference;
@@ -11777,14 +11803,25 @@ package body Sem_Ch3 is
if Nkind (Exp) = N_Type_Conversion
and then Nkind (Expression (Exp)) = N_Function_Call
then
- Error_Msg_N
- ("illegal context for call"
- & " to function with limited result", Exp);
+ -- No error for internally-generated object declarations,
+ -- which can come from build-in-place assignment statements.
+
+ if Nkind (Parent (Exp)) = N_Object_Declaration
+ and then not Comes_From_Source
+ (Defining_Identifier (Parent (Exp)))
+ then
+ null;
+
+ else
+ Error_Msg_N
+ ("illegal context for call to function with limited "
+ & "result", Exp);
+ end if;
else
Error_Msg_N
- ("initialization of limited object requires aggregate "
- & "or function call", Exp);
+ ("initialization of limited object requires aggregate or "
+ & "function call", Exp);
end if;
end if;
end if;
@@ -12755,9 +12792,13 @@ package body Sem_Ch3 is
end if;
-- A deferred constant is a visible entity. If type has invariants,
- -- verify that the initial value satisfies them.
+ -- verify that the initial value satisfies them. This is not done in
+ -- GNATprove mode, as GNATprove handles invariant checks itself.
- if Has_Invariants (T) and then Present (Invariant_Procedure (T)) then
+ if Has_Invariants (T)
+ and then Present (Invariant_Procedure (T))
+ and then not GNATprove_Mode
+ then
Insert_After (N,
Make_Invariant_Call (New_Occurrence_Of (Prev, Sloc (N))));
end if;
@@ -21928,6 +21969,17 @@ package body Sem_Ch3 is
Next_Discriminant (Comp);
end loop;
+ elsif Nkind (N) = N_Variant_Part then
+ Comp := First_Discriminant (Typ);
+ while Present (Comp) loop
+ if Chars (Comp) = Chars (Name (N)) then
+ Set_Entity (Name (N), Comp);
+ exit;
+ end if;
+
+ Next_Discriminant (Comp);
+ end loop;
+
elsif Nkind (N) = N_Component_Declaration then
Comp := First_Component (Typ);
while Present (Comp) loop
diff --git a/gcc/ada/sem_ch4.adb b/gcc/ada/sem_ch4.adb
index 555217c..5380235 100644
--- a/gcc/ada/sem_ch4.adb
+++ b/gcc/ada/sem_ch4.adb
@@ -3931,16 +3931,14 @@ package body Sem_Ch4 is
Find_Type (Mark);
T := Entity (Mark);
- if Nkind_In
- (Enclosing_Declaration (N),
- N_Formal_Type_Declaration,
- N_Full_Type_Declaration,
- N_Incomplete_Type_Declaration,
- N_Protected_Type_Declaration,
- N_Private_Extension_Declaration,
- N_Private_Type_Declaration,
- N_Subtype_Declaration,
- N_Task_Type_Declaration)
+ if Nkind_In (Enclosing_Declaration (N), N_Formal_Type_Declaration,
+ N_Full_Type_Declaration,
+ N_Incomplete_Type_Declaration,
+ N_Protected_Type_Declaration,
+ N_Private_Extension_Declaration,
+ N_Private_Type_Declaration,
+ N_Subtype_Declaration,
+ N_Task_Type_Declaration)
and then T = Defining_Identifier (Enclosing_Declaration (N))
then
Error_Msg_N ("current instance not allowed", Mark);
@@ -6433,10 +6431,24 @@ package body Sem_Ch4 is
Op_Id : Entity_Id;
N : Node_Id)
is
- Op_Type : constant Entity_Id := Etype (Op_Id);
+ Is_String : constant Boolean := Nkind (L) = N_String_Literal
+ or else
+ Nkind (R) = N_String_Literal;
+ Op_Type : constant Entity_Id := Etype (Op_Id);
begin
if Is_Array_Type (Op_Type)
+
+ -- Small but very effective optimization: if at least one operand is a
+ -- string literal, then the type of the operator must be either array
+ -- of characters or array of strings.
+
+ and then (not Is_String
+ or else
+ Is_Character_Type (Component_Type (Op_Type))
+ or else
+ Is_String_Type (Component_Type (Op_Type)))
+
and then not Is_Limited_Type (Op_Type)
and then (Has_Compatible_Type (L, Op_Type)
@@ -6479,9 +6491,17 @@ package body Sem_Ch4 is
--------------------
procedure Try_One_Interp (T1 : Entity_Id) is
- Bas : constant Entity_Id := Base_Type (T1);
+ Bas : Entity_Id;
begin
+ -- Perform a sanity check in case of previous errors
+
+ if No (T1) then
+ return;
+ end if;
+
+ Bas := Base_Type (T1);
+
-- If the operator is an expanded name, then the type of the operand
-- must be defined in the corresponding scope. If the type is
-- universal, the context will impose the correct type. An anonymous
@@ -8562,11 +8582,11 @@ package body Sem_Ch4 is
elsif Is_Access_Type (Formal_Type)
and then not Is_Access_Type (Etype (Obj))
- and then (not Has_Implicit_Dereference (Etype (Obj))
- or else
- not Is_Access_Type
- (Designated_Type
- (Etype (Get_Reference_Discriminant (Etype (Obj))))))
+ and then
+ (not Has_Implicit_Dereference (Etype (Obj))
+ or else
+ not Is_Access_Type (Designated_Type (Etype
+ (Get_Reference_Discriminant (Etype (Obj))))))
then
-- A special case: A.all'Access is illegal if A is an access to a
-- constant and the context requires an access to a variable.
@@ -8854,7 +8874,7 @@ package body Sem_Ch4 is
while Present (Hom) loop
if Ekind_In (Hom, E_Procedure, E_Function)
and then (not Is_Hidden (Hom) or else In_Instance)
- and then Scope (Hom) = Scope (Anc_Type)
+ and then Scope (Hom) = Scope (Base_Type (Anc_Type))
and then Present (First_Formal (Hom))
and then
(Base_Type (Etype (First_Formal (Hom))) = Cls_Type
@@ -8915,8 +8935,13 @@ package body Sem_Ch4 is
Success => Success,
Skip_First => True);
+ -- The same operation may be encountered on two homonym
+ -- traversals, before and after looking at interfaces.
+ -- Check for this case before reporting a real ambiguity.
+
if Present (Valid_Candidate (Success, Call_Node, Hom))
and then Nkind (Call_Node) /= N_Function_Call
+ and then Hom /= Matching_Op
then
Error_Msg_NE ("ambiguous call to&", N, Hom);
Report_Ambiguity (Matching_Op);
diff --git a/gcc/ada/sem_ch5.adb b/gcc/ada/sem_ch5.adb
index e72dc4b..10002ea 100644
--- a/gcc/ada/sem_ch5.adb
+++ b/gcc/ada/sem_ch5.adb
@@ -101,13 +101,7 @@ package body Sem_Ch5 is
procedure Analyze_Assignment (N : Node_Id) is
Lhs : constant Node_Id := Name (N);
- Rhs : constant Node_Id := Expression (N);
-
- Decl : Node_Id;
- T1 : Entity_Id;
- T2 : Entity_Id;
-
- Save_Full_Analysis : Boolean := False; -- initialize to prevent warning
+ Rhs : Node_Id := Expression (N);
procedure Diagnose_Non_Variable_Lhs (N : Node_Id);
-- N is the node for the left hand side of an assignment, and it is not
@@ -126,6 +120,27 @@ package body Sem_Ch5 is
-- nominal subtype. This procedure is used to deal with cases where the
-- nominal subtype must be replaced by the actual subtype.
+ procedure Transform_BIP_Assignment (Typ : Entity_Id);
+ function Should_Transform_BIP_Assignment
+ (Typ : Entity_Id) return Boolean;
+ -- If the right-hand side of an assignment statement is a build-in-place
+ -- call we cannot build in place, so we insert a temp initialized with
+ -- the call, and transform the assignment statement to copy the temp.
+ -- Transform_BIP_Assignment does the tranformation, and
+ -- Should_Transform_BIP_Assignment determines whether we should.
+ -- The same goes for qualified expressions and conversions whose
+ -- operand is such a call.
+ --
+ -- This is only for nonlimited types; assignment statements are illegal
+ -- for limited types, but are generated internally for aggregates and
+ -- init procs. These limited-type are not really assignment statements
+ -- -- conceptually, they are initializations, so should not be
+ -- transformed.
+ --
+ -- Similarly, for nonlimited types, aggregates and init procs generate
+ -- assignment statements that are really initializations. These are
+ -- marked No_Ctrl_Actions.
+
-------------------------------
-- Diagnose_Non_Variable_Lhs --
-------------------------------
@@ -232,6 +247,8 @@ package body Sem_Ch5 is
(Opnd : Node_Id;
Opnd_Type : in out Entity_Id)
is
+ Decl : Node_Id;
+
begin
Require_Entity (Opnd);
@@ -249,9 +266,9 @@ package body Sem_Ch5 is
or else
(Ekind (Entity (Opnd)) = E_Variable
and then Nkind (Parent (Entity (Opnd))) =
- N_Object_Renaming_Declaration
+ N_Object_Renaming_Declaration
and then Nkind (Parent (Parent (Entity (Opnd)))) =
- N_Accept_Statement))
+ N_Accept_Statement))
then
Opnd_Type := Get_Actual_Subtype (Opnd);
@@ -282,8 +299,100 @@ package body Sem_Ch5 is
end if;
end Set_Assignment_Type;
+ -------------------------------------
+ -- Should_Transform_BIP_Assignment --
+ -------------------------------------
+
+ function Should_Transform_BIP_Assignment
+ (Typ : Entity_Id) return Boolean
+ is
+ Result : Boolean;
+
+ begin
+ if Expander_Active
+ and then not Is_Limited_View (Typ)
+ and then Is_Build_In_Place_Result_Type (Typ)
+ and then not No_Ctrl_Actions (N)
+ then
+ -- This function is called early, before name resolution is
+ -- complete, so we have to deal with things that might turn into
+ -- function calls later. N_Function_Call and N_Op nodes are the
+ -- obvious case. An N_Identifier or N_Expanded_Name is a
+ -- parameterless function call if it denotes a function.
+ -- Finally, an attribute reference can be a function call.
+
+ case Nkind (Unqual_Conv (Rhs)) is
+ when N_Function_Call
+ | N_Op
+ =>
+ Result := True;
+
+ when N_Expanded_Name
+ | N_Identifier
+ =>
+ case Ekind (Entity (Unqual_Conv (Rhs))) is
+ when E_Function
+ | E_Operator
+ =>
+ Result := True;
+
+ when others =>
+ Result := False;
+ end case;
+
+ when N_Attribute_Reference =>
+ Result := Attribute_Name (Unqual_Conv (Rhs)) = Name_Input;
+ -- T'Input will turn into a call whose result type is T
+
+ when others =>
+ Result := False;
+ end case;
+ else
+ Result := False;
+ end if;
+
+ return Result;
+ end Should_Transform_BIP_Assignment;
+
+ ------------------------------
+ -- Transform_BIP_Assignment --
+ ------------------------------
+
+ procedure Transform_BIP_Assignment (Typ : Entity_Id) is
+
+ -- Tranform "X : [constant] T := F (...);" into:
+ --
+ -- Temp : constant T := F (...);
+ -- X := Temp;
+
+ Loc : constant Source_Ptr := Sloc (N);
+ Def_Id : constant Entity_Id := Make_Temporary (Loc, 'Y', Rhs);
+ Obj_Decl : constant Node_Id :=
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Def_Id,
+ Constant_Present => True,
+ Object_Definition => New_Occurrence_Of (Typ, Loc),
+ Expression => Rhs,
+ Has_Init_Expression => True);
+
+ begin
+ Set_Etype (Def_Id, Typ);
+ Set_Expression (N, New_Occurrence_Of (Def_Id, Loc));
+
+ -- At this point, Rhs is no longer equal to Expression (N), so:
+
+ Rhs := Expression (N);
+
+ Insert_Action (N, Obj_Decl);
+ end Transform_BIP_Assignment;
+
-- Local variables
+ T1 : Entity_Id;
+ T2 : Entity_Id;
+
+ Save_Full_Analysis : Boolean;
+
Saved_GM : constant Ghost_Mode_Type := Ghost_Mode;
-- Save the Ghost mode to restore on exit
@@ -292,6 +401,15 @@ package body Sem_Ch5 is
begin
Mark_Coextensions (N, Rhs);
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => N,
+ Checks => True,
+ Modes => True);
+
-- Analyze the target of the assignment first in case the expression
-- contains references to Ghost entities. The checks that verify the
-- proper use of a Ghost entity need to know the enclosing context.
@@ -360,8 +478,9 @@ package body Sem_Ch5 is
null;
elsif Has_Compatible_Type (Rhs, It.Typ) then
- if T1 /= Any_Type then
-
+ if T1 = Any_Type then
+ T1 := It.Typ;
+ else
-- An explicit dereference is overloaded if the prefix
-- is. Try to remove the ambiguity on the prefix, the
-- error will be posted there if the ambiguity is real.
@@ -412,8 +531,6 @@ package body Sem_Ch5 is
("ambiguous left-hand side in assignment", Lhs);
exit;
end if;
- else
- T1 := It.Typ;
end if;
end if;
@@ -429,13 +546,21 @@ package body Sem_Ch5 is
end if;
end if;
+ -- Deal with build-in-place calls for nonlimited types. We don't do this
+ -- later, because resolving the rhs tranforms it incorrectly for build-
+ -- in-place.
+
+ if Should_Transform_BIP_Assignment (Typ => T1) then
+ Transform_BIP_Assignment (Typ => T1);
+ end if;
+
+ pragma Assert (not Should_Transform_BIP_Assignment (Typ => T1));
+
-- The resulting assignment type is T1, so now we will resolve the left
-- hand side of the assignment using this determined type.
Resolve (Lhs, T1);
- -- Cases where Lhs is not a variable
-
-- Cases where Lhs is not a variable. In an instance or an inlined body
-- no need for further check because assignment was legal in template.
@@ -822,11 +947,9 @@ package body Sem_Ch5 is
Error_Msg_CRT ("composite assignment", N);
end if;
- -- Check elaboration warning for left side if not in elab code
+ -- Save the scenario for later examination by the ABE Processing phase
- if not In_Subprogram_Or_Concurrent_Unit then
- Check_Elab_Assign (Lhs);
- end if;
+ Record_Elaboration_Scenario (N);
-- Set Referenced_As_LHS if appropriate. We only set this flag if the
-- assignment is a source assignment in the extended main source unit.
@@ -839,14 +962,16 @@ package body Sem_Ch5 is
Set_Referenced_Modified (Lhs, Out_Param => False);
end if;
- -- RM 7.3.2 (12/3): An assignment to a view conversion (from a type
- -- to one of its ancestors) requires an invariant check. Apply check
- -- only if expression comes from source, otherwise it will be applied
- -- when value is assigned to source entity.
+ -- RM 7.3.2 (12/3): An assignment to a view conversion (from a type to
+ -- one of its ancestors) requires an invariant check. Apply check only
+ -- if expression comes from source, otherwise it will be applied when
+ -- value is assigned to source entity. This is not done in GNATprove
+ -- mode, as GNATprove handles invariant checks itself.
if Nkind (Lhs) = N_Type_Conversion
and then Has_Invariants (Etype (Expression (Lhs)))
and then Comes_From_Source (Expression (Lhs))
+ and then not GNATprove_Mode
then
Insert_After (N, Make_Invariant_Call (Expression (Lhs)));
end if;
@@ -965,9 +1090,13 @@ package body Sem_Ch5 is
-- the context of the assignment statement. Restore the expander mode
-- now so that assignment statement can be properly expanded.
- if Nkind (N) = N_Assignment_Statement and then Has_Target_Names (N) then
- Expander_Mode_Restore;
- Full_Analysis := Save_Full_Analysis;
+ if Nkind (N) = N_Assignment_Statement then
+ if Has_Target_Names (N) then
+ Expander_Mode_Restore;
+ Full_Analysis := Save_Full_Analysis;
+ end if;
+
+ pragma Assert (not Should_Transform_BIP_Assignment (Typ => T1));
end if;
end Analyze_Assignment;
@@ -1130,6 +1259,7 @@ package body Sem_Ch5 is
end if;
Check_References (Ent);
+ Update_Use_Clause_Chain;
End_Scope;
if Unblocked_Exit_Count = 0 then
@@ -1830,12 +1960,20 @@ package body Sem_Ch5 is
procedure Check_Reverse_Iteration (Typ : Entity_Id) is
begin
- if Reverse_Present (N)
- and then not Is_Array_Type (Typ)
- and then not Is_Reversible_Iterator (Typ)
- then
- Error_Msg_NE
- ("container type does not support reverse iteration", N, Typ);
+ if Reverse_Present (N) then
+ if Is_Array_Type (Typ)
+ or else Is_Reversible_Iterator (Typ)
+ or else
+ (Present (Find_Aspect (Typ, Aspect_Iterable))
+ and then
+ Present
+ (Get_Iterable_Type_Primitive (Typ, Name_Previous)))
+ then
+ null;
+ else
+ Error_Msg_NE
+ ("container type does not support reverse iteration", N, Typ);
+ end if;
end if;
end Check_Reverse_Iteration;
@@ -1944,13 +2082,13 @@ package body Sem_Ch5 is
begin
if No (Iterator) then
- null; -- error reported below.
+ null; -- error reported below
elsif not Is_Overloaded (Iterator) then
Check_Reverse_Iteration (Etype (Iterator));
- -- If Iterator is overloaded, use reversible iterator if
- -- one is available.
+ -- If Iterator is overloaded, use reversible iterator if one is
+ -- available.
elsif Is_Overloaded (Iterator) then
Get_First_Interp (Iterator, I, It);
@@ -2196,6 +2334,7 @@ package body Sem_Ch5 is
("missing Element primitive for iteration", N);
else
Set_Etype (Def_Id, Etype (Elt));
+ Check_Reverse_Iteration (Typ);
end if;
end;
@@ -3509,8 +3648,7 @@ package body Sem_Ch5 is
end if;
else
-
- -- Pre-Ada2012 for-loops and while loops.
+ -- Pre-Ada2012 for-loops and while loops
Analyze_Statements (Statements (N));
end if;
diff --git a/gcc/ada/sem_ch6.adb b/gcc/ada/sem_ch6.adb
index 468c112..4f719e9 100644
--- a/gcc/ada/sem_ch6.adb
+++ b/gcc/ada/sem_ch6.adb
@@ -226,6 +226,20 @@ package body Sem_Ch6 is
Generate_Definition (Subp_Id);
+ -- Set the SPARK mode from the current context (may be overwritten later
+ -- with explicit pragma).
+
+ Set_SPARK_Pragma (Subp_Id, SPARK_Mode_Pragma);
+ Set_SPARK_Pragma_Inherited (Subp_Id);
+
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => Subp_Id,
+ Checks => True);
+
Set_Is_Abstract_Subprogram (Subp_Id);
New_Overloaded_Entity (Subp_Id);
Check_Delayed_Subprogram (Subp_Id);
@@ -428,18 +442,12 @@ package body Sem_Ch6 is
begin
-- Preanalyze a duplicate of the expression to have available the
-- minimum decoration needed to locate referenced unfrozen types
- -- without adding any decoration to the function expression. This
- -- preanalysis is performed with errors disabled to avoid reporting
- -- spurious errors on Ghost entities (since the expression is not
- -- fully analyzed).
+ -- without adding any decoration to the function expression.
Push_Scope (Def_Id);
Install_Formals (Def_Id);
- Ignore_Errors_Enable := Ignore_Errors_Enable + 1;
Preanalyze_Spec_Expression (Dup_Expr, Etype (Def_Id));
-
- Ignore_Errors_Enable := Ignore_Errors_Enable - 1;
End_Scope;
-- Restore certain attributes of Def_Id since the preanalysis may
@@ -568,8 +576,11 @@ package body Sem_Ch6 is
-- Note that we cannot defer this freezing to the analysis of the
-- expression itself, because a freeze node might appear in a nested
-- scope, leading to an elaboration order issue in gigi.
+ -- As elsewhere, we do not emit freeze nodes within a generic unit.
- Freeze_Expr_Types (Def_Id);
+ if not Inside_A_Generic then
+ Freeze_Expr_Types (Def_Id);
+ end if;
-- For navigation purposes, indicate that the function is a body
@@ -1465,7 +1476,7 @@ package body Sem_Ch6 is
Set_Actual_Subtypes (N, Current_Scope);
- Set_SPARK_Pragma (Body_Id, SPARK_Mode_Pragma);
+ Set_SPARK_Pragma (Body_Id, SPARK_Mode_Pragma);
Set_SPARK_Pragma_Inherited (Body_Id);
-- Analyze any aspect specifications that appear on the generic
@@ -1498,6 +1509,7 @@ package body Sem_Ch6 is
end;
Process_End_Label (Handled_Statement_Sequence (N), 't', Current_Scope);
+ Update_Use_Clause_Chain;
End_Scope;
Check_Subprogram_Order (N);
@@ -1765,13 +1777,12 @@ package body Sem_Ch6 is
if Analyzed (N) then
return;
- end if;
-- If there is an error analyzing the name (which may have been
-- rewritten if the original call was in prefix notation) then error
-- has been emitted already, mark node and return.
- if Error_Posted (N) or else Etype (Name (N)) = Any_Type then
+ elsif Error_Posted (N) or else Etype (Name (N)) = Any_Type then
Set_Etype (N, Any_Type);
return;
end if;
@@ -1845,9 +1856,9 @@ package body Sem_Ch6 is
New_N :=
Make_Indexed_Component (Loc,
- Prefix =>
+ Prefix =>
Make_Selected_Component (Loc,
- Prefix => New_Occurrence_Of (Scope (Entity (P)), Loc),
+ Prefix => New_Occurrence_Of (Scope (Entity (P)), Loc),
Selector_Name => New_Occurrence_Of (Entity (P), Loc)),
Expressions => Actuals);
Set_Name (N, New_N);
@@ -1953,7 +1964,8 @@ package body Sem_Ch6 is
then
New_N :=
Make_Selected_Component (Loc,
- Prefix => New_Occurrence_Of (Scope (Entity (Prefix (P))), Loc),
+ Prefix =>
+ New_Occurrence_Of (Scope (Entity (Prefix (P))), Loc),
Selector_Name => New_Occurrence_Of (Entity (Prefix (P)), Loc));
Rewrite (Prefix (P), New_N);
Analyze (P);
@@ -4022,7 +4034,7 @@ package body Sem_Ch6 is
-- between the spec and body.
elsif No (SPARK_Pragma (Body_Id)) then
- Set_SPARK_Pragma (Body_Id, SPARK_Mode_Pragma);
+ Set_SPARK_Pragma (Body_Id, SPARK_Mode_Pragma);
Set_SPARK_Pragma_Inherited (Body_Id);
end if;
@@ -4357,6 +4369,7 @@ package body Sem_Ch6 is
-- Deal with end of scope processing for the body
Process_End_Label (HSS, 't', Current_Scope);
+ Update_Use_Clause_Chain;
End_Scope;
-- If we are compiling an entry wrapper, remove the enclosing
@@ -4466,12 +4479,11 @@ package body Sem_Ch6 is
Stm : Node_Id;
begin
- -- Skip initial labels (for one thing this occurs when we are in
- -- front-end ZCX mode, but in any case it is irrelevant), and also
- -- initial Push_xxx_Error_Label nodes, which are also irrelevant.
+ -- Skip call markers installed by the ABE mechanism, labels, and
+ -- Push_xxx_Error_Label to find the first real statement.
Stm := First (Statements (HSS));
- while Nkind (Stm) = N_Label
+ while Nkind_In (Stm, N_Call_Marker, N_Label)
or else Nkind (Stm) in N_Push_xxx_Label
loop
Next (Stm);
@@ -4652,8 +4664,9 @@ package body Sem_Ch6 is
and then Is_Entry_Barrier_Function (N)
then
null;
+
else
- Set_SPARK_Pragma (Designator, SPARK_Mode_Pragma);
+ Set_SPARK_Pragma (Designator, SPARK_Mode_Pragma);
Set_SPARK_Pragma_Inherited (Designator);
end if;
@@ -4666,6 +4679,14 @@ package body Sem_Ch6 is
Set_Ignore_SPARK_Mode_Pragmas (Designator);
end if;
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => Designator,
+ Checks => True);
+
if Debug_Flag_C then
Write_Str ("==> subprogram spec ");
Write_Name (Chars (Designator));
@@ -7997,7 +8018,7 @@ package body Sem_Ch6 is
-- Ada 2005 (AI-318-02): In the case of build-in-place functions, add
-- appropriate extra formals. See type Exp_Ch6.BIP_Formal_Kind.
- if Ada_Version >= Ada_2005 and then Is_Build_In_Place_Function (E) then
+ if Is_Build_In_Place_Function (E) then
declare
Result_Subt : constant Entity_Id := Etype (E);
Full_Subt : constant Entity_Id := Available_View (Result_Subt);
diff --git a/gcc/ada/sem_ch7.adb b/gcc/ada/sem_ch7.adb
index 030d4f0..dc00cf9 100644
--- a/gcc/ada/sem_ch7.adb
+++ b/gcc/ada/sem_ch7.adb
@@ -199,7 +199,7 @@ package body Sem_Ch7 is
subtype Entity_Header_Num is Integer range 0 .. Entity_Table_Size - 1;
-- Range of headers in hash table
- function Entity_Hash (Id : Entity_Id) return Entity_Header_Num;
+ function Node_Hash (Id : Entity_Id) return Entity_Header_Num;
-- Simple hash function for Entity_Ids
package Subprogram_Table is new GNAT.Htable.Simple_HTable
@@ -207,19 +207,29 @@ package body Sem_Ch7 is
Element => Boolean,
No_Element => False,
Key => Entity_Id,
- Hash => Entity_Hash,
+ Hash => Node_Hash,
Equal => "=");
-- Hash table to record which subprograms are referenced. It is declared
-- at library level to avoid elaborating it for every call to Analyze.
+ package Traversed_Table is new GNAT.Htable.Simple_HTable
+ (Header_Num => Entity_Header_Num,
+ Element => Boolean,
+ No_Element => False,
+ Key => Node_Id,
+ Hash => Node_Hash,
+ Equal => "=");
+ -- Hash table to record which nodes we have traversed, so we can avoid
+ -- traversing the same nodes repeatedly.
+
-----------------
- -- Entity_Hash --
+ -- Node_Hash --
-----------------
- function Entity_Hash (Id : Entity_Id) return Entity_Header_Num is
+ function Node_Hash (Id : Entity_Id) return Entity_Header_Num is
begin
return Entity_Header_Num (Id mod Entity_Table_Size);
- end Entity_Hash;
+ end Node_Hash;
---------------------------------
-- Analyze_Package_Body_Helper --
@@ -260,13 +270,17 @@ package body Sem_Ch7 is
function Scan_Subprogram_Ref (N : Node_Id) return Traverse_Result;
-- Determine whether a node denotes a reference to a subprogram
- procedure Scan_Subprogram_Refs is
+ procedure Traverse_And_Scan_Subprogram_Refs is
new Traverse_Proc (Scan_Subprogram_Ref);
-- Subsidiary to routine Has_Referencer. Determine whether a node
-- contains references to a subprogram and record them.
-- WARNING: this is a very expensive routine as it performs a full
-- tree traversal.
+ procedure Scan_Subprogram_Refs (Node : Node_Id);
+ -- If we haven't already traversed Node, then mark it and traverse
+ -- it.
+
--------------------
-- Has_Referencer --
--------------------
@@ -511,6 +525,18 @@ package body Sem_Ch7 is
return OK;
end Scan_Subprogram_Ref;
+ --------------------------
+ -- Scan_Subprogram_Refs --
+ --------------------------
+
+ procedure Scan_Subprogram_Refs (Node : Node_Id) is
+ begin
+ if not Traversed_Table.Get (Node) then
+ Traversed_Table.Set (Node, True);
+ Traverse_And_Scan_Subprogram_Refs (Node);
+ end if;
+ end Scan_Subprogram_Refs;
+
-- Local variables
Discard : Boolean;
@@ -581,6 +607,7 @@ package body Sem_Ch7 is
-- actual parameters of the instantiations matter here, and they are
-- present in the declarations list of the instantiated packages.
+ Traversed_Table.Reset;
Subprogram_Table.Reset;
Discard := Has_Referencer (Decls, Top_Level => True);
end Hide_Public_Entities;
@@ -945,6 +972,7 @@ package body Sem_Ch7 is
Set_Last_Entity (Spec_Id, Empty);
end if;
+ Update_Use_Clause_Chain;
End_Package_Scope (Spec_Id);
-- All entities declared in body are not visible
@@ -1120,16 +1148,10 @@ package body Sem_Ch7 is
end if;
end if;
- if Is_Comp_Unit then
-
- -- Set Body_Required indication on the compilation unit node, and
- -- determine whether elaboration warnings may be meaningful on it.
+ -- Set Body_Required indication on the compilation unit node
+ if Is_Comp_Unit then
Set_Body_Required (Parent (N), Body_Required);
-
- if not Body_Required then
- Set_Suppress_Elaboration_Warnings (Id);
- end if;
end if;
End_Package_Scope (Id);
@@ -1796,6 +1818,18 @@ package body Sem_Ch7 is
then
Unit_Requires_Body_Info (Id);
end if;
+
+ -- Nested package specs that do not require bodies are not checked for
+ -- ineffective use clauses due to the possbility of subunits. This is
+ -- because at this stage it is impossible to tell whether there will be
+ -- a separate body.
+
+ if not Unit_Requires_Body (Id)
+ and then Is_Compilation_Unit (Id)
+ and then not Is_Private_Descendant (Id)
+ then
+ Update_Use_Clause_Chain;
+ end if;
end Analyze_Package_Specification;
--------------------------------------
diff --git a/gcc/ada/sem_ch8.adb b/gcc/ada/sem_ch8.adb
index 8947841..bdc8aba 100644
--- a/gcc/ada/sem_ch8.adb
+++ b/gcc/ada/sem_ch8.adb
@@ -57,6 +57,7 @@ with Sem_Ch13; use Sem_Ch13;
with Sem_Dim; use Sem_Dim;
with Sem_Disp; use Sem_Disp;
with Sem_Dist; use Sem_Dist;
+with Sem_Elab; use Sem_Elab;
with Sem_Eval; use Sem_Eval;
with Sem_Res; use Sem_Res;
with Sem_Util; use Sem_Util;
@@ -65,7 +66,7 @@ with Stand; use Stand;
with Sinfo; use Sinfo;
with Sinfo.CN; use Sinfo.CN;
with Snames; use Snames;
-with Style; use Style;
+with Style;
with Table;
with Tbuild; use Tbuild;
with Uintp; use Uintp;
@@ -402,11 +403,6 @@ package body Sem_Ch8 is
-- The renaming operation is intrinsic because the compiler must in
-- fact generate a wrapper for it (6.3.1 (10 1/2)).
- function Applicable_Use (Pack_Name : Node_Id) return Boolean;
- -- Common code to Use_One_Package and Set_Use, to determine whether use
- -- clause must be processed. Pack_Name is an entity name that references
- -- the package in question.
-
procedure Attribute_Renaming (N : Node_Id);
-- Analyze renaming of attribute as subprogram. The renaming declaration N
-- is rewritten as a subprogram body that returns the attribute reference
@@ -469,19 +465,22 @@ package body Sem_Ch8 is
-- but is a reasonable heuristic on the use of nested generics. The
-- proper solution requires a full renaming model.
- function Has_Implicit_Character_Literal (N : Node_Id) return Boolean;
- -- Find a type derived from Character or Wide_Character in the prefix of N.
- -- Used to resolved qualified names whose selector is a character literal.
-
- function Has_Private_With (E : Entity_Id) return Boolean;
- -- Ada 2005 (AI-262): Determines if the current compilation unit has a
- -- private with on E.
+ function Entity_Of_Unit (U : Node_Id) return Entity_Id;
+ -- Return the appropriate entity for determining which unit has a deeper
+ -- scope: the defining entity for U, unless U is a package instance, in
+ -- which case we retrieve the entity of the instance spec.
procedure Find_Expanded_Name (N : Node_Id);
-- The input is a selected component known to be an expanded name. Verify
-- legality of selector given the scope denoted by prefix, and change node
-- N into a expanded name with a properly set Entity field.
+ function Find_Most_Prev (Use_Clause : Node_Id) return Node_Id;
+ -- Find the most previous use clause (that is, the first one to appear in
+ -- the source) by traversing the previous clause chain that exists in both
+ -- N_Use_Package_Clause nodes and N_Use_Type_Clause nodes.
+ -- ??? a better subprogram name is in order
+
function Find_Renamed_Entity
(N : Node_Id;
Nam : Node_Id;
@@ -493,6 +492,14 @@ package body Sem_Ch8 is
-- indicates that the renaming is the one generated for an actual subpro-
-- gram in an instance, for which special visibility checks apply.
+ function Has_Implicit_Character_Literal (N : Node_Id) return Boolean;
+ -- Find a type derived from Character or Wide_Character in the prefix of N.
+ -- Used to resolved qualified names whose selector is a character literal.
+
+ function Has_Private_With (E : Entity_Id) return Boolean;
+ -- Ada 2005 (AI-262): Determines if the current compilation unit has a
+ -- private with on E.
+
function Has_Implicit_Operator (N : Node_Id) return Boolean;
-- N is an expanded name whose selector is an operator name (e.g. P."+").
-- declarative part contains an implicit declaration of an operator if it
@@ -507,30 +514,38 @@ package body Sem_Ch8 is
-- specification are discarded and replaced with those of the renamed
-- subprogram, which are then used to recheck the default values.
- function Is_Appropriate_For_Record (T : Entity_Id) return Boolean;
- -- Prefix is appropriate for record if it is of a record type, or an access
- -- to such.
-
function Is_Appropriate_For_Entry_Prefix (T : Entity_Id) return Boolean;
-- True if it is of a task type, a protected type, or else an access to one
-- of these types.
- procedure Note_Redundant_Use (Clause : Node_Id);
- -- Mark the name in a use clause as redundant if the corresponding entity
- -- is already use-visible. Emit a warning if the use clause comes from
- -- source and the proper warnings are enabled.
+ function Is_Appropriate_For_Record (T : Entity_Id) return Boolean;
+ -- Prefix is appropriate for record if it is of a record type, or an access
+ -- to such.
+
+ function Most_Descendant_Use_Clause
+ (Clause1 : Entity_Id;
+ Clause2 : Entity_Id) return Entity_Id;
+ -- Determine which use clause parameter is the most descendant in terms of
+ -- scope.
+ -- ??? a better subprogram name is in order
procedure Premature_Usage (N : Node_Id);
-- Diagnose usage of an entity before it is visible
- procedure Use_One_Package (P : Entity_Id; N : Node_Id);
+ procedure Use_One_Package
+ (N : Node_Id;
+ Pack_Name : Entity_Id := Empty;
+ Force : Boolean := False);
-- Make visible entities declared in package P potentially use-visible
-- in the current context. Also used in the analysis of subunits, when
-- re-installing use clauses of parent units. N is the use_clause that
-- names P (and possibly other packages).
- procedure Use_One_Type (Id : Node_Id; Installed : Boolean := False);
- -- Id is the subtype mark from a use type clause. This procedure makes
+ procedure Use_One_Type
+ (Id : Node_Id;
+ Installed : Boolean := False;
+ Force : Boolean := False);
+ -- Id is the subtype mark from a use_type_clause. This procedure makes
-- the primitive operators of the type potentially use-visible. The
-- boolean flag Installed indicates that the clause is being reinstalled
-- after previous analysis, and primitive operations are already chained
@@ -3437,7 +3452,7 @@ package body Sem_Ch8 is
-- addition the renamed entity may depend on the generic formals of
-- the enclosing generic.
- if Is_Actual and then not Inside_A_Generic then
+ if Is_Actual and not Inside_A_Generic then
Freeze_Before (N, Old_S);
Freeze_Actual_Profile;
Set_Has_Delayed_Freeze (New_S, False);
@@ -3624,6 +3639,22 @@ package body Sem_Ch8 is
Analyze (N);
end if;
end if;
+
+ -- Check if we are looking at an Ada 2012 defaulted formal subprogram
+ -- and mark any use_package_clauses that affect the visibility of the
+ -- implicit generic actual.
+
+ if Is_Generic_Actual_Subprogram (New_S)
+ and then (Is_Intrinsic_Subprogram (New_S) or else From_Default (N))
+ then
+ Mark_Use_Clauses (New_S);
+
+ -- Handle overloaded subprograms
+
+ if Present (Alias (New_S)) then
+ Mark_Use_Clauses (Alias (New_S));
+ end if;
+ end if;
end Analyze_Subprogram_Renaming;
-------------------------
@@ -3637,11 +3668,77 @@ package body Sem_Ch8 is
-- use. If the package is an open scope, i.e. if the use clause occurs
-- within the package itself, ignore it.
- procedure Analyze_Use_Package (N : Node_Id) is
+ procedure Analyze_Use_Package (N : Node_Id; Chain : Boolean := True) is
+ procedure Analyze_Package_Name (Clause : Node_Id);
+ -- Perform analysis on a package name from a use_package_clause
+
+ procedure Analyze_Package_Name_List (Head_Clause : Node_Id);
+ -- Similar to Analyze_Package_Name but iterates over all the names
+ -- in a use clause.
+
+ --------------------------
+ -- Analyze_Package_Name --
+ --------------------------
+
+ procedure Analyze_Package_Name (Clause : Node_Id) is
+ Pack : constant Node_Id := Name (Clause);
+ Pref : Node_Id;
+
+ begin
+ pragma Assert (Nkind (Clause) = N_Use_Package_Clause);
+ Analyze (Pack);
+
+ -- Verify that the package standard is not directly named in a
+ -- use_package_clause.
+
+ if Nkind (Parent (Clause)) = N_Compilation_Unit
+ and then Nkind (Pack) = N_Expanded_Name
+ then
+ Pref := Prefix (Pack);
+
+ while Nkind (Pref) = N_Expanded_Name loop
+ Pref := Prefix (Pref);
+ end loop;
+
+ if Entity (Pref) = Standard_Standard then
+ Error_Msg_N
+ ("predefined package Standard cannot appear in a context "
+ & "clause", Pref);
+ end if;
+ end if;
+ end Analyze_Package_Name;
+
+ -------------------------------
+ -- Analyze_Package_Name_List --
+ -------------------------------
+
+ procedure Analyze_Package_Name_List (Head_Clause : Node_Id) is
+ Curr : Node_Id;
+
+ begin
+ -- Due to the way source use clauses are split during parsing we are
+ -- forced to simply iterate through all entities in scope until the
+ -- clause representing the last name in the list is found.
+
+ Curr := Head_Clause;
+ while Present (Curr) loop
+ Analyze_Package_Name (Curr);
+
+ -- Stop iterating over the names in the use clause when we are at
+ -- the last one.
+
+ exit when not More_Ids (Curr) and then Prev_Ids (Curr);
+ Next (Curr);
+ end loop;
+ end Analyze_Package_Name_List;
+
+ -- Local variables
+
Ghost_Id : Entity_Id := Empty;
Living_Id : Entity_Id := Empty;
Pack : Entity_Id;
- Pack_Name : Node_Id;
+
+ -- Start of processing for Analyze_Use_Package
begin
Check_SPARK_05_Restriction ("use clause is not allowed", N);
@@ -3661,143 +3758,125 @@ package body Sem_Ch8 is
Error_Msg_N ("use clause not allowed in predefined spec", N);
end if;
- -- Chain clause to list of use clauses in current scope
-
- if Nkind (Parent (N)) /= N_Compilation_Unit then
- Chain_Use_Clause (N);
- end if;
+ -- Loop through all package names from the original use clause in
+ -- order to analyze referenced packages. A use_package_clause with only
+ -- one name does not have More_Ids or Prev_Ids set, while a clause with
+ -- More_Ids only starts the chain produced by the parser.
- -- Loop through package names to identify referenced packages
+ if not More_Ids (N) and then not Prev_Ids (N) then
+ Analyze_Package_Name (N);
- Pack_Name := First (Names (N));
- while Present (Pack_Name) loop
- Analyze (Pack_Name);
+ elsif More_Ids (N) and then not Prev_Ids (N) then
+ Analyze_Package_Name_List (N);
+ end if;
- if Nkind (Parent (N)) = N_Compilation_Unit
- and then Nkind (Pack_Name) = N_Expanded_Name
- then
- declare
- Pref : Node_Id;
+ if not Is_Entity_Name (Name (N)) then
+ Error_Msg_N ("& is not a package", Name (N));
- begin
- Pref := Prefix (Pack_Name);
- while Nkind (Pref) = N_Expanded_Name loop
- Pref := Prefix (Pref);
- end loop;
+ return;
+ end if;
- if Entity (Pref) = Standard_Standard then
- Error_Msg_N
- ("predefined package Standard cannot appear in a context "
- & "clause", Pref);
- end if;
- end;
- end if;
+ if Chain then
+ Chain_Use_Clause (N);
+ end if;
- Next (Pack_Name);
- end loop;
+ Pack := Entity (Name (N));
- -- Loop through package names to mark all entities as potentially use
- -- visible.
+ -- There are many cases where scopes are manipulated during analysis, so
+ -- check that Pack's current use clause has not already been chained
+ -- before setting its previous use clause.
- Pack_Name := First (Names (N));
- while Present (Pack_Name) loop
- if Is_Entity_Name (Pack_Name) then
- Pack := Entity (Pack_Name);
+ if Ekind (Pack) = E_Package
+ and then Present (Current_Use_Clause (Pack))
+ and then Current_Use_Clause (Pack) /= N
+ and then No (Prev_Use_Clause (N))
+ and then Prev_Use_Clause (Current_Use_Clause (Pack)) /= N
+ then
+ Set_Prev_Use_Clause (N, Current_Use_Clause (Pack));
+ end if;
- if Ekind (Pack) /= E_Package and then Etype (Pack) /= Any_Type then
- if Ekind (Pack) = E_Generic_Package then
- Error_Msg_N -- CODEFIX
- ("a generic package is not allowed in a use clause",
- Pack_Name);
+ -- Mark all entities as potentially use visible.
- elsif Ekind_In (Pack, E_Generic_Function, E_Generic_Package)
- then
- Error_Msg_N -- CODEFIX
- ("a generic subprogram is not allowed in a use clause",
- Pack_Name);
+ if Ekind (Pack) /= E_Package and then Etype (Pack) /= Any_Type then
+ if Ekind (Pack) = E_Generic_Package then
+ Error_Msg_N -- CODEFIX
+ ("a generic package is not allowed in a use clause", Name (N));
- elsif Ekind_In (Pack, E_Function, E_Procedure, E_Operator) then
- Error_Msg_N -- CODEFIX
- ("a subprogram is not allowed in a use clause",
- Pack_Name);
+ elsif Ekind_In (Pack, E_Generic_Function, E_Generic_Package)
+ then
+ Error_Msg_N -- CODEFIX
+ ("a generic subprogram is not allowed in a use clause",
+ Name (N));
- else
- Error_Msg_N ("& is not allowed in a use clause", Pack_Name);
- end if;
+ elsif Ekind_In (Pack, E_Function, E_Procedure, E_Operator) then
+ Error_Msg_N -- CODEFIX
+ ("a subprogram is not allowed in a use clause", Name (N));
- else
- if Nkind (Parent (N)) = N_Compilation_Unit then
- Check_In_Previous_With_Clause (N, Pack_Name);
- end if;
+ else
+ Error_Msg_N ("& is not allowed in a use clause", Name (N));
+ end if;
- if Applicable_Use (Pack_Name) then
- Use_One_Package (Pack, N);
- end if;
+ else
+ if Nkind (Parent (N)) = N_Compilation_Unit then
+ Check_In_Previous_With_Clause (N, Name (N));
+ end if;
- -- Capture the first Ghost package and the first living package
+ Use_One_Package (N, Name (N));
- if Is_Entity_Name (Pack_Name) then
- Pack := Entity (Pack_Name);
+ -- Capture the first Ghost package and the first living package
- if Is_Ghost_Entity (Pack) then
- if No (Ghost_Id) then
- Ghost_Id := Pack;
- end if;
+ if Is_Entity_Name (Name (N)) then
+ Pack := Entity (Name (N));
- elsif No (Living_Id) then
- Living_Id := Pack;
- end if;
+ if Is_Ghost_Entity (Pack) then
+ if No (Ghost_Id) then
+ Ghost_Id := Pack;
end if;
- end if;
-
- -- Report error because name denotes something other than a package
- else
- Error_Msg_N ("& is not a package", Pack_Name);
+ elsif No (Living_Id) then
+ Living_Id := Pack;
+ end if;
end if;
-
- Next (Pack_Name);
- end loop;
-
- -- Detect a mixture of Ghost packages and living packages within the
- -- same use package clause. Ideally one would split a use package clause
- -- with multiple names into multiple use package clauses with a single
- -- name, however clients of the front end would have to adapt to this
- -- change.
-
- if Present (Ghost_Id) and then Present (Living_Id) then
- Error_Msg_N
- ("use clause cannot mention ghost and non-ghost ghost units", N);
-
- Error_Msg_Sloc := Sloc (Ghost_Id);
- Error_Msg_NE ("\& # declared as ghost", N, Ghost_Id);
-
- Error_Msg_Sloc := Sloc (Living_Id);
- Error_Msg_NE ("\& # declared as non-ghost", N, Living_Id);
end if;
-
- Mark_Ghost_Clause (N);
end Analyze_Use_Package;
----------------------
-- Analyze_Use_Type --
----------------------
- procedure Analyze_Use_Type (N : Node_Id) is
- E : Entity_Id;
- Ghost_Id : Entity_Id := Empty;
- Id : Node_Id;
- Living_Id : Entity_Id := Empty;
+ procedure Analyze_Use_Type (N : Node_Id; Chain : Boolean := True) is
+ E : Entity_Id;
+ Id : Node_Id;
begin
Set_Hidden_By_Use_Clause (N, No_Elist);
- -- Chain clause to list of use clauses in current scope
+ -- Chain clause to list of use clauses in current scope when flagged
- if Nkind (Parent (N)) /= N_Compilation_Unit then
+ if Chain then
Chain_Use_Clause (N);
end if;
+ -- Obtain the base type of the type denoted within the use_type_clause's
+ -- subtype mark.
+
+ Id := Subtype_Mark (N);
+ Find_Type (Id);
+ E := Base_Type (Entity (Id));
+
+ -- There are many cases where a use_type_clause may be reanalyzed due to
+ -- manipulation of the scope stack so we much guard against those cases
+ -- here, otherwise, we must add the new use_type_clause to the previous
+ -- use_type_clause chain in order to mark redundant use_type_clauses as
+ -- used.
+
+ if Present (Current_Use_Clause (E))
+ and then Current_Use_Clause (E) /= N
+ and then No (Prev_Use_Clause (N))
+ then
+ Set_Prev_Use_Clause (N, Current_Use_Clause (E));
+ end if;
+
-- If the Used_Operations list is already initialized, the clause has
-- been analyzed previously, and it is being reinstalled, for example
-- when the clause appears in a package spec and we are compiling the
@@ -3806,15 +3885,10 @@ package body Sem_Ch8 is
if Present (Used_Operations (N)) then
declare
- Mark : Node_Id;
Elmt : Elmt_Id;
begin
- Mark := First (Subtype_Marks (N));
- while Present (Mark) loop
- Use_One_Type (Mark, Installed => True);
- Next (Mark);
- end loop;
+ Use_One_Type (Subtype_Mark (N), Installed => True);
Elmt := First_Elmt (Used_Operations (N));
while Present (Elmt) loop
@@ -3830,133 +3904,69 @@ package body Sem_Ch8 is
-- made use-visible by the clause.
Set_Used_Operations (N, New_Elmt_List);
- Id := First (Subtype_Marks (N));
- while Present (Id) loop
- Find_Type (Id);
- E := Entity (Id);
-
- if E /= Any_Type then
- Use_One_Type (Id);
+ E := Entity (Id);
- if Nkind (Parent (N)) = N_Compilation_Unit then
- if Nkind (Id) = N_Identifier then
- Error_Msg_N ("type is not directly visible", Id);
-
- elsif Is_Child_Unit (Scope (E))
- and then Scope (E) /= System_Aux_Id
- then
- Check_In_Previous_With_Clause (N, Prefix (Id));
- end if;
- end if;
+ if E /= Any_Type then
+ Use_One_Type (Id);
- else
- -- If the use_type_clause appears in a compilation unit context,
- -- check whether it comes from a unit that may appear in a
- -- limited_with_clause, for a better error message.
+ if Nkind (Parent (N)) = N_Compilation_Unit then
+ if Nkind (Id) = N_Identifier then
+ Error_Msg_N ("type is not directly visible", Id);
- if Nkind (Parent (N)) = N_Compilation_Unit
- and then Nkind (Id) /= N_Identifier
+ elsif Is_Child_Unit (Scope (E))
+ and then Scope (E) /= System_Aux_Id
then
- declare
- Item : Node_Id;
- Pref : Node_Id;
-
- function Mentioned (Nam : Node_Id) return Boolean;
- -- Check whether the prefix of expanded name for the type
- -- appears in the prefix of some limited_with_clause.
-
- ---------------
- -- Mentioned --
- ---------------
-
- function Mentioned (Nam : Node_Id) return Boolean is
- begin
- return Nkind (Name (Item)) = N_Selected_Component
- and then Chars (Prefix (Name (Item))) = Chars (Nam);
- end Mentioned;
-
- begin
- Pref := Prefix (Id);
- Item := First (Context_Items (Parent (N)));
- while Present (Item) and then Item /= N loop
- if Nkind (Item) = N_With_Clause
- and then Limited_Present (Item)
- and then Mentioned (Pref)
- then
- Change_Error_Text
- (Get_Msg_Id, "premature usage of incomplete type");
- end if;
-
- Next (Item);
- end loop;
- end;
+ Check_In_Previous_With_Clause (N, Prefix (Id));
end if;
end if;
- -- Capture the first Ghost type and the first living type
-
- if Is_Ghost_Entity (E) then
- if No (Ghost_Id) then
- Ghost_Id := E;
- end if;
+ else
+ -- If the use_type_clause appears in a compilation unit context,
+ -- check whether it comes from a unit that may appear in a
+ -- limited_with_clause, for a better error message.
- elsif No (Living_Id) then
- Living_Id := E;
- end if;
+ if Nkind (Parent (N)) = N_Compilation_Unit
+ and then Nkind (Id) /= N_Identifier
+ then
+ declare
+ Item : Node_Id;
+ Pref : Node_Id;
- Next (Id);
- end loop;
+ function Mentioned (Nam : Node_Id) return Boolean;
+ -- Check whether the prefix of expanded name for the type
+ -- appears in the prefix of some limited_with_clause.
- -- Detect a mixture of Ghost types and living types within the same use
- -- type clause. Ideally one would split a use type clause with multiple
- -- marks into multiple use type clauses with a single mark, however
- -- clients of the front end will have to adapt to this change.
+ ---------------
+ -- Mentioned --
+ ---------------
- if Present (Ghost_Id) and then Present (Living_Id) then
- Error_Msg_N
- ("use clause cannot mention ghost and non-ghost ghost types", N);
+ function Mentioned (Nam : Node_Id) return Boolean is
+ begin
+ return Nkind (Name (Item)) = N_Selected_Component
+ and then Chars (Prefix (Name (Item))) = Chars (Nam);
+ end Mentioned;
- Error_Msg_Sloc := Sloc (Ghost_Id);
- Error_Msg_NE ("\& # declared as ghost", N, Ghost_Id);
+ begin
+ Pref := Prefix (Id);
+ Item := First (Context_Items (Parent (N)));
+ while Present (Item) and then Item /= N loop
+ if Nkind (Item) = N_With_Clause
+ and then Limited_Present (Item)
+ and then Mentioned (Pref)
+ then
+ Change_Error_Text
+ (Get_Msg_Id, "premature usage of incomplete type");
+ end if;
- Error_Msg_Sloc := Sloc (Living_Id);
- Error_Msg_NE ("\& # declared as non-ghost", N, Living_Id);
+ Next (Item);
+ end loop;
+ end;
+ end if;
end if;
Mark_Ghost_Clause (N);
end Analyze_Use_Type;
- --------------------
- -- Applicable_Use --
- --------------------
-
- function Applicable_Use (Pack_Name : Node_Id) return Boolean is
- Pack : constant Entity_Id := Entity (Pack_Name);
-
- begin
- if In_Open_Scopes (Pack) then
- if Warn_On_Redundant_Constructs and then Pack = Current_Scope then
- Error_Msg_NE -- CODEFIX
- ("& is already use-visible within itself?r?", Pack_Name, Pack);
- end if;
-
- return False;
-
- elsif In_Use (Pack) then
- Note_Redundant_Use (Pack_Name);
- return False;
-
- elsif Present (Renamed_Object (Pack))
- and then In_Use (Renamed_Object (Pack))
- then
- Note_Redundant_Use (Pack_Name);
- return False;
-
- else
- return True;
- end if;
- end Applicable_Use;
-
------------------------
-- Attribute_Renaming --
------------------------
@@ -4107,6 +4117,11 @@ package body Sem_Ch8 is
Statements => New_List (Attr_Node)));
end if;
+ -- Signal the ABE mechanism that the generated subprogram body has not
+ -- ABE ramifications.
+
+ Set_Was_Attribute_Reference (Body_Node);
+
-- In case of tagged types we add the body of the generated function to
-- the freezing actions of the type (because in the general case such
-- type is still not frozen). We exclude from this processing generic
@@ -4166,15 +4181,6 @@ package body Sem_Ch8 is
Error_Msg_N
("a library unit can only rename another library unit", N);
end if;
-
- -- We suppress elaboration warnings for the resulting entity, since
- -- clearly they are not needed, and more particularly, in the case
- -- of a generic formal subprogram, the resulting entity can appear
- -- after the instantiation itself, and thus look like a bogus case
- -- of access before elaboration.
-
- Set_Suppress_Elaboration_Warnings (New_S);
-
end Attribute_Renaming;
----------------------
@@ -4182,25 +4188,32 @@ package body Sem_Ch8 is
----------------------
procedure Chain_Use_Clause (N : Node_Id) is
- Pack : Entity_Id;
Level : Int := Scope_Stack.Last;
+ Pack : Entity_Id;
begin
+ -- Common case
+
if not Is_Compilation_Unit (Current_Scope)
or else not Is_Child_Unit (Current_Scope)
then
- null; -- Common case
+ null;
+
+ -- Common case for compilation unit
- elsif Defining_Entity (Parent (N)) = Current_Scope then
- null; -- Common case for compilation unit
+ elsif Defining_Entity (N => Parent (N),
+ Empty_On_Errors => True) = Current_Scope
+ then
+ null;
else
-- If declaration appears in some other scope, it must be in some
-- parent unit when compiling a child.
- Pack := Defining_Entity (Parent (N));
+ Pack := Defining_Entity (Parent (N), Empty_On_Errors => True);
+
if not In_Open_Scopes (Pack) then
- null; -- default as well
+ null;
-- If the use clause appears in an ancestor and we are in the
-- private part of the immediate parent, the use clauses are
@@ -4547,11 +4560,11 @@ package body Sem_Ch8 is
---------------------
procedure End_Use_Clauses (Clause : Node_Id) is
- U : Node_Id;
+ U : Node_Id;
begin
- -- Remove Use_Type clauses first, because they affect the
- -- visibility of operators in subsequent used packages.
+ -- Remove use_type_clauses first, because they affect the visibility of
+ -- operators in subsequent used packages.
U := Clause;
while Present (U) loop
@@ -4577,8 +4590,8 @@ package body Sem_Ch8 is
---------------------
procedure End_Use_Package (N : Node_Id) is
- Pack_Name : Node_Id;
Pack : Entity_Id;
+ Pack_Name : Node_Id;
Id : Entity_Id;
Elmt : Elmt_Id;
@@ -4603,43 +4616,64 @@ package body Sem_Ch8 is
-- Start of processing for End_Use_Package
begin
- Pack_Name := First (Names (N));
- while Present (Pack_Name) loop
+ Pack_Name := Name (N);
- -- Test that Pack_Name actually denotes a package before processing
+ -- Test that Pack_Name actually denotes a package before processing
- if Is_Entity_Name (Pack_Name)
- and then Ekind (Entity (Pack_Name)) = E_Package
- then
- Pack := Entity (Pack_Name);
+ if Is_Entity_Name (Pack_Name)
+ and then Ekind (Entity (Pack_Name)) = E_Package
+ then
+ Pack := Entity (Pack_Name);
- if In_Open_Scopes (Pack) then
- null;
+ if In_Open_Scopes (Pack) then
+ null;
- elsif not Redundant_Use (Pack_Name) then
- Set_In_Use (Pack, False);
- Set_Current_Use_Clause (Pack, Empty);
+ elsif not Redundant_Use (Pack_Name) then
+ Set_In_Use (Pack, False);
+ Set_Current_Use_Clause (Pack, Empty);
- Id := First_Entity (Pack);
- while Present (Id) loop
+ Id := First_Entity (Pack);
+ while Present (Id) loop
- -- Preserve use-visibility of operators that are primitive
- -- operators of a type that is use-visible through an active
- -- use_type clause.
+ -- Preserve use-visibility of operators that are primitive
+ -- operators of a type that is use-visible through an active
+ -- use_type_clause.
- if Nkind (Id) = N_Defining_Operator_Symbol
- and then
- (Is_Primitive_Operator_In_Use (Id, First_Formal (Id))
- or else
- (Present (Next_Formal (First_Formal (Id)))
- and then
- Is_Primitive_Operator_In_Use
- (Id, Next_Formal (First_Formal (Id)))))
- then
- null;
- else
- Set_Is_Potentially_Use_Visible (Id, False);
- end if;
+ if Nkind (Id) = N_Defining_Operator_Symbol
+ and then
+ (Is_Primitive_Operator_In_Use (Id, First_Formal (Id))
+ or else
+ (Present (Next_Formal (First_Formal (Id)))
+ and then
+ Is_Primitive_Operator_In_Use
+ (Id, Next_Formal (First_Formal (Id)))))
+ then
+ null;
+ else
+ Set_Is_Potentially_Use_Visible (Id, False);
+ end if;
+
+ if Is_Private_Type (Id)
+ and then Present (Full_View (Id))
+ then
+ Set_Is_Potentially_Use_Visible (Full_View (Id), False);
+ end if;
+
+ Next_Entity (Id);
+ end loop;
+
+ if Present (Renamed_Object (Pack)) then
+ Set_In_Use (Renamed_Object (Pack), False);
+ Set_Current_Use_Clause (Renamed_Object (Pack), Empty);
+ end if;
+
+ if Chars (Pack) = Name_System
+ and then Scope (Pack) = Standard_Standard
+ and then Present_System_Aux
+ then
+ Id := First_Entity (System_Aux_Id);
+ while Present (Id) loop
+ Set_Is_Potentially_Use_Visible (Id, False);
if Is_Private_Type (Id)
and then Present (Full_View (Id))
@@ -4650,38 +4684,12 @@ package body Sem_Ch8 is
Next_Entity (Id);
end loop;
- if Present (Renamed_Object (Pack)) then
- Set_In_Use (Renamed_Object (Pack), False);
- Set_Current_Use_Clause (Renamed_Object (Pack), Empty);
- end if;
-
- if Chars (Pack) = Name_System
- and then Scope (Pack) = Standard_Standard
- and then Present_System_Aux
- then
- Id := First_Entity (System_Aux_Id);
- while Present (Id) loop
- Set_Is_Potentially_Use_Visible (Id, False);
-
- if Is_Private_Type (Id)
- and then Present (Full_View (Id))
- then
- Set_Is_Potentially_Use_Visible (Full_View (Id), False);
- end if;
-
- Next_Entity (Id);
- end loop;
-
- Set_In_Use (System_Aux_Id, False);
- end if;
-
- else
- Set_Redundant_Use (Pack_Name, False);
+ Set_In_Use (System_Aux_Id, False);
end if;
+ else
+ Set_Redundant_Use (Pack_Name, False);
end if;
-
- Next (Pack_Name);
- end loop;
+ end if;
if Present (Hidden_By_Use_Clause (N)) then
Elmt := First_Elmt (Hidden_By_Use_Clause (N));
@@ -4714,30 +4722,26 @@ package body Sem_Ch8 is
------------------
procedure End_Use_Type (N : Node_Id) is
- Elmt : Elmt_Id;
- Id : Entity_Id;
- T : Entity_Id;
+ Elmt : Elmt_Id;
+ Id : Entity_Id;
+ T : Entity_Id;
-- Start of processing for End_Use_Type
begin
- Id := First (Subtype_Marks (N));
- while Present (Id) loop
-
- -- A call to Rtsfind may occur while analyzing a use_type clause,
- -- in which case the type marks are not resolved yet, and there is
- -- nothing to remove.
+ Id := Subtype_Mark (N);
- if not Is_Entity_Name (Id) or else No (Entity (Id)) then
- goto Continue;
- end if;
+ -- A call to Rtsfind may occur while analyzing a use_type_clause, in
+ -- which case the type marks are not resolved yet, so guard against that
+ -- here.
+ if Is_Entity_Name (Id) and then Present (Entity (Id)) then
T := Entity (Id);
if T = Any_Type or else From_Limited_With (T) then
null;
- -- Note that the use_type clause may mention a subtype of the type
+ -- Note that the use_type_clause may mention a subtype of the type
-- whose primitive operations have been made visible. Here as
-- elsewhere, it is the base type that matters for visibility.
@@ -4750,10 +4754,7 @@ package body Sem_Ch8 is
Set_Current_Use_Clause (T, Empty);
Set_Current_Use_Clause (Base_Type (T), Empty);
end if;
-
- <<Continue>>
- Next (Id);
- end loop;
+ end if;
if Is_Empty_Elmt_List (Used_Operations (N)) then
return;
@@ -4767,6 +4768,19 @@ package body Sem_Ch8 is
end if;
end End_Use_Type;
+ --------------------
+ -- Entity_Of_Unit --
+ --------------------
+
+ function Entity_Of_Unit (U : Node_Id) return Entity_Id is
+ begin
+ if Nkind (U) = N_Package_Instantiation and then Analyzed (U) then
+ return Defining_Entity (Instance_Spec (U));
+ else
+ return Defining_Entity (U);
+ end if;
+ end Entity_Of_Unit;
+
----------------------
-- Find_Direct_Name --
----------------------
@@ -5384,9 +5398,30 @@ package body Sem_Ch8 is
end;
end if;
+ -- Although the marking of use clauses happens at the end of
+ -- Find_Direct_Name, a certain case where a generic actual satisfies
+ -- a use clause must be checked here due to how the generic machinery
+ -- handles the analysis of said actuals.
+
+ if In_Instance
+ and then Nkind (Parent (N)) = N_Generic_Association
+ then
+ Mark_Use_Clauses (Entity (N));
+ end if;
+
return;
end if;
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ if Nkind (N) = N_Identifier then
+ Mark_Elaboration_Attributes
+ (N_Id => N,
+ Modes => True);
+ end if;
+
-- Here if Entity pointer was not set, we need full visibility analysis
-- First we generate debugging output if the debug E flag is set.
@@ -5561,7 +5596,7 @@ package body Sem_Ch8 is
goto Done;
elsif Is_Predefined_Unit (Current_Sem_Unit) then
- -- A use-clause in the body of a system file creates conflict
+ -- A use clause in the body of a system file creates conflict
-- with some entity in a user scope, while rtsfind is active.
-- Keep only the entity coming from another predefined unit.
@@ -5843,10 +5878,26 @@ package body Sem_Ch8 is
end if;
end;
+ -- Mark relevant use-type and use-package clauses as effective if the
+ -- node in question is not overloaded and therefore does not require
+ -- resolution.
+ --
+ -- Note: Generic actual subprograms do not follow the normal resolution
+ -- path, so ignore the fact that they are overloaded and mark them
+ -- anyway.
+
+ if Nkind (N) not in N_Subexpr or else not Is_Overloaded (N) then
+ Mark_Use_Clauses (N);
+ end if;
+
-- Come here with entity set
<<Done>>
Check_Restriction_No_Use_Of_Entity (N);
+
+ -- Save the scenario for later examination by the ABE Processing phase
+
+ Record_Elaboration_Scenario (N);
end Find_Direct_Name;
------------------------
@@ -6361,6 +6412,14 @@ package body Sem_Ch8 is
Change_Selected_Component_To_Expanded_Name (N);
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => N,
+ Modes => True);
+
-- Set appropriate type
if Is_Type (Id) then
@@ -6460,9 +6519,39 @@ package body Sem_Ch8 is
Generate_Reference (Id, N);
end if;
+ -- Mark relevant use-type and use-package clauses as effective if the
+ -- node in question is not overloaded and therefore does not require
+ -- resolution.
+
+ if Nkind (N) not in N_Subexpr or else not Is_Overloaded (N) then
+ Mark_Use_Clauses (N);
+ end if;
+
Check_Restriction_No_Use_Of_Entity (N);
+
+ -- Save the scenario for later examination by the ABE Processing phase
+
+ Record_Elaboration_Scenario (N);
end Find_Expanded_Name;
+ --------------------
+ -- Find_Most_Prev --
+ --------------------
+
+ function Find_Most_Prev (Use_Clause : Node_Id) return Node_Id is
+ Curr : Node_Id;
+
+ begin
+ -- Loop through the Prev_Use_Clause chain
+
+ Curr := Use_Clause;
+ while Present (Prev_Use_Clause (Curr)) loop
+ Curr := Prev_Use_Clause (Curr);
+ end loop;
+
+ return Curr;
+ end Find_Most_Prev;
+
-------------------------
-- Find_Renamed_Entity --
-------------------------
@@ -8039,9 +8128,7 @@ package body Sem_Ch8 is
(Clause : Node_Id;
Force_Installation : Boolean := False)
is
- U : Node_Id;
- P : Node_Id;
- Id : Entity_Id;
+ U : Node_Id;
begin
U := Clause;
@@ -8050,44 +8137,13 @@ package body Sem_Ch8 is
-- Case of USE package
if Nkind (U) = N_Use_Package_Clause then
- P := First (Names (U));
- while Present (P) loop
- Id := Entity (P);
-
- if Ekind (Id) = E_Package then
- if In_Use (Id) then
- Note_Redundant_Use (P);
-
- elsif Present (Renamed_Object (Id))
- and then In_Use (Renamed_Object (Id))
- then
- Note_Redundant_Use (P);
-
- elsif Force_Installation or else Applicable_Use (P) then
- Use_One_Package (Id, U);
-
- end if;
- end if;
-
- Next (P);
- end loop;
+ Use_One_Package (U, Name (U), True);
-- Case of USE TYPE
else
- P := First (Subtype_Marks (U));
- while Present (P) loop
- if not Is_Entity_Name (P)
- or else No (Entity (P))
- then
- null;
+ Use_One_Type (Subtype_Mark (U), Force => Force_Installation);
- elsif Entity (P) /= Any_Type then
- Use_One_Type (P);
- end if;
-
- Next (P);
- end loop;
end if;
Next_Use_Clause (U);
@@ -8145,196 +8201,260 @@ package body Sem_Ch8 is
and then Has_Components (Designated_Type (T))));
end Is_Appropriate_For_Record;
- ------------------------
- -- Note_Redundant_Use --
- ------------------------
+ ----------------------
+ -- Mark_Use_Clauses --
+ ----------------------
- procedure Note_Redundant_Use (Clause : Node_Id) is
- Pack_Name : constant Entity_Id := Entity (Clause);
- Cur_Use : constant Node_Id := Current_Use_Clause (Pack_Name);
- Decl : constant Node_Id := Parent (Clause);
+ procedure Mark_Use_Clauses (Id : Node_Or_Entity_Id) is
+ procedure Mark_Parameters (Call : Entity_Id);
+ -- Perform use_type_clause marking for all parameters in a subprogram
+ -- or operator call.
- Prev_Use : Node_Id := Empty;
- Redundant : Node_Id := Empty;
- -- The Use_Clause which is actually redundant. In the simplest case it
- -- is Pack itself, but when we compile a body we install its context
- -- before that of its spec, in which case it is the use_clause in the
- -- spec that will appear to be redundant, and we want the warning to be
- -- placed on the body. Similar complications appear when the redundancy
- -- is between a child unit and one of its ancestors.
+ procedure Mark_Use_Package (Pak : Entity_Id);
+ -- Move up the Prev_Use_Clause chain for packages denoted by Pak -
+ -- marking each clause in the chain as effective in the process.
- begin
- Set_Redundant_Use (Clause, True);
+ procedure Mark_Use_Type (E : Entity_Id);
+ -- Similar to Do_Use_Package_Marking except we move up the
+ -- Prev_Use_Clause chain for the type denoted by E.
- if not Comes_From_Source (Clause)
- or else In_Instance
- or else not Warn_On_Redundant_Constructs
- then
- return;
- end if;
+ ---------------------
+ -- Mark_Parameters --
+ ---------------------
- if not Is_Compilation_Unit (Current_Scope) then
+ procedure Mark_Parameters (Call : Entity_Id) is
+ Curr : Node_Id;
- -- If the use_clause is in an inner scope, it is made redundant by
- -- some clause in the current context, with one exception: If we're
- -- compiling a nested package body, and the use_clause comes from the
- -- corresponding spec, the clause is not necessarily fully redundant,
- -- so we should not warn. If a warning was warranted, it would have
- -- been given when the spec was processed.
+ begin
+ -- Move through all of the formals
- if Nkind (Parent (Decl)) = N_Package_Specification then
- declare
- Package_Spec_Entity : constant Entity_Id :=
- Defining_Unit_Name (Parent (Decl));
- begin
- if In_Package_Body (Package_Spec_Entity) then
- return;
- end if;
- end;
- end if;
+ Curr := First_Formal (Call);
+ while Present (Curr) loop
+ Mark_Use_Type (Curr);
- Redundant := Clause;
- Prev_Use := Cur_Use;
+ Curr := Next_Formal (Curr);
+ end loop;
- elsif Nkind (Unit (Cunit (Current_Sem_Unit))) = N_Package_Body then
- declare
- Cur_Unit : constant Unit_Number_Type := Get_Source_Unit (Cur_Use);
- New_Unit : constant Unit_Number_Type := Get_Source_Unit (Clause);
- Scop : Entity_Id;
+ -- Handle the return type
- begin
- if Cur_Unit = New_Unit then
+ Mark_Use_Type (Call);
+ end Mark_Parameters;
- -- Redundant clause in same body
+ ----------------------
+ -- Mark_Use_Package --
+ ----------------------
- Redundant := Clause;
- Prev_Use := Cur_Use;
+ procedure Mark_Use_Package (Pak : Entity_Id) is
+ Curr : Node_Id;
- elsif Cur_Unit = Current_Sem_Unit then
+ begin
+ -- Ignore cases where the scope of the type is not a package (e.g.
+ -- Standard_Standard).
- -- If the new clause is not in the current unit it has been
- -- analyzed first, and it makes the other one redundant.
- -- However, if the new clause appears in a subunit, Cur_Unit
- -- is still the parent, and in that case the redundant one
- -- is the one appearing in the subunit.
+ if Ekind (Pak) /= E_Package then
+ return;
+ end if;
- if Nkind (Unit (Cunit (New_Unit))) = N_Subunit then
- Redundant := Clause;
- Prev_Use := Cur_Use;
+ Curr := Current_Use_Clause (Pak);
+ while Present (Curr)
+ and then not Is_Effective_Use_Clause (Curr)
+ loop
+ -- We need to mark the previous use clauses as effective, but
+ -- each use clause may in turn render other use_package_clauses
+ -- effective. Additionally, it is possible to have a parent
+ -- package renamed as a child of itself so we must check the
+ -- prefix entity is not the same as the package we are marking.
+
+ if Nkind (Name (Curr)) /= N_Identifier
+ and then Present (Prefix (Name (Curr)))
+ and then Entity (Prefix (Name (Curr))) /= Pak
+ then
+ Mark_Use_Package (Entity (Prefix (Name (Curr))));
- -- Most common case: redundant clause in body,
- -- original clause in spec. Current scope is spec entity.
+ -- It is also possible to have a child package without a prefix
+ -- that relies on a previous use_package_clause.
- elsif
- Current_Scope =
- Defining_Entity (
- Unit (Library_Unit (Cunit (Current_Sem_Unit))))
- then
- Redundant := Cur_Use;
- Prev_Use := Clause;
+ elsif Nkind (Name (Curr)) = N_Identifier
+ and then Is_Child_Unit (Entity (Name (Curr)))
+ then
+ Mark_Use_Package (Scope (Entity (Name (Curr))));
+ end if;
- else
- -- The new clause may appear in an unrelated unit, when
- -- the parents of a generic are being installed prior to
- -- instantiation. In this case there must be no warning.
- -- We detect this case by checking whether the current top
- -- of the stack is related to the current compilation.
-
- Scop := Current_Scope;
- while Present (Scop) and then Scop /= Standard_Standard loop
- if Is_Compilation_Unit (Scop)
- and then not Is_Child_Unit (Scop)
- then
- return;
+ -- Mark the use_package_clause as effective and move up the chain
- elsif Scop = Cunit_Entity (Current_Sem_Unit) then
- exit;
- end if;
+ Set_Is_Effective_Use_Clause (Curr);
- Scop := Scope (Scop);
- end loop;
+ Curr := Prev_Use_Clause (Curr);
+ end loop;
+ end Mark_Use_Package;
- Redundant := Cur_Use;
- Prev_Use := Clause;
- end if;
+ -------------------
+ -- Mark_Use_Type --
+ -------------------
- elsif New_Unit = Current_Sem_Unit then
- Redundant := Clause;
- Prev_Use := Cur_Use;
+ procedure Mark_Use_Type (E : Entity_Id) is
+ Curr : Node_Id;
- else
- -- Neither is the current unit, so they appear in parent or
- -- sibling units. Warning will be emitted elsewhere.
+ begin
+ -- Ignore void types and unresolved string literals and primitives
- return;
+ if Nkind (E) = N_String_Literal
+ or else Nkind (Etype (E)) not in N_Entity
+ or else not Is_Type (Etype (E))
+ then
+ return;
+ end if;
+
+ -- The package containing the type or operator function being used
+ -- may be in use as well, so mark any use_package_clauses for it as
+ -- effective. There are also additional sanity checks performed here
+ -- for ignoring previous errors.
+
+ Mark_Use_Package (Scope (Base_Type (Etype (E))));
+
+ if Nkind (E) in N_Op
+ and then Present (Entity (E))
+ and then Present (Scope (Entity (E)))
+ then
+ Mark_Use_Package (Scope (Entity (E)));
+ end if;
+
+ Curr := Current_Use_Clause (Base_Type (Etype (E)));
+ while Present (Curr)
+ and then not Is_Effective_Use_Clause (Curr)
+ loop
+ -- Current use_type_clause may render other use_package_clauses
+ -- effective.
+
+ if Nkind (Subtype_Mark (Curr)) /= N_Identifier
+ and then Present (Prefix (Subtype_Mark (Curr)))
+ then
+ Mark_Use_Package (Entity (Prefix (Subtype_Mark (Curr))));
end if;
- end;
- elsif Nkind (Unit (Cunit (Current_Sem_Unit))) = N_Package_Declaration
- and then Present (Parent_Spec (Unit (Cunit (Current_Sem_Unit))))
- then
- -- Use_clause is in child unit of current unit, and the child unit
- -- appears in the context of the body of the parent, so it has been
- -- installed first, even though it is the redundant one. Depending on
- -- their placement in the context, the visible or the private parts
- -- of the two units, either might appear as redundant, but the
- -- message has to be on the current unit.
-
- if Get_Source_Unit (Cur_Use) = Current_Sem_Unit then
- Redundant := Cur_Use;
- Prev_Use := Clause;
- else
- Redundant := Clause;
- Prev_Use := Cur_Use;
+ -- Mark the use_type_clause as effective and move up the chain
+
+ Set_Is_Effective_Use_Clause (Curr);
+
+ Curr := Prev_Use_Clause (Curr);
+ end loop;
+ end Mark_Use_Type;
+
+ -- Start of processing for Mark_Use_Clauses
+
+ begin
+ -- Use clauses in and of themselves do not count as a "use" of a
+ -- package.
+
+ if Nkind_In (Parent (Id), N_Use_Package_Clause, N_Use_Type_Clause) then
+ return;
+ end if;
+
+ -- Handle entities
+
+ if Nkind (Id) in N_Entity then
+
+ -- Mark the entity's package
+
+ if Is_Potentially_Use_Visible (Id) then
+ Mark_Use_Package (Scope (Id));
end if;
- -- If the new use clause appears in the private part of a parent unit
- -- it may appear to be redundant w.r.t. a use clause in a child unit,
- -- but the previous use clause was needed in the visible part of the
- -- child, and no warning should be emitted.
+ -- Mark enumeration literals
- if Nkind (Parent (Decl)) = N_Package_Specification
- and then
- List_Containing (Decl) = Private_Declarations (Parent (Decl))
+ if Ekind (Id) = E_Enumeration_Literal then
+ Mark_Use_Type (Id);
+
+ -- Mark primitives
+
+ elsif (Ekind (Id) in Overloadable_Kind
+ or else Ekind_In (Id, E_Generic_Function,
+ E_Generic_Procedure))
+ and then (Is_Potentially_Use_Visible (Id)
+ or else Is_Intrinsic_Subprogram (Id))
then
- declare
- Par : constant Entity_Id := Defining_Entity (Parent (Decl));
- Spec : constant Node_Id :=
- Specification (Unit (Cunit (Current_Sem_Unit)));
+ Mark_Parameters (Id);
+ end if;
- begin
- if Is_Compilation_Unit (Par)
- and then Par /= Cunit_Entity (Current_Sem_Unit)
- and then Parent (Cur_Use) = Spec
- and then
- List_Containing (Cur_Use) = Visible_Declarations (Spec)
- then
- return;
- end if;
- end;
+ -- Handle nodes
+
+ else
+ -- Mark operators
+
+ if Nkind (Id) in N_Op then
+
+ -- At this point the left operand may not be resolved if we are
+ -- encountering multiple operators next to eachother in an
+ -- expression.
+
+ if Nkind (Id) in N_Binary_Op
+ and then not (Nkind (Left_Opnd (Id)) in N_Op)
+ then
+ Mark_Use_Type (Left_Opnd (Id));
+ end if;
+
+ Mark_Use_Type (Right_Opnd (Id));
+ Mark_Use_Type (Id);
+
+ -- Mark entity identifiers
+
+ elsif Nkind (Id) in N_Has_Entity
+ and then (Is_Potentially_Use_Visible (Entity (Id))
+ or else (Is_Generic_Instance (Entity (Id))
+ and then Is_Immediately_Visible (Entity (Id))))
+ then
+ -- Ignore fully qualified names as they do not count as a "use" of
+ -- a package.
+
+ if Nkind_In (Id, N_Identifier, N_Operator_Symbol)
+ or else (Present (Prefix (Id))
+ and then Scope (Entity (Id)) /= Entity (Prefix (Id)))
+ then
+ Mark_Use_Clauses (Entity (Id));
+ end if;
end if;
+ end if;
+ end Mark_Use_Clauses;
- -- Finally, if the current use clause is in the context then
- -- the clause is redundant when it is nested within the unit.
+ --------------------------------
+ -- Most_Descendant_Use_Clause --
+ --------------------------------
- elsif Nkind (Parent (Cur_Use)) = N_Compilation_Unit
- and then Nkind (Parent (Parent (Clause))) /= N_Compilation_Unit
- and then Get_Source_Unit (Cur_Use) = Get_Source_Unit (Clause)
- then
- Redundant := Clause;
- Prev_Use := Cur_Use;
+ function Most_Descendant_Use_Clause
+ (Clause1 : Entity_Id;
+ Clause2 : Entity_Id) return Entity_Id
+ is
+ Scope1, Scope2 : Entity_Id;
- else
- null;
+ begin
+ if Clause1 = Clause2 then
+ return Clause1;
end if;
- if Present (Redundant) then
- Error_Msg_Sloc := Sloc (Prev_Use);
- Error_Msg_NE -- CODEFIX
- ("& is already use-visible through previous use clause #??",
- Redundant, Pack_Name);
+ -- We determine which one is the most descendant by the scope distance
+ -- to the ultimate parent unit.
+
+ Scope1 := Entity_Of_Unit (Unit (Parent (Clause1)));
+ Scope2 := Entity_Of_Unit (Unit (Parent (Clause2)));
+ while Scope1 /= Standard_Standard
+ and then Scope2 /= Standard_Standard
+ loop
+ Scope1 := Scope (Scope1);
+ Scope2 := Scope (Scope2);
+
+ if not Present (Scope1) then
+ return Clause1;
+ elsif not Present (Scope2) then
+ return Clause2;
+ end if;
+ end loop;
+
+ if Scope1 = Standard_Standard then
+ return Clause1;
end if;
- end Note_Redundant_Use;
+
+ return Clause2;
+ end Most_Descendant_Use_Clause;
---------------
-- Pop_Scope --
@@ -8400,9 +8520,9 @@ package body Sem_Ch8 is
Scope_Stack.Decrement_Last;
end Pop_Scope;
- ---------------
+ ----------------
-- Push_Scope --
- ---------------
+ ----------------
procedure Push_Scope (S : Entity_Id) is
E : constant Entity_Id := Scope (S);
@@ -8776,7 +8896,9 @@ package body Sem_Ch8 is
and then Scope_Stack.Table (SS_Last).Entity /= Standard_Standard
and then Handle_Use
then
- Install_Use_Clauses (Scope_Stack.Table (SS_Last).First_Use_Clause);
+ Install_Use_Clauses
+ (Scope_Stack.Table (SS_Last).First_Use_Clause,
+ Force_Installation => True);
end if;
end Restore_Scope_Stack;
@@ -8873,10 +8995,7 @@ package body Sem_Ch8 is
-------------
procedure Set_Use (L : List_Id) is
- Decl : Node_Id;
- Pack_Name : Node_Id;
- Pack : Entity_Id;
- Id : Entity_Id;
+ Decl : Node_Id;
begin
if Present (L) then
@@ -8884,52 +9003,417 @@ package body Sem_Ch8 is
while Present (Decl) loop
if Nkind (Decl) = N_Use_Package_Clause then
Chain_Use_Clause (Decl);
+ Use_One_Package (Decl, Name (Decl));
+
+ elsif Nkind (Decl) = N_Use_Type_Clause then
+ Chain_Use_Clause (Decl);
+ Use_One_Type (Subtype_Mark (Decl));
+
+ end if;
+
+ Next (Decl);
+ end loop;
+ end if;
+ end Set_Use;
+
+ -----------------------------
+ -- Update_Use_Clause_Chain --
+ -----------------------------
+
+ procedure Update_Use_Clause_Chain is
+ procedure Update_Chain_In_Scope (Level : Int);
+ -- Iterate through one level in the scope stack verifying each use-type
+ -- clause within said level is used then reset the Current_Use_Clause
+ -- to a redundant use clause outside of the current ending scope if such
+ -- a clause exists.
+
+ ---------------------------
+ -- Update_Chain_In_Scope --
+ ---------------------------
+
+ procedure Update_Chain_In_Scope (Level : Int) is
+ Curr : Node_Id;
+ N : Node_Id;
+
+ begin
+ -- Loop through all use clauses within the scope dictated by Level
+
+ Curr := Scope_Stack.Table (Level).First_Use_Clause;
+ while Present (Curr) loop
+
+ -- Retrieve the subtype mark or name within the current current
+ -- use clause.
+
+ if Nkind (Curr) = N_Use_Type_Clause then
+ N := Subtype_Mark (Curr);
+ else
+ N := Name (Curr);
+ end if;
+
+ -- If warnings for unreferenced entities are enabled and the
+ -- current use clause has not been marked effective.
+
+ if Check_Unreferenced
+ and then Comes_From_Source (Curr)
+ and then not Is_Effective_Use_Clause (Curr)
+ and then not In_Instance
+ then
+ -- We are dealing with a potentially unused use_package_clause
- Pack_Name := First (Names (Decl));
- while Present (Pack_Name) loop
- Pack := Entity (Pack_Name);
+ if Nkind (Curr) = N_Use_Package_Clause then
- if Ekind (Pack) = E_Package
- and then Applicable_Use (Pack_Name)
+ -- Renamings and formal subprograms may cause the associated
+ -- to be marked as effective instead of the original.
+
+ if not (Present (Associated_Node (N))
+ and then Present
+ (Current_Use_Clause
+ (Associated_Node (N)))
+ and then Is_Effective_Use_Clause
+ (Current_Use_Clause
+ (Associated_Node (N))))
then
- Use_One_Package (Pack, Decl);
+ Error_Msg_Node_1 := Entity (N);
+ Error_Msg_NE
+ ("use clause for package & has no effect?u?",
+ Curr, Entity (N));
end if;
- Next (Pack_Name);
- end loop;
+ -- We are dealing with an unused use_type_clause
- elsif Nkind (Decl) = N_Use_Type_Clause then
- Chain_Use_Clause (Decl);
+ else
+ Error_Msg_Node_1 := Etype (N);
+ Error_Msg_NE
+ ("use clause for } has no effect?u?", Curr, Etype (N));
+ end if;
+ end if;
- Id := First (Subtype_Marks (Decl));
- while Present (Id) loop
- if Entity (Id) /= Any_Type then
- Use_One_Type (Id);
- end if;
+ -- Verify that we haven't already processed a redundant
+ -- use_type_clause within the same scope before we move the
+ -- current use clause up to a previous one for type T.
- Next (Id);
- end loop;
+ if Present (Prev_Use_Clause (Curr)) then
+ Set_Current_Use_Clause (Entity (N), Prev_Use_Clause (Curr));
end if;
- Next (Decl);
+ Curr := Next_Use_Clause (Curr);
end loop;
+ end Update_Chain_In_Scope;
+
+ -- Start of processing for Update_Use_Clause_Chain
+
+ begin
+ Update_Chain_In_Scope (Scope_Stack.Last);
+
+ -- Deal with use clauses within the context area if the current
+ -- scope is a compilation unit.
+
+ if Is_Compilation_Unit (Current_Scope)
+ and then Sloc (Scope_Stack.Table
+ (Scope_Stack.Last - 1).Entity) = Standard_Location
+ then
+ Update_Chain_In_Scope (Scope_Stack.Last - 1);
end if;
- end Set_Use;
+ end Update_Use_Clause_Chain;
---------------------
-- Use_One_Package --
---------------------
- procedure Use_One_Package (P : Entity_Id; N : Node_Id) is
+ procedure Use_One_Package
+ (N : Node_Id;
+ Pack_Name : Entity_Id := Empty;
+ Force : Boolean := False)
+ is
+ procedure Note_Redundant_Use (Clause : Node_Id);
+ -- Mark the name in a use clause as redundant if the corresponding
+ -- entity is already use-visible. Emit a warning if the use clause comes
+ -- from source and the proper warnings are enabled.
+
+ ------------------------
+ -- Note_Redundant_Use --
+ ------------------------
+
+ procedure Note_Redundant_Use (Clause : Node_Id) is
+ Decl : constant Node_Id := Parent (Clause);
+ Pack_Name : constant Entity_Id := Entity (Clause);
+
+ Cur_Use : Node_Id := Current_Use_Clause (Pack_Name);
+ Prev_Use : Node_Id := Empty;
+ Redundant : Node_Id := Empty;
+ -- The Use_Clause which is actually redundant. In the simplest case
+ -- it is Pack itself, but when we compile a body we install its
+ -- context before that of its spec, in which case it is the
+ -- use_clause in the spec that will appear to be redundant, and we
+ -- want the warning to be placed on the body. Similar complications
+ -- appear when the redundancy is between a child unit and one of its
+ -- ancestors.
+
+ begin
+ -- Could be renamed...
+
+ if No (Cur_Use) then
+ Cur_Use := Current_Use_Clause (Renamed_Entity (Pack_Name));
+ end if;
+
+ Set_Redundant_Use (Clause, True);
+
+ if not Comes_From_Source (Clause)
+ or else In_Instance
+ or else not Warn_On_Redundant_Constructs
+ then
+ return;
+ end if;
+
+ if not Is_Compilation_Unit (Current_Scope) then
+
+ -- If the use_clause is in an inner scope, it is made redundant by
+ -- some clause in the current context, with one exception: If we
+ -- are compiling a nested package body, and the use_clause comes
+ -- from then corresponding spec, the clause is not necessarily
+ -- fully redundant, so we should not warn. If a warning was
+ -- warranted, it would have been given when the spec was
+ -- processed.
+
+ if Nkind (Parent (Decl)) = N_Package_Specification then
+ declare
+ Package_Spec_Entity : constant Entity_Id :=
+ Defining_Unit_Name (Parent (Decl));
+ begin
+ if In_Package_Body (Package_Spec_Entity) then
+ return;
+ end if;
+ end;
+ end if;
+
+ Redundant := Clause;
+ Prev_Use := Cur_Use;
+
+ elsif Nkind (Unit (Cunit (Current_Sem_Unit))) = N_Package_Body then
+ declare
+ Cur_Unit : constant Unit_Number_Type :=
+ Get_Source_Unit (Cur_Use);
+ New_Unit : constant Unit_Number_Type :=
+ Get_Source_Unit (Clause);
+
+ Scop : Entity_Id;
+
+ begin
+ if Cur_Unit = New_Unit then
+
+ -- Redundant clause in same body
+
+ Redundant := Clause;
+ Prev_Use := Cur_Use;
+
+ elsif Cur_Unit = Current_Sem_Unit then
+
+ -- If the new clause is not in the current unit it has been
+ -- analyzed first, and it makes the other one redundant.
+ -- However, if the new clause appears in a subunit, Cur_Unit
+ -- is still the parent, and in that case the redundant one
+ -- is the one appearing in the subunit.
+
+ if Nkind (Unit (Cunit (New_Unit))) = N_Subunit then
+ Redundant := Clause;
+ Prev_Use := Cur_Use;
+
+ -- Most common case: redundant clause in body, original
+ -- clause in spec. Current scope is spec entity.
+
+ elsif Current_Scope = Cunit_Entity (Current_Sem_Unit) then
+ Redundant := Cur_Use;
+ Prev_Use := Clause;
+
+ else
+ -- The new clause may appear in an unrelated unit, when
+ -- the parents of a generic are being installed prior to
+ -- instantiation. In this case there must be no warning.
+ -- We detect this case by checking whether the current
+ -- top of the stack is related to the current
+ -- compilation.
+
+ Scop := Current_Scope;
+ while Present (Scop)
+ and then Scop /= Standard_Standard
+ loop
+ if Is_Compilation_Unit (Scop)
+ and then not Is_Child_Unit (Scop)
+ then
+ return;
+
+ elsif Scop = Cunit_Entity (Current_Sem_Unit) then
+ exit;
+ end if;
+
+ Scop := Scope (Scop);
+ end loop;
+
+ Redundant := Cur_Use;
+ Prev_Use := Clause;
+ end if;
+
+ elsif New_Unit = Current_Sem_Unit then
+ Redundant := Clause;
+ Prev_Use := Cur_Use;
+
+ else
+ -- Neither is the current unit, so they appear in parent or
+ -- sibling units. Warning will be emitted elsewhere.
+
+ return;
+ end if;
+ end;
+
+ elsif Nkind (Unit (Cunit (Current_Sem_Unit))) = N_Package_Declaration
+ and then Present (Parent_Spec (Unit (Cunit (Current_Sem_Unit))))
+ then
+ -- Use_clause is in child unit of current unit, and the child unit
+ -- appears in the context of the body of the parent, so it has
+ -- been installed first, even though it is the redundant one.
+ -- Depending on their placement in the context, the visible or the
+ -- private parts of the two units, either might appear as
+ -- redundant, but the message has to be on the current unit.
+
+ if Get_Source_Unit (Cur_Use) = Current_Sem_Unit then
+ Redundant := Cur_Use;
+ Prev_Use := Clause;
+ else
+ Redundant := Clause;
+ Prev_Use := Cur_Use;
+ end if;
+
+ -- If the new use clause appears in the private part of a parent
+ -- unit it may appear to be redundant w.r.t. a use clause in a
+ -- child unit, but the previous use clause was needed in the
+ -- visible part of the child, and no warning should be emitted.
+
+ if Nkind (Parent (Decl)) = N_Package_Specification
+ and then List_Containing (Decl) =
+ Private_Declarations (Parent (Decl))
+ then
+ declare
+ Par : constant Entity_Id := Defining_Entity (Parent (Decl));
+ Spec : constant Node_Id :=
+ Specification (Unit (Cunit (Current_Sem_Unit)));
+
+ begin
+ if Is_Compilation_Unit (Par)
+ and then Par /= Cunit_Entity (Current_Sem_Unit)
+ and then Parent (Cur_Use) = Spec
+ and then List_Containing (Cur_Use) =
+ Visible_Declarations (Spec)
+ then
+ return;
+ end if;
+ end;
+ end if;
+
+ -- Finally, if the current use clause is in the context then the
+ -- clause is redundant when it is nested within the unit.
+
+ elsif Nkind (Parent (Cur_Use)) = N_Compilation_Unit
+ and then Nkind (Parent (Parent (Clause))) /= N_Compilation_Unit
+ and then Get_Source_Unit (Cur_Use) = Get_Source_Unit (Clause)
+ then
+ Redundant := Clause;
+ Prev_Use := Cur_Use;
+
+ end if;
+
+ if Present (Redundant) and then Parent (Redundant) /= Prev_Use then
+
+ -- Make sure we are looking at most-descendant use_package_clause
+ -- by traversing the chain with Find_Most_Prev and then verifying
+ -- there is no scope manipulation via Most_Descendant_Use_Clause.
+
+ if Nkind (Prev_Use) = N_Use_Package_Clause
+ and then
+ (Nkind (Parent (Prev_Use)) /= N_Compilation_Unit
+ or else Most_Descendant_Use_Clause
+ (Prev_Use, Find_Most_Prev (Prev_Use)) /= Prev_Use)
+ then
+ Prev_Use := Find_Most_Prev (Prev_Use);
+ end if;
+
+ Error_Msg_Sloc := Sloc (Prev_Use);
+ Error_Msg_NE -- CODEFIX
+ ("& is already use-visible through previous use_clause #??",
+ Redundant, Pack_Name);
+ end if;
+ end Note_Redundant_Use;
+
+ -- Local variables
+
+ Current_Instance : Entity_Id := Empty;
Id : Entity_Id;
+ P : Entity_Id;
Prev : Entity_Id;
- Current_Instance : Entity_Id := Empty;
- Real_P : Entity_Id;
Private_With_OK : Boolean := False;
+ Real_P : Entity_Id;
+
+ -- Start of processing for Use_One_Package
begin
- if Ekind (P) /= E_Package then
- return;
+ -- Use_One_Package may have been called recursively to handle an
+ -- implicit use for a auxiliary system package, so set P accordingly
+ -- and skip redundancy checks.
+
+ if No (Pack_Name) and then Present_System_Aux (N) then
+ P := System_Aux_Id;
+
+ -- Check for redundant use_package_clauses
+
+ else
+ -- Ignore cases where we are dealing with a non user defined package
+ -- like Standard_Standard or something other than a valid package.
+
+ if not Is_Entity_Name (Pack_Name)
+ or else No (Entity (Pack_Name))
+ or else Ekind (Entity (Pack_Name)) /= E_Package
+ then
+ return;
+ end if;
+
+ -- When a renaming exists we must check it for redundancy. The
+ -- original package would have already been seen at this point.
+
+ if Present (Renamed_Object (Entity (Pack_Name))) then
+ P := Renamed_Object (Entity (Pack_Name));
+ else
+ P := Entity (Pack_Name);
+ end if;
+
+ -- Check for redundant clauses then set the current use clause for
+ -- P if were are not "forcing" an installation from a scope
+ -- reinstallation that is done throughout analysis for various
+ -- reasons.
+
+ if In_Use (P) then
+ Note_Redundant_Use (Pack_Name);
+
+ if not Force then
+ Set_Current_Use_Clause (P, N);
+ end if;
+
+ return;
+
+ -- Warn about detected redundant clauses
+
+ elsif In_Open_Scopes (P) and not Force then
+ if Warn_On_Redundant_Constructs and then P = Current_Scope then
+ Error_Msg_NE -- CODEFIX
+ ("& is already use-visible within itself?r?",
+ Pack_Name, P);
+ end if;
+
+ return;
+ end if;
+
+ -- Set P back to the non-renamed package so that visiblilty of the
+ -- entities within the package can be properly set below.
+
+ P := Entity (Pack_Name);
end if;
Set_In_Use (P);
@@ -8954,10 +9438,9 @@ package body Sem_Ch8 is
end if;
end if;
- -- If unit is a package renaming, indicate that the renamed
- -- package is also in use (the flags on both entities must
- -- remain consistent, and a subsequent use of either of them
- -- should be recognized as redundant).
+ -- If unit is a package renaming, indicate that the renamed package is
+ -- also in use (the flags on both entities must remain consistent, and a
+ -- subsequent use of either of them should be recognized as redundant).
if Present (Renamed_Object (P)) then
Set_In_Use (Renamed_Object (P));
@@ -9113,21 +9596,19 @@ package body Sem_Ch8 is
and then Scope (Real_P) = Standard_Standard
and then Present_System_Aux (N)
then
- Use_One_Package (System_Aux_Id, N);
+ Use_One_Package (N);
end if;
-
end Use_One_Package;
------------------
-- Use_One_Type --
------------------
- procedure Use_One_Type (Id : Node_Id; Installed : Boolean := False) is
- Elmt : Elmt_Id;
- Is_Known_Used : Boolean;
- Op_List : Elist_Id;
- T : Entity_Id;
-
+ procedure Use_One_Type
+ (Id : Node_Id;
+ Installed : Boolean := False;
+ Force : Boolean := False)
+ is
function Spec_Reloaded_For_Body return Boolean;
-- Determine whether the compilation unit is a package body and the use
-- type clause is in the spec of the same package. Even though the spec
@@ -9156,9 +9637,9 @@ package body Sem_Ch8 is
return
Nkind (Spec) = N_Package_Specification
- and then
- In_Same_Source_Unit (Corresponding_Body (Parent (Spec)),
- Cunit_Entity (Current_Sem_Unit));
+ and then In_Same_Source_Unit
+ (Corresponding_Body (Parent (Spec)),
+ Cunit_Entity (Current_Sem_Unit));
end;
end if;
@@ -9170,12 +9651,9 @@ package body Sem_Ch8 is
-------------------------------
procedure Use_Class_Wide_Operations (Typ : Entity_Id) is
- Scop : Entity_Id;
- Ent : Entity_Id;
-
function Is_Class_Wide_Operation_Of
- (Op : Entity_Id;
- T : Entity_Id) return Boolean;
+ (Op : Entity_Id;
+ T : Entity_Id) return Boolean;
-- Determine whether a subprogram has a class-wide parameter or
-- result that is T'Class.
@@ -9184,8 +9662,8 @@ package body Sem_Ch8 is
---------------------------------
function Is_Class_Wide_Operation_Of
- (Op : Entity_Id;
- T : Entity_Id) return Boolean
+ (Op : Entity_Id;
+ T : Entity_Id) return Boolean
is
Formal : Entity_Id;
@@ -9195,6 +9673,7 @@ package body Sem_Ch8 is
if Etype (Formal) = Class_Wide_Type (T) then
return True;
end if;
+
Next_Formal (Formal);
end loop;
@@ -9205,6 +9684,11 @@ package body Sem_Ch8 is
return False;
end Is_Class_Wide_Operation_Of;
+ -- Local variables
+
+ Ent : Entity_Id;
+ Scop : Entity_Id;
+
-- Start of processing for Use_Class_Wide_Operations
begin
@@ -9229,22 +9713,36 @@ package body Sem_Ch8 is
end if;
end Use_Class_Wide_Operations;
+ -- Local variables
+
+ Elmt : Elmt_Id;
+ Is_Known_Used : Boolean;
+ Op_List : Elist_Id;
+ T : Entity_Id;
+
-- Start of processing for Use_One_Type
begin
+ if Entity (Id) = Any_Type then
+ return;
+ end if;
+
-- It is the type determined by the subtype mark (8.4(8)) whose
-- operations become potentially use-visible.
T := Base_Type (Entity (Id));
- -- Either the type itself is used, the package where it is declared
- -- is in use or the entity is declared in the current package, thus
+ -- Either the type itself is used, the package where it is declared is
+ -- in use or the entity is declared in the current package, thus
-- use-visible.
Is_Known_Used :=
- In_Use (T)
- or else In_Use (Scope (T))
- or else Scope (T) = Current_Scope;
+ (In_Use (T)
+ and then ((Present (Current_Use_Clause (T))
+ and then All_Present (Current_Use_Clause (T)))
+ or else not All_Present (Parent (Id))))
+ or else In_Use (Scope (T))
+ or else Scope (T) = Current_Scope;
Set_Redundant_Use (Id,
Is_Known_Used or else Is_Potentially_Use_Visible (T));
@@ -9255,7 +9753,7 @@ package body Sem_Ch8 is
elsif In_Open_Scopes (Scope (T)) then
null;
- -- A limited view cannot appear in a use_type clause. However, an access
+ -- A limited view cannot appear in a use_type_clause. However, an access
-- type whose designated type is limited has the flag but is not itself
-- a limited view unless we only have a limited view of its enclosing
-- package.
@@ -9274,24 +9772,37 @@ package body Sem_Ch8 is
-- even if it is redundant at the place of the instantiation.
elsif Redundant_Use (Id) then
+
+ -- We must avoid incorrectly setting the Current_Use_Clause when we
+ -- are working with a redundant clause that has already been linked
+ -- in the Prev_Use_Clause chain, otherwise the chain will break.
+
+ if Present (Current_Use_Clause (T))
+ and then Present (Prev_Use_Clause (Current_Use_Clause (T)))
+ and then Parent (Id) = Prev_Use_Clause (Current_Use_Clause (T))
+ then
+ null;
+ else
+ Set_Current_Use_Clause (T, Parent (Id));
+ end if;
+
Set_Used_Operations (Parent (Id), New_Elmt_List);
-- If the subtype mark designates a subtype in a different package,
-- we have to check that the parent type is visible, otherwise the
- -- use type clause is a noop. Not clear how to do that???
+ -- use_type_clause is a no-op. Not clear how to do that???
else
+ Set_Current_Use_Clause (T, Parent (Id));
Set_In_Use (T);
- -- If T is tagged, primitive operators on class-wide operands
- -- are also available.
+ -- If T is tagged, primitive operators on class-wide operands are
+ -- also available.
if Is_Tagged_Type (T) then
Set_In_Use (Class_Wide_Type (T));
end if;
- Set_Current_Use_Clause (T, Parent (Id));
-
-- Iterate over primitive operations of the type. If an operation is
-- already use_visible, it is the result of a previous use_clause,
-- and already appears on the corresponding entity chain. If the
@@ -9335,7 +9846,8 @@ package body Sem_Ch8 is
-- If warning on redundant constructs, check for unnecessary WITH
- if Warn_On_Redundant_Constructs
+ if not Force
+ and then Warn_On_Redundant_Constructs
and then Is_Known_Used
-- with P; with P; use P;
@@ -9362,39 +9874,19 @@ package body Sem_Ch8 is
if Present (Current_Use_Clause (T)) then
Use_Clause_Known : declare
- Clause1 : constant Node_Id := Parent (Id);
- Clause2 : constant Node_Id := Current_Use_Clause (T);
+ Clause1 : constant Node_Id :=
+ Find_Most_Prev (Current_Use_Clause (T));
+ Clause2 : constant Node_Id := Parent (Id);
Ent1 : Entity_Id;
Ent2 : Entity_Id;
Err_No : Node_Id;
Unit1 : Node_Id;
Unit2 : Node_Id;
- function Entity_Of_Unit (U : Node_Id) return Entity_Id;
- -- Return the appropriate entity for determining which unit
- -- has a deeper scope: the defining entity for U, unless U
- -- is a package instance, in which case we retrieve the
- -- entity of the instance spec.
-
- --------------------
- -- Entity_Of_Unit --
- --------------------
-
- function Entity_Of_Unit (U : Node_Id) return Entity_Id is
- begin
- if Nkind (U) = N_Package_Instantiation
- and then Analyzed (U)
- then
- return Defining_Entity (Instance_Spec (U));
- else
- return Defining_Entity (U);
- end if;
- end Entity_Of_Unit;
-
-- Start of processing for Use_Clause_Known
begin
- -- If both current use type clause and the use type clause
+ -- If both current use_type_clause and the use_type_clause
-- for the type are at the compilation unit level, one of
-- the units must be an ancestor of the other, and the
-- warning belongs on the descendant.
@@ -9418,14 +9910,7 @@ package body Sem_Ch8 is
-- of the other, or one of them is in a subunit, report
-- redundancy on the later one.
- if Unit1 = Unit2 then
- Error_Msg_Sloc := Sloc (Current_Use_Clause (T));
- Error_Msg_NE -- CODEFIX
- ("& is already use-visible through previous "
- & "use_type_clause #??", Clause1, T);
- return;
-
- elsif Nkind (Unit1) = N_Subunit then
+ if Unit1 = Unit2 or else Nkind (Unit1) = N_Subunit then
Error_Msg_Sloc := Sloc (Current_Use_Clause (T));
Error_Msg_NE -- CODEFIX
("& is already use-visible through previous "
@@ -9443,7 +9928,7 @@ package body Sem_Ch8 is
return;
end if;
- -- There is a redundant use type clause in a child unit.
+ -- There is a redundant use_type_clause in a child unit.
-- Determine which of the units is more deeply nested.
-- If a unit is a package instance, retrieve the entity
-- and its scope from the instance spec.
@@ -9465,7 +9950,8 @@ package body Sem_Ch8 is
else
declare
- S1, S2 : Entity_Id;
+ S1 : Entity_Id;
+ S2 : Entity_Id;
begin
S1 := Scope (Ent1);
@@ -9489,34 +9975,44 @@ package body Sem_Ch8 is
end;
end if;
- Error_Msg_NE -- CODEFIX
- ("& is already use-visible through previous "
- & "use_type_clause #??", Err_No, Id);
+ if Parent (Id) /= Err_No then
+ if Most_Descendant_Use_Clause
+ (Err_No, Parent (Id)) = Parent (Id)
+ then
+ Error_Msg_Sloc := Sloc (Err_No);
+ Err_No := Parent (Id);
+ end if;
+
+ Error_Msg_NE -- CODEFIX
+ ("& is already use-visible through previous "
+ & "use_type_clause #??", Err_No, Id);
+ end if;
- -- Case where current use type clause and the use type
- -- clause for the type are not both at the compilation unit
- -- level. In this case we don't have location information.
+ -- Case where current use_type_clause and use_type_clause
+ -- for the type are not both at the compilation unit level.
+ -- In this case we don't have location information.
else
Error_Msg_NE -- CODEFIX
("& is already use-visible through previous "
- & "use type clause??", Id, T);
+ & "use_type_clause??", Id, T);
end if;
end Use_Clause_Known;
- -- Here if Current_Use_Clause is not set for T, another case
- -- where we do not have the location information available.
+ -- Here if Current_Use_Clause is not set for T, another case where
+ -- we do not have the location information available.
else
Error_Msg_NE -- CODEFIX
("& is already use-visible through previous "
- & "use type clause??", Id, T);
+ & "use_type_clause??", Id, T);
end if;
-- The package where T is declared is already used
elsif In_Use (Scope (T)) then
- Error_Msg_Sloc := Sloc (Current_Use_Clause (Scope (T)));
+ Error_Msg_Sloc :=
+ Sloc (Find_Most_Prev (Current_Use_Clause (Scope (T))));
Error_Msg_NE -- CODEFIX
("& is already use-visible through package use clause #??",
Id, T);
diff --git a/gcc/ada/sem_ch8.ads b/gcc/ada/sem_ch8.ads
index ae63e17..bee5f49 100644
--- a/gcc/ada/sem_ch8.ads
+++ b/gcc/ada/sem_ch8.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -52,8 +52,16 @@ package Sem_Ch8 is
procedure Analyze_Object_Renaming (N : Node_Id);
procedure Analyze_Package_Renaming (N : Node_Id);
procedure Analyze_Subprogram_Renaming (N : Node_Id);
- procedure Analyze_Use_Package (N : Node_Id);
- procedure Analyze_Use_Type (N : Node_Id);
+
+ procedure Analyze_Use_Package (N : Node_Id; Chain : Boolean := True);
+ -- Analyze a use package clause and control (through the Chain parameter)
+ -- whether to add N to the use clause chain for the name denoted within
+ -- use clause N in case we are reanalyzing a use clause because of stack
+ -- manipulation.
+
+ procedure Analyze_Use_Type (N : Node_Id; Chain : Boolean := True);
+ -- Similar to Analyze_Use_Package except the Chain parameter applies to the
+ -- type within N's subtype mark Current_Use_Clause.
procedure End_Scope;
-- Called at end of scope. On exit from blocks and bodies (subprogram,
@@ -131,6 +139,10 @@ package Sem_Ch8 is
-- Analyze_Subunit.Re_Install_Use_Clauses to insure that, after the
-- analysis of the subunit, the parent's environment is again identical.
+ procedure Mark_Use_Clauses (Id : Node_Or_Entity_Id);
+ -- Mark a given entity or node Id's relevant use clauses as effective,
+ -- including redundant ones and ones outside of the current scope.
+
procedure Push_Scope (S : Entity_Id);
-- Make new scope stack entry, pushing S, the entity for a scope onto the
-- top of the scope table. The current setting of the scope suppress flags
@@ -174,6 +186,10 @@ package Sem_Ch8 is
-- and set the potentially use-visible flags of imported entities before
-- analyzing the corresponding package body.
+ procedure Update_Use_Clause_Chain;
+ -- Called at the end of a declarative region to detect unused use type
+ -- clauses and maintain the Current_Use_Clause for type entities.
+
procedure ws;
-- Debugging routine for use in gdb: dump all entities on scope stack
diff --git a/gcc/ada/sem_ch9.adb b/gcc/ada/sem_ch9.adb
index 2fb8ebd..199cd8a 100644
--- a/gcc/ada/sem_ch9.adb
+++ b/gcc/ada/sem_ch9.adb
@@ -50,6 +50,7 @@ with Sem_Ch5; use Sem_Ch5;
with Sem_Ch6; use Sem_Ch6;
with Sem_Ch8; use Sem_Ch8;
with Sem_Ch13; use Sem_Ch13;
+with Sem_Elab; use Sem_Elab;
with Sem_Eval; use Sem_Eval;
with Sem_Prag; use Sem_Prag;
with Sem_Res; use Sem_Res;
@@ -1447,6 +1448,7 @@ package body Sem_Ch9 is
-- Process the end label, and terminate the scope
Process_End_Label (Handled_Statement_Sequence (N), 't', Entry_Name);
+ Update_Use_Clause_Chain;
End_Scope;
-- If this is an entry family, remove the loop created to provide
@@ -1655,6 +1657,14 @@ package body Sem_Ch9 is
Set_SPARK_Pragma_Inherited (Def_Id);
end if;
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => Def_Id,
+ Checks => True);
+
-- Process formals
if Present (Formals) then
@@ -1851,6 +1861,7 @@ package body Sem_Ch9 is
Check_Completion (Body_Id);
Check_References (Spec_Id);
Process_End_Label (N, 't', Ref_Id);
+ Update_Use_Clause_Chain;
End_Scope;
-- When a Lock_Free aspect specification/pragma forces the lock-free
@@ -2279,6 +2290,15 @@ package body Sem_Ch9 is
Synch_Type : Entity_Id;
begin
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => N,
+ Checks => True,
+ Modes => True);
+
Tasking_Used := True;
Check_SPARK_05_Restriction ("requeue statement is not allowed", N);
Check_Restriction (No_Requeue_Statements, N);
@@ -2551,6 +2571,12 @@ package body Sem_Ch9 is
Error_Msg_N
("target protected object of requeue must be a variable", N);
end if;
+
+ -- A requeue statement is treated as a call for purposes of ABE checks
+ -- and diagnostics. Annotate the tree by creating a call marker in case
+ -- the requeue statement is transformed by expansion.
+
+ Build_Call_Marker (N);
end Analyze_Requeue;
------------------------------
@@ -2834,6 +2860,14 @@ package body Sem_Ch9 is
Set_SPARK_Pragma (Obj_Id, SPARK_Mode_Pragma);
Set_SPARK_Pragma_Inherited (Obj_Id);
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => Obj_Id,
+ Checks => True);
+
-- Instead of calling Analyze on the new node, call the proper analysis
-- procedure directly. Otherwise the node would be expanded twice, with
-- disastrous result.
@@ -2991,6 +3025,7 @@ package body Sem_Ch9 is
end;
Process_End_Label (HSS, 't', Ref_Id);
+ Update_Use_Clause_Chain;
End_Scope;
end Analyze_Task_Body;
@@ -3096,6 +3131,14 @@ package body Sem_Ch9 is
Set_SPARK_Pragma_Inherited (T);
Set_SPARK_Aux_Pragma_Inherited (T);
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => T,
+ Checks => True);
+
Push_Scope (T);
if Ada_Version >= Ada_2005 then
diff --git a/gcc/ada/sem_dim.adb b/gcc/ada/sem_dim.adb
index 6330703..a271ca5 100644
--- a/gcc/ada/sem_dim.adb
+++ b/gcc/ada/sem_dim.adb
@@ -518,25 +518,17 @@ package body Sem_Dim is
Position : Dimension_Position)
is
begin
- -- Integer case
-
- if Is_Integer_Type (Def_Id) then
-
- -- Dimension value must be an integer literal
-
- if Nkind (Expr) = N_Integer_Literal then
- Dimensions (Position) := +Whole (UI_To_Int (Intval (Expr)));
- else
- Error_Msg_N ("integer literal expected", Expr);
- end if;
+ Dimensions (Position) := Create_Rational_From (Expr, True);
+ Processed (Position) := True;
- -- Float case
+ -- If the dimensioned root type is an integer type, it is not
+ -- particularly useful, and fractional dimensions do not make
+ -- much sense for such types, so previously we used to reject
+ -- dimensions of integer types that were not integer literals.
+ -- However, the manipulation of dimensions does not depend on
+ -- the kind of root type, so we can accept this usage for rare
+ -- cases where dimensions are specified for integer values.
- else
- Dimensions (Position) := Create_Rational_From (Expr, True);
- end if;
-
- Processed (Position) := True;
end Extract_Power;
------------------------
@@ -1585,6 +1577,20 @@ package body Sem_Dim is
then
null;
+ -- Numeric literal case. Issue a warning to indicate the
+ -- literal is treated as if its dimension matches the type
+ -- dimension.
+
+ elsif Nkind_In (Original_Node (L), N_Integer_Literal,
+ N_Real_Literal)
+ then
+ Dim_Warning_For_Numeric_Literal (L, Etype (R));
+
+ elsif Nkind_In (Original_Node (R), N_Integer_Literal,
+ N_Real_Literal)
+ then
+ Dim_Warning_For_Numeric_Literal (R, Etype (L));
+
else
Error_Dim_Msg_For_Binary_Op (N, L, R);
end if;
@@ -2732,6 +2738,24 @@ package body Sem_Dim is
procedure Dim_Warning_For_Numeric_Literal (N : Node_Id; Typ : Entity_Id) is
begin
+ -- Consider the literal zero (integer 0 or real 0.0) to be of any
+ -- dimension.
+
+ case Nkind (Original_Node (N)) is
+ when N_Real_Literal =>
+ if Expr_Value_R (N) = Ureal_0 then
+ return;
+ end if;
+
+ when N_Integer_Literal =>
+ if Expr_Value (N) = Uint_0 then
+ return;
+ end if;
+
+ when others =>
+ null;
+ end case;
+
-- Initialize name buffer
Name_Len := 0;
diff --git a/gcc/ada/sem_elab.adb b/gcc/ada/sem_elab.adb
index 7be57cf..8dec428 100644
--- a/gcc/ada/sem_elab.adb
+++ b/gcc/ada/sem_elab.adb
@@ -24,31 +24,28 @@
------------------------------------------------------------------------------
with Atree; use Atree;
-with Checks; use Checks;
with Debug; use Debug;
with Einfo; use Einfo;
-with Elists; use Elists;
with Errout; use Errout;
+with Exp_Ch11; use Exp_Ch11;
with Exp_Tss; use Exp_Tss;
with Exp_Util; use Exp_Util;
-with Expander; use Expander;
with Lib; use Lib;
with Lib.Load; use Lib.Load;
with Namet; use Namet;
with Nlists; use Nlists;
with Nmake; use Nmake;
with Opt; use Opt;
-with Output; use Output;
with Restrict; use Restrict;
with Rident; use Rident;
+with Rtsfind; use Rtsfind;
with Sem; use Sem;
with Sem_Aux; use Sem_Aux;
-with Sem_Cat; use Sem_Cat;
with Sem_Ch7; use Sem_Ch7;
with Sem_Ch8; use Sem_Ch8;
+with Sem_Prag; use Sem_Prag;
with Sem_Util; use Sem_Util;
with Sinfo; use Sinfo;
-with Sinput; use Sinput;
with Snames; use Snames;
with Stand; use Stand;
with Table;
@@ -56,3795 +53,8437 @@ with Tbuild; use Tbuild;
with Uintp; use Uintp;
with Uname; use Uname;
+with GNAT.HTable; use GNAT.HTable;
+
package body Sem_Elab is
- -- The following table records the recursive call chain for output in the
- -- Output routine. Each entry records the call node and the entity of the
- -- called routine. The number of entries in the table (i.e. the value of
- -- Elab_Call.Last) indicates the current depth of recursion and is used to
- -- identify the outer level.
+ -----------------------------------------
+ -- Access-before-elaboration mechanism --
+ -----------------------------------------
+
+ -- The access-before-elaboration (ABE) mechanism implemented in this unit
+ -- has the following objectives:
+ --
+ -- * Diagnose at compile-time or install run-time checks to prevent ABE
+ -- access to data and behaviour.
+ --
+ -- The high level idea is to accurately diagnose ABE issues within a
+ -- single unit because the ABE mechanism can inspect the whole unit.
+ -- As soon as the elaboration graph extends to an external unit, the
+ -- diagnostics stop because the body of the unit may not be available.
+ -- Due to control and data flow, the ABE mechanism cannot accurately
+ -- determine whether a particular scenario will be elaborated or not.
+ -- Conditional ABE checks are therefore used to verify the elaboration
+ -- status of a local and external target at run time.
+ --
+ -- * Supply elaboration dependencies for a unit to binde
+ --
+ -- The ABE mechanism registers each outgoing elaboration edge for the
+ -- main unit in its ALI file. GNATbind and binde can then reconstruct
+ -- the full elaboration graph and determine the proper elaboration
+ -- order for all units in the compilation.
+ --
+ -- The ABE mechanism supports three models of elaboration:
+ --
+ -- * Dynamic model - This is the most permissive of the three models.
+ -- When the dynamic model is in effect, the mechanism performs very
+ -- little diagnostics and generates run-time checks to detect ABE
+ -- issues. The behaviour of this model is identical to that specified
+ -- by the Ada RM. This model is enabled with switch -gnatE.
+ --
+ -- * Static model - This is the middle ground of the three models. When
+ -- the static model is in effect, the mechanism diagnoses and installs
+ -- run-time checks to detect ABE issues in the main unit. In addition,
+ -- the mechanism generates implicit Elaborate or Elaborate_All pragmas
+ -- to ensure the prior elaboration of withed units. The model employs
+ -- textual order, with clause context, and elaboration-related source
+ -- pragmas. This is the default model.
+ --
+ -- * SPARK model - This is the most conservative of the three models and
+ -- impelements the semantics defined in SPARK RM 7.7. The SPARK model
+ -- is in effect only when a context resides in a SPARK_Mode On region,
+ -- otherwise the mechanism falls back to one of the previous models.
+ --
+ -- The ABE mechanism consists of a "recording" phase and a "processing"
+ -- phase.
+
+ -----------------
+ -- Terminology --
+ -----------------
+
+ -- * Bridge target - A type of target. A bridge target is a link between
+ -- scenarios. It is usually a byproduct of expansion and does not have
+ -- any direct ABE ramifications.
+ --
+ -- * Call marker - A special node used to indicate the presence of a call
+ -- in the tree in case expansion transforms or eliminates the original
+ -- call. N_Call_Marker nodes do not have static and run-time semantics.
+ --
+ -- * Conditional ABE - A type of ABE. A conditional ABE occurs when the
+ -- elaboration or invocation of a target by a scenario within the main
+ -- unit causes an ABE, but does not cause an ABE for another scenarios
+ -- within the main unit.
+ --
+ -- * Declaration level - A type of enclosing level. A scenario or target is
+ -- at the declaration level when it appears within the declarations of a
+ -- block statement, entry body, subprogram body, or task body, ignoring
+ -- enclosing packges.
+ --
+ -- * Generic library level - A type of enclosing level. A scenario or
+ -- target is at the generic library level if it appears in a generic
+ -- package library unit, ignoring enclosing packages.
+ --
+ -- * Guaranteed ABE - A type of ABE. A guaranteed ABE occurs when the
+ -- elaboration or invocation of a target by all scenarios within the
+ -- main unit causes an ABE.
+ --
+ -- * Instantiation library level - A type of enclosing level. A scenario
+ -- or target is at the instantiation library level if it appears in an
+ -- instantiation library unit, ignoring enclosing packages.
+ --
+ -- * Library level - A type of enclosing level. A scenario or target is at
+ -- the library level if it appears in a package library unit, ignoring
+ -- enclosng packages.
+ --
+ -- * Non-library level encapsulator - A construct that cannot be elaborated
+ -- on its own and requires elaboration by a top level scenario.
+ --
+ -- * Scenario - A construct or context which may be elaborated or executed
+ -- by elaboration code. The scenarios recognized by the ABE mechanism are
+ -- as follows:
+ --
+ -- - '[Unrestricted_]Access of entries, operators, and subprograms
+ --
+ -- - Assignments to variables
+ --
+ -- - Calls to entries, operators, and subprograms
+ --
+ -- - Instantiations
+ --
+ -- - Reads of variables
+ --
+ -- - Task activation
+ --
+ -- * Target - A construct referenced by a scenario. The targets recognized
+ -- by the ABE mechanism are as follows:
+ --
+ -- - For '[Unrestricted_]Access of entries, operators, and subprograms,
+ -- the target is the entry, operator, or subprogram.
+ --
+ -- - For assignments to variables, the target is the variable
+ --
+ -- - For calls, the target is the entry, operator, or subprogram
+ --
+ -- - For instantiations, the target is the generic template
+ --
+ -- - For reads of variables, the target is the variable
+ --
+ -- - For task activation, the target is the task body
+ --
+ -- * Top level scenario - A scenario which appears in a non-generic main
+ -- unit. Depending on the elaboration model is in effect, the following
+ -- addotional restrictions apply:
+ --
+ -- - Dynamic model - No restrictions
+ --
+ -- - SPARK model - Falls back to either the dynamic or static model
+ --
+ -- - Static model - The scenario must be at the library level
+
+ ---------------------
+ -- Recording phase --
+ ---------------------
+
+ -- The Recording phase coincides with the analysis/resolution phase of the
+ -- compiler. It has the following objectives:
+ --
+ -- * Record all top level scenarios for examination by the Processing
+ -- phase.
+ --
+ -- Saving only a certain number of nodes improves the performance of
+ -- the ABE mechanism. This eliminates the need to examine the whole
+ -- tree in a separate pass.
+ --
+ -- * Detect and diagnose calls in preelaborable or pure units, including
+ -- generic bodies.
+ --
+ -- This diagnostic is carried out during the Recording phase because it
+ -- does not need the heavy recursive traversal done by the Processing
+ -- phase.
+ --
+ -- * Detect and diagnose guaranteed ABEs caused by instantiations,
+ -- calls, and task activation.
+ --
+ -- The issues detected by the ABE mechanism are reported as warnings
+ -- because they do not violate Ada semantics. Forward instantiations
+ -- may thus reach gigi, however gigi cannot handle certain kinds of
+ -- premature instantiations and may crash. To avoid this limitation,
+ -- the ABE mechanism must identify forward instantiations as early as
+ -- possible and suppress their bodies. Calls and task activations are
+ -- included in this category for completeness.
+
+ ----------------------
+ -- Processing phase --
+ ----------------------
+
+ -- The Processing phase is a separate pass which starts after instantiating
+ -- and/or inlining of bodies, but before the removal of Ghost code. It has
+ -- the following objectives:
+ --
+ -- * Examine all top level scenarios saved during the Recording phase
+ --
+ -- The top level scenarios act as roots for depth-first traversal of
+ -- the call/instantiation/task activation graph. The traversal stops
+ -- when an outgoing edge leaves the main unit.
+ --
+ -- * Depending on the elaboration model in effect, perform the following
+ -- actions:
+ --
+ -- - Dynamic model - Diagnose guaranteed ABEs and install run-time
+ -- conditional ABE checks.
+ --
+ -- - SPARK model - Enforce the SPARK elaboration rules
+ --
+ -- - Static model - Diagnose conditional/guaranteed ABEs, install
+ -- run-time conditional ABE checks, and guarantee the elaboration
+ -- of external units.
+ --
+ -- * Examine nested scenarios
+ --
+ -- Nested scenarios discovered during the depth-first traversal are
+ -- in turn subjected to the same actions outlined above and examined
+ -- for the next level of nested scenarios.
+
+ ------------------
+ -- Architecture --
+ ------------------
+
+ -- +------------------------ Recording phase ---------------------------+
+ -- | |
+ -- | Record_Elaboration_Scenario |
+ -- | | |
+ -- | +--> Check_Preelaborated_Call |
+ -- | | |
+ -- | +--> Process_Guaranteed_ABE |
+ -- | | |
+ -- +------------------------- | --------------------------------------+
+ -- |
+ -- |
+ -- v
+ -- Top_Level_Scenarios
+ -- +-----------+-----------+ .. +-----------+
+ -- | Scenario1 | Scenario2 | .. | ScenarioN |
+ -- +-----------+-----------+ .. +-----------+
+ -- |
+ -- |
+ -- +------------------------- | --------------------------------------+
+ -- | | |
+ -- | Check_Elaboration_Scenarios |
+ -- | | |
+ -- | v |
+ -- | +----------- Process_Scenario <-----------+ |
+ -- | | | |
+ -- | +--> Process_Access Is_Suitable_Scenario |
+ -- | | ^ |
+ -- | +--> Process_Activation_Call --+ | |
+ -- | | +---> Traverse_Body |
+ -- | +--> Process_Call -------------+ |
+ -- | | |
+ -- | +--> Process_Instantiation |
+ -- | | |
+ -- | +--> Process_Variable_Assignment |
+ -- | | |
+ -- | +--> Process_Variable_Read |
+ -- | |
+ -- +------------------------- Processing phase -------------------------+
+
+ ----------------------
+ -- Important points --
+ ----------------------
+
+ -- The Processing phase starts after the analysis, resolution, expansion
+ -- phase has completed. As a result, no current semantic information is
+ -- available. The scope stack is empty, global flags such as In_Instance
+ -- or Inside_A_Generic become useless. To remedy this, the ABE mechanism
+ -- must either save or recompute semantic information.
+
+ -- Expansion heavily transforms calls and to some extent instantiations. To
+ -- remedy this, the ABE mechanism generates N_Call_Marker nodes in order to
+ -- capture the target and relevant attributes of the original call.
+
+ -- The diagnostics of the ABE mechanism depend on accurate source locations
+ -- to determine the spacial relation of nodes.
+
+ --------------
+ -- Switches --
+ --------------
+
+ -- The following switches may be used to control the behavior of the ABE
+ -- mechanism.
+ --
+ -- -gnatdE elaboration checks on predefined units
+ --
+ -- The ABE mechanism considers scenarios which appear in internal
+ -- units (Ada, GNAT, Interfaces, System).
+ --
+ -- -gnatd.G ignore calls through generic formal parameters for elaboration
+ --
+ -- The ABE mechanism does not generate N_Call_Marker nodes for
+ -- calls which occur in expanded instances, and invoke generic
+ -- actual subprograms through generic formal subprograms. As a
+ -- result, the calls are not recorded or processed.
+ --
+ -- If switches -gnatd.G and -gnatdL are used together, then the
+ -- ABE mechanism effectively ignores all calls which cause the
+ -- elaboration flow to "leave" the instance.
+ --
+ -- -gnatdL ignore external calls from instances for elaboration
+ --
+ -- The ABE mechanism does not generate N_Call_Marker nodes for
+ -- calls which occur in expanded instances, do not invoke generic
+ -- actual subprograms through formal subprograms, and the target
+ -- is external to the instance. As a result, the calls are not
+ -- recorded or processed.
+ --
+ -- If switches -gnatd.G and -gnatdL are used together, then the
+ -- ABE mechanism effectively ignores all calls which cause the
+ -- elaboration flow to "leave" the instance.
+ --
+ -- -gnatd.o conservative elaboration order for indirect calls
+ --
+ -- The ABE mechanism treats '[Unrestricted_]Access of an entry,
+ -- operator, or subprogram as an immediate invocation of the
+ -- target. As a result, it performs ABE checks and diagnostics on
+ -- the immediate call.
+ --
+ -- -gnatd.U ignore indirect calls for static elaboration
+ --
+ -- The ABE mechanism does not consider '[Unrestricted_]Access of
+ -- entries, operators, and subprograms. As a result, the scenarios
+ -- are not recorder or processed.
+ --
+ -- -gnatd.v enforce SPARK elaboration rules in SPARK code
+ --
+ -- The ABE mechanism applies some of the SPARK elaboration rules
+ -- defined in the SPARK reference manual, chapter 7.7. Note that
+ -- certain rules are always enforced, regardless of whether the
+ -- switch is active.
+ --
+ -- -gnatd.y disable implicit pragma Elaborate_All on task bodies
+ --
+ -- The ABE mechanism does not generate implicit Elaborate_All when
+ -- the need for the pragma came from a task body.
+ --
+ -- -gnatE dynamic elaboration checking mode enabled
+ --
+ -- The ABE mechanism assumes that any scenario is elaborated or
+ -- invoked by elaboration code. The ABE mechanism performs very
+ -- little diagnostics and generates condintional ABE checks to
+ -- detect ABE issues at run-time.
+ --
+ -- -gnatel turn on info messages on generated Elaborate[_All] pragmas
+ --
+ -- The ABE mechanism produces information messages on generated
+ -- implicit Elabote[_All] pragmas along with traceback showing
+ -- why the pragma was generated. In addition, the ABE mechanism
+ -- produces information messages for each scenario elaborated or
+ -- invoked by elaboration code.
+ --
+ -- -gnateL turn off info messages on generated Elaborate[_All] pragmas
+ --
+ -- The complimentary switch for -gnatel.
+ --
+ -- -gnatwl turn on warnings for elaboration problems
+ --
+ -- The ABE mechanism produces warnings on detected ABEs along with
+ -- traceback showing the graph of the ABE.
+ --
+ -- -gnatwL turn off warnings for elaboration problems
+ --
+ -- The complimentary switch for -gnatwl.
+ --
+ -- -gnatw.f turn on warnings for suspicious Subp'Access
+ --
+ -- The ABE mechanism treats '[Unrestricted_]Access of an entry,
+ -- operator, or subprogram as a pseudo invocation of the target.
+ -- As a result, it performs ABE diagnostics on the pseudo call.
+ --
+ -- -gnatw.F turn off warnings for suspicious Subp'Access
+ --
+ -- The complimentary switch for -gnatw.f.
+
+ ---------------------------
+ -- Adding a new scenario --
+ ---------------------------
+
+ -- The following steps describe how to add a new elaboration scenario and
+ -- preserve the existing architecture.
+ --
+ -- 1) If necessary, update predicates Is_Check_Emitting_Scenario and
+ -- Is_Scenario.
+ --
+ -- 2) Add predicate Is_Suitable_xxx. Include a call to it in predicate
+ -- Is_Suitable_Scenario.
+ --
+ -- 3) Update routine Record_Elaboration_Scenario
+ --
+ -- 4) Add routine Process_xxx. Include a call to it in Process_Scenario.
+ --
+ -- 5) Add routine Info_xxx. Include a call to it in Process_xxx.
+ --
+ -- 6) Add routine Output_xxx. Include a call to it in routine
+ -- Output_Active_Scenarios.
+ --
+ -- 7) If necessary, add a new Extract_xxx_Attributes routine
+ --
+ -- 8) If necessary, update routine Is_Potential_Scenario
+
+ -------------------------
+ -- Adding a new target --
+ -------------------------
+
+ -- The following steps describe how to add a new elaboration target and
+ -- preserve the existing architecture.
+ --
+ -- 1) Add predicate Is_xxx.
+ --
+ -- 2) Update predicates Is_Ada_Semantic_Target, Is_Bridge_Target, or
+ -- Is_SPARK_Semantic_Target. If necessary, create a new category.
+ --
+ -- 3) Update the appropriate Info_xxx routine.
+ --
+ -- 4) Update the appropriate Output_xxx routine.
+ --
+ -- 5) Update routine Extract_Target_Attributes. If necessary, create a
+ -- new Extract_xxx routine.
+
+ --------------------------
+ -- Debugging ABE issues --
+ --------------------------
+
+ -- * If the issue involves a call, ensure that the call is eligible for ABE
+ -- processing and receives a corresponding call marker. The routines of
+ -- interest are
+ --
+ -- Build_Call_Marker
+ -- Record_Elaboration_Scenario
+
+ -- * If the issue involves an arbitrary scenario, ensure that the scenario
+ -- is either recorded, or is successfully recognized while traversing a
+ -- body. The routines of interest are
+ --
+ -- Record_Elaboration_Scenario
+ -- Process_Scenario
+ -- Traverse_Body
+
+ -- * If the issue involves a circularity in the elaboration order, examine
+ -- the ALI files and look for the following encodings next to units:
+ --
+ -- E indicates a source Elaborate
+ --
+ -- EA indicates a source Elaborate_All
+ --
+ -- AD indicates an implicit Elaborate_All
+ --
+ -- ED indicates an implicit Elaborate
+ --
+ -- If possible, compare these encodings with those generated by the old
+ -- ABE mechanism. The routines of interest are
+ --
+ -- Ensure_Prior_Elaboration
+
+ ----------------
+ -- Attributes --
+ ----------------
+
+ -- The following type captures relevant attributes which pertain to a call
+
+ type Call_Attributes is record
+ Elab_Checks_OK : Boolean;
+ -- This flag is set when the call has elaboration checks enabled
- type Elab_Call_Element is record
- Cloc : Source_Ptr;
- Ent : Entity_Id;
+ From_Source : Boolean;
+ -- This flag is set when the call comes from source
+
+ Ghost_Mode_Ignore : Boolean;
+ -- This flag is set when the call appears in a region subject to pragma
+ -- Ghost with policy Ignore.
+
+ In_Declarations : Boolean;
+ -- This flag is set when the call appears at the declaration level
+
+ Is_Dispatching : Boolean;
+ -- This flag is set when the call is dispatching
+
+ SPARK_Mode_On : Boolean;
+ -- This flag is set when the call appears in a region subject to pragma
+ -- SPARK_Mode with value On.
end record;
- package Elab_Call is new Table.Table
- (Table_Component_Type => Elab_Call_Element,
- Table_Index_Type => Int,
- Table_Low_Bound => 1,
- Table_Initial => 50,
- Table_Increment => 100,
- Table_Name => "Elab_Call");
+ -- The following type captures relevant attributes which pertain to the
+ -- prior elaboration of a unit. This type is coupled together with a unit
+ -- to form a key -> value relationship.
+
+ type Elaboration_Attributes is record
+ Source_Pragma : Node_Id;
+ -- This attribute denotes a source Elaborate or Elaborate_All pragma
+ -- which guarantees the prior elaboration of some unit with respect
+ -- to the main unit. The pragma may come from the following contexts:
+
+ -- * The main unit
+ -- * The spec of the main unit (if applicable)
+ -- * Any parent spec of the main unit (if applicable)
+ -- * Any parent subunit of the main unit (if applicable)
+
+ -- The attribute remains Empty if no such pragma is available. Source
+ -- pragmas play a role in satisfying SPARK elaboration requirements.
+
+ With_Clause : Node_Id;
+ -- This attribute denotes an internally generated or source with clause
+ -- for some unit withed by the main unit. With clauses carry flags which
+ -- represent implicit Elaborate or Elaborate_All pragmas. These clauses
+ -- play a role in supplying the elaboration dependencies to binde.
+ end record;
- -- The following table records all calls that have been processed starting
- -- from an outer level call. The table prevents both infinite recursion and
- -- useless reanalysis of calls within the same context. The use of context
- -- is important because it allows for proper checks in more complex code:
+ No_Elaboration_Attributes : constant Elaboration_Attributes :=
+ (Source_Pragma => Empty,
+ With_Clause => Empty);
- -- if ... then
- -- Call; -- requires a check
- -- Call; -- does not need a check thanks to the table
- -- elsif ... then
- -- Call; -- requires a check, different context
- -- end if;
+ -- The following type captures relevant attributes which pertain to an
+ -- instantiation.
- -- Call; -- requires a check, different context
+ type Instantiation_Attributes is record
+ Elab_Checks_OK : Boolean;
+ -- This flag is set when the instantiation has elaboration checks
+ -- enabled.
- type Visited_Element is record
- Subp_Id : Entity_Id;
- -- The entity of the subprogram being called
+ Ghost_Mode_Ignore : Boolean;
+ -- This flag is set when the instantiation appears in a region subject
+ -- to pragma Ghost with policy ignore, or starts one such region.
- Context : Node_Id;
- -- The context where the call to the subprogram occurs
+ In_Declarations : Boolean;
+ -- This flag is set when the instantiation appears at the declaration
+ -- level.
+
+ SPARK_Mode_On : Boolean;
+ -- This flag is set when the instantiation appears in a region subject
+ -- to pragma SPARK_Mode with value On, or starts one such region.
end record;
- package Elab_Visited is new Table.Table
- (Table_Component_Type => Visited_Element,
- Table_Index_Type => Int,
- Table_Low_Bound => 1,
- Table_Initial => 200,
- Table_Increment => 100,
- Table_Name => "Elab_Visited");
+ -- The following type captures relevant attributes which pertain to a
+ -- target.
+
+ type Target_Attributes is record
+ Elab_Checks_OK : Boolean;
+ -- This flag is set when the target has elaboration checks enabled
+
+ From_Source : Boolean;
+ -- This flag is set when the target comes from source
+
+ Ghost_Mode_Ignore : Boolean;
+ -- This flag is set when the target appears in a region subject to
+ -- pragma Ghost with policy ignore, or starts one such region.
+
+ SPARK_Mode_On : Boolean;
+ -- This flag is set when the target appears in a region subject to
+ -- pragma SPARK_Mode with value On, or starts one such region.
+
+ Spec_Decl : Node_Id;
+ -- This attribute denotes the declaration of Spec_Id
+
+ Unit_Id : Entity_Id;
+ -- This attribute denotes the top unit where Spec_Id resides
+
+ -- The semantics of the following attributes depend on the target
+
+ Body_Barf : Node_Id;
+ Body_Decl : Node_Id;
+ Spec_Id : Entity_Id;
+
+ -- The target is a generic package or a subprogram
+ --
+ -- * Body_Barf - Empty
+ --
+ -- * Body_Decl - This attribute denotes the generic or subprogram
+ -- body.
+ --
+ -- * Spec_Id - This attribute denotes the entity of the generic
+ -- package or subprogram.
+
+ -- The target is a protected entry
+ --
+ -- * Body_Barf - This attribute denotes the body of the barrier
+ -- function if expansion took place, otherwise it is Empty.
+ --
+ -- * Body_Decl - This attribute denotes the body of the procedure
+ -- which emulates the entry if expansion took place, otherwise it
+ -- denotes the body of the protected entry.
+ --
+ -- * Spec_Id - This attribute denotes the entity of the procedure
+ -- which emulates the entry if expansion took place, otherwise it
+ -- denotes the protected entry.
+
+ -- The target is a protected subprogram
+ --
+ -- * Body_Barf - Empty
+ --
+ -- * Body_Decl - This attribute denotes the body of the protected or
+ -- unprotected version of the protected subprogram if expansion took
+ -- place, otherwise it denotes the body of the protected subprogram.
+ --
+ -- * Spec_Id - This attribute denotes the entity of the protected or
+ -- unprotected version of the protected subprogram if expansion took
+ -- place, otherwise it is the entity of the protected subprogram.
+
+ -- The target is a task entry
+ --
+ -- * Body_Barf - Empty
+ --
+ -- * Body_Decl - This attribute denotes the body of the procedure
+ -- which emulates the task body if expansion took place, otherwise
+ -- it denotes the body of the task type.
+ --
+ -- * Spec_Id - This attribute denotes the entity of the procedure
+ -- which emulates the task body if expansion took place, otherwise
+ -- it denotes the entity of the task type.
+ end record;
+
+ -- The following type captures relevant attributes which pertain to a task
+ -- type.
- -- The following table records delayed calls which must be examined after
- -- all generic bodies have been instantiated.
+ type Task_Attributes is record
+ Body_Decl : Node_Id;
+ -- This attribute denotes the declaration of the procedure body which
+ -- emulates the behaviour of the task body.
- type Delay_Element is record
- N : Node_Id;
- -- The parameter N from the call to Check_Internal_Call. Note that this
- -- node may get rewritten over the delay period by expansion in the call
- -- case (but not in the instantiation case).
+ Elab_Checks_OK : Boolean;
+ -- This flag is set when the task type has elaboration checks enabled
- E : Entity_Id;
- -- The parameter E from the call to Check_Internal_Call
+ Ghost_Mode_Ignore : Boolean;
+ -- This flag is set when the task type appears in a region subject to
+ -- pragma Ghost with policy ignore, or starts one such region.
- Orig_Ent : Entity_Id;
- -- The parameter Orig_Ent from the call to Check_Internal_Call
+ SPARK_Mode_On : Boolean;
+ -- This flag is set when the task type appears in a region subject to
+ -- pragma SPARK_Mode with value On, or starts one such region.
- Curscop : Entity_Id;
- -- The current scope of the call. This is restored when we complete the
- -- delayed call, so that we do this in the right scope.
+ Spec_Id : Entity_Id;
+ -- This attribute denotes the entity of the initial declaration of the
+ -- procedure body which emulates the behaviour of the task body.
- Outer_Scope : Entity_Id;
- -- Save scope of outer level call
+ Task_Decl : Node_Id;
+ -- This attribute denotes the declaration of the task type
+
+ Unit_Id : Entity_Id;
+ -- This attribute denotes the entity of the compilation unit where the
+ -- task type resides.
+ end record;
- From_Elab_Code : Boolean;
- -- Save indication of whether this call is from elaboration code
+ -- The following type captures relevant attributes which pertain to a
+ -- variable.
- In_Task_Activation : Boolean;
- -- Save indication of whether this call is from a task body. Tasks are
- -- activated at the "begin", which is after all local procedure bodies,
- -- so calls to those procedures can't fail, even if they occur after the
- -- task body.
+ type Variable_Attributes is record
+ SPARK_Mode_On : Boolean;
+ -- This flag is set when the variable appears in a region subject to
+ -- pragma SPARK_Mode with value On, or starts one such region.
- From_SPARK_Code : Boolean;
- -- Save indication of whether this call is under SPARK_Mode => On
+ Unit_Id : Entity_Id;
+ -- This attribute denotes the entity of the compilation unit where the
+ -- variable resides.
end record;
- package Delay_Check is new Table.Table
- (Table_Component_Type => Delay_Element,
+ ---------------------
+ -- Data structures --
+ ---------------------
+
+ -- The following table stores the elaboration status of all units withed by
+ -- the main unit.
+
+ Elaboration_Context_Max : constant := 1009;
+
+ type Elaboration_Context_Index is range 0 .. Elaboration_Context_Max - 1;
+
+ function Elaboration_Context_Hash
+ (Key : Entity_Id) return Elaboration_Context_Index;
+ -- Obtain the hash value of entity Key
+
+ package Elaboration_Context is new Simple_HTable
+ (Header_Num => Elaboration_Context_Index,
+ Element => Elaboration_Attributes,
+ No_Element => No_Elaboration_Attributes,
+ Key => Entity_Id,
+ Hash => Elaboration_Context_Hash,
+ Equal => "=");
+
+ -- The following table stores all active scenarios in a recursive traversal
+ -- starting from a top level scenario. This table must be maintained in a
+ -- FIFO fashion.
+
+ package Scenario_Stack is new Table.Table
+ (Table_Component_Type => Node_Id,
+ Table_Index_Type => Int,
+ Table_Low_Bound => 1,
+ Table_Initial => 50,
+ Table_Increment => 100,
+ Table_Name => "Scenario_Stack");
+
+ -- The following table stores all top level scenario saved during the
+ -- Recording phase. The contents of this table act as traversal roots
+ -- later in the Processing phase. This table must be maintained in a
+ -- LIFO fashion.
+
+ package Top_Level_Scenarios is new Table.Table
+ (Table_Component_Type => Node_Id,
Table_Index_Type => Int,
Table_Low_Bound => 1,
Table_Initial => 1000,
Table_Increment => 100,
- Table_Name => "Delay_Check");
-
- C_Scope : Entity_Id;
- -- Top-level scope of current scope. Compute this only once at the outer
- -- level, i.e. for a call to Check_Elab_Call from outside this unit.
-
- Outer_Level_Sloc : Source_Ptr;
- -- Save Sloc value for outer level call node for comparisons of source
- -- locations. A body is too late if it appears after the *outer* level
- -- call, not the particular call that is being analyzed.
-
- From_Elab_Code : Boolean;
- -- This flag shows whether the outer level call currently being examined
- -- is or is not in elaboration code. We are only interested in calls to
- -- routines in other units if this flag is True.
-
- In_Task_Activation : Boolean := False;
- -- This flag indicates whether we are performing elaboration checks on task
- -- bodies, at the point of activation. If true, we do not raise
- -- Program_Error for calls to local procedures, because all local bodies
- -- are known to be elaborated. However, we still need to trace such calls,
- -- because a local procedure could call a procedure in another package,
- -- so we might need an implicit Elaborate_All.
-
- Delaying_Elab_Checks : Boolean := True;
- -- This is set True till the compilation is complete, including the
- -- insertion of all instance bodies. Then when Check_Elab_Calls is called,
- -- the delay table is used to make the delayed calls and this flag is reset
- -- to False, so that the calls are processed.
+ Table_Name => "Top_Level_Scenarios");
+
+ -- The following table stores the bodies of all eligible scenarios visited
+ -- during a traversal starting from a top level scenario. The contents of
+ -- this table must be reset upon each new traversal.
+
+ Visited_Bodies_Max : constant := 511;
+
+ type Visited_Bodies_Index is range 0 .. Visited_Bodies_Max - 1;
+
+ function Visited_Bodies_Hash (Key : Node_Id) return Visited_Bodies_Index;
+ -- Obtain the hash value of node Key
+
+ package Visited_Bodies is new Simple_HTable
+ (Header_Num => Visited_Bodies_Index,
+ Element => Boolean,
+ No_Element => False,
+ Key => Node_Id,
+ Hash => Visited_Bodies_Hash,
+ Equal => "=");
-----------------------
- -- Local Subprograms --
+ -- Local subprograms --
-----------------------
- -- Note: Outer_Scope in all following specs represents the scope of
- -- interest of the outer level call. If it is set to Standard_Standard,
- -- then it means the outer level call was at elaboration level, and that
- -- thus all calls are of interest. If it was set to some other scope,
- -- then the original call was an inner call, and we are not interested
- -- in calls that go outside this scope.
-
- procedure Activate_Elaborate_All_Desirable (N : Node_Id; U : Entity_Id);
- -- Analysis of construct N shows that we should set Elaborate_All_Desirable
- -- for the WITH clause for unit U (which will always be present). A special
- -- case is when N is a function or procedure instantiation, in which case
- -- it is sufficient to set Elaborate_Desirable, since in this case there is
- -- no possibility of transitive elaboration issues.
-
- procedure Check_A_Call
- (N : Node_Id;
- E : Entity_Id;
- Outer_Scope : Entity_Id;
- Inter_Unit_Only : Boolean;
- Generate_Warnings : Boolean := True;
- In_Init_Proc : Boolean := False);
- -- This is the internal recursive routine that is called to check for
- -- possible elaboration error. The argument N is a subprogram call or
- -- generic instantiation, or 'Access attribute reference to be checked, and
- -- E is the entity of the called subprogram, or instantiated generic unit,
- -- or subprogram referenced by 'Access.
- --
- -- In SPARK mode, N can also be a variable reference, since in SPARK this
- -- also triggers a requirement for Elaborate_All, and in this case E is the
- -- entity being referenced.
- --
- -- Outer_Scope is the outer level scope for the original reference.
- -- Inter_Unit_Only is set if the call is only to be checked in the
- -- case where it is to another unit (and skipped if within a unit).
- -- Generate_Warnings is set to False to suppress warning messages about
- -- missing pragma Elaborate_All's. These messages are not wanted for
- -- inner calls in the dynamic model. Note that an instance of the Access
- -- attribute applied to a subprogram also generates a call to this
- -- procedure (since the referenced subprogram may be called later
- -- indirectly). Flag In_Init_Proc should be set whenever the current
- -- context is a type init proc.
- --
- -- Note: this might better be called Check_A_Reference to recognize the
- -- variable case for SPARK, but we prefer to retain the historical name
- -- since in practice this is mostly about checking calls for the possible
- -- occurrence of an access-before-elaboration exception.
-
- procedure Check_Bad_Instantiation (N : Node_Id);
- -- N is a node for an instantiation (if called with any other node kind,
- -- Check_Bad_Instantiation ignores the call). This subprogram checks for
- -- the special case of a generic instantiation of a generic spec in the
- -- same declarative part as the instantiation where a body is present and
- -- has not yet been seen. This is an obvious error, but needs to be checked
- -- specially at the time of the instantiation, since it is a case where we
- -- cannot insert the body anywhere. If this case is detected, warnings are
- -- generated, and a raise of Program_Error is inserted. In addition any
- -- subprograms in the generic spec are stubbed, and the Bad_Instantiation
- -- flag is set on the instantiation node. The caller in Sem_Ch12 uses this
- -- flag as an indication that no attempt should be made to insert an
- -- instance body.
-
- procedure Check_Internal_Call
+ procedure Check_Preelaborated_Call (Call : Node_Id);
+ -- Determine whether entry, operator, or subprogram call Call appears at
+ -- the library level of a preelaborated unit. Emit an error if this is the
+ -- case.
+
+ function Compilation_Unit (Unit_Id : Entity_Id) return Node_Id;
+ pragma Inline (Compilation_Unit);
+ -- Return the N_Compilation_Unit node of unit Unit_Id
+
+ procedure Elab_Msg_NE
+ (Msg : String;
+ N : Node_Id;
+ Id : Entity_Id;
+ Info_Msg : Boolean;
+ In_SPARK : Boolean);
+ pragma Inline (Elab_Msg_NE);
+ -- Wrapper around Error_Msg_NE. Emit message Msg concerning arbitrary node
+ -- N and entity. If flag Info_Msg is set, the routine emits an information
+ -- message, otherwise it emits an error. If flag In_SPARK is set, then
+ -- string " in SPARK" is added to the end of the message.
+
+ procedure Ensure_Prior_Elaboration
+ (N : Node_Id;
+ Unit_Id : Entity_Id;
+ In_Task_Body : Boolean);
+ -- Guarantee the elaboration of unit Unit_Id with respect to the main unit.
+ -- N denotes the related scenario. Flag In_Task_Body should be set when the
+ -- need for elaboration is initiated from a task body.
+
+ procedure Ensure_Prior_Elaboration_Dynamic
+ (N : Node_Id;
+ Unit_Id : Entity_Id;
+ Prag_Nam : Name_Id);
+ -- Guarantee the elaboration of unit Unit_Id with respect to the main unit
+ -- by suggesting the use of Elaborate[_All] with name Prag_Nam. N denotes
+ -- the related scenario.
+
+ procedure Ensure_Prior_Elaboration_Static
+ (N : Node_Id;
+ Unit_Id : Entity_Id;
+ Prag_Nam : Name_Id);
+ -- Guarantee the elaboration of unit Unit_Id with respect to the main unit
+ -- by installing an implicit Elaborate[_All] pragma with name Prag_Nam. N
+ -- denotes the related scenario.
+
+ function Extract_Assignment_Name (Asmt : Node_Id) return Node_Id;
+ pragma Inline (Extract_Assignment_Name);
+ -- Obtain the Name attribute of assignment statement Asmt
+
+ procedure Extract_Call_Attributes
+ (Call : Node_Id;
+ Target_Id : out Entity_Id;
+ Attrs : out Call_Attributes);
+ pragma Inline (Extract_Call_Attributes);
+ -- Obtain attributes Attrs associated with call Call. Target_Id is the
+ -- entity of the call target.
+
+ function Extract_Call_Name (Call : Node_Id) return Node_Id;
+ pragma Inline (Extract_Call_Name);
+ -- Obtain the Name attribute of entry or subprogram call Call
+
+ procedure Extract_Instance_Attributes
+ (Exp_Inst : Node_Id;
+ Inst_Body : out Node_Id;
+ Inst_Decl : out Node_Id);
+ pragma Inline (Extract_Instance_Attributes);
+ -- Obtain body Inst_Body and spec Inst_Decl of expanded instance Exp_Inst
+
+ procedure Extract_Instantiation_Attributes
+ (Exp_Inst : Node_Id;
+ Inst : out Node_Id;
+ Inst_Id : out Entity_Id;
+ Gen_Id : out Entity_Id;
+ Attrs : out Instantiation_Attributes);
+ pragma Inline (Extract_Instantiation_Attributes);
+ -- Obtain attributes Attrs associated with expanded instantiation Exp_Inst.
+ -- Inst is the instantiation. Inst_Id is the entity of the instance. Gen_Id
+ -- is the entity of the generic unit being instantiated.
+
+ procedure Extract_Target_Attributes
+ (Target_Id : Entity_Id;
+ Attrs : out Target_Attributes);
+ -- Obtain attributes Attrs associated with an entry, package, or subprogram
+ -- denoted by Target_Id.
+
+ procedure Extract_Task_Attributes
+ (Typ : Entity_Id;
+ Attrs : out Task_Attributes);
+ pragma Inline (Extract_Task_Attributes);
+ -- Obtain attributes Attrs associated with task type Typ
+
+ procedure Extract_Variable_Reference_Attributes
+ (Ref : Node_Id;
+ Var_Id : out Entity_Id;
+ Attrs : out Variable_Attributes);
+ pragma Inline (Extract_Variable_Reference_Attributes);
+ -- Obtain attributes Attrs associated with reference Ref that mentions
+ -- variable Var_Id.
+
+ function Find_Code_Unit (N : Node_Or_Entity_Id) return Entity_Id;
+ pragma Inline (Find_Code_Unit);
+ -- Return the code unit which contains arbitrary node or entity N. This
+ -- is the unit of the file which physically contains the related construct
+ -- denoted by N except when N is within an instantiation. In that case the
+ -- unit is that of the top level instantiation.
+
+ procedure Find_Elaborated_Units;
+ -- Populate table Elaboration_Context with all units which have prior
+ -- elaboration with respect to the main unit.
+
+ function Find_Enclosing_Instance (N : Node_Id) return Node_Id;
+ pragma Inline (Find_Enclosing_Instance);
+ -- Find the declaration or body of the nearest expanded instance which
+ -- encloses arbitrary node N. Return Empty if no such instance exists.
+
+ function Find_Top_Unit (N : Node_Or_Entity_Id) return Entity_Id;
+ pragma Inline (Find_Top_Unit);
+ -- Return the top unit which contains arbitrary node or entity N. The unit
+ -- is obtained by logically unwinding instantiations and subunits when N
+ -- resides within one.
+
+ function Find_Unit_Entity (N : Node_Id) return Entity_Id;
+ pragma Inline (Find_Unit_Entity);
+ -- Return the entity of unit N
+
+ function First_Formal_Type (Subp_Id : Entity_Id) return Entity_Id;
+ pragma Inline (First_Formal_Type);
+ -- Return the type of subprogram Subp_Id's first formal parameter. If the
+ -- subprogram lacks formal parameters, return Empty.
+
+ function Has_Body (Pack_Decl : Node_Id) return Boolean;
+ -- Determine whether package declaration Pack_Decl has a corresponding body
+ -- or would eventually have one.
+
+ function Has_Prior_Elaboration
+ (Unit_Id : Entity_Id;
+ Context_OK : Boolean := False;
+ Elab_Body_OK : Boolean := False;
+ Same_Unit_OK : Boolean := False) return Boolean;
+ pragma Inline (Has_Prior_Elaboration);
+ -- Determine whether unit Unit_Id is elaborated prior to the main unit.
+ -- If flag Context_OK is set, the routine considers the following case
+ -- as valid prior elaboration:
+ --
+ -- * Unit_Id is in the elaboration context of the main unit
+ --
+ -- If flag Elab_Body_OK is set, the routine considers the following case
+ -- as valid prior elaboration:
+ --
+ -- * Unit_Id has pragma Elaborate_Body and is not the main unit
+ --
+ -- If flag Same_Unit_OK is set, the routine considers the following cases
+ -- as valid prior elaboration:
+ --
+ -- * Unit_Id is the main unit
+ --
+ -- * Unit_Id denotes the spec of the main unit body
+
+ function In_External_Instance
(N : Node_Id;
- E : Entity_Id;
- Outer_Scope : Entity_Id;
- Orig_Ent : Entity_Id);
- -- N is a function call or procedure statement call node and E is the
- -- entity of the called function, which is within the current compilation
- -- unit (where subunits count as part of the parent). This call checks if
- -- this call, or any call within any accessed body could cause an ABE, and
- -- if so, outputs a warning. Orig_Ent differs from E only in the case of
- -- renamings, and points to the original name of the entity. This is used
- -- for error messages. Outer_Scope is the outer level scope for the
- -- original call.
-
- procedure Check_Internal_Call_Continue
+ Target_Decl : Node_Id) return Boolean;
+ pragma Inline (In_External_Instance);
+ -- Determine whether a target desctibed by its declaration Target_Decl
+ -- resides in a package instance which is external to scenario N.
+
+ function In_Main_Context (N : Node_Id) return Boolean;
+ pragma Inline (In_Main_Context);
+ -- Determine whether arbitrary node N appears within the main compilation
+ -- unit.
+
+ function In_Same_Context
+ (N1 : Node_Id;
+ N2 : Node_Id;
+ Nested_OK : Boolean := False) return Boolean;
+ -- Determine whether two arbitrary nodes N1 and N2 appear within the same
+ -- context ignoring enclosing library levels. Nested_OK should be set when
+ -- the context of N1 can enclose that of N2.
+
+ procedure Info_Call
+ (Call : Node_Id;
+ Target_Id : Entity_Id;
+ Info_Msg : Boolean;
+ In_SPARK : Boolean);
+ -- Output information concerning call Call which invokes target Target_Id.
+ -- If flag Info_Msg is set, the routine emits an information message,
+ -- otherwise it emits an error. If flag In_SPARK is set, then the string
+ -- " in SPARK" is added to the end of the message.
+
+ procedure Info_Instantiation
+ (Inst : Node_Id;
+ Gen_Id : Entity_Id;
+ Info_Msg : Boolean;
+ In_SPARK : Boolean);
+ pragma Inline (Info_Instantiation);
+ -- Output information concerning instantiation Inst which instantiates
+ -- generic unit Gen_Id. If flag Info_Msg is set, the routine emits an
+ -- information message, otherwise it emits an error. If flag In_SPARK
+ -- is set, then string " in SPARK" is added to the end of the message.
+
+ procedure Info_Variable_Read
+ (Ref : Node_Id;
+ Var_Id : Entity_Id;
+ Info_Msg : Boolean;
+ In_SPARK : Boolean);
+ pragma Inline (Info_Variable_Read);
+ -- Output information concerning reference Ref which reads variable Var_Id.
+ -- If flag Info_Msg is set, the routine emits an information message,
+ -- otherwise it emits an error. If flag In_SPARK is set, then string " in
+ -- SPARK" is added to the end of the message.
+
+ function Insertion_Node (N : Node_Id; Ins_Nod : Node_Id) return Node_Id;
+ pragma Inline (Insertion_Node);
+ -- Obtain the proper insertion node of an ABE check or failure for scenario
+ -- N and candidate insertion node Ins_Nod.
+
+ procedure Install_ABE_Check
+ (N : Node_Id;
+ Id : Entity_Id;
+ Ins_Nod : Node_Id);
+ -- Insert a run-time ABE check for elaboration scenario N which verifies
+ -- whether arbitrary entity Id is elaborated. The check in inserted prior
+ -- to node Ins_Nod.
+
+ procedure Install_ABE_Check
(N : Node_Id;
- E : Entity_Id;
- Outer_Scope : Entity_Id;
- Orig_Ent : Entity_Id);
- -- The processing for Check_Internal_Call is divided up into two phases,
- -- and this represents the second phase. The second phase is delayed if
- -- Delaying_Elab_Checks is set to True. In this delayed case, the first
- -- phase makes an entry in the Delay_Check table, which is processed when
- -- Check_Elab_Calls is called. N, E and Orig_Ent are as for the call to
- -- Check_Internal_Call. Outer_Scope is the outer level scope for the
- -- original call.
-
- function Has_Generic_Body (N : Node_Id) return Boolean;
- -- N is a generic package instantiation node, and this routine determines
- -- if this package spec does in fact have a generic body. If so, then
- -- True is returned, otherwise False. Note that this is not at all the
- -- same as checking if the unit requires a body, since it deals with
- -- the case of optional bodies accurately (i.e. if a body is optional,
- -- then it looks to see if a body is actually present). Note: this
- -- function can only do a fully correct job if in generating code mode
- -- where all bodies have to be present. If we are operating in semantics
- -- check only mode, then in some cases of optional bodies, a result of
- -- False may incorrectly be given. In practice this simply means that
- -- some cases of warnings for incorrect order of elaboration will only
- -- be given when generating code, which is not a big problem (and is
- -- inevitable, given the optional body semantics of Ada).
-
- procedure Insert_Elab_Check (N : Node_Id; C : Node_Id := Empty);
- -- Given code for an elaboration check (or unconditional raise if the check
- -- is not needed), inserts the code in the appropriate place. N is the call
- -- or instantiation node for which the check code is required. C is the
- -- test whose failure triggers the raise.
-
- function Is_Call_Of_Generic_Formal (N : Node_Id) return Boolean;
- -- Returns True if node N is a call to a generic formal subprogram
-
- function Is_Finalization_Procedure (Id : Entity_Id) return Boolean;
- -- Determine whether entity Id denotes a [Deep_]Finalize procedure
-
- procedure Output_Calls
- (N : Node_Id;
- Check_Elab_Flag : Boolean);
- -- Outputs chain of calls stored in the Elab_Call table. The caller has
- -- already generated the main warning message, so the warnings generated
- -- are all continuation messages. The argument is the call node at which
- -- the messages are to be placed. When Check_Elab_Flag is set, calls are
- -- enumerated only when flag Elab_Warning is set for the dynamic case or
- -- when flag Elab_Info_Messages is set for the static case.
-
- function Same_Elaboration_Scope (Scop1, Scop2 : Entity_Id) return Boolean;
- -- Given two scopes, determine whether they are the same scope from an
- -- elaboration point of view, i.e. packages and blocks are ignored.
-
- procedure Set_C_Scope;
- -- On entry C_Scope is set to some scope. On return, C_Scope is reset
- -- to be the enclosing compilation unit of this scope.
-
- function Get_Referenced_Ent (N : Node_Id) return Entity_Id;
- -- N is either a function or procedure call or an access attribute that
- -- references a subprogram. This call retrieves the relevant entity. If
- -- this is a call to a protected subprogram, the entity is a selected
- -- component. The callable entity may be absent, in which case Empty is
- -- returned. This happens with non-analyzed calls in nested generics.
- --
- -- If SPARK_Mode is On, then N can also be a reference to an E_Variable
- -- entity, in which case, the value returned is simply this entity.
-
- procedure Set_Elaboration_Constraint
- (Call : Node_Id;
- Subp : Entity_Id;
- Scop : Entity_Id);
- -- The current unit U may depend semantically on some unit P that is not
- -- in the current context. If there is an elaboration call that reaches P,
- -- we need to indicate that P requires an Elaborate_All, but this is not
- -- effective in U's ali file, if there is no with_clause for P. In this
- -- case we add the Elaborate_All on the unit Q that directly or indirectly
- -- makes P available. This can happen in two cases:
- --
- -- a) Q declares a subtype of a type declared in P, and the call is an
- -- initialization call for an object of that subtype.
- --
- -- b) Q declares an object of some tagged type whose root type is
- -- declared in P, and the initialization call uses object notation on
- -- that object to reach a primitive operation or a classwide operation
- -- declared in P.
- --
- -- If P appears in the context of U, the current processing is correct.
- -- Otherwise we must identify these two cases to retrieve Q and place the
- -- Elaborate_All_Desirable on it.
-
- function Spec_Entity (E : Entity_Id) return Entity_Id;
- -- Given a compilation unit entity, if it is a spec entity, it is returned
- -- unchanged. If it is a body entity, then the spec for the corresponding
- -- spec is returned
-
- procedure Supply_Bodies (N : Node_Id);
- -- Given a node, N, that is either a subprogram declaration or a package
- -- declaration, this procedure supplies dummy bodies for the subprogram
- -- or for all subprograms in the package. If the given node is not one of
- -- these two possibilities, then Supply_Bodies does nothing. The dummy body
- -- contains a single Raise statement.
-
- procedure Supply_Bodies (L : List_Id);
- -- Calls Supply_Bodies for all elements of the given list L
-
- function Within (E1, E2 : Entity_Id) return Boolean;
- -- Given two scopes E1 and E2, returns True if E1 is equal to E2, or is one
- -- of its contained scopes, False otherwise.
-
- function Within_Elaborate_All
- (Unit : Unit_Number_Type;
- E : Entity_Id) return Boolean;
- -- Return True if we are within the scope of an Elaborate_All for E, or if
- -- we are within the scope of an Elaborate_All for some other unit U, and U
- -- with's E. This prevents spurious warnings when the called entity is
- -- renamed within U, or in case of generic instances.
+ Target_Id : Entity_Id;
+ Target_Decl : Node_Id;
+ Target_Body : Node_Id;
+ Ins_Nod : Node_Id);
+ -- Insert a run-time ABE check for elaboration scenario N which verifies
+ -- whether target Target_Id with initial declaration Target_Decl and body
+ -- Target_Body is elaborated. The check is inserted prior to node Ins_Nod.
+
+ procedure Install_ABE_Failure (N : Node_Id; Ins_Nod : Node_Id);
+ -- Insert a Program_Error concerning a guaranteed ABE for elaboration
+ -- scenario N. The failure is inserted prior to node Node_Id.
+
+ function Is_Accept_Alternative_Proc (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Accept_Alternative_Proc);
+ -- Determine whether arbitrary entity Id denotes an internally generated
+ -- procedure which encapsulates the statements of an accept alternative.
+
+ function Is_Activation_Proc (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Activation_Proc);
+ -- Determine whether arbitrary entity Id denotes a runtime procedure in
+ -- charge with activating tasks.
+
+ function Is_Ada_Semantic_Target (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Ada_Semantic_Target);
+ -- Determine whether arbitrary entity Id nodes a source or internally
+ -- generated subprogram which emulates Ada semantics.
+
+ function Is_Bodiless_Subprogram (Subp_Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Bodiless_Subprogram);
+ -- Determine whether subprogram Subp_Id will never have a body
+
+ function Is_Check_Emitting_Scenario (N : Node_Id) return Boolean;
+ pragma Inline (Is_Check_Emitting_Scenario);
+ -- Determine whether arbitrary node N denotes a scenario which may emit a
+ -- conditional ABE check.
+
+ function Is_Controlled_Proc
+ (Subp_Id : Entity_Id;
+ Subp_Nam : Name_Id) return Boolean;
+ pragma Inline (Is_Controlled_Proc);
+ -- Determine whether subprogram Subp_Id denotes controlled type primitives
+ -- Adjust, Finalize, or Initialize as denoted by name Subp_Nam.
+
+ function Is_Default_Initial_Condition_Proc (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Default_Initial_Condition_Proc);
+ -- Determine whether arbitrary entity Id denotes internally generated
+ -- routine Default_Initial_Condition.
+
+ function Is_Finalizer_Proc (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Finalizer_Proc);
+ -- Determine whether arbitrary entity Id denotes internally generated
+ -- routine _Finalizer.
+
+ function Is_Guaranteed_ABE
+ (N : Node_Id;
+ Target_Decl : Node_Id;
+ Target_Body : Node_Id) return Boolean;
+ pragma Inline (Is_Guaranteed_ABE);
+ -- Determine whether scenario N with a target described by its initial
+ -- declaration Target_Decl and body Target_Decl results in a guaranteed
+ -- ABE.
+
+ function Is_Initial_Condition_Proc (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Initial_Condition_Proc);
+ -- Determine whether arbitrary entity Id denotes internally generated
+ -- routine Initial_Condition.
+
+ function Is_Initialized (Obj_Decl : Node_Id) return Boolean;
+ pragma Inline (Is_Initialized);
+ -- Determine whether object declaration Obj_Decl is initialized
+
+ function Is_Invariant_Proc (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Invariant_Proc);
+ -- Determine whether arbitrary entity Id denotes an invariant procedure
+
+ function Is_Non_Library_Level_Encapsulator (N : Node_Id) return Boolean;
+ pragma Inline (Is_Non_Library_Level_Encapsulator);
+ -- Determine whether arbitrary node N is a non-library encapsulator
+
+ function Is_Partial_Invariant_Proc (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Partial_Invariant_Proc);
+ -- Determine whether arbitrary entity Id denotes a partial invariant
+ -- procedure.
+
+ function Is_Postconditions_Proc (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Postconditions_Proc);
+ -- Determine whether arbitrary entity Id denotes internally generated
+ -- routine _Postconditions.
+
+ function Is_Preelaborated_Unit (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Preelaborated_Unit);
+ -- Determine whether arbitrary entity Id denotes a unit which is subject to
+ -- one of the following pragmas:
+ --
+ -- * Preelaborable
+ -- * Pure
+ -- * Remote_Call_Interface
+ -- * Remote_Types
+ -- * Shared_Passive
+
+ function Is_Protected_Entry (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Protected_Entry);
+ -- Determine whether arbitrary entity Id denotes a protected entry
+
+ function Is_Protected_Subp (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Protected_Subp);
+ -- Determine whether entity Id denotes a protected subprogram
+
+ function Is_Protected_Body_Subp (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Protected_Body_Subp);
+ -- Determine whether entity Id denotes the protected or unprotected version
+ -- of a protected subprogram.
+
+ function Is_Safe_Activation
+ (Call : Node_Id;
+ Task_Decl : Node_Id) return Boolean;
+ pragma Inline (Is_Safe_Activation);
+ -- Determine whether call Call which activates a task object described by
+ -- declaration Task_Decl is always ABE-safe.
+
+ function Is_Safe_Call
+ (Call : Node_Id;
+ Target_Attrs : Target_Attributes) return Boolean;
+ pragma Inline (Is_Safe_Call);
+ -- Determine whether call Call which invokes a target described by
+ -- attributes Target_Attrs is always ABE-safe.
+
+ function Is_Safe_Instantiation
+ (Inst : Node_Id;
+ Gen_Attrs : Target_Attributes) return Boolean;
+ pragma Inline (Is_Safe_Instantiation);
+ -- Determine whether instance Inst which instantiates a generic unit
+ -- described by attributes Gen_Attrs is always ABE-safe.
+
+ function Is_Same_Unit
+ (Unit_1 : Entity_Id;
+ Unit_2 : Entity_Id) return Boolean;
+ pragma Inline (Is_Same_Unit);
+ -- Determine whether entities Unit_1 and Unit_2 denote the same unit
+
+ function Is_Scenario (N : Node_Id) return Boolean;
+ pragma Inline (Is_Scenario);
+ -- Determine whether attribute node N denotes a scenario. The scenario may
+ -- not necessarily be eligible for ABE processing.
+
+ function Is_SPARK_Semantic_Target (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_SPARK_Semantic_Target);
+ -- Determine whether arbitrary entity Id nodes a source or internally
+ -- generated subprogram which emulates SPARK semantics.
+
+ function Is_Suitable_Access (N : Node_Id) return Boolean;
+ pragma Inline (Is_Suitable_Access);
+ -- Determine whether arbitrary node N denotes a suitable attribute for ABE
+ -- processing.
+
+ function Is_Suitable_Call (N : Node_Id) return Boolean;
+ pragma Inline (Is_Suitable_Call);
+ -- Determine whether arbitrary node N denotes a suitable call for ABE
+ -- processing.
+
+ function Is_Suitable_Instantiation (N : Node_Id) return Boolean;
+ pragma Inline (Is_Suitable_Instantiation);
+ -- Determine whether arbitrary node N is a suitable instantiation for ABE
+ -- processing.
+
+ function Is_Suitable_Scenario (N : Node_Id) return Boolean;
+ pragma Inline (Is_Suitable_Scenario);
+ -- Determine whether arbitrary node N is a suitable scenario for ABE
+ -- processing.
+
+ function Is_Suitable_Variable_Assignment (N : Node_Id) return Boolean;
+ pragma Inline (Is_Suitable_Variable_Assignment);
+ -- Determine whether arbitrary node N denotes a suitable assignment for ABE
+ -- processing.
+
+ function Is_Suitable_Variable_Read (N : Node_Id) return Boolean;
+ pragma Inline (Is_Suitable_Variable_Read);
+ -- Determine whether arbitrary node N is a suitable variable read for ABE
+ -- processing.
+
+ function Is_Task_Entry (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Task_Entry);
+ -- Determine whether arbitrary entity Id denotes a task entry
+
+ function Is_Up_Level_Target (Target_Decl : Node_Id) return Boolean;
+ pragma Inline (Is_Up_Level_Target);
+ -- Determine whether the current root resides at the declaration level. If
+ -- this is the case, determine whether a target described by declaration
+ -- Target_Decl is within a context which encloses the current root or is in
+ -- a different unit.
+
+ procedure Meet_Elaboration_Requirement
+ (N : Node_Id;
+ Target_Id : Entity_Id;
+ Req_Nam : Name_Id);
+ -- Determine whether elaboration requirement Req_Nam for scenario N with
+ -- target Target_Id is met by the context of the main unit using the SPARK
+ -- rules. Req_Nam must denote either Elaborate or Elaborate_All. Emit an
+ -- error if this is not the case.
+
+ function Non_Private_View (Typ : Entity_Id) return Entity_Id;
+ pragma Inline (Non_Private_View);
+ -- Return the full view of private type Typ if available, otherwise return
+ -- type Typ.
+
+ procedure Output_Active_Scenarios (Error_Nod : Node_Id);
+ -- Output the contents of the active scenario stack from earliest to latest
+ -- to supplement an earlier error emitted for node Error_Nod.
+
+ procedure Pop_Active_Scenario (N : Node_Id);
+ pragma Inline (Pop_Active_Scenario);
+ -- Pop the top of the scenario stack. A check is made to ensure that the
+ -- scenario being removed is the same as N.
+
+ procedure Process_Access (Attr : Node_Id; In_Task_Body : Boolean);
+ -- Perform ABE checks and diagnostics for 'Access to entry, operator, or
+ -- subprogram denoted by Attr. Flag In_Task_Body should be set when the
+ -- processing is initiated from a task body.
+
+ generic
+ with procedure Process_Single_Activation
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Obj_Id : Entity_Id;
+ Task_Attrs : Task_Attributes;
+ In_Task_Body : Boolean);
+ -- Perform ABE checks and diagnostics for task activation call Call
+ -- which activates task Obj_Id. Call_Attrs are the attributes of the
+ -- activation call. Task_Attrs are the attributes of the task type.
+ -- Flag In_Task_Body should be set when the processing is initiated
+ -- from a task body.
+
+ procedure Process_Activation_Call
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ In_Task_Body : Boolean);
+ -- Perform ABE checks and diagnostics for activation call Call by invoking
+ -- routine Process_Single_Activation on each task object being activated.
+ -- Call_Attrs are the attributes of the activation call. Flag In_Task_Body
+ -- should be set when the processing is initiated from a task body.
+
+ procedure Process_Activation_Conditional_ABE_Impl
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Obj_Id : Entity_Id;
+ Task_Attrs : Task_Attributes;
+ In_Task_Body : Boolean);
+ -- Perform common conditional ABE checks and diagnostics for call Call
+ -- which activates task Obj_Id ignoring the Ada or SPARK rules. CAll_Attrs
+ -- are the attributes of the activation call. Task_Attrs are the attributes
+ -- of the task type. Flag In_Task_Body should be set when the processing is
+ -- initiated from a task body.
+
+ procedure Process_Activation_Guaranteed_ABE_Impl
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Obj_Id : Entity_Id;
+ Task_Attrs : Task_Attributes;
+ In_Task_Body : Boolean);
+ -- Perform common guaranteed ABE checks and diagnostics for call Call
+ -- which activates task Obj_Id ignoring the Ada or SPARK rules. CAll_Attrs
+ -- are the attributes of the activation call. Task_Attrs are the attributes
+ -- of the task type. Flag In_Task_Body should be set when the processing is
+ -- initiated from a task body.
+
+ procedure Process_Call
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+ In_Task_Body : Boolean);
+ -- Top-level dispatcher for processing of calls. Perform ABE checks and
+ -- diagnostics for call Call which invokes target Target_Id. Call_Attrs
+ -- are the attributes of the call. Flag In_Task_Body should be set when
+ -- the processing is initiated from a task body.
+
+ procedure Process_Call_Ada
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+ Target_Attrs : Target_Attributes;
+ In_Task_Body : Boolean);
+ -- Perform ABE checks and diagnostics for call Call which invokes target
+ -- Target_Id using the Ada rules. Call_Attrs are the attributes of the
+ -- call. Target_Attrs are attributes of the target. Flag In_Task_Body
+ -- should be set when the processing is initiated from a task body.
+
+ procedure Process_Call_Conditional_ABE
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+ Target_Attrs : Target_Attributes);
+ -- Perform common conditional ABE checks and diagnostics for call Call that
+ -- invokes target Target_Id ignoring the Ada or SPARK rules. Call_Attrs are
+ -- the attributes of the call. Target_Attrs are attributes of the target.
+
+ procedure Process_Call_Guaranteed_ABE
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id);
+ -- Perform common guaranteed ABE checks and diagnostics for call Call which
+ -- invokes target Target_Id ignoring the Ada or SPARK rules. Call_Attrs are
+ -- the attributes of the call.
+
+ procedure Process_Call_SPARK
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+ Target_Attrs : Target_Attributes);
+ -- Perform ABE checks and diagnostics for call Call which invokes target
+ -- Target_Id using the SPARK rules. Call_Attrs are the attributes of the
+ -- call. Target_Attrs are attributes of the target.
+
+ procedure Process_Guaranteed_ABE (N : Node_Id);
+ -- Top level dispatcher for processing of scenarios which result in a
+ -- guaranteed ABE.
+
+ procedure Process_Instantiation
+ (Exp_Inst : Node_Id;
+ In_Task_Body : Boolean);
+ -- Top level dispatcher for processing of instantiations. Perform ABE
+ -- checks and diagnostics for expanded instantiation Exp_Inst. Flag
+ -- In_Task_Body should be set when the processing is initiated from a
+ -- task body.
+
+ procedure Process_Instantiation_Ada
+ (Exp_Inst : Node_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Gen_Id : Entity_Id;
+ Gen_Attrs : Target_Attributes;
+ In_Task_Body : Boolean);
+ -- Perform ABE checks and diagnostics for expanded instantiation Exp_Inst
+ -- of generic Gen_Id using the Ada rules. Inst is the instantiation node.
+ -- Inst_Attrs are the attributes of the instance. Gen_Attrs are the
+ -- attributes of the generic. Flag In_Task_Body should be set when the
+ -- processing is initiated from a task body.
+
+ procedure Process_Instantiation_Conditional_ABE
+ (Exp_Inst : Node_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Gen_Id : Entity_Id;
+ Gen_Attrs : Target_Attributes);
+ -- Perform common conditional ABE checks and diagnostics for expanded
+ -- instantiation Exp_Inst of generic Gen_Id ignoring the Ada or SPARK
+ -- rules. Inst is the instantiation node. Inst_Attrs are the attributes
+ -- of the instance. Gen_Attrs are the attributes of the generic.
+
+ procedure Process_Instantiation_Guaranteed_ABE (Exp_Inst : Node_Id);
+ -- Perform common guaranteed ABE checks and diagnostics for expanded
+ -- instantiation Exp_Inst of generic Gen_Id ignoring the Ada or SPARK
+ -- rules.
+
+ procedure Process_Instantiation_SPARK
+ (Exp_Inst : Node_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Gen_Id : Entity_Id;
+ Gen_Attrs : Target_Attributes);
+ -- Perform ABE checks and diagnostics for expanded instantiation Exp_Inst
+ -- of generic Gen_Id using the SPARK rules. Inst is the instantiation node.
+ -- Inst_Attrs are the attributes of the instance. Gen_Attrs are the
+ -- attributes of the generic.
+
+ procedure Process_Scenario (N : Node_Id; In_Task_Body : Boolean := False);
+ -- Top level dispatcher for processing of various elaboration scenarios.
+ -- Perform ABE checks and diagnostics for scenario N. Flag In_Task_Body
+ -- should be set when the processing is initiated from a task body.
+
+ procedure Process_Variable_Assignment (Asmt : Node_Id);
+ -- Top level dispatcher for processing of variable assignments. Perform ABE
+ -- checks and diagnostics for assignment statement Asmt.
+
+ procedure Process_Variable_Assignment_Ada
+ (Asmt : Node_Id;
+ Var_Id : Entity_Id);
+ -- Perform ABE checks and diagnostics for assignment statement Asmt that
+ -- updates the value of variable Var_Id using the Ada rules.
+
+ procedure Process_Variable_Assignment_SPARK
+ (Asmt : Node_Id;
+ Var_Id : Entity_Id);
+ -- Perform ABE checks and diagnostics for assignment statement Asmt that
+ -- updates the value of variable Var_Id using the SPARK rules.
+
+ procedure Process_Variable_Read (Ref : Node_Id);
+ -- Perform ABE checks and diagnostics for reference Ref that reads a
+ -- variable.
+
+ procedure Push_Active_Scenario (N : Node_Id);
+ pragma Inline (Push_Active_Scenario);
+ -- Push scenario N on top of the scenario stack
+
+ function Root_Scenario return Node_Id;
+ pragma Inline (Root_Scenario);
+ -- Return the top level scenario which started a recursive search for other
+ -- scenarios. It is assumed that there is a valid top level scenario on the
+ -- active scenario stack.
+
+ function Static_Elaboration_Checks return Boolean;
+ pragma Inline (Static_Elaboration_Checks);
+ -- Determine whether the static model is in effect
+
+ procedure Traverse_Body (N : Node_Id; In_Task_Body : Boolean);
+ -- Inspect the declarations and statements of subprogram body N for
+ -- suitable elaboration scenarios and process them. Flag In_Task_Body
+ -- should be set when the traversal is initiated from a task body.
+
+ procedure Update_Elaboration_Scenario (New_N : Node_Id; Old_N : Node_Id);
+ pragma Inline (Update_Elaboration_Scenario);
+ -- Update all relevant internal data structures when scenario Old_N is
+ -- transformed into scenario New_N by Atree.Rewrite.
- --------------------------------------
- -- Activate_Elaborate_All_Desirable --
- --------------------------------------
+ -----------------------
+ -- Build_Call_Marker --
+ -----------------------
- procedure Activate_Elaborate_All_Desirable (N : Node_Id; U : Entity_Id) is
- UN : constant Unit_Number_Type := Get_Code_Unit (N);
- CU : constant Node_Id := Cunit (UN);
- UE : constant Entity_Id := Cunit_Entity (UN);
- Unm : constant Unit_Name_Type := Unit_Name (UN);
- CI : constant List_Id := Context_Items (CU);
- Itm : Node_Id;
- Ent : Entity_Id;
+ procedure Build_Call_Marker (N : Node_Id) is
+ function In_External_Context
+ (Call : Node_Id;
+ Target_Id : Entity_Id) return Boolean;
+ pragma Inline (In_External_Context);
+ -- Determine whether target Target_Id is external to call N which must
+ -- reside within an instance.
- procedure Add_To_Context_And_Mark (Itm : Node_Id);
- -- This procedure is called when the elaborate indication must be
- -- applied to a unit not in the context of the referencing unit. The
- -- unit gets added to the context as an implicit with.
+ function In_Premature_Context (Call : Node_Id) return Boolean;
+ -- Determine whether call Call appears within a premature context
- function In_Withs_Of (UEs : Entity_Id) return Boolean;
- -- UEs is the spec entity of a unit. If the unit to be marked is
- -- in the context item list of this unit spec, then the call returns
- -- True and Itm is left set to point to the relevant N_With_Clause node.
+ function Is_Bridge_Target (Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Bridge_Target);
+ -- Determine whether arbitrary entity Id denotes a bridge target
- procedure Set_Elab_Flag (Itm : Node_Id);
- -- Sets Elaborate_[All_]Desirable as appropriate on Itm
+ function Is_Default_Expression (Call : Node_Id) return Boolean;
+ pragma Inline (Is_Default_Expression);
+ -- Determine whether call Call acts as the expression of a defaulted
+ -- parameter within a source call.
- -----------------------------
- -- Add_To_Context_And_Mark --
- -----------------------------
+ function Is_Generic_Formal_Subp (Subp_Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Generic_Formal_Subp);
+ -- Determine whether subprogram Subp_Id denotes a generic formal
+ -- subprogram which appears in the "prologue" of an instantiation.
- procedure Add_To_Context_And_Mark (Itm : Node_Id) is
- CW : constant Node_Id :=
- Make_With_Clause (Sloc (Itm),
- Name => Name (Itm));
+ -------------------------
+ -- In_External_Context --
+ -------------------------
+
+ function In_External_Context
+ (Call : Node_Id;
+ Target_Id : Entity_Id) return Boolean
+ is
+ Target_Decl : constant Node_Id := Unit_Declaration_Node (Target_Id);
+
+ Inst : Node_Id;
+ Inst_Body : Node_Id;
+ Inst_Decl : Node_Id;
begin
- Set_Library_Unit (CW, Library_Unit (Itm));
- Set_Implicit_With (CW, True);
+ -- Performance note: parent traversal
- -- Set elaborate all desirable on copy and then append the copy to
- -- the list of body with's and we are done.
+ Inst := Find_Enclosing_Instance (Call);
- Set_Elab_Flag (CW);
- Append_To (CI, CW);
- end Add_To_Context_And_Mark;
+ -- The call appears within an instance
- -----------------
- -- In_Withs_Of --
- -----------------
+ if Present (Inst) then
+
+ -- The call comes from the main unit and the target does not
+
+ if In_Extended_Main_Code_Unit (Call)
+ and then not In_Extended_Main_Code_Unit (Target_Decl)
+ then
+ return True;
+
+ -- Otherwise the target declaration must not appear within the
+ -- instance spec or body.
- function In_Withs_Of (UEs : Entity_Id) return Boolean is
- UNs : constant Unit_Number_Type := Get_Source_Unit (UEs);
- CUs : constant Node_Id := Cunit (UNs);
- CIs : constant List_Id := Context_Items (CUs);
+ else
+ Extract_Instance_Attributes
+ (Exp_Inst => Inst,
+ Inst_Decl => Inst_Decl,
+ Inst_Body => Inst_Body);
+
+ -- Performance note: parent traversal
+
+ return not In_Subtree
+ (N => Target_Decl,
+ Root1 => Inst_Decl,
+ Root2 => Inst_Body);
+ end if;
+ end if;
+
+ return False;
+ end In_External_Context;
+
+ --------------------------
+ -- In_Premature_Context --
+ --------------------------
+
+ function In_Premature_Context (Call : Node_Id) return Boolean is
+ Par : Node_Id;
begin
- Itm := First (CIs);
- while Present (Itm) loop
- if Nkind (Itm) = N_With_Clause then
- Ent :=
- Cunit_Entity (Get_Cunit_Unit_Number (Library_Unit (Itm)));
+ -- Climb the parent chain looking for premature contexts
- if U = Ent then
- return True;
- end if;
+ Par := Parent (Call);
+ while Present (Par) loop
+
+ -- Aspect specifications and generic associations are premature
+ -- contexts because nested calls has not been relocated to their
+ -- final context.
+
+ if Nkind_In (Par, N_Aspect_Specification,
+ N_Generic_Association)
+ then
+ return True;
+
+ -- Prevent the search from going too far
+
+ elsif Is_Body_Or_Package_Declaration (Par) then
+ exit;
end if;
- Next (Itm);
+ Par := Parent (Par);
end loop;
return False;
- end In_Withs_Of;
+ end In_Premature_Context;
- -------------------
- -- Set_Elab_Flag --
- -------------------
+ ----------------------
+ -- Is_Bridge_Target --
+ ----------------------
- procedure Set_Elab_Flag (Itm : Node_Id) is
+ function Is_Bridge_Target (Id : Entity_Id) return Boolean is
begin
- if Nkind (N) in N_Subprogram_Instantiation then
- Set_Elaborate_Desirable (Itm);
- else
- Set_Elaborate_All_Desirable (Itm);
+ return
+ Is_Accept_Alternative_Proc (Id)
+ or else Is_Finalizer_Proc (Id)
+ or else Is_Partial_Invariant_Proc (Id)
+ or else Is_Postconditions_Proc (Id)
+ or else Is_TSS (Id, TSS_Deep_Adjust)
+ or else Is_TSS (Id, TSS_Deep_Finalize)
+ or else Is_TSS (Id, TSS_Deep_Initialize);
+ end Is_Bridge_Target;
+
+ ---------------------------
+ -- Is_Default_Expression --
+ ---------------------------
+
+ function Is_Default_Expression (Call : Node_Id) return Boolean is
+ Outer_Call : constant Node_Id := Parent (Call);
+ Outer_Nam : Node_Id;
+
+ begin
+ -- To qualify, the node must appear immediately within a source call
+ -- which invokes a source target.
+
+ if Nkind_In (Outer_Call, N_Entry_Call_Statement,
+ N_Function_Call,
+ N_Procedure_Call_Statement)
+ and then Comes_From_Source (Outer_Call)
+ then
+ Outer_Nam := Extract_Call_Name (Outer_Call);
+
+ return
+ Is_Entity_Name (Outer_Nam)
+ and then Present (Entity (Outer_Nam))
+ and then Is_Subprogram_Or_Entry (Entity (Outer_Nam))
+ and then Comes_From_Source (Entity (Outer_Nam));
end if;
- end Set_Elab_Flag;
- -- Start of processing for Activate_Elaborate_All_Desirable
+ return False;
+ end Is_Default_Expression;
+
+ ----------------------------
+ -- Is_Generic_Formal_Subp --
+ ----------------------------
+
+ function Is_Generic_Formal_Subp (Subp_Id : Entity_Id) return Boolean is
+ Subp_Decl : constant Node_Id := Unit_Declaration_Node (Subp_Id);
+ Context : constant Node_Id := Parent (Subp_Decl);
+
+ begin
+ -- To qualify, the subprogram must rename a generic actual subprogram
+ -- where the enclosing context is an instantiation.
+
+ return
+ Nkind (Subp_Decl) = N_Subprogram_Renaming_Declaration
+ and then not Comes_From_Source (Subp_Decl)
+ and then Nkind_In (Context, N_Function_Specification,
+ N_Package_Specification,
+ N_Procedure_Specification)
+ and then Present (Generic_Parent (Context));
+ end Is_Generic_Formal_Subp;
+
+ -- Local variables
+
+ Call_Attrs : Call_Attributes;
+ Call_Nam : Node_Id;
+ Marker : Node_Id;
+ Target_Id : Entity_Id;
+
+ -- Start of processing for Build_Call_Marker
begin
- -- Do not set binder indication if expansion is disabled, as when
- -- compiling a generic unit.
+ -- Nothing to do for ASIS. As a result, ABE checks and diagnostics are
+ -- not performed in this mode.
- if not Expander_Active then
+ if ASIS_Mode then
+ return;
+
+ -- Nothing to do when the input does not denote a call or a requeue
+
+ elsif not Nkind_In (N, N_Entry_Call_Statement,
+ N_Function_Call,
+ N_Procedure_Call_Statement,
+ N_Requeue_Statement)
+ then
+ return;
+
+ -- Nothing to do when the call is being preanalyzed as the marker will
+ -- be inserted in the wrong place.
+
+ elsif Preanalysis_Active then
+ return;
+
+ -- Nothing to do when the call is analyzed/resolved too early within an
+ -- intermediate context.
+
+ -- Performance note: parent traversal
+
+ elsif In_Premature_Context (N) then
return;
end if;
- -- If an instance of a generic package contains a controlled object (so
- -- we're calling Initialize at elaboration time), and the instance is in
- -- a package body P that says "with P;", then we need to return without
- -- adding "pragma Elaborate_All (P);" to P.
+ Call_Nam := Extract_Call_Name (N);
+
+ -- Nothing to do when the call is erroneous or left in a bad state
- if U = Main_Unit_Entity then
+ if not (Is_Entity_Name (Call_Nam)
+ and then Present (Entity (Call_Nam))
+ and then Is_Subprogram_Or_Entry (Entity (Call_Nam)))
+ then
+ return;
+
+ -- Nothing to do when the call invokes a generic formal subprogram and
+ -- switch -gnatd.G (ignore calls through generic formal parameters for
+ -- elaboration) is in effect. This check must be performed with the
+ -- direct target of the call to avoid the side effects of mapping
+ -- actuals to formals using renamings.
+
+ elsif Debug_Flag_Dot_GG
+ and then Is_Generic_Formal_Subp (Entity (Call_Nam))
+ then
return;
end if;
- Itm := First (CI);
- while Present (Itm) loop
- if Nkind (Itm) = N_With_Clause then
- Ent := Cunit_Entity (Get_Cunit_Unit_Number (Library_Unit (Itm)));
+ Extract_Call_Attributes
+ (Call => N,
+ Target_Id => Target_Id,
+ Attrs => Call_Attrs);
- -- If we find it, then mark elaborate all desirable and return
+ -- Nothing to do when the call appears within the expanded spec or
+ -- body of an instantiated generic, the call does not invoke a generic
+ -- formal subprogram, the target is external to the instance, and switch
+ -- -gnatdL (ignore external calls from instances for elaboration) is in
+ -- effect. This behaviour approximates that of the old ABE mechanism.
- if U = Ent then
- Set_Elab_Flag (Itm);
- return;
- end if;
- end if;
+ if Debug_Flag_LL
+ and then not Is_Generic_Formal_Subp (Entity (Call_Nam))
- Next (Itm);
- end loop;
+ -- Performance note: parent traversal
+
+ and then In_External_Context
+ (Call => N,
+ Target_Id => Target_Id)
+ then
+ return;
+
+ -- Source calls to source targets are always considered because they
+ -- reflect the original call graph.
- -- If we fall through then the with clause is not present in the
- -- current unit. One legitimate possibility is that the with clause
- -- is present in the spec when we are a body.
+ elsif Comes_From_Source (Target_Id) and then Call_Attrs.From_Source then
+ null;
- if Is_Body_Name (Unm)
- and then In_Withs_Of (Spec_Entity (UE))
+ -- A call to a source function which acts as the default expression in
+ -- another call requires special detection.
+
+ elsif Comes_From_Source (Target_Id)
+ and then Nkind (N) = N_Function_Call
+ and then Is_Default_Expression (N)
then
- Add_To_Context_And_Mark (Itm);
+ null;
+
+ -- The target emulates Ada semantics
+
+ elsif Is_Ada_Semantic_Target (Target_Id) then
+ null;
+
+ -- The target acts as a link between scenarios
+
+ elsif Is_Bridge_Target (Target_Id) then
+ null;
+
+ -- The target emulates SPARK semantics
+
+ elsif Is_SPARK_Semantic_Target (Target_Id) then
+ null;
+
+ -- Otherwise the call is not suitable for ABE processing. This prevents
+ -- the generation of call markers which will never play a role in ABE
+ -- diagnostics.
+
+ else
return;
end if;
- -- Similarly, we may be in the spec or body of a child unit, where
- -- the unit in question is with'ed by some ancestor of the child unit.
+ -- At this point it is known that the call will play some role in ABE
+ -- checks and diagnostics. Create a corresponding call marker in case
+ -- the original call is heavily transformed by expansion later on.
- if Is_Child_Name (Unm) then
- declare
- Pkg : Entity_Id;
+ Marker := Make_Call_Marker (Sloc (N));
- begin
- Pkg := UE;
- loop
- Pkg := Scope (Pkg);
- exit when Pkg = Standard_Standard;
-
- if In_Withs_Of (Pkg) then
- Add_To_Context_And_Mark (Itm);
- return;
- end if;
- end loop;
- end;
- end if;
+ -- Inherit the attributes of the original call
- -- Here if we do not find with clause on spec or body. We just ignore
- -- this case; it means that the elaboration involves some other unit
- -- than the unit being compiled, and will be caught elsewhere.
- end Activate_Elaborate_All_Desirable;
+ Set_Target (Marker, Target_Id);
+ Set_Is_Elaboration_Checks_OK_Node (Marker, Call_Attrs.Elab_Checks_OK);
+ Set_Is_Declaration_Level_Node (Marker, Call_Attrs.In_Declarations);
+ Set_Is_Dispatching_Call (Marker, Call_Attrs.Is_Dispatching);
+ Set_Is_Ignored_Ghost_Node (Marker, Call_Attrs.Ghost_Mode_Ignore);
+ Set_Is_Source_Call (Marker, Call_Attrs.From_Source);
+ Set_Is_SPARK_Mode_On_Node (Marker, Call_Attrs.SPARK_Mode_On);
- ------------------
- -- Check_A_Call --
- ------------------
+ -- The marker is inserted prior to the original call. This placement has
+ -- several desirable effects:
- procedure Check_A_Call
- (N : Node_Id;
- E : Entity_Id;
- Outer_Scope : Entity_Id;
- Inter_Unit_Only : Boolean;
- Generate_Warnings : Boolean := True;
- In_Init_Proc : Boolean := False)
- is
- Access_Case : constant Boolean := Nkind (N) = N_Attribute_Reference;
- -- Indicates if we have Access attribute case
-
- function Call_To_Instance_From_Outside (Id : Entity_Id) return Boolean;
- -- True if we're calling an instance of a generic subprogram, or a
- -- subprogram in an instance of a generic package, and the call is
- -- outside that instance.
-
- procedure Elab_Warning
- (Msg_D : String;
- Msg_S : String;
- Ent : Node_Or_Entity_Id);
- -- Generate a call to Error_Msg_NE with parameters Msg_D or Msg_S (for
- -- dynamic or static elaboration model), N and Ent. Msg_D is a real
- -- warning (output if Msg_D is non-null and Elab_Warnings is set),
- -- Msg_S is an info message (output if Elab_Info_Messages is set).
-
- function Find_W_Scope return Entity_Id;
- -- Find top-level scope for called entity (not following renamings
- -- or derivations). This is where the Elaborate_All will go if it is
- -- needed. We start with the called entity, except in the case of an
- -- initialization procedure outside the current package, where the init
- -- proc is in the root package, and we start from the entity of the name
- -- in the call.
+ -- 1) The marker appears in the same context, in close proximity to
+ -- the call.
- -----------------------------------
- -- Call_To_Instance_From_Outside --
- -----------------------------------
+ -- <marker>
+ -- <call>
- function Call_To_Instance_From_Outside (Id : Entity_Id) return Boolean is
- Scop : Entity_Id := Id;
+ -- 2) Inserting the marker prior to the call ensures that an ABE check
+ -- will take effect prior to the call.
- begin
- loop
- if Scop = Standard_Standard then
- return False;
- end if;
+ -- <ABE check>
+ -- <marker>
+ -- <call>
- if Is_Generic_Instance (Scop) then
- return not In_Open_Scopes (Scop);
- end if;
+ -- 3) The above two properties are preserved even when the call is a
+ -- function which is subsequently relocated in order to capture its
+ -- result. Note that if the call is relocated to a new context, the
+ -- relocated call will receive a marker of its own.
- Scop := Scope (Scop);
- end loop;
- end Call_To_Instance_From_Outside;
+ -- <ABE check>
+ -- <maker>
+ -- Temp : ... := Func_Call ...;
+ -- ... Temp ...
- ------------------
- -- Elab_Warning --
- ------------------
+ -- The insertion must take place even when the call does not occur in
+ -- the main unit to keep the tree symmetric. This ensures that internal
+ -- name serialization is consistent in case the call marker causes the
+ -- tree to transform in some way.
- procedure Elab_Warning
- (Msg_D : String;
- Msg_S : String;
- Ent : Node_Or_Entity_Id)
- is
- begin
- -- Dynamic elaboration checks, real warning
+ Insert_Action (N, Marker);
- if Dynamic_Elaboration_Checks then
- if not Access_Case then
- if Msg_D /= "" and then Elab_Warnings then
- Error_Msg_NE (Msg_D, N, Ent);
- end if;
+ -- The marker becomes the "corresponding" scenario for the call. Save
+ -- the marker for later processing by the ABE phase.
- -- In the access case emit first warning message as well,
- -- otherwise list of calls will appear as errors.
+ Record_Elaboration_Scenario (Marker);
+ end Build_Call_Marker;
- elsif Elab_Warnings then
- Error_Msg_NE (Msg_S, N, Ent);
- end if;
+ ---------------------------------
+ -- Check_Elaboration_Scenarios --
+ ---------------------------------
- -- Static elaboration checks, info message
+ procedure Check_Elaboration_Scenarios is
+ begin
+ -- Nothing to do for ASIS. As a result, no ABE checks and diagnostics
+ -- are performed in this mode.
- else
- if Elab_Info_Messages then
- Error_Msg_NE (Msg_S, N, Ent);
- end if;
- end if;
- end Elab_Warning;
+ if ASIS_Mode then
+ return;
+ end if;
+
+ -- Examine the context of the main unit and record all units with prior
+ -- elaboration with respect to it.
+
+ Find_Elaborated_Units;
+
+ -- Examine each top level scenario saved during the Recording phase and
+ -- perform various actions depending on the elaboration model in effect.
+
+ for Index in Top_Level_Scenarios.First .. Top_Level_Scenarios.Last loop
+
+ -- Clear the table of visited scenario bodies for each new top level
+ -- scenario.
+
+ Visited_Bodies.Reset;
+
+ Process_Scenario (Top_Level_Scenarios.Table (Index));
+ end loop;
+ end Check_Elaboration_Scenarios;
+
+ ------------------------------
+ -- Check_Preelaborated_Call --
+ ------------------------------
+
+ procedure Check_Preelaborated_Call (Call : Node_Id) is
+ function In_Preelaborated_Context (N : Node_Id) return Boolean;
+ -- Determine whether arbitrary node appears in a preelaborated context
- ------------------
- -- Find_W_Scope --
- ------------------
+ ------------------------------
+ -- In_Preelaborated_Context --
+ ------------------------------
- function Find_W_Scope return Entity_Id is
- Refed_Ent : constant Entity_Id := Get_Referenced_Ent (N);
- W_Scope : Entity_Id;
+ function In_Preelaborated_Context (N : Node_Id) return Boolean is
+ Body_Id : constant Entity_Id := Find_Code_Unit (N);
+ Spec_Id : constant Entity_Id := Unique_Entity (Body_Id);
begin
- if Is_Init_Proc (Refed_Ent)
- and then not In_Same_Extended_Unit (N, Refed_Ent)
+ -- The node appears within a package body whose corresponding spec is
+ -- subject to pragma Remote_Call_Interface or Remote_Types. This does
+ -- not result in a preelaborated context because the package body may
+ -- be on another machine.
+
+ if Ekind (Body_Id) = E_Package_Body
+ and then Ekind_In (Spec_Id, E_Generic_Package, E_Package)
+ and then (Is_Remote_Call_Interface (Spec_Id)
+ or else Is_Remote_Types (Spec_Id))
then
- W_Scope := Scope (Refed_Ent);
+ return False;
+
+ -- Otherwise the node appears within a preelaborated context when the
+ -- associated unit is preelaborated.
+
else
- W_Scope := E;
+ return Is_Preelaborated_Unit (Spec_Id);
end if;
+ end In_Preelaborated_Context;
- -- Now loop through scopes to get to the enclosing compilation unit
+ -- Local variables
- while not Is_Compilation_Unit (W_Scope) loop
- W_Scope := Scope (W_Scope);
- end loop;
+ Call_Attrs : Call_Attributes;
+ Level : Enclosing_Level_Kind;
+ Target_Id : Entity_Id;
- return W_Scope;
- end Find_W_Scope;
+ -- Start of processing for Check_Preelaborated_Call
- -- Local variables
+ begin
+ Extract_Call_Attributes
+ (Call => Call,
+ Target_Id => Target_Id,
+ Attrs => Call_Attrs);
- Inst_Case : constant Boolean := Nkind (N) in N_Generic_Instantiation;
- -- Indicates if we have instantiation case
-
- Loc : constant Source_Ptr := Sloc (N);
-
- Variable_Case : constant Boolean :=
- Nkind (N) in N_Has_Entity
- and then Present (Entity (N))
- and then Ekind (Entity (N)) = E_Variable;
- -- Indicates if we have variable reference case
-
- W_Scope : constant Entity_Id := Find_W_Scope;
- -- Top-level scope of directly called entity for subprogram. This
- -- differs from E_Scope in the case where renamings or derivations
- -- are involved, since it does not follow these links. W_Scope is
- -- generally in a visible unit, and it is this scope that may require
- -- an Elaborate_All. However, there are some cases (initialization
- -- calls and calls involving object notation) where W_Scope might not
- -- be in the context of the current unit, and there is an intermediate
- -- package that is, in which case the Elaborate_All has to be placed
- -- on this intermediate package. These special cases are handled in
- -- Set_Elaboration_Constraint.
-
- Ent : Entity_Id;
- Callee_Unit_Internal : Boolean;
- Caller_Unit_Internal : Boolean;
- Decl : Node_Id;
- Inst_Callee : Source_Ptr;
- Inst_Caller : Source_Ptr;
- Unit_Callee : Unit_Number_Type;
- Unit_Caller : Unit_Number_Type;
-
- Body_Acts_As_Spec : Boolean;
- -- Set to true if call is to body acting as spec (no separate spec)
-
- Cunit_SC : Boolean := False;
- -- Set to suppress dynamic elaboration checks where one of the
- -- enclosing scopes has Elaboration_Checks_Suppressed set, or else
- -- if a pragma Elaborate[_All] applies to that scope, in which case
- -- warnings on the scope are also suppressed. For the internal case,
- -- we ignore this flag.
-
- E_Scope : Entity_Id;
- -- Top-level scope of entity for called subprogram. This value includes
- -- following renamings and derivations, so this scope can be in a
- -- non-visible unit. This is the scope that is to be investigated to
- -- see whether an elaboration check is required.
-
- Is_DIC : Boolean;
- -- Flag set when the subprogram being invoked is the procedure generated
- -- for pragma Default_Initial_Condition.
-
- SPARK_Elab_Errors : Boolean;
- -- Flag set when an entity is called or a variable is read during SPARK
- -- dynamic elaboration.
-
- -- Start of processing for Check_A_Call
-
- begin
- -- If the call is known to be within a local Suppress Elaboration
- -- pragma, nothing to check. This can happen in task bodies. But
- -- we ignore this for a call to a generic formal.
-
- if Nkind (N) in N_Subprogram_Call
- and then No_Elaboration_Check (N)
- and then not Is_Call_Of_Generic_Formal (N)
- then
+ -- Nothing to do when the call is internally generated because it is
+ -- assumed that it will never violate preelaboration.
+
+ if not Call_Attrs.From_Source then
return;
+ end if;
- -- If this is a rewrite of a Valid_Scalars attribute, then nothing to
- -- check, we don't mind in this case if the call occurs before the body
- -- since this is all generated code.
+ -- Performance note: parent traversal
- elsif Nkind (Original_Node (N)) = N_Attribute_Reference
- and then Attribute_Name (Original_Node (N)) = Name_Valid_Scalars
- then
- return;
+ Level := Find_Enclosing_Level (Call);
- -- Intrinsics such as instances of Unchecked_Deallocation do not have
- -- any body, so elaboration checking is not needed, and would be wrong.
+ -- Library level calls are always considered because they are part of
+ -- the associated unit's elaboration actions.
- elsif Is_Intrinsic_Subprogram (E) then
- return;
+ if Level in Library_Level then
+ null;
- -- Do not consider references to internal variables for SPARK semantics
+ -- Calls at the library level of a generic package body must be checked
+ -- because they would render an instantiation illegal if the template is
+ -- marked as preelaborated. Note that this does not apply to calls at
+ -- the library level of a generic package spec.
- elsif Variable_Case and then not Comes_From_Source (E) then
+ elsif Level = Generic_Package_Body then
+ null;
+
+ -- Otherwise the call does not appear at the proper level and must not
+ -- be considered for this check.
+
+ else
return;
end if;
- -- Proceed with check
+ -- The call appears within a preelaborated unit. Emit a warning only for
+ -- internal uses, otherwise this is an error.
+
+ if In_Preelaborated_Context (Call) then
+ Error_Msg_Warn := GNAT_Mode;
+ Error_Msg_N
+ ("<<non-static call not allowed in preelaborated unit", Call);
+ end if;
+ end Check_Preelaborated_Call;
- Ent := E;
+ ----------------------
+ -- Compilation_Unit --
+ ----------------------
- -- For a variable reference, just set Body_Acts_As_Spec to False
+ function Compilation_Unit (Unit_Id : Entity_Id) return Node_Id is
+ Comp_Unit : Node_Id;
- if Variable_Case then
- Body_Acts_As_Spec := False;
+ begin
+ Comp_Unit := Parent (Unit_Id);
- -- Additional checks for all other cases
+ -- Handle the case where a concurrent subunit is rewritten as a null
+ -- statement due to expansion activities.
+
+ if Nkind (Comp_Unit) = N_Null_Statement
+ and then Nkind_In (Original_Node (Comp_Unit), N_Protected_Body,
+ N_Task_Body)
+ then
+ Comp_Unit := Parent (Comp_Unit);
+ pragma Assert (Nkind (Comp_Unit) = N_Subunit);
+
+ -- Otherwise use the declaration node of the unit
else
- -- Go to parent for derived subprogram, or to original subprogram in
- -- the case of a renaming (Alias covers both these cases).
+ Comp_Unit := Parent (Unit_Declaration_Node (Unit_Id));
+ end if;
- loop
- if (Suppress_Elaboration_Warnings (Ent)
- or else Elaboration_Checks_Suppressed (Ent))
- and then (Inst_Case or else No (Alias (Ent)))
- then
- return;
- end if;
+ -- Handle the case where a subprogram instantiation which acts as a
+ -- compilation unit is expanded into an anonymous package that wraps
+ -- the instantiated subprogram.
- -- Nothing to do for imported entities
+ if Nkind (Comp_Unit) = N_Package_Specification
+ and then Nkind_In (Original_Node (Parent (Comp_Unit)),
+ N_Function_Instantiation,
+ N_Procedure_Instantiation)
+ then
+ Comp_Unit := Parent (Parent (Comp_Unit));
- if Is_Imported (Ent) then
- return;
- end if;
+ -- Handle the case where the compilation unit is a subunit
- exit when Inst_Case or else No (Alias (Ent));
- Ent := Alias (Ent);
- end loop;
+ elsif Nkind (Comp_Unit) = N_Subunit then
+ Comp_Unit := Parent (Comp_Unit);
+ end if;
- Decl := Unit_Declaration_Node (Ent);
+ pragma Assert (Nkind (Comp_Unit) = N_Compilation_Unit);
- if Nkind (Decl) = N_Subprogram_Body then
- Body_Acts_As_Spec := True;
+ return Comp_Unit;
+ end Compilation_Unit;
- elsif Nkind_In (Decl, N_Subprogram_Declaration,
- N_Subprogram_Body_Stub)
- or else Inst_Case
- then
- Body_Acts_As_Spec := False;
+ -----------------
+ -- Elab_Msg_NE --
+ -----------------
+
+ procedure Elab_Msg_NE
+ (Msg : String;
+ N : Node_Id;
+ Id : Entity_Id;
+ Info_Msg : Boolean;
+ In_SPARK : Boolean)
+ is
+ function Prefix return String;
+ -- Obtain the prefix of the message
- -- If we have none of an instantiation, subprogram body or subprogram
- -- declaration, or in the SPARK case, a variable reference, then
- -- it is not a case that we want to check. (One case is a call to a
- -- generic formal subprogram, where we do not want the check in the
- -- template).
+ function Suffix return String;
+ -- Obtain the suffix of the message
+ ------------
+ -- Prefix --
+ ------------
+
+ function Prefix return String is
+ begin
+ if Info_Msg then
+ return "info: ";
else
- return;
+ return "";
end if;
- end if;
+ end Prefix;
- E_Scope := Ent;
- loop
- if Elaboration_Checks_Suppressed (E_Scope)
- or else Suppress_Elaboration_Warnings (E_Scope)
- then
- Cunit_SC := True;
+ ------------
+ -- Suffix --
+ ------------
+
+ function Suffix return String is
+ begin
+ if In_SPARK then
+ return " in SPARK";
+ else
+ return "";
end if;
+ end Suffix;
- -- Exit when we get to compilation unit, not counting subunits
+ -- Start of processing for Elab_Msg_NE
- exit when Is_Compilation_Unit (E_Scope)
- and then (Is_Child_Unit (E_Scope)
- or else Scope (E_Scope) = Standard_Standard);
+ begin
+ Error_Msg_NE (Prefix & Msg & Suffix, N, Id);
+ end Elab_Msg_NE;
- pragma Assert (E_Scope /= Standard_Standard);
+ ------------------------------
+ -- Elaboration_Context_Hash --
+ ------------------------------
- -- Move up a scope looking for compilation unit
+ function Elaboration_Context_Hash
+ (Key : Entity_Id) return Elaboration_Context_Index
+ is
+ begin
+ return Elaboration_Context_Index (Key mod Elaboration_Context_Max);
+ end Elaboration_Context_Hash;
- E_Scope := Scope (E_Scope);
- end loop;
+ ------------------------------
+ -- Ensure_Prior_Elaboration --
+ ------------------------------
- -- No checks needed for pure or preelaborated compilation units
+ procedure Ensure_Prior_Elaboration
+ (N : Node_Id;
+ Unit_Id : Entity_Id;
+ In_Task_Body : Boolean)
+ is
+ Prag_Nam : Name_Id;
- if Is_Pure (E_Scope) or else Is_Preelaborated (E_Scope) then
- return;
+ begin
+ -- Instantiating an external generic unit requires an implicit Elaborate
+ -- because Elaborate_All is too strong and could introduce non-existent
+ -- elaboration cycles.
+
+ -- package External is
+ -- function Func ...;
+ -- end External;
+
+ -- with External;
+ -- generic
+ -- package Gen is
+ -- X : ... := External.Func;
+ -- end Gen;
+
+ -- [with External;] -- implicit with for External
+ -- [pragma Elaborate_All (External);] -- Elaborate_All for External
+ -- with Gen;
+ -- [pragma Elaborate (Gen);] -- Elaborate for generic
+ -- procedure Main is
+ -- package Inst is new Gen; -- calls External.Func
+ -- ...
+ -- end Main;
+
+ if Nkind (N) in N_Generic_Instantiation then
+ Prag_Nam := Name_Elaborate;
+
+ -- Otherwise generate an implicit Elaborate_All
+
+ else
+ Prag_Nam := Name_Elaborate_All;
end if;
- -- If the generic entity is within a deeper instance than we are, then
- -- either the instantiation to which we refer itself caused an ABE, in
- -- which case that will be handled separately, or else we know that the
- -- body we need appears as needed at the point of the instantiation.
- -- However, this assumption is only valid if we are in static mode.
+ -- Nothing to do when the need for prior elaboration came from a task
+ -- body and switch -gnatd.y (disable implicit pragma Elaborate_All on
+ -- task bodies) is in effect.
+
+ if Debug_Flag_Dot_Y and then In_Task_Body then
+ return;
- if not Dynamic_Elaboration_Checks
- and then
- Instantiation_Depth (Sloc (Ent)) > Instantiation_Depth (Sloc (N))
+ -- Nothing to do when the unit is elaborated prior to the main unit.
+ -- This check must also consider the following cases:
+
+ -- * No check is made against the context of the main unit because this
+ -- is specific to the elaboration model in effect and requires custom
+ -- handling (see Ensure_xxx_Prior_Elaboration).
+
+ -- * Unit_Id is subject to pragma Elaborate_Body. An implicit pragma
+ -- Elaborate[_All] MUST be generated even though Unit_Id is always
+ -- elaborated prior to the main unit. This is a conservative strategy
+ -- which ensures that other units withed by Unit_Id will not lead to
+ -- an ABE.
+
+ -- package A is package body A is
+ -- procedure ABE; procedure ABE is ... end ABE;
+ -- end A; end A;
+
+ -- with A;
+ -- package B is package body B is
+ -- pragma Elaborate_Body; procedure Proc is
+ -- begin
+ -- procedure Proc; A.ABE;
+ -- package B; end Proc;
+ -- end B;
+
+ -- with B;
+ -- package C is package body C is
+ -- ... ...
+ -- end C; begin
+ -- B.Proc;
+ -- end C;
+
+ -- In the example above, the elaboration of C invokes B.Proc. B is
+ -- subject to pragma Elaborate_Body. If no pragma Elaborate[_All] is
+ -- generated for B in C, then the following elaboratio order will lead
+ -- to an ABE:
+
+ -- spec of A elaborated
+ -- spec of B elaborated
+ -- body of B elaborated
+ -- spec of C elaborated
+ -- body of C elaborated <-- calls B.Proc which calls A.ABE
+ -- body of A elaborated <-- problem
+
+ -- The generation of an implicit pragma Elaborate_All (B) ensures that
+ -- the elaboration order mechanism will not pick the above order.
+
+ -- An implicit Elaborate is NOT generated when the unit is subject to
+ -- Elaborate_Body because both pragmas have the exact same effect.
+
+ -- * Unit_Id is the main unit. An implicit pragma Elaborate[_All] MUST
+ -- NOT be generated in this case because a unit cannot depend on its
+ -- own elaboration. This case is therefore treated as valid prior
+ -- elaboration.
+
+ elsif Has_Prior_Elaboration
+ (Unit_Id => Unit_Id,
+ Same_Unit_OK => True,
+ Elab_Body_OK => Prag_Nam = Name_Elaborate)
then
return;
- end if;
- -- Do not give a warning for a package with no body
+ -- Suggest the use of pragma Prag_Nam when the dynamic model is in
+ -- effect.
- if Ekind (Ent) = E_Generic_Package and then not Has_Generic_Body (N) then
- return;
+ elsif Dynamic_Elaboration_Checks then
+ Ensure_Prior_Elaboration_Dynamic
+ (N => N,
+ Unit_Id => Unit_Id,
+ Prag_Nam => Prag_Nam);
+
+ -- Install an implicit pragma Prag_Nam when the static model is in
+ -- effect.
+
+ else
+ pragma Assert (Static_Elaboration_Checks);
+
+ Ensure_Prior_Elaboration_Static
+ (N => N,
+ Unit_Id => Unit_Id,
+ Prag_Nam => Prag_Nam);
end if;
+ end Ensure_Prior_Elaboration;
- -- Case of entity is in same unit as call or instantiation. In the
- -- instantiation case, W_Scope may be different from E_Scope; we want
- -- the unit in which the instantiation occurs, since we're analyzing
- -- based on the expansion.
+ --------------------------------------
+ -- Ensure_Prior_Elaboration_Dynamic --
+ --------------------------------------
+
+ procedure Ensure_Prior_Elaboration_Dynamic
+ (N : Node_Id;
+ Unit_Id : Entity_Id;
+ Prag_Nam : Name_Id)
+ is
+ procedure Info_Missing_Pragma;
+ pragma Inline (Info_Missing_Pragma);
+ -- Output information concerning missing Elaborate or Elaborate_All
+ -- pragma with name Prag_Nam for scenario N, which would ensure the
+ -- prior elaboration of Unit_Id.
- if W_Scope = C_Scope then
- if not Inter_Unit_Only then
- Check_Internal_Call (N, Ent, Outer_Scope, E);
+ -------------------------
+ -- Info_Missing_Pragma --
+ -------------------------
+
+ procedure Info_Missing_Pragma is
+ begin
+ -- Internal units are ignored as they cause unnecessary noise
+
+ if not In_Internal_Unit (Unit_Id) then
+
+ -- The name of the unit subjected to the elaboration pragma is
+ -- fully qualified to improve the clarity of the info message.
+
+ Error_Msg_Name_1 := Prag_Nam;
+ Error_Msg_Qual_Level := Nat'Last;
+
+ Error_Msg_NE ("info: missing pragma % for unit &", N, Unit_Id);
+ Error_Msg_Qual_Level := 0;
end if;
+ end Info_Missing_Pragma;
- return;
- end if;
+ -- Local variables
- -- Case of entity is not in current unit (i.e. with'ed unit case)
+ Elab_Attrs : Elaboration_Attributes;
+ Level : Enclosing_Level_Kind;
- -- We are only interested in such calls if the outer call was from
- -- elaboration code, or if we are in Dynamic_Elaboration_Checks mode.
+ -- Start of processing for Ensure_Prior_Elaboration_Dynamic
- if not From_Elab_Code and then not Dynamic_Elaboration_Checks then
- return;
- end if;
+ begin
+ Elab_Attrs := Elaboration_Context.Get (Unit_Id);
- -- Nothing to do if some scope said that no checks were required
+ -- Nothing to do when the unit is guaranteed prior elaboration by means
+ -- of a source Elaborate[_All] pragma.
- if Cunit_SC then
+ if Present (Elab_Attrs.Source_Pragma) then
return;
end if;
- -- Nothing to do for a generic instance, because a call to an instance
- -- cannot fail the elaboration check, because the body of the instance
- -- is always elaborated immediately after the spec.
+ -- Output extra information on a missing Elaborate[_All] pragma when
+ -- switch -gnatel (info messages on implicit Elaborate[_All] pragmas
+ -- is in effect.
- if Call_To_Instance_From_Outside (Ent) then
- return;
- end if;
+ if Elab_Info_Messages then
- -- Nothing to do if subprogram with no separate spec. However, a call
- -- to Deep_Initialize may result in a call to a user-defined Initialize
- -- procedure, which imposes a body dependency. This happens only if the
- -- type is controlled and the Initialize procedure is not inherited.
+ -- Performance note: parent traversal
- if Body_Acts_As_Spec then
- if Is_TSS (Ent, TSS_Deep_Initialize) then
- declare
- Typ : constant Entity_Id := Etype (First_Formal (Ent));
- Init : Entity_Id;
+ Level := Find_Enclosing_Level (N);
- begin
- if not Is_Controlled (Typ) then
- return;
- else
- Init := Find_Prim_Op (Typ, Name_Initialize);
+ -- Declaration-level scenario
- if Comes_From_Source (Init) then
- Ent := Init;
- else
- return;
- end if;
- end if;
- end;
+ if (Is_Suitable_Call (N) or else Is_Suitable_Instantiation (N))
+ and then Level = Declaration_Level
+ then
+ null;
+
+ -- Library-level scenario
+
+ elsif Level in Library_Level then
+ null;
+
+ -- Instantiation library-level scenario
+
+ elsif Level = Instantiation then
+ null;
+
+ -- Otherwise the scenario does not appear at the proper level and
+ -- cannot possibly act as a top-level scenario.
else
return;
end if;
+
+ Info_Missing_Pragma;
end if;
+ end Ensure_Prior_Elaboration_Dynamic;
- -- Check cases of internal units
+ -------------------------------------
+ -- Ensure_Prior_Elaboration_Static --
+ -------------------------------------
- Callee_Unit_Internal := In_Internal_Unit (E_Scope);
+ procedure Ensure_Prior_Elaboration_Static
+ (N : Node_Id;
+ Unit_Id : Entity_Id;
+ Prag_Nam : Name_Id)
+ is
+ function Find_With_Clause
+ (Items : List_Id;
+ Withed_Id : Entity_Id) return Node_Id;
+ pragma Inline (Find_With_Clause);
+ -- Find a nonlimited with clause in the list of context items Items
+ -- that withs unit Withed_Id. Return Empty if no such clause is found.
+
+ procedure Info_Implicit_Pragma;
+ pragma Inline (Info_Implicit_Pragma);
+ -- Output information concerning an implicitly generated Elaborate or
+ -- Elaborate_All pragma with name Prag_Nam for scenario N which ensures
+ -- the prior elaboration of unit Unit_Id.
+
+ ----------------------
+ -- Find_With_Clause --
+ ----------------------
+
+ function Find_With_Clause
+ (Items : List_Id;
+ Withed_Id : Entity_Id) return Node_Id
+ is
+ Item : Node_Id;
- -- Do not give a warning if the with'ed unit is internal and this is
- -- the generic instantiation case (this saves a lot of hassle dealing
- -- with the Text_IO special child units)
+ begin
+ -- Examine the context clauses looking for a suitable with. Note that
+ -- limited clauses do not affect the elaboration order.
- if Callee_Unit_Internal and Inst_Case then
- return;
- end if;
+ Item := First (Items);
+ while Present (Item) loop
+ if Nkind (Item) = N_With_Clause
+ and then not Error_Posted (Item)
+ and then not Limited_Present (Item)
+ and then Entity (Name (Item)) = Withed_Id
+ then
+ return Item;
+ end if;
- if C_Scope = Standard_Standard then
- Caller_Unit_Internal := False;
- else
- Caller_Unit_Internal := In_Internal_Unit (C_Scope);
- end if;
+ Next (Item);
+ end loop;
+
+ return Empty;
+ end Find_With_Clause;
+
+ --------------------------
+ -- Info_Implicit_Pragma --
+ --------------------------
+
+ procedure Info_Implicit_Pragma is
+ begin
+ -- Internal units are ignored as they cause unnecessary noise
+
+ if not In_Internal_Unit (Unit_Id) then
+
+ -- The name of the unit subjected to the elaboration pragma is
+ -- fully qualified to improve the clarity of the info message.
+
+ Error_Msg_Name_1 := Prag_Nam;
+ Error_Msg_Qual_Level := Nat'Last;
+
+ Error_Msg_NE
+ ("info: implicit pragma % generated for unit &", N, Unit_Id);
+
+ Error_Msg_Qual_Level := 0;
+ Output_Active_Scenarios (N);
+ end if;
+ end Info_Implicit_Pragma;
+
+ -- Local variables
- -- Do not give a warning if the with'ed unit is internal and the caller
- -- is not internal (since the binder always elaborates internal units
- -- first).
+ Main_Cunit : constant Node_Id := Cunit (Main_Unit);
+ Loc : constant Source_Ptr := Sloc (Main_Cunit);
+ Unit_Cunit : constant Node_Id := Compilation_Unit (Unit_Id);
- if Callee_Unit_Internal and not Caller_Unit_Internal then
+ Is_Instantiation : constant Boolean :=
+ Nkind (N) in N_Generic_Instantiation;
+
+ Clause : Node_Id;
+ Elab_Attrs : Elaboration_Attributes;
+ Items : List_Id;
+
+ -- Start of processing for Ensure_Prior_Elaboration_Static
+
+ begin
+ Elab_Attrs := Elaboration_Context.Get (Unit_Id);
+
+ -- Nothing to do when the unit is guaranteed prior elaboration by means
+ -- of a source Elaborate[_All] pragma.
+
+ if Present (Elab_Attrs.Source_Pragma) then
return;
- end if;
- -- For now, if debug flag -gnatdE is not set, do no checking for one
- -- internal unit withing another. This fixes the problem with the sgi
- -- build and storage errors. To be resolved later ???
+ -- Nothing to do when the unit has an existing implicit Elaborate[_All]
+ -- pragma installed by a previous scenario.
+
+ elsif Present (Elab_Attrs.With_Clause) then
+
+ -- The unit is already guaranteed prior elaboration by means of an
+ -- implicit Elaborate pragma, however the current scenario imposes
+ -- a stronger requirement of Elaborate_All. "Upgrade" the existing
+ -- pragma to match this new requirement.
+
+ if Elaborate_Desirable (Elab_Attrs.With_Clause)
+ and then Prag_Nam = Name_Elaborate_All
+ then
+ Set_Elaborate_All_Desirable (Elab_Attrs.With_Clause);
+ Set_Elaborate_Desirable (Elab_Attrs.With_Clause, False);
+ end if;
- if (Callee_Unit_Internal and Caller_Unit_Internal)
- and not Debug_Flag_EE
- then
return;
end if;
- if Is_TSS (E, TSS_Deep_Initialize) then
- Ent := E;
+ -- At this point it is known that the unit has no prior elaboration
+ -- according to pragmas and hierarchical relationships.
+
+ Items := Context_Items (Main_Cunit);
+
+ if No (Items) then
+ Items := New_List;
+ Set_Context_Items (Main_Cunit, Items);
end if;
- -- If the call is in an instance, and the called entity is not
- -- defined in the same instance, then the elaboration issue focuses
- -- around the unit containing the template, it is this unit that
- -- requires an Elaborate_All.
+ -- Locate the with clause for the unit. Note that there may not be a
+ -- clause if the unit is visible through a subunit-body, body-spec, or
+ -- spec-parent relationship.
- -- However, if we are doing dynamic elaboration, we need to chase the
- -- call in the usual manner.
+ Clause :=
+ Find_With_Clause
+ (Items => Items,
+ Withed_Id => Unit_Id);
- -- We also need to chase the call in the usual manner if it is a call
- -- to a generic formal parameter, since that case was not handled as
- -- part of the processing of the template.
+ -- Generate:
+ -- with Id;
- Inst_Caller := Instantiation (Get_Source_File_Index (Sloc (N)));
- Inst_Callee := Instantiation (Get_Source_File_Index (Sloc (Ent)));
+ -- Note that adding implicit with clauses is safe because analysis,
+ -- resolution, and expansion have already taken place and it is not
+ -- possible to interfere with visibility.
- if Inst_Caller = No_Location then
- Unit_Caller := No_Unit;
- else
- Unit_Caller := Get_Source_Unit (N);
+ if No (Clause) then
+ Clause :=
+ Make_With_Clause (Loc,
+ Name => New_Occurrence_Of (Unit_Id, Loc));
+
+ Set_Implicit_With (Clause);
+ Set_Library_Unit (Clause, Unit_Cunit);
+
+ Append_To (Items, Clause);
end if;
- if Inst_Callee = No_Location then
- Unit_Callee := No_Unit;
+ -- Instantiations require an implicit Elaborate because Elaborate_All is
+ -- too conservative and may introduce non-existent elaboration cycles.
+
+ if Is_Instantiation then
+ Set_Elaborate_Desirable (Clause);
+
+ -- Otherwise generate an implicit Elaborate_All
+
else
- Unit_Callee := Get_Source_Unit (Ent);
+ Set_Elaborate_All_Desirable (Clause);
end if;
- if Unit_Caller /= No_Unit
- and then Unit_Callee /= Unit_Caller
- and then not Dynamic_Elaboration_Checks
- and then not Is_Call_Of_Generic_Formal (N)
- then
- E_Scope := Spec_Entity (Cunit_Entity (Unit_Caller));
+ -- The implicit Elaborate[_All] ensures the prior elaboration of the
+ -- unit. Include the unit in the elaboration context of the main unit.
- -- If we don't get a spec entity, just ignore call. Not quite
- -- clear why this check is necessary. ???
+ Elaboration_Context.Set (Unit_Id,
+ Elaboration_Attributes'(Source_Pragma => Empty,
+ With_Clause => Clause));
- if No (E_Scope) then
- return;
- end if;
+ -- Output extra information on an implicit Elaborate[_All] pragma when
+ -- switch -gnatel (info messages on implicit Elaborate[_All] pragmas is
+ -- in effect.
- -- Otherwise step to enclosing compilation unit
+ if Elab_Info_Messages then
+ Info_Implicit_Pragma;
+ end if;
+ end Ensure_Prior_Elaboration_Static;
- while not Is_Compilation_Unit (E_Scope) loop
- E_Scope := Scope (E_Scope);
- end loop;
+ -----------------------------
+ -- Extract_Assignment_Name --
+ -----------------------------
- -- For the case where N is not an instance, and is not a call within
- -- instance to other than a generic formal, we recompute E_Scope
- -- for the error message, since we do NOT want to go to the unit
- -- that has the ultimate declaration in the case of renaming and
- -- derivation and we also want to go to the generic unit in the
- -- case of an instance, and no further.
+ function Extract_Assignment_Name (Asmt : Node_Id) return Node_Id is
+ Nam : Node_Id;
+
+ begin
+ Nam := Name (Asmt);
+
+ -- When the name denotes an array or record component, find the whole
+ -- object.
+
+ while Nkind_In (Nam, N_Explicit_Dereference,
+ N_Indexed_Component,
+ N_Selected_Component,
+ N_Slice)
+ loop
+ Nam := Prefix (Nam);
+ end loop;
+
+ return Nam;
+ end Extract_Assignment_Name;
+
+ -----------------------------
+ -- Extract_Call_Attributes --
+ -----------------------------
+
+ procedure Extract_Call_Attributes
+ (Call : Node_Id;
+ Target_Id : out Entity_Id;
+ Attrs : out Call_Attributes)
+ is
+ From_Source : Boolean;
+ In_Declarations : Boolean;
+ Is_Dispatching : Boolean;
+
+ begin
+ -- Extraction for call markers
+
+ if Nkind (Call) = N_Call_Marker then
+ Target_Id := Target (Call);
+ From_Source := Is_Source_Call (Call);
+ In_Declarations := Is_Declaration_Level_Node (Call);
+ Is_Dispatching := Is_Dispatching_Call (Call);
+
+ -- Extraction for entry calls, requeue, and subprogram calls
else
- -- Loop to carefully follow renamings and derivations one step
- -- outside the current unit, but not further.
+ pragma Assert (Nkind_In (Call, N_Entry_Call_Statement,
+ N_Function_Call,
+ N_Procedure_Call_Statement,
+ N_Requeue_Statement));
- if not (Inst_Case or Variable_Case)
- and then Present (Alias (Ent))
- then
- E_Scope := Alias (Ent);
- else
- E_Scope := Ent;
- end if;
+ Target_Id := Entity (Extract_Call_Name (Call));
+ From_Source := Comes_From_Source (Call);
- loop
- while not Is_Compilation_Unit (E_Scope) loop
- E_Scope := Scope (E_Scope);
- end loop;
+ -- Performance note: parent traversal
+
+ In_Declarations := Find_Enclosing_Level (Call) = Declaration_Level;
+ Is_Dispatching :=
+ Nkind_In (Call, N_Function_Call, N_Procedure_Call_Statement)
+ and then Present (Controlling_Argument (Call));
+ end if;
- -- If E_Scope is the same as C_Scope, it means that there
- -- definitely was a local renaming or derivation, and we
- -- are not yet out of the current unit.
+ -- Obtain the original entry or subprogram which the target may rename
+ -- except when the target is an instantiation. In this case the alias
+ -- is the internally generated subprogram which appears within the the
+ -- anonymous package created for the instantiation. Such an alias is not
+ -- a suitable target.
- exit when E_Scope /= C_Scope;
- Ent := Alias (Ent);
- E_Scope := Ent;
+ if not (Is_Subprogram (Target_Id)
+ and then Is_Generic_Instance (Target_Id))
+ then
+ Target_Id := Get_Renamed_Entity (Target_Id);
+ end if;
- -- If no alias, there could be a previous error, but not if we've
- -- already reached the outermost level (Standard).
+ -- Set all attributes
- if No (Ent) then
- return;
- end if;
- end loop;
+ Attrs.Elab_Checks_OK := Is_Elaboration_Checks_OK_Node (Call);
+ Attrs.From_Source := From_Source;
+ Attrs.Ghost_Mode_Ignore := Is_Ignored_Ghost_Node (Call);
+ Attrs.In_Declarations := In_Declarations;
+ Attrs.Is_Dispatching := Is_Dispatching;
+ Attrs.SPARK_Mode_On := Is_SPARK_Mode_On_Node (Call);
+ end Extract_Call_Attributes;
+
+ -----------------------
+ -- Extract_Call_Name --
+ -----------------------
+
+ function Extract_Call_Name (Call : Node_Id) return Node_Id is
+ Nam : Node_Id;
+
+ begin
+ Nam := Name (Call);
+
+ -- When the call invokes an entry family, the name appears as an indexed
+ -- component.
+
+ if Nkind (Nam) = N_Indexed_Component then
+ Nam := Prefix (Nam);
end if;
- if Within_Elaborate_All (Current_Sem_Unit, E_Scope) then
- return;
+ -- When the call employs the object.operation form, the name appears as
+ -- a selected component.
+
+ if Nkind (Nam) = N_Selected_Component then
+ Nam := Selector_Name (Nam);
end if;
- -- Determine whether the Default_Initial_Condition procedure of some
- -- type is being invoked.
+ return Nam;
+ end Extract_Call_Name;
- Is_DIC := Ekind (Ent) = E_Procedure and then Is_DIC_Procedure (Ent);
+ ---------------------------------
+ -- Extract_Instance_Attributes --
+ ---------------------------------
- -- Checks related to Default_Initial_Condition fall under the SPARK
- -- umbrella because this is a SPARK-specific annotation.
+ procedure Extract_Instance_Attributes
+ (Exp_Inst : Node_Id;
+ Inst_Body : out Node_Id;
+ Inst_Decl : out Node_Id)
+ is
+ Body_Id : Entity_Id;
+
+ begin
+ -- Assume that the attributes are unavailable
- SPARK_Elab_Errors :=
- SPARK_Mode = On and (Is_DIC or Dynamic_Elaboration_Checks);
+ Inst_Body := Empty;
+ Inst_Decl := Empty;
- -- Now check if an Elaborate_All (or dynamic check) is needed
+ -- Generic package or subprogram spec
- if (Elab_Info_Messages or Elab_Warnings or SPARK_Elab_Errors)
- and then Generate_Warnings
- and then not Suppress_Elaboration_Warnings (Ent)
- and then not Elaboration_Checks_Suppressed (Ent)
- and then not Suppress_Elaboration_Warnings (E_Scope)
- and then not Elaboration_Checks_Suppressed (E_Scope)
+ if Nkind_In (Exp_Inst, N_Package_Declaration,
+ N_Subprogram_Declaration)
then
- -- Instantiation case
+ Inst_Decl := Exp_Inst;
+ Body_Id := Corresponding_Body (Inst_Decl);
- if Inst_Case then
- if Comes_From_Source (Ent) and then SPARK_Elab_Errors then
- Error_Msg_NE
- ("instantiation of & during elaboration in SPARK", N, Ent);
- else
- Elab_Warning
- ("instantiation of & may raise Program_Error?l?",
- "info: instantiation of & during elaboration?$?", Ent);
- end if;
+ if Present (Body_Id) then
+ Inst_Body := Unit_Declaration_Node (Body_Id);
+ end if;
- -- Indirect call case, info message only in static elaboration
- -- case, because the attribute reference itself cannot raise an
- -- exception. Note that SPARK does not permit indirect calls.
+ -- Generic package or subprogram body
- elsif Access_Case then
- Elab_Warning ("", "info: access to & during elaboration?$?", Ent);
+ else
+ pragma Assert
+ (Nkind_In (Exp_Inst, N_Package_Body, N_Subprogram_Body));
- -- Variable reference in SPARK mode
+ Inst_Body := Exp_Inst;
+ Inst_Decl := Unit_Declaration_Node (Corresponding_Spec (Inst_Body));
+ end if;
+ end Extract_Instance_Attributes;
- elsif Variable_Case then
- if Comes_From_Source (Ent) and then SPARK_Elab_Errors then
- Error_Msg_NE
- ("reference to & during elaboration in SPARK", N, Ent);
- end if;
+ --------------------------------------
+ -- Extract_Instantiation_Attributes --
+ --------------------------------------
- -- Subprogram call case
+ procedure Extract_Instantiation_Attributes
+ (Exp_Inst : Node_Id;
+ Inst : out Node_Id;
+ Inst_Id : out Entity_Id;
+ Gen_Id : out Entity_Id;
+ Attrs : out Instantiation_Attributes)
+ is
+ begin
+ Inst := Original_Node (Exp_Inst);
+ Inst_Id := Defining_Entity (Inst);
- else
- if Nkind (Name (N)) in N_Has_Entity
- and then Is_Init_Proc (Entity (Name (N)))
- and then Comes_From_Source (Ent)
- then
- Elab_Warning
- ("implicit call to & may raise Program_Error?l?",
- "info: implicit call to & during elaboration?$?",
- Ent);
-
- elsif SPARK_Elab_Errors then
-
- -- Emit a specialized error message when the elaboration of an
- -- object of a private type evaluates the expression of pragma
- -- Default_Initial_Condition. This prevents the internal name
- -- of the procedure from appearing in the error message.
-
- if Is_DIC then
- Error_Msg_N
- ("call to Default_Initial_Condition during elaboration in "
- & "SPARK", N);
- else
- Error_Msg_NE
- ("call to & during elaboration in SPARK", N, Ent);
- end if;
+ -- Traverse a possible chain of renamings to obtain the original generic
+ -- being instantiatied.
- else
- Elab_Warning
- ("call to & may raise Program_Error?l?",
- "info: call to & during elaboration?$?",
- Ent);
+ Gen_Id := Get_Renamed_Entity (Entity (Name (Inst)));
+
+ -- Set all attributes
+
+ Attrs.Elab_Checks_OK := Is_Elaboration_Checks_OK_Node (Inst);
+ Attrs.Ghost_Mode_Ignore := Is_Ignored_Ghost_Node (Inst);
+ Attrs.In_Declarations := Is_Declaration_Level_Node (Inst);
+ Attrs.SPARK_Mode_On := Is_SPARK_Mode_On_Node (Inst);
+ end Extract_Instantiation_Attributes;
+
+ -------------------------------
+ -- Extract_Target_Attributes --
+ -------------------------------
+
+ procedure Extract_Target_Attributes
+ (Target_Id : Entity_Id;
+ Attrs : out Target_Attributes)
+ is
+ procedure Extract_Package_Or_Subprogram_Attributes
+ (Spec_Id : out Entity_Id;
+ Body_Decl : out Node_Id);
+ -- Obtain the attributes associated with a package or a subprogram.
+ -- Spec_Id is the package or subprogram. Body_Decl is the declaration
+ -- of the corresponding package or subprogram body.
+
+ procedure Extract_Protected_Entry_Attributes
+ (Spec_Id : out Entity_Id;
+ Body_Decl : out Node_Id;
+ Body_Barf : out Node_Id);
+ -- Obtain the attributes associated with a protected entry [family].
+ -- Spec_Id is the entity of the protected body subprogram. Body_Decl
+ -- is the declaration of Spec_Id's corresponding body. Body_Barf is
+ -- the declaration of the barrier function body.
+
+ procedure Extract_Protected_Subprogram_Attributes
+ (Spec_Id : out Entity_Id;
+ Body_Decl : out Node_Id);
+ -- Obtain the attributes associated with a protected subprogram. Formal
+ -- Spec_Id is the entity of the protected body subprogram. Body_Decl is
+ -- the declaration of Spec_Id's corresponding body.
+
+ procedure Extract_Task_Entry_Attributes
+ (Spec_Id : out Entity_Id;
+ Body_Decl : out Node_Id);
+ -- Obtain the attributes associated with a task entry [family]. Formal
+ -- Spec_Id is the entity of the task body procedure. Body_Decl is the
+ -- declaration of Spec_Id's corresponding body.
+
+ ----------------------------------------------
+ -- Extract_Package_Or_Subprogram_Attributes --
+ ----------------------------------------------
+
+ procedure Extract_Package_Or_Subprogram_Attributes
+ (Spec_Id : out Entity_Id;
+ Body_Decl : out Node_Id)
+ is
+ Body_Id : Entity_Id;
+ Init_Id : Entity_Id;
+ Spec_Decl : Node_Id;
+
+ begin
+ -- Assume that the body is not available
+
+ Body_Decl := Empty;
+ Spec_Id := Target_Id;
+
+ -- For body retrieval purposes, the entity of the initial declaration
+ -- is that of the spec.
+
+ Init_Id := Spec_Id;
+
+ -- The only exception to the above is a function which returns a
+ -- constrained array type in a SPARK-to-C compilation. In this case
+ -- the function receives a corresponding procedure which has an out
+ -- parameter. The proper body for ABE checks and diagnostics is that
+ -- of the procedure.
+
+ if Ekind (Init_Id) = E_Function
+ and then Rewritten_For_C (Init_Id)
+ then
+ Init_Id := Corresponding_Procedure (Init_Id);
+ end if;
+
+ -- Extract the attributes of the body
+
+ Spec_Decl := Unit_Declaration_Node (Init_Id);
+
+ -- The initial declaration is a stand alone subprogram body
+
+ if Nkind (Spec_Decl) = N_Subprogram_Body then
+ Body_Decl := Spec_Decl;
+
+ -- Otherwise the package or subprogram has a spec and a completing
+ -- body.
+
+ elsif Nkind_In (Spec_Decl, N_Generic_Package_Declaration,
+ N_Generic_Subprogram_Declaration,
+ N_Package_Declaration,
+ N_Subprogram_Body_Stub,
+ N_Subprogram_Declaration)
+ then
+ Body_Id := Corresponding_Body (Spec_Decl);
+
+ if Present (Body_Id) then
+ Body_Decl := Unit_Declaration_Node (Body_Id);
end if;
end if;
+ end Extract_Package_Or_Subprogram_Attributes;
- Error_Msg_Qual_Level := Nat'Last;
+ ----------------------------------------
+ -- Extract_Protected_Entry_Attributes --
+ ----------------------------------------
- -- Case of Elaborate_All not present and required, for SPARK this
- -- is an error, so give an error message.
+ procedure Extract_Protected_Entry_Attributes
+ (Spec_Id : out Entity_Id;
+ Body_Decl : out Node_Id;
+ Body_Barf : out Node_Id)
+ is
+ Barf_Id : Entity_Id;
+ Body_Id : Entity_Id;
+
+ begin
+ -- Assume that the bodies are not available
- if SPARK_Elab_Errors then
- Error_Msg_NE -- CODEFIX
- ("\Elaborate_All pragma required for&", N, W_Scope);
+ Body_Barf := Empty;
+ Body_Decl := Empty;
- -- Otherwise we generate an implicit pragma. For a subprogram
- -- instantiation, Elaborate is good enough, since no transitive
- -- call is possible at elaboration time in this case.
+ -- When the entry [family] has already been expanded, it carries both
+ -- the procedure which emulates the behavior of the entry [family] as
+ -- well as the barrier function.
- elsif Nkind (N) in N_Subprogram_Instantiation then
- Elab_Warning
- ("\missing pragma Elaborate for&?l?",
- "\implicit pragma Elaborate for& generated?$?",
- W_Scope);
+ if Present (Protected_Body_Subprogram (Target_Id)) then
+ Spec_Id := Protected_Body_Subprogram (Target_Id);
- -- For all other cases, we need an implicit Elaborate_All
+ -- Extract the attributes of the barrier function
+
+ Barf_Id :=
+ Corresponding_Body
+ (Unit_Declaration_Node (Barrier_Function (Target_Id)));
+
+ if Present (Barf_Id) then
+ Body_Barf := Unit_Declaration_Node (Barf_Id);
+ end if;
+
+ -- Otherwise no expansion took place
else
- Elab_Warning
- ("\missing pragma Elaborate_All for&?l?",
- "\implicit pragma Elaborate_All for & generated?$?",
- W_Scope);
+ Spec_Id := Target_Id;
end if;
- Error_Msg_Qual_Level := 0;
+ -- Extract the attributes of the entry body
- -- Take into account the flags related to elaboration warning
- -- messages when enumerating the various calls involved. This
- -- ensures the proper pairing of the main warning and the
- -- clarification messages generated by Output_Calls.
+ Body_Id := Corresponding_Body (Unit_Declaration_Node (Spec_Id));
- Output_Calls (N, Check_Elab_Flag => True);
+ if Present (Body_Id) then
+ Body_Decl := Unit_Declaration_Node (Body_Id);
+ end if;
+ end Extract_Protected_Entry_Attributes;
- -- Set flag to prevent further warnings for same unit unless in
- -- All_Errors_Mode.
+ ---------------------------------------------
+ -- Extract_Protected_Subprogram_Attributes --
+ ---------------------------------------------
- if not All_Errors_Mode and not Dynamic_Elaboration_Checks then
- Set_Suppress_Elaboration_Warnings (W_Scope);
- end if;
- end if;
+ procedure Extract_Protected_Subprogram_Attributes
+ (Spec_Id : out Entity_Id;
+ Body_Decl : out Node_Id)
+ is
+ Body_Id : Entity_Id;
- -- Check for runtime elaboration check required
+ begin
+ -- Assume that the body is not available
- if Dynamic_Elaboration_Checks then
- if not Elaboration_Checks_Suppressed (Ent)
- and then not Elaboration_Checks_Suppressed (W_Scope)
- and then not Elaboration_Checks_Suppressed (E_Scope)
- and then not Cunit_SC
- then
- -- Runtime elaboration check required. Generate check of the
- -- elaboration Boolean for the unit containing the entity.
+ Body_Decl := Empty;
- -- Note that for this case, we do check the real unit (the one
- -- from following renamings, since that is the issue).
+ -- When the protected subprogram has already been expanded, it
+ -- carries the subprogram which seizes the lock and invokes the
+ -- original statements.
- -- Could this possibly miss a useless but required PE???
+ if Present (Protected_Subprogram (Target_Id)) then
+ Spec_Id :=
+ Protected_Body_Subprogram (Protected_Subprogram (Target_Id));
- Insert_Elab_Check (N,
- Make_Attribute_Reference (Loc,
- Attribute_Name => Name_Elaborated,
- Prefix =>
- New_Occurrence_Of (Spec_Entity (E_Scope), Loc)));
+ -- Otherwise no expansion took place
- -- Prevent duplicate elaboration checks on the same call,
- -- which can happen if the body enclosing the call appears
- -- itself in a call whose elaboration check is delayed.
+ else
+ Spec_Id := Target_Id;
+ end if;
- if Nkind (N) in N_Subprogram_Call then
- Set_No_Elaboration_Check (N);
- end if;
+ -- Extract the attributes of the body
+
+ Body_Id := Corresponding_Body (Unit_Declaration_Node (Spec_Id));
+
+ if Present (Body_Id) then
+ Body_Decl := Unit_Declaration_Node (Body_Id);
end if;
+ end Extract_Protected_Subprogram_Attributes;
- -- Case of static elaboration model
+ -----------------------------------
+ -- Extract_Task_Entry_Attributes --
+ -----------------------------------
- else
- -- Do not do anything if elaboration checks suppressed. Note that
- -- we check Ent here, not E, since we want the real entity for the
- -- body to see if checks are suppressed for it, not the dummy
- -- entry for renamings or derivations.
-
- if Elaboration_Checks_Suppressed (Ent)
- or else Elaboration_Checks_Suppressed (E_Scope)
- or else Elaboration_Checks_Suppressed (W_Scope)
- then
- null;
+ procedure Extract_Task_Entry_Attributes
+ (Spec_Id : out Entity_Id;
+ Body_Decl : out Node_Id)
+ is
+ Task_Typ : constant Entity_Id := Non_Private_View (Scope (Target_Id));
+ Body_Id : Entity_Id;
- -- Do not generate an Elaborate_All for finalization routines
- -- that perform partial clean up as part of initialization.
+ begin
+ -- Assume that the body is not available
- elsif In_Init_Proc and then Is_Finalization_Procedure (Ent) then
- null;
+ Body_Decl := Empty;
- -- Here we need to generate an implicit elaborate all
+ -- The the task type has already been expanded, it carries the
+ -- procedure which emulates the behavior of the task body.
+
+ if Present (Task_Body_Procedure (Task_Typ)) then
+ Spec_Id := Task_Body_Procedure (Task_Typ);
+
+ -- Otherwise no expansion took place
else
- -- Generate Elaborate_All warning unless suppressed
+ Spec_Id := Task_Typ;
+ end if;
- if (Elab_Info_Messages and Generate_Warnings and not Inst_Case)
- and then not Suppress_Elaboration_Warnings (Ent)
- and then not Suppress_Elaboration_Warnings (E_Scope)
- and then not Suppress_Elaboration_Warnings (W_Scope)
- then
- Error_Msg_Node_2 := W_Scope;
- Error_Msg_NE
- ("info: call to& in elaboration code requires pragma "
- & "Elaborate_All on&?$?", N, E);
- end if;
+ -- Extract the attributes of the body
- -- Set indication for binder to generate Elaborate_All
+ Body_Id := Corresponding_Body (Unit_Declaration_Node (Spec_Id));
- Set_Elaboration_Constraint (N, E, W_Scope);
+ if Present (Body_Id) then
+ Body_Decl := Unit_Declaration_Node (Body_Id);
end if;
+ end Extract_Task_Entry_Attributes;
+
+ -- Local variables
+
+ Prag : constant Node_Id := SPARK_Pragma (Target_Id);
+ Body_Barf : Node_Id;
+ Body_Decl : Node_Id;
+ Spec_Id : Entity_Id;
+
+ -- Start of processing for Extract_Target_Attributes
+
+ begin
+ -- Assume that the body of the barrier function is not available
+
+ Body_Barf := Empty;
+
+ -- The target is a protected entry [family]
+
+ if Is_Protected_Entry (Target_Id) then
+ Extract_Protected_Entry_Attributes
+ (Spec_Id => Spec_Id,
+ Body_Decl => Body_Decl,
+ Body_Barf => Body_Barf);
+
+ -- The target is a protected subprogram
+
+ elsif Is_Protected_Subp (Target_Id)
+ or else Is_Protected_Body_Subp (Target_Id)
+ then
+ Extract_Protected_Subprogram_Attributes
+ (Spec_Id => Spec_Id,
+ Body_Decl => Body_Decl);
+
+ -- The target is a task entry [family]
+
+ elsif Is_Task_Entry (Target_Id) then
+ Extract_Task_Entry_Attributes
+ (Spec_Id => Spec_Id,
+ Body_Decl => Body_Decl);
+
+ -- Otherwise the target is a package or a subprogram
+
+ else
+ Extract_Package_Or_Subprogram_Attributes
+ (Spec_Id => Spec_Id,
+ Body_Decl => Body_Decl);
end if;
- end Check_A_Call;
+
+ -- Set all attributes
+
+ Attrs.Body_Barf := Body_Barf;
+ Attrs.Body_Decl := Body_Decl;
+ Attrs.Elab_Checks_OK := Is_Elaboration_Checks_OK_Id (Target_Id);
+ Attrs.From_Source := Comes_From_Source (Target_Id);
+ Attrs.Ghost_Mode_Ignore := Is_Ignored_Ghost_Entity (Target_Id);
+ Attrs.SPARK_Mode_On :=
+ Present (Prag) and then Get_SPARK_Mode_From_Annotation (Prag) = On;
+ Attrs.Spec_Decl := Unit_Declaration_Node (Spec_Id);
+ Attrs.Spec_Id := Spec_Id;
+ Attrs.Unit_Id := Find_Top_Unit (Target_Id);
+
+ -- At this point certain attributes should always be available
+
+ pragma Assert (Present (Attrs.Spec_Decl));
+ pragma Assert (Present (Attrs.Spec_Id));
+ pragma Assert (Present (Attrs.Unit_Id));
+ end Extract_Target_Attributes;
-----------------------------
- -- Check_Bad_Instantiation --
+ -- Extract_Task_Attributes --
-----------------------------
- procedure Check_Bad_Instantiation (N : Node_Id) is
- Ent : Entity_Id;
+ procedure Extract_Task_Attributes
+ (Typ : Entity_Id;
+ Attrs : out Task_Attributes)
+ is
+ Task_Typ : constant Entity_Id := Non_Private_View (Typ);
+
+ Body_Decl : Node_Id;
+ Body_Id : Entity_Id;
+ Prag : Node_Id;
+ Spec_Id : Entity_Id;
begin
- -- Nothing to do if we do not have an instantiation (happens in some
- -- error cases, and also in the formal package declaration case)
+ -- Assume that the body of the task procedure is not available
- if Nkind (N) not in N_Generic_Instantiation then
- return;
+ Body_Decl := Empty;
- -- Nothing to do if serious errors detected (avoid cascaded errors)
+ -- The initial declaration is that of the task body procedure
- elsif Serious_Errors_Detected /= 0 then
- return;
+ Spec_Id := Get_Task_Body_Procedure (Task_Typ);
+ Body_Id := Corresponding_Body (Unit_Declaration_Node (Spec_Id));
- -- Nothing to do if not in full analysis mode
+ if Present (Body_Id) then
+ Body_Decl := Unit_Declaration_Node (Body_Id);
+ end if;
- elsif not Full_Analysis then
- return;
+ Prag := SPARK_Pragma (Task_Typ);
- -- Nothing to do if inside a generic template
+ -- Set all attributes
- elsif Inside_A_Generic then
- return;
+ Attrs.Body_Decl := Body_Decl;
+ Attrs.Elab_Checks_OK := Is_Elaboration_Checks_OK_Id (Task_Typ);
+ Attrs.Ghost_Mode_Ignore := Is_Ignored_Ghost_Entity (Task_Typ);
+ Attrs.SPARK_Mode_On :=
+ Present (Prag) and then Get_SPARK_Mode_From_Annotation (Prag) = On;
+ Attrs.Spec_Id := Spec_Id;
+ Attrs.Task_Decl := Declaration_Node (Task_Typ);
+ Attrs.Unit_Id := Find_Top_Unit (Task_Typ);
- -- Nothing to do if a library level instantiation
+ -- At this point certain attributes should always be available
- elsif Nkind (Parent (N)) = N_Compilation_Unit then
- return;
+ pragma Assert (Present (Attrs.Spec_Id));
+ pragma Assert (Present (Attrs.Task_Decl));
+ pragma Assert (Present (Attrs.Unit_Id));
+ end Extract_Task_Attributes;
- -- Nothing to do if we are compiling a proper body for semantic
- -- purposes only. The generic body may be in another proper body.
+ -------------------------------------------
+ -- Extract_Variable_Reference_Attributes --
+ -------------------------------------------
- elsif
- Nkind (Parent (Unit_Declaration_Node (Main_Unit_Entity))) = N_Subunit
- then
- return;
- end if;
+ procedure Extract_Variable_Reference_Attributes
+ (Ref : Node_Id;
+ Var_Id : out Entity_Id;
+ Attrs : out Variable_Attributes)
+ is
+ begin
+ -- Traverse a possible chain of renamings to obtain the original
+ -- variable being referenced.
- Ent := Get_Generic_Entity (N);
+ Var_Id := Get_Renamed_Entity (Entity (Ref));
- -- The case we are interested in is when the generic spec is in the
- -- current declarative part
+ Attrs.SPARK_Mode_On := Is_SPARK_Mode_On_Node (Ref);
+ Attrs.Unit_Id := Find_Top_Unit (Var_Id);
- if not Same_Elaboration_Scope (Current_Scope, Scope (Ent))
- or else not In_Same_Extended_Unit (N, Ent)
- then
- return;
- end if;
+ -- At this point certain attributes should always be available
+
+ pragma Assert (Present (Attrs.Unit_Id));
+ end Extract_Variable_Reference_Attributes;
+
+ --------------------
+ -- Find_Code_Unit --
+ --------------------
+
+ function Find_Code_Unit (N : Node_Or_Entity_Id) return Entity_Id is
+ begin
+ return Find_Unit_Entity (Unit (Cunit (Get_Code_Unit (N))));
+ end Find_Code_Unit;
+
+ ---------------------------
+ -- Find_Elaborated_Units --
+ ---------------------------
+
+ procedure Find_Elaborated_Units is
+ procedure Add_Pragma (Prag : Node_Id);
+ -- Determine whether pragma Prag denotes a legal Elaborate[_All] pragma.
+ -- If this is the case, add the related unit to the elaboration context.
+ -- For pragma Elaborate_All, include recursively all units withed by the
+ -- related unit.
+
+ procedure Add_Unit
+ (Unit_Id : Entity_Id;
+ Prag : Node_Id;
+ Full_Context : Boolean);
+ -- Add unit Unit_Id to the elaboration context. Prag denotes the pragma
+ -- which prompted the inclusion of the unit to the elaboration context.
+ -- If flag Full_Context is set, examine the nonlimited clauses of unit
+ -- Unit_Id and add each withed unit to the context.
+
+ procedure Find_Elaboration_Context (Comp_Unit : Node_Id);
+ -- Examine the context items of compilation unit Comp_Unit for suitable
+ -- elaboration-related pragmas and add all related units to the context.
+
+ ----------------
+ -- Add_Pragma --
+ ----------------
+
+ procedure Add_Pragma (Prag : Node_Id) is
+ Prag_Args : constant List_Id := Pragma_Argument_Associations (Prag);
+ Prag_Nam : constant Name_Id := Pragma_Name (Prag);
+ Unit_Arg : Node_Id;
+
+ begin
+ -- Nothing to do if the pragma is not related to elaboration
+
+ if not Nam_In (Prag_Nam, Name_Elaborate, Name_Elaborate_All) then
+ return;
+
+ -- Nothing to do when the pragma is illegal
+
+ elsif Error_Posted (Prag) then
+ return;
+ end if;
+
+ Unit_Arg := Get_Pragma_Arg (First (Prag_Args));
+
+ -- The argument of the pragma may appear in package.package form
+
+ if Nkind (Unit_Arg) = N_Selected_Component then
+ Unit_Arg := Selector_Name (Unit_Arg);
+ end if;
+
+ Add_Unit
+ (Unit_Id => Entity (Unit_Arg),
+ Prag => Prag,
+ Full_Context => Prag_Nam = Name_Elaborate_All);
+ end Add_Pragma;
- -- If the generic entity is within a deeper instance than we are, then
- -- either the instantiation to which we refer itself caused an ABE, in
- -- which case that will be handled separately. Otherwise, we know that
- -- the body we need appears as needed at the point of the instantiation.
- -- If they are both at the same level but not within the same instance
- -- then the body of the generic will be in the earlier instance.
+ --------------
+ -- Add_Unit --
+ --------------
- declare
- D1 : constant Nat := Instantiation_Depth (Sloc (Ent));
- D2 : constant Nat := Instantiation_Depth (Sloc (N));
+ procedure Add_Unit
+ (Unit_Id : Entity_Id;
+ Prag : Node_Id;
+ Full_Context : Boolean)
+ is
+ Clause : Node_Id;
+ Elab_Attrs : Elaboration_Attributes;
begin
- if D1 > D2 then
+ -- Nothing to do when some previous error left a with clause or a
+ -- pragma in a bad state.
+
+ if No (Unit_Id) then
return;
+ end if;
- elsif D1 = D2
- and then Is_Generic_Instance (Scope (Ent))
- and then not In_Open_Scopes (Scope (Ent))
+ Elab_Attrs := Elaboration_Context.Get (Unit_Id);
+
+ -- The current unit is not part of the context. Prepare a new set of
+ -- attributes.
+
+ if Elab_Attrs = No_Elaboration_Attributes then
+ Elab_Attrs :=
+ Elaboration_Attributes'(Source_Pragma => Prag,
+ With_Clause => Empty);
+
+ -- The unit is already included in the context by means of pragma
+ -- Elaborate. "Upgrage" the existing attributes when the unit is
+ -- subject to Elaborate_All because the new pragma covers a larger
+ -- set of units. All other properties remain the same.
+
+ elsif Pragma_Name (Elab_Attrs.Source_Pragma) = Name_Elaborate
+ and then Pragma_Name (Prag) = Name_Elaborate_All
then
+ Elab_Attrs.Source_Pragma := Prag;
+
+ -- Otherwise the unit is already included in the context
+
+ else
return;
end if;
- end;
- -- Now we can proceed, if the entity being called has a completion,
- -- then we are definitely OK, since we have already seen the body.
+ -- Add or update the attributes of the unit
- if Has_Completion (Ent) then
- return;
- end if;
+ Elaboration_Context.Set (Unit_Id, Elab_Attrs);
- -- If there is no body, then nothing to do
+ -- Includes all units withed by the current one when computing the
+ -- full context.
- if not Has_Generic_Body (N) then
- return;
- end if;
+ if Full_Context then
- -- Here we definitely have a bad instantiation
+ -- Process all nonlimited with clauses found in the context of
+ -- the current unit. Note that limited clauses do not impose an
+ -- elaboration order.
- Error_Msg_Warn := SPARK_Mode /= On;
- Error_Msg_NE ("cannot instantiate& before body seen<<", N, Ent);
+ Clause := First (Context_Items (Compilation_Unit (Unit_Id)));
+ while Present (Clause) loop
+ if Nkind (Clause) = N_With_Clause
+ and then not Error_Posted (Clause)
+ and then not Limited_Present (Clause)
+ then
+ Add_Unit
+ (Unit_Id => Entity (Name (Clause)),
+ Prag => Prag,
+ Full_Context => Full_Context);
+ end if;
- if Present (Instance_Spec (N)) then
- Supply_Bodies (Instance_Spec (N));
- end if;
+ Next (Clause);
+ end loop;
+ end if;
+ end Add_Unit;
- Error_Msg_N ("\Program_Error [<<", N);
- Insert_Elab_Check (N);
- Set_ABE_Is_Certain (N);
- end Check_Bad_Instantiation;
+ ------------------------------
+ -- Find_Elaboration_Context --
+ ------------------------------
- ---------------------
- -- Check_Elab_Call --
- ---------------------
+ procedure Find_Elaboration_Context (Comp_Unit : Node_Id) is
+ Prag : Node_Id;
- procedure Check_Elab_Call
- (N : Node_Id;
- Outer_Scope : Entity_Id := Empty;
- In_Init_Proc : Boolean := False)
- is
- Ent : Entity_Id;
- P : Node_Id;
+ begin
+ pragma Assert (Nkind (Comp_Unit) = N_Compilation_Unit);
+
+ -- Process all elaboration-related pragmas found in the context of
+ -- the compilation unit.
+
+ Prag := First (Context_Items (Comp_Unit));
+ while Present (Prag) loop
+ if Nkind (Prag) = N_Pragma then
+ Add_Pragma (Prag);
+ end if;
+
+ Next (Prag);
+ end loop;
+ end Find_Elaboration_Context;
+
+ -- Local variables
+
+ Par_Id : Entity_Id;
+ Unt : Node_Id;
+
+ -- Start of processing for Find_Elaborated_Units
begin
- -- If the reference is not in the main unit, there is nothing to check.
- -- Elaboration call from units in the context of the main unit will lead
- -- to semantic dependencies when those units are compiled.
+ -- Perform a traversal which examines the context of the main unit and
+ -- populates the Elaboration_Context table with all units elaborated
+ -- prior to the main unit. The traversal performs the following jumps:
- if not In_Extended_Main_Code_Unit (N) then
- return;
- end if;
+ -- subunit -> parent subunit
+ -- parent subunit -> body
+ -- body -> spec
+ -- spec -> parent spec
+ -- parent spec -> grandparent spec and so on
- -- For an entry call, check relevant restriction
+ -- The traversal relies on units rather than scopes because the scope of
+ -- a subunit is some spec, while this traversal must process the body as
+ -- well. Given that protected and task bodies can also be subunits, this
+ -- complicates the scope approach even further.
- if Nkind (N) = N_Entry_Call_Statement
- and then not In_Subprogram_Or_Concurrent_Unit
- then
- Check_Restriction (No_Entry_Calls_In_Elaboration_Code, N);
+ Unt := Unit (Cunit (Main_Unit));
- -- Nothing to do if this is not an expected type of reference (happens
- -- in some error conditions, and in some cases where rewriting occurs).
+ -- Perform the following traversals when the main unit is a subunit
- elsif Nkind (N) not in N_Subprogram_Call
- and then Nkind (N) /= N_Attribute_Reference
- and then (SPARK_Mode /= On
- or else Nkind (N) not in N_Has_Entity
- or else No (Entity (N))
- or else Ekind (Entity (N)) /= E_Variable)
- then
- return;
+ -- subunit -> parent subunit
+ -- parent subunit -> body
- -- Nothing to do if this is a call already rewritten for elab checking.
- -- Such calls appear as the targets of If_Expressions.
+ while Present (Unt) and then Nkind (Unt) = N_Subunit loop
+ Find_Elaboration_Context (Parent (Unt));
- -- This check MUST be wrong, it catches far too much
+ -- Continue the traversal by going to the unit which contains the
+ -- corresponding stub.
- elsif Nkind (Parent (N)) = N_If_Expression then
- return;
+ if Present (Corresponding_Stub (Unt)) then
+ Unt := Unit (Cunit (Get_Source_Unit (Corresponding_Stub (Unt))));
- -- Nothing to do if inside a generic template
+ -- Otherwise the subunit may be erroneous or left in a bad state
- elsif Inside_A_Generic
- and then No (Enclosing_Generic_Body (N))
+ else
+ exit;
+ end if;
+ end loop;
+
+ -- Perform the following traversal now that subunits have been taken
+ -- care of, or the main unit is a body.
+
+ -- body -> spec
+
+ if Present (Unt)
+ and then Nkind_In (Unt, N_Package_Body, N_Subprogram_Body)
then
- return;
+ Find_Elaboration_Context (Parent (Unt));
- -- Nothing to do if call is being pre-analyzed, as when within a
- -- pre/postcondition, a predicate, or an invariant.
+ -- Continue the traversal by going to the unit which contains the
+ -- corresponding spec.
- elsif In_Spec_Expression then
- return;
+ if Present (Corresponding_Spec (Unt)) then
+ Unt := Unit (Cunit (Get_Source_Unit (Corresponding_Spec (Unt))));
+ end if;
end if;
- -- Nothing to do if this is a call to a postcondition, which is always
- -- within a subprogram body, even though the current scope may be the
- -- enclosing scope of the subprogram.
+ -- Perform the following traversals now that the body has been taken
+ -- care of, or the main unit is a spec.
+
+ -- spec -> parent spec
+ -- parent spec -> grandparent spec and so on
- if Nkind (N) = N_Procedure_Call_Statement
- and then Is_Entity_Name (Name (N))
- and then Chars (Entity (Name (N))) = Name_uPostconditions
+ if Present (Unt)
+ and then Nkind_In (Unt, N_Generic_Package_Declaration,
+ N_Generic_Subprogram_Declaration,
+ N_Package_Declaration,
+ N_Subprogram_Declaration)
then
- return;
+ Find_Elaboration_Context (Parent (Unt));
+
+ -- Process a potential chain of parent units which ends with the
+ -- main unit spec. The traversal can now safely rely on the scope
+ -- chain.
+
+ Par_Id := Scope (Defining_Entity (Unt));
+ while Present (Par_Id) and then Par_Id /= Standard_Standard loop
+ Find_Elaboration_Context (Compilation_Unit (Par_Id));
+
+ Par_Id := Scope (Par_Id);
+ end loop;
end if;
+ end Find_Elaborated_Units;
- -- Here we have a reference at elaboration time that must be checked
+ -----------------------------
+ -- Find_Enclosing_Instance --
+ -----------------------------
- if Debug_Flag_LL then
- Write_Str (" Check_Elab_Ref: ");
+ function Find_Enclosing_Instance (N : Node_Id) return Node_Id is
+ Par : Node_Id;
+ Spec_Id : Entity_Id;
- if Nkind (N) = N_Attribute_Reference then
- if not Is_Entity_Name (Prefix (N)) then
- Write_Str ("<<not entity name>>");
- else
- Write_Name (Chars (Entity (Prefix (N))));
+ begin
+ -- Climb the parent chain looking for an enclosing instance spec or body
+
+ Par := N;
+ while Present (Par) loop
+
+ -- Generic package or subprogram spec
+
+ if Nkind_In (Par, N_Package_Declaration,
+ N_Subprogram_Declaration)
+ and then Is_Generic_Instance (Defining_Entity (Par))
+ then
+ return Par;
+
+ -- Generic package or subprogram body
+
+ elsif Nkind_In (Par, N_Package_Body, N_Subprogram_Body) then
+ Spec_Id := Corresponding_Spec (Par);
+
+ if Present (Spec_Id) and then Is_Generic_Instance (Spec_Id) then
+ return Par;
end if;
+ end if;
- Write_Str ("'Access");
+ Par := Parent (Par);
+ end loop;
- elsif No (Name (N)) or else not Is_Entity_Name (Name (N)) then
- Write_Str ("<<not entity name>> ");
+ return Empty;
+ end Find_Enclosing_Instance;
- else
- Write_Name (Chars (Entity (Name (N))));
+ --------------------------
+ -- Find_Enclosing_Level --
+ --------------------------
+
+ function Find_Enclosing_Level (N : Node_Id) return Enclosing_Level_Kind is
+ function Level_Of (Unit : Node_Id) return Enclosing_Level_Kind;
+ -- Obtain the corresponding level of unit Unit
+
+ --------------
+ -- Level_Of --
+ --------------
+
+ function Level_Of (Unit : Node_Id) return Enclosing_Level_Kind is
+ Spec_Id : Entity_Id;
+
+ begin
+ if Nkind (Unit) in N_Generic_Instantiation then
+ return Instantiation;
+
+ elsif Nkind (Unit) = N_Generic_Package_Declaration then
+ return Generic_Package_Spec;
+
+ elsif Nkind (Unit) = N_Package_Declaration then
+ return Package_Spec;
+
+ elsif Nkind (Unit) = N_Package_Body then
+ Spec_Id := Corresponding_Spec (Unit);
+
+ -- The body belongs to a generic package
+
+ if Present (Spec_Id)
+ and then Ekind (Spec_Id) = E_Generic_Package
+ then
+ return Generic_Package_Body;
+
+ -- Otherwise the body belongs to a non-generic package. This also
+ -- treats an illegal package body without a corresponding spec as
+ -- a non-generic package body.
+
+ else
+ return Package_Body;
+ end if;
end if;
- Write_Str (" reference at ");
- Write_Location (Sloc (N));
- Write_Eol;
+ return No_Level;
+ end Level_Of;
+
+ -- Local variables
+
+ Context : Node_Id;
+ Curr : Node_Id;
+ Prev : Node_Id;
+
+ -- Start of processing for Find_Enclosing_Level
+
+ begin
+ -- Call markers and instantiations which appear at the declaration level
+ -- but are later relocated in a different context retain their original
+ -- declaration level.
+
+ if Nkind_In (N, N_Call_Marker,
+ N_Function_Instantiation,
+ N_Package_Instantiation,
+ N_Procedure_Instantiation)
+ and then Is_Declaration_Level_Node (N)
+ then
+ return Declaration_Level;
end if;
- -- Climb up the tree to make sure we are not inside default expression
- -- of a parameter specification or a record component, since in both
- -- these cases, we will be doing the actual reference later, not now,
- -- and it is at the time of the actual reference (statically speaking)
- -- that we must do our static check, not at the time of its initial
- -- analysis).
+ -- Climb the parent chain looking at the enclosing levels
+
+ Prev := N;
+ Curr := Parent (Prev);
+ while Present (Curr) loop
+
+ -- A traversal from a subunit continues via the corresponding stub
+
+ if Nkind (Curr) = N_Subunit then
+ Curr := Corresponding_Stub (Curr);
+
+ -- The current construct is a package. Packages are ignored because
+ -- they are always elaborated when the enclosing context is invoked
+ -- or elaborated.
+
+ elsif Nkind_In (Curr, N_Package_Body, N_Package_Declaration) then
+ null;
+
+ -- The current construct is a block statement
+
+ elsif Nkind (Curr) = N_Block_Statement then
+
+ -- Ignore internally generated blocks created by the expander for
+ -- various purposes such as abort defer/undefer.
- -- However, we have to check references within component definitions
- -- (e.g. a function call that determines an array component bound),
- -- so we terminate the loop in that case.
+ if not Comes_From_Source (Curr) then
+ null;
- P := Parent (N);
- while Present (P) loop
- if Nkind_In (P, N_Parameter_Specification,
- N_Component_Declaration)
+ -- If the traversal came from the handled sequence of statments,
+ -- then the node appears at the level of the enclosing construct.
+ -- This is a more reliable test because transients scopes within
+ -- the declarative region of the encapsulator are hard to detect.
+
+ elsif Nkind (Prev) = N_Handled_Sequence_Of_Statements
+ and then Handled_Statement_Sequence (Curr) = Prev
+ then
+ return Find_Enclosing_Level (Parent (Curr));
+
+ -- Otherwise the traversal came from the declarations, the node is
+ -- at the declaration level.
+
+ else
+ return Declaration_Level;
+ end if;
+
+ -- The current construct is a declaration level encapsulator
+
+ elsif Nkind_In (Curr, N_Entry_Body,
+ N_Subprogram_Body,
+ N_Task_Body)
then
- return;
+ -- If the traversal came from the handled sequence of statments,
+ -- then the node cannot possibly appear at any level. This is
+ -- a more reliable test because transients scopes within the
+ -- declarative region of the encapsulator are hard to detect.
- -- The reference occurs within the constraint of a component,
- -- so it must be checked.
+ if Nkind (Prev) = N_Handled_Sequence_Of_Statements
+ and then Handled_Statement_Sequence (Curr) = Prev
+ then
+ return No_Level;
- elsif Nkind (P) = N_Component_Definition then
- exit;
+ -- Otherwise the traversal came from the declarations, the node is
+ -- at the declaration level.
- else
- P := Parent (P);
+ else
+ return Declaration_Level;
+ end if;
+
+ -- The current construct is a non-library level encapsulator which
+ -- indicates that the node cannot possibly appear at any level.
+ -- Note that this check must come after the declaration level check
+ -- because both predicates share certain nodes.
+
+ elsif Is_Non_Library_Level_Encapsulator (Curr) then
+ Context := Parent (Curr);
+
+ -- The sole exception is when the encapsulator is the compilation
+ -- utit itself because the compilation unit node requires special
+ -- processing (see below).
+
+ if Present (Context)
+ and then Nkind (Context) = N_Compilation_Unit
+ then
+ null;
+
+ -- Otherwise the node is not at any level
+
+ else
+ return No_Level;
+ end if;
+
+ -- The current construct is a compilation unit. The node appears at
+ -- the [generic] library level when the unit is a [generic] package.
+
+ elsif Nkind (Curr) = N_Compilation_Unit then
+ return Level_Of (Unit (Curr));
end if;
+
+ Prev := Curr;
+ Curr := Parent (Prev);
end loop;
- -- Stuff that happens only at the outer level
+ return No_Level;
+ end Find_Enclosing_Level;
- if No (Outer_Scope) then
- Elab_Visited.Set_Last (0);
+ -------------------
+ -- Find_Top_Unit --
+ -------------------
- -- Nothing to do if current scope is Standard (this is a bit odd, but
- -- it happens in the case of generic instantiations).
+ function Find_Top_Unit (N : Node_Or_Entity_Id) return Entity_Id is
+ begin
+ return Find_Unit_Entity (Unit (Cunit (Get_Top_Level_Code_Unit (N))));
+ end Find_Top_Unit;
- C_Scope := Current_Scope;
+ ----------------------
+ -- Find_Unit_Entity --
+ ----------------------
- if C_Scope = Standard_Standard then
- return;
- end if;
+ function Find_Unit_Entity (N : Node_Id) return Entity_Id is
+ Context : constant Node_Id := Parent (N);
+ Orig_N : constant Node_Id := Original_Node (N);
+
+ begin
+ -- The unit denotes a package body of an instantiation which acts as
+ -- a compilation unit. The proper entity is that of the package spec.
+
+ if Nkind (N) = N_Package_Body
+ and then Nkind (Orig_N) = N_Package_Instantiation
+ and then Nkind (Context) = N_Compilation_Unit
+ then
+ return Corresponding_Spec (N);
+
+ -- The unit denotes an anonymous package created to wrap a subprogram
+ -- instantiation which acts as a compilation unit. The proper entity is
+ -- that of the "related instance".
- -- First case, we are in elaboration code
+ elsif Nkind (N) = N_Package_Declaration
+ and then Nkind_In (Orig_N, N_Function_Instantiation,
+ N_Procedure_Instantiation)
+ and then Nkind (Context) = N_Compilation_Unit
+ then
+ return
+ Related_Instance (Defining_Entity (N, Concurrent_Subunit => True));
+
+ -- Otherwise the proper entity is the defining entity
+
+ else
+ return Defining_Entity (N, Concurrent_Subunit => True);
+ end if;
+ end Find_Unit_Entity;
- From_Elab_Code := not In_Subprogram_Or_Concurrent_Unit;
+ -----------------------
+ -- First_Formal_Type --
+ -----------------------
- if From_Elab_Code then
+ function First_Formal_Type (Subp_Id : Entity_Id) return Entity_Id is
+ Formal_Id : constant Entity_Id := First_Formal (Subp_Id);
+ Typ : Entity_Id;
- -- Complain if ref that comes from source in preelaborated unit
- -- and we are not inside a subprogram (i.e. we are in elab code).
+ begin
+ if Present (Formal_Id) then
+ Typ := Etype (Formal_Id);
- if Comes_From_Source (N)
- and then In_Preelaborated_Unit
- and then not In_Inlined_Body
- and then Nkind (N) /= N_Attribute_Reference
+ -- Handle various combinations of concurrent and private types
+
+ loop
+ if Ekind_In (Typ, E_Protected_Type, E_Task_Type)
+ and then Present (Anonymous_Object (Typ))
then
- -- This is a warning in GNAT mode allowing such calls to be
- -- used in the predefined library with appropriate care.
+ Typ := Anonymous_Object (Typ);
- Error_Msg_Warn := GNAT_Mode;
- Error_Msg_N
- ("<<non-static call not allowed in preelaborated unit", N);
- return;
+ elsif Is_Concurrent_Record_Type (Typ) then
+ Typ := Corresponding_Concurrent_Type (Typ);
+
+ elsif Is_Private_Type (Typ) and then Present (Full_View (Typ)) then
+ Typ := Full_View (Typ);
+
+ else
+ exit;
end if;
+ end loop;
- -- Second case, we are inside a subprogram or concurrent unit, which
- -- means we are not in elaboration code.
+ return Typ;
+ end if;
- else
- -- In this case, the issue is whether we are inside the
- -- declarative part of the unit in which we live, or inside its
- -- statements. In the latter case, there is no issue of ABE calls
- -- at this level (a call from outside to the unit in which we live
- -- might cause an ABE, but that will be detected when we analyze
- -- that outer level call, as it recurses into the called unit).
-
- -- Climb up the tree, doing this test, and also testing for being
- -- inside a default expression, which, as discussed above, is not
- -- checked at this stage.
-
- declare
- P : Node_Id;
- L : List_Id;
-
- begin
- P := N;
- loop
- -- If we find a parentless subtree, it seems safe to assume
- -- that we are not in a declarative part and that no
- -- checking is required.
-
- if No (P) then
- return;
- end if;
+ return Empty;
+ end First_Formal_Type;
- if Is_List_Member (P) then
- L := List_Containing (P);
- P := Parent (L);
- else
- L := No_List;
- P := Parent (P);
- end if;
+ --------------
+ -- Has_Body --
+ --------------
- exit when Nkind (P) = N_Subunit;
+ function Has_Body (Pack_Decl : Node_Id) return Boolean is
+ function Find_Corresponding_Body (Spec_Id : Entity_Id) return Node_Id;
+ -- Try to locate the corresponding body of spec Spec_Id. If no body is
+ -- found, return Empty.
- -- Filter out case of default expressions, where we do not
- -- do the check at this stage.
+ function Find_Body
+ (Spec_Id : Entity_Id;
+ From : Node_Id) return Node_Id;
+ -- Try to locate the corresponding body of spec Spec_Id in the node list
+ -- which follows arbitrary node From. If no body is found, return Empty.
- if Nkind_In (P, N_Parameter_Specification,
- N_Component_Declaration)
- then
- return;
- end if;
+ function Load_Package_Body (Unit_Nam : Unit_Name_Type) return Node_Id;
+ -- Attempt to load the body of unit Unit_Nam. If the load failed, return
+ -- Empty. If the compilation will not generate code, return Empty.
- -- A protected body has no elaboration code and contains
- -- only other bodies.
+ -----------------------------
+ -- Find_Corresponding_Body --
+ -----------------------------
- if Nkind (P) = N_Protected_Body then
- return;
+ function Find_Corresponding_Body (Spec_Id : Entity_Id) return Node_Id is
+ Context : constant Entity_Id := Scope (Spec_Id);
+ Spec_Decl : constant Node_Id := Unit_Declaration_Node (Spec_Id);
+ Body_Decl : Node_Id;
+ Body_Id : Entity_Id;
- elsif Nkind_In (P, N_Subprogram_Body,
- N_Task_Body,
- N_Block_Statement,
- N_Entry_Body)
- then
- if L = Declarations (P) then
- exit;
+ begin
+ if Is_Compilation_Unit (Spec_Id) then
+ Body_Id := Corresponding_Body (Spec_Decl);
- -- We are not in elaboration code, but we are doing
- -- dynamic elaboration checks, in this case, we still
- -- need to do the reference, since the subprogram we are
- -- in could be called from another unit, also in dynamic
- -- elaboration check mode, at elaboration time.
+ if Present (Body_Id) then
+ return Unit_Declaration_Node (Body_Id);
- elsif Dynamic_Elaboration_Checks then
+ -- The package is at the library and requires a body. Load the
+ -- corresponding body because the optional body may be declared
+ -- there.
- -- We provide a debug flag to disable this check. That
- -- way we have an easy work around for regressions
- -- that are caused by this new check. This debug flag
- -- can be removed later.
+ elsif Unit_Requires_Body (Spec_Id) then
+ return
+ Load_Package_Body
+ (Get_Body_Name (Unit_Name (Get_Source_Unit (Spec_Decl))));
- if Debug_Flag_DD then
- return;
- end if;
+ -- Otherwise there is no optional body
- -- Do the check in this case
+ else
+ return Empty;
+ end if;
- exit;
+ -- The immediate context is a package. The optional body may be
+ -- within the body of that package.
- elsif Nkind (P) = N_Task_Body then
+ -- procedure Proc is
+ -- package Nested_1 is
+ -- package Nested_2 is
+ -- generic
+ -- package Pack is
+ -- end Pack;
+ -- end Nested_2;
+ -- end Nested_1;
- -- The check is deferred until Check_Task_Activation
- -- but we need to capture local suppress pragmas
- -- that may inhibit checks on this call.
+ -- package body Nested_1 is
+ -- package body Nested_2 is separate;
+ -- end Nested_1;
- Ent := Get_Referenced_Ent (N);
+ -- separate (Proc.Nested_1.Nested_2)
+ -- package body Nested_2 is
+ -- package body Pack is -- optional body
+ -- ...
+ -- end Pack;
+ -- end Nested_2;
- if No (Ent) then
- return;
+ elsif Is_Package_Or_Generic_Package (Context) then
+ Body_Decl := Find_Corresponding_Body (Context);
- elsif Elaboration_Checks_Suppressed (Current_Scope)
- or else Elaboration_Checks_Suppressed (Ent)
- or else Elaboration_Checks_Suppressed (Scope (Ent))
- then
- if Nkind (N) in N_Subprogram_Call then
- Set_No_Elaboration_Check (N);
- end if;
- end if;
+ -- The optional body is within the body of the enclosing package
- return;
+ if Present (Body_Decl) then
+ return
+ Find_Body
+ (Spec_Id => Spec_Id,
+ From => First (Declarations (Body_Decl)));
- -- Static model, call is not in elaboration code, we
- -- never need to worry, because in the static model the
- -- top-level caller always takes care of things.
+ -- Otherwise the enclosing package does not have a body. This may
+ -- be the result of an error or a genuine lack of a body.
- else
- return;
- end if;
- end if;
- end loop;
- end;
- end if;
- end if;
+ else
+ return Empty;
+ end if;
- Ent := Get_Referenced_Ent (N);
+ -- Otherwise the immediate context is a body. The optional body may
+ -- be within the same list as the spec.
- if No (Ent) then
- return;
- end if;
+ -- procedure Proc is
+ -- generic
+ -- package Pack is
+ -- end Pack;
+
+ -- package body Pack is -- optional body
+ -- ...
+ -- end Pack;
- -- Determine whether a prior call to the same subprogram was already
- -- examined within the same context. If this is the case, then there is
- -- no need to proceed with the various warnings and checks because the
- -- work was already done for the previous call.
+ else
+ return
+ Find_Body
+ (Spec_Id => Spec_Id,
+ From => Next (Spec_Decl));
+ end if;
+ end Find_Corresponding_Body;
- declare
- Self : constant Visited_Element :=
- (Subp_Id => Ent, Context => Parent (N));
+ ---------------
+ -- Find_Body --
+ ---------------
+
+ function Find_Body
+ (Spec_Id : Entity_Id;
+ From : Node_Id) return Node_Id
+ is
+ Spec_Nam : constant Name_Id := Chars (Spec_Id);
+ Item : Node_Id;
+ Lib_Unit : Node_Id;
begin
- for Index in 1 .. Elab_Visited.Last loop
- if Self = Elab_Visited.Table (Index) then
- return;
+ Item := From;
+ while Present (Item) loop
+
+ -- The current item denotes the optional body
+
+ if Nkind (Item) = N_Package_Body
+ and then Chars (Defining_Entity (Item)) = Spec_Nam
+ then
+ return Item;
+
+ -- The current item denotes a stub, the optional body may be in
+ -- the subunit.
+
+ elsif Nkind (Item) = N_Package_Body_Stub
+ and then Chars (Defining_Entity (Item)) = Spec_Nam
+ then
+ Lib_Unit := Library_Unit (Item);
+
+ -- The corresponding subunit was previously loaded
+
+ if Present (Lib_Unit) then
+ return Lib_Unit;
+
+ -- Otherwise attempt to load the corresponding subunit
+
+ else
+ return Load_Package_Body (Get_Unit_Name (Item));
+ end if;
end if;
+
+ Next (Item);
end loop;
- end;
- -- See if we need to analyze this reference. We analyze it if either of
- -- the following conditions is met:
+ return Empty;
+ end Find_Body;
- -- It is an inner level call (since in this case it was triggered
- -- by an outer level call from elaboration code), but only if the
- -- call is within the scope of the original outer level call.
+ -----------------------
+ -- Load_Package_Body --
+ -----------------------
- -- It is an outer level reference from elaboration code, or a call to
- -- an entity is in the same elaboration scope.
+ function Load_Package_Body (Unit_Nam : Unit_Name_Type) return Node_Id is
+ Body_Decl : Node_Id;
+ Unit_Num : Unit_Number_Type;
- -- And in these cases, we will check both inter-unit calls and
- -- intra-unit (within a single unit) calls.
+ begin
+ -- The load is performed only when the compilation will generate code
- C_Scope := Current_Scope;
+ if Operating_Mode = Generate_Code then
+ Unit_Num :=
+ Load_Unit
+ (Load_Name => Unit_Nam,
+ Required => False,
+ Subunit => False,
+ Error_Node => Pack_Decl);
- -- If not outer level reference, then we follow it if it is within the
- -- original scope of the outer reference.
+ -- The load failed most likely because the physical file is
+ -- missing.
- if Present (Outer_Scope)
- and then Within (Scope (Ent), Outer_Scope)
- then
- Set_C_Scope;
- Check_A_Call
- (N => N,
- E => Ent,
- Outer_Scope => Outer_Scope,
- Inter_Unit_Only => False,
- In_Init_Proc => In_Init_Proc);
-
- -- Nothing to do if elaboration checks suppressed for this scope.
- -- However, an interesting exception, the fact that elaboration checks
- -- are suppressed within an instance (because we can trace the body when
- -- we process the template) does not extend to calls to generic formal
- -- subprograms.
-
- elsif Elaboration_Checks_Suppressed (Current_Scope)
- and then not Is_Call_Of_Generic_Formal (N)
- then
- null;
+ if Unit_Num = No_Unit then
+ return Empty;
- elsif From_Elab_Code then
- Set_C_Scope;
- Check_A_Call (N, Ent, Standard_Standard, Inter_Unit_Only => False);
+ -- Otherwise the load was successful, return the body of the unit
- elsif Same_Elaboration_Scope (C_Scope, Scope (Ent)) then
- Set_C_Scope;
- Check_A_Call (N, Ent, Scope (Ent), Inter_Unit_Only => False);
+ else
+ Body_Decl := Unit (Cunit (Unit_Num));
- -- If none of those cases holds, but Dynamic_Elaboration_Checks mode
- -- is set, then we will do the check, but only in the inter-unit case
- -- (this is to accommodate unguarded elaboration calls from other units
- -- in which this same mode is set). We don't want warnings in this case,
- -- it would generate warnings having nothing to do with elaboration.
+ -- If the unit is a subunit with an available proper body,
+ -- return the proper body.
- elsif Dynamic_Elaboration_Checks then
- Set_C_Scope;
- Check_A_Call
- (N,
- Ent,
- Standard_Standard,
- Inter_Unit_Only => True,
- Generate_Warnings => False);
+ if Nkind (Body_Decl) = N_Subunit
+ and then Present (Proper_Body (Body_Decl))
+ then
+ Body_Decl := Proper_Body (Body_Decl);
+ end if;
+
+ return Body_Decl;
+ end if;
+ end if;
+
+ return Empty;
+ end Load_Package_Body;
- -- Otherwise nothing to do
+ -- Local variables
+
+ Pack_Id : constant Entity_Id := Defining_Entity (Pack_Decl);
+
+ -- Start of processing for Has_Body
+
+ begin
+ -- The body is available
+
+ if Present (Corresponding_Body (Pack_Decl)) then
+ return True;
+
+ -- The body is required if the package spec contains a construct which
+ -- requires a completion in a body.
+
+ elsif Unit_Requires_Body (Pack_Id) then
+ return True;
+
+ -- The body may be optional
else
- return;
+ return Present (Find_Corresponding_Body (Pack_Id));
end if;
+ end Has_Body;
- -- A call to an Init_Proc in elaboration code may bring additional
- -- dependencies, if some of the record components thereof have
- -- initializations that are function calls that come from source. We
- -- treat the current node as a call to each of these functions, to check
- -- their elaboration impact.
+ ---------------------------
+ -- Has_Prior_Elaboration --
+ ---------------------------
- if Is_Init_Proc (Ent) and then From_Elab_Code then
- Process_Init_Proc : declare
- Unit_Decl : constant Node_Id := Unit_Declaration_Node (Ent);
+ function Has_Prior_Elaboration
+ (Unit_Id : Entity_Id;
+ Context_OK : Boolean := False;
+ Elab_Body_OK : Boolean := False;
+ Same_Unit_OK : Boolean := False) return Boolean
+ is
+ Main_Id : constant Entity_Id := Cunit_Entity (Main_Unit);
- function Check_Init_Call (Nod : Node_Id) return Traverse_Result;
- -- Find subprogram calls within body of Init_Proc for Traverse
- -- instantiation below.
+ begin
+ -- A preelaborated unit is always elaborated prior to the main unit
- procedure Traverse_Body is new Traverse_Proc (Check_Init_Call);
- -- Traversal procedure to find all calls with body of Init_Proc
+ if Is_Preelaborated_Unit (Unit_Id) then
+ return True;
- ---------------------
- -- Check_Init_Call --
- ---------------------
+ -- An internal unit is always elaborated prior to a non-internal main
+ -- unit.
- function Check_Init_Call (Nod : Node_Id) return Traverse_Result is
- Func : Entity_Id;
+ elsif In_Internal_Unit (Unit_Id)
+ and then not In_Internal_Unit (Main_Id)
+ then
+ return True;
- begin
- if Nkind (Nod) in N_Subprogram_Call
- and then Is_Entity_Name (Name (Nod))
- then
- Func := Entity (Name (Nod));
+ -- A unit has prior elaboration if it appears within the context of the
+ -- main unit. Consider this case only when requested by the caller.
- if Comes_From_Source (Func) then
- Check_A_Call
- (N, Func, Standard_Standard, Inter_Unit_Only => True);
- end if;
+ elsif Context_OK
+ and then Elaboration_Context.Get (Unit_Id) /= No_Elaboration_Attributes
+ then
+ return True;
- return OK;
+ -- A unit whose body is elaborated together with its spec has prior
+ -- elaboration except with respect to itself. Consider this case only
+ -- when requested by the caller.
- else
- return OK;
- end if;
- end Check_Init_Call;
+ elsif Elab_Body_OK
+ and then Has_Pragma_Elaborate_Body (Unit_Id)
+ and then not Is_Same_Unit (Unit_Id, Main_Id)
+ then
+ return True;
- -- Start of processing for Process_Init_Proc
+ -- A unit has no prior elaboration with respect to itself, but does not
+ -- require any means of ensuring its own elaboration either. Treat this
+ -- case as valid prior elaboration only when requested by the caller.
- begin
- if Nkind (Unit_Decl) = N_Subprogram_Body then
- Traverse_Body (Handled_Statement_Sequence (Unit_Decl));
- end if;
- end Process_Init_Proc;
+ elsif Same_Unit_OK and then Is_Same_Unit (Unit_Id, Main_Id) then
+ return True;
end if;
- end Check_Elab_Call;
- -----------------------
- -- Check_Elab_Assign --
- -----------------------
+ return False;
+ end Has_Prior_Elaboration;
- procedure Check_Elab_Assign (N : Node_Id) is
- Ent : Entity_Id;
- Scop : Entity_Id;
+ --------------------------
+ -- In_External_Instance --
+ --------------------------
- Pkg_Spec : Entity_Id;
- Pkg_Body : Entity_Id;
+ function In_External_Instance
+ (N : Node_Id;
+ Target_Decl : Node_Id) return Boolean
+ is
+ Dummy : Node_Id;
+ Inst_Body : Node_Id;
+ Inst_Decl : Node_Id;
begin
- -- For record or array component, check prefix. If it is an access type,
- -- then there is nothing to do (we do not know what is being assigned),
- -- but otherwise this is an assignment to the prefix.
+ -- Performance note: parent traversal
+
+ Inst_Decl := Find_Enclosing_Instance (Target_Decl);
- if Nkind_In (N, N_Indexed_Component,
- N_Selected_Component,
- N_Slice)
+ -- The target declaration appears within an instance spec. Visibility is
+ -- ignored because internally generated primitives for private types may
+ -- reside in the private declarations and still be invoked from outside.
+
+ if Present (Inst_Decl)
+ and then Nkind (Inst_Decl) = N_Package_Declaration
then
- if not Is_Access_Type (Etype (Prefix (N))) then
- Check_Elab_Assign (Prefix (N));
- end if;
+ -- The scenario comes from the main unit and the instance does not
- return;
- end if;
+ if In_Extended_Main_Code_Unit (N)
+ and then not In_Extended_Main_Code_Unit (Inst_Decl)
+ then
+ return True;
- -- For type conversion, check expression
+ -- Otherwise the scenario must not appear within the instance spec or
+ -- body.
- if Nkind (N) = N_Type_Conversion then
- Check_Elab_Assign (Expression (N));
- return;
+ else
+ Extract_Instance_Attributes
+ (Exp_Inst => Inst_Decl,
+ Inst_Body => Inst_Body,
+ Inst_Decl => Dummy);
+
+ -- Performance note: parent traversal
+
+ return not In_Subtree
+ (N => N,
+ Root1 => Inst_Decl,
+ Root2 => Inst_Body);
+ end if;
end if;
- -- Nothing to do if this is not an entity reference otherwise get entity
+ return False;
+ end In_External_Instance;
- if Is_Entity_Name (N) then
- Ent := Entity (N);
- else
- return;
+ ---------------------
+ -- In_Main_Context --
+ ---------------------
+
+ function In_Main_Context (N : Node_Id) return Boolean is
+ begin
+ -- Scenarios outside the main unit are not considered because the ALI
+ -- information supplied to binde is for the main unit only.
+
+ if not In_Extended_Main_Code_Unit (N) then
+ return False;
+
+ -- Scenarios within internal units are not considered unless switch
+ -- -gnatdE (elaboration checks on predefined units) is in effect.
+
+ elsif not Debug_Flag_EE and then In_Internal_Unit (N) then
+ return False;
end if;
- -- What we are looking for is a reference in the body of a package that
- -- modifies a variable declared in the visible part of the package spec.
+ return True;
+ end In_Main_Context;
- if Present (Ent)
- and then Comes_From_Source (N)
- and then not Suppress_Elaboration_Warnings (Ent)
- and then Ekind (Ent) = E_Variable
- and then not In_Private_Part (Ent)
- and then Is_Library_Level_Entity (Ent)
- then
- Scop := Current_Scope;
- loop
- if No (Scop) or else Scop = Standard_Standard then
- return;
- elsif Ekind (Scop) = E_Package
- and then Is_Compilation_Unit (Scop)
- then
- exit;
- else
- Scop := Scope (Scop);
+ ---------------------
+ -- In_Same_Context --
+ ---------------------
+
+ function In_Same_Context
+ (N1 : Node_Id;
+ N2 : Node_Id;
+ Nested_OK : Boolean := False) return Boolean
+ is
+ function Find_Enclosing_Context (N : Node_Id) return Node_Id;
+ -- Return the nearest enclosing non-library level or compilation unit
+ -- node which which encapsulates arbitrary node N. Return Empty is no
+ -- such context is available.
+
+ function In_Nested_Context
+ (Outer : Node_Id;
+ Inner : Node_Id) return Boolean;
+ -- Determine whether arbitrary node Outer encapsulates arbitrary node
+ -- Inner.
+
+ ----------------------------
+ -- Find_Enclosing_Context --
+ ----------------------------
+
+ function Find_Enclosing_Context (N : Node_Id) return Node_Id is
+ Context : Node_Id;
+ Par : Node_Id;
+
+ begin
+ Par := Parent (N);
+ while Present (Par) loop
+
+ -- A traversal from a subunit continues via the corresponding stub
+
+ if Nkind (Par) = N_Subunit then
+ Par := Corresponding_Stub (Par);
+
+ -- Stop the traversal when the nearest enclosing non-library level
+ -- encapsulator has been reached.
+
+ elsif Is_Non_Library_Level_Encapsulator (Par) then
+ Context := Parent (Par);
+
+ -- The sole exception is when the encapsulator is the unit of
+ -- compilation because this case requires special processing
+ -- (see below).
+
+ if Present (Context)
+ and then Nkind (Context) = N_Compilation_Unit
+ then
+ null;
+
+ else
+ return Par;
+ end if;
+
+ -- Reaching a compilation unit node without hitting a non-library
+ -- level encapsulator indicates that N is at the library level in
+ -- which case the compilation unit is the context.
+
+ elsif Nkind (Par) = N_Compilation_Unit then
+ return Par;
end if;
- end loop;
- -- Here Scop points to the containing library package
+ Par := Parent (Par);
+ end loop;
- Pkg_Spec := Scop;
- Pkg_Body := Body_Entity (Pkg_Spec);
+ return Empty;
+ end Find_Enclosing_Context;
- -- All OK if the package has an Elaborate_Body pragma
+ -----------------------
+ -- In_Nested_Context --
+ -----------------------
- if Has_Pragma_Elaborate_Body (Scop) then
- return;
- end if;
+ function In_Nested_Context
+ (Outer : Node_Id;
+ Inner : Node_Id) return Boolean
+ is
+ Par : Node_Id;
- -- OK if entity being modified is not in containing package spec
+ begin
+ Par := Inner;
+ while Present (Par) loop
- if not In_Same_Source_Unit (Scop, Ent) then
- return;
- end if;
+ -- A traversal from a subunit continues via the corresponding stub
- -- All OK if entity appears in generic package or generic instance.
- -- We just get too messed up trying to give proper warnings in the
- -- presence of generics. Better no message than a junk one.
+ if Nkind (Par) = N_Subunit then
+ Par := Corresponding_Stub (Par);
- Scop := Scope (Ent);
- while Present (Scop) and then Scop /= Pkg_Spec loop
- if Ekind (Scop) = E_Generic_Package then
- return;
- elsif Ekind (Scop) = E_Package
- and then Is_Generic_Instance (Scop)
- then
- return;
+ elsif Par = Outer then
+ return True;
end if;
- Scop := Scope (Scop);
+ Par := Parent (Par);
end loop;
- -- All OK if in task, don't issue warnings there
+ return False;
+ end In_Nested_Context;
- if In_Task_Activation then
- return;
- end if;
+ -- Local variables
- -- OK if no package body
+ Context_1 : constant Node_Id := Find_Enclosing_Context (N1);
+ Context_2 : constant Node_Id := Find_Enclosing_Context (N2);
- if No (Pkg_Body) then
- return;
- end if;
+ -- Start of processing for In_Same_Context
- -- OK if reference is not in package body
+ begin
+ -- Both nodes appear within the same context
- if not In_Same_Source_Unit (Pkg_Body, N) then
- return;
- end if;
+ if Context_1 = Context_2 then
+ return True;
- -- OK if package body has no handled statement sequence
+ -- Both nodes appear in compilation units. Determine whether one unit
+ -- is the body of the other.
- declare
- HSS : constant Node_Id :=
- Handled_Statement_Sequence (Declaration_Node (Pkg_Body));
- begin
- if No (HSS) or else not Comes_From_Source (HSS) then
- return;
- end if;
- end;
+ elsif Nkind (Context_1) = N_Compilation_Unit
+ and then Nkind (Context_2) = N_Compilation_Unit
+ then
+ return
+ Is_Same_Unit
+ (Unit_1 => Defining_Entity (Unit (Context_1)),
+ Unit_2 => Defining_Entity (Unit (Context_2)));
- -- We definitely have a case of a modification of an entity in
- -- the package spec from the elaboration code of the package body.
- -- We may not give the warning (because there are some additional
- -- checks to avoid too many false positives), but it would be a good
- -- idea for the binder to try to keep the body elaboration close to
- -- the spec elaboration.
+ -- The context of N1 encloses the context of N2
- Set_Elaborate_Body_Desirable (Pkg_Spec);
+ elsif Nested_OK and then In_Nested_Context (Context_1, Context_2) then
+ return True;
+ end if;
- -- All OK in gnat mode (we know what we are doing)
+ return False;
+ end In_Same_Context;
- if GNAT_Mode then
- return;
- end if;
+ ----------------
+ -- Initialize --
+ ----------------
- -- All OK if all warnings suppressed
+ procedure Initialize is
+ begin
+ -- Set the soft link which enables Atree.Rewrite to update a top level
+ -- scenario each time it is transformed into another node.
- if Warning_Mode = Suppress then
- return;
- end if;
+ Set_Rewriting_Proc (Update_Elaboration_Scenario'Access);
+ end Initialize;
+
+ ---------------
+ -- Info_Call --
+ ---------------
+
+ procedure Info_Call
+ (Call : Node_Id;
+ Target_Id : Entity_Id;
+ Info_Msg : Boolean;
+ In_SPARK : Boolean)
+ is
+ procedure Info_Accept_Alternative;
+ pragma Inline (Info_Accept_Alternative);
+ -- Output information concerning an accept alternative
+
+ procedure Info_Simple_Call;
+ pragma Inline (Info_Simple_Call);
+ -- Output information concerning the call
+
+ procedure Info_Type_Actions (Action : String);
+ pragma Inline (Info_Type_Actions);
+ -- Output information concerning action Action of a type
+
+ procedure Info_Verification_Call
+ (Pred : String;
+ Id : Entity_Id;
+ Id_Kind : String);
+ pragma Inline (Info_Verification_Call);
+ -- Output information concerning the verification of predicate Pred
+ -- applied to related entity Id with kind Id_Kind.
+
+ -----------------------------
+ -- Info_Accept_Alternative --
+ -----------------------------
+
+ procedure Info_Accept_Alternative is
+ Entry_Id : constant Entity_Id := Receiving_Entry (Target_Id);
+
+ begin
+ pragma Assert (Present (Entry_Id));
+
+ Elab_Msg_NE
+ (Msg => "accept for entry & during elaboration",
+ N => Call,
+ Id => Entry_Id,
+ Info_Msg => Info_Msg,
+ In_SPARK => In_SPARK);
+ end Info_Accept_Alternative;
+
+ ----------------------
+ -- Info_Simple_Call --
+ ----------------------
+
+ procedure Info_Simple_Call is
+ begin
+ Elab_Msg_NE
+ (Msg => "call to & during elaboration",
+ N => Call,
+ Id => Target_Id,
+ Info_Msg => Info_Msg,
+ In_SPARK => In_SPARK);
+ end Info_Simple_Call;
+
+ -----------------------
+ -- Info_Type_Actions --
+ -----------------------
+
+ procedure Info_Type_Actions (Action : String) is
+ Typ : constant Entity_Id := First_Formal_Type (Target_Id);
+
+ begin
+ pragma Assert (Present (Typ));
+
+ Elab_Msg_NE
+ (Msg => Action & " actions for type & during elaboration",
+ N => Call,
+ Id => Typ,
+ Info_Msg => Info_Msg,
+ In_SPARK => In_SPARK);
+ end Info_Type_Actions;
+
+ ----------------------------
+ -- Info_Verification_Call --
+ ----------------------------
+
+ procedure Info_Verification_Call
+ (Pred : String;
+ Id : Entity_Id;
+ Id_Kind : String)
+ is
+ begin
+ pragma Assert (Present (Id));
+
+ Elab_Msg_NE
+ (Msg =>
+ "verification of " & Pred & " of " & Id_Kind & " & during "
+ & "elaboration",
+ N => Call,
+ Id => Id,
+ Info_Msg => Info_Msg,
+ In_SPARK => In_SPARK);
+ end Info_Verification_Call;
+
+ -- Start of processing for Info_Call
+
+ begin
+ -- Do not output anything for targets defined in internal units because
+ -- this creates noise.
+
+ if not In_Internal_Unit (Target_Id) then
+
+ -- Accept alternative
+
+ if Is_Accept_Alternative_Proc (Target_Id) then
+ Info_Accept_Alternative;
+
+ -- Adjustment
+
+ elsif Is_TSS (Target_Id, TSS_Deep_Adjust) then
+ Info_Type_Actions ("adjustment");
+
+ -- Default_Initial_Condition
+
+ elsif Is_Default_Initial_Condition_Proc (Target_Id) then
+ Info_Verification_Call
+ (Pred => "Default_Initial_Condition",
+ Id => First_Formal_Type (Target_Id),
+ Id_Kind => "type");
+
+ -- Entries
- -- All OK if elaboration checks suppressed for entity
+ elsif Is_Protected_Entry (Target_Id) then
+ Info_Simple_Call;
- if Checks_May_Be_Suppressed (Ent)
- and then Is_Check_Suppressed (Ent, Elaboration_Check)
+ -- Task entry calls are never processed because the entry being
+ -- invoked does not have a corresponding "body", it has a select.
+
+ elsif Is_Task_Entry (Target_Id) then
+ null;
+
+ -- Finalization
+
+ elsif Is_TSS (Target_Id, TSS_Deep_Finalize) then
+ Info_Type_Actions ("finalization");
+
+ -- Calls to _Finalizer procedures must not appear in the output
+ -- because this creates confusing noise.
+
+ elsif Is_Finalizer_Proc (Target_Id) then
+ null;
+
+ -- Initial_Condition
+
+ elsif Is_Initial_Condition_Proc (Target_Id) then
+ Info_Verification_Call
+ (Pred => "Initial_Condition",
+ Id => Find_Enclosing_Scope (Call),
+ Id_Kind => "package");
+
+ -- Initialization
+
+ elsif Is_Init_Proc (Target_Id)
+ or else Is_TSS (Target_Id, TSS_Deep_Initialize)
then
- return;
- end if;
+ Info_Type_Actions ("initialization");
- -- OK if the entity is initialized. Note that the No_Initialization
- -- flag usually means that the initialization has been rewritten into
- -- assignments, but that still counts for us.
+ -- Invariant
- declare
- Decl : constant Node_Id := Declaration_Node (Ent);
- begin
- if Nkind (Decl) = N_Object_Declaration
- and then (Present (Expression (Decl))
- or else No_Initialization (Decl))
- then
- return;
- end if;
- end;
+ elsif Is_Invariant_Proc (Target_Id) then
+ Info_Verification_Call
+ (Pred => "invariants",
+ Id => First_Formal_Type (Target_Id),
+ Id_Kind => "type");
- -- Here is where we give the warning
+ -- Partial invariant calls must not appear in the output because this
+ -- creates confusing noise.
- -- All OK if warnings suppressed on the entity
+ elsif Is_Partial_Invariant_Proc (Target_Id) then
+ null;
- if not Has_Warnings_Off (Ent) then
- Error_Msg_Sloc := Sloc (Ent);
+ -- _Postconditions
- Error_Msg_NE
- ("??& can be accessed by clients before this initialization",
- N, Ent);
- Error_Msg_NE
- ("\??add Elaborate_Body to spec to ensure & is initialized",
- N, Ent);
- end if;
+ elsif Is_Postconditions_Proc (Target_Id) then
+ Info_Verification_Call
+ (Pred => "postconditions",
+ Id => Find_Enclosing_Scope (Call),
+ Id_Kind => "subprogram");
+
+ -- Subprograms must come last because some of the previous cases fall
+ -- under this category.
+
+ elsif Ekind (Target_Id) = E_Function then
+ Info_Simple_Call;
+
+ elsif Ekind (Target_Id) = E_Procedure then
+ Info_Simple_Call;
- if not All_Errors_Mode then
- Set_Suppress_Elaboration_Warnings (Ent);
+ else
+ pragma Assert (False);
+ null;
end if;
end if;
- end Check_Elab_Assign;
+ end Info_Call;
- ----------------------
- -- Check_Elab_Calls --
- ----------------------
+ ------------------------
+ -- Info_Instantiation --
+ ------------------------
- -- WARNING: This routine manages SPARK regions
+ procedure Info_Instantiation
+ (Inst : Node_Id;
+ Gen_Id : Entity_Id;
+ Info_Msg : Boolean;
+ In_SPARK : Boolean)
+ is
+ begin
+ Elab_Msg_NE
+ (Msg => "instantiation of & during elaboration",
+ N => Inst,
+ Id => Gen_Id,
+ Info_Msg => Info_Msg,
+ In_SPARK => In_SPARK);
+ end Info_Instantiation;
- procedure Check_Elab_Calls is
- Saved_SM : SPARK_Mode_Type;
- Saved_SMP : Node_Id;
+ ------------------------
+ -- Info_Variable_Read --
+ ------------------------
+ procedure Info_Variable_Read
+ (Ref : Node_Id;
+ Var_Id : Entity_Id;
+ Info_Msg : Boolean;
+ In_SPARK : Boolean)
+ is
+ begin
+ Elab_Msg_NE
+ (Msg => "read of variable & during elaboration",
+ N => Ref,
+ Id => Var_Id,
+ Info_Msg => Info_Msg,
+ In_SPARK => In_SPARK);
+ end Info_Variable_Read;
+
+ --------------------
+ -- Insertion_Node --
+ --------------------
+
+ function Insertion_Node (N : Node_Id; Ins_Nod : Node_Id) return Node_Id is
begin
- -- If expansion is disabled, do not generate any checks, unless we
- -- are in GNATprove mode, so that errors are issued in GNATprove for
- -- violations of static elaboration rules in SPARK code. Also skip
- -- checks if any subunits are missing because in either case we lack the
- -- full information that we need, and no object file will be created in
- -- any case.
+ -- When the scenario denotes an instantiation, the proper insertion node
+ -- is the instance spec. This ensures that the generic actuals will not
+ -- be evaluated prior to a potential ABE.
- if (not Expander_Active and not GNATprove_Mode)
- or else Is_Generic_Unit (Cunit_Entity (Main_Unit))
- or else Subunits_Missing
+ if Nkind (N) in N_Generic_Instantiation
+ and then Present (Instance_Spec (N))
then
- return;
+ return Instance_Spec (N);
+
+ -- Otherwise the proper insertion node is the candidate insertion node
+
+ else
+ return Ins_Nod;
end if;
+ end Insertion_Node;
- -- Skip delayed calls if we had any errors
+ -----------------------
+ -- Install_ABE_Check --
+ -----------------------
- if Serious_Errors_Detected = 0 then
- Delaying_Elab_Checks := False;
- Expander_Mode_Save_And_Set (True);
+ procedure Install_ABE_Check
+ (N : Node_Id;
+ Id : Entity_Id;
+ Ins_Nod : Node_Id)
+ is
+ Check_Ins_Nod : constant Node_Id := Insertion_Node (N, Ins_Nod);
+ -- Insert the check prior to this node
- for J in Delay_Check.First .. Delay_Check.Last loop
- Push_Scope (Delay_Check.Table (J).Curscop);
- From_Elab_Code := Delay_Check.Table (J).From_Elab_Code;
- In_Task_Activation := Delay_Check.Table (J).In_Task_Activation;
+ Loc : constant Source_Ptr := Sloc (N);
+ Spec_Id : constant Entity_Id := Unique_Entity (Id);
+ Unit_Id : constant Entity_Id := Find_Top_Unit (Id);
+ Scop_Id : Entity_Id;
- Saved_SM := SPARK_Mode;
- Saved_SMP := SPARK_Mode_Pragma;
+ begin
+ -- Nothing to do when compiling for GNATprove because raise statements
+ -- are not supported.
- -- Set appropriate value of SPARK_Mode
+ if GNATprove_Mode then
+ return;
- if Delay_Check.Table (J).From_SPARK_Code then
- SPARK_Mode := On;
- end if;
+ -- Nothing to do when the compilation will not produce an executable
- Check_Internal_Call_Continue
- (N => Delay_Check.Table (J).N,
- E => Delay_Check.Table (J).E,
- Outer_Scope => Delay_Check.Table (J).Outer_Scope,
- Orig_Ent => Delay_Check.Table (J).Orig_Ent);
+ elsif Serious_Errors_Detected > 0 then
+ return;
- Restore_SPARK_Mode (Saved_SM, Saved_SMP);
- Pop_Scope;
- end loop;
+ -- Nothing to do for a compilation unit because there is no executable
+ -- environment at that level.
+
+ elsif Nkind (Parent (Check_Ins_Nod)) = N_Compilation_Unit then
+ return;
+
+ -- Nothing to do when the unit is elaborated prior to the main unit.
+ -- This check must also consider the following cases:
- -- Set Delaying_Elab_Checks back on for next main compilation
+ -- * Id's unit appears in the context of the main unit
- Expander_Mode_Restore;
- Delaying_Elab_Checks := True;
+ -- * Id's unit is subject to pragma Elaborate_Body. An ABE check MUST
+ -- NOT be generated because Id's unit is always elaborated prior to
+ -- the main unit.
+
+ -- * Id's unit is the main unit. An ABE check MUST be generated in this
+ -- case because a conditional ABE may be raised depending on the flow
+ -- of execution within the main unit (flag Same_Unit_OK is False).
+
+ elsif Has_Prior_Elaboration
+ (Unit_Id => Unit_Id,
+ Context_OK => True,
+ Elab_Body_OK => True)
+ then
+ return;
end if;
- end Check_Elab_Calls;
- ------------------------------
- -- Check_Elab_Instantiation --
- ------------------------------
+ -- Prevent multiple scenarios from installing the same ABE check
+
+ Set_Is_Elaboration_Checks_OK_Node (N, False);
+
+ -- Install the nearest enclosing scope of the scenario as there must be
+ -- something on the scope stack.
+
+ -- Performance note: parent traversal
+
+ Scop_Id := Find_Enclosing_Scope (Check_Ins_Nod);
+ pragma Assert (Present (Scop_Id));
+
+ Push_Scope (Scop_Id);
+
+ -- Generate:
+ -- if not Spec_Id'Elaborated then
+ -- raise Program_Error with "access before elaboration";
+ -- end if;
+
+ Insert_Action (Check_Ins_Nod,
+ Make_Raise_Program_Error (Loc,
+ Condition =>
+ Make_Op_Not (Loc,
+ Right_Opnd =>
+ Make_Attribute_Reference (Loc,
+ Prefix => New_Occurrence_Of (Spec_Id, Loc),
+ Attribute_Name => Name_Elaborated)),
+ Reason => PE_Access_Before_Elaboration));
+
+ Pop_Scope;
+ end Install_ABE_Check;
- procedure Check_Elab_Instantiation
+ -----------------------
+ -- Install_ABE_Check --
+ -----------------------
+
+ procedure Install_ABE_Check
(N : Node_Id;
- Outer_Scope : Entity_Id := Empty)
+ Target_Id : Entity_Id;
+ Target_Decl : Node_Id;
+ Target_Body : Node_Id;
+ Ins_Nod : Node_Id)
is
- Ent : Entity_Id;
+ procedure Build_Elaboration_Entity;
+ pragma Inline (Build_Elaboration_Entity);
+ -- Create a new elaboration flag for Target_Id, insert it prior to
+ -- Target_Decl, and set it after Body_Decl.
+
+ ------------------------------
+ -- Build_Elaboration_Entity --
+ ------------------------------
+
+ procedure Build_Elaboration_Entity is
+ Loc : constant Source_Ptr := Sloc (Target_Id);
+ Flag_Id : Entity_Id;
+
+ begin
+ -- Create the declaration of the elaboration flag. The name carries a
+ -- unique counter in case of name overloading.
+
+ Flag_Id :=
+ Make_Defining_Identifier (Loc,
+ Chars => New_External_Name (Chars (Target_Id), 'E', -1));
+
+ Set_Elaboration_Entity (Target_Id, Flag_Id);
+ Set_Elaboration_Entity_Required (Target_Id);
+
+ Push_Scope (Scope (Target_Id));
+
+ -- Generate:
+ -- Enn : Short_Integer := 0;
+
+ Insert_Action (Target_Decl,
+ Make_Object_Declaration (Loc,
+ Defining_Identifier => Flag_Id,
+ Object_Definition =>
+ New_Occurrence_Of (Standard_Short_Integer, Loc),
+ Expression => Make_Integer_Literal (Loc, Uint_0)));
+
+ -- Generate:
+ -- Enn := 1;
+
+ Set_Elaboration_Flag (Target_Body, Target_Id);
+
+ Pop_Scope;
+ end Build_Elaboration_Entity;
+
+ -- Local variables
+
+ Target_Unit_Id : constant Entity_Id := Find_Top_Unit (Target_Id);
+
+ -- Start for processing for Install_ABE_Check
begin
- -- Check for and deal with bad instantiation case. There is some
- -- duplicated code here, but we will worry about this later ???
+ -- Nothing to do when compiling for GNATprove because raise statements
+ -- are not supported.
- Check_Bad_Instantiation (N);
+ if GNATprove_Mode then
+ return;
- if ABE_Is_Certain (N) then
+ -- Nothing to do when the compilation will not produce an executable
+
+ elsif Serious_Errors_Detected > 0 then
return;
- end if;
- -- Nothing to do if we do not have an instantiation (happens in some
- -- error cases, and also in the formal package declaration case)
+ -- Nothing to do when the target is a protected subprogram because the
+ -- check is associated with the protected body subprogram.
- if Nkind (N) not in N_Generic_Instantiation then
+ elsif Is_Protected_Subp (Target_Id) then
return;
- end if;
- -- Nothing to do if inside a generic template
+ -- Nothing to do when the target is elaborated prior to the main unit.
+ -- This check must also consider the following cases:
+
+ -- * The unit of the target appears in the context of the main unit
+
+ -- * The unit of the target is subject to pragma Elaborate_Body. An ABE
+ -- check MUST NOT be generated because the unit is always elaborated
+ -- prior to the main unit.
+
+ -- * The unit of the target is the main unit. An ABE check MUST be added
+ -- in this case because a conditional ABE may be raised depending on
+ -- the flow of execution within the main unit (flag Same_Unit_OK is
+ -- False).
- if Inside_A_Generic then
+ elsif Has_Prior_Elaboration
+ (Unit_Id => Target_Unit_Id,
+ Context_OK => True,
+ Elab_Body_OK => True)
+ then
return;
+
+ -- Create an elaboration flag for the target when it does not have one
+
+ elsif No (Elaboration_Entity (Target_Id)) then
+ Build_Elaboration_Entity;
end if;
- -- Nothing to do if the instantiation is not in the main unit
+ Install_ABE_Check
+ (N => N,
+ Ins_Nod => Ins_Nod,
+ Id => Target_Id);
+ end Install_ABE_Check;
- if not In_Extended_Main_Code_Unit (N) then
+ -------------------------
+ -- Install_ABE_Failure --
+ -------------------------
+
+ procedure Install_ABE_Failure (N : Node_Id; Ins_Nod : Node_Id) is
+ Fail_Ins_Nod : constant Node_Id := Insertion_Node (N, Ins_Nod);
+ -- Insert the failure prior to this node
+
+ Loc : constant Source_Ptr := Sloc (N);
+ Scop_Id : Entity_Id;
+
+ begin
+ -- Nothing to do when compiling for GNATprove because raise statements
+ -- are not supported.
+
+ if GNATprove_Mode then
+ return;
+
+ -- Nothing to do when the compilation will not produce an executable
+
+ elsif Serious_Errors_Detected > 0 then
+ return;
+
+ -- Do not install an ABE check for a compilation unit because there is
+ -- no executable environment at that level.
+
+ elsif Nkind (Parent (Fail_Ins_Nod)) = N_Compilation_Unit then
return;
end if;
- Ent := Get_Generic_Entity (N);
- From_Elab_Code := not In_Subprogram_Or_Concurrent_Unit;
+ -- Prevent multiple scenarios from installing the same ABE failure
- -- See if we need to analyze this instantiation. We analyze it if
- -- either of the following conditions is met:
+ Set_Is_Elaboration_Checks_OK_Node (N, False);
- -- It is an inner level instantiation (since in this case it was
- -- triggered by an outer level call from elaboration code), but
- -- only if the instantiation is within the scope of the original
- -- outer level call.
+ -- Install the nearest enclosing scope of the scenario as there must be
+ -- something on the scope stack.
- -- It is an outer level instantiation from elaboration code, or the
- -- instantiated entity is in the same elaboration scope.
+ -- Performance note: parent traversal
- -- And in these cases, we will check both the inter-unit case and
- -- the intra-unit (within a single unit) case.
+ Scop_Id := Find_Enclosing_Scope (Fail_Ins_Nod);
+ pragma Assert (Present (Scop_Id));
- C_Scope := Current_Scope;
+ Push_Scope (Scop_Id);
- if Present (Outer_Scope) and then Within (Scope (Ent), Outer_Scope) then
- Set_C_Scope;
- Check_A_Call (N, Ent, Outer_Scope, Inter_Unit_Only => False);
+ -- Generate:
+ -- raise Program_Error with "access before elaboration";
- elsif From_Elab_Code then
- Set_C_Scope;
- Check_A_Call (N, Ent, Standard_Standard, Inter_Unit_Only => False);
+ Insert_Action (Fail_Ins_Nod,
+ Make_Raise_Program_Error (Loc,
+ Reason => PE_Access_Before_Elaboration));
- elsif Same_Elaboration_Scope (C_Scope, Scope (Ent)) then
- Set_C_Scope;
- Check_A_Call (N, Ent, Scope (Ent), Inter_Unit_Only => False);
+ Pop_Scope;
+ end Install_ABE_Failure;
- -- If none of those cases holds, but Dynamic_Elaboration_Checks mode is
- -- set, then we will do the check, but only in the inter-unit case (this
- -- is to accommodate unguarded elaboration calls from other units in
- -- which this same mode is set). We inhibit warnings in this case, since
- -- this instantiation is not occurring in elaboration code.
+ --------------------------------
+ -- Is_Accept_Alternative_Proc --
+ --------------------------------
- elsif Dynamic_Elaboration_Checks then
- Set_C_Scope;
- Check_A_Call
- (N,
- Ent,
- Standard_Standard,
- Inter_Unit_Only => True,
- Generate_Warnings => False);
+ function Is_Accept_Alternative_Proc (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote a procedure with a receiving entry
- else
- return;
+ return Ekind (Id) = E_Procedure and then Present (Receiving_Entry (Id));
+ end Is_Accept_Alternative_Proc;
+
+ ------------------------
+ -- Is_Activation_Proc --
+ ------------------------
+
+ function Is_Activation_Proc (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote one of the runtime procedures in
+ -- charge of task activation.
+
+ if Ekind (Id) = E_Procedure then
+ if Restricted_Profile then
+ return Is_RTE (Id, RE_Activate_Restricted_Tasks);
+ else
+ return Is_RTE (Id, RE_Activate_Tasks);
+ end if;
end if;
- end Check_Elab_Instantiation;
- -------------------------
- -- Check_Internal_Call --
- -------------------------
+ return False;
+ end Is_Activation_Proc;
+
+ ----------------------------
+ -- Is_Ada_Semantic_Target --
+ ----------------------------
+
+ function Is_Ada_Semantic_Target (Id : Entity_Id) return Boolean is
+ begin
+ return
+ Is_Activation_Proc (Id)
+ or else Is_Controlled_Proc (Id, Name_Adjust)
+ or else Is_Controlled_Proc (Id, Name_Finalize)
+ or else Is_Controlled_Proc (Id, Name_Initialize)
+ or else Is_Init_Proc (Id)
+ or else Is_Invariant_Proc (Id)
+ or else Is_Protected_Entry (Id)
+ or else Is_Protected_Subp (Id)
+ or else Is_Protected_Body_Subp (Id)
+ or else Is_Task_Entry (Id);
+ end Is_Ada_Semantic_Target;
+
+ ----------------------------
+ -- Is_Bodiless_Subprogram --
+ ----------------------------
+
+ function Is_Bodiless_Subprogram (Subp_Id : Entity_Id) return Boolean is
+ begin
+ -- An abstract subprogram does not have a body
+
+ if Ekind_In (Subp_Id, E_Function,
+ E_Operator,
+ E_Procedure)
+ and then Is_Abstract_Subprogram (Subp_Id)
+ then
+ return True;
+
+ -- A formal subprogram does not have a body
+
+ elsif Is_Formal_Subprogram (Subp_Id) then
+ return True;
+
+ -- An imported subprogram may have a body, however it is not known at
+ -- compile or bind time where the body resides and whether it will be
+ -- elaborated on time.
+
+ elsif Is_Imported (Subp_Id) then
+ return True;
+ end if;
+
+ return False;
+ end Is_Bodiless_Subprogram;
- procedure Check_Internal_Call
+ --------------------------------
+ -- Is_Check_Emitting_Scenario --
+ --------------------------------
+
+ function Is_Check_Emitting_Scenario (N : Node_Id) return Boolean is
+ begin
+ return
+ Nkind_In (N, N_Call_Marker,
+ N_Function_Instantiation,
+ N_Package_Instantiation,
+ N_Procedure_Instantiation);
+ end Is_Check_Emitting_Scenario;
+
+ ------------------------
+ -- Is_Controlled_Proc --
+ ------------------------
+
+ function Is_Controlled_Proc
+ (Subp_Id : Entity_Id;
+ Subp_Nam : Name_Id) return Boolean
+ is
+ Formal_Id : Entity_Id;
+
+ begin
+ pragma Assert (Nam_In (Subp_Nam, Name_Adjust,
+ Name_Finalize,
+ Name_Initialize));
+
+ -- To qualify, the subprogram must denote a source procedure with name
+ -- Adjust, Finalize, or Initialize where the sole formal is controlled.
+
+ if Comes_From_Source (Subp_Id)
+ and then Ekind (Subp_Id) = E_Procedure
+ and then Chars (Subp_Id) = Subp_Nam
+ then
+ Formal_Id := First_Formal (Subp_Id);
+
+ return
+ Present (Formal_Id)
+ and then Is_Controlled (Etype (Formal_Id))
+ and then No (Next_Formal (Formal_Id));
+ end if;
+
+ return False;
+ end Is_Controlled_Proc;
+
+ ---------------------------------------
+ -- Is_Default_Initial_Condition_Proc --
+ ---------------------------------------
+
+ function Is_Default_Initial_Condition_Proc
+ (Id : Entity_Id) return Boolean
+ is
+ begin
+ -- To qualify, the entity must denote a Default_Initial_Condition
+ -- procedure.
+
+ return Ekind (Id) = E_Procedure and then Is_DIC_Procedure (Id);
+ end Is_Default_Initial_Condition_Proc;
+
+ -----------------------
+ -- Is_Finalizer_Proc --
+ -----------------------
+
+ function Is_Finalizer_Proc (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote a _Finalizer procedure
+
+ return Ekind (Id) = E_Procedure and then Chars (Id) = Name_uFinalizer;
+ end Is_Finalizer_Proc;
+
+ -----------------------
+ -- Is_Guaranteed_ABE --
+ -----------------------
+
+ function Is_Guaranteed_ABE
(N : Node_Id;
- E : Entity_Id;
- Outer_Scope : Entity_Id;
- Orig_Ent : Entity_Id)
+ Target_Decl : Node_Id;
+ Target_Body : Node_Id) return Boolean
is
- function Within_Initial_Condition (Call : Node_Id) return Boolean;
- -- Determine whether call Call occurs within pragma Initial_Condition or
- -- pragma Check with check_kind set to Initial_Condition.
+ begin
+ -- Avoid cascaded errors if there were previous serious infractions.
+ -- As a result the scenario will not be treated as a guaranteed ABE.
+ -- This behaviour parallels that of the old ABE mechanism.
- ------------------------------
- -- Within_Initial_Condition --
- ------------------------------
+ if Serious_Errors_Detected > 0 then
+ return False;
- function Within_Initial_Condition (Call : Node_Id) return Boolean is
- Args : List_Id;
- Nam : Name_Id;
- Par : Node_Id;
+ -- The scenario and the target appear within the same context ignoring
+ -- enclosing library levels.
- begin
- -- Traverse the parent chain looking for an enclosing pragma
+ -- Performance note: parent traversal
- Par := Call;
- while Present (Par) loop
- if Nkind (Par) = N_Pragma then
- Nam := Pragma_Name (Par);
+ elsif In_Same_Context (N, Target_Decl) then
- -- Pragma Initial_Condition appears in its alternative from as
- -- Check (Initial_Condition, ...).
+ -- The target body has already been encountered. The scenario results
+ -- in a guaranteed ABE if it appears prior to the body.
- if Nam = Name_Check then
- Args := Pragma_Argument_Associations (Par);
+ if Present (Target_Body) then
+ return Earlier_In_Extended_Unit (N, Target_Body);
- -- Pragma Check should have at least two arguments
+ -- Otherwise the body has not been encountered yet. The scenario is
+ -- a guaranteed ABE since the body will appear later. It is assumed
+ -- that the caller has already checked whether the scenario is ABE-
+ -- safe as optional bodies are not considered here.
- pragma Assert (Present (Args));
+ else
+ return True;
+ end if;
+ end if;
- return
- Chars (Expression (First (Args))) = Name_Initial_Condition;
+ return False;
+ end Is_Guaranteed_ABE;
- -- Direct match
+ -------------------------------
+ -- Is_Initial_Condition_Proc --
+ -------------------------------
- elsif Nam = Name_Initial_Condition then
- return True;
+ function Is_Initial_Condition_Proc (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote an Initial_Condition procedure
- -- Since pragmas are never nested within other pragmas, stop
- -- the traversal.
+ return
+ Ekind (Id) = E_Procedure and then Is_Initial_Condition_Procedure (Id);
+ end Is_Initial_Condition_Proc;
- else
- return False;
- end if;
+ --------------------
+ -- Is_Initialized --
+ --------------------
- -- Prevent the search from going too far
+ function Is_Initialized (Obj_Decl : Node_Id) return Boolean is
+ begin
+ -- To qualify, the object declaration must have an expression
- elsif Is_Body_Or_Package_Declaration (Par) then
- exit;
- end if;
+ return
+ Present (Expression (Obj_Decl)) or else Has_Init_Expression (Obj_Decl);
+ end Is_Initialized;
- Par := Parent (Par);
+ -----------------------
+ -- Is_Invariant_Proc --
+ -----------------------
- -- If assertions are not enabled, the check pragma is rewritten
- -- as an if_statement in sem_prag, to generate various warnings
- -- on boolean expressions. Retrieve the original pragma.
+ function Is_Invariant_Proc (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote the "full" invariant procedure
- if Nkind (Original_Node (Par)) = N_Pragma then
- Par := Original_Node (Par);
- end if;
- end loop;
+ return Ekind (Id) = E_Procedure and then Is_Invariant_Procedure (Id);
+ end Is_Invariant_Proc;
- return False;
- end Within_Initial_Condition;
+ ---------------------------------------
+ -- Is_Non_Library_Level_Encapsulator --
+ ---------------------------------------
- -- Local variables
+ function Is_Non_Library_Level_Encapsulator (N : Node_Id) return Boolean is
+ begin
+ case Nkind (N) is
+ when N_Abstract_Subprogram_Declaration
+ | N_Aspect_Specification
+ | N_Component_Declaration
+ | N_Entry_Body
+ | N_Entry_Declaration
+ | N_Expression_Function
+ | N_Formal_Abstract_Subprogram_Declaration
+ | N_Formal_Concrete_Subprogram_Declaration
+ | N_Formal_Object_Declaration
+ | N_Formal_Package_Declaration
+ | N_Formal_Type_Declaration
+ | N_Generic_Association
+ | N_Implicit_Label_Declaration
+ | N_Incomplete_Type_Declaration
+ | N_Private_Extension_Declaration
+ | N_Private_Type_Declaration
+ | N_Protected_Body
+ | N_Protected_Type_Declaration
+ | N_Single_Protected_Declaration
+ | N_Single_Task_Declaration
+ | N_Subprogram_Body
+ | N_Subprogram_Declaration
+ | N_Task_Body
+ | N_Task_Type_Declaration
+ =>
+ return True;
+
+ when others =>
+ return Is_Generic_Declaration_Or_Body (N);
+ end case;
+ end Is_Non_Library_Level_Encapsulator;
+
+ -------------------------------
+ -- Is_Partial_Invariant_Proc --
+ -------------------------------
+
+ function Is_Partial_Invariant_Proc (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote the "partial" invariant procedure
+
+ return
+ Ekind (Id) = E_Procedure and then Is_Partial_Invariant_Procedure (Id);
+ end Is_Partial_Invariant_Proc;
+
+ ----------------------------
+ -- Is_Postconditions_Proc --
+ ----------------------------
- Inst_Case : constant Boolean := Nkind (N) in N_Generic_Instantiation;
+ function Is_Postconditions_Proc (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote a _Postconditions procedure
+
+ return
+ Ekind (Id) = E_Procedure and then Chars (Id) = Name_uPostconditions;
+ end Is_Postconditions_Proc;
+
+ ---------------------------
+ -- Is_Preelaborated_Unit --
+ ---------------------------
+
+ function Is_Preelaborated_Unit (Id : Entity_Id) return Boolean is
+ begin
+ return
+ Is_Preelaborated (Id)
+ or else Is_Pure (Id)
+ or else Is_Remote_Call_Interface (Id)
+ or else Is_Remote_Types (Id)
+ or else Is_Shared_Passive (Id);
+ end Is_Preelaborated_Unit;
+
+ ------------------------
+ -- Is_Protected_Entry --
+ ------------------------
+
+ function Is_Protected_Entry (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote an entry defined in a protected
+ -- type.
+
+ return
+ Is_Entry (Id)
+ and then Is_Protected_Type (Non_Private_View (Scope (Id)));
+ end Is_Protected_Entry;
+
+ -----------------------
+ -- Is_Protected_Subp --
+ -----------------------
+
+ function Is_Protected_Subp (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote a subprogram defined within a
+ -- protected type.
+
+ return
+ Ekind_In (Id, E_Function, E_Procedure)
+ and then Is_Protected_Type (Non_Private_View (Scope (Id)));
+ end Is_Protected_Subp;
- -- Start of processing for Check_Internal_Call
+ ----------------------------
+ -- Is_Protected_Body_Subp --
+ ----------------------------
+
+ function Is_Protected_Body_Subp (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote a subprogram with attribute
+ -- Protected_Subprogram set.
+
+ return
+ Ekind_In (Id, E_Function, E_Procedure)
+ and then Present (Protected_Subprogram (Id));
+ end Is_Protected_Body_Subp;
+ ------------------------
+ -- Is_Safe_Activation --
+ ------------------------
+
+ function Is_Safe_Activation
+ (Call : Node_Id;
+ Task_Decl : Node_Id) return Boolean
+ is
begin
- -- For P'Access, we want to warn if the -gnatw.f switch is set, and the
- -- node comes from source.
+ -- The activation of a task coming from an external instance cannot
+ -- cause an ABE because the generic was already instantiated. Note
+ -- that the instantiation itself may lead to an ABE.
+
+ return
+ In_External_Instance
+ (N => Call,
+ Target_Decl => Task_Decl);
+ end Is_Safe_Activation;
+
+ ------------------
+ -- Is_Safe_Call --
+ ------------------
+
+ function Is_Safe_Call
+ (Call : Node_Id;
+ Target_Attrs : Target_Attributes) return Boolean
+ is
+ begin
+ -- The target is either an abstract subprogram, formal subprogram, or
+ -- imported, in which case it does not have a body at compile or bind
+ -- time. Assume that the call is ABE-safe.
+
+ if Is_Bodiless_Subprogram (Target_Attrs.Spec_Id) then
+ return True;
+
+ -- The target is an instantiation of a generic subprogram. The call
+ -- cannot cause an ABE because the generic was already instantiated.
+ -- Note that the instantiation itself may lead to an ABE.
- if Nkind (N) = N_Attribute_Reference
- and then ((not Warn_On_Elab_Access and then not Debug_Flag_Dot_O)
- or else not Comes_From_Source (N))
+ elsif Is_Generic_Instance (Target_Attrs.Spec_Id) then
+ return True;
+
+ -- The invocation of a target coming from an external instance cannot
+ -- cause an ABE because the generic was already instantiated. Note that
+ -- the instantiation itself may lead to an ABE.
+
+ elsif In_External_Instance
+ (N => Call,
+ Target_Decl => Target_Attrs.Spec_Decl)
then
- return;
+ return True;
- -- If not function or procedure call, instantiation, or 'Access, then
- -- ignore call (this happens in some error cases and rewriting cases).
+ -- The target is a subprogram body without a previous declaration. The
+ -- call cannot cause an ABE because the body has already been seen.
- elsif not Nkind_In (N, N_Attribute_Reference,
- N_Function_Call,
- N_Procedure_Call_Statement)
- and then not Inst_Case
+ elsif Nkind (Target_Attrs.Spec_Decl) = N_Subprogram_Body
+ and then No (Corresponding_Spec (Target_Attrs.Spec_Decl))
then
- return;
+ return True;
- -- Nothing to do if this is a call or instantiation that has already
- -- been found to be a sure ABE.
+ -- The target is a subprogram body stub without a prior declaration.
+ -- The call cannot cause an ABE because the proper body substitutes
+ -- the stub.
- elsif Nkind (N) /= N_Attribute_Reference and then ABE_Is_Certain (N) then
- return;
+ elsif Nkind (Target_Attrs.Spec_Decl) = N_Subprogram_Body_Stub
+ and then No (Corresponding_Spec_Of_Stub (Target_Attrs.Spec_Decl))
+ then
+ return True;
- -- Nothing to do if errors already detected (avoid cascaded errors)
+ -- Subprogram bodies which wrap attribute references used as actuals
+ -- in instantiations are always ABE-safe. These bodies are artifacts
+ -- of expansion.
- elsif Serious_Errors_Detected /= 0 then
- return;
+ elsif Present (Target_Attrs.Body_Decl)
+ and then Nkind (Target_Attrs.Body_Decl) = N_Subprogram_Body
+ and then Was_Attribute_Reference (Target_Attrs.Body_Decl)
+ then
+ return True;
+ end if;
- -- Nothing to do if not in full analysis mode
+ return False;
+ end Is_Safe_Call;
- elsif not Full_Analysis then
- return;
+ ---------------------------
+ -- Is_Safe_Instantiation --
+ ---------------------------
- -- Nothing to do if analyzing in special spec-expression mode, since the
- -- call is not actually being made at this time.
+ function Is_Safe_Instantiation
+ (Inst : Node_Id;
+ Gen_Attrs : Target_Attributes) return Boolean
+ is
+ begin
+ -- The generic is an intrinsic subprogram in which case it does not
+ -- have a body at compile or bind time. Assume that the instantiation
+ -- is ABE-safe.
- elsif In_Spec_Expression then
- return;
+ if Is_Bodiless_Subprogram (Gen_Attrs.Spec_Id) then
+ return True;
- -- Nothing to do for call to intrinsic subprogram
+ -- The instantiation of an external nested generic cannot cause an ABE
+ -- if the outer generic was already instantiated. Note that the instance
+ -- of the outer generic may lead to an ABE.
- elsif Is_Intrinsic_Subprogram (E) then
- return;
+ elsif In_External_Instance
+ (N => Inst,
+ Target_Decl => Gen_Attrs.Spec_Decl)
+ then
+ return True;
- -- Nothing to do if call is within a generic unit
+ -- The generic is a package. The instantiation cannot cause an ABE when
+ -- the package has no body.
- elsif Inside_A_Generic then
- return;
+ elsif Ekind (Gen_Attrs.Spec_Id) = E_Generic_Package
+ and then not Has_Body (Gen_Attrs.Spec_Decl)
+ then
+ return True;
+ end if;
- -- Nothing to do when the call appears within pragma Initial_Condition.
- -- The pragma is part of the elaboration statements of a package body
- -- and may only call external subprograms or subprograms whose body is
- -- already available.
+ return False;
+ end Is_Safe_Instantiation;
- elsif Within_Initial_Condition (N) then
- return;
+ ------------------
+ -- Is_Same_Unit --
+ ------------------
+
+ function Is_Same_Unit
+ (Unit_1 : Entity_Id;
+ Unit_2 : Entity_Id) return Boolean
+ is
+ function Is_Subunit (Unit_Id : Entity_Id) return Boolean;
+ pragma Inline (Is_Subunit);
+ -- Determine whether unit Unit_Id is a subunit
+
+ function Normalize_Unit (Unit_Id : Entity_Id) return Entity_Id;
+ -- Strip a potential subunit chain ending with unit Unit_Id and return
+ -- the corresponding spec.
+
+ ----------------
+ -- Is_Subunit --
+ ----------------
+
+ function Is_Subunit (Unit_Id : Entity_Id) return Boolean is
+ begin
+ return Nkind (Parent (Unit_Declaration_Node (Unit_Id))) = N_Subunit;
+ end Is_Subunit;
+
+ --------------------
+ -- Normalize_Unit --
+ --------------------
+
+ function Normalize_Unit (Unit_Id : Entity_Id) return Entity_Id is
+ Result : Entity_Id;
+
+ begin
+ -- Eliminate a potential chain of subunits to reach to proper body
+
+ Result := Unit_Id;
+ while Present (Result)
+ and then Result /= Standard_Standard
+ and then Is_Subunit (Result)
+ loop
+ Result := Scope (Result);
+ end loop;
+
+ -- Obtain the entity of the corresponding spec (if any)
+
+ return Unique_Entity (Result);
+ end Normalize_Unit;
+
+ -- Start of processing for Is_Same_Unit
+
+ begin
+ return Normalize_Unit (Unit_1) = Normalize_Unit (Unit_2);
+ end Is_Same_Unit;
+
+ -----------------
+ -- Is_Scenario --
+ -----------------
+
+ function Is_Scenario (N : Node_Id) return Boolean is
+ begin
+ case Nkind (N) is
+ when N_Assignment_Statement
+ | N_Attribute_Reference
+ | N_Call_Marker
+ | N_Entry_Call_Statement
+ | N_Expanded_Name
+ | N_Function_Call
+ | N_Function_Instantiation
+ | N_Identifier
+ | N_Package_Instantiation
+ | N_Procedure_Call_Statement
+ | N_Procedure_Instantiation
+ | N_Requeue_Statement
+ =>
+ return True;
+
+ when others =>
+ return False;
+ end case;
+ end Is_Scenario;
+
+ ------------------------------
+ -- Is_SPARK_Semantic_Target --
+ ------------------------------
+
+ function Is_SPARK_Semantic_Target (Id : Entity_Id) return Boolean is
+ begin
+ return
+ Is_Default_Initial_Condition_Proc (Id)
+ or else Is_Initial_Condition_Proc (Id);
+ end Is_SPARK_Semantic_Target;
+
+ ------------------------
+ -- Is_Suitable_Access --
+ ------------------------
+
+ function Is_Suitable_Access (N : Node_Id) return Boolean is
+ Nam : Name_Id;
+ Pref : Node_Id;
+ Subp_Id : Entity_Id;
+
+ begin
+ -- This scenario is relevant only when the static model is in effect
+ -- because it is graph-dependent and does not involve any run-time
+ -- checks. Allowing it in the dynamic model would create confusing
+ -- noise.
+
+ if not Static_Elaboration_Checks then
+ return False;
+
+ -- Nothing to do when switch -gnatd.U (ignore 'Access) is in effect
+
+ elsif Debug_Flag_Dot_UU then
+ return False;
+
+ -- Nothing to do when the scenario is not an attribute reference
+
+ elsif Nkind (N) /= N_Attribute_Reference then
+ return False;
+
+ -- Nothing to do for internally-generated attributes because they are
+ -- assumed to be ABE safe.
+
+ elsif not Comes_From_Source (N) then
+ return False;
end if;
- -- Delay this call if we are still delaying calls
+ Nam := Attribute_Name (N);
+ Pref := Prefix (N);
- if Delaying_Elab_Checks then
- Delay_Check.Append
- ((N => N,
- E => E,
- Orig_Ent => Orig_Ent,
- Curscop => Current_Scope,
- Outer_Scope => Outer_Scope,
- From_Elab_Code => From_Elab_Code,
- In_Task_Activation => In_Task_Activation,
- From_SPARK_Code => SPARK_Mode = On));
- return;
+ -- Sanitize the prefix of the attribute
- -- Otherwise, call phase 2 continuation right now
+ if not Is_Entity_Name (Pref) then
+ return False;
- else
- Check_Internal_Call_Continue (N, E, Outer_Scope, Orig_Ent);
+ elsif No (Entity (Pref)) then
+ return False;
end if;
- end Check_Internal_Call;
- ----------------------------------
- -- Check_Internal_Call_Continue --
- ----------------------------------
+ Subp_Id := Entity (Pref);
- procedure Check_Internal_Call_Continue
- (N : Node_Id;
- E : Entity_Id;
- Outer_Scope : Entity_Id;
- Orig_Ent : Entity_Id)
- is
- function Find_Elab_Reference (N : Node_Id) return Traverse_Result;
- -- Function applied to each node as we traverse the body. Checks for
- -- call or entity reference that needs checking, and if so checks it.
- -- Always returns OK, so entire tree is traversed, except that as
- -- described below subprogram bodies are skipped for now.
+ if not Is_Subprogram_Or_Entry (Subp_Id) then
+ return False;
+ end if;
- procedure Traverse is new Atree.Traverse_Proc (Find_Elab_Reference);
- -- Traverse procedure using above Find_Elab_Reference function
+ -- Traverse a possible chain of renamings to obtain the original entry
+ -- or subprogram which the prefix may rename.
- -------------------------
- -- Find_Elab_Reference --
- -------------------------
+ Subp_Id := Get_Renamed_Entity (Subp_Id);
+
+ -- To qualify, the attribute must meet the following prerequisites:
+
+ return
- function Find_Elab_Reference (N : Node_Id) return Traverse_Result is
- Actual : Node_Id;
+ -- The prefix must denote a source entry, operator, or subprogram
+ -- which is not imported.
+
+ Comes_From_Source (Subp_Id)
+ and then Is_Subprogram_Or_Entry (Subp_Id)
+ and then not Is_Bodiless_Subprogram (Subp_Id)
+
+ -- The attribute name must be one of the 'Access forms. Note that
+ -- 'Unchecked_Access cannot apply to a subprogram.
+
+ and then Nam_In (Nam, Name_Access, Name_Unrestricted_Access);
+ end Is_Suitable_Access;
+
+ ----------------------
+ -- Is_Suitable_Call --
+ ----------------------
+
+ function Is_Suitable_Call (N : Node_Id) return Boolean is
+ begin
+ -- Entry and subprogram calls are intentionally ignored because they
+ -- may undergo expansion depending on the compilation mode, previous
+ -- errors, generic context, etc. Call markers play the role of calls
+ -- and provide a uniform foundation for ABE processing.
+
+ return Nkind (N) = N_Call_Marker;
+ end Is_Suitable_Call;
+
+ -------------------------------
+ -- Is_Suitable_Instantiation --
+ -------------------------------
+
+ function Is_Suitable_Instantiation (N : Node_Id) return Boolean is
+ Orig_N : constant Node_Id := Original_Node (N);
+ -- Use the original node in case an instantiation library unit is
+ -- rewritten as a package or subprogram.
+
+ begin
+ -- To qualify, the instantiation must come from source
+
+ return
+ Comes_From_Source (Orig_N)
+ and then Nkind (Orig_N) in N_Generic_Instantiation;
+ end Is_Suitable_Instantiation;
+
+ --------------------------
+ -- Is_Suitable_Scenario --
+ --------------------------
+
+ function Is_Suitable_Scenario (N : Node_Id) return Boolean is
+ begin
+ return
+ Is_Suitable_Access (N)
+ or else Is_Suitable_Call (N)
+ or else Is_Suitable_Instantiation (N)
+ or else Is_Suitable_Variable_Assignment (N)
+ or else Is_Suitable_Variable_Read (N);
+ end Is_Suitable_Scenario;
+
+ -------------------------------------
+ -- Is_Suitable_Variable_Assignment --
+ -------------------------------------
+
+ function Is_Suitable_Variable_Assignment (N : Node_Id) return Boolean is
+ N_Unit : Node_Id;
+ N_Unit_Id : Entity_Id;
+ Nam : Node_Id;
+ Var_Decl : Node_Id;
+ Var_Id : Entity_Id;
+ Var_Unit : Node_Id;
+ Var_Unit_Id : Entity_Id;
+
+ begin
+ -- This scenario is relevant only when the static model is in effect
+ -- because it is graph-dependent and does not involve any run-time
+ -- checks. Allowing it in the dynamic model would create confusing
+ -- noise.
+
+ if not Static_Elaboration_Checks then
+ return False;
+
+ -- Nothing to do when the scenario is not an assignment
+
+ elsif Nkind (N) /= N_Assignment_Statement then
+ return False;
+
+ -- Nothing to do for internally-generated assignments because they are
+ -- assumed to be ABE safe.
+
+ elsif not Comes_From_Source (N) then
+ return False;
+
+ -- Assignments are ignored in GNAT mode on the assumption that they are
+ -- ABE-safe. This behaviour parallels that of the old ABE mechanism.
+
+ elsif GNAT_Mode then
+ return False;
+ end if;
+
+ Nam := Extract_Assignment_Name (N);
+
+ -- Sanitize the left hand side of the assignment
+
+ if not Is_Entity_Name (Nam) then
+ return False;
+
+ elsif No (Entity (Nam)) then
+ return False;
+ end if;
+
+ Var_Id := Entity (Nam);
+
+ -- Sanitize the variable
+
+ if Var_Id = Any_Id then
+ return False;
+
+ elsif Ekind (Var_Id) /= E_Variable then
+ return False;
+ end if;
+
+ Var_Decl := Declaration_Node (Var_Id);
+
+ if Nkind (Var_Decl) /= N_Object_Declaration then
+ return False;
+ end if;
+
+ N_Unit_Id := Find_Top_Unit (N);
+ N_Unit := Unit_Declaration_Node (N_Unit_Id);
+
+ Var_Unit_Id := Find_Top_Unit (Var_Decl);
+ Var_Unit := Unit_Declaration_Node (Var_Unit_Id);
+
+ -- To qualify, the assignment must meet the following prerequisites:
+
+ return
+ Comes_From_Source (Var_Id)
+
+ -- The variable must be declared in the spec of compilation unit U
+
+ and then Nkind (Var_Unit) = N_Package_Declaration
+
+ -- Performance note: parent traversal
+
+ and then Find_Enclosing_Level (Var_Decl) = Package_Spec
+
+ -- The assignment must occur in the body of compilation unit U
+
+ and then Nkind (N_Unit) = N_Package_Body
+ and then Present (Corresponding_Body (Var_Unit))
+ and then Corresponding_Body (Var_Unit) = N_Unit_Id;
+ end Is_Suitable_Variable_Assignment;
+
+ -------------------------------
+ -- Is_Suitable_Variable_Read --
+ -------------------------------
+
+ function Is_Suitable_Variable_Read (N : Node_Id) return Boolean is
+ function In_Pragma (Nod : Node_Id) return Boolean;
+ -- Determine whether arbitrary node Nod appears within a pragma
+
+ function Is_Variable_Read (Ref : Node_Id) return Boolean;
+ -- Determine whether variable reference Ref constitutes a read
+
+ ---------------
+ -- In_Pragma --
+ ---------------
+
+ function In_Pragma (Nod : Node_Id) return Boolean is
+ Par : Node_Id;
begin
- -- If user has specified that there are no entry calls in elaboration
- -- code, do not trace past an accept statement, because the rendez-
- -- vous will happen after elaboration.
+ Par := Nod;
+ while Present (Par) loop
+ if Nkind (Par) = N_Pragma then
+ return True;
- if Nkind_In (Original_Node (N), N_Accept_Statement,
- N_Selective_Accept)
- and then Restriction_Active (No_Entry_Calls_In_Elaboration_Code)
- then
- return Abandon;
+ -- Prevent the search from going too far
+
+ elsif Is_Body_Or_Package_Declaration (Par) then
+ exit;
+ end if;
- -- If we have a function call, check it
+ Par := Parent (Par);
+ end loop;
+
+ return False;
+ end In_Pragma;
+
+ ----------------------
+ -- Is_Variable_Read --
+ ----------------------
- elsif Nkind (N) = N_Function_Call then
- Check_Elab_Call (N, Outer_Scope);
- return OK;
+ function Is_Variable_Read (Ref : Node_Id) return Boolean is
+ function Is_Out_Actual (Call : Node_Id) return Boolean;
+ -- Determine whether the corresponding formal of actual Ref which
+ -- appears in call Call has mode OUT.
- -- If we have a procedure call, check the call, and also check
- -- arguments that are assignments (OUT or IN OUT mode formals).
+ -------------------
+ -- Is_Out_Actual --
+ -------------------
- elsif Nkind (N) = N_Procedure_Call_Statement then
- Check_Elab_Call (N, Outer_Scope, In_Init_Proc => Is_Init_Proc (E));
+ function Is_Out_Actual (Call : Node_Id) return Boolean is
+ Actual : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Formal : Entity_Id;
+ Target_Id : Entity_Id;
- Actual := First_Actual (N);
- while Present (Actual) loop
- if Known_To_Be_Assigned (Actual) then
- Check_Elab_Assign (Actual);
+ begin
+ Extract_Call_Attributes
+ (Call => Call,
+ Target_Id => Target_Id,
+ Attrs => Call_Attrs);
+
+ -- Inspect the actual and formal parameters, trying to find the
+ -- corresponding formal for Ref.
+
+ Actual := First_Actual (Call);
+ Formal := First_Formal (Target_Id);
+ while Present (Actual) and then Present (Formal) loop
+ if Actual = Ref then
+ return Ekind (Formal) = E_Out_Parameter;
end if;
Next_Actual (Actual);
+ Next_Formal (Formal);
end loop;
- return OK;
+ return False;
+ end Is_Out_Actual;
- -- If we have an access attribute for a subprogram, check it.
- -- Suppress this behavior under debug flag.
+ -- Local variables
- elsif not Debug_Flag_Dot_UU
- and then Nkind (N) = N_Attribute_Reference
- and then Nam_In (Attribute_Name (N), Name_Access,
- Name_Unrestricted_Access)
- and then Is_Entity_Name (Prefix (N))
- and then Is_Subprogram (Entity (Prefix (N)))
- then
- Check_Elab_Call (N, Outer_Scope);
- return OK;
+ Context : constant Node_Id := Parent (Ref);
- -- In SPARK mode, if we have an entity reference to a variable, then
- -- check it. For now we consider any reference.
+ -- Start of processing for Is_Variable_Read
- elsif SPARK_Mode = On
- and then Nkind (N) in N_Has_Entity
- and then Present (Entity (N))
- and then Ekind (Entity (N)) = E_Variable
- then
- Check_Elab_Call (N, Outer_Scope);
- return OK;
-
- -- If we have a generic instantiation, check it
+ begin
+ -- The majority of variable references are reads, and they can appear
+ -- in a great number of contexts. To determine whether a reference is
+ -- a read, it is more practical to find out whether it is a write.
- elsif Nkind (N) in N_Generic_Instantiation then
- Check_Elab_Instantiation (N, Outer_Scope);
- return OK;
+ -- A reference is a write when it appears immediately on the left-
+ -- hand side of an assignment.
- -- Skip subprogram bodies that come from source (wait for call to
- -- analyze these). The reason for the come from source test is to
- -- avoid catching task bodies.
+ if Nkind (Context) = N_Assignment_Statement
+ and then Name (Context) = Ref
+ then
+ return False;
- -- For task bodies, we should really avoid these too, waiting for the
- -- task activation, but that's too much trouble to catch for now, so
- -- we go in unconditionally. This is not so terrible, it means the
- -- error backtrace is not quite complete, and we are too eager to
- -- scan bodies of tasks that are unused, but this is hardly very
- -- significant.
+ -- A reference is a write when it acts as an actual in a subprogram
+ -- call and the corresponding formal has mode OUT.
- elsif Nkind (N) = N_Subprogram_Body
- and then Comes_From_Source (N)
+ elsif Nkind_In (Context, N_Function_Call,
+ N_Procedure_Call_Statement)
+ and then Is_Out_Actual (Context)
then
- return Skip;
+ return False;
+ end if;
- elsif Nkind (N) = N_Assignment_Statement
- and then Comes_From_Source (N)
- then
- Check_Elab_Assign (Name (N));
- return OK;
+ -- Any other reference is a read
- else
- return OK;
- end if;
- end Find_Elab_Reference;
+ return True;
+ end Is_Variable_Read;
- Inst_Case : constant Boolean := Is_Generic_Unit (E);
- Loc : constant Source_Ptr := Sloc (N);
+ -- Local variables
- Ebody : Entity_Id;
- Sbody : Node_Id;
+ Prag : Node_Id;
+ Var_Id : Entity_Id;
- -- Start of processing for Check_Internal_Call_Continue
+ -- Start of processing for Is_Suitable_Variable_Read
begin
- -- Save outer level call if at outer level
+ -- This scenario is relevant only when the static model is in effect
+ -- because it is graph-dependent and does not involve any run-time
+ -- checks. Allowing it in the dynamic model would create confusing
+ -- noise.
+
+ if not Static_Elaboration_Checks then
+ return False;
+
+ -- Attributes and operator sumbols are not considered to be suitable
+ -- references even though they are part of predicate Is_Entity_Name.
- if Elab_Call.Last = 0 then
- Outer_Level_Sloc := Loc;
+ elsif not Nkind_In (N, N_Expanded_Name, N_Identifier) then
+ return False;
+
+ -- Nothing to do for internally-generated references because they are
+ -- assumed to be ABE safe.
+
+ elsif not Comes_From_Source (N) then
+ return False;
end if;
- -- If the call is to a function that renames a literal, no check needed
+ -- Sanitize the reference
- if Ekind (E) = E_Enumeration_Literal then
- return;
+ Var_Id := Entity (N);
+
+ if No (Var_Id) then
+ return False;
+
+ elsif Var_Id = Any_Id then
+ return False;
+
+ elsif Ekind (Var_Id) /= E_Variable then
+ return False;
end if;
- -- Register the subprogram as examined within this particular context.
- -- This ensures that calls to the same subprogram but in different
- -- contexts receive warnings and checks of their own since the calls
- -- may be reached through different flow paths.
+ Prag := SPARK_Pragma (Var_Id);
- Elab_Visited.Append ((Subp_Id => E, Context => Parent (N)));
+ -- To qualify, the reference must meet the following prerequisites:
- Sbody := Unit_Declaration_Node (E);
+ return
+ Comes_From_Source (Var_Id)
- if not Nkind_In (Sbody, N_Subprogram_Body, N_Package_Body) then
- Ebody := Corresponding_Body (Sbody);
+ -- Both the variable and the reference must appear in SPARK_Mode On
+ -- regions because this scenario falls under the SPARK rules.
+
+ and then Present (Prag)
+ and then Get_SPARK_Mode_From_Annotation (Prag) = On
+ and then Is_SPARK_Mode_On_Node (N)
+
+ -- The reference must denote a variable read
+
+ and then Is_Variable_Read (N)
+
+ -- The reference must not be considered when it appears in a pragma.
+ -- If the pragma has run-time semantics, then the reference will be
+ -- reconsidered once the pragma is expanded.
+
+ -- Performance note: parent traversal
+
+ and then not In_Pragma (N);
+ end Is_Suitable_Variable_Read;
+
+ -------------------
+ -- Is_Task_Entry --
+ -------------------
+
+ function Is_Task_Entry (Id : Entity_Id) return Boolean is
+ begin
+ -- To qualify, the entity must denote an entry defined in a task type
+
+ return
+ Is_Entry (Id) and then Is_Task_Type (Non_Private_View (Scope (Id)));
+ end Is_Task_Entry;
+
+ ------------------------
+ -- Is_Up_Level_Target --
+ ------------------------
+
+ function Is_Up_Level_Target (Target_Decl : Node_Id) return Boolean is
+ Root : constant Node_Id := Root_Scenario;
+
+ begin
+ -- The root appears within the declaratons of a block statement, entry
+ -- body, subprogram body, or task body ignoring enclosing packages. The
+ -- root is always within the main unit. An up level target is a notion
+ -- applicable only to the static model because scenarios are reached by
+ -- means of graph traversal started from a fixed declarative or library
+ -- level.
+
+ -- Performance note: parent traversal
+
+ if Static_Elaboration_Checks
+ and then Find_Enclosing_Level (Root) = Declaration_Level
+ then
+ -- The target is within the main unit. It acts as an up level target
+ -- when it appears within a context which encloses the root.
+
+ -- package body Main_Unit is
+ -- function Func ...; -- target
+
+ -- procedure Proc is
+ -- X : ... := Func; -- root scenario
+
+ if In_Extended_Main_Code_Unit (Target_Decl) then
+
+ -- Performance note: parent traversal
+
+ return not In_Same_Context (Root, Target_Decl, Nested_OK => True);
+
+ -- Otherwise the target is external to the main unit which makes it
+ -- an up level target.
- if No (Ebody) then
- return;
else
- Sbody := Unit_Declaration_Node (Ebody);
+ return True;
end if;
end if;
- -- If the body appears after the outer level call or instantiation then
- -- we have an error case handled below.
+ return False;
+ end Is_Up_Level_Target;
- if Earlier_In_Extended_Unit (Outer_Level_Sloc, Sloc (Sbody))
- and then not In_Task_Activation
- then
- null;
+ -------------------------------
+ -- Kill_Elaboration_Scenario --
+ -------------------------------
- -- If we have the instantiation case we are done, since we now know that
- -- the body of the generic appeared earlier.
+ procedure Kill_Elaboration_Scenario (N : Node_Id) is
+ begin
+ -- Eliminate the scenario by suppressing the generation of conditional
+ -- ABE checks or guaranteed ABE failures. Note that other diagnostics
+ -- must be carried out ignoring the fact that the scenario is within
+ -- dead code.
- elsif Inst_Case then
- return;
+ if Is_Scenario (N) then
+ Set_Is_Elaboration_Checks_OK_Node (N, False);
+ end if;
+ end Kill_Elaboration_Scenario;
- -- Otherwise we have a call, so we trace through the called body to see
- -- if it has any problems.
+ ----------------------------------
+ -- Meet_Elaboration_Requirement --
+ ----------------------------------
- else
- pragma Assert (Nkind (Sbody) = N_Subprogram_Body);
-
- Elab_Call.Append ((Cloc => Loc, Ent => E));
-
- if Debug_Flag_LL then
- Write_Str ("Elab_Call.Last = ");
- Write_Int (Int (Elab_Call.Last));
- Write_Str (" Ent = ");
- Write_Name (Chars (E));
- Write_Str (" at ");
- Write_Location (Sloc (N));
- Write_Eol;
- end if;
+ procedure Meet_Elaboration_Requirement
+ (N : Node_Id;
+ Target_Id : Entity_Id;
+ Req_Nam : Name_Id)
+ is
+ Main_Id : constant Entity_Id := Cunit_Entity (Main_Unit);
+ Unit_Id : constant Entity_Id := Find_Top_Unit (Target_Id);
+
+ function Find_Preelaboration_Pragma
+ (Prag_Nam : Name_Id) return Node_Id;
+ pragma Inline (Find_Preelaboration_Pragma);
+ -- Traverse the visible declarations of unit Unit_Id and locate a source
+ -- preelaboration-related pragma with name Prag_Nam.
+
+ procedure Info_Requirement_Met (Prag : Node_Id);
+ pragma Inline (Info_Requirement_Met);
+ -- Output information concerning pragma Prag which meets requirement
+ -- Req_Nam.
+
+ procedure Info_Scenario;
+ pragma Inline (Info_Scenario);
+ -- Output information concerning scenario N
+
+ --------------------------------
+ -- Find_Preelaboration_Pragma --
+ --------------------------------
+
+ function Find_Preelaboration_Pragma
+ (Prag_Nam : Name_Id) return Node_Id
+ is
+ Spec : constant Node_Id := Parent (Unit_Id);
+ Decl : Node_Id;
- -- Now traverse declarations and statements of subprogram body. Note
- -- that we cannot simply Traverse (Sbody), since traverse does not
- -- normally visit subprogram bodies.
+ begin
+ -- A preelaboration-related pragma comes from source and appears at
+ -- the top of the visible declarations of a package.
- declare
- Decl : Node_Id;
- begin
- Decl := First (Declarations (Sbody));
+ if Nkind (Spec) = N_Package_Specification then
+ Decl := First (Visible_Declarations (Spec));
while Present (Decl) loop
- Traverse (Decl);
+ if Comes_From_Source (Decl) then
+ if Nkind (Decl) = N_Pragma
+ and then Pragma_Name (Decl) = Prag_Nam
+ then
+ return Decl;
+
+ -- Otherwise the construct terminates the region where the
+ -- preelabortion-related pragma may appear.
+
+ else
+ exit;
+ end if;
+ end if;
+
Next (Decl);
end loop;
- end;
+ end if;
- Traverse (Handled_Statement_Sequence (Sbody));
+ return Empty;
+ end Find_Preelaboration_Pragma;
- Elab_Call.Decrement_Last;
- return;
- end if;
+ --------------------------
+ -- Info_Requirement_Met --
+ --------------------------
+
+ procedure Info_Requirement_Met (Prag : Node_Id) is
+ begin
+ pragma Assert (Present (Prag));
- -- Here is the case of calling a subprogram where the body has not yet
- -- been encountered. A warning message is needed, except if this is the
- -- case of appearing within an aspect specification that results in
- -- a check call, we do not really have such a situation, so no warning
- -- is needed (e.g. the case of a precondition, where the call appears
- -- textually before the body, but in actual fact is moved to the
- -- appropriate subprogram body and so does not need a check).
+ Error_Msg_Name_1 := Req_Nam;
+ Error_Msg_Sloc := Sloc (Prag);
+ Error_Msg_NE
+ ("\\% requirement for unit & met by pragma #", N, Unit_Id);
+ end Info_Requirement_Met;
- declare
- P : Node_Id;
- O : Node_Id;
+ -------------------
+ -- Info_Scenario --
+ -------------------
+ procedure Info_Scenario is
begin
- P := Parent (N);
- loop
- -- Keep looking at parents if we are still in the subexpression
+ if Is_Suitable_Call (N) then
+ Info_Call
+ (Call => N,
+ Target_Id => Target_Id,
+ Info_Msg => False,
+ In_SPARK => True);
+
+ elsif Is_Suitable_Instantiation (N) then
+ Info_Instantiation
+ (Inst => N,
+ Gen_Id => Target_Id,
+ Info_Msg => False,
+ In_SPARK => True);
+
+ elsif Is_Suitable_Variable_Read (N) then
+ Info_Variable_Read
+ (Ref => N,
+ Var_Id => Target_Id,
+ Info_Msg => False,
+ In_SPARK => True);
+
+ -- No other scenario may impose a requirement on the context of the
+ -- main unit.
- if Nkind (P) in N_Subexpr then
- P := Parent (P);
+ else
+ pragma Assert (False);
+ null;
+ end if;
+ end Info_Scenario;
- -- Here P is the parent of the expression, check for special case
+ -- Local variables
- else
- O := Original_Node (P);
+ Elab_Attrs : Elaboration_Attributes;
+ Elab_Nam : Name_Id;
+ Req_Met : Boolean;
- -- Definitely not the special case if orig node is not a pragma
+ -- Start of processing for Meet_Elaboration_Requirement
- exit when Nkind (O) /= N_Pragma;
+ begin
+ pragma Assert (Nam_In (Req_Nam, Name_Elaborate, Name_Elaborate_All));
- -- Check we have an If statement or a null statement (happens
- -- when the If has been expanded to be True).
+ -- Assume that the requirement has not been met
- exit when not Nkind_In (P, N_If_Statement, N_Null_Statement);
+ Req_Met := False;
- -- Our special case will be indicated either by the pragma
- -- coming from an aspect ...
+ -- Elaboration requirements are verified only when the static model is
+ -- in effect because this diagnostic is graph-dependent.
- if Present (Corresponding_Aspect (O)) then
- return;
+ if not Static_Elaboration_Checks then
+ return;
- -- Or, in the case of an initial condition, specifically by a
- -- Check pragma specifying an Initial_Condition check.
+ -- If the target is within the main unit, either at the source level or
+ -- through an instantiation, then there is no real requirement to meet
+ -- because the main unit cannot force its own elaboration by means of an
+ -- Elaborate[_All] pragma. Treat this case as valid coverage.
- elsif Pragma_Name (O) = Name_Check
- and then
- Chars
- (Expression (First (Pragma_Argument_Associations (O)))) =
- Name_Initial_Condition
- then
- return;
+ elsif In_Extended_Main_Code_Unit (Target_Id) then
+ Req_Met := True;
- -- For anything else, we have an error
+ -- Otherwise the target resides in an external unit
- else
- exit;
- end if;
- end if;
- end loop;
- end;
+ -- The requirement is met when the target comes from an internal unit
+ -- because such a unit is elaborated prior to a non-internal unit.
- -- Not that special case, warning and dynamic check is required
+ elsif In_Internal_Unit (Unit_Id)
+ and then not In_Internal_Unit (Main_Id)
+ then
+ Req_Met := True;
- -- If we have nothing in the call stack, then this is at the outer
- -- level, and the ABE is bound to occur, unless it's a 'Access, or
- -- it's a renaming.
+ -- The requirement is met when the target comes from a preelaborated
+ -- unit. This portion must parallel predicate Is_Preelaborated_Unit.
- if Elab_Call.Last = 0 then
- Error_Msg_Warn := SPARK_Mode /= On;
+ elsif Is_Preelaborated_Unit (Unit_Id) then
+ Req_Met := True;
- declare
- Insert_Check : Boolean := True;
- -- This flag is set to True if an elaboration check should be
- -- inserted.
+ -- Output extra information when switch -gnatel (info messages on
+ -- implicit Elaborate[_All] pragmas.
- begin
- if In_Task_Activation then
- Insert_Check := False;
+ if Elab_Info_Messages then
+ if Is_Preelaborated (Unit_Id) then
+ Elab_Nam := Name_Preelaborate;
- elsif Inst_Case then
- Error_Msg_NE
- ("cannot instantiate& before body seen<<", N, Orig_Ent);
+ elsif Is_Pure (Unit_Id) then
+ Elab_Nam := Name_Pure;
- elsif Nkind (N) = N_Attribute_Reference then
- Error_Msg_NE
- ("Access attribute of & before body seen<<", N, Orig_Ent);
- Error_Msg_N ("\possible Program_Error on later references<", N);
- Insert_Check := False;
+ elsif Is_Remote_Call_Interface (Unit_Id) then
+ Elab_Nam := Name_Remote_Call_Interface;
- elsif Nkind (Unit_Declaration_Node (Orig_Ent)) /=
- N_Subprogram_Renaming_Declaration
- then
- Error_Msg_NE
- ("cannot call& before body seen<<", N, Orig_Ent);
+ elsif Is_Remote_Types (Unit_Id) then
+ Elab_Nam := Name_Remote_Types;
- elsif not Is_Generic_Actual_Subprogram (Orig_Ent) then
- Insert_Check := False;
+ else
+ pragma Assert (Is_Shared_Passive (Unit_Id));
+ Elab_Nam := Name_Shared_Passive;
end if;
- if Insert_Check then
- Error_Msg_N ("\Program_Error [<<", N);
- Insert_Elab_Check (N);
- end if;
- end;
+ Info_Requirement_Met (Find_Preelaboration_Pragma (Elab_Nam));
+ end if;
- -- Call is not at outer level
+ -- Determine whether the context of the main unit has a pragma strong
+ -- enough to meet the requirement.
else
- -- Do not generate elaboration checks in GNATprove mode because the
- -- elaboration counter and the check are both forms of expansion.
+ Elab_Attrs := Elaboration_Context.Get (Unit_Id);
- if GNATprove_Mode then
- null;
+ -- The pragma must be either Elaborate_All or be as strong as the
+ -- requirement.
- -- Generate an elaboration check
-
- elsif not Elaboration_Checks_Suppressed (E) then
- Set_Elaboration_Entity_Required (E);
-
- -- Create a declaration of the elaboration entity, and insert it
- -- prior to the subprogram or the generic unit, within the same
- -- scope. Since the subprogram may be overloaded, create a unique
- -- entity.
-
- if No (Elaboration_Entity (E)) then
- declare
- Loce : constant Source_Ptr := Sloc (E);
- Ent : constant Entity_Id :=
- Make_Defining_Identifier (Loc,
- New_External_Name (Chars (E), 'E', -1));
-
- begin
- Set_Elaboration_Entity (E, Ent);
- Push_Scope (Scope (E));
-
- Insert_Action (Declaration_Node (E),
- Make_Object_Declaration (Loce,
- Defining_Identifier => Ent,
- Object_Definition =>
- New_Occurrence_Of (Standard_Short_Integer, Loce),
- Expression =>
- Make_Integer_Literal (Loc, Uint_0)));
-
- -- Set elaboration flag at the point of the body
-
- Set_Elaboration_Flag (Sbody, E);
-
- -- Kill current value indication. This is necessary because
- -- the tests of this flag are inserted out of sequence and
- -- must not pick up bogus indications of the wrong constant
- -- value. Also, this is never a true constant, since one way
- -- or another, it gets reset.
-
- Set_Current_Value (Ent, Empty);
- Set_Last_Assignment (Ent, Empty);
- Set_Is_True_Constant (Ent, False);
- Pop_Scope;
- end;
- end if;
+ if Present (Elab_Attrs.Source_Pragma)
+ and then Nam_In (Pragma_Name (Elab_Attrs.Source_Pragma),
+ Name_Elaborate_All,
+ Req_Nam)
+ then
+ Req_Met := True;
- -- Generate:
- -- if Enn = 0 then
- -- raise Program_Error with "access before elaboration";
- -- end if;
+ -- Output extra information when switch -gnatel (info messages on
+ -- implicit Elaborate[_All] pragmas.
- Insert_Elab_Check (N,
- Make_Attribute_Reference (Loc,
- Attribute_Name => Name_Elaborated,
- Prefix => New_Occurrence_Of (E, Loc)));
+ if Elab_Info_Messages then
+ Info_Requirement_Met (Elab_Attrs.Source_Pragma);
+ end if;
end if;
+ end if;
- -- Generate the warning
+ -- The requirement was not met by the context of the main unit, issue an
+ -- error.
- if not Suppress_Elaboration_Warnings (E)
- and then not Elaboration_Checks_Suppressed (E)
+ if not Req_Met then
+ Info_Scenario;
- -- Suppress this warning if we have a function call that occurred
- -- within an assertion expression, since we can get false warnings
- -- in this case, due to the out of order handling in this case.
+ Error_Msg_Name_1 := Req_Nam;
+ Error_Msg_Node_2 := Unit_Id;
+ Error_Msg_NE ("\\unit & requires pragma % for &", N, Main_Id);
- and then
- (Nkind (Original_Node (N)) /= N_Function_Call
- or else not In_Assertion_Expression_Pragma (Original_Node (N)))
- then
- Error_Msg_Warn := SPARK_Mode /= On;
+ Output_Active_Scenarios (N);
+ end if;
+ end Meet_Elaboration_Requirement;
- if Inst_Case then
- Error_Msg_NE
- ("instantiation of& may occur before body is seen<l<",
- N, Orig_Ent);
- else
- -- A rather specific check. For Finalize/Adjust/Initialize, if
- -- the type has Warnings_Off set, suppress the warning.
+ ----------------------
+ -- Non_Private_View --
+ ----------------------
- if Nam_In (Chars (E), Name_Adjust,
- Name_Finalize,
- Name_Initialize)
- and then Present (First_Formal (E))
- then
- declare
- T : constant Entity_Id := Etype (First_Formal (E));
- begin
- if Is_Controlled (T) then
- if Warnings_Off (T)
- or else (Ekind (T) = E_Private_Type
- and then Warnings_Off (Full_View (T)))
- then
- goto Output;
- end if;
- end if;
- end;
- end if;
+ function Non_Private_View (Typ : Entity_Id) return Entity_Id is
+ Result : Entity_Id;
- -- Go ahead and give warning if not this special case
+ begin
+ Result := Typ;
- Error_Msg_NE
- ("call to& may occur before body is seen<l<", N, Orig_Ent);
- end if;
+ if Is_Private_Type (Result) and then Present (Full_View (Result)) then
+ Result := Full_View (Result);
+ end if;
- Error_Msg_N ("\Program_Error ]<l<", N);
+ return Result;
+ end Non_Private_View;
- -- There is no need to query the elaboration warning message flags
- -- because the main message is an error, not a warning, therefore
- -- all the clarification messages produces by Output_Calls must be
- -- emitted unconditionally.
+ -----------------------------
+ -- Output_Active_Scenarios --
+ -----------------------------
- <<Output>>
+ procedure Output_Active_Scenarios (Error_Nod : Node_Id) is
+ procedure Output_Access (N : Node_Id);
+ -- Emit a specific diagnostic message for 'Access denote by N
- Output_Calls (N, Check_Elab_Flag => False);
- end if;
- end if;
- end Check_Internal_Call_Continue;
+ procedure Output_Activation_Call (N : Node_Id);
+ -- Emit a specific diagnostic message for task activation N
- ---------------------------
- -- Check_Task_Activation --
- ---------------------------
+ procedure Output_Call (N : Node_Id; Target_Id : Entity_Id);
+ -- Emit a specific diagnostic message for call N which invokes target
+ -- Target_Id.
+
+ procedure Output_Header;
+ -- Emit a specific diagnostic message for the unit of the root scenario
- procedure Check_Task_Activation (N : Node_Id) is
- Loc : constant Source_Ptr := Sloc (N);
- Inter_Procs : constant Elist_Id := New_Elmt_List;
- Intra_Procs : constant Elist_Id := New_Elmt_List;
- Ent : Entity_Id;
- P : Entity_Id;
- Task_Scope : Entity_Id;
- Cunit_SC : Boolean := False;
- Decl : Node_Id;
- Elmt : Elmt_Id;
- Enclosing : Entity_Id;
-
- procedure Add_Task_Proc (Typ : Entity_Id);
- -- Add to Task_Procs the task body procedure(s) of task types in Typ.
- -- For record types, this procedure recurses over component types.
-
- procedure Collect_Tasks (Decls : List_Id);
- -- Collect the types of the tasks that are to be activated in the given
- -- list of declarations, in order to perform elaboration checks on the
- -- corresponding task procedures that are called implicitly here.
-
- function Outer_Unit (E : Entity_Id) return Entity_Id;
- -- find enclosing compilation unit of Entity, ignoring subunits, or
- -- else enclosing subprogram. If E is not a package, there is no need
- -- for inter-unit elaboration checks.
+ procedure Output_Instantiation (N : Node_Id);
+ -- Emit a specific diagnostic message for instantiation N
+
+ procedure Output_Variable_Assignment (N : Node_Id);
+ -- Emit a specific diagnostic message for assignment statement N
+
+ procedure Output_Variable_Read (N : Node_Id);
+ -- Emit a specific diagnostic message for reference N which reads a
+ -- variable.
-------------------
- -- Add_Task_Proc --
+ -- Output_Access --
-------------------
- procedure Add_Task_Proc (Typ : Entity_Id) is
- Comp : Entity_Id;
- Proc : Entity_Id := Empty;
+ procedure Output_Access (N : Node_Id) is
+ Subp_Id : constant Entity_Id := Entity (Prefix (N));
begin
- if Is_Task_Type (Typ) then
- Proc := Get_Task_Body_Procedure (Typ);
+ Error_Msg_Name_1 := Attribute_Name (N);
+ Error_Msg_Sloc := Sloc (N);
+ Error_Msg_NE ("\\ % of & taken #", Error_Nod, Subp_Id);
+ end Output_Access;
- elsif Is_Array_Type (Typ)
- and then Has_Task (Base_Type (Typ))
- then
- Add_Task_Proc (Component_Type (Typ));
+ ----------------------------
+ -- Output_Activation_Call --
+ ----------------------------
- elsif Is_Record_Type (Typ)
- and then Has_Task (Base_Type (Typ))
- then
- Comp := First_Component (Typ);
- while Present (Comp) loop
- Add_Task_Proc (Etype (Comp));
- Comp := Next_Component (Comp);
- end loop;
- end if;
+ procedure Output_Activation_Call (N : Node_Id) is
+ function Find_Activator (Call : Node_Id) return Entity_Id;
+ -- Find the nearest enclosing construct which houses call Call
- -- If the task type is another unit, we will perform the usual
- -- elaboration check on its enclosing unit. If the type is in the
- -- same unit, we can trace the task body as for an internal call,
- -- but we only need to examine other external calls, because at
- -- the point the task is activated, internal subprogram bodies
- -- will have been elaborated already. We keep separate lists for
- -- each kind of task.
+ --------------------
+ -- Find_Activator --
+ --------------------
- -- Skip this test if errors have occurred, since in this case
- -- we can get false indications.
+ function Find_Activator (Call : Node_Id) return Entity_Id is
+ Par : Node_Id;
- if Serious_Errors_Detected /= 0 then
- return;
- end if;
+ begin
+ -- Climb the parent chain looking for a package [body] or a
+ -- construct with a statement sequence.
- if Present (Proc) then
- if Outer_Unit (Scope (Proc)) = Enclosing then
+ Par := Parent (Call);
+ while Present (Par) loop
+ if Nkind_In (Par, N_Package_Body, N_Package_Declaration) then
+ return Defining_Entity (Par);
- if No (Corresponding_Body (Unit_Declaration_Node (Proc)))
- and then
- (not Is_Generic_Instance (Scope (Proc))
- or else Scope (Proc) = Scope (Defining_Identifier (Decl)))
- then
- Error_Msg_Warn := SPARK_Mode /= On;
- Error_Msg_N
- ("task will be activated before elaboration of its body<<",
- Decl);
- Error_Msg_N ("\Program_Error [<<", Decl);
-
- elsif Present
- (Corresponding_Body (Unit_Declaration_Node (Proc)))
- then
- Append_Elmt (Proc, Intra_Procs);
+ elsif Nkind (Par) = N_Handled_Sequence_Of_Statements then
+ return Defining_Entity (Parent (Par));
end if;
- else
- -- No need for multiple entries of the same type
+ Par := Parent (Par);
+ end loop;
- Elmt := First_Elmt (Inter_Procs);
- while Present (Elmt) loop
- if Node (Elmt) = Proc then
- return;
- end if;
+ return Empty;
+ end Find_Activator;
- Next_Elmt (Elmt);
- end loop;
+ -- Local variables
- Append_Elmt (Proc, Inter_Procs);
- end if;
+ Activator : constant Entity_Id := Find_Activator (N);
+
+ -- Start of processing for Output_Activation_Call
+
+ begin
+ pragma Assert (Present (Activator));
+
+ Error_Msg_NE ("\\ local tasks of & activated", Error_Nod, Activator);
+ end Output_Activation_Call;
+
+ -----------------
+ -- Output_Call --
+ -----------------
+
+ procedure Output_Call (N : Node_Id; Target_Id : Entity_Id) is
+ procedure Output_Accept_Alternative;
+ pragma Inline (Output_Accept_Alternative);
+ -- Emit a specific diagnostic message concerning an accept
+ -- alternative.
+
+ procedure Output_Call (Kind : String);
+ pragma Inline (Output_Call);
+ -- Emit a specific diagnostic message concerning a call of kind Kind
+
+ procedure Output_Type_Actions (Action : String);
+ pragma Inline (Output_Type_Actions);
+ -- Emit a specific diagnostic message concerning action Action of a
+ -- type.
+
+ procedure Output_Verification_Call
+ (Pred : String;
+ Id : Entity_Id;
+ Id_Kind : String);
+ pragma Inline (Output_Verification_Call);
+ -- Emit a specific diagnostic message concerning the verification of
+ -- predicate Pred applied to related entity Id with kind Id_Kind.
+
+ -------------------------------
+ -- Output_Accept_Alternative --
+ -------------------------------
+
+ procedure Output_Accept_Alternative is
+ Entry_Id : constant Entity_Id := Receiving_Entry (Target_Id);
+
+ begin
+ pragma Assert (Present (Entry_Id));
+
+ Error_Msg_NE ("\\ entry & selected #", Error_Nod, Entry_Id);
+ end Output_Accept_Alternative;
+
+ -----------------
+ -- Output_Call --
+ -----------------
+
+ procedure Output_Call (Kind : String) is
+ begin
+ Error_Msg_NE ("\\ " & Kind & " & called #", Error_Nod, Target_Id);
+ end Output_Call;
+
+ -------------------------
+ -- Output_Type_Actions --
+ -------------------------
+
+ procedure Output_Type_Actions (Action : String) is
+ Typ : constant Entity_Id := First_Formal_Type (Target_Id);
+
+ begin
+ pragma Assert (Present (Typ));
+
+ Error_Msg_NE
+ ("\\ " & Action & " actions for type & #", Error_Nod, Typ);
+ end Output_Type_Actions;
+
+ ------------------------------
+ -- Output_Verification_Call --
+ ------------------------------
+
+ procedure Output_Verification_Call
+ (Pred : String;
+ Id : Entity_Id;
+ Id_Kind : String)
+ is
+ begin
+ pragma Assert (Present (Id));
+
+ Error_Msg_NE
+ ("\\ " & Pred & " of " & Id_Kind & " & verified #",
+ Error_Nod, Id);
+ end Output_Verification_Call;
+
+ -- Start of processing for Output_Call
+
+ begin
+ Error_Msg_Sloc := Sloc (N);
+
+ -- Accept alternative
+
+ if Is_Accept_Alternative_Proc (Target_Id) then
+ Output_Accept_Alternative;
+
+ -- Adjustment
+
+ elsif Is_TSS (Target_Id, TSS_Deep_Adjust) then
+ Output_Type_Actions ("adjustment");
+
+ -- Default_Initial_Condition
+
+ elsif Is_Default_Initial_Condition_Proc (Target_Id) then
+ Output_Verification_Call
+ (Pred => "Default_Initial_Condition",
+ Id => First_Formal_Type (Target_Id),
+ Id_Kind => "type");
+
+ -- Entries
+
+ elsif Is_Protected_Entry (Target_Id) then
+ Output_Call ("entry");
+
+ -- Task entry calls are never processed because the entry being
+ -- invoked does not have a corresponding "body", it has a select. A
+ -- task entry call appears in the stack of active scenarios for the
+ -- sole purpose of checking No_Entry_Calls_In_Elaboration_Code and
+ -- nothing more.
+
+ elsif Is_Task_Entry (Target_Id) then
+ null;
+
+ -- Finalization
+
+ elsif Is_TSS (Target_Id, TSS_Deep_Finalize) then
+ Output_Type_Actions ("finalization");
+
+ -- Calls to _Finalizer procedures must not appear in the output
+ -- because this creates confusing noise.
+
+ elsif Is_Finalizer_Proc (Target_Id) then
+ null;
+
+ -- Initial_Condition
+
+ elsif Is_Initial_Condition_Proc (Target_Id) then
+ Output_Verification_Call
+ (Pred => "Initial_Condition",
+ Id => Find_Enclosing_Scope (N),
+ Id_Kind => "package");
+
+ -- Initialization
+
+ elsif Is_Init_Proc (Target_Id)
+ or else Is_TSS (Target_Id, TSS_Deep_Initialize)
+ then
+ Output_Type_Actions ("initialization");
+
+ -- Invariant
+
+ elsif Is_Invariant_Proc (Target_Id) then
+ Output_Verification_Call
+ (Pred => "invariants",
+ Id => First_Formal_Type (Target_Id),
+ Id_Kind => "type");
+
+ -- Partial invariant calls must not appear in the output because this
+ -- creates confusing noise. Note that a partial invariant is always
+ -- invoked by the "full" invariant which is already placed on the
+ -- stack.
+
+ elsif Is_Partial_Invariant_Proc (Target_Id) then
+ null;
+
+ -- _Postconditions
+
+ elsif Is_Postconditions_Proc (Target_Id) then
+ Output_Verification_Call
+ (Pred => "postconditions",
+ Id => Find_Enclosing_Scope (N),
+ Id_Kind => "subprogram");
+
+ -- Subprograms must come last because some of the previous cases fall
+ -- under this category.
+
+ elsif Ekind (Target_Id) = E_Function then
+ Output_Call ("function");
+
+ elsif Ekind (Target_Id) = E_Procedure then
+ Output_Call ("procedure");
+
+ else
+ pragma Assert (False);
+ null;
end if;
- end Add_Task_Proc;
+ end Output_Call;
-------------------
- -- Collect_Tasks --
+ -- Output_Header --
-------------------
- procedure Collect_Tasks (Decls : List_Id) is
+ procedure Output_Header is
+ Unit_Id : constant Entity_Id := Find_Top_Unit (Root_Scenario);
+
begin
- if Present (Decls) then
- Decl := First (Decls);
- while Present (Decl) loop
- if Nkind (Decl) = N_Object_Declaration
- and then Has_Task (Etype (Defining_Identifier (Decl)))
- then
- Add_Task_Proc (Etype (Defining_Identifier (Decl)));
- end if;
+ if Ekind (Unit_Id) = E_Package then
+ Error_Msg_NE ("\\ spec of unit & elaborated", Error_Nod, Unit_Id);
- Next (Decl);
- end loop;
+ elsif Ekind (Unit_Id) = E_Package_Body then
+ Error_Msg_NE ("\\ body of unit & elaborated", Error_Nod, Unit_Id);
+
+ else
+ Error_Msg_NE ("\\ in body of unit &", Error_Nod, Unit_Id);
end if;
- end Collect_Tasks;
+ end Output_Header;
- ----------------
- -- Outer_Unit --
- ----------------
+ --------------------------
+ -- Output_Instantiation --
+ --------------------------
+
+ procedure Output_Instantiation (N : Node_Id) is
+ procedure Output_Instantiation (Gen_Id : Entity_Id; Kind : String);
+ pragma Inline (Output_Instantiation);
+ -- Emit a specific diagnostic message concerning an instantiation of
+ -- generic unit Gen_Id. Kind denotes the kind of the instantiation.
+
+ --------------------------
+ -- Output_Instantiation --
+ --------------------------
+
+ procedure Output_Instantiation (Gen_Id : Entity_Id; Kind : String) is
+ begin
+ Error_Msg_NE
+ ("\\ " & Kind & " & instantiated as & #", Error_Nod, Gen_Id);
+ end Output_Instantiation;
+
+ -- Local variables
- function Outer_Unit (E : Entity_Id) return Entity_Id is
- Outer : Entity_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Inst_Id : Entity_Id;
+ Gen_Id : Entity_Id;
+
+ -- Start of processing for Output_Instantiation
begin
- Outer := E;
- while Present (Outer) loop
- if Elaboration_Checks_Suppressed (Outer) then
- Cunit_SC := True;
- end if;
+ Extract_Instantiation_Attributes
+ (Exp_Inst => N,
+ Inst => Inst,
+ Inst_Id => Inst_Id,
+ Gen_Id => Gen_Id,
+ Attrs => Inst_Attrs);
- exit when Is_Child_Unit (Outer)
- or else Scope (Outer) = Standard_Standard
- or else Ekind (Outer) /= E_Package;
- Outer := Scope (Outer);
- end loop;
+ Error_Msg_Node_2 := Inst_Id;
+ Error_Msg_Sloc := Sloc (Inst);
- return Outer;
- end Outer_Unit;
+ if Nkind (Inst) = N_Function_Instantiation then
+ Output_Instantiation (Gen_Id, "function");
- -- Start of processing for Check_Task_Activation
+ elsif Nkind (Inst) = N_Package_Instantiation then
+ Output_Instantiation (Gen_Id, "package");
- begin
- Enclosing := Outer_Unit (Current_Scope);
+ elsif Nkind (Inst) = N_Procedure_Instantiation then
+ Output_Instantiation (Gen_Id, "procedure");
- -- Find all tasks declared in the current unit
+ else
+ pragma Assert (False);
+ null;
+ end if;
+ end Output_Instantiation;
- if Nkind (N) = N_Package_Body then
- P := Unit_Declaration_Node (Corresponding_Spec (N));
+ --------------------------------
+ -- Output_Variable_Assignment --
+ --------------------------------
- Collect_Tasks (Declarations (N));
- Collect_Tasks (Visible_Declarations (Specification (P)));
- Collect_Tasks (Private_Declarations (Specification (P)));
+ procedure Output_Variable_Assignment (N : Node_Id) is
+ Var_Id : constant Entity_Id := Entity (Extract_Assignment_Name (N));
- elsif Nkind (N) = N_Package_Declaration then
- Collect_Tasks (Visible_Declarations (Specification (N)));
- Collect_Tasks (Private_Declarations (Specification (N)));
+ begin
+ Error_Msg_Sloc := Sloc (N);
+ Error_Msg_NE ("\\ variable & assigned #", Error_Nod, Var_Id);
+ end Output_Variable_Assignment;
- else
- Collect_Tasks (Declarations (N));
- end if;
+ --------------------------
+ -- Output_Variable_Read --
+ --------------------------
- -- We only perform detailed checks in all tasks that are library level
- -- entities. If the master is a subprogram or task, activation will
- -- depend on the activation of the master itself.
+ procedure Output_Variable_Read (N : Node_Id) is
+ Dummy : Variable_Attributes;
+ Var_Id : Entity_Id;
- -- Should dynamic checks be added in the more general case???
+ begin
+ Extract_Variable_Reference_Attributes
+ (Ref => N,
+ Var_Id => Var_Id,
+ Attrs => Dummy);
+
+ Error_Msg_Sloc := Sloc (N);
+ Error_Msg_NE ("\\ variable & read #", Error_Nod, Var_Id);
+ end Output_Variable_Read;
+
+ -- Local variables
+
+ package Stack renames Scenario_Stack;
+
+ Dummy : Call_Attributes;
+ N : Node_Id;
+ Posted : Boolean;
+ Target_Id : Entity_Id;
+
+ -- Start of processing for Output_Active_Scenarios
+
+ begin
+ -- Active scenarios are emitted only when the static model is in effect
+ -- because there is an inherent order by which all these scenarios were
+ -- reached from the declaration or library level.
- if Ekind (Enclosing) /= E_Package then
+ if not Static_Elaboration_Checks then
return;
end if;
- -- For task types defined in other units, we want the unit containing
- -- the task body to be elaborated before the current one.
+ Posted := False;
- Elmt := First_Elmt (Inter_Procs);
- while Present (Elmt) loop
- Ent := Node (Elmt);
- Task_Scope := Outer_Unit (Scope (Ent));
+ for Index in Stack.First .. Stack.Last loop
+ N := Stack.Table (Index);
- if not Is_Compilation_Unit (Task_Scope) then
- null;
+ if not Posted then
+ Posted := True;
+ Output_Header;
+ end if;
- elsif Suppress_Elaboration_Warnings (Task_Scope)
- or else Elaboration_Checks_Suppressed (Task_Scope)
- then
- null;
+ -- 'Access
- elsif Dynamic_Elaboration_Checks then
- if not Elaboration_Checks_Suppressed (Ent)
- and then not Cunit_SC
- and then not Restriction_Active
- (No_Entry_Calls_In_Elaboration_Code)
- then
- -- Runtime elaboration check required. Generate check of the
- -- elaboration counter for the unit containing the entity.
-
- Insert_Elab_Check (N,
- Make_Attribute_Reference (Loc,
- Prefix =>
- New_Occurrence_Of (Spec_Entity (Task_Scope), Loc),
- Attribute_Name => Name_Elaborated));
- end if;
+ if Nkind (N) = N_Attribute_Reference then
+ Output_Access (N);
- else
- -- Force the binder to elaborate other unit first
+ -- Calls
- if Elab_Info_Messages
- and then not Suppress_Elaboration_Warnings (Ent)
- and then not Elaboration_Checks_Suppressed (Ent)
- and then not Suppress_Elaboration_Warnings (Task_Scope)
- and then not Elaboration_Checks_Suppressed (Task_Scope)
- then
- Error_Msg_Node_2 := Task_Scope;
- Error_Msg_NE
- ("info: activation of an instance of task type & requires "
- & "pragma Elaborate_All on &?$?", N, Ent);
+ elsif Is_Suitable_Call (N) then
+ Extract_Call_Attributes
+ (Call => N,
+ Target_Id => Target_Id,
+ Attrs => Dummy);
+
+ if Is_Activation_Proc (Target_Id) then
+ Output_Activation_Call (N);
+ else
+ Output_Call (N, Target_Id);
end if;
- Activate_Elaborate_All_Desirable (N, Task_Scope);
- Set_Suppress_Elaboration_Warnings (Task_Scope);
- end if;
+ -- Instantiations
+
+ elsif Is_Suitable_Instantiation (N) then
+ Output_Instantiation (N);
+
+ -- Variable assignments
+
+ elsif Nkind (N) = N_Assignment_Statement then
+ Output_Variable_Assignment (N);
- Next_Elmt (Elmt);
+ -- Variable read
+
+ elsif Is_Suitable_Variable_Read (N) then
+ Output_Variable_Read (N);
+
+ else
+ pragma Assert (False);
+ null;
+ end if;
end loop;
+ end Output_Active_Scenarios;
- -- For tasks declared in the current unit, trace other calls within the
- -- task procedure bodies, which are available.
+ -------------------------
+ -- Pop_Active_Scenario --
+ -------------------------
- if not Debug_Flag_Dot_Y then
- In_Task_Activation := True;
+ procedure Pop_Active_Scenario (N : Node_Id) is
+ Top : Node_Id renames Scenario_Stack.Table (Scenario_Stack.Last);
- Elmt := First_Elmt (Intra_Procs);
- while Present (Elmt) loop
- Ent := Node (Elmt);
- Check_Internal_Call_Continue (N, Ent, Enclosing, Ent);
- Next_Elmt (Elmt);
- end loop;
+ begin
+ pragma Assert (Top = N);
+ Scenario_Stack.Decrement_Last;
+ end Pop_Active_Scenario;
- In_Task_Activation := False;
- end if;
- end Check_Task_Activation;
+ --------------------
+ -- Process_Access --
+ --------------------
- -------------------------------
- -- Is_Call_Of_Generic_Formal --
- -------------------------------
+ procedure Process_Access (Attr : Node_Id; In_Task_Body : Boolean) is
+ function Build_Access_Marker (Target_Id : Entity_Id) return Node_Id;
+ pragma Inline (Build_Access_Marker);
+ -- Create a suitable call marker which invokes target Target_Id
+
+ -------------------------
+ -- Build_Access_Marker --
+ -------------------------
+
+ function Build_Access_Marker (Target_Id : Entity_Id) return Node_Id is
+ Marker : Node_Id;
+
+ begin
+ Marker := Make_Call_Marker (Sloc (Attr));
+
+ -- Inherit relevant attributes from the attribute
+
+ -- Performance note: parent traversal
+
+ Set_Target (Marker, Target_Id);
+ Set_Is_Declaration_Level_Node
+ (Marker, Find_Enclosing_Level (Attr) = Declaration_Level);
+ Set_Is_Dispatching_Call
+ (Marker, False);
+ Set_Is_Elaboration_Checks_OK_Node
+ (Marker, Is_Elaboration_Checks_OK_Node (Attr));
+ Set_Is_Source_Call
+ (Marker, Comes_From_Source (Attr));
+ Set_Is_SPARK_Mode_On_Node
+ (Marker, Is_SPARK_Mode_On_Node (Attr));
+
+ -- Partially insert the call marker into the tree by setting its
+ -- parent pointer.
+
+ Set_Parent (Marker, Attr);
+
+ return Marker;
+ end Build_Access_Marker;
+
+ -- Local variables
+
+ Root : constant Node_Id := Root_Scenario;
+ Target_Id : constant Entity_Id := Entity (Prefix (Attr));
+
+ Target_Attrs : Target_Attributes;
+
+ -- Start of processing for Process_Access
- function Is_Call_Of_Generic_Formal (N : Node_Id) return Boolean is
begin
- return Nkind_In (N, N_Function_Call, N_Procedure_Call_Statement)
+ -- Output relevant information when switch -gnatel (info messages on
+ -- implicit Elaborate[_All] pragmas) is in effect.
+
+ if Elab_Info_Messages then
+ Error_Msg_NE
+ ("info: access to & during elaboration", Attr, Target_Id);
+ end if;
+
+ Extract_Target_Attributes
+ (Target_Id => Target_Id,
+ Attrs => Target_Attrs);
+
+ -- Both the attribute and the corresponding body are in the same unit.
+ -- The corresponding body must appear prior to the root scenario which
+ -- started the recursive search. If this is not the case, then there is
+ -- a potential ABE if the access value is used to call the subprogram.
+ -- Emit a warning only when switch -gnatw.f (warnings on suspucious
+ -- 'Access) is in effect.
+
+ if Warn_On_Elab_Access
+ and then Present (Target_Attrs.Body_Decl)
+ and then In_Extended_Main_Code_Unit (Target_Attrs.Body_Decl)
+ and then Earlier_In_Extended_Unit (Root, Target_Attrs.Body_Decl)
+ then
+ Error_Msg_Name_1 := Attribute_Name (Attr);
+ Error_Msg_NE ("??% attribute of & before body seen", Attr, Target_Id);
+ Error_Msg_N ("\possible Program_Error on later references", Attr);
- -- Always return False if debug flag -gnatd.G is set
+ Output_Active_Scenarios (Attr);
+ end if;
- and then not Debug_Flag_Dot_GG
+ -- Treat the attribute as an immediate invocation of the target when
+ -- switch -gnatd.o (conservative elaboration order for indirect calls)
+ -- is in effect. Note that the prior elaboration of the unit containing
+ -- the target is ensured processing the corresponding call marker.
- -- For now, we detect this by looking for the strange identifier
- -- node, whose Chars reflect the name of the generic formal, but
- -- the Chars of the Entity references the generic actual.
+ if Debug_Flag_Dot_O then
+ Process_Scenario
+ (N => Build_Access_Marker (Target_Id),
+ In_Task_Body => In_Task_Body);
- and then Nkind (Name (N)) = N_Identifier
- and then Chars (Name (N)) /= Chars (Entity (Name (N)));
- end Is_Call_Of_Generic_Formal;
+ -- Otherwise ensure that the unit with the corresponding body is
+ -- elaborated prior to the main unit.
- --------------------------------
- -- Set_Elaboration_Constraint --
- --------------------------------
+ else
+ Ensure_Prior_Elaboration
+ (N => Attr,
+ Unit_Id => Target_Attrs.Unit_Id,
+ In_Task_Body => In_Task_Body);
+ end if;
+ end Process_Access;
+
+ -----------------------------
+ -- Process_Activation_Call --
+ -----------------------------
- procedure Set_Elaboration_Constraint
- (Call : Node_Id;
- Subp : Entity_Id;
- Scop : Entity_Id)
+ procedure Process_Activation_Call
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ In_Task_Body : Boolean)
is
- Elab_Unit : Entity_Id;
+ procedure Process_Task_Object (Obj_Id : Entity_Id; Typ : Entity_Id);
+ -- Perform ABE checks and diagnostics for object Obj_Id with type Typ.
+ -- Typ may be a task type or a composite type with at least one task
+ -- component.
- -- Check whether this is a call to an Initialize subprogram for a
- -- controlled type. Note that Call can also be a 'Access attribute
- -- reference, which now generates an elaboration check.
+ procedure Process_Task_Objects (List : List_Id);
+ -- Perform ABE checks and diagnostics for all task objects found in
+ -- the list List.
- Init_Call : constant Boolean :=
- Nkind (Call) = N_Procedure_Call_Statement
- and then Chars (Subp) = Name_Initialize
- and then Comes_From_Source (Subp)
- and then Present (Parameter_Associations (Call))
- and then Is_Controlled (Etype (First_Actual (Call)));
+ -------------------------
+ -- Process_Task_Object --
+ -------------------------
+
+ procedure Process_Task_Object (Obj_Id : Entity_Id; Typ : Entity_Id) is
+ Base_Typ : constant Entity_Id := Base_Type (Typ);
+
+ Comp_Id : Entity_Id;
+ Task_Attrs : Task_Attributes;
+
+ begin
+ if Is_Task_Type (Typ) then
+ Extract_Task_Attributes
+ (Typ => Base_Typ,
+ Attrs => Task_Attrs);
+
+ Process_Single_Activation
+ (Call => Call,
+ Call_Attrs => Call_Attrs,
+ Obj_Id => Obj_Id,
+ Task_Attrs => Task_Attrs,
+ In_Task_Body => In_Task_Body);
+
+ -- Examine the component type when the object is an array
+
+ elsif Is_Array_Type (Typ) and then Has_Task (Base_Typ) then
+ Process_Task_Object (Obj_Id, Component_Type (Typ));
+
+ -- Examine individual component types when the object is a record
+
+ elsif Is_Record_Type (Typ) and then Has_Task (Base_Typ) then
+ Comp_Id := First_Component (Typ);
+ while Present (Comp_Id) loop
+ Process_Task_Object (Obj_Id, Etype (Comp_Id));
+ Next_Component (Comp_Id);
+ end loop;
+ end if;
+ end Process_Task_Object;
+
+ --------------------------
+ -- Process_Task_Objects --
+ --------------------------
+
+ procedure Process_Task_Objects (List : List_Id) is
+ Item : Node_Id;
+ Item_Id : Entity_Id;
+ Item_Typ : Entity_Id;
+
+ begin
+ -- Examine the contents of the list looking for an object declaration
+ -- of a task type or one that contains a task within.
+
+ Item := First (List);
+ while Present (Item) loop
+ if Nkind (Item) = N_Object_Declaration then
+ Item_Id := Defining_Entity (Item);
+ Item_Typ := Etype (Item_Id);
+
+ if Has_Task (Item_Typ) then
+ Process_Task_Object (Item_Id, Item_Typ);
+ end if;
+ end if;
+
+ Next (Item);
+ end loop;
+ end Process_Task_Objects;
+
+ -- Local variables
+
+ Context : Node_Id;
+ Spec : Node_Id;
+
+ -- Start of processing for Process_Activation_Call
begin
- -- If the unit is mentioned in a with_clause of the current unit, it is
- -- visible, and we can set the elaboration flag.
+ -- Nothing to do when the activation is a guaranteed ABE
- if Is_Immediately_Visible (Scop)
- or else (Is_Child_Unit (Scop) and then Is_Visible_Lib_Unit (Scop))
- then
- Activate_Elaborate_All_Desirable (Call, Scop);
- Set_Suppress_Elaboration_Warnings (Scop);
+ if Is_Known_Guaranteed_ABE (Call) then
return;
end if;
- -- If this is not an initialization call or a call using object notation
- -- we know that the unit of the called entity is in the context, and we
- -- can set the flag as well. The unit need not be visible if the call
- -- occurs within an instantiation.
+ -- Find the proper context of the activation call where all task objects
+ -- being activated are declared. This is usually the immediate parent of
+ -- the call.
+
+ Context := Parent (Call);
+
+ -- In the case of package bodies, the activation call is in the handled
+ -- sequence of statements, but the task objects are in the declaration
+ -- list of the body.
- if Is_Init_Proc (Subp)
- or else Init_Call
- or else Nkind (Original_Node (Call)) = N_Selected_Component
+ if Nkind (Context) = N_Handled_Sequence_Of_Statements
+ and then Nkind (Parent (Context)) = N_Package_Body
then
- null; -- detailed processing follows.
+ Context := Parent (Context);
+ end if;
+
+ -- Process all task objects defined in both the spec and body when the
+ -- activation call precedes the "begin" of a package body.
+
+ if Nkind (Context) = N_Package_Body then
+ Spec :=
+ Specification
+ (Unit_Declaration_Node (Corresponding_Spec (Context)));
+
+ Process_Task_Objects (Visible_Declarations (Spec));
+ Process_Task_Objects (Private_Declarations (Spec));
+ Process_Task_Objects (Declarations (Context));
+
+ -- Process all task objects defined in the spec when the activation call
+ -- appears at the end of a package spec.
+
+ elsif Nkind (Context) = N_Package_Specification then
+ Process_Task_Objects (Visible_Declarations (Context));
+ Process_Task_Objects (Private_Declarations (Context));
+
+ -- Otherwise the context of the activation is some construct with a
+ -- declarative part. Note that the corresponding record type of a task
+ -- type is controlled. Because of this, the finalization machinery must
+ -- relocate the task object to the handled statements of the construct
+ -- to perform proper finalization in case of an exception. Examine the
+ -- statements of the construct rather than the declarations.
else
- Activate_Elaborate_All_Desirable (Call, Scop);
- Set_Suppress_Elaboration_Warnings (Scop);
- return;
+ pragma Assert (Nkind (Context) = N_Handled_Sequence_Of_Statements);
+
+ Process_Task_Objects (Statements (Context));
end if;
+ end Process_Activation_Call;
+
+ ---------------------------------------------
+ -- Process_Activation_Conditional_ABE_Impl --
+ ---------------------------------------------
+
+ procedure Process_Activation_Conditional_ABE_Impl
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Obj_Id : Entity_Id;
+ Task_Attrs : Task_Attributes;
+ In_Task_Body : Boolean)
+ is
+ Check_OK : constant Boolean :=
+ not Is_Ignored_Ghost_Entity (Obj_Id)
+ and then not Task_Attrs.Ghost_Mode_Ignore
+ and then Is_Elaboration_Checks_OK_Id (Obj_Id)
+ and then Task_Attrs.Elab_Checks_OK;
+ -- A run-time ABE check may be installed only when the object and the
+ -- task type have active elaboration checks, and both are not ignored
+ -- Ghost constructs.
- -- If the unit is not in the context, there must be an intermediate unit
- -- that is, on which we need to place to elaboration flag. This happens
- -- with init proc calls.
+ Root : constant Node_Id := Root_Scenario;
- if Is_Init_Proc (Subp) or else Init_Call then
+ begin
+ -- Output relevant information when switch -gnatel (info messages on
+ -- implicit Elaborate[_All] pragmas) is in effect.
- -- The initialization call is on an object whose type is not declared
- -- in the same scope as the subprogram. The type of the object must
- -- be a subtype of the type of operation. This object is the first
- -- actual in the call.
+ if Elab_Info_Messages then
+ Error_Msg_NE
+ ("info: activation of & during elaboration", Call, Obj_Id);
+ end if;
- declare
- Typ : constant Entity_Id :=
- Etype (First (Parameter_Associations (Call)));
- begin
- Elab_Unit := Scope (Typ);
- while (Present (Elab_Unit))
- and then not Is_Compilation_Unit (Elab_Unit)
- loop
- Elab_Unit := Scope (Elab_Unit);
- end loop;
- end;
+ -- Nothing to do when the activation is a guaranteed ABE
- -- If original node uses selected component notation, the prefix is
- -- visible and determines the scope that must be elaborated. After
- -- rewriting, the prefix is the first actual in the call.
+ if Is_Known_Guaranteed_ABE (Call) then
+ return;
- elsif Nkind (Original_Node (Call)) = N_Selected_Component then
- Elab_Unit := Scope (Etype (First (Parameter_Associations (Call))));
+ -- Nothing to do when the root scenario appears at the declaration
+ -- level and the task is in the same unit, but outside this context.
- -- Not one of special cases above
+ -- task type Task_Typ; -- task declaration
- else
- -- Using previously computed scope. If the elaboration check is
- -- done after analysis, the scope is not visible any longer, but
- -- must still be in the context.
+ -- procedure Proc is
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- declare
+ -- T : Task_Typ;
+ -- begin
+ -- <activation call> -- activation site
+ -- end;
+ -- ...
+ -- end A;
+
+ -- X : ... := A; -- root scenario
+ -- ...
+
+ -- task body Task_Typ is
+ -- ...
+ -- end Task_Typ;
+
+ -- In the example above, the context of X is the declarative list of
+ -- Proc. The "elaboration" of X may reach the activation of T whose body
+ -- is defined outside of X's context. The task body is relevant only
+ -- when Proc is invoked, but this happens only in "normal" elaboration,
+ -- therefore the task body must not be considered if this is not the
+ -- case.
+
+ -- Performance note: parent traversal
+
+ elsif Is_Up_Level_Target (Task_Attrs.Task_Decl) then
+ return;
+
+ -- Nothing to do when the activation is ABE-safe
+
+ -- generic
+ -- package Gen is
+ -- task type Task_Typ;
+ -- end Gen;
+
+ -- package body Gen is
+ -- task body Task_Typ is
+ -- begin
+ -- ...
+ -- end Task_Typ;
+ -- end Gen;
+
+ -- with Gen;
+ -- procedure Main is
+ -- package Nested is
+ -- ...
+ -- end Nested;
+
+ -- package body Nested is
+ -- package Inst is new Gen;
+ -- T : Inst.Task_Typ;
+ -- [begin]
+ -- <activation call> -- safe activation
+ -- end Nested;
+ -- ...
+
+ elsif Is_Safe_Activation (Call, Task_Attrs.Task_Decl) then
+
+ -- Note that the task body must still be examined for any nested
+ -- scenarios.
+
+ null;
+
+ -- The activation call and the task body are both in the main unit
+
+ elsif Present (Task_Attrs.Body_Decl)
+ and then In_Extended_Main_Code_Unit (Task_Attrs.Body_Decl)
+ then
+ -- If the root scenario appears prior to the task body, then this is
+ -- a possible ABE with respect to the root scenario.
+
+ -- task type Task_Typ;
+
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- declare
+ -- package Pack is
+ -- ...
+ -- end Pack;
+
+ -- package body Pack is
+ -- T : Task_Typ;
+ -- [begin]
+ -- <activation call> -- activation of T
+ -- end Pack;
+ -- ...
+ -- end A;
+
+ -- X : ... := A; -- root scenario
+
+ -- task body Task_Typ is -- task body
+ -- ...
+ -- end Task_Typ;
+
+ -- Y : ... := A; -- root scenario
+
+ -- IMPORTANT: The activation of T is a possible ABE for X, but
+ -- not for Y. Intalling an unconditional ABE raise prior to the
+ -- activation call would be wrong as it will fail for Y as well
+ -- but in Y's case the activation of T is never an ABE.
+
+ if Earlier_In_Extended_Unit (Root, Task_Attrs.Body_Decl) then
- Elab_Unit := Scop;
+ -- ABE diagnostics are emitted only in the static model because
+ -- there is a well-defined order to visiting scenarios. Without
+ -- this order diagnostics appear jumbled and result in unwanted
+ -- noise.
+
+ if Static_Elaboration_Checks then
+ Error_Msg_Sloc := Sloc (Call);
+ Error_Msg_N
+ ("??task & will be activated # before elaboration of its "
+ & "body", Obj_Id);
+ Error_Msg_N
+ ("\Program_Error may be raised at run time", Obj_Id);
+
+ Output_Active_Scenarios (Obj_Id);
+ end if;
+
+ -- Install a conditional run-time ABE check to verify that the
+ -- task body has been elaborated prior to the activation call.
+
+ if Check_OK then
+ Install_ABE_Check
+ (N => Call,
+ Ins_Nod => Call,
+ Target_Id => Task_Attrs.Spec_Id,
+ Target_Decl => Task_Attrs.Task_Decl,
+ Target_Body => Task_Attrs.Body_Decl);
+ end if;
+ end if;
+
+ -- Otherwise the task body is not available in this compilation or it
+ -- resides in an external unit. Install a run-time ABE check to verify
+ -- that the task body has been elaborated prior to the activation call
+ -- when the dynamic model is in effect.
+
+ elsif Dynamic_Elaboration_Checks and then Check_OK then
+ Install_ABE_Check
+ (N => Call,
+ Ins_Nod => Call,
+ Id => Task_Attrs.Unit_Id);
end if;
- Activate_Elaborate_All_Desirable (Call, Elab_Unit);
- Set_Suppress_Elaboration_Warnings (Elab_Unit);
- end Set_Elaboration_Constraint;
+ -- Both the activation call and task type are subject to SPARK_Mode
+ -- On, this triggers the SPARK rules for task activation. Compared to
+ -- calls and instantiations, task activation in SPARK does not require
+ -- the presence of Elaborate[_All] pragmas in case the task type is
+ -- defined outside the main unit. This is because SPARK utilizes a
+ -- special policy which activates all tasks after the main unit has
+ -- finished its elaboration.
- ------------------------
- -- Get_Referenced_Ent --
- ------------------------
+ if Call_Attrs.SPARK_Mode_On and Task_Attrs.SPARK_Mode_On then
+ null;
- function Get_Referenced_Ent (N : Node_Id) return Entity_Id is
- Nam : Node_Id;
+ -- Otherwise the Ada rules are in effect. Ensure that the unit with the
+ -- task body is elaborated prior to the main unit.
+
+ else
+ Ensure_Prior_Elaboration
+ (N => Call,
+ Unit_Id => Task_Attrs.Unit_Id,
+ In_Task_Body => In_Task_Body);
+ end if;
+
+ Traverse_Body (Task_Attrs.Body_Decl, In_Task_Body => True);
+ end Process_Activation_Conditional_ABE_Impl;
+
+ procedure Process_Activation_Conditional_ABE is
+ new Process_Activation_Call (Process_Activation_Conditional_ABE_Impl);
+
+ --------------------------------------------
+ -- Process_Activation_Guaranteed_ABE_Impl --
+ --------------------------------------------
+
+ procedure Process_Activation_Guaranteed_ABE_Impl
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Obj_Id : Entity_Id;
+ Task_Attrs : Task_Attributes;
+ In_Task_Body : Boolean)
+ is
+ pragma Unreferenced (Call_Attrs);
+ pragma Unreferenced (In_Task_Body);
+
+ Check_OK : constant Boolean :=
+ not Is_Ignored_Ghost_Entity (Obj_Id)
+ and then not Task_Attrs.Ghost_Mode_Ignore
+ and then Is_Elaboration_Checks_OK_Id (Obj_Id)
+ and then Task_Attrs.Elab_Checks_OK;
+ -- A run-time ABE check may be installed only when the object and the
+ -- task type have active elaboration checks, and both are not ignored
+ -- Ghost constructs.
begin
- if Nkind (N) in N_Has_Entity
- and then Present (Entity (N))
- and then Ekind (Entity (N)) = E_Variable
+ -- Nothing to do when the root scenario appears at the declaration
+ -- level and the task is in the same unit, but outside this context.
+
+ -- task type Task_Typ; -- task declaration
+
+ -- procedure Proc is
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- declare
+ -- T : Task_Typ;
+ -- begin
+ -- <activation call> -- activation site
+ -- end;
+ -- ...
+ -- end A;
+
+ -- X : ... := A; -- root scenario
+ -- ...
+
+ -- task body Task_Typ is
+ -- ...
+ -- end Task_Typ;
+
+ -- In the example above, the context of X is the declarative list of
+ -- Proc. The "elaboration" of X may reach the activation of T whose body
+ -- is defined outside of X's context. The task body is relevant only
+ -- when Proc is invoked, but this happens only in "normal" elaboration,
+ -- therefore the task body must not be considered if this is not the
+ -- case.
+
+ -- Performance note: parent traversal
+
+ if Is_Up_Level_Target (Task_Attrs.Task_Decl) then
+ return;
+
+ -- Nothing to do when the activation is ABE-safe
+
+ -- generic
+ -- package Gen is
+ -- task type Task_Typ;
+ -- end Gen;
+
+ -- package body Gen is
+ -- task body Task_Typ is
+ -- begin
+ -- ...
+ -- end Task_Typ;
+ -- end Gen;
+
+ -- with Gen;
+ -- procedure Main is
+ -- package Nested is
+ -- ...
+ -- end Nested;
+
+ -- package body Nested is
+ -- package Inst is new Gen;
+ -- T : Inst.Task_Typ;
+ -- [begin]
+ -- <activation call> -- safe activation
+ -- end Nested;
+ -- ...
+
+ elsif Is_Safe_Activation (Call, Task_Attrs.Task_Decl) then
+ return;
+
+ -- An activation call leads to a guaranteed ABE when the activation
+ -- call and the task appear within the same context ignoring library
+ -- levels, and the body of the task has not been seen yet or appears
+ -- after the activation call.
+
+ -- procedure Guaranteed_ABE is
+ -- task type Task_Typ;
+
+ -- package Nested is
+ -- ...
+ -- end Nested;
+
+ -- package body Nested is
+ -- T : Task_Typ;
+ -- [begin]
+ -- <activation call> -- guaranteed ABE
+ -- end Nested;
+
+ -- task body Task_Typ is
+ -- ...
+ -- end Task_Typ;
+ -- ...
+
+ -- Performance note: parent traversal
+
+ elsif Is_Guaranteed_ABE
+ (N => Call,
+ Target_Decl => Task_Attrs.Task_Decl,
+ Target_Body => Task_Attrs.Body_Decl)
then
- return Entity (N);
+ Error_Msg_Sloc := Sloc (Call);
+ Error_Msg_N
+ ("??task & will be activated # before elaboration of its body",
+ Obj_Id);
+ Error_Msg_N ("\Program_Error will be raised at run time", Obj_Id);
+
+ -- Mark the activation call as a guaranteed ABE
+
+ Set_Is_Known_Guaranteed_ABE (Call);
+
+ -- Install a run-time ABE failue because this activation call will
+ -- always result in an ABE.
+
+ if Check_OK then
+ Install_ABE_Failure
+ (N => Call,
+ Ins_Nod => Call);
+ end if;
end if;
+ end Process_Activation_Guaranteed_ABE_Impl;
- if Nkind (N) = N_Attribute_Reference then
- Nam := Prefix (N);
- else
- Nam := Name (N);
+ procedure Process_Activation_Guaranteed_ABE is
+ new Process_Activation_Call (Process_Activation_Guaranteed_ABE_Impl);
+
+ ------------------
+ -- Process_Call --
+ ------------------
+
+ procedure Process_Call
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+ In_Task_Body : Boolean)
+ is
+ SPARK_Rules_On : Boolean;
+ Target_Attrs : Target_Attributes;
+
+ begin
+ Extract_Target_Attributes
+ (Target_Id => Target_Id,
+ Attrs => Target_Attrs);
+
+ -- The SPARK rules are in effect when both the call and target are
+ -- subject to SPARK_Mode On.
+
+ SPARK_Rules_On :=
+ Call_Attrs.SPARK_Mode_On and Target_Attrs.SPARK_Mode_On;
+
+ -- Output relevant information when switch -gnatel (info messages on
+ -- implicit Elaborate[_All] pragmas) is in effect.
+
+ if Elab_Info_Messages then
+ Info_Call
+ (Call => Call,
+ Target_Id => Target_Id,
+ Info_Msg => True,
+ In_SPARK => SPARK_Rules_On);
end if;
- if No (Nam) then
- return Empty;
- elsif Nkind (Nam) = N_Selected_Component then
- return Entity (Selector_Name (Nam));
- elsif not Is_Entity_Name (Nam) then
- return Empty;
+ -- Check whether the invocation of an entry clashes with an existing
+ -- restriction.
+
+ if Is_Protected_Entry (Target_Id) then
+ Check_Restriction (No_Entry_Calls_In_Elaboration_Code, Call);
+
+ elsif Is_Task_Entry (Target_Id) then
+ Check_Restriction (No_Entry_Calls_In_Elaboration_Code, Call);
+
+ -- Task entry calls are never processed because the entry being
+ -- invoked does not have a corresponding "body", it has a select.
+
+ return;
+ end if;
+
+ -- Nothing to do when the call is a guaranteed ABE
+
+ if Is_Known_Guaranteed_ABE (Call) then
+ return;
+
+ -- Nothing to do when the root scenario appears at the declaration level
+ -- and the target is in the same unit, but outside this context.
+
+ -- function B ...; -- target declaration
+
+ -- procedure Proc is
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- return B; -- call site
+ -- ...
+ -- end A;
+
+ -- X : ... := A; -- root scenario
+ -- ...
+
+ -- function B ... is
+ -- ...
+ -- end B;
+
+ -- In the example above, the context of X is the declarative region of
+ -- Proc. The "elaboration" of X may eventually reach B which is defined
+ -- outside of X's context. B is relevant only when Proc is invoked, but
+ -- this happens only by means of "normal" elaboration, therefore B must
+ -- not be considered if this is not the case.
+
+ -- Performance note: parent traversal
+
+ elsif Is_Up_Level_Target (Target_Attrs.Spec_Decl) then
+ return;
+
+ -- The SPARK rules are verified only when -gnatd.v (enforce SPARK
+ -- elaboration rules in SPARK code) is in effect.
+
+ elsif SPARK_Rules_On and Debug_Flag_Dot_V then
+ Process_Call_SPARK
+ (Call => Call,
+ Call_Attrs => Call_Attrs,
+ Target_Id => Target_Id,
+ Target_Attrs => Target_Attrs);
+
+ -- Otherwise the Ada rules are in effect, or SPARK code is allowed to
+ -- violate the SPARK rules.
+
else
- return Entity (Nam);
+ Process_Call_Ada
+ (Call => Call,
+ Call_Attrs => Call_Attrs,
+ Target_Id => Target_Id,
+ Target_Attrs => Target_Attrs,
+ In_Task_Body => In_Task_Body);
end if;
- end Get_Referenced_Ent;
+
+ -- Inspect the target body (and barried function) for other suitable
+ -- elaboration scenarios.
+
+ Traverse_Body (Target_Attrs.Body_Barf, In_Task_Body);
+ Traverse_Body (Target_Attrs.Body_Decl, In_Task_Body);
+ end Process_Call;
----------------------
- -- Has_Generic_Body --
+ -- Process_Call_Ada --
----------------------
- function Has_Generic_Body (N : Node_Id) return Boolean is
- Ent : constant Entity_Id := Get_Generic_Entity (N);
- Decl : constant Node_Id := Unit_Declaration_Node (Ent);
- Scop : Entity_Id;
-
- function Find_Body_In (E : Entity_Id; N : Node_Id) return Node_Id;
- -- Determine if the list of nodes headed by N and linked by Next
- -- contains a package body for the package spec entity E, and if so
- -- return the package body. If not, then returns Empty.
-
- function Load_Package_Body (Nam : Unit_Name_Type) return Node_Id;
- -- This procedure is called load the unit whose name is given by Nam.
- -- This unit is being loaded to see whether it contains an optional
- -- generic body. The returned value is the loaded unit, which is always
- -- a package body (only package bodies can contain other entities in the
- -- sense in which Has_Generic_Body is interested). We only attempt to
- -- load bodies if we are generating code. If we are in semantics check
- -- only mode, then it would be wrong to load bodies that are not
- -- required from a semantic point of view, so in this case we return
- -- Empty. The result is that the caller may incorrectly decide that a
- -- generic spec does not have a body when in fact it does, but the only
- -- harm in this is that some warnings on elaboration problems may be
- -- lost in semantic checks only mode, which is not big loss. We also
- -- return Empty if we go for a body and it is not there.
-
- function Locate_Corresponding_Body (PE : Entity_Id) return Node_Id;
- -- PE is the entity for a package spec. This function locates the
- -- corresponding package body, returning Empty if none is found. The
- -- package body returned is fully parsed but may not yet be analyzed,
- -- so only syntactic fields should be referenced.
-
- ------------------
- -- Find_Body_In --
- ------------------
-
- function Find_Body_In (E : Entity_Id; N : Node_Id) return Node_Id is
- Nod : Node_Id;
+ procedure Process_Call_Ada
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+ Target_Attrs : Target_Attributes;
+ In_Task_Body : Boolean)
+ is
+ function In_Initialization_Context (N : Node_Id) return Boolean;
+ -- Determine whether arbitrary node N appears within a type init proc or
+ -- primitive [Deep_]Initialize.
+
+ -------------------------------
+ -- In_Initialization_Context --
+ -------------------------------
+
+ function In_Initialization_Context (N : Node_Id) return Boolean is
+ Par : Node_Id;
+ Spec_Id : Entity_Id;
begin
- Nod := N;
- while Present (Nod) loop
+ -- Climb the parent chain looking for initialization actions
+
+ Par := Parent (N);
+ while Present (Par) loop
- -- If we found the package body we are looking for, return it
+ -- A block may be part of the initialization actions of a default
+ -- initialized object.
- if Nkind (Nod) = N_Package_Body
- and then Chars (Defining_Unit_Name (Nod)) = Chars (E)
+ if Nkind (Par) = N_Block_Statement
+ and then Is_Initialization_Block (Par)
then
- return Nod;
+ return True;
- -- If we found the stub for the body, go after the subunit,
- -- loading it if necessary.
+ -- A subprogram body may denote an initialization routine
- elsif Nkind (Nod) = N_Package_Body_Stub
- and then Chars (Defining_Identifier (Nod)) = Chars (E)
- then
- if Present (Library_Unit (Nod)) then
- return Unit (Library_Unit (Nod));
+ elsif Nkind (Par) = N_Subprogram_Body then
+ Spec_Id := Unique_Defining_Entity (Par);
- else
- return Load_Package_Body (Get_Unit_Name (Nod));
+ -- The current subprogram body denotes a type init proc or
+ -- primitive [Deep_]Initialize.
+
+ if Is_Init_Proc (Spec_Id)
+ or else Is_Controlled_Proc (Spec_Id, Name_Initialize)
+ or else Is_TSS (Spec_Id, TSS_Deep_Initialize)
+ then
+ return True;
end if;
- -- If neither package body nor stub, keep looking on chain
+ -- Prevent the search from going too far
- else
- Next (Nod);
+ elsif Is_Body_Or_Package_Declaration (Par) then
+ exit;
end if;
+
+ Par := Parent (Par);
end loop;
- return Empty;
- end Find_Body_In;
+ return False;
+ end In_Initialization_Context;
- -----------------------
- -- Load_Package_Body --
- -----------------------
+ -- Local variables
- function Load_Package_Body (Nam : Unit_Name_Type) return Node_Id is
- U : Unit_Number_Type;
+ Check_OK : constant Boolean :=
+ not Call_Attrs.Ghost_Mode_Ignore
+ and then not Target_Attrs.Ghost_Mode_Ignore
+ and then Call_Attrs.Elab_Checks_OK
+ and then Target_Attrs.Elab_Checks_OK;
+ -- A run-time ABE check may be installed only when both the call and the
+ -- target have active elaboration checks, and both are not ignored Ghost
+ -- constructs.
- begin
- if Operating_Mode /= Generate_Code then
- return Empty;
- else
- U :=
- Load_Unit
- (Load_Name => Nam,
- Required => False,
- Subunit => False,
- Error_Node => N);
+ -- Start of processing for Process_Call_Ada
- if U = No_Unit then
- return Empty;
- else
- return Unit (Cunit (U));
- end if;
- end if;
- end Load_Package_Body;
+ begin
+ -- Nothing to do for an Ada dispatching call because there are no ABE
+ -- diagnostics for either models. ABE checks for the dynamic model are
+ -- handled by Install_Primitive_Elaboration_Check.
- -------------------------------
- -- Locate_Corresponding_Body --
- -------------------------------
+ if Call_Attrs.Is_Dispatching then
+ return;
- function Locate_Corresponding_Body (PE : Entity_Id) return Node_Id is
- Spec : constant Node_Id := Declaration_Node (PE);
- Decl : constant Node_Id := Parent (Spec);
- Scop : constant Entity_Id := Scope (PE);
- PBody : Node_Id;
+ -- Nothing to do when the call is ABE-safe
- begin
- if Is_Library_Level_Entity (PE) then
+ -- generic
+ -- function Gen ...;
- -- If package is a library unit that requires a body, we have no
- -- choice but to go after that body because it might contain an
- -- optional body for the original generic package.
+ -- function Gen ... is
+ -- begin
+ -- ...
+ -- end Gen;
- if Unit_Requires_Body (PE) then
+ -- with Gen;
+ -- procedure Main is
+ -- function Inst is new Gen;
+ -- X : ... := Inst; -- safe call
+ -- ...
- -- Load the body. Note that we are a little careful here to use
- -- Spec to get the unit number, rather than PE or Decl, since
- -- in the case where the package is itself a library level
- -- instantiation, Spec will properly reference the generic
- -- template, which is what we really want.
+ elsif Is_Safe_Call (Call, Target_Attrs) then
+ return;
- return
- Load_Package_Body
- (Get_Body_Name (Unit_Name (Get_Source_Unit (Spec))));
+ -- The call and the target body are both in the main unit
- -- But if the package is a library unit that does NOT require
- -- a body, then no body is permitted, so we are sure that there
- -- is no body for the original generic package.
+ elsif Present (Target_Attrs.Body_Decl)
+ and then In_Extended_Main_Code_Unit (Target_Attrs.Body_Decl)
+ then
+ Process_Call_Conditional_ABE
+ (Call => Call,
+ Call_Attrs => Call_Attrs,
+ Target_Id => Target_Id,
+ Target_Attrs => Target_Attrs);
+
+ -- Otherwise the target body is not available in this compilation or it
+ -- resides in an external unit. Install a run-time ABE check to verify
+ -- that the target body has been elaborated prior to the call site when
+ -- the dynamic model is in effect.
+
+ elsif Dynamic_Elaboration_Checks and then Check_OK then
+ Install_ABE_Check
+ (N => Call,
+ Ins_Nod => Call,
+ Id => Target_Attrs.Unit_Id);
+ end if;
- else
- return Empty;
- end if;
+ -- No implicit pragma Elaborate[_All] is generated when the call has
+ -- elaboration checks suppressed. This behaviour parallels that of the
+ -- old ABE mechanism.
- -- Otherwise look and see if we are embedded in a further package
+ if not Call_Attrs.Elab_Checks_OK then
+ null;
- elsif Is_Package_Or_Generic_Package (Scop) then
+ -- No implicit pragma Elaborate[_All] is generated for finalization
+ -- actions when primitive [Deep_]Finalize is not defined in the main
+ -- unit and the call appears within some initialization actions. This
+ -- behaviour parallels that of the old ABE mechanism.
- -- If so, get the body of the enclosing package, and look in
- -- its package body for the package body we are looking for.
+ -- Performance note: parent traversal
- PBody := Locate_Corresponding_Body (Scop);
+ elsif (Is_Controlled_Proc (Target_Id, Name_Finalize)
+ or else Is_TSS (Target_Id, TSS_Deep_Finalize))
+ and then not In_Extended_Main_Code_Unit (Target_Attrs.Spec_Decl)
+ and then In_Initialization_Context (Call)
+ then
+ null;
- if No (PBody) then
- return Empty;
- else
- return Find_Body_In (PE, First (Declarations (PBody)));
- end if;
+ -- Otherwise ensure that the unit with the target body is elaborated
+ -- prior to the main unit.
+
+ else
+ Ensure_Prior_Elaboration
+ (N => Call,
+ Unit_Id => Target_Attrs.Unit_Id,
+ In_Task_Body => In_Task_Body);
+ end if;
+ end Process_Call_Ada;
- -- If we are not embedded in a further package, then the body
- -- must be in the same declarative part as we are.
+ ----------------------------------
+ -- Process_Call_Conditional_ABE --
+ ----------------------------------
- else
- return Find_Body_In (PE, Next (Decl));
+ procedure Process_Call_Conditional_ABE
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+ Target_Attrs : Target_Attributes)
+ is
+ Check_OK : constant Boolean :=
+ not Call_Attrs.Ghost_Mode_Ignore
+ and then not Target_Attrs.Ghost_Mode_Ignore
+ and then Call_Attrs.Elab_Checks_OK
+ and then Target_Attrs.Elab_Checks_OK;
+ -- A run-time ABE check may be installed only when both the call and the
+ -- target have active elaboration checks, and both are not ignored Ghost
+ -- constructs.
+
+ Root : constant Node_Id := Root_Scenario;
+
+ begin
+ -- If the root scenario appears prior to the target body, then this is a
+ -- possible ABE with respect to the root scenario.
+
+ -- function B ...;
+
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- return B; -- call site
+ -- ...
+ -- end A;
+
+ -- X : ... := A; -- root scenario
+
+ -- function B ... is -- target body
+ -- ...
+ -- end B;
+
+ -- Y : ... := A; -- root scenario
+
+ -- IMPORTANT: The call to B from A is a possible ABE for X, but not for
+ -- Y. Installing an unconditional ABE raise prior to the call to B would
+ -- be wrong as it will fail for Y as well, but in Y's case the call to B
+ -- is never an ABE.
+
+ if Earlier_In_Extended_Unit (Root, Target_Attrs.Body_Decl) then
+
+ -- ABE diagnostics are emitted only in the static model because there
+ -- is a well-defined order to visiting scenarios. Without this order
+ -- diagnostics appear jumbled and result in unwanted noise.
+
+ if Static_Elaboration_Checks then
+ Error_Msg_NE ("??cannot call & before body seen", Call, Target_Id);
+ Error_Msg_N ("\Program_Error may be raised at run time", Call);
+
+ Output_Active_Scenarios (Call);
end if;
- end Locate_Corresponding_Body;
- -- Start of processing for Has_Generic_Body
+ -- Install a conditional run-time ABE check to verify that the target
+ -- body has been elaborated prior to the call.
+
+ if Check_OK then
+ Install_ABE_Check
+ (N => Call,
+ Ins_Nod => Call,
+ Target_Id => Target_Attrs.Spec_Id,
+ Target_Decl => Target_Attrs.Spec_Decl,
+ Target_Body => Target_Attrs.Body_Decl);
+ end if;
+ end if;
+ end Process_Call_Conditional_ABE;
+
+ ---------------------------------
+ -- Process_Call_Guaranteed_ABE --
+ ---------------------------------
+
+ procedure Process_Call_Guaranteed_ABE
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id)
+ is
+ Target_Attrs : Target_Attributes;
begin
- if Present (Corresponding_Body (Decl)) then
- return True;
+ Extract_Target_Attributes
+ (Target_Id => Target_Id,
+ Attrs => Target_Attrs);
- elsif Unit_Requires_Body (Ent) then
- return True;
+ -- Nothing to do when the root scenario appears at the declaration level
+ -- and the target is in the same unit, but outside this context.
- -- Compilation units cannot have optional bodies
+ -- function B ...; -- target declaration
- elsif Is_Compilation_Unit (Ent) then
- return False;
+ -- procedure Proc is
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- return B; -- call site
+ -- ...
+ -- end A;
- -- Otherwise look at what scope we are in
+ -- X : ... := A; -- root scenario
+ -- ...
- else
- Scop := Scope (Ent);
+ -- function B ... is
+ -- ...
+ -- end B;
- -- Case of entity is in other than a package spec, in this case
- -- the body, if present, must be in the same declarative part.
+ -- In the example above, the context of X is the declarative region of
+ -- Proc. The "elaboration" of X may eventually reach B which is defined
+ -- outside of X's context. B is relevant only when Proc is invoked, but
+ -- this happens only by means of "normal" elaboration, therefore B must
+ -- not be considered if this is not the case.
- if not Is_Package_Or_Generic_Package (Scop) then
- declare
- P : Node_Id;
+ -- Performance note: parent traversal
- begin
- -- Declaration node may get us a spec, so if so, go to
- -- the parent declaration.
+ if Is_Up_Level_Target (Target_Attrs.Spec_Decl) then
+ return;
- P := Declaration_Node (Ent);
- while not Is_List_Member (P) loop
- P := Parent (P);
- end loop;
+ -- Nothing to do when the call is ABE-safe
- return Present (Find_Body_In (Ent, Next (P)));
- end;
+ -- generic
+ -- function Gen ...;
- -- If the entity is in a package spec, then we have to locate
- -- the corresponding package body, and look there.
+ -- function Gen ... is
+ -- begin
+ -- ...
+ -- end Gen;
- else
- declare
- PBody : constant Node_Id := Locate_Corresponding_Body (Scop);
+ -- with Gen;
+ -- procedure Main is
+ -- function Inst is new Gen;
+ -- X : ... := Inst; -- safe call
+ -- ...
- begin
- if No (PBody) then
- return False;
- else
- return
- Present
- (Find_Body_In (Ent, (First (Declarations (PBody)))));
- end if;
- end;
+ elsif Is_Safe_Call (Call, Target_Attrs) then
+ return;
+
+ -- A call leads to a guaranteed ABE when the call and the target appear
+ -- within the same context ignoring library levels, and the body of the
+ -- target has not been seen yet or appears after the call.
+
+ -- procedure Guaranteed_ABE is
+ -- function Func ...;
+
+ -- package Nested is
+ -- Obj : ... := Func; -- guaranteed ABE
+ -- end Nested;
+
+ -- function Func ... is
+ -- ...
+ -- end Func;
+ -- ...
+
+ -- Performance note: parent traversal
+
+ elsif Is_Guaranteed_ABE
+ (N => Call,
+ Target_Decl => Target_Attrs.Spec_Decl,
+ Target_Body => Target_Attrs.Body_Decl)
+ then
+ Error_Msg_NE ("??cannot call & before body seen", Call, Target_Id);
+ Error_Msg_N ("\Program_Error will be raised at run time", Call);
+
+ -- Mark the call as a guarnateed ABE
+
+ Set_Is_Known_Guaranteed_ABE (Call);
+
+ -- Install a run-time ABE failure because the call will always result
+ -- in an ABE. The failure is installed when both the call and target
+ -- have enabled elaboration checks, and both are not ignored Ghost
+ -- constructs.
+
+ if Call_Attrs.Elab_Checks_OK
+ and then Target_Attrs.Elab_Checks_OK
+ and then not Call_Attrs.Ghost_Mode_Ignore
+ and then not Target_Attrs.Ghost_Mode_Ignore
+ then
+ Install_ABE_Failure
+ (N => Call,
+ Ins_Nod => Call);
end if;
end if;
- end Has_Generic_Body;
+ end Process_Call_Guaranteed_ABE;
- -----------------------
- -- Insert_Elab_Check --
- -----------------------
+ ------------------------
+ -- Process_Call_SPARK --
+ ------------------------
- procedure Insert_Elab_Check (N : Node_Id; C : Node_Id := Empty) is
- Nod : Node_Id;
- Loc : constant Source_Ptr := Sloc (N);
+ procedure Process_Call_SPARK
+ (Call : Node_Id;
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+ Target_Attrs : Target_Attributes)
+ is
+ begin
+ -- A call to a source target or to a target which emulates Ada or SPARK
+ -- semantics imposes an Elaborate_All requirement on the context of the
+ -- main unit. Determine whether the context has a pragma strong enough
+ -- to meet the requirement. The check is orthogonal to the ABE effects
+ -- of the call.
+
+ if Target_Attrs.From_Source
+ or else Is_Ada_Semantic_Target (Target_Id)
+ or else Is_SPARK_Semantic_Target (Target_Id)
+ then
+ Meet_Elaboration_Requirement
+ (N => Call,
+ Target_Id => Target_Id,
+ Req_Nam => Name_Elaborate_All);
+ end if;
- Chk : Node_Id;
- -- The check (N_Raise_Program_Error) node to be inserted
+ -- Nothing to do when the call is ABE-safe
- begin
- -- If expansion is disabled, do not generate any checks. Also
- -- skip checks if any subunits are missing because in either
- -- case we lack the full information that we need, and no object
- -- file will be created in any case.
+ -- generic
+ -- function Gen ...;
+
+ -- function Gen ... is
+ -- begin
+ -- ...
+ -- end Gen;
- if not Expander_Active or else Subunits_Missing then
+ -- with Gen;
+ -- procedure Main is
+ -- function Inst is new Gen;
+ -- X : ... := Inst; -- safe call
+ -- ...
+
+ if Is_Safe_Call (Call, Target_Attrs) then
return;
- end if;
- -- If we have a generic instantiation, where Instance_Spec is set,
- -- then this field points to a generic instance spec that has
- -- been inserted before the instantiation node itself, so that
- -- is where we want to insert a check.
+ -- The call and the target body are both in the main unit
- if Nkind (N) in N_Generic_Instantiation
- and then Present (Instance_Spec (N))
+ elsif Present (Target_Attrs.Body_Decl)
+ and then In_Extended_Main_Code_Unit (Target_Attrs.Body_Decl)
then
- Nod := Instance_Spec (N);
+ Process_Call_Conditional_ABE
+ (Call => Call,
+ Call_Attrs => Call_Attrs,
+ Target_Id => Target_Id,
+ Target_Attrs => Target_Attrs);
+
+ -- Otherwise the target body is not available in this compilation or it
+ -- resides in an external unit. There is no need to guarantee the prior
+ -- elaboration of the unit with the target body because either the main
+ -- unit meets the Elaborate_All requirement imposed by the call, or the
+ -- program is illegal.
+
else
- Nod := N;
+ null;
end if;
+ end Process_Call_SPARK;
+
+ ----------------------------
+ -- Process_Guaranteed_ABE --
+ ----------------------------
+
+ procedure Process_Guaranteed_ABE (N : Node_Id) is
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+
+ begin
+ -- Add the current scenario to the stack of active scenarios
- -- Build check node, possibly with condition
+ Push_Active_Scenario (N);
- Chk :=
- Make_Raise_Program_Error (Loc, Reason => PE_Access_Before_Elaboration);
+ -- Only calls, instantiations, and task activations may result in a
+ -- guaranteed ABE.
- if Present (C) then
- Set_Condition (Chk, Make_Op_Not (Loc, Right_Opnd => C));
+ if Is_Suitable_Call (N) then
+ Extract_Call_Attributes
+ (Call => N,
+ Target_Id => Target_Id,
+ Attrs => Call_Attrs);
+
+ if Is_Activation_Proc (Target_Id) then
+ Process_Activation_Guaranteed_ABE
+ (Call => N,
+ Call_Attrs => Call_Attrs,
+ In_Task_Body => False);
+
+ else
+ Process_Call_Guaranteed_ABE
+ (Call => N,
+ Call_Attrs => Call_Attrs,
+ Target_Id => Target_Id);
+ end if;
+
+ elsif Is_Suitable_Instantiation (N) then
+ Process_Instantiation_Guaranteed_ABE (N);
end if;
- -- If we are inserting at the top level, insert in Aux_Decls
+ -- Remove the current scenario from the stack of active scenarios once
+ -- all ABE diagnostics and checks have been performed.
- if Nkind (Parent (Nod)) = N_Compilation_Unit then
- declare
- ADN : constant Node_Id := Aux_Decls_Node (Parent (Nod));
+ Pop_Active_Scenario (N);
+ end Process_Guaranteed_ABE;
- begin
- if No (Declarations (ADN)) then
- Set_Declarations (ADN, New_List (Chk));
- else
- Append_To (Declarations (ADN), Chk);
- end if;
+ ---------------------------
+ -- Process_Instantiation --
+ ---------------------------
+
+ procedure Process_Instantiation
+ (Exp_Inst : Node_Id;
+ In_Task_Body : Boolean)
+ is
+ Gen_Attrs : Target_Attributes;
+ Gen_Id : Entity_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Inst_Id : Entity_Id;
+
+ SPARK_Rules_On : Boolean;
+ -- This flag is set when the SPARK rules are in effect
+
+ begin
+ Extract_Instantiation_Attributes
+ (Exp_Inst => Exp_Inst,
+ Inst => Inst,
+ Inst_Id => Inst_Id,
+ Gen_Id => Gen_Id,
+ Attrs => Inst_Attrs);
+
+ Extract_Target_Attributes (Gen_Id, Gen_Attrs);
+
+ -- The SPARK rules are in effect when both the instantiation and generic
+ -- are subject to SPARK_Mode On.
+
+ SPARK_Rules_On := Inst_Attrs.SPARK_Mode_On and Gen_Attrs.SPARK_Mode_On;
+
+ -- Output relevant information when switch -gnatel (info messages on
+ -- implicit Elaborate[_All] pragmas) is in effect.
+
+ if Elab_Info_Messages then
+ Info_Instantiation
+ (Inst => Inst,
+ Gen_Id => Gen_Id,
+ Info_Msg => True,
+ In_SPARK => SPARK_Rules_On);
+ end if;
+
+ -- Nothing to do when the instantiation is a guaranteed ABE
+
+ if Is_Known_Guaranteed_ABE (Inst) then
+ return;
+
+ -- Nothing to do when the root scenario appears at the declaration level
+ -- and the generic is in the same unit, but outside this context.
+
+ -- generic
+ -- procedure Gen is ...; -- generic declaration
+
+ -- procedure Proc is
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- declare
+ -- procedure I is new Gen; -- instantiation site
+ -- ...
+ -- ...
+ -- end A;
- Analyze (Chk);
- end;
+ -- X : ... := A; -- root scenario
+ -- ...
- -- Otherwise just insert as an action on the node in question
+ -- procedure Gen is
+ -- ...
+ -- end Gen;
+
+ -- In the example above, the context of X is the declarative region of
+ -- Proc. The "elaboration" of X may eventually reach Gen which appears
+ -- outside of X's context. Gen is relevant only when Proc is invoked,
+ -- but this happens only by means of "normal" elaboration, therefore
+ -- Gen must not be considered if this is not the case.
+
+ -- Performance note: parent traversal
+
+ elsif Is_Up_Level_Target (Gen_Attrs.Spec_Decl) then
+ return;
+
+ -- The SPARK rules are verified only when -gnatd.v (enforce SPARK
+ -- elaboration rules in SPARK code) is in effect.
+
+ elsif SPARK_Rules_On and Debug_Flag_Dot_V then
+ Process_Instantiation_SPARK
+ (Exp_Inst => Exp_Inst,
+ Inst => Inst,
+ Inst_Attrs => Inst_Attrs,
+ Gen_Id => Gen_Id,
+ Gen_Attrs => Gen_Attrs);
+
+ -- Otherwise the Ada rules are in effect, or SPARK code is allowed to
+ -- violate the SPARK rules.
else
- Insert_Action (Nod, Chk);
+ Process_Instantiation_Ada
+ (Exp_Inst => Exp_Inst,
+ Inst => Inst,
+ Inst_Attrs => Inst_Attrs,
+ Gen_Id => Gen_Id,
+ Gen_Attrs => Gen_Attrs,
+ In_Task_Body => In_Task_Body);
end if;
- end Insert_Elab_Check;
+ end Process_Instantiation;
-------------------------------
- -- Is_Finalization_Procedure --
+ -- Process_Instantiation_Ada --
-------------------------------
- function Is_Finalization_Procedure (Id : Entity_Id) return Boolean is
+ procedure Process_Instantiation_Ada
+ (Exp_Inst : Node_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Gen_Id : Entity_Id;
+ Gen_Attrs : Target_Attributes;
+ In_Task_Body : Boolean)
+ is
+ Check_OK : constant Boolean :=
+ not Inst_Attrs.Ghost_Mode_Ignore
+ and then not Gen_Attrs.Ghost_Mode_Ignore
+ and then Inst_Attrs.Elab_Checks_OK
+ and then Gen_Attrs.Elab_Checks_OK;
+ -- A run-time ABE check may be installed only when both the instance and
+ -- the generic have active elaboration checks and both are not ignored
+ -- Ghost constructs.
+
begin
- -- Check whether Id is a procedure with at least one parameter
+ -- Nothing to do when the instantiation is ABE-safe
- if Ekind (Id) = E_Procedure and then Present (First_Formal (Id)) then
- declare
- Typ : constant Entity_Id := Etype (First_Formal (Id));
- Deep_Fin : Entity_Id := Empty;
- Fin : Entity_Id := Empty;
+ -- generic
+ -- package Gen is
+ -- ...
+ -- end Gen;
- begin
- -- If the type of the first formal does not require finalization
- -- actions, then this is definitely not [Deep_]Finalize.
+ -- package body Gen is
+ -- ...
+ -- end Gen;
- if not Needs_Finalization (Typ) then
- return False;
- end if;
+ -- with Gen;
+ -- procedure Main is
+ -- package Inst is new Gen (ABE); -- safe instantiation
+ -- ...
- -- At this point we have the following scenario:
+ if Is_Safe_Instantiation (Inst, Gen_Attrs) then
+ return;
- -- procedure Name (Param1 : [in] [out] Ctrl[; Param2 : ...]);
+ -- The instantiation and the generic body are both in the main unit
- -- Recover the two possible versions of [Deep_]Finalize using the
- -- type of the first parameter and compare with the input.
+ elsif Present (Gen_Attrs.Body_Decl)
+ and then In_Extended_Main_Code_Unit (Gen_Attrs.Body_Decl)
+ then
+ Process_Instantiation_Conditional_ABE
+ (Exp_Inst => Exp_Inst,
+ Inst => Inst,
+ Inst_Attrs => Inst_Attrs,
+ Gen_Id => Gen_Id,
+ Gen_Attrs => Gen_Attrs);
+
+ -- Otherwise the generic body is not available in this compilation or it
+ -- resides in an external unit. Install a run-time ABE check to verify
+ -- that the generic body has been elaborated prior to the instantiation
+ -- when the dynamic model is in effect.
+
+ elsif Dynamic_Elaboration_Checks and then Check_OK then
+ Install_ABE_Check
+ (N => Inst,
+ Ins_Nod => Exp_Inst,
+ Id => Gen_Attrs.Unit_Id);
+ end if;
- Deep_Fin := TSS (Typ, TSS_Deep_Finalize);
+ -- Ensure that the unit with the generic body is elaborated prior to
+ -- the main unit. No implicit pragma Elaborate[_All] is generated if
+ -- the instantiation has elaboration checks suppressed. This behaviour
+ -- parallels that of the old ABE mechanism.
- if Is_Controlled (Typ) then
- Fin := Find_Prim_Op (Typ, Name_Finalize);
- end if;
-
- return (Present (Deep_Fin) and then Id = Deep_Fin)
- or else (Present (Fin) and then Id = Fin);
- end;
+ if Inst_Attrs.Elab_Checks_OK then
+ Ensure_Prior_Elaboration
+ (N => Inst,
+ Unit_Id => Gen_Attrs.Unit_Id,
+ In_Task_Body => In_Task_Body);
end if;
+ end Process_Instantiation_Ada;
+
+ -------------------------------------------
+ -- Process_Instantiation_Conditional_ABE --
+ -------------------------------------------
+
+ procedure Process_Instantiation_Conditional_ABE
+ (Exp_Inst : Node_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Gen_Id : Entity_Id;
+ Gen_Attrs : Target_Attributes)
+ is
+ Check_OK : constant Boolean :=
+ not Inst_Attrs.Ghost_Mode_Ignore
+ and then not Gen_Attrs.Ghost_Mode_Ignore
+ and then Inst_Attrs.Elab_Checks_OK
+ and then Gen_Attrs.Elab_Checks_OK;
+ -- A run-time ABE check may be installed only when both the instance and
+ -- the generic have active elaboration checks and both are not ignored
+ -- Ghost constructs.
- return False;
- end Is_Finalization_Procedure;
+ Root : constant Node_Id := Root_Scenario;
- ------------------
- -- Output_Calls --
- ------------------
+ begin
+ -- If the root scenario appears prior to the generic body, then this is
+ -- a possible ABE with respect to the root scenario.
- procedure Output_Calls
- (N : Node_Id;
- Check_Elab_Flag : Boolean)
- is
- function Emit (Flag : Boolean) return Boolean;
- -- Determine whether to emit an error message based on the combination
- -- of flags Check_Elab_Flag and Flag.
+ -- generic
+ -- package Gen is
+ -- ...
+ -- end Gen;
- function Is_Printable_Error_Name return Boolean;
- -- An internal function, used to determine if a name, stored in the
- -- Name_Buffer, is either a non-internal name, or is an internal name
- -- that is printable by the error message circuits (i.e. it has a single
- -- upper case letter at the end).
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- declare
+ -- package Inst is new Gen; -- instantiation site
+ -- ...
+ -- end A;
- ----------
- -- Emit --
- ----------
+ -- X : ... := A; -- root scenario
- function Emit (Flag : Boolean) return Boolean is
- begin
- if Check_Elab_Flag then
- return Flag;
- else
- return True;
- end if;
- end Emit;
+ -- package body Gen is -- generic body
+ -- ...
+ -- end Gen;
- -----------------------------
- -- Is_Printable_Error_Name --
- -----------------------------
+ -- Y : ... := A; -- root scenario
- function Is_Printable_Error_Name return Boolean is
- begin
- if not Is_Internal_Name then
- return True;
+ -- IMPORTANT: The instantiation of Gen is a possible ABE for X, but not
+ -- for Y. Installing an unconditional ABE raise prior to the instance
+ -- site would be wrong as it will fail for Y as well, but in Y's case
+ -- the instantiation of Gen is never an ABE.
- elsif Name_Len = 1 then
- return False;
+ if Earlier_In_Extended_Unit (Root, Gen_Attrs.Body_Decl) then
- else
- Name_Len := Name_Len - 1;
- return not Is_Internal_Name;
+ -- ABE diagnostics are emitted only in the static model because there
+ -- is a well-defined order to visiting scenarios. Without this order
+ -- diagnostics appear jumbled and result in unwanted noise.
+
+ if Static_Elaboration_Checks then
+ Error_Msg_NE
+ ("??cannot instantiate & before body seen", Inst, Gen_Id);
+ Error_Msg_N ("\Program_Error may be raised at run time", Inst);
+
+ Output_Active_Scenarios (Inst);
end if;
- end Is_Printable_Error_Name;
- -- Local variables
+ -- Install a conditional run-time ABE check to verify that the
+ -- generic body has been elaborated prior to the instantiation.
+
+ if Check_OK then
+ Install_ABE_Check
+ (N => Inst,
+ Ins_Nod => Exp_Inst,
+ Target_Id => Gen_Attrs.Spec_Id,
+ Target_Decl => Gen_Attrs.Spec_Decl,
+ Target_Body => Gen_Attrs.Body_Decl);
+ end if;
+ end if;
+ end Process_Instantiation_Conditional_ABE;
- Ent : Entity_Id;
+ ------------------------------------------
+ -- Process_Instantiation_Guaranteed_ABE --
+ ------------------------------------------
- -- Start of processing for Output_Calls
+ procedure Process_Instantiation_Guaranteed_ABE (Exp_Inst : Node_Id) is
+ Gen_Attrs : Target_Attributes;
+ Gen_Id : Entity_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Inst_Id : Entity_Id;
begin
- for J in reverse 1 .. Elab_Call.Last loop
- Error_Msg_Sloc := Elab_Call.Table (J).Cloc;
+ Extract_Instantiation_Attributes
+ (Exp_Inst => Exp_Inst,
+ Inst => Inst,
+ Inst_Id => Inst_Id,
+ Gen_Id => Gen_Id,
+ Attrs => Inst_Attrs);
+
+ Extract_Target_Attributes (Gen_Id, Gen_Attrs);
+
+ -- Nothing to do when the root scenario appears at the declaration level
+ -- and the generic is in the same unit, but outside this context.
+
+ -- generic
+ -- procedure Gen is ...; -- generic declaration
+
+ -- procedure Proc is
+ -- function A ... is
+ -- begin
+ -- if Some_Condition then
+ -- declare
+ -- procedure I is new Gen; -- instantiation site
+ -- ...
+ -- ...
+ -- end A;
+
+ -- X : ... := A; -- root scenario
+ -- ...
+
+ -- procedure Gen is
+ -- ...
+ -- end Gen;
+
+ -- In the example above, the context of X is the declarative region of
+ -- Proc. The "elaboration" of X may eventually reach Gen which appears
+ -- outside of X's context. Gen is relevant only when Proc is invoked,
+ -- but this happens only by means of "normal" elaboration, therefore
+ -- Gen must not be considered if this is not the case.
+
+ -- Performance note: parent traversal
+
+ if Is_Up_Level_Target (Gen_Attrs.Spec_Decl) then
+ return;
- Ent := Elab_Call.Table (J).Ent;
- Get_Name_String (Chars (Ent));
+ -- Nothing to do when the instantiation is ABE-safe
- -- Dynamic elaboration model, warnings controlled by -gnatwl
+ -- generic
+ -- package Gen is
+ -- ...
+ -- end Gen;
- if Dynamic_Elaboration_Checks then
- if Emit (Elab_Warnings) then
- if Is_Generic_Unit (Ent) then
- Error_Msg_NE ("\\?l?& instantiated #", N, Ent);
- elsif Is_Init_Proc (Ent) then
- Error_Msg_N ("\\?l?initialization procedure called #", N);
- elsif Is_Printable_Error_Name then
- Error_Msg_NE ("\\?l?& called #", N, Ent);
- else
- Error_Msg_N ("\\?l?called #", N);
- end if;
- end if;
+ -- package body Gen is
+ -- ...
+ -- end Gen;
- -- Static elaboration model, info messages controlled by -gnatel
+ -- with Gen;
+ -- procedure Main is
+ -- package Inst is new Gen (ABE); -- safe instantiation
+ -- ...
- else
- if Emit (Elab_Info_Messages) then
- if Is_Generic_Unit (Ent) then
- Error_Msg_NE ("\\?$?& instantiated #", N, Ent);
- elsif Is_Init_Proc (Ent) then
- Error_Msg_N ("\\?$?initialization procedure called #", N);
- elsif Is_Printable_Error_Name then
- Error_Msg_NE ("\\?$?& called #", N, Ent);
- else
- Error_Msg_N ("\\?$?called #", N);
- end if;
- end if;
+ elsif Is_Safe_Instantiation (Inst, Gen_Attrs) then
+ return;
+
+ -- An instantiation leads to a guaranteed ABE when the instantiation and
+ -- the generic appear within the same context ignoring library levels,
+ -- and the body of the generic has not been seen yet or appears after
+ -- the instantiation.
+
+ -- procedure Guaranteed_ABE is
+ -- generic
+ -- procedure Gen;
+
+ -- package Nested is
+ -- procedure Inst is new Gen; -- guaranteed ABE
+ -- end Nested;
+
+ -- procedure Gen is
+ -- ...
+ -- end Gen;
+ -- ...
+
+ -- Performance note: parent traversal
+
+ elsif Is_Guaranteed_ABE
+ (N => Inst,
+ Target_Decl => Gen_Attrs.Spec_Decl,
+ Target_Body => Gen_Attrs.Body_Decl)
+ then
+ Error_Msg_NE
+ ("??cannot instantiate & before body seen", Inst, Gen_Id);
+ Error_Msg_N ("\Program_Error will be raised at run time", Inst);
+
+ -- Mark the instantiation as a guarantee ABE. This automatically
+ -- suppresses the instantiation of the generic body.
+
+ Set_Is_Known_Guaranteed_ABE (Inst);
+
+ -- Install a run-time ABE failure because the instantiation will
+ -- always result in an ABE. The failure is installed when both the
+ -- instance and the generic have enabled elaboration checks, and both
+ -- are not ignored Ghost constructs.
+
+ if Inst_Attrs.Elab_Checks_OK
+ and then Gen_Attrs.Elab_Checks_OK
+ and then not Inst_Attrs.Ghost_Mode_Ignore
+ and then not Gen_Attrs.Ghost_Mode_Ignore
+ then
+ Install_ABE_Failure
+ (N => Inst,
+ Ins_Nod => Exp_Inst);
end if;
- end loop;
- end Output_Calls;
+ end if;
+ end Process_Instantiation_Guaranteed_ABE;
+
+ ---------------------------------
+ -- Process_Instantiation_SPARK --
+ ---------------------------------
+
+ procedure Process_Instantiation_SPARK
+ (Exp_Inst : Node_Id;
+ Inst : Node_Id;
+ Inst_Attrs : Instantiation_Attributes;
+ Gen_Id : Entity_Id;
+ Gen_Attrs : Target_Attributes)
+ is
+ Req_Nam : Name_Id;
- ----------------------------
- -- Same_Elaboration_Scope --
- ----------------------------
+ begin
+ -- A source instantiation imposes an Elaborate[_All] requirement on the
+ -- context of the main unit. Determine whether the context has a pragma
+ -- strong enough to meet the requirement. The check is orthogonal to the
+ -- ABE ramifications of the instantiation.
+
+ if Nkind (Inst) = N_Package_Instantiation then
+ Req_Nam := Name_Elaborate_All;
+ else
+ Req_Nam := Name_Elaborate;
+ end if;
+
+ Meet_Elaboration_Requirement
+ (N => Inst,
+ Target_Id => Gen_Id,
+ Req_Nam => Req_Nam);
+
+ -- Nothing to do when the instantiation is ABE-safe
+
+ -- generic
+ -- package Gen is
+ -- ...
+ -- end Gen;
+
+ -- package body Gen is
+ -- ...
+ -- end Gen;
+
+ -- with Gen;
+ -- procedure Main is
+ -- package Inst is new Gen (ABE); -- safe instantiation
+ -- ...
+
+ if Is_Safe_Instantiation (Inst, Gen_Attrs) then
+ return;
- function Same_Elaboration_Scope (Scop1, Scop2 : Entity_Id) return Boolean is
- S1 : Entity_Id;
- S2 : Entity_Id;
+ -- The instantiation and the generic body are both in the main unit
+
+ elsif Present (Gen_Attrs.Body_Decl)
+ and then In_Extended_Main_Code_Unit (Gen_Attrs.Body_Decl)
+ then
+ Process_Instantiation_Conditional_ABE
+ (Exp_Inst => Exp_Inst,
+ Inst => Inst,
+ Inst_Attrs => Inst_Attrs,
+ Gen_Id => Gen_Id,
+ Gen_Attrs => Gen_Attrs);
+
+ -- Otherwise the generic body is not available in this compilation or
+ -- it resides in an external unit. There is no need to guarantee the
+ -- prior elaboration of the unit with the generic body because either
+ -- the main unit meets the Elaborate[_All] requirement imposed by the
+ -- instantiation, or the program is illegal.
+
+ else
+ null;
+ end if;
+ end Process_Instantiation_SPARK;
+
+ ---------------------------------
+ -- Process_Variable_Assignment --
+ ---------------------------------
+
+ procedure Process_Variable_Assignment (Asmt : Node_Id) is
+ Var_Id : constant Entity_Id := Entity (Extract_Assignment_Name (Asmt));
+ Prag : constant Node_Id := SPARK_Pragma (Var_Id);
+
+ SPARK_Rules_On : Boolean;
+ -- This flag is set when the SPARK rules are in effect
begin
- -- Find elaboration scope for Scop1
- -- This is either a subprogram or a compilation unit.
+ -- The SPARK rules are in effect when both the assignment and the
+ -- variable are subject to SPARK_Mode On.
+
+ SPARK_Rules_On :=
+ Present (Prag)
+ and then Get_SPARK_Mode_From_Annotation (Prag) = On
+ and then Is_SPARK_Mode_On_Node (Asmt);
+
+ -- Output relevant information when switch -gnatel (info messages on
+ -- implicit Elaborate[_All] pragmas) is in effect.
+
+ if Elab_Info_Messages then
+ Elab_Msg_NE
+ (Msg => "assignment to & during elaboration",
+ N => Asmt,
+ Id => Var_Id,
+ Info_Msg => True,
+ In_SPARK => SPARK_Rules_On);
+ end if;
- S1 := Scop1;
- while S1 /= Standard_Standard
- and then not Is_Compilation_Unit (S1)
- and then Ekind_In (S1, E_Package, E_Protected_Type, E_Block)
- loop
- S1 := Scope (S1);
- end loop;
+ -- The SPARK rules are in effect. These rules are applied regardless of
+ -- whether -gnatd.v (enforce SPARK elaboration rules in SPARK code) is
+ -- in effect because the static model cannot ensure safe assignment of
+ -- variables.
- -- Find elaboration scope for Scop2
+ if SPARK_Rules_On then
+ Process_Variable_Assignment_SPARK
+ (Asmt => Asmt,
+ Var_Id => Var_Id);
- S2 := Scop2;
- while S2 /= Standard_Standard
- and then not Is_Compilation_Unit (S2)
- and then Ekind_In (S2, E_Package, E_Protected_Type, E_Block)
- loop
- S2 := Scope (S2);
- end loop;
+ -- Otherwise the Ada rules are in effect
- return S1 = S2;
- end Same_Elaboration_Scope;
+ else
+ Process_Variable_Assignment_Ada
+ (Asmt => Asmt,
+ Var_Id => Var_Id);
+ end if;
+ end Process_Variable_Assignment;
- -----------------
- -- Set_C_Scope --
- -----------------
+ -------------------------------------
+ -- Process_Variable_Assignment_Ada --
+ -------------------------------------
+
+ procedure Process_Variable_Assignment_Ada
+ (Asmt : Node_Id;
+ Var_Id : Entity_Id)
+ is
+ Var_Decl : constant Node_Id := Declaration_Node (Var_Id);
+ Spec_Id : constant Entity_Id := Find_Top_Unit (Var_Decl);
- procedure Set_C_Scope is
begin
- while not Is_Compilation_Unit (C_Scope) loop
- C_Scope := Scope (C_Scope);
- end loop;
- end Set_C_Scope;
+ -- Emit a warning when an uninitialized variable declared in a package
+ -- spec without a pragma Elaborate_Body is initialized by elaboration
+ -- code within the corresponding body.
- -----------------
- -- Spec_Entity --
- -----------------
+ if not Warnings_Off (Var_Id)
+ and then not Is_Initialized (Var_Decl)
+ and then not Has_Pragma_Elaborate_Body (Spec_Id)
+ then
+ -- Generate an implicit Elaborate_Body in the spec
+
+ Set_Elaborate_Body_Desirable (Spec_Id);
+
+ Error_Msg_NE
+ ("??variable & can be accessed by clients before this "
+ & "initialization", Asmt, Var_Id);
+
+ Error_Msg_NE
+ ("\add pragma ""Elaborate_Body"" to spec & to ensure proper "
+ & "initialization", Asmt, Spec_Id);
+
+ Output_Active_Scenarios (Asmt);
+ end if;
+ end Process_Variable_Assignment_Ada;
- function Spec_Entity (E : Entity_Id) return Entity_Id is
- Decl : Node_Id;
+ ---------------------------------------
+ -- Process_Variable_Assignment_SPARK --
+ ---------------------------------------
+
+ procedure Process_Variable_Assignment_SPARK
+ (Asmt : Node_Id;
+ Var_Id : Entity_Id)
+ is
+ Var_Decl : constant Node_Id := Declaration_Node (Var_Id);
+ Spec_Id : constant Entity_Id := Find_Top_Unit (Var_Decl);
begin
- -- Check for case of body entity
- -- Why is the check for E_Void needed???
+ -- Emit an error when an initialized variable declared in a package spec
+ -- without pragma Elaborate_Body is further modified by elaboration code
+ -- within the corresponding body.
- if Ekind_In (E, E_Void, E_Subprogram_Body, E_Package_Body) then
- Decl := E;
+ if Is_Initialized (Var_Decl)
+ and then not Has_Pragma_Elaborate_Body (Spec_Id)
+ then
+ Error_Msg_NE
+ ("variable & modified by elaboration code in package body",
+ Asmt, Var_Id);
- loop
- Decl := Parent (Decl);
- exit when Nkind (Decl) in N_Proper_Body;
- end loop;
+ Error_Msg_NE
+ ("\add pragma ""Elaborate_Body"" to spec & to ensure full "
+ & "initialization", Asmt, Spec_Id);
- return Corresponding_Spec (Decl);
+ Output_Active_Scenarios (Asmt);
+ end if;
+ end Process_Variable_Assignment_SPARK;
+
+ ---------------------------
+ -- Process_Variable_Read --
+ ---------------------------
+
+ procedure Process_Variable_Read (Ref : Node_Id) is
+ Var_Attrs : Variable_Attributes;
+ Var_Id : Entity_Id;
+
+ begin
+ Extract_Variable_Reference_Attributes
+ (Ref => Ref,
+ Var_Id => Var_Id,
+ Attrs => Var_Attrs);
+
+ -- Output relevant information when switch -gnatel (info messages on
+ -- implicit Elaborate[_All] pragmas) is in effect.
+
+ if Elab_Info_Messages then
+ Elab_Msg_NE
+ (Msg => "read of variable & during elaboration",
+ N => Ref,
+ Id => Var_Id,
+ Info_Msg => True,
+ In_SPARK => True);
+ end if;
+
+ -- Nothing to do when the variable appears within the main unit because
+ -- diagnostics on reads are relevant only for external variables.
+
+ if Is_Same_Unit (Var_Attrs.Unit_Id, Cunit_Entity (Main_Unit)) then
+ null;
+
+ -- Nothing to do when the variable is already initialized. Note that the
+ -- variable may be further modified by the external unit.
+
+ elsif Is_Initialized (Declaration_Node (Var_Id)) then
+ null;
+
+ -- Nothing to do when the external unit guarantees the initialization of
+ -- the variable by means of pragma Elaborate_Body.
+
+ elsif Has_Pragma_Elaborate_Body (Var_Attrs.Unit_Id) then
+ null;
+
+ -- A variable read imposes an Elaborate requirement on the context of
+ -- the main unit. Determine whether the context has a pragma strong
+ -- enough to meet the requirement.
else
- return E;
+ Meet_Elaboration_Requirement
+ (N => Ref,
+ Target_Id => Var_Id,
+ Req_Nam => Name_Elaborate);
end if;
- end Spec_Entity;
+ end Process_Variable_Read;
- -------------------
- -- Supply_Bodies --
- -------------------
+ --------------------------
+ -- Push_Active_Scenario --
+ --------------------------
- procedure Supply_Bodies (N : Node_Id) is
+ procedure Push_Active_Scenario (N : Node_Id) is
begin
- if Nkind (N) = N_Subprogram_Declaration then
- declare
- Ent : constant Entity_Id := Defining_Unit_Name (Specification (N));
+ Scenario_Stack.Append (N);
+ end Push_Active_Scenario;
- begin
- -- Internal subprograms will already have a generated body, so
- -- there is no need to provide a stub for them.
-
- if No (Corresponding_Body (N)) then
- declare
- Loc : constant Source_Ptr := Sloc (N);
- Formals : constant List_Id := Copy_Parameter_List (Ent);
- Nam : constant Entity_Id :=
- Make_Defining_Identifier (Loc, Chars (Ent));
- Stats : constant List_Id :=
- New_List (
- Make_Raise_Program_Error (Loc,
- Reason => PE_Access_Before_Elaboration));
- Spec : Node_Id;
-
- begin
- if Ekind (Ent) = E_Function then
- Spec :=
- Make_Function_Specification (Loc,
- Defining_Unit_Name => Nam,
- Parameter_Specifications => Formals,
- Result_Definition =>
- New_Copy_Tree
- (Result_Definition (Specification (N))));
-
- -- We cannot reliably make a return statement for this
- -- body, but none is needed because the call raises
- -- program error.
-
- Set_Return_Present (Ent);
+ ----------------------
+ -- Process_Scenario --
+ ----------------------
- else
- Spec :=
- Make_Procedure_Specification (Loc,
- Defining_Unit_Name => Nam,
- Parameter_Specifications => Formals);
- end if;
+ procedure Process_Scenario (N : Node_Id; In_Task_Body : Boolean := False) is
+ Call_Attrs : Call_Attributes;
+ Target_Id : Entity_Id;
+
+ begin
+ -- Add the current scenario to the stack of active scenarios
+
+ Push_Active_Scenario (N);
+
+ -- 'Access
+
+ if Is_Suitable_Access (N) then
+ Process_Access (N, In_Task_Body);
- Insert_After_And_Analyze (N,
- Make_Subprogram_Body (Loc,
- Specification => Spec,
- Declarations => New_List,
- Handled_Statement_Sequence =>
- Make_Handled_Sequence_Of_Statements (Loc, Stats)));
- end;
+ -- Calls
+
+ elsif Is_Suitable_Call (N) then
+
+ -- In general, only calls found within the main unit are processed
+ -- because the ALI information supplied to binde is for the main
+ -- unit only. However, to preserve the consistency of the tree and
+ -- ensure proper serialization of internal names, external calls
+ -- also receive corresponding call markers (see Build_Call_Marker).
+ -- Regardless of the reason, external calls must not be processed.
+
+ if In_Main_Context (N) then
+ Extract_Call_Attributes
+ (Call => N,
+ Target_Id => Target_Id,
+ Attrs => Call_Attrs);
+
+ if Is_Activation_Proc (Target_Id) then
+ Process_Activation_Conditional_ABE
+ (Call => N,
+ Call_Attrs => Call_Attrs,
+ In_Task_Body => In_Task_Body);
+
+ else
+ Process_Call
+ (Call => N,
+ Call_Attrs => Call_Attrs,
+ Target_Id => Target_Id,
+ In_Task_Body => In_Task_Body);
end if;
- end;
+ end if;
- elsif Nkind (N) = N_Package_Declaration then
- declare
- Spec : constant Node_Id := Specification (N);
- begin
- Push_Scope (Defining_Unit_Name (Spec));
- Supply_Bodies (Visible_Declarations (Spec));
- Supply_Bodies (Private_Declarations (Spec));
- Pop_Scope;
- end;
- end if;
- end Supply_Bodies;
-
- procedure Supply_Bodies (L : List_Id) is
- Elmt : Node_Id;
- begin
- if Present (L) then
- Elmt := First (L);
- while Present (Elmt) loop
- Supply_Bodies (Elmt);
- Next (Elmt);
- end loop;
+ -- Instantiations
+
+ elsif Is_Suitable_Instantiation (N) then
+ Process_Instantiation (N, In_Task_Body);
+
+ -- Variable assignments
+
+ elsif Is_Suitable_Variable_Assignment (N) then
+ Process_Variable_Assignment (N);
+
+ -- Variable read
+
+ elsif Is_Suitable_Variable_Read (N) then
+ Process_Variable_Read (N);
end if;
- end Supply_Bodies;
- ------------
- -- Within --
- ------------
+ -- Remove the current scenario from the stack of active scenarios once
+ -- all ABE diagnostics and checks have been performed.
+
+ Pop_Active_Scenario (N);
+ end Process_Scenario;
+
+ ---------------------------------
+ -- Record_Elaboration_Scenario --
+ ---------------------------------
+
+ procedure Record_Elaboration_Scenario (N : Node_Id) is
+ Level : Enclosing_Level_Kind;
+
+ Declaration_Level_OK : Boolean;
+ -- This flag is set when a particular scenario is allowed to appear at
+ -- the declaration level.
- function Within (E1, E2 : Entity_Id) return Boolean is
- Scop : Entity_Id;
begin
- Scop := E1;
- loop
- if Scop = E2 then
- return True;
- elsif Scop = Standard_Standard then
- return False;
+ -- Assume that the scenario must not appear at the declaration level
+
+ Declaration_Level_OK := False;
+
+ -- Nothing to do for ASIS. As a result, no ABE checks and diagnostics
+ -- are performed in this mode.
+
+ if ASIS_Mode then
+ return;
+
+ -- Nothing to do when the scenario is being preanalyzed
+
+ elsif Preanalysis_Active then
+ return;
+ end if;
+
+ -- Ensure that a library level call does not appear in a preelaborated
+ -- unit. The check must come before ignoring scenarios within external
+ -- units or inside generics because calls in those context must also be
+ -- verified.
+
+ if Is_Suitable_Call (N) then
+ Check_Preelaborated_Call (N);
+ end if;
+
+ -- Nothing to do when the scenario does not appear within the main unit
+
+ if not In_Main_Context (N) then
+ return;
+
+ -- Scenarios within a generic unit are never considered because generics
+ -- cannot be elaborated.
+
+ elsif Inside_A_Generic then
+ return;
+
+ -- Scenarios which do not fall in one of the elaboration categories
+ -- listed below are not considered. The categories are:
+
+ -- 'Access for entries, operators, and subprograms
+ -- Assignments to variables
+ -- Calls (includes task activation)
+ -- Instantiations
+ -- Reads of variables
+
+ elsif Is_Suitable_Access (N) then
+
+ -- Signal any enclosing local exception handlers that the 'Access may
+ -- raise Program_Error due to a failed ABE check when switch -gnatd.o
+ -- (conservative elaboration order for indirect calls) is in effect.
+ -- Marking the exception handlers ensures proper expansion by both
+ -- the front and back end restriction when No_Exception_Propagation
+ -- is in effect.
+
+ if Debug_Flag_Dot_O then
+ Possible_Local_Raise (N, Standard_Program_Error);
+ end if;
+
+ elsif Is_Suitable_Call (N) or else Is_Suitable_Instantiation (N) then
+ Declaration_Level_OK := True;
+
+ -- Signal any enclosing local exception handlers that the call or
+ -- instantiation may raise Program_Error due to a failed ABE check.
+ -- Marking the exception handlers ensures proper expansion by both
+ -- the front and back end restriction when No_Exception_Propagation
+ -- is in effect.
+
+ Possible_Local_Raise (N, Standard_Program_Error);
+
+ elsif Is_Suitable_Variable_Assignment (N)
+ or else Is_Suitable_Variable_Read (N)
+ then
+ null;
+
+ -- Otherwise the input does not denote a suitable scenario
+
+ else
+ return;
+ end if;
+
+ -- The static model imposes additional restrictions on the placement of
+ -- scenarios. In contrast, the dynamic model assumes that every scenario
+ -- will be elaborated or invoked at some point.
+
+ if Static_Elaboration_Checks then
+
+ -- Performance note: parent traversal
+
+ Level := Find_Enclosing_Level (N);
+
+ -- Declaration level scenario
+
+ if Declaration_Level_OK and then Level = Declaration_Level then
+ null;
+
+ -- Library level scenario
+
+ elsif Level in Library_Level then
+ null;
+
+ -- Instantiation library level scenario
+
+ elsif Level = Instantiation then
+ null;
+
+ -- Otherwise the scenario does not appear at the proper level and
+ -- cannot possibly act as a top level scenario.
+
else
- Scop := Scope (Scop);
+ return;
end if;
- end loop;
- end Within;
+ end if;
- --------------------------
- -- Within_Elaborate_All --
- --------------------------
+ -- Perform early detection of guaranteed ABEs in order to suppress the
+ -- instantiation of generic bodies as gigi cannot handle certain types
+ -- of premature instantiations.
- function Within_Elaborate_All
- (Unit : Unit_Number_Type;
- E : Entity_Id) return Boolean
- is
- type Unit_Number_Set is array (Main_Unit .. Last_Unit) of Boolean;
- pragma Pack (Unit_Number_Set);
+ Process_Guaranteed_ABE (N);
- Seen : Unit_Number_Set := (others => False);
- -- Seen (X) is True after we have seen unit X in the walk. This is used
- -- to prevent processing the same unit more than once.
+ -- At this point all checks have been performed. Record the scenario for
+ -- later processing by the ABE phase.
- Result : Boolean := False;
+ Top_Level_Scenarios.Append (N);
- procedure Helper (Unit : Unit_Number_Type);
- -- This helper procedure does all the work for Within_Elaborate_All. It
- -- walks the dependency graph, and sets Result to True if it finds an
- -- appropriate Elaborate_All.
+ -- Mark a scenario which may produce run-time conditional ABE checks or
+ -- guaranteed ABE failures as recorded. The flag ensures that scenario
+ -- rewriting performed by Atree.Rewrite will be properly reflected in
+ -- all relevant internal data structures.
- ------------
- -- Helper --
- ------------
+ if Is_Check_Emitting_Scenario (N) then
+ Set_Is_Recorded_Scenario (N);
+ end if;
+ end Record_Elaboration_Scenario;
- procedure Helper (Unit : Unit_Number_Type) is
- CU : constant Node_Id := Cunit (Unit);
+ -------------------
+ -- Root_Scenario --
+ -------------------
- Item : Node_Id;
- Item2 : Node_Id;
- Elab_Id : Entity_Id;
- Par : Node_Id;
+ function Root_Scenario return Node_Id is
+ package Stack renames Scenario_Stack;
+
+ begin
+ -- Ensure that the scenario stack has at least one active scenario in
+ -- it. The one at the bottom (index First) is the root scenario.
+ pragma Assert (Stack.Last >= Stack.First);
+ return Stack.Table (Stack.First);
+ end Root_Scenario;
+
+ -------------------------------
+ -- Static_Elaboration_Checks --
+ -------------------------------
+
+ function Static_Elaboration_Checks return Boolean is
+ begin
+ return not Dynamic_Elaboration_Checks;
+ end Static_Elaboration_Checks;
+
+ -------------------
+ -- Traverse_Body --
+ -------------------
+
+ procedure Traverse_Body (N : Node_Id; In_Task_Body : Boolean) is
+ function Is_Potential_Scenario (Nod : Node_Id) return Traverse_Result;
+ -- Determine whether arbitrary node Nod denotes a suitable scenario and
+ -- if so, process it.
+
+ procedure Traverse_Potential_Scenarios is
+ new Traverse_Proc (Is_Potential_Scenario);
+
+ procedure Traverse_List (List : List_Id);
+ -- Inspect list List for suitable elaboration scenarios and process them
+
+ ---------------------------
+ -- Is_Potential_Scenario --
+ ---------------------------
+
+ function Is_Potential_Scenario (Nod : Node_Id) return Traverse_Result is
begin
- if Seen (Unit) then
- return;
- else
- Seen (Unit) := True;
+ -- Special cases
+
+ -- Skip constructs which do not have elaboration of their own and
+ -- need to be elaborated by other means such as invocation, task
+ -- activation, etc.
+
+ if Is_Non_Library_Level_Encapsulator (Nod) then
+ return Skip;
+
+ -- Terminate the traversal of a task body with an accept statement
+ -- when no entry calls in elaboration are allowed because the task
+ -- will block at run-time and none of the remaining statements will
+ -- be executed.
+
+ elsif Nkind_In (Original_Node (Nod), N_Accept_Statement,
+ N_Selective_Accept)
+ and then Restriction_Active (No_Entry_Calls_In_Elaboration_Code)
+ then
+ return Abandon;
+
+ -- Certain nodes carry semantic lists which act as repositories until
+ -- expansion transforms the node and relocates the contents. Examine
+ -- these lists in case expansion is disabled.
+
+ elsif Nkind_In (Nod, N_And_Then, N_Or_Else) then
+ Traverse_List (Actions (Nod));
+
+ elsif Nkind_In (Nod, N_Elsif_Part, N_Iteration_Scheme) then
+ Traverse_List (Condition_Actions (Nod));
+
+ elsif Nkind (Nod) = N_If_Expression then
+ Traverse_List (Then_Actions (Nod));
+ Traverse_List (Else_Actions (Nod));
+
+ elsif Nkind_In (Nod, N_Component_Association,
+ N_Iterated_Component_Association)
+ then
+ Traverse_List (Loop_Actions (Nod));
+
+ -- General case
+
+ elsif Is_Suitable_Scenario (Nod) then
+ Process_Scenario (Nod, In_Task_Body);
end if;
- -- First, check for Elaborate_Alls on this unit
+ return OK;
+ end Is_Potential_Scenario;
+
+ -------------------
+ -- Traverse_List --
+ -------------------
- Item := First (Context_Items (CU));
+ procedure Traverse_List (List : List_Id) is
+ Item : Node_Id;
+
+ begin
+ Item := First (List);
while Present (Item) loop
- if Nkind (Item) = N_Pragma
- and then Pragma_Name (Item) = Name_Elaborate_All
- then
- -- Return if some previous error on the pragma itself. The
- -- pragma may be unanalyzed, because of a previous error, or
- -- if it is the context of a subunit, inherited by its parent.
+ Traverse_Potential_Scenarios (Item);
+ Next (Item);
+ end loop;
+ end Traverse_List;
- if Error_Posted (Item) or else not Analyzed (Item) then
- return;
- end if;
+ -- Start of processing for Traverse_Body
- Elab_Id :=
- Entity
- (Expression (First (Pragma_Argument_Associations (Item))));
+ begin
+ -- Nothing to do when there is no body
- if E = Elab_Id then
- Result := True;
- return;
- end if;
+ if No (N) then
+ return;
- Par := Parent (Unit_Declaration_Node (Elab_Id));
+ elsif Nkind (N) /= N_Subprogram_Body then
+ return;
+ end if;
- Item2 := First (Context_Items (Par));
- while Present (Item2) loop
- if Nkind (Item2) = N_With_Clause
- and then Entity (Name (Item2)) = E
- and then not Limited_Present (Item2)
- then
- Result := True;
- return;
- end if;
+ -- Nothing to do if the body was already traversed during the processing
+ -- of the same top level scenario.
- Next (Item2);
- end loop;
- end if;
+ if Visited_Bodies.Get (N) then
+ return;
- Next (Item);
+ -- Otherwise mark the body as traversed
+
+ else
+ Visited_Bodies.Set (N, True);
+ end if;
+
+ -- Examine the declarations for suitable scenarios
+
+ Traverse_List (Declarations (N));
+
+ -- Examine the handled sequence of statements. This also includes any
+ -- exceptions handlers.
+
+ Traverse_Potential_Scenarios (Handled_Statement_Sequence (N));
+ end Traverse_Body;
+
+ ---------------------------------
+ -- Update_Elaboration_Scenario --
+ ---------------------------------
+
+ procedure Update_Elaboration_Scenario (New_N : Node_Id; Old_N : Node_Id) is
+ package Scenarios renames Top_Level_Scenarios;
+
+ begin
+ -- A scenario is being transformed by Atree.Rewrite. Update all relevant
+ -- internal data structures to reflect this change. This ensures that a
+ -- potential run-time conditional ABE check or a guaranteed ABE failure
+ -- is inserted at the proper place in the tree.
+
+ if Is_Check_Emitting_Scenario (Old_N)
+ and then Is_Recorded_Scenario (Old_N)
+ and then Old_N /= New_N
+ then
+ -- Performance note: list traversal
+
+ for Index in Scenarios.First .. Scenarios.Last loop
+ if Scenarios.Table (Index) = Old_N then
+ Scenarios.Table (Index) := New_N;
+
+ Set_Is_Recorded_Scenario (Old_N, False);
+ Set_Is_Recorded_Scenario (New_N);
+ return;
+ end if;
end loop;
- -- Second, recurse on with's. We could do this as part of the above
- -- loop, but it's probably more efficient to have two loops, because
- -- the relevant Elaborate_All is likely to be on the initial unit. In
- -- other words, we're walking the with's breadth-first. This part is
- -- only necessary in the dynamic elaboration model.
-
- if Dynamic_Elaboration_Checks then
- Item := First (Context_Items (CU));
- while Present (Item) loop
- if Nkind (Item) = N_With_Clause
- and then not Limited_Present (Item)
- then
- -- Note: the following call to Get_Cunit_Unit_Number does a
- -- linear search, which could be slow, but it's OK because
- -- we're about to give a warning anyway. Also, there might
- -- be hundreds of units, but not millions. If it turns out
- -- to be a problem, we could store the Get_Cunit_Unit_Number
- -- in each N_Compilation_Unit node, but that would involve
- -- rearranging N_Compilation_Unit_Aux to make room.
-
- Helper (Get_Cunit_Unit_Number (Library_Unit (Item)));
-
- if Result then
- return;
- end if;
- end if;
+ -- A recorded scenario must be in the table of recorded scenarios
- Next (Item);
- end loop;
- end if;
- end Helper;
+ pragma Assert (False);
+ end if;
+ end Update_Elaboration_Scenario;
- -- Start of processing for Within_Elaborate_All
+ -------------------------
+ -- Visited_Bodies_Hash --
+ -------------------------
+ function Visited_Bodies_Hash (Key : Node_Id) return Visited_Bodies_Index is
begin
- Helper (Unit);
- return Result;
- end Within_Elaborate_All;
+ return Visited_Bodies_Index (Key mod Visited_Bodies_Max);
+ end Visited_Bodies_Hash;
end Sem_Elab;
diff --git a/gcc/ada/sem_elab.ads b/gcc/ada/sem_elab.ads
index d246582..ddcd433 100644
--- a/gcc/ada/sem_elab.ads
+++ b/gcc/ada/sem_elab.ads
@@ -23,158 +23,93 @@
-- --
------------------------------------------------------------------------------
--- This package contains the routines used to deal with issuing warnings
--- for cases of calls that may require warnings about possible access
--- before elaboration.
+-- This package contains routines which handle access-before-elaboration
+-- run-time checks and compile-time diagnostics. See the body for details.
with Types; use Types;
package Sem_Elab is
- -----------------------------
- -- Description of Approach --
- -----------------------------
-
- -- Every non-static call that is encountered by Sem_Res results in a call
- -- to Check_Elab_Call, with N being the call node, and Outer set to its
- -- default value of True. In addition X'Access is treated like a call
- -- for the access-to-procedure case, and in SPARK mode only we also
- -- check variable references.
-
- -- The goal of Check_Elab_Call is to determine whether or not the reference
- -- in question can generate an access before elaboration error (raising
- -- Program_Error) either by directly calling a subprogram whose body
- -- has not yet been elaborated, or indirectly, by calling a subprogram
- -- whose body has been elaborated, but which contains a call to such a
- -- subprogram.
-
- -- In addition, in SPARK mode, we are checking for a variable reference in
- -- another package, which requires an explicit Elaborate_All pragma.
-
- -- The only references that we need to look at the outer level are
- -- references that occur in elaboration code. There are two cases. The
- -- reference can be at the outer level of elaboration code, or it can
- -- be within another unit, e.g. the elaboration code of a subprogram.
-
- -- In the case of an elaboration call at the outer level, we must trace
- -- all calls to outer level routines either within the current unit or to
- -- other units that are with'ed. For calls within the current unit, we can
- -- determine if the body has been elaborated or not, and if it has not,
- -- then a warning is generated.
-
- -- Note that there are two subcases. If the original call directly calls a
- -- subprogram whose body has not been elaborated, then we know that an ABE
- -- will take place, and we replace the call by a raise of Program_Error.
- -- If the call is indirect, then we don't know that the PE will be raised,
- -- since the call might be guarded by a conditional. In this case we set
- -- Do_Elab_Check on the call so that a dynamic check is generated, and
- -- output a warning.
-
- -- For calls to a subprogram in a with'ed unit or a 'Access or variable
- -- reference (SPARK mode case), we require that a pragma Elaborate_All
- -- or pragma Elaborate be present, or that the referenced unit have a
- -- pragma Preelaborate, pragma Pure, or pragma Elaborate_Body. If none
- -- of these conditions is met, then a warning is generated that a pragma
- -- Elaborate_All may be needed (error in the SPARK case), or an implicit
- -- pragma is generated.
-
- -- For the case of an elaboration call at some inner level, we are
- -- interested in tracing only calls to subprograms at the same level,
- -- i.e. those that can be called during elaboration. Any calls to
- -- outer level routines cannot cause ABE's as a result of the original
- -- call (there might be an outer level call to the subprogram from
- -- outside that causes the ABE, but that gets analyzed separately).
-
- -- Note that we never trace calls to inner level subprograms, since
- -- these cannot result in ABE's unless there is an elaboration problem
- -- at a lower level, which will be separately detected.
-
- -- Note on pragma Elaborate. The checking here assumes that a pragma
- -- Elaborate on a with'ed unit guarantees that subprograms within the
- -- unit can be called without causing an ABE. This is not in fact the
- -- case since pragma Elaborate does not guarantee the transitive
- -- coverage guaranteed by Elaborate_All. However, we decide to trust
- -- the user in this case.
-
- --------------------------------------
- -- Instantiation Elaboration Errors --
- --------------------------------------
-
- -- A special case arises when an instantiation appears in a context
- -- that is known to be before the body is elaborated, e.g.
-
- -- generic package x is ...
- -- ...
- -- package xx is new x;
- -- ...
- -- package body x is ...
-
- -- In this situation it is certain that an elaboration error will
- -- occur, and an unconditional raise Program_Error statement is
- -- inserted before the instantiation, and a warning generated.
-
- -- The problem is that in this case we have no place to put the
- -- body of the instantiation. We can't put it in the normal place,
- -- because it is too early, and will cause errors to occur as a
- -- result of referencing entities before they are declared.
-
- -- Our approach in this case is simply to avoid creating the body
- -- of the instantiation in such a case. The instantiation spec is
- -- modified to include dummy bodies for all subprograms, so that
- -- the resulting code does not contain subprogram specs with no
- -- corresponding bodies.
-
- procedure Check_Elab_Call
- (N : Node_Id;
- Outer_Scope : Entity_Id := Empty;
- In_Init_Proc : Boolean := False);
- -- Check a call for possible elaboration problems. The node N is either an
- -- N_Function_Call or N_Procedure_Call_Statement node or an access
- -- attribute reference whose prefix is a subprogram.
- --
- -- If SPARK_Mode is On, then N can also be a variable reference, since
- -- SPARK requires the use of Elaborate_All for references to variables
- -- in other packages.
-
- -- The Outer_Scope argument indicates whether this is an outer level
- -- call from Sem_Res (Outer_Scope set to Empty), or an internal recursive
- -- call (Outer_Scope set to entity of outermost call, see body). The flag
- -- In_Init_Proc should be set whenever the current context is a type
- -- init proc.
-
- -- Note: this might better be called Check_Elab_Reference (to recognize
- -- the SPARK case), but we prefer to keep the original name, since this
- -- is primarily used for checking for calls that could generate an ABE).
-
- procedure Check_Elab_Calls;
- -- Not all the processing for Check_Elab_Call can be done at the time
- -- of calls to Check_Elab_Call. This is because for internal calls, we
- -- need to wait to complete the check until all generic bodies have been
- -- instantiated. The Check_Elab_Calls procedure cleans up these waiting
- -- checks. It is called once after the completion of instantiation.
-
- procedure Check_Elab_Assign (N : Node_Id);
- -- N is either the left side of an assignment, or a procedure argument for
- -- a mode OUT or IN OUT formal. This procedure checks for a possible case
- -- of access to an entity from elaboration code before the entity has been
- -- initialized, and issues appropriate warnings.
-
- procedure Check_Elab_Instantiation
- (N : Node_Id;
- Outer_Scope : Entity_Id := Empty);
- -- Check an instantiation for possible elaboration problems. N is an
- -- instantiation node (N_Package_Instantiation, N_Function_Instantiation,
- -- or N_Procedure_Instantiation), and Outer_Scope indicates if this is
- -- an outer level call from Sem_Ch12 (Outer_Scope set to Empty), or an
- -- internal recursive call (Outer_Scope set to scope of outermost call,
- -- see body for further details). The returned value is relevant only
- -- for an outer level call, and is set to False if an elaboration error
- -- is bound to occur on the instantiation, and True otherwise. This is
- -- used by the caller to signal that the body of the instance should
- -- not be generated (see detailed description in body).
-
- procedure Check_Task_Activation (N : Node_Id);
- -- At the point at which tasks are activated in a package body, check
- -- that the bodies of the tasks are elaborated.
+ procedure Build_Call_Marker (N : Node_Id);
+ -- Create a call marker for call or requeue statement N and record it for
+ -- later processing by the ABE mechanism.
+
+ procedure Check_Elaboration_Scenarios;
+ -- Examine each scenario recorded during analysis/resolution and apply the
+ -- Ada or SPARK elaboration rules taking into account the model in effect.
+ -- This processing detects and diagnoses ABE issues, installs conditional
+ -- ABE checks or guaranteed ABE failures, and ensures the elaboration of
+ -- units.
+
+ -- The following type classifies the various enclosing levels used in ABE
+ -- diagnostics.
+
+ type Enclosing_Level_Kind is
+ (Declaration_Level,
+ -- A construct is at the "declaration level" when it appears within the
+ -- declarations of a block statement, an entry body, a subprogram body,
+ -- or a task body, ignoring enclosing packages. Example:
+
+ -- package Pack is
+ -- procedure Proc is -- subprogram body
+ -- package Nested is -- enclosing package ignored
+ -- X ... -- at declaration level
+
+ Generic_Package_Spec,
+ Generic_Package_Body,
+ -- A construct is at the "generic library level" when it appears in a
+ -- generic package library unit, ignoring enclosing packages. Example:
+
+ -- generic
+ -- package Pack is -- generic package spec
+ -- package Nested is -- enclosing package ignored
+ -- X ... -- at generic library level
+
+ Instantiation,
+ -- A construct is at the "instantiation library level" when it appears
+ -- in a library unit which is also an instantiation. Example:
+
+ -- package Inst is new Gen; -- at instantiation level
+
+ Package_Spec,
+ Package_Body,
+ -- A construct is at the "library level" when it appears in a package
+ -- library unit, ignoring enclosing packages. Example:
+
+ -- package body Pack is -- package body
+ -- package Nested is -- enclosing package ignored
+ -- X ... -- at library level
+
+ No_Level);
+ -- This value is used to indicate that none of the levels above are in
+ -- effect.
+
+ subtype Generic_Library_Level is Enclosing_Level_Kind range
+ Generic_Package_Spec ..
+ Generic_Package_Body;
+
+ subtype Library_Level is Enclosing_Level_Kind range
+ Package_Spec ..
+ Package_Body;
+
+ subtype Any_Library_Level is Enclosing_Level_Kind range
+ Generic_Package_Spec ..
+ Package_Body;
+
+ function Find_Enclosing_Level (N : Node_Id) return Enclosing_Level_Kind;
+ -- Determine the enclosing level of arbitrary node N
+
+ procedure Initialize;
+ -- Initialize the internal structures of this unit
+
+ procedure Kill_Elaboration_Scenario (N : Node_Id);
+ -- Determine whether arbitrary node N denotes a scenario which requires
+ -- ABE diagnostics or runtime checks and eliminate it from a region with
+ -- dead code.
+
+ procedure Record_Elaboration_Scenario (N : Node_Id);
+ -- Determine whether atribtray node N denotes a scenario which requires
+ -- ABE diagnostics or runtime checks. If this is the case, store N into
+ -- a table for later processing.
end Sem_Elab;
diff --git a/gcc/ada/sem_prag.adb b/gcc/ada/sem_prag.adb
index 417de92..eae1498 100644
--- a/gcc/ada/sem_prag.adb
+++ b/gcc/ada/sem_prag.adb
@@ -2818,10 +2818,16 @@ package body Sem_Prag is
E_Constant,
E_Variable)
then
+ -- When the initialization item is undefined, it appears as
+ -- Any_Id. Do not continue with the analysis of the item.
+
+ if Item_Id = Any_Id then
+ null;
+
-- The state or variable must be declared in the visible
-- declarations of the package (SPARK RM 7.1.5(7)).
- if not Contains (States_And_Objs, Item_Id) then
+ elsif not Contains (States_And_Objs, Item_Id) then
Error_Msg_Name_1 := Chars (Pack_Id);
SPARK_Msg_NE
("initialization item & must appear in the visible "
@@ -13219,7 +13225,7 @@ package body Sem_Prag is
Analyze (N);
raise Pragma_Exit;
- -- No other possibilities
+ -- No other possibilities
when others =>
raise Program_Error;
@@ -13236,23 +13242,21 @@ package body Sem_Prag is
Set_SCO_Pragma_Enabled (Loc);
end if;
- -- Deal with analyzing the string argument
+ -- Deal with analyzing the string argument. If checks are not
+ -- on we don't want any expansion (since such expansion would
+ -- not get properly deleted) but we do want to analyze (to get
+ -- proper references). The Preanalyze_And_Resolve routine does
+ -- just what we want. Ditto if pragma is active, because it will
+ -- be rewritten as an if-statement whose analysis will complete
+ -- analysis and expansion of the string message. This makes a
+ -- difference in the unusual case where the expression for the
+ -- string may have a side effect, such as raising an exception.
+ -- This is mandated by RM 11.4.2, which specifies that the string
+ -- expression is only evaluated if the check fails and
+ -- Assertion_Error is to be raised.
if Arg_Count = 3 then
-
- -- If checks are not on we don't want any expansion (since
- -- such expansion would not get properly deleted) but
- -- we do want to analyze (to get proper references).
- -- The Preanalyze_And_Resolve routine does just what we want
-
- if Is_Ignored (N) then
- Preanalyze_And_Resolve (Str, Standard_String);
-
- -- Otherwise we need a proper analysis and expansion
-
- else
- Analyze_And_Resolve (Str, Standard_String);
- end if;
+ Preanalyze_And_Resolve (Str, Standard_String);
end if;
-- Now you might think we could just do the same with the Boolean
@@ -14384,12 +14388,11 @@ package body Sem_Prag is
Call := Get_Pragma_Arg (Arg1);
end if;
- if Nkind_In (Call,
- N_Indexed_Component,
- N_Function_Call,
- N_Identifier,
- N_Expanded_Name,
- N_Selected_Component)
+ if Nkind_In (Call, N_Expanded_Name,
+ N_Function_Call,
+ N_Identifier,
+ N_Indexed_Component,
+ N_Selected_Component)
then
-- If this pragma Debug comes from source, its argument was
-- parsed as a name form (which is syntactically identical).
@@ -14999,26 +15002,6 @@ package body Sem_Prag is
Set_Elaborate_Present (Citem, True);
Set_Elab_Unit_Name (Get_Pragma_Arg (Arg), Name (Citem));
- -- With the pragma present, elaboration calls on
- -- subprograms from the named unit need no further
- -- checks, as long as the pragma appears in the current
- -- compilation unit. If the pragma appears in some unit
- -- in the context, there might still be a need for an
- -- Elaborate_All_Desirable from the current compilation
- -- to the named unit, so we keep the check enabled.
-
- if In_Extended_Main_Source_Unit (N) then
-
- -- This does not apply in SPARK mode, where we allow
- -- pragma Elaborate, but we don't trust it to be right
- -- so we will still insist on the Elaborate_All.
-
- if SPARK_Mode /= On then
- Set_Suppress_Elaboration_Warnings
- (Entity (Name (Citem)));
- end if;
- end if;
-
exit Inner;
end if;
@@ -15096,14 +15079,6 @@ package body Sem_Prag is
Set_Elaborate_All_Present (Citem, True);
Set_Elab_Unit_Name (Get_Pragma_Arg (Arg), Name (Citem));
- -- Suppress warnings and elaboration checks on the named
- -- unit if the pragma is in the current compilation, as
- -- for pragma Elaborate.
-
- if In_Extended_Main_Source_Unit (N) then
- Set_Suppress_Elaboration_Warnings
- (Entity (Name (Citem)));
- end if;
exit Innr;
end if;
@@ -15151,27 +15126,8 @@ package body Sem_Prag is
then
Error_Pragma ("pragma% must refer to a spec, not a body");
else
- Set_Body_Required (Cunit_Node, True);
+ Set_Body_Required (Cunit_Node);
Set_Has_Pragma_Elaborate_Body (Cunit_Ent);
-
- -- If we are in dynamic elaboration mode, then we suppress
- -- elaboration warnings for the unit, since it is definitely
- -- fine NOT to do dynamic checks at the first level (and such
- -- checks will be suppressed because no elaboration boolean
- -- is created for Elaborate_Body packages).
-
- -- But in the static model of elaboration, Elaborate_Body is
- -- definitely NOT good enough to ensure elaboration safety on
- -- its own, since the body may WITH other units that are not
- -- safe from an elaboration point of view, so a client must
- -- still do an Elaborate_All on such units.
-
- -- Debug flag -gnatdD restores the old behavior of 3.13, where
- -- Elaborate_Body always suppressed elab warnings.
-
- if Dynamic_Elaboration_Checks or Debug_Flag_DD then
- Set_Suppress_Elaboration_Warnings (Cunit_Ent);
- end if;
end if;
end Elaborate_Body;
@@ -20249,7 +20205,6 @@ package body Sem_Prag is
else
if not Debug_Flag_U then
Set_Is_Preelaborated (Ent);
- Set_Suppress_Elaboration_Warnings (Ent);
end if;
end if;
end if;
@@ -20877,7 +20832,6 @@ package body Sem_Prag is
if not Debug_Flag_U then
Set_Is_Pure (Ent);
Set_Has_Pragma_Pure (Ent);
- Set_Suppress_Elaboration_Warnings (Ent);
end if;
end Pure;
@@ -27448,7 +27402,7 @@ package body Sem_Prag is
-- Stop the compilation, as this leads to a multitude
-- of misleading cascaded errors.
- raise Program_Error;
+ raise Unrecoverable_Error;
end if;
-- The constituent is a valid state or object
diff --git a/gcc/ada/sem_prag.ads b/gcc/ada/sem_prag.ads
index ff4a1cb..33dbe48 100644
--- a/gcc/ada/sem_prag.ads
+++ b/gcc/ada/sem_prag.ads
@@ -175,6 +175,25 @@ package Sem_Prag is
Pragma_Warnings => True,
others => False);
+ -- The following table lists all pragmas which are significant in SPARK and
+ -- as a result get translated into verification conditions. The table is an
+ -- amalgamation of the pragmas listed in SPARK RM 16.1 and internally added
+ -- entries.
+
+ Pragma_Significant_In_SPARK : constant array (Pragma_Id) of Boolean :=
+ (Pragma_All_Calls_Remote => False,
+ Pragma_Asynchronous => False,
+ Pragma_Default_Storage_Pool => False,
+ Pragma_Discard_Names => False,
+ Pragma_Dispatching_Domain => False,
+ Pragma_Priority_Specific_Dispatching => False,
+ Pragma_Remote_Call_Interface => False,
+ Pragma_Remote_Types => False,
+ Pragma_Shared_Passive => False,
+ Pragma_Task_Dispatching_Policy => False,
+ Pragma_Warnings => False,
+ others => True);
+
-----------------
-- Subprograms --
-----------------
diff --git a/gcc/ada/sem_res.adb b/gcc/ada/sem_res.adb
index 6e83958..f5c5f9e 100644
--- a/gcc/ada/sem_res.adb
+++ b/gcc/ada/sem_res.adb
@@ -63,8 +63,8 @@ with Sem_Ch13; use Sem_Ch13;
with Sem_Dim; use Sem_Dim;
with Sem_Disp; use Sem_Disp;
with Sem_Dist; use Sem_Dist;
-with Sem_Elim; use Sem_Elim;
with Sem_Elab; use Sem_Elab;
+with Sem_Elim; use Sem_Elim;
with Sem_Eval; use Sem_Eval;
with Sem_Intr; use Sem_Intr;
with Sem_Util; use Sem_Util;
@@ -1325,6 +1325,12 @@ package body Sem_Res is
begin
Op_Node := New_Node (Operator_Kind (Op_Name, Is_Binary), Sloc (N));
+ -- Ensure that the corresponding operator has the same parent as the
+ -- original call. This guarantees that parent traversals performed by
+ -- the ABE mechanism succeed.
+
+ Set_Parent (Op_Node, Parent (N));
+
-- Binary operator
if Is_Binary then
@@ -1837,7 +1843,17 @@ package body Sem_Res is
-- Start of processing for Replace_Actual_Discriminants
begin
- if not Expander_Active then
+ if Expander_Active then
+ null;
+
+ -- Allow the replacement of concurrent discriminants in GNATprove even
+ -- though this is a light expansion activity. Note that generic units
+ -- are not modified.
+
+ elsif GNATprove_Mode and not Inside_A_Generic then
+ null;
+
+ else
return;
end if;
@@ -1848,9 +1864,7 @@ package body Sem_Res is
Tsk := Prefix (Prefix (Name (N)));
end if;
- if No (Tsk) then
- return;
- else
+ if Present (Tsk) then
Replace_Discrs (Default);
end if;
end Replace_Actual_Discriminants;
@@ -3002,6 +3016,14 @@ package body Sem_Res is
Resolve_Unchecked_Type_Conversion (N, Ctx_Type);
end case;
+ -- Mark relevant use-type and use-package clauses as effective using
+ -- the original node because constant folding may have occured and
+ -- removed references that need to be examined.
+
+ if Nkind (Original_Node (N)) in N_Op then
+ Mark_Use_Clauses (Original_Node (N));
+ end if;
+
-- Ada 2012 (AI05-0149): Apply an (implicit) conversion to an
-- expression of an anonymous access type that occurs in the context
-- of a named general access type, except when the expression is that
@@ -3054,7 +3076,14 @@ package body Sem_Res is
-- Here we are resolving the corresponding expanded body, so we do
-- need to perform normal freezing.
- Freeze_Expression (N);
+ -- As elsewhere we do not emit freeze node within a generic. We make
+ -- an exception for entities that are expressions, only to detect
+ -- misuses of deferred constants and preserve the output of various
+ -- tests.
+
+ if not Inside_A_Generic or else Is_Entity_Name (N) then
+ Freeze_Expression (N);
+ end if;
-- Now we can do the expansion
@@ -3149,14 +3178,6 @@ package body Sem_Res is
-- an instance of the default expression. The insertion is always
-- a named association.
- procedure Property_Error
- (Var : Node_Id;
- Var_Id : Entity_Id;
- Prop_Nam : Name_Id);
- -- Emit an error concerning variable Var with entity Var_Id that has
- -- enabled property Prop_Nam when it acts as an actual parameter in a
- -- call and the corresponding formal parameter is of mode IN.
-
function Same_Ancestor (T1, T2 : Entity_Id) return Boolean;
-- Check whether T1 and T2, or their full views, are derived from a
-- common type. Used to enforce the restrictions on array conversions
@@ -3561,6 +3582,7 @@ package body Sem_Res is
Rewrite (Actval,
Make_Raise_Constraint_Error (Loc,
Reason => CE_Range_Check_Failed));
+
Set_Raises_Constraint_Error (Actval);
Set_Etype (Actval, Etype (F));
end if;
@@ -3568,12 +3590,12 @@ package body Sem_Res is
Assoc :=
Make_Parameter_Association (Loc,
Explicit_Actual_Parameter => Actval,
- Selector_Name => Make_Identifier (Loc, Chars (F)));
+ Selector_Name => Make_Identifier (Loc, Chars (F)));
-- Case of insertion is first named actual
- if No (Prev) or else
- Nkind (Parent (Prev)) /= N_Parameter_Association
+ if No (Prev)
+ or else Nkind (Parent (Prev)) /= N_Parameter_Association
then
Set_Next_Named_Actual (Assoc, First_Named_Actual (N));
Set_First_Named_Actual (N, Actval);
@@ -3604,23 +3626,6 @@ package body Sem_Res is
Prev := Actval;
end Insert_Default;
- --------------------
- -- Property_Error --
- --------------------
-
- procedure Property_Error
- (Var : Node_Id;
- Var_Id : Entity_Id;
- Prop_Nam : Name_Id)
- is
- begin
- Error_Msg_Name_1 := Prop_Nam;
- Error_Msg_NE
- ("external variable & with enabled property % cannot appear as "
- & "actual in procedure call (SPARK RM 7.1.3(10))", Var, Var_Id);
- Error_Msg_N ("\\corresponding formal parameter has mode In", Var);
- end Property_Error;
-
-------------------
-- Same_Ancestor --
-------------------
@@ -4629,26 +4634,28 @@ package body Sem_Res is
Flag_Effectively_Volatile_Objects (A);
end if;
- -- Detect an external variable with an enabled property that
- -- does not match the mode of the corresponding formal in a
- -- procedure call. Functions are not considered because they
- -- cannot have effectively volatile formal parameters in the
- -- first place.
+ -- An effectively volatile variable cannot act as an actual
+ -- parameter in a procedure call when the variable has enabled
+ -- property Effective_Reads and the corresponding formal is of
+ -- mode IN (SPARK RM 7.1.3(10)).
if Ekind (Nam) = E_Procedure
and then Ekind (F) = E_In_Parameter
and then Is_Entity_Name (A)
- and then Present (Entity (A))
- and then Ekind (Entity (A)) = E_Variable
then
A_Id := Entity (A);
- if Async_Readers_Enabled (A_Id) then
- Property_Error (A, A_Id, Name_Async_Readers);
- elsif Effective_Reads_Enabled (A_Id) then
- Property_Error (A, A_Id, Name_Effective_Reads);
- elsif Effective_Writes_Enabled (A_Id) then
- Property_Error (A, A_Id, Name_Effective_Writes);
+ if Ekind (A_Id) = E_Variable
+ and then Is_Effectively_Volatile (Etype (A_Id))
+ and then Effective_Reads_Enabled (A_Id)
+ then
+ Error_Msg_NE
+ ("effectively volatile variable & cannot appear as "
+ & "actual in procedure call", A, A_Id);
+
+ Error_Msg_Name_1 := Name_Effective_Reads;
+ Error_Msg_N ("\\variable has enabled property %", A);
+ Error_Msg_N ("\\corresponding formal has mode IN", A);
end if;
end if;
end if;
@@ -4827,10 +4834,17 @@ package body Sem_Res is
-- are explicitly marked as coming from source but do not need to be
-- checked for limited initialization. To exclude this case, ensure
-- that the parent of the allocator is a source node.
+ -- The return statement constructed for an Expression_Function does
+ -- not come from source but requires a limited check.
if Is_Limited_Type (Etype (E))
and then Comes_From_Source (N)
- and then Comes_From_Source (Parent (N))
+ and then
+ (Comes_From_Source (Parent (N))
+ or else
+ (Ekind (Current_Scope) = E_Function
+ and then Nkind (Original_Node (Unit_Declaration_Node
+ (Current_Scope))) = N_Expression_Function))
and then not In_Instance_Body
then
if not OK_For_Limited_Init (Etype (E), Expression (E)) then
@@ -5761,6 +5775,15 @@ package body Sem_Res is
-- Start of processing for Resolve_Call
begin
+ -- Preserve relevant elaboration-related attributes of the context which
+ -- are no longer available or very expensive to recompute once analysis,
+ -- resolution, and expansion are over.
+
+ Mark_Elaboration_Attributes
+ (N_Id => N,
+ Checks => True,
+ Modes => True);
+
-- The context imposes a unique interpretation with type Typ on a
-- procedure or function call. Find the entity of the subprogram that
-- yields the expected type, and propagate the corresponding formal
@@ -5817,10 +5840,15 @@ package body Sem_Res is
elsif Nkind_In (Subp, N_Selected_Component, N_Indexed_Component)
or else (Is_Entity_Name (Subp)
- and then Ekind (Entity (Subp)) = E_Entry)
+ and then Ekind_In (Entity (Subp), E_Entry, E_Entry_Family))
then
Resolve_Entry_Call (N, Typ);
- Check_Elab_Call (N);
+
+ -- Annotate the tree by creating a call marker in case the original
+ -- call is transformed by expansion. The call marker is automatically
+ -- saved for later examination by the ABE Processing phase.
+
+ Build_Call_Marker (N);
-- Kill checks and constant values, as above for indirect case
-- Who knows what happens when another task is activated?
@@ -6076,14 +6104,14 @@ package body Sem_Res is
-- the proper indexed component.
Index_Node :=
- Make_Indexed_Component (Loc,
- Prefix =>
- Make_Function_Call (Loc,
- Name => New_Subp,
- Parameter_Associations =>
- New_List
- (Remove_Head (Parameter_Associations (N)))),
- Expressions => Parameter_Associations (N));
+ Make_Indexed_Component (Loc,
+ Prefix =>
+ Make_Function_Call (Loc,
+ Name => New_Subp,
+ Parameter_Associations =>
+ New_List
+ (Remove_Head (Parameter_Associations (N)))),
+ Expressions => Parameter_Associations (N));
end if;
-- Preserve the parenthesis count of the node
@@ -6098,7 +6126,13 @@ package body Sem_Res is
Set_Etype (Prefix (N), Ret_Type);
Set_Etype (N, Typ);
Resolve_Indexed_Component (N, Typ);
- Check_Elab_Call (Prefix (N));
+
+ -- Annotate the tree by creating a call marker in case
+ -- the original call is transformed by expansion. The call
+ -- marker is automatically saved for later examination by
+ -- the ABE Processing phase.
+
+ Build_Call_Marker (Prefix (N));
end if;
end if;
@@ -6609,7 +6643,12 @@ package body Sem_Res is
-- All done, evaluate call and deal with elaboration issues
Eval_Call (N);
- Check_Elab_Call (N);
+
+ -- Annotate the tree by creating a call marker in case the original call
+ -- is transformed by expansion. The call marker is automatically saved
+ -- for later examination by the ABE Processing phase.
+
+ Build_Call_Marker (N);
-- In GNATprove mode, expansion is disabled, but we want to inline some
-- subprograms to facilitate formal verification. Indirect calls through
@@ -6715,6 +6754,8 @@ package body Sem_Res is
end if;
end if;
+ Mark_Use_Clauses (Subp);
+
Warn_On_Overlapping_Actuals (Nam, N);
end Resolve_Call;
@@ -7150,7 +7191,7 @@ package body Sem_Res is
else
Error_Msg_N
- ("invalid use of subtype mark in expression or call", N);
+ ("invalid use of subtype mark in expression or call", N);
end if;
-- Check discriminant use if entity is discriminant in current scope,
@@ -7243,17 +7284,6 @@ package body Sem_Res is
& "(SPARK RM 7.1.3(12))", N);
end if;
- -- Check for possible elaboration issues with respect to reads of
- -- variables. The act of renaming the variable is not considered a
- -- read as it simply establishes an alias.
-
- if Ekind (E) = E_Variable
- and then Dynamic_Elaboration_Checks
- and then Nkind (Par) /= N_Object_Renaming_Declaration
- then
- Check_Elab_Call (N);
- end if;
-
-- The variable may eventually become a constituent of a single
-- protected/task type. Record the reference now and verify its
-- legality when analyzing the contract of the variable
@@ -7270,6 +7300,8 @@ package body Sem_Res is
Check_Ghost_Context (E, N);
end if;
end if;
+
+ Mark_Use_Clauses (E);
end Resolve_Entity_Name;
-------------------
@@ -7474,6 +7506,12 @@ package body Sem_Res is
Index := First (Expressions (Entry_Name));
Resolve (Index, Entry_Index_Type (Nam));
+ -- Generate a reference for the index when it denotes an entity
+
+ if Is_Entity_Name (Index) then
+ Generate_Reference (Entity (Index), Nam);
+ end if;
+
-- Up to this point the expression could have been the actual in a
-- simple entry call, and be given by a named association.
@@ -7490,14 +7528,13 @@ package body Sem_Res is
------------------------
procedure Resolve_Entry_Call (N : Node_Id; Typ : Entity_Id) is
- Entry_Name : constant Node_Id := Name (N);
- Loc : constant Source_Ptr := Sloc (Entry_Name);
- Actuals : List_Id;
- First_Named : Node_Id;
- Nam : Entity_Id;
- Norm_OK : Boolean;
- Obj : Node_Id;
- Was_Over : Boolean;
+ Entry_Name : constant Node_Id := Name (N);
+ Loc : constant Source_Ptr := Sloc (Entry_Name);
+
+ Nam : Entity_Id;
+ Norm_OK : Boolean;
+ Obj : Node_Id;
+ Was_Over : Boolean;
begin
-- We kill all checks here, because it does not seem worth the effort to
@@ -7611,7 +7648,6 @@ package body Sem_Res is
and then Present (Contract_Wrapper (Nam))
and then Current_Scope /= Contract_Wrapper (Nam)
then
-
-- Note the entity being called before rewriting the call, so that
-- it appears used at this point.
@@ -7726,16 +7762,29 @@ package body Sem_Res is
Entry_Name);
end if;
- Actuals := Parameter_Associations (N);
- First_Named := First_Named_Actual (N);
+ declare
+ Entry_Call : Node_Id;
+
+ begin
+ Entry_Call :=
+ Make_Entry_Call_Statement (Loc,
+ Name => Entry_Name,
+ Parameter_Associations => Parameter_Associations (N));
- Rewrite (N,
- Make_Entry_Call_Statement (Loc,
- Name => Entry_Name,
- Parameter_Associations => Actuals));
+ -- Inherit relevant attributes from the original call
- Set_First_Named_Actual (N, First_Named);
- Set_Analyzed (N, True);
+ Set_First_Named_Actual
+ (Entry_Call, First_Named_Actual (N));
+
+ Set_Is_Elaboration_Checks_OK_Node
+ (Entry_Call, Is_Elaboration_Checks_OK_Node (N));
+
+ Set_Is_SPARK_Mode_On_Node
+ (Entry_Call, Is_SPARK_Mode_On_Node (N));
+
+ Rewrite (N, Entry_Call);
+ Set_Analyzed (N, True);
+ end;
-- Protected functions can return on the secondary stack, in which
-- case we must trigger the transient scope mechanism.
diff --git a/gcc/ada/sem_spark.adb b/gcc/ada/sem_spark.adb
index 8c81d2e..5107d3b 100644
--- a/gcc/ada/sem_spark.adb
+++ b/gcc/ada/sem_spark.adb
@@ -2314,6 +2314,7 @@ package body Sem_SPARK is
when N_Abstract_Subprogram_Declaration
| N_At_Clause
| N_Attribute_Definition_Clause
+ | N_Call_Marker
| N_Delta_Constraint
| N_Digits_Constraint
| N_Empty
@@ -5285,6 +5286,7 @@ package body Sem_SPARK is
is
begin
case Nkind (N) is
+
-- Base identifier. Set permission to W or No depending on Mode.
when N_Identifier
@@ -5292,9 +5294,8 @@ package body Sem_SPARK is
=>
declare
P : constant Node_Id := Entity (N);
-
C : constant Perm_Tree_Access :=
- Get (Current_Perm_Env, Unique_Entity (P));
+ Get (Current_Perm_Env, Unique_Entity (P));
begin
-- The base tree can be RW (first move from this base path) or
diff --git a/gcc/ada/sem_type.adb b/gcc/ada/sem_type.adb
index c70d892..e2b3afd 100644
--- a/gcc/ada/sem_type.adb
+++ b/gcc/ada/sem_type.adb
@@ -761,15 +761,19 @@ package body Sem_Type is
function Full_View_Covers (Typ1, Typ2 : Entity_Id) return Boolean is
begin
- return
- Is_Private_Type (Typ1)
- and then
- ((Present (Full_View (Typ1))
- and then Covers (Full_View (Typ1), Typ2))
- or else (Present (Underlying_Full_View (Typ1))
- and then Covers (Underlying_Full_View (Typ1), Typ2))
- or else Base_Type (Typ1) = Typ2
- or else Base_Type (Typ2) = Typ1);
+ if Present (Full_View (Typ1))
+ and then Covers (Full_View (Typ1), Typ2)
+ then
+ return True;
+
+ elsif Present (Underlying_Full_View (Typ1))
+ and then Covers (Underlying_Full_View (Typ1), Typ2)
+ then
+ return True;
+
+ else
+ return False;
+ end if;
end Full_View_Covers;
-----------------
@@ -825,7 +829,7 @@ package body Sem_Type is
-- Standard_Void_Type is a special entity that has some, but not all,
-- properties of types.
- if (T1 = Standard_Void_Type) /= (T2 = Standard_Void_Type) then
+ if T1 = Standard_Void_Type or else T2 = Standard_Void_Type then
return False;
end if;
@@ -892,8 +896,8 @@ package body Sem_Type is
or else (T2 = Universal_Real and then Is_Real_Type (T1))
or else (T2 = Universal_Fixed and then Is_Fixed_Point_Type (T1))
or else (T2 = Any_Fixed and then Is_Fixed_Point_Type (T1))
- or else (T2 = Any_String and then Is_String_Type (T1))
or else (T2 = Any_Character and then Is_Character_Type (T1))
+ or else (T2 = Any_String and then Is_String_Type (T1))
or else (T2 = Any_Access and then Is_Access_Type (T1))
then
return True;
@@ -916,9 +920,9 @@ package body Sem_Type is
-- task_type or protected_type that implements the interface.
elsif Ada_Version >= Ada_2005
+ and then Is_Concurrent_Type (T2)
and then Is_Class_Wide_Type (T1)
and then Is_Interface (Etype (T1))
- and then Is_Concurrent_Type (T2)
and then Interface_Present_In_Ancestor
(Typ => BT2, Iface => Etype (T1))
then
@@ -928,9 +932,9 @@ package body Sem_Type is
-- object T2 implementing T1.
elsif Ada_Version >= Ada_2005
+ and then Is_Tagged_Type (T2)
and then Is_Class_Wide_Type (T1)
and then Is_Interface (Etype (T1))
- and then Is_Tagged_Type (T2)
then
if Interface_Present_In_Ancestor (Typ => T2,
Iface => Etype (T1))
@@ -1183,19 +1187,16 @@ package body Sem_Type is
-- whether a partial and a full view match. Verify that types are
-- legal, to prevent cascaded errors.
- elsif In_Instance
- and then (Full_View_Covers (T1, T2) or else Full_View_Covers (T2, T1))
- then
- return True;
-
- elsif Is_Type (T2)
- and then Is_Generic_Actual_Type (T2)
+ elsif Is_Private_Type (T1)
+ and then (In_Instance
+ or else (Is_Type (T2) and then Is_Generic_Actual_Type (T2)))
and then Full_View_Covers (T1, T2)
then
return True;
- elsif Is_Type (T1)
- and then Is_Generic_Actual_Type (T1)
+ elsif Is_Private_Type (T2)
+ and then (In_Instance
+ or else (Is_Type (T1) and then Is_Generic_Actual_Type (T1)))
and then Full_View_Covers (T2, T1)
then
return True;
@@ -2837,11 +2838,9 @@ package body Sem_Type is
return False;
elsif Nkind (Par) in N_Declaration then
- if Nkind (Par) = N_Object_Declaration then
- return Present (Corresponding_Generic_Association (Par));
- else
- return False;
- end if;
+ return
+ Nkind (Par) = N_Object_Declaration
+ and then Present (Corresponding_Generic_Association (Par));
elsif Nkind (Par) = N_Object_Renaming_Declaration then
return Present (Corresponding_Generic_Association (Par));
diff --git a/gcc/ada/sem_util.adb b/gcc/ada/sem_util.adb
index 0b73112..3698bbf 100644
--- a/gcc/ada/sem_util.adb
+++ b/gcc/ada/sem_util.adb
@@ -53,6 +53,7 @@ with Sem_Attr; use Sem_Attr;
with Sem_Ch6; use Sem_Ch6;
with Sem_Ch8; use Sem_Ch8;
with Sem_Disp; use Sem_Disp;
+with Sem_Elab; use Sem_Elab;
with Sem_Eval; use Sem_Eval;
with Sem_Prag; use Sem_Prag;
with Sem_Res; use Sem_Res;
@@ -941,6 +942,45 @@ package body Sem_Util is
and then not In_Same_Extended_Unit (N, T);
end Bad_Unordered_Enumeration_Reference;
+ ----------------------------
+ -- Begin_Keyword_Location --
+ ----------------------------
+
+ function Begin_Keyword_Location (N : Node_Id) return Source_Ptr is
+ HSS : Node_Id;
+
+ begin
+ pragma Assert (Nkind_In (N, N_Block_Statement,
+ N_Entry_Body,
+ N_Package_Body,
+ N_Subprogram_Body,
+ N_Task_Body));
+
+ HSS := Handled_Statement_Sequence (N);
+
+ -- When the handled sequence of statements comes from source, the
+ -- location of the "begin" keyword is that of the sequence itself.
+ -- Note that an internal construct may inherit a source sequence.
+
+ if Comes_From_Source (HSS) then
+ return Sloc (HSS);
+
+ -- The parser generates an internal handled sequence of statements to
+ -- capture the location of the "begin" keyword if present in the source.
+ -- Since there are no source statements, the location of the "begin"
+ -- keyword is effectively that of the "end" keyword.
+
+ elsif Comes_From_Source (N) then
+ return Sloc (HSS);
+
+ -- Otherwise the construct is internal and should carry the location of
+ -- the original construct which prompted its creation.
+
+ else
+ return Sloc (N);
+ end if;
+ end Begin_Keyword_Location;
+
--------------------------
-- Build_Actual_Subtype --
--------------------------
@@ -3138,34 +3178,10 @@ package body Sem_Util is
---------------------------
procedure Check_No_Hidden_State (Id : Entity_Id) is
- function Has_Null_Abstract_State (Pkg : Entity_Id) return Boolean;
- -- Determine whether the entity of a package denoted by Pkg has a null
- -- abstract state.
-
- -----------------------------
- -- Has_Null_Abstract_State --
- -----------------------------
-
- function Has_Null_Abstract_State (Pkg : Entity_Id) return Boolean is
- States : constant Elist_Id := Abstract_States (Pkg);
-
- begin
- -- Check first available state of related package. A null abstract
- -- state always appears as the sole element of the state list.
-
- return
- Present (States)
- and then Is_Null_State (Node (First_Elmt (States)));
- end Has_Null_Abstract_State;
-
- -- Local variables
-
Context : Entity_Id := Empty;
Not_Visible : Boolean := False;
Scop : Entity_Id;
- -- Start of processing for Check_No_Hidden_State
-
begin
pragma Assert (Ekind_In (Id, E_Abstract_State, E_Variable));
@@ -3338,10 +3354,13 @@ package body Sem_Util is
and then not Comes_From_Source (Par)
then
-- Continue to examine the context if the reference appears in a
- -- subprogram body which was previously an expression function.
+ -- subprogram body which was previously an expression function,
+ -- unless this is during preanalysis (when In_Spec_Expression is
+ -- True), as the body may not yet be inserted in the tree.
if Nkind (Par) = N_Subprogram_Body
and then Was_Expression_Function (Par)
+ and then not In_Spec_Expression
then
null;
@@ -5784,11 +5803,10 @@ package body Sem_Util is
---------------------
function Defining_Entity
- (N : Node_Id;
- Empty_On_Errors : Boolean := False) return Entity_Id
+ (N : Node_Id;
+ Empty_On_Errors : Boolean := False;
+ Concurrent_Subunit : Boolean := False) return Entity_Id
is
- Err : Entity_Id := Empty;
-
begin
case Nkind (N) is
when N_Abstract_Subprogram_Declaration
@@ -5840,7 +5858,23 @@ package body Sem_Util is
return Defining_Identifier (N);
when N_Subunit =>
- return Defining_Entity (Proper_Body (N));
+ declare
+ Bod : constant Node_Id := Proper_Body (N);
+ Orig_Bod : constant Node_Id := Original_Node (Bod);
+
+ begin
+ -- Retrieve the entity of the original protected or task body
+ -- if requested by the caller.
+
+ if Concurrent_Subunit
+ and then Nkind (Bod) = N_Null_Statement
+ and then Nkind_In (Orig_Bod, N_Protected_Body, N_Task_Body)
+ then
+ return Defining_Entity (Orig_Bod);
+ else
+ return Defining_Entity (Bod);
+ end if;
+ end;
when N_Function_Instantiation
| N_Function_Specification
@@ -5856,6 +5890,7 @@ package body Sem_Util is
=>
declare
Nam : constant Node_Id := Defining_Unit_Name (N);
+ Err : Entity_Id := Empty;
begin
if Nkind (Nam) in N_Entity then
@@ -6886,6 +6921,82 @@ package body Sem_Util is
end if;
end Enclosing_Subprogram;
+ --------------------------
+ -- End_Keyword_Location --
+ --------------------------
+
+ function End_Keyword_Location (N : Node_Id) return Source_Ptr is
+ function End_Label_Loc (Nod : Node_Id) return Source_Ptr;
+ -- Return the source location of Nod's end label according to the
+ -- following precedence rules:
+ --
+ -- 1) If the end label exists, return its location
+ -- 2) If Nod exists, return its location
+ -- 3) Return the location of N
+
+ -------------------
+ -- End_Label_Loc --
+ -------------------
+
+ function End_Label_Loc (Nod : Node_Id) return Source_Ptr is
+ Label : Node_Id;
+
+ begin
+ if Present (Nod) then
+ Label := End_Label (Nod);
+
+ if Present (Label) then
+ return Sloc (Label);
+ else
+ return Sloc (Nod);
+ end if;
+
+ else
+ return Sloc (N);
+ end if;
+ end End_Label_Loc;
+
+ -- Local variables
+
+ Owner : Node_Id;
+
+ -- Start of processing for End_Keyword_Location
+
+ begin
+ if Nkind_In (N, N_Block_Statement,
+ N_Entry_Body,
+ N_Package_Body,
+ N_Subprogram_Body,
+ N_Task_Body)
+ then
+ Owner := Handled_Statement_Sequence (N);
+
+ elsif Nkind (N) = N_Package_Declaration then
+ Owner := Specification (N);
+
+ elsif Nkind (N) = N_Protected_Body then
+ Owner := N;
+
+ elsif Nkind_In (N, N_Protected_Type_Declaration,
+ N_Single_Protected_Declaration)
+ then
+ Owner := Protected_Definition (N);
+
+ elsif Nkind_In (N, N_Single_Task_Declaration,
+ N_Task_Type_Declaration)
+ then
+ Owner := Task_Definition (N);
+
+ -- This routine should not be called with other contexts
+
+ else
+ pragma Assert (False);
+ null;
+ end if;
+
+ return End_Label_Loc (Owner);
+ end End_Keyword_Location;
+
------------------------
-- Ensure_Freeze_Node --
------------------------
@@ -7759,6 +7870,101 @@ package body Sem_Util is
return Empty;
end Find_Enclosing_Iterator_Loop;
+ --------------------------
+ -- Find_Enclosing_Scope --
+ --------------------------
+
+ function Find_Enclosing_Scope (N : Node_Id) return Entity_Id is
+ Par : Node_Id;
+ Spec_Id : Entity_Id;
+
+ begin
+ -- Examine the parent chain looking for a construct which defines a
+ -- scope.
+
+ Par := Parent (N);
+ while Present (Par) loop
+ case Nkind (Par) is
+
+ -- The construct denotes a declaration, the proper scope is its
+ -- entity.
+
+ when N_Entry_Declaration
+ | N_Expression_Function
+ | N_Full_Type_Declaration
+ | N_Generic_Package_Declaration
+ | N_Generic_Subprogram_Declaration
+ | N_Package_Declaration
+ | N_Private_Extension_Declaration
+ | N_Protected_Type_Declaration
+ | N_Single_Protected_Declaration
+ | N_Single_Task_Declaration
+ | N_Subprogram_Declaration
+ | N_Task_Type_Declaration
+ =>
+ return Defining_Entity (Par);
+
+ -- The construct denotes a body, the proper scope is the entity of
+ -- the corresponding spec.
+
+ when N_Entry_Body
+ | N_Package_Body
+ | N_Protected_Body
+ | N_Subprogram_Body
+ | N_Task_Body
+ =>
+ Spec_Id := Corresponding_Spec (Par);
+
+ -- The defining entity of a stand-alone subprogram body defines
+ -- a scope.
+
+ if Nkind (Par) = N_Subprogram_Body and then No (Spec_Id) then
+ return Defining_Entity (Par);
+
+ -- Otherwise there should be corresponding spec which defines a
+ -- scope.
+
+ else
+ pragma Assert (Present (Spec_Id));
+
+ return Spec_Id;
+ end if;
+
+ -- Special cases
+
+ -- Blocks carry either a source or an internally-generated scope,
+ -- unless the block is a byproduct of exception handling.
+
+ when N_Block_Statement =>
+ if not Exception_Junk (Par) then
+ return Entity (Identifier (Par));
+ end if;
+
+ -- Loops carry an internally-generated scope
+
+ when N_Loop_Statement =>
+ return Entity (Identifier (Par));
+
+ -- Extended return statements carry an internally-generated scope
+
+ when N_Extended_Return_Statement =>
+ return Return_Statement_Entity (Par);
+
+ -- A traversal from a subunit continues via the corresponding stub
+
+ when N_Subunit =>
+ Par := Corresponding_Stub (Par);
+
+ when others =>
+ null;
+ end case;
+
+ Par := Parent (Par);
+ end loop;
+
+ return Standard_Standard;
+ end Find_Enclosing_Scope;
+
------------------------------------
-- Find_Loop_In_Conditional_Block --
------------------------------------
@@ -9417,7 +9623,7 @@ package body Sem_Util is
-- Get_Task_Body_Procedure --
-----------------------------
- function Get_Task_Body_Procedure (E : Entity_Id) return Node_Id is
+ function Get_Task_Body_Procedure (E : Entity_Id) return Entity_Id is
begin
-- Note: A task type may be the completion of a private type with
-- discriminants. When performing elaboration checks on a task
@@ -10547,12 +10753,14 @@ package body Sem_Util is
-- Has_Non_Trivial_Precondition --
----------------------------------
- function Has_Non_Trivial_Precondition (P : Entity_Id) return Boolean is
- Cont : constant Node_Id := Find_Aspect (P, Aspect_Pre);
+ function Has_Non_Trivial_Precondition (Subp : Entity_Id) return Boolean is
+ Pre : constant Node_Id := Find_Aspect (Subp, Aspect_Pre);
+
begin
- return Present (Cont)
- and then Class_Present (Cont)
- and then not Is_Entity_Name (Expression (Cont));
+ return
+ Present (Pre)
+ and then Class_Present (Pre)
+ and then not Is_Entity_Name (Expression (Pre));
end Has_Non_Trivial_Precondition;
-------------------
@@ -10793,160 +11001,6 @@ package body Sem_Util is
Ent : Entity_Id;
Exp : Node_Id;
- function Is_Preelaborable_Expression (N : Node_Id) return Boolean;
- -- Returns True if and only if the expression denoted by N does not
- -- violate restrictions on preelaborable constructs (RM-10.2.1(5-9)).
-
- ---------------------------------
- -- Is_Preelaborable_Expression --
- ---------------------------------
-
- function Is_Preelaborable_Expression (N : Node_Id) return Boolean is
- Exp : Node_Id;
- Assn : Node_Id;
- Choice : Node_Id;
- Comp_Type : Entity_Id;
- Is_Array_Aggr : Boolean;
-
- begin
- if Is_OK_Static_Expression (N) then
- return True;
-
- elsif Nkind (N) = N_Null then
- return True;
-
- -- Attributes are allowed in general, even if their prefix is a
- -- formal type. (It seems that certain attributes known not to be
- -- static might not be allowed, but there are no rules to prevent
- -- them.)
-
- elsif Nkind (N) = N_Attribute_Reference then
- return True;
-
- -- The name of a discriminant evaluated within its parent type is
- -- defined to be preelaborable (10.2.1(8)). Note that we test for
- -- names that denote discriminals as well as discriminants to
- -- catch references occurring within init procs.
-
- elsif Is_Entity_Name (N)
- and then
- (Ekind (Entity (N)) = E_Discriminant
- or else (Ekind_In (Entity (N), E_Constant, E_In_Parameter)
- and then Present (Discriminal_Link (Entity (N)))))
- then
- return True;
-
- elsif Nkind (N) = N_Qualified_Expression then
- return Is_Preelaborable_Expression (Expression (N));
-
- -- For aggregates we have to check that each of the associations
- -- is preelaborable.
-
- elsif Nkind_In (N, N_Aggregate, N_Extension_Aggregate) then
- Is_Array_Aggr := Is_Array_Type (Etype (N));
-
- if Is_Array_Aggr then
- Comp_Type := Component_Type (Etype (N));
- end if;
-
- -- Check the ancestor part of extension aggregates, which must
- -- be either the name of a type that has preelaborable init or
- -- an expression that is preelaborable.
-
- if Nkind (N) = N_Extension_Aggregate then
- declare
- Anc_Part : constant Node_Id := Ancestor_Part (N);
-
- begin
- if Is_Entity_Name (Anc_Part)
- and then Is_Type (Entity (Anc_Part))
- then
- if not Has_Preelaborable_Initialization
- (Entity (Anc_Part))
- then
- return False;
- end if;
-
- elsif not Is_Preelaborable_Expression (Anc_Part) then
- return False;
- end if;
- end;
- end if;
-
- -- Check positional associations
-
- Exp := First (Expressions (N));
- while Present (Exp) loop
- if not Is_Preelaborable_Expression (Exp) then
- return False;
- end if;
-
- Next (Exp);
- end loop;
-
- -- Check named associations
-
- Assn := First (Component_Associations (N));
- while Present (Assn) loop
- Choice := First (Choices (Assn));
- while Present (Choice) loop
- if Is_Array_Aggr then
- if Nkind (Choice) = N_Others_Choice then
- null;
-
- elsif Nkind (Choice) = N_Range then
- if not Is_OK_Static_Range (Choice) then
- return False;
- end if;
-
- elsif not Is_OK_Static_Expression (Choice) then
- return False;
- end if;
-
- else
- Comp_Type := Etype (Choice);
- end if;
-
- Next (Choice);
- end loop;
-
- -- If the association has a <> at this point, then we have
- -- to check whether the component's type has preelaborable
- -- initialization. Note that this only occurs when the
- -- association's corresponding component does not have a
- -- default expression, the latter case having already been
- -- expanded as an expression for the association.
-
- if Box_Present (Assn) then
- if not Has_Preelaborable_Initialization (Comp_Type) then
- return False;
- end if;
-
- -- In the expression case we check whether the expression
- -- is preelaborable.
-
- elsif
- not Is_Preelaborable_Expression (Expression (Assn))
- then
- return False;
- end if;
-
- Next (Assn);
- end loop;
-
- -- If we get here then aggregate as a whole is preelaborable
-
- return True;
-
- -- All other cases are not preelaborable
-
- else
- return False;
- end if;
- end Is_Preelaborable_Expression;
-
- -- Start of processing for Check_Components
-
begin
-- Loop through entities of record or protected type
@@ -10993,7 +11047,7 @@ package body Sem_Util is
-- Require the default expression to be preelaborable
- elsif not Is_Preelaborable_Expression (Exp) then
+ elsif not Is_Preelaborable_Construct (Exp) then
Has_PE := False;
exit;
end if;
@@ -11738,21 +11792,23 @@ package body Sem_Util is
-- In_Instance_Visible_Part --
------------------------------
- function In_Instance_Visible_Part return Boolean is
- S : Entity_Id;
+ function In_Instance_Visible_Part
+ (Id : Entity_Id := Current_Scope) return Boolean
+ is
+ Inst : Entity_Id;
begin
- S := Current_Scope;
- while Present (S) and then S /= Standard_Standard loop
- if Ekind (S) = E_Package
- and then Is_Generic_Instance (S)
- and then not In_Package_Body (S)
- and then not In_Private_Part (S)
+ Inst := Id;
+ while Present (Inst) and then Inst /= Standard_Standard loop
+ if Ekind (Inst) = E_Package
+ and then Is_Generic_Instance (Inst)
+ and then not In_Package_Body (Inst)
+ and then not In_Private_Part (Inst)
then
return True;
end if;
- S := Scope (S);
+ Inst := Scope (Inst);
end loop;
return False;
@@ -11911,7 +11967,7 @@ package body Sem_Util is
-- In_Subtree --
----------------
- function In_Subtree (Root : Node_Id; N : Node_Id) return Boolean is
+ function In_Subtree (N : Node_Id; Root : Node_Id) return Boolean is
Curr : Node_Id;
begin
@@ -11927,6 +11983,30 @@ package body Sem_Util is
return False;
end In_Subtree;
+ ----------------
+ -- In_Subtree --
+ ----------------
+
+ function In_Subtree
+ (N : Node_Id;
+ Root1 : Node_Id;
+ Root2 : Node_Id) return Boolean
+ is
+ Curr : Node_Id;
+
+ begin
+ Curr := N;
+ while Present (Curr) loop
+ if Curr = Root1 or else Curr = Root2 then
+ return True;
+ end if;
+
+ Curr := Parent (Curr);
+ end loop;
+
+ return False;
+ end In_Subtree;
+
---------------------
-- In_Visible_Part --
---------------------
@@ -12468,10 +12548,8 @@ package body Sem_Util is
or else (Present (Renamed_Object (E))
and then Is_Aliased_View (Renamed_Object (E)))))
- or else ((Is_Formal (E)
- or else Ekind_In (E, E_Generic_In_Out_Parameter,
- E_Generic_In_Parameter))
- and then Is_Tagged_Type (Etype (E)))
+ or else ((Is_Formal (E) or else Is_Formal_Object (E))
+ and then Is_Tagged_Type (Etype (E)))
or else (Is_Concurrent_Type (E) and then In_Open_Scopes (E))
@@ -13108,17 +13186,29 @@ package body Sem_Util is
function Is_Controlling_Limited_Procedure
(Proc_Nam : Entity_Id) return Boolean
is
+ Param : Node_Id;
Param_Typ : Entity_Id := Empty;
begin
if Ekind (Proc_Nam) = E_Procedure
and then Present (Parameter_Specifications (Parent (Proc_Nam)))
then
- Param_Typ := Etype (Parameter_Type (First (
- Parameter_Specifications (Parent (Proc_Nam)))));
+ Param := Parameter_Type (First (
+ Parameter_Specifications (Parent (Proc_Nam))));
+
+ -- The formal may be an anonymous access type.
+
+ if Nkind (Param) = N_Access_Definition then
+ Param_Typ := Entity (Subtype_Mark (Param));
+
+ else
+ Param_Typ := Etype (Param);
+ end if;
- -- In this case where an Itype was created, the procedure call has been
- -- rewritten.
+ -- In the case where an Itype was created for a dispatchin call, the
+ -- procedure call has been rewritten. The actual may be an access to
+ -- interface type in which case it is the designated type that is the
+ -- controlling type.
elsif Present (Associated_Node_For_Itype (Proc_Nam))
and then Present (Original_Node (Associated_Node_For_Itype (Proc_Nam)))
@@ -13129,6 +13219,10 @@ package body Sem_Util is
Param_Typ :=
Etype (First (Parameter_Associations
(Associated_Node_For_Itype (Proc_Nam))));
+
+ if Ekind (Param_Typ) = E_Anonymous_Access_Type then
+ Param_Typ := Directly_Designated_Type (Param_Typ);
+ end if;
end if;
if Present (Param_Typ) then
@@ -13310,7 +13404,7 @@ package body Sem_Util is
end if;
-- A discriminant check on a selected component may be expanded
- -- into a dereference when removing side-effects. Recover the
+ -- into a dereference when removing side effects. Recover the
-- original node and its type, which may be unconstrained.
elsif Nkind (P) = N_Explicit_Dereference
@@ -15311,6 +15405,162 @@ package body Sem_Util is
end if;
end Is_Potentially_Unevaluated;
+ --------------------------------
+ -- Is_Preelaborable_Aggregate --
+ --------------------------------
+
+ function Is_Preelaborable_Aggregate (Aggr : Node_Id) return Boolean is
+ Aggr_Typ : constant Entity_Id := Etype (Aggr);
+ Array_Aggr : constant Boolean := Is_Array_Type (Aggr_Typ);
+
+ Anc_Part : Node_Id;
+ Assoc : Node_Id;
+ Choice : Node_Id;
+ Comp_Typ : Entity_Id;
+ Expr : Node_Id;
+
+ begin
+ if Array_Aggr then
+ Comp_Typ := Component_Type (Aggr_Typ);
+ end if;
+
+ -- Inspect the ancestor part
+
+ if Nkind (Aggr) = N_Extension_Aggregate then
+ Anc_Part := Ancestor_Part (Aggr);
+
+ -- The ancestor denotes a subtype mark
+
+ if Is_Entity_Name (Anc_Part)
+ and then Is_Type (Entity (Anc_Part))
+ then
+ if not Has_Preelaborable_Initialization (Entity (Anc_Part)) then
+ return False;
+ end if;
+
+ -- Otherwise the ancestor denotes an expression
+
+ elsif not Is_Preelaborable_Construct (Anc_Part) then
+ return False;
+ end if;
+ end if;
+
+ -- Inspect the positional associations
+
+ Expr := First (Expressions (Aggr));
+ while Present (Expr) loop
+ if not Is_Preelaborable_Construct (Expr) then
+ return False;
+ end if;
+
+ Next (Expr);
+ end loop;
+
+ -- Inspect the named associations
+
+ Assoc := First (Component_Associations (Aggr));
+ while Present (Assoc) loop
+
+ -- Inspect the choices of the current named association
+
+ Choice := First (Choices (Assoc));
+ while Present (Choice) loop
+ if Array_Aggr then
+
+ -- For a choice to be preelaborable, it must denote either a
+ -- static range or a static expression.
+
+ if Nkind (Choice) = N_Others_Choice then
+ null;
+
+ elsif Nkind (Choice) = N_Range then
+ if not Is_OK_Static_Range (Choice) then
+ return False;
+ end if;
+
+ elsif not Is_OK_Static_Expression (Choice) then
+ return False;
+ end if;
+
+ else
+ Comp_Typ := Etype (Choice);
+ end if;
+
+ Next (Choice);
+ end loop;
+
+ -- The type of the choice must have preelaborable initialization if
+ -- the association carries a <>.
+
+ if Box_Present (Assoc) then
+ if not Has_Preelaborable_Initialization (Comp_Typ) then
+ return False;
+ end if;
+
+ -- The type of the expression must have preelaborable initialization
+
+ elsif not Is_Preelaborable_Construct (Expression (Assoc)) then
+ return False;
+ end if;
+
+ Next (Assoc);
+ end loop;
+
+ -- At this point the aggregate is preelaborable
+
+ return True;
+ end Is_Preelaborable_Aggregate;
+
+ --------------------------------
+ -- Is_Preelaborable_Construct --
+ --------------------------------
+
+ function Is_Preelaborable_Construct (N : Node_Id) return Boolean is
+ begin
+ -- Aggregates
+
+ if Nkind_In (N, N_Aggregate, N_Extension_Aggregate) then
+ return Is_Preelaborable_Aggregate (N);
+
+ -- Attributes are allowed in general, even if their prefix is a formal
+ -- type. It seems that certain attributes known not to be static might
+ -- not be allowed, but there are no rules to prevent them.
+
+ elsif Nkind (N) = N_Attribute_Reference then
+ return True;
+
+ -- Expressions
+
+ elsif Nkind (N) in N_Subexpr and then Is_OK_Static_Expression (N) then
+ return True;
+
+ elsif Nkind (N) = N_Qualified_Expression then
+ return Is_Preelaborable_Construct (Expression (N));
+
+ -- Names are preelaborable when they denote a discriminant of an
+ -- enclosing type. Discriminals are also considered for this check.
+
+ elsif Is_Entity_Name (N)
+ and then Present (Entity (N))
+ and then
+ (Ekind (Entity (N)) = E_Discriminant
+ or else (Ekind_In (Entity (N), E_Constant, E_In_Parameter)
+ and then Present (Discriminal_Link (Entity (N)))))
+ then
+ return True;
+
+ -- Statements
+
+ elsif Nkind (N) = N_Null then
+ return True;
+
+ -- Otherwise the construct is not preelaborable
+
+ else
+ return False;
+ end if;
+ end Is_Preelaborable_Construct;
+
---------------------------------
-- Is_Protected_Self_Reference --
---------------------------------
@@ -16965,6 +17215,306 @@ package body Sem_Util is
return N;
end Last_Source_Statement;
+ -----------------------
+ -- Mark_Coextensions --
+ -----------------------
+
+ procedure Mark_Coextensions (Context_Nod : Node_Id; Root_Nod : Node_Id) is
+ Is_Dynamic : Boolean;
+ -- Indicates whether the context causes nested coextensions to be
+ -- dynamic or static
+
+ function Mark_Allocator (N : Node_Id) return Traverse_Result;
+ -- Recognize an allocator node and label it as a dynamic coextension
+
+ --------------------
+ -- Mark_Allocator --
+ --------------------
+
+ function Mark_Allocator (N : Node_Id) return Traverse_Result is
+ begin
+ if Nkind (N) = N_Allocator then
+ if Is_Dynamic then
+ Set_Is_Dynamic_Coextension (N);
+
+ -- If the allocator expression is potentially dynamic, it may
+ -- be expanded out of order and require dynamic allocation
+ -- anyway, so we treat the coextension itself as dynamic.
+ -- Potential optimization ???
+
+ elsif Nkind (Expression (N)) = N_Qualified_Expression
+ and then Nkind (Expression (Expression (N))) = N_Op_Concat
+ then
+ Set_Is_Dynamic_Coextension (N);
+ else
+ Set_Is_Static_Coextension (N);
+ end if;
+ end if;
+
+ return OK;
+ end Mark_Allocator;
+
+ procedure Mark_Allocators is new Traverse_Proc (Mark_Allocator);
+
+ -- Start of processing for Mark_Coextensions
+
+ begin
+ -- An allocator that appears on the right-hand side of an assignment is
+ -- treated as a potentially dynamic coextension when the right-hand side
+ -- is an allocator or a qualified expression.
+
+ -- Obj := new ...'(new Coextension ...);
+
+ if Nkind (Context_Nod) = N_Assignment_Statement then
+ Is_Dynamic :=
+ Nkind_In (Expression (Context_Nod), N_Allocator,
+ N_Qualified_Expression);
+
+ -- An allocator that appears within the expression of a simple return
+ -- statement is treated as a potentially dynamic coextension when the
+ -- expression is either aggregate, allocator, or qualified expression.
+
+ -- return (new Coextension ...);
+ -- return new ...'(new Coextension ...);
+
+ elsif Nkind (Context_Nod) = N_Simple_Return_Statement then
+ Is_Dynamic :=
+ Nkind_In (Expression (Context_Nod), N_Aggregate,
+ N_Allocator,
+ N_Qualified_Expression);
+
+ -- An alloctor that appears within the initialization expression of an
+ -- object declaration is considered a potentially dynamic coextension
+ -- when the initialization expression is an allocator or a qualified
+ -- expression.
+
+ -- Obj : ... := new ...'(new Coextension ...);
+
+ -- A similar case arises when the object declaration is part of an
+ -- extended return statement.
+
+ -- return Obj : ... := new ...'(new Coextension ...);
+ -- return Obj : ... := (new Coextension ...);
+
+ elsif Nkind (Context_Nod) = N_Object_Declaration then
+ Is_Dynamic :=
+ Nkind_In (Root_Nod, N_Allocator, N_Qualified_Expression)
+ or else
+ Nkind (Parent (Context_Nod)) = N_Extended_Return_Statement;
+
+ -- This routine should not be called with constructs that cannot contain
+ -- coextensions.
+
+ else
+ raise Program_Error;
+ end if;
+
+ Mark_Allocators (Root_Nod);
+ end Mark_Coextensions;
+
+ ---------------------------------
+ -- Mark_Elaboration_Attributes --
+ ---------------------------------
+
+ procedure Mark_Elaboration_Attributes
+ (N_Id : Node_Or_Entity_Id;
+ Checks : Boolean := False;
+ Level : Boolean := False;
+ Modes : Boolean := False)
+ is
+ function Elaboration_Checks_OK
+ (Target_Id : Entity_Id;
+ Context_Id : Entity_Id) return Boolean;
+ -- Determine whether elaboration checks are enabled for target Target_Id
+ -- which resides within context Context_Id.
+
+ procedure Mark_Elaboration_Attributes_Id (Id : Entity_Id);
+ -- Preserve relevant attributes of the context in arbitrary entity Id
+
+ procedure Mark_Elaboration_Attributes_Node (N : Node_Id);
+ -- Preserve relevant attributes of the context in arbitrary node N
+
+ ---------------------------
+ -- Elaboration_Checks_OK --
+ ---------------------------
+
+ function Elaboration_Checks_OK
+ (Target_Id : Entity_Id;
+ Context_Id : Entity_Id) return Boolean
+ is
+ Encl_Scop : Entity_Id;
+
+ begin
+ -- Elaboration checks are suppressed for the target
+
+ if Elaboration_Checks_Suppressed (Target_Id) then
+ return False;
+ end if;
+
+ -- Otherwise elaboration checks are OK for the target, but may be
+ -- suppressed for the context where the target is declared.
+
+ Encl_Scop := Context_Id;
+ while Present (Encl_Scop) and then Encl_Scop /= Standard_Standard loop
+ if Elaboration_Checks_Suppressed (Encl_Scop) then
+ return False;
+ end if;
+
+ Encl_Scop := Scope (Encl_Scop);
+ end loop;
+
+ -- Neither the target nor its declarative context have elaboration
+ -- checks suppressed.
+
+ return True;
+ end Elaboration_Checks_OK;
+
+ ------------------------------------
+ -- Mark_Elaboration_Attributes_Id --
+ ------------------------------------
+
+ procedure Mark_Elaboration_Attributes_Id (Id : Entity_Id) is
+ begin
+ -- Mark the status of elaboration checks in effect. Do not reset the
+ -- status in case the entity is reanalyzed with checks suppressed.
+
+ if Checks and then not Is_Elaboration_Checks_OK_Id (Id) then
+ Set_Is_Elaboration_Checks_OK_Id (Id,
+ Elaboration_Checks_OK
+ (Target_Id => Id,
+ Context_Id => Scope (Id)));
+
+ -- Entities do not need to capture their enclosing level. The Ghost
+ -- and SPARK modes in effect are already marked during analysis.
+
+ else
+ null;
+ end if;
+ end Mark_Elaboration_Attributes_Id;
+
+ --------------------------------------
+ -- Mark_Elaboration_Attributes_Node --
+ --------------------------------------
+
+ procedure Mark_Elaboration_Attributes_Node (N : Node_Id) is
+ function Extract_Name (N : Node_Id) return Node_Id;
+ -- Obtain the Name attribute of call or instantiation N
+
+ ------------------
+ -- Extract_Name --
+ ------------------
+
+ function Extract_Name (N : Node_Id) return Node_Id is
+ Nam : Node_Id;
+
+ begin
+ Nam := Name (N);
+
+ -- A call to an entry family appears in indexed form
+
+ if Nkind (Nam) = N_Indexed_Component then
+ Nam := Prefix (Nam);
+ end if;
+
+ -- The name may also appear in qualified form
+
+ if Nkind (Nam) = N_Selected_Component then
+ Nam := Selector_Name (Nam);
+ end if;
+
+ return Nam;
+ end Extract_Name;
+
+ -- Local variables
+
+ Context_Id : Entity_Id;
+ Nam : Node_Id;
+
+ -- Start of processing for Mark_Elaboration_Attributes_Node
+
+ begin
+ -- Mark the status of elaboration checks in effect. Do not reset the
+ -- status in case the node is reanalyzed with checks suppressed.
+
+ if Checks and then not Is_Elaboration_Checks_OK_Node (N) then
+
+ -- Assignments, attribute references, and variable references do
+ -- not have a "declarative" context.
+
+ Context_Id := Empty;
+
+ -- The status of elaboration checks for calls and instantiations
+ -- depends on the most recent pragma Suppress/Unsuppress, as well
+ -- as the suppression status of the context where the target is
+ -- defined.
+
+ -- package Pack is
+ -- function Func ...;
+ -- end Pack;
+
+ -- with Pack;
+ -- procedure Main is
+ -- pragma Suppress (Elaboration_Checks, Pack);
+ -- X : ... := Pack.Func;
+ -- ...
+
+ -- In the example above, the call to Func has elaboration checks
+ -- enabled because there is no active general purpose suppression
+ -- pragma, however the elaboration checks of Pack are explicitly
+ -- suppressed. As a result the elaboration checks of the call must
+ -- be disabled in order to preserve this dependency.
+
+ if Nkind_In (N, N_Entry_Call_Statement,
+ N_Function_Call,
+ N_Function_Instantiation,
+ N_Package_Instantiation,
+ N_Procedure_Call_Statement,
+ N_Procedure_Instantiation)
+ then
+ Nam := Extract_Name (N);
+
+ if Is_Entity_Name (Nam) and then Present (Entity (Nam)) then
+ Context_Id := Scope (Entity (Nam));
+ end if;
+ end if;
+
+ Set_Is_Elaboration_Checks_OK_Node (N,
+ Elaboration_Checks_OK
+ (Target_Id => Empty,
+ Context_Id => Context_Id));
+ end if;
+
+ -- Mark the enclosing level of the node. Do not reset the status in
+ -- case the node is relocated and reanalyzed.
+
+ if Level and then not Is_Declaration_Level_Node (N) then
+ Set_Is_Declaration_Level_Node (N,
+ Find_Enclosing_Level (N) = Declaration_Level);
+ end if;
+
+ -- Mark the Ghost and SPARK mode in effect
+
+ if Modes then
+ if Ghost_Mode = Ignore then
+ Set_Is_Ignored_Ghost_Node (N);
+ end if;
+
+ if SPARK_Mode = On then
+ Set_Is_SPARK_Mode_On_Node (N);
+ end if;
+ end if;
+ end Mark_Elaboration_Attributes_Node;
+
+ -- Start of processing for Mark_Elaboration_Attributes
+
+ begin
+ if Nkind (N_Id) in N_Entity then
+ Mark_Elaboration_Attributes_Id (N_Id);
+ else
+ Mark_Elaboration_Attributes_Node (N_Id);
+ end if;
+ end Mark_Elaboration_Attributes;
+
----------------------------------
-- Matching_Static_Array_Bounds --
----------------------------------
@@ -17269,103 +17819,6 @@ package body Sem_Util is
end case;
end May_Be_Lvalue;
- -----------------------
- -- Mark_Coextensions --
- -----------------------
-
- procedure Mark_Coextensions (Context_Nod : Node_Id; Root_Nod : Node_Id) is
- Is_Dynamic : Boolean;
- -- Indicates whether the context causes nested coextensions to be
- -- dynamic or static
-
- function Mark_Allocator (N : Node_Id) return Traverse_Result;
- -- Recognize an allocator node and label it as a dynamic coextension
-
- --------------------
- -- Mark_Allocator --
- --------------------
-
- function Mark_Allocator (N : Node_Id) return Traverse_Result is
- begin
- if Nkind (N) = N_Allocator then
- if Is_Dynamic then
- Set_Is_Dynamic_Coextension (N);
-
- -- If the allocator expression is potentially dynamic, it may
- -- be expanded out of order and require dynamic allocation
- -- anyway, so we treat the coextension itself as dynamic.
- -- Potential optimization ???
-
- elsif Nkind (Expression (N)) = N_Qualified_Expression
- and then Nkind (Expression (Expression (N))) = N_Op_Concat
- then
- Set_Is_Dynamic_Coextension (N);
- else
- Set_Is_Static_Coextension (N);
- end if;
- end if;
-
- return OK;
- end Mark_Allocator;
-
- procedure Mark_Allocators is new Traverse_Proc (Mark_Allocator);
-
- -- Start of processing for Mark_Coextensions
-
- begin
- -- An allocator that appears on the right-hand side of an assignment is
- -- treated as a potentially dynamic coextension when the right-hand side
- -- is an allocator or a qualified expression.
-
- -- Obj := new ...'(new Coextension ...);
-
- if Nkind (Context_Nod) = N_Assignment_Statement then
- Is_Dynamic :=
- Nkind_In (Expression (Context_Nod), N_Allocator,
- N_Qualified_Expression);
-
- -- An allocator that appears within the expression of a simple return
- -- statement is treated as a potentially dynamic coextension when the
- -- expression is either aggregate, allocator, or qualified expression.
-
- -- return (new Coextension ...);
- -- return new ...'(new Coextension ...);
-
- elsif Nkind (Context_Nod) = N_Simple_Return_Statement then
- Is_Dynamic :=
- Nkind_In (Expression (Context_Nod), N_Aggregate,
- N_Allocator,
- N_Qualified_Expression);
-
- -- An allocator that appears within the initialization expression of an
- -- object declaration is considered a potentially dynamic coextension
- -- when the initialization expression is an allocator or a qualified
- -- expression.
-
- -- Obj : ... := new ...'(new Coextension ...);
-
- -- A similar case arises when the object declaration is part of an
- -- extended return statement.
-
- -- return Obj : ... := new ...'(new Coextension ...);
- -- return Obj : ... := (new Coextension ...);
-
- elsif Nkind (Context_Nod) = N_Object_Declaration then
- Is_Dynamic :=
- Nkind_In (Root_Nod, N_Allocator, N_Qualified_Expression)
- or else
- Nkind (Parent (Context_Nod)) = N_Extended_Return_Statement;
-
- -- This routine should not be called with constructs that cannot contain
- -- coextensions.
-
- else
- raise Program_Error;
- end if;
-
- Mark_Allocators (Root_Nod);
- end Mark_Coextensions;
-
-----------------
-- Might_Raise --
-----------------
@@ -18532,8 +18985,8 @@ package body Sem_Util is
-- the subtree being replicated.
elsif not In_Subtree
- (Root => Source,
- N => Declaration_Node (Id))
+ (N => Declaration_Node (Id),
+ Root => Source)
then
return;
end if;
@@ -18677,8 +19130,8 @@ package body Sem_Util is
-- the subtree being replicated.
elsif not In_Subtree
- (Root => Source,
- N => Associated_Node_For_Itype (Itype))
+ (N => Associated_Node_For_Itype (Itype),
+ Root => Source)
then
return;
end if;
@@ -19083,7 +19536,18 @@ package body Sem_Util is
N := Next (Actual_Id);
if Nkind (N) = N_Parameter_Association then
- return First_Named_Actual (Parent (Actual_Id));
+
+ -- In case of a build-in-place call, the call will no longer be a
+ -- call; it will have been rewritten.
+
+ if Nkind_In (Parent (Actual_Id), N_Entry_Call_Statement,
+ N_Function_Call,
+ N_Procedure_Call_Statement)
+ then
+ return First_Named_Actual (Parent (Actual_Id));
+ else
+ return Empty;
+ end if;
else
return N;
end if;
@@ -20137,6 +20601,51 @@ package body Sem_Util is
return False;
end Null_To_Null_Address_Convert_OK;
+ ---------------------------------
+ -- Number_Of_Elements_In_Array --
+ ---------------------------------
+
+ function Number_Of_Elements_In_Array (T : Entity_Id) return Int is
+ Indx : Node_Id;
+ Typ : Entity_Id;
+ Low : Node_Id;
+ High : Node_Id;
+ Num : Int := 1;
+
+ begin
+ pragma Assert (Is_Array_Type (T));
+
+ Indx := First_Index (T);
+ while Present (Indx) loop
+ Typ := Underlying_Type (Etype (Indx));
+
+ -- Never look at junk bounds of a generic type
+
+ if Is_Generic_Type (Typ) then
+ return 0;
+ end if;
+
+ -- Check the array bounds are known at compile time and return zero
+ -- if they are not.
+
+ Low := Type_Low_Bound (Typ);
+ High := Type_High_Bound (Typ);
+
+ if not Compile_Time_Known_Value (Low) then
+ return 0;
+ elsif not Compile_Time_Known_Value (High) then
+ return 0;
+ else
+ Num :=
+ Num * UI_To_Int ((Expr_Value (High) - Expr_Value (Low) + 1));
+ end if;
+
+ Next_Index (Indx);
+ end loop;
+
+ return Num;
+ end Number_Of_Elements_In_Array;
+
-------------------------
-- Object_Access_Level --
-------------------------
@@ -20156,7 +20665,7 @@ package body Sem_Util is
-- This construct appears in the context of dispatching calls.
function Reference_To (Obj : Node_Id) return Node_Id;
- -- An explicit dereference is created when removing side-effects from
+ -- An explicit dereference is created when removing side effects from
-- expressions for constraint checking purposes. In this case a local
-- access type is created for it. The correct access level is that of
-- the original source node. We detect this case by noting that the
@@ -20396,6 +20905,17 @@ package body Sem_Util is
(Nearest_Dynamic_Scope
(Defining_Entity (Node_Par)));
+ -- For a return statement within a function, return
+ -- the depth of the function itself. This is not just
+ -- a small optimization, but matters when analyzing
+ -- the expression in an expression function before
+ -- the body is created.
+
+ when N_Simple_Return_Statement =>
+ if Ekind (Current_Scope) = E_Function then
+ return Scope_Depth (Current_Scope);
+ end if;
+
when others =>
null;
end case;
@@ -21988,15 +22508,18 @@ package body Sem_Util is
-- Scope_Within --
------------------
- function Scope_Within (Scope1, Scope2 : Entity_Id) return Boolean is
- Scop : Entity_Id;
+ function Scope_Within
+ (Inner : Entity_Id;
+ Outer : Entity_Id) return Boolean
+ is
+ Curr : Entity_Id;
begin
- Scop := Scope1;
- while Scop /= Standard_Standard loop
- Scop := Scope (Scop);
+ Curr := Inner;
+ while Present (Curr) and then Curr /= Standard_Standard loop
+ Curr := Scope (Curr);
- if Scop = Scope2 then
+ if Curr = Outer then
return True;
end if;
end loop;
@@ -22008,17 +22531,20 @@ package body Sem_Util is
-- Scope_Within_Or_Same --
--------------------------
- function Scope_Within_Or_Same (Scope1, Scope2 : Entity_Id) return Boolean is
- Scop : Entity_Id;
+ function Scope_Within_Or_Same
+ (Inner : Entity_Id;
+ Outer : Entity_Id) return Boolean
+ is
+ Curr : Entity_Id;
begin
- Scop := Scope1;
- while Scop /= Standard_Standard loop
- if Scop = Scope2 then
+ Curr := Inner;
+ while Present (Curr) and then Curr /= Standard_Standard loop
+ if Curr = Outer then
return True;
- else
- Scop := Scope (Scop);
end if;
+
+ Curr := Scope (Curr);
end loop;
return False;
@@ -22801,7 +23327,15 @@ package body Sem_Util is
return "unknown subprogram";
end if;
- Append_Entity_Name (Buf, Ent);
+ -- If the subprogram is a child unit, use its simple name to start the
+ -- construction of the fully qualified name.
+
+ if Nkind (Ent) = N_Defining_Program_Unit_Name then
+ Append_Entity_Name (Buf, Defining_Identifier (Ent));
+ else
+ Append_Entity_Name (Buf, Ent);
+ end if;
+
return +Buf;
end Subprogram_Name;
diff --git a/gcc/ada/sem_util.ads b/gcc/ada/sem_util.ads
index 30c35cb..c6958cb 100644
--- a/gcc/ada/sem_util.ads
+++ b/gcc/ada/sem_util.ads
@@ -202,6 +202,10 @@ package Sem_Util is
-- given, and the reference N is not in the same extended source unit as
-- the declaration of T.
+ function Begin_Keyword_Location (N : Node_Id) return Source_Ptr;
+ -- Given block statement, entry body, package body, subprogram body, or
+ -- task body N, return the closest source location to the "begin" keyword.
+
function Build_Actual_Subtype
(T : Entity_Id;
N : Node_Or_Entity_Id) return Node_Id;
@@ -547,8 +551,9 @@ package Sem_Util is
-- instead of 0).
function Defining_Entity
- (N : Node_Id;
- Empty_On_Errors : Boolean := False) return Entity_Id;
+ (N : Node_Id;
+ Empty_On_Errors : Boolean := False;
+ Concurrent_Subunit : Boolean := False) return Entity_Id;
-- Given a declaration N, returns the associated defining entity. If the
-- declaration has a specification, the entity is obtained from the
-- specification. If the declaration has a defining unit name, then the
@@ -572,6 +577,9 @@ package Sem_Util is
--
-- The former semantics is appropriate for the back end; the latter
-- semantics is appropriate for the front end.
+ --
+ -- Set flag Concurrent_Subunit to handle rewritings of concurrent bodies
+ -- which act as subunits. Such bodies are generally rewritten as null.
function Denotes_Discriminant
(N : Node_Id;
@@ -685,6 +693,12 @@ package Sem_Util is
-- Utility function to return the Ada entity of the subprogram enclosing
-- the entity E, if any. Returns Empty if no enclosing subprogram.
+ function End_Keyword_Location (N : Node_Id) return Source_Ptr;
+ -- Given block statement, entry body, package body, package declaration,
+ -- protected body, [single] protected type declaration, subprogram body,
+ -- task body, or [single] task type declaration N, return the closest
+ -- source location of the "end" keyword.
+
procedure Ensure_Freeze_Node (E : Entity_Id);
-- Make sure a freeze node is allocated for entity E. If necessary, build
-- and initialize a new freeze node and set Has_Delayed_Freeze True for E.
@@ -740,12 +754,6 @@ package Sem_Util is
-- Call is set to the node for the corresponding call. If the node N is not
-- an actual parameter then Formal and Call are set to Empty.
- function Find_Specific_Type (CW : Entity_Id) return Entity_Id;
- -- Find specific type of a class-wide type, and handle the case of an
- -- incomplete type coming either from a limited_with clause or from an
- -- incomplete type declaration. If resulting type is private return its
- -- full view.
-
function Find_Body_Discriminal
(Spec_Discriminant : Entity_Id) return Entity_Id;
-- Given a discriminant of the record type that implements a task or
@@ -762,9 +770,12 @@ package Sem_Util is
-- discriminant at the same position in this new type.
function Find_Enclosing_Iterator_Loop (Id : Entity_Id) return Entity_Id;
- -- Given an arbitrary entity, try to find the nearest enclosing iterator
- -- loop. If such a loop is found, return the entity of its identifier (the
- -- E_Loop scope), otherwise return Empty.
+ -- Find the nearest iterator loop which encloses arbitrary entity Id. If
+ -- such a loop exists, return the entity of its identifier (E_Loop scope),
+ -- otherwise return Empty.
+
+ function Find_Enclosing_Scope (N : Node_Id) return Entity_Id;
+ -- Find the nearest scope which encloses arbitrary node N
function Find_Loop_In_Conditional_Block (N : Node_Id) return Node_Id;
-- Find the nested loop statement in a conditional block. Loops subject to
@@ -868,6 +879,12 @@ package Sem_Util is
-- If the state space is that of a package, Pack_Id denotes its entity,
-- otherwise Pack_Id is Empty.
+ function Find_Specific_Type (CW : Entity_Id) return Entity_Id;
+ -- Find specific type of a class-wide type, and handle the case of an
+ -- incomplete type coming either from a limited_with clause or from an
+ -- incomplete type declaration. If resulting type is private return its
+ -- full view.
+
function Find_Static_Alternative (N : Node_Id) return Node_Id;
-- N is a case statement whose expression is a compile-time value.
-- Determine the alternative chosen, so that the code of non-selected
@@ -1134,8 +1151,7 @@ package Sem_Util is
-- subprogram or entry and returns it, or if no subprogram can be found,
-- returns Empty.
- function Get_Task_Body_Procedure (E : Entity_Id) return Node_Id;
- pragma Inline (Get_Task_Body_Procedure);
+ function Get_Task_Body_Procedure (E : Entity_Id) return Entity_Id;
-- Given an entity for a task type or subtype, retrieves the
-- Task_Body_Procedure field from the corresponding task type declaration.
@@ -1259,14 +1275,14 @@ package Sem_Util is
-- as expressed in pragma Refined_State. This function does not take into
-- account the visible refinement region of abstract state Id.
- function Has_Null_Body (Proc_Id : Entity_Id) return Boolean;
- -- Determine whether the body of procedure Proc_Id contains a sole
- -- null statement, possibly followed by an optional return. Used to
- -- optimize useless calls to assertion checks.
+ function Has_Non_Trivial_Precondition (Subp : Entity_Id) return Boolean;
+ -- Determine whether subprogram Subp has a class-wide precondition that is
+ -- not statically True.
- function Has_Non_Trivial_Precondition (P : Entity_Id) return Boolean;
- -- True if subprogram has a class-wide precondition that is not
- -- statically True.
+ function Has_Null_Body (Proc_Id : Entity_Id) return Boolean;
+ -- Determine whether the body of procedure Proc_Id contains a sole null
+ -- statement, possibly followed by an optional return. Used to optimize
+ -- useless calls to assertion checks.
function Has_Null_Exclusion (N : Node_Id) return Boolean;
-- Determine whether node N has a null exclusion
@@ -1357,9 +1373,10 @@ package Sem_Util is
-- Returns True if current scope is with the private part or the body of
-- an instance. Other semantic checks are suppressed in this context.
- function In_Instance_Visible_Part return Boolean;
- -- Returns True if current scope is within the visible part of a package
- -- instance, where several additional semantic checks apply.
+ function In_Instance_Visible_Part
+ (Id : Entity_Id := Current_Scope) return Boolean;
+ -- Returns True if arbitrary entity Id is within the visible part of a
+ -- package instance, where several additional semantic checks apply.
function In_Package_Body return Boolean;
-- Returns True if current scope is within a package body
@@ -1382,9 +1399,17 @@ package Sem_Util is
-- appearing anywhere within such a construct (that is it does not need
-- to be directly within).
- function In_Subtree (Root : Node_Id; N : Node_Id) return Boolean;
+ function In_Subtree (N : Node_Id; Root : Node_Id) return Boolean;
-- Determine whether node N is within the subtree rooted at Root
+ function In_Subtree
+ (N : Node_Id;
+ Root1 : Node_Id;
+ Root2 : Node_Id) return Boolean;
+ -- Determine whether node N is within the subtree rooted at Root1 or Root2.
+ -- This version is more efficient than calling the single root version of
+ -- Is_Subtree twice.
+
function In_Visible_Part (Scope_Id : Entity_Id) return Boolean;
-- Determine whether a declaration occurs within the visible part of a
-- package specification. The package must be on the scope stack, and the
@@ -1765,6 +1790,14 @@ package Sem_Util is
-- persistent. A private type is potentially persistent if the full type
-- is potentially persistent.
+ function Is_Preelaborable_Aggregate (Aggr : Node_Id) return Boolean;
+ -- Determine whether aggregate Aggr violates the restrictions of
+ -- preelaborable constructs as defined in ARM 10.2.1(5-9).
+
+ function Is_Preelaborable_Construct (N : Node_Id) return Boolean;
+ -- Determine whether arbitrary node N violates the restrictions of
+ -- preelaborable constructs as defined in ARM 10.2.1(5-9).
+
function Is_Protected_Self_Reference (N : Node_Id) return Boolean;
-- Return True if node N denotes a protected type name which represents
-- the current instance of a protected object according to RM 9.4(21/2).
@@ -2028,6 +2061,24 @@ package Sem_Util is
-- statement in Statements (HSS) that has Comes_From_Source set. If no
-- such statement exists, Empty is returned.
+ procedure Mark_Coextensions (Context_Nod : Node_Id; Root_Nod : Node_Id);
+ -- Given a node which designates the context of analysis and an origin in
+ -- the tree, traverse from Root_Nod and mark all allocators as either
+ -- dynamic or static depending on Context_Nod. Any incorrect marking is
+ -- cleaned up during resolution.
+
+ procedure Mark_Elaboration_Attributes
+ (N_Id : Node_Or_Entity_Id;
+ Checks : Boolean := False;
+ Level : Boolean := False;
+ Modes : Boolean := False);
+ -- Preserve relevant elaboration-related properties of the context in
+ -- arbitrary entity or node N_Id. When flag Checks is set, the routine
+ -- saves the status of Elaboration_Check. When flag Level is set, the
+ -- routine captures the declaration level of N_Id if applicable. When
+ -- flag Modes is set, the routine saves the Ghost and SPARK modes in
+ -- effect if applicable.
+
function Matching_Static_Array_Bounds
(L_Typ : Node_Id;
R_Typ : Node_Id) return Boolean;
@@ -2035,12 +2086,6 @@ package Sem_Util is
-- same number of dimensions, and the same static bounds for each index
-- position.
- procedure Mark_Coextensions (Context_Nod : Node_Id; Root_Nod : Node_Id);
- -- Given a node which designates the context of analysis and an origin in
- -- the tree, traverse from Root_Nod and mark all allocators as either
- -- dynamic or static depending on Context_Nod. Any incorrect marking is
- -- cleaned up during resolution.
-
function May_Be_Lvalue (N : Node_Id) return Boolean;
-- Determines if N could be an lvalue (e.g. an assignment left hand side).
-- An lvalue is defined as any expression which appears in a context where
@@ -2230,6 +2275,11 @@ package Sem_Util is
-- 2) N is a comparison operator, one of the operands is null, and the
-- type of the other operand is a descendant of System.Address.
+ function Number_Of_Elements_In_Array (T : Entity_Id) return Int;
+ -- Returns the number of elements in the array T if the index bounds of T
+ -- is known at compile time. If the bounds are not known at compile time,
+ -- the function returns the value zero.
+
function Object_Access_Level (Obj : Node_Id) return Uint;
-- Return the accessibility level of the view of the object Obj. For
-- convenience, qualified expressions applied to object names are also
@@ -2460,15 +2510,19 @@ package Sem_Util is
-- this is the case, and False if no scalar parts are present (meaning that
-- the result of Valid_Scalars applied to T is always vacuously True).
- function Scope_Within_Or_Same (Scope1, Scope2 : Entity_Id) return Boolean;
- -- Determines if the entity Scope1 is the same as Scope2, or if it is
- -- inside it, where both entities represent scopes. Note that scopes
- -- are only partially ordered, so Scope_Within_Or_Same (A,B) and
- -- Scope_Within_Or_Same (B,A) can both be False for a given pair A,B.
-
- function Scope_Within (Scope1, Scope2 : Entity_Id) return Boolean;
- -- Like Scope_Within_Or_Same, except that this function returns
- -- False in the case where Scope1 and Scope2 are the same scope.
+ function Scope_Within
+ (Inner : Entity_Id;
+ Outer : Entity_Id) return Boolean;
+ -- Determine whether scope Inner appears within scope Outer. Note that
+ -- scopes are partially ordered, so Scope_Within (A, B) and Scope_Within
+ -- (B, A) may both return False.
+
+ function Scope_Within_Or_Same
+ (Inner : Entity_Id;
+ Outer : Entity_Id) return Boolean;
+ -- Determine whether scope Inner appears within scope Outer or both renote
+ -- the same scope. Note that scopes are partially ordered, so Scope_Within
+ -- (A, B) and Scope_Within (B, A) may both return False.
procedure Set_Convention (E : Entity_Id; Val : Convention_Id);
-- Same as Basic_Set_Convention, but with an extra check for access types.
diff --git a/gcc/ada/sem_warn.adb b/gcc/ada/sem_warn.adb
index 278d6b6..0e498d3 100644
--- a/gcc/ada/sem_warn.adb
+++ b/gcc/ada/sem_warn.adb
@@ -248,6 +248,10 @@ package body Sem_Warn is
-- If so, Ref is set to point to the reference node, and Var is set to
-- the referenced Entity.
+ function Has_Condition_Actions (Iter : Node_Id) return Boolean;
+ -- Determine whether iteration scheme Iter has meaningful condition
+ -- actions.
+
function Has_Indirection (T : Entity_Id) return Boolean;
-- If the controlling variable is an access type, or is a record type
-- with access components, assume that it is changed indirectly and
@@ -360,6 +364,29 @@ package body Sem_Warn is
end if;
end Find_Var;
+ ---------------------------
+ -- Has_Condition_Actions --
+ ---------------------------
+
+ function Has_Condition_Actions (Iter : Node_Id) return Boolean is
+ Action : Node_Id;
+
+ begin
+ -- A call marker is not considered a meaningful action because it
+ -- acts as an annotation and has no runtime semantics.
+
+ Action := First (Condition_Actions (Iter));
+ while Present (Action) loop
+ if Nkind (Action) /= N_Call_Marker then
+ return True;
+ end if;
+
+ Next (Action);
+ end loop;
+
+ return False;
+ end Has_Condition_Actions;
+
---------------------
-- Has_Indirection --
---------------------
@@ -482,7 +509,7 @@ package body Sem_Warn is
end if;
-- If the condition contains a function call, we consider it may
- -- be modified by side-effects from a procedure call. Otherwise,
+ -- be modified by side effects from a procedure call. Otherwise,
-- we consider the condition may not be modified, although that
-- might happen if Variable is itself a by-reference parameter,
-- and the procedure called modifies the global object referred to
@@ -597,7 +624,7 @@ package body Sem_Warn is
-- Skip processing for while iteration with conditions actions,
-- since they make it too complicated to get the warning right.
- if Present (Condition_Actions (Iter)) then
+ if Has_Condition_Actions (Iter) then
return;
end if;
@@ -2225,29 +2252,21 @@ package body Sem_Warn is
----------------------
function Check_Use_Clause (N : Node_Id) return Traverse_Result is
- Nam : Node_Id;
-
begin
- if Nkind (N) = N_Use_Package_Clause then
- Nam := First (Names (N));
- while Present (Nam) loop
- if Entity (Nam) = Pack then
-
- -- Suppress message if any serious errors detected
- -- that turn off expansion, and thus result in false
- -- positives for this warning.
-
- if Serious_Errors_Detected = 0 then
- Error_Msg_Qual_Level := 1;
- Error_Msg_NE -- CODEFIX
- ("?u?no entities of package& are referenced!",
- Nam, Pack);
- Error_Msg_Qual_Level := 0;
- end if;
- end if;
-
- Next (Nam);
- end loop;
+ if Nkind (N) = N_Use_Package_Clause
+ and then Entity (Name (N)) = Pack
+ then
+ -- Suppress message if any serious errors detected that turn
+ -- off expansion, and thus result in false positives for
+ -- this warning.
+
+ if Serious_Errors_Detected = 0 then
+ Error_Msg_Qual_Level := 1;
+ Error_Msg_NE -- CODEFIX
+ ("?u?no entities of package& are referenced!",
+ Name (N), Pack);
+ Error_Msg_Qual_Level := 0;
+ end if;
end if;
return OK;
@@ -4266,7 +4285,7 @@ package body Sem_Warn is
then
if not Has_Pragma_Unmodified_Check_Spec (E) then
Error_Msg_N -- CODEFIX
- ("?u?variable & is assigned but never read!", E);
+ ("?m?variable & is assigned but never read!", E);
end if;
Set_Last_Assignment (E, Empty);
diff --git a/gcc/ada/sem_warn.ads b/gcc/ada/sem_warn.ads
index e19c1c7..de43c29 100644
--- a/gcc/ada/sem_warn.ads
+++ b/gcc/ada/sem_warn.ads
@@ -27,7 +27,7 @@
-- about uses of uninitialized variables and unused with's. It also has
-- some unrelated routines related to the generation of warnings.
-with Alloc; use Alloc;
+with Alloc;
with Table;
with Types; use Types;
diff --git a/gcc/ada/sinfo.adb b/gcc/ada/sinfo.adb
index 4a902e8..dc4e8fb 100644
--- a/gcc/ada/sinfo.adb
+++ b/gcc/ada/sinfo.adb
@@ -61,19 +61,6 @@ package body Sinfo is
-- uniform format of the conditions following this. Note that csinfo
-- expects this uniform format.
- function ABE_Is_Certain
- (N : Node_Id) return Boolean is
- begin
- pragma Assert (False
- or else NT (N).Nkind = N_Formal_Package_Declaration
- or else NT (N).Nkind = N_Function_Call
- or else NT (N).Nkind = N_Function_Instantiation
- or else NT (N).Nkind = N_Package_Instantiation
- or else NT (N).Nkind = N_Procedure_Call_Statement
- or else NT (N).Nkind = N_Procedure_Instantiation);
- return Flag18 (N);
- end ABE_Is_Certain;
-
function Abort_Present
(N : Node_Id) return Boolean is
begin
@@ -216,6 +203,14 @@ package body Sinfo is
return Flag4 (N);
end Aliased_Present;
+ function Alloc_For_BIP_Return
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Allocator);
+ return Flag1 (N);
+ end Alloc_For_BIP_Return;
+
function All_Others
(N : Node_Id) return Boolean is
begin
@@ -298,7 +293,8 @@ package body Sinfo is
or else NT (N).Nkind in N_Has_Entity
or else NT (N).Nkind = N_Aggregate
or else NT (N).Nkind = N_Extension_Aggregate
- or else NT (N).Nkind = N_Selected_Component);
+ or else NT (N).Nkind = N_Selected_Component
+ or else NT (N).Nkind = N_Use_Package_Clause);
return Node4 (N);
end Associated_Node;
@@ -438,7 +434,7 @@ package body Sinfo is
end Classifications;
function Cleanup_Actions
- (N : Node_Id) return List_Id is
+ (N : Node_Id) return List_Id is
begin
pragma Assert (False
or else NT (N).Nkind = N_Block_Statement);
@@ -446,7 +442,7 @@ package body Sinfo is
end Cleanup_Actions;
function Comes_From_Extended_Return_Statement
- (N : Node_Id) return Boolean is
+ (N : Node_Id) return Boolean is
begin
pragma Assert (False
or else NT (N).Nkind = N_Simple_Return_Statement);
@@ -950,7 +946,7 @@ package body Sinfo is
or else NT (N).Nkind = N_Assignment_Statement
or else NT (N).Nkind = N_Selected_Component
or else NT (N).Nkind = N_Type_Conversion);
- return Flag1 (N);
+ return Flag3 (N);
end Do_Discriminant_Check;
function Do_Division_Check
@@ -1646,7 +1642,7 @@ package body Sinfo is
pragma Assert (False
or else NT (N).Nkind = N_Use_Package_Clause
or else NT (N).Nkind = N_Use_Type_Clause);
- return Elist4 (N);
+ return Elist5 (N);
end Hidden_By_Use_Clause;
function High_Bound
@@ -1855,14 +1851,16 @@ package body Sinfo is
return Flag16 (N);
end Is_Controlling_Actual;
- function Is_Disabled
+ function Is_Declaration_Level_Node
(N : Node_Id) return Boolean is
begin
pragma Assert (False
- or else NT (N).Nkind = N_Aspect_Specification
- or else NT (N).Nkind = N_Pragma);
- return Flag15 (N);
- end Is_Disabled;
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Instantiation);
+ return Flag5 (N);
+ end Is_Declaration_Level_Node;
function Is_Delayed_Aspect
(N : Node_Id) return Boolean is
@@ -1874,6 +1872,23 @@ package body Sinfo is
return Flag14 (N);
end Is_Delayed_Aspect;
+ function Is_Disabled
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Aspect_Specification
+ or else NT (N).Nkind = N_Pragma);
+ return Flag15 (N);
+ end Is_Disabled;
+
+ function Is_Dispatching_Call
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker);
+ return Flag3 (N);
+ end Is_Dispatching_Call;
+
function Is_Dynamic_Coextension
(N : Node_Id) return Boolean is
begin
@@ -1882,8 +1897,36 @@ package body Sinfo is
return Flag18 (N);
end Is_Dynamic_Coextension;
+ function Is_Effective_Use_Clause
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Use_Package_Clause
+ or else NT (N).Nkind = N_Use_Type_Clause);
+ return Flag1 (N);
+ end Is_Effective_Use_Clause;
+
+ function Is_Elaboration_Checks_OK_Node
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Assignment_Statement
+ or else NT (N).Nkind = N_Attribute_Reference
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Entry_Call_Statement
+ or else NT (N).Nkind = N_Expanded_Name
+ or else NT (N).Nkind = N_Function_Call
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Identifier
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Call_Statement
+ or else NT (N).Nkind = N_Procedure_Instantiation
+ or else NT (N).Nkind = N_Requeue_Statement);
+ return Flag1 (N);
+ end Is_Elaboration_Checks_OK_Node;
+
function Is_Elsif
- (N : Node_Id) return Boolean is
+ (N : Node_Id) return Boolean is
begin
pragma Assert (False
or else NT (N).Nkind = N_If_Expression);
@@ -1972,6 +2015,25 @@ package body Sinfo is
return Flag4 (N);
end Is_Inherited_Pragma;
+ function Is_Initialization_Block
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Block_Statement);
+ return Flag1 (N);
+ end Is_Initialization_Block;
+
+ function Is_Known_Guaranteed_ABE
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Instantiation);
+ return Flag18 (N);
+ end Is_Known_Guaranteed_ABE;
+
function Is_Machine_Number
(N : Node_Id) return Boolean is
begin
@@ -2028,6 +2090,44 @@ package body Sinfo is
return Flag4 (N);
end Is_Qualified_Universal_Literal;
+ function Is_Recorded_Scenario
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Instantiation);
+ return Flag6 (N);
+ end Is_Recorded_Scenario;
+
+ function Is_Source_Call
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker);
+ return Flag4 (N);
+ end Is_Source_Call;
+
+ function Is_SPARK_Mode_On_Node
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Assignment_Statement
+ or else NT (N).Nkind = N_Attribute_Reference
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Entry_Call_Statement
+ or else NT (N).Nkind = N_Expanded_Name
+ or else NT (N).Nkind = N_Function_Call
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Identifier
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Call_Statement
+ or else NT (N).Nkind = N_Procedure_Instantiation
+ or else NT (N).Nkind = N_Requeue_Statement);
+ return Flag2 (N);
+ end Is_SPARK_Mode_On_Node;
+
function Is_Static_Coextension
(N : Node_Id) return Boolean is
begin
@@ -2254,7 +2354,9 @@ package body Sinfo is
or else NT (N).Nkind = N_Formal_Object_Declaration
or else NT (N).Nkind = N_Number_Declaration
or else NT (N).Nkind = N_Object_Declaration
- or else NT (N).Nkind = N_Parameter_Specification);
+ or else NT (N).Nkind = N_Parameter_Specification
+ or else NT (N).Nkind = N_Use_Package_Clause
+ or else NT (N).Nkind = N_Use_Type_Clause);
return Flag5 (N);
end More_Ids;
@@ -2328,6 +2430,7 @@ package body Sinfo is
or else NT (N).Nkind = N_Requeue_Statement
or else NT (N).Nkind = N_Subprogram_Renaming_Declaration
or else NT (N).Nkind = N_Subunit
+ or else NT (N).Nkind = N_Use_Package_Clause
or else NT (N).Nkind = N_Variant_Part
or else NT (N).Nkind = N_With_Clause);
return Node2 (N);
@@ -2337,8 +2440,7 @@ package body Sinfo is
(N : Node_Id) return List_Id is
begin
pragma Assert (False
- or else NT (N).Nkind = N_Abort_Statement
- or else NT (N).Nkind = N_Use_Package_Clause);
+ or else NT (N).Nkind = N_Abort_Statement);
return List2 (N);
end Names;
@@ -2413,15 +2515,6 @@ package body Sinfo is
return Flag7 (N);
end No_Ctrl_Actions;
- function No_Elaboration_Check
- (N : Node_Id) return Boolean is
- begin
- pragma Assert (False
- or else NT (N).Nkind = N_Function_Call
- or else NT (N).Nkind = N_Procedure_Call_Statement);
- return Flag14 (N);
- end No_Elaboration_Check;
-
function No_Entities_Ref_In_Spec
(N : Node_Id) return Boolean is
begin
@@ -2453,7 +2546,7 @@ package body Sinfo is
begin
pragma Assert (False
or else NT (N).Nkind = N_Function_Call);
- return Flag1 (N);
+ return Flag17 (N);
end No_Side_Effect_Removal;
function No_Truncation
@@ -2723,10 +2816,21 @@ package body Sinfo is
or else NT (N).Nkind = N_Formal_Object_Declaration
or else NT (N).Nkind = N_Number_Declaration
or else NT (N).Nkind = N_Object_Declaration
- or else NT (N).Nkind = N_Parameter_Specification);
+ or else NT (N).Nkind = N_Parameter_Specification
+ or else NT (N).Nkind = N_Use_Package_Clause
+ or else NT (N).Nkind = N_Use_Type_Clause);
return Flag6 (N);
end Prev_Ids;
+ function Prev_Use_Clause
+ (N : Node_Id) return Node_Id is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Use_Package_Clause
+ or else NT (N).Nkind = N_Use_Type_Clause);
+ return Node1 (N);
+ end Prev_Use_Clause;
+
function Print_In_Hex
(N : Node_Id) return Boolean is
begin
@@ -3133,7 +3237,8 @@ package body Sinfo is
or else NT (N).Nkind = N_Qualified_Expression
or else NT (N).Nkind = N_Subtype_Indication
or else NT (N).Nkind = N_Type_Conversion
- or else NT (N).Nkind = N_Unchecked_Type_Conversion);
+ or else NT (N).Nkind = N_Unchecked_Type_Conversion
+ or else NT (N).Nkind = N_Use_Type_Clause);
return Node4 (N);
end Subtype_Mark;
@@ -3141,8 +3246,7 @@ package body Sinfo is
(N : Node_Id) return List_Id is
begin
pragma Assert (False
- or else NT (N).Nkind = N_Unconstrained_Array_Definition
- or else NT (N).Nkind = N_Use_Type_Clause);
+ or else NT (N).Nkind = N_Unconstrained_Array_Definition);
return List2 (N);
end Subtype_Marks;
@@ -3169,6 +3273,14 @@ package body Sinfo is
return Flag15 (N);
end Tagged_Present;
+ function Target
+ (N : Node_Id) return Entity_Id is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker);
+ return Node1 (N);
+ end Target;
+
function Target_Type
(N : Node_Id) return Entity_Id is
begin
@@ -3338,9 +3450,17 @@ package body Sinfo is
begin
pragma Assert (False
or else NT (N).Nkind = N_Use_Type_Clause);
- return Elist5 (N);
+ return Elist2 (N);
end Used_Operations;
+ function Was_Attribute_Reference
+ (N : Node_Id) return Boolean is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Subprogram_Body);
+ return Flag2 (N);
+ end Was_Attribute_Reference;
+
function Was_Expression_Function
(N : Node_Id) return Boolean is
begin
@@ -3372,19 +3492,6 @@ package body Sinfo is
-- Field Set Procedures --
--------------------------
- procedure Set_ABE_Is_Certain
- (N : Node_Id; Val : Boolean := True) is
- begin
- pragma Assert (False
- or else NT (N).Nkind = N_Formal_Package_Declaration
- or else NT (N).Nkind = N_Function_Call
- or else NT (N).Nkind = N_Function_Instantiation
- or else NT (N).Nkind = N_Package_Instantiation
- or else NT (N).Nkind = N_Procedure_Call_Statement
- or else NT (N).Nkind = N_Procedure_Instantiation);
- Set_Flag18 (N, Val);
- end Set_ABE_Is_Certain;
-
procedure Set_Abort_Present
(N : Node_Id; Val : Boolean := True) is
begin
@@ -3527,6 +3634,14 @@ package body Sinfo is
Set_Flag4 (N, Val);
end Set_Aliased_Present;
+ procedure Set_Alloc_For_BIP_Return
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Allocator);
+ Set_Flag1 (N, Val);
+ end Set_Alloc_For_BIP_Return;
+
procedure Set_All_Others
(N : Node_Id; Val : Boolean := True) is
begin
@@ -3609,7 +3724,8 @@ package body Sinfo is
or else NT (N).Nkind in N_Has_Entity
or else NT (N).Nkind = N_Aggregate
or else NT (N).Nkind = N_Extension_Aggregate
- or else NT (N).Nkind = N_Selected_Component);
+ or else NT (N).Nkind = N_Selected_Component
+ or else NT (N).Nkind = N_Use_Package_Clause);
Set_Node4 (N, Val); -- semantic field, no parent set
end Set_Associated_Node;
@@ -4261,7 +4377,7 @@ package body Sinfo is
or else NT (N).Nkind = N_Assignment_Statement
or else NT (N).Nkind = N_Selected_Component
or else NT (N).Nkind = N_Type_Conversion);
- Set_Flag1 (N, Val);
+ Set_Flag3 (N, Val);
end Set_Do_Discriminant_Check;
procedure Set_Do_Division_Check
@@ -4948,7 +5064,7 @@ package body Sinfo is
pragma Assert (False
or else NT (N).Nkind = N_Use_Package_Clause
or else NT (N).Nkind = N_Use_Type_Clause);
- Set_Elist4 (N, Val);
+ Set_Elist5 (N, Val);
end Set_Hidden_By_Use_Clause;
procedure Set_High_Bound
@@ -5157,6 +5273,17 @@ package body Sinfo is
Set_Flag16 (N, Val);
end Set_Is_Controlling_Actual;
+ procedure Set_Is_Declaration_Level_Node
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Instantiation);
+ Set_Flag5 (N, Val);
+ end Set_Is_Declaration_Level_Node;
+
procedure Set_Is_Delayed_Aspect
(N : Node_Id; Val : Boolean := True) is
begin
@@ -5176,6 +5303,14 @@ package body Sinfo is
Set_Flag15 (N, Val);
end Set_Is_Disabled;
+ procedure Set_Is_Dispatching_Call
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker);
+ Set_Flag3 (N, Val);
+ end Set_Is_Dispatching_Call;
+
procedure Set_Is_Dynamic_Coextension
(N : Node_Id; Val : Boolean := True) is
begin
@@ -5184,8 +5319,36 @@ package body Sinfo is
Set_Flag18 (N, Val);
end Set_Is_Dynamic_Coextension;
+ procedure Set_Is_Effective_Use_Clause
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Use_Package_Clause
+ or else NT (N).Nkind = N_Use_Type_Clause);
+ Set_Flag1 (N, Val);
+ end Set_Is_Effective_Use_Clause;
+
+ procedure Set_Is_Elaboration_Checks_OK_Node
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Assignment_Statement
+ or else NT (N).Nkind = N_Attribute_Reference
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Entry_Call_Statement
+ or else NT (N).Nkind = N_Expanded_Name
+ or else NT (N).Nkind = N_Function_Call
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Identifier
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Call_Statement
+ or else NT (N).Nkind = N_Procedure_Instantiation
+ or else NT (N).Nkind = N_Requeue_Statement);
+ Set_Flag1 (N, Val);
+ end Set_Is_Elaboration_Checks_OK_Node;
+
procedure Set_Is_Elsif
- (N : Node_Id; Val : Boolean := True) is
+ (N : Node_Id; Val : Boolean := True) is
begin
pragma Assert (False
or else NT (N).Nkind = N_If_Expression);
@@ -5274,6 +5437,25 @@ package body Sinfo is
Set_Flag4 (N, Val);
end Set_Is_Inherited_Pragma;
+ procedure Set_Is_Initialization_Block
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Block_Statement);
+ Set_Flag1 (N, Val);
+ end Set_Is_Initialization_Block;
+
+ procedure Set_Is_Known_Guaranteed_ABE
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Instantiation);
+ Set_Flag18 (N, Val);
+ end Set_Is_Known_Guaranteed_ABE;
+
procedure Set_Is_Machine_Number
(N : Node_Id; Val : Boolean := True) is
begin
@@ -5330,6 +5512,44 @@ package body Sinfo is
Set_Flag4 (N, Val);
end Set_Is_Qualified_Universal_Literal;
+ procedure Set_Is_Recorded_Scenario
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Instantiation);
+ Set_Flag6 (N, Val);
+ end Set_Is_Recorded_Scenario;
+
+ procedure Set_Is_Source_Call
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker);
+ Set_Flag4 (N, Val);
+ end Set_Is_Source_Call;
+
+ procedure Set_Is_SPARK_Mode_On_Node
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Assignment_Statement
+ or else NT (N).Nkind = N_Attribute_Reference
+ or else NT (N).Nkind = N_Call_Marker
+ or else NT (N).Nkind = N_Entry_Call_Statement
+ or else NT (N).Nkind = N_Expanded_Name
+ or else NT (N).Nkind = N_Function_Call
+ or else NT (N).Nkind = N_Function_Instantiation
+ or else NT (N).Nkind = N_Identifier
+ or else NT (N).Nkind = N_Package_Instantiation
+ or else NT (N).Nkind = N_Procedure_Call_Statement
+ or else NT (N).Nkind = N_Procedure_Instantiation
+ or else NT (N).Nkind = N_Requeue_Statement);
+ Set_Flag2 (N, Val);
+ end Set_Is_SPARK_Mode_On_Node;
+
procedure Set_Is_Static_Coextension
(N : Node_Id; Val : Boolean := True) is
begin
@@ -5556,7 +5776,9 @@ package body Sinfo is
or else NT (N).Nkind = N_Formal_Object_Declaration
or else NT (N).Nkind = N_Number_Declaration
or else NT (N).Nkind = N_Object_Declaration
- or else NT (N).Nkind = N_Parameter_Specification);
+ or else NT (N).Nkind = N_Parameter_Specification
+ or else NT (N).Nkind = N_Use_Package_Clause
+ or else NT (N).Nkind = N_Use_Type_Clause);
Set_Flag5 (N, Val);
end Set_More_Ids;
@@ -5630,6 +5852,7 @@ package body Sinfo is
or else NT (N).Nkind = N_Requeue_Statement
or else NT (N).Nkind = N_Subprogram_Renaming_Declaration
or else NT (N).Nkind = N_Subunit
+ or else NT (N).Nkind = N_Use_Package_Clause
or else NT (N).Nkind = N_Variant_Part
or else NT (N).Nkind = N_With_Clause);
Set_Node2_With_Parent (N, Val);
@@ -5639,8 +5862,7 @@ package body Sinfo is
(N : Node_Id; Val : List_Id) is
begin
pragma Assert (False
- or else NT (N).Nkind = N_Abort_Statement
- or else NT (N).Nkind = N_Use_Package_Clause);
+ or else NT (N).Nkind = N_Abort_Statement);
Set_List2_With_Parent (N, Val);
end Set_Names;
@@ -5715,15 +5937,6 @@ package body Sinfo is
Set_Flag7 (N, Val);
end Set_No_Ctrl_Actions;
- procedure Set_No_Elaboration_Check
- (N : Node_Id; Val : Boolean := True) is
- begin
- pragma Assert (False
- or else NT (N).Nkind = N_Function_Call
- or else NT (N).Nkind = N_Procedure_Call_Statement);
- Set_Flag14 (N, Val);
- end Set_No_Elaboration_Check;
-
procedure Set_No_Entities_Ref_In_Spec
(N : Node_Id; Val : Boolean := True) is
begin
@@ -5755,7 +5968,7 @@ package body Sinfo is
begin
pragma Assert (False
or else NT (N).Nkind = N_Function_Call);
- Set_Flag1 (N, Val);
+ Set_Flag17 (N, Val);
end Set_No_Side_Effect_Removal;
procedure Set_No_Truncation
@@ -6025,10 +6238,21 @@ package body Sinfo is
or else NT (N).Nkind = N_Formal_Object_Declaration
or else NT (N).Nkind = N_Number_Declaration
or else NT (N).Nkind = N_Object_Declaration
- or else NT (N).Nkind = N_Parameter_Specification);
+ or else NT (N).Nkind = N_Parameter_Specification
+ or else NT (N).Nkind = N_Use_Package_Clause
+ or else NT (N).Nkind = N_Use_Type_Clause);
Set_Flag6 (N, Val);
end Set_Prev_Ids;
+ procedure Set_Prev_Use_Clause
+ (N : Node_Id; Val : Node_Id) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Use_Package_Clause
+ or else NT (N).Nkind = N_Use_Type_Clause);
+ Set_Node1 (N, Val); -- semantic field, no parent set
+ end Set_Prev_Use_Clause;
+
procedure Set_Print_In_Hex
(N : Node_Id; Val : Boolean := True) is
begin
@@ -6418,7 +6642,8 @@ package body Sinfo is
or else NT (N).Nkind = N_Qualified_Expression
or else NT (N).Nkind = N_Subtype_Indication
or else NT (N).Nkind = N_Type_Conversion
- or else NT (N).Nkind = N_Unchecked_Type_Conversion);
+ or else NT (N).Nkind = N_Unchecked_Type_Conversion
+ or else NT (N).Nkind = N_Use_Type_Clause);
Set_Node4_With_Parent (N, Val);
end Set_Subtype_Mark;
@@ -6426,8 +6651,7 @@ package body Sinfo is
(N : Node_Id; Val : List_Id) is
begin
pragma Assert (False
- or else NT (N).Nkind = N_Unconstrained_Array_Definition
- or else NT (N).Nkind = N_Use_Type_Clause);
+ or else NT (N).Nkind = N_Unconstrained_Array_Definition);
Set_List2_With_Parent (N, Val);
end Set_Subtype_Marks;
@@ -6471,6 +6695,14 @@ package body Sinfo is
Set_Flag15 (N, Val);
end Set_Tagged_Present;
+ procedure Set_Target
+ (N : Node_Id; Val : Entity_Id) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Call_Marker);
+ Set_Node1 (N, Val); -- semantic field, no parent set
+ end Set_Target;
+
procedure Set_Target_Type
(N : Node_Id; Val : Entity_Id) is
begin
@@ -6640,9 +6872,17 @@ package body Sinfo is
begin
pragma Assert (False
or else NT (N).Nkind = N_Use_Type_Clause);
- Set_Elist5 (N, Val);
+ Set_Elist2 (N, Val);
end Set_Used_Operations;
+ procedure Set_Was_Attribute_Reference
+ (N : Node_Id; Val : Boolean := True) is
+ begin
+ pragma Assert (False
+ or else NT (N).Nkind = N_Subprogram_Body);
+ Set_Flag2 (N, Val);
+ end Set_Was_Attribute_Reference;
+
procedure Set_Was_Expression_Function
(N : Node_Id; Val : Boolean := True) is
begin
diff --git a/gcc/ada/sinfo.ads b/gcc/ada/sinfo.ads
index a5a6413..cf220e4 100644
--- a/gcc/ada/sinfo.ads
+++ b/gcc/ada/sinfo.ads
@@ -770,7 +770,7 @@ package Sinfo is
-- The following flag fields appear in all nodes:
-- Analyzed
- -- This flag is used to indicate that a node (and all its children have
+ -- This flag is used to indicate that a node (and all its children) have
-- been analyzed. It is used to avoid reanalysis of a node that has
-- already been analyzed, both for efficiency and functional correctness
-- reasons.
@@ -845,15 +845,6 @@ package Sinfo is
-- section describes the usage of the semantic fields, which are used to
-- contain additional information determined during semantic analysis.
- -- ABE_Is_Certain (Flag18-Sem)
- -- This flag is set in an instantiation node or a call node is determined
- -- to be sure to raise an ABE. This is used to trigger special handling
- -- of such cases, particularly in the instantiation case where we avoid
- -- instantiating the body if this flag is set. This flag is also present
- -- in an N_Formal_Package_Declaration node since formal package
- -- declarations are treated like instantiations, but it is always set to
- -- False in this context.
-
-- Accept_Handler_Records (List5-Sem)
-- This field is present only in an N_Accept_Alternative node. It is used
-- to temporarily hold the exception handler records from an accept
@@ -912,6 +903,10 @@ package Sinfo is
-- known at compile time, this field points to an N_Range node with those
-- bounds. Otherwise Empty.
+ -- Alloc_For_BIP_Return (Flag1-Sem)
+ -- Present in N_Allocator nodes. True if the allocator is one of those
+ -- generated for a build-in-place return statement.
+
-- All_Others (Flag11-Sem)
-- Present in an N_Others_Choice node. This flag is set for an others
-- exception where all exceptions are to be caught, even those that are
@@ -1159,7 +1154,7 @@ package Sinfo is
-- that an accessibility check is required for the parameter. It is
-- not yet decided who takes care of this check (TBD ???).
- -- Do_Discriminant_Check (Flag1-Sem)
+ -- Do_Discriminant_Check (Flag3-Sem)
-- This flag is set on N_Selected_Component nodes to indicate that a
-- discriminant check is required using the discriminant check routine
-- associated with the selector. The actual check is generated by the
@@ -1372,9 +1367,9 @@ package Sinfo is
-- up. For nested aggregates the expansion is delayed until the enclosing
-- aggregate itself is expanded, e.g. in the context of a declaration. To
-- delay it we set this flag. This is done to avoid creating a temporary
- -- for each level of a nested aggregates, and also to prevent the
+ -- for each level of a nested aggregate, and also to prevent the
-- premature generation of constraint checks. This is also a requirement
- -- if we want to generate the proper attachment to the internal
+ -- if we want to generate the proper attachment to the internal????
-- finalization lists (for record with controlled components). Top down
-- expansion of aggregates is also used for in-place array aggregate
-- assignment or initialization. When the full context is known, the
@@ -1481,10 +1476,7 @@ package Sinfo is
-- Generic_Parent (Node5-Sem)
-- Generic_Parent is defined on declaration nodes that are instances. The
-- value of Generic_Parent is the generic entity from which the instance
- -- is obtained. Generic_Parent is also defined for the renaming
- -- declarations and object declarations created for the actuals in an
- -- instantiation. The generic parent of such a declaration is the
- -- corresponding generic association in the Instantiation node.
+ -- is obtained.
-- Generic_Parent_Type (Node4-Sem)
-- Generic_Parent_Type is defined on Subtype_Declaration nodes for the
@@ -1596,7 +1588,7 @@ package Sinfo is
-- added to the size of the prefix. The flag also prevents the infinite
-- expansion of the same attribute in the said context.
- -- Hidden_By_Use_Clause (Elist4-Sem)
+ -- Hidden_By_Use_Clause (Elist5-Sem)
-- An entity list present in use clauses that appear within
-- instantiations. For the resolution of local entities, entities
-- introduced by these use clauses have priority over global ones, and
@@ -1663,10 +1655,6 @@ package Sinfo is
-- place in the various Analyze_xxx_In_Decl_Part routines which perform
-- full analysis. The flag prevents the reanalysis of a delayed pragma.
- -- Is_Expanded_Contract (Flag1-Sem)
- -- Present in N_Contract nodes. Set if the contract has already undergone
- -- expansion activities.
-
-- Is_Asynchronous_Call_Block (Flag7-Sem)
-- A flag set in a Block_Statement node to indicate that it is the
-- expansion of an asynchronous entry call. Such a block needs cleanup
@@ -1701,6 +1689,12 @@ package Sinfo is
-- a dispatching call. It is off in all other cases. See Sem_Disp for
-- details of its use.
+ -- Is_Declaration_Level_Node (Flag5-Sem)
+ -- Present in call marker and instantiation nodes. Set when the constuct
+ -- appears within the declarations of a block statement, an entry body,
+ -- a subprogram body, or a task body. The flag aids the ABE Processing
+ -- phase to catch certain forms of guaranteed ABEs.
+
-- Is_Delayed_Aspect (Flag14-Sem)
-- Present in N_Pragma and N_Attribute_Definition_Clause nodes which
-- come from aspect specifications, where the evaluation of the aspect
@@ -1715,12 +1709,29 @@ package Sinfo is
-- If this flag is set, the aspect or policy is not analyzed for semantic
-- correctness, so any expressions etc will not be marked as analyzed.
+ -- Is_Dispatching_Call (Flag3-Sem)
+ -- Present in call marker nodes. Set when the related call which prompted
+ -- the creation of the marker is dispatching.
+
-- Is_Dynamic_Coextension (Flag18-Sem)
-- Present in allocator nodes, to indicate that this is an allocator
-- for an access discriminant of a dynamically allocated object. The
-- coextension must be deallocated and finalized at the same time as
-- the enclosing object.
+ -- Is_Effective_Use_Clause (Flag1-Sem)
+ -- Present in both N_Use_Type_Clause and N_Use_Package_Clause to indicate
+ -- a use clause is "used" in the current source.
+
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Present in nodes which represent an elaboration scenario. Those are
+ -- assignment statement, attribute reference, call marker, entry call
+ -- statement, expanded name, function call, identifier, instantiation,
+ -- procedure call statement, and requeue statement nodes. Set when the
+ -- node appears within a context which allows for the generation of
+ -- run-time ABE checks. This flag detemines whether the ABE Processing
+ -- phase generates conditional ABE checks and guaranteed ABE failures.
+
-- Is_Entry_Barrier_Function (Flag8-Sem)
-- This flag is set on N_Subprogram_Declaration and N_Subprogram_Body
-- nodes which emulate the barrier function of a protected entry body.
@@ -1731,6 +1742,10 @@ package Sinfo is
-- actuals to support a build-in-place style of call have been added to
-- the call.
+ -- Is_Expanded_Contract (Flag1-Sem)
+ -- Present in N_Contract nodes. Set if the contract has already undergone
+ -- expansion activities.
+
-- Is_Finalization_Wrapper (Flag9-Sem)
-- This flag is present in N_Block_Statement nodes. It is set when the
-- block acts as a wrapper of a handled construct which has controlled
@@ -1790,6 +1805,19 @@ package Sinfo is
-- This flag is set in an N_Pragma node that appears in a N_Contract node
-- to indicate that the pragma has been inherited from a parent context.
+ -- Is_Initialization_Block (Flag1-Sem)
+ -- Defined in block nodes. Set when the block statement was created by
+ -- the finalization machinery to wrap initialization statements. This
+ -- flag aids the ABE Processing phase to suppress the diagnostics of
+ -- finalization actions in initialization contexts.
+
+ -- Is_Known_Guaranteed_ABE (Flag18-Sem)
+ -- Present in call markers and instantiations. Set when the elaboration
+ -- or evaluation of the scenario results in a guaranteed ABE. The flag
+ -- is used to suppress the instantiation of generic bodies because gigi
+ -- cannot handle certain forms of premature instantiation, as well as to
+ -- prevent the reexamination of the node by the ABE Processing phase.
+
-- Is_Machine_Number (Flag11-Sem)
-- This flag is set in an N_Real_Literal node to indicate that the value
-- is a machine number. This avoids some unnecessary cases of converting
@@ -1835,6 +1863,25 @@ package Sinfo is
-- the resolution of accidental overloading of binary or unary operators
-- which may occur in instances.
+ -- Is_Recorded_Scenario (Flag6-Sem)
+ -- Present in call marker and instantiation nodes. Set when the scenario
+ -- was saved by the ABE Recording phase. This flag aids the ABE machinery
+ -- to keep its internal data up-to-date in case the node is transformed
+ -- by Atree.Rewrite.
+
+ -- Is_Source_Call (Flag4-Sem)
+ -- Present in call marker nodes. Set when the related call came from
+ -- source.
+
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
+ -- Present in nodes which represent an elaboration scenario. Those are
+ -- assignment statement, attribute reference, call marker, entry call
+ -- statement, expanded name, function call, identifier, instantiation,
+ -- procedure call statement, and requeue statement nodes. Set when the
+ -- node appears within a context subject to SPARK_Mode On. This flag
+ -- determines when the SPARK model of elaboration be activated by the
+ -- ABE Processing phase.
+
-- Is_Static_Coextension (Flag14-Sem)
-- Present in N_Allocator nodes. Set if the allocator is a coextension
-- of an object allocated on the stack rather than the heap.
@@ -2036,13 +2083,6 @@ package Sinfo is
-- expansions where the generated assignments are initializations, not
-- real assignments.
- -- No_Elaboration_Check (Flag14-Sem)
- -- Present in N_Function_Call and N_Procedure_Call_Statement. Indicates
- -- that no elaboration check is needed on the call, because it appears in
- -- the context of a local Suppress pragma. This is used on calls within
- -- task bodies, where the actual elaboration checks are applied after
- -- analysis, when the local scope stack is not present.
-
-- No_Entities_Ref_In_Spec (Flag8-Sem)
-- Present in N_With_Clause nodes. Set if the with clause is on the
-- package or subprogram spec where the main unit is the corresponding
@@ -2065,7 +2105,7 @@ package Sinfo is
-- It is used to indicate that processing for extended overflow checking
-- modes is not required (this is used to prevent infinite recursion).
- -- No_Side_Effect_Removal (Flag1-Sem)
+ -- No_Side_Effect_Removal (Flag17-Sem)
-- Present in N_Function_Call nodes. Set when a function call does not
-- require side effect removal. This attribute suppresses the generation
-- of a temporary to capture the result of the function which eventually
@@ -2137,6 +2177,11 @@ package Sinfo is
-- ASIS processing (data decomposition annex) to determine if a field is
-- present or not.
+ -- Prev_Use_Clause (Node1-Sem)
+ -- Present in both N_Use_Package_Clause and N_Use_Type_Clause. Used in
+ -- detection of ineffective use clauses by allowing a chain of related
+ -- clauses together to avoid traversing the current scope stack.
+
-- Print_In_Hex (Flag13-Sem)
-- Set on an N_Integer_Literal node to indicate that the value should be
-- printed in hexadecimal in the sprint listing. Has no effect on
@@ -2272,6 +2317,10 @@ package Sinfo is
-- of a FOR loop is known to be null, or is probably null (loop would
-- only execute if invalid values are present).
+ -- Target (Node1-Sem)
+ -- Present in call marker nodes. References the entity of the entry,
+ -- operator, or subprogram invoked by the related call or requeue.
+
-- Target_Type (Node2-Sem)
-- Used in an N_Validate_Unchecked_Conversion node to point to the target
-- type entity for the unchecked conversion instantiation which gigi must
@@ -2338,12 +2387,18 @@ package Sinfo is
-- initialized. Used to warn if the corresponding actual type is not
-- a fully initialized type.
- -- Used_Operations (Elist5-Sem)
+ -- Used_Operations (Elist2-Sem)
-- Present in N_Use_Type_Clause nodes. Holds the list of operations that
-- are made potentially use-visible by the clause. Simplifies processing
-- on exit from the scope of the use_type_clause, in particular in the
-- case of Use_All_Type, when those operations several scopes.
+ -- Was_Attribute_Reference (Flag2-Sem)
+ -- Present in N_Subprogram_Body. Set to True if the original source is an
+ -- attribute reference which is an actual in a generic instantiation. The
+ -- instantiation prologue renames these attributes, and expansion later
+ -- converts them into subprogram bodies.
+
-- Was_Expression_Function (Flag18-Sem)
-- Present in N_Subprogram_Body. True if the original source had an
-- N_Expression_Function, which was converted to the N_Subprogram_Body
@@ -2469,9 +2524,11 @@ package Sinfo is
-- Entity (Node4-Sem)
-- Associated_Node (Node4-Sem)
-- Original_Discriminant (Node2-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
+ -- Has_Private_View (Flag11-Sem) (set in generic units)
-- Redundant_Use (Flag13-Sem)
-- Atomic_Sync_Required (Flag14-Sem)
- -- Has_Private_View (Flag11-Sem) (set in generic units)
-- plus fields for expression
--------------------------
@@ -2616,20 +2673,20 @@ package Sinfo is
-- Corresponding_Aspect (Node3-Sem) (set to Empty if not present)
-- Pragma_Identifier (Node4)
-- Next_Rep_Item (Node5-Sem)
- -- Class_Present (Flag6) set if from Aspect with 'Class
- -- From_Aspect_Specification (Flag13-Sem)
- -- Import_Interface_Present (Flag16-Sem)
+ -- Is_Generic_Contract_Pragma (Flag2-Sem)
+ -- Is_Checked_Ghost_Pragma (Flag3-Sem)
+ -- Is_Inherited_Pragma (Flag4-Sem)
-- Is_Analyzed_Pragma (Flag5-Sem)
+ -- Class_Present (Flag6) set if from Aspect with 'Class
+ -- Uneval_Old_Accept (Flag7-Sem)
+ -- Is_Ignored_Ghost_Pragma (Flag8-Sem)
+ -- Is_Ignored (Flag9-Sem)
-- Is_Checked (Flag11-Sem)
- -- Is_Checked_Ghost_Pragma (Flag3-Sem)
+ -- From_Aspect_Specification (Flag13-Sem)
-- Is_Delayed_Aspect (Flag14-Sem)
-- Is_Disabled (Flag15-Sem)
- -- Is_Generic_Contract_Pragma (Flag2-Sem)
- -- Is_Ignored (Flag9-Sem)
- -- Is_Ignored_Ghost_Pragma (Flag8-Sem)
- -- Is_Inherited_Pragma (Flag4-Sem)
+ -- Import_Interface_Present (Flag16-Sem)
-- Split_PPC (Flag17) set if corresponding aspect had Split_PPC set
- -- Uneval_Old_Accept (Flag7-Sem)
-- Uneval_Old_Warn (Flag18-Sem)
-- Note: we should have a section on what pragmas are passed on to
@@ -2908,7 +2965,7 @@ package Sinfo is
-- case the front end must generate an extra temporary and initialize
-- this temporary as required (the temporary itself is not atomic).
- -- Note: there is not node kind for object definition. Instead, the
+ -- Note: there is no node kind for object definition. Instead, the
-- corresponding field holds a subtype indication, an array type
-- definition, or (Ada 2005, AI-406) an access definition.
@@ -3771,8 +3828,8 @@ package Sinfo is
-- Sloc points to ALL
-- Prefix (Node3)
-- Actual_Designated_Subtype (Node4-Sem)
- -- Atomic_Sync_Required (Flag14-Sem)
-- Has_Dereference_Action (Flag13-Sem)
+ -- Atomic_Sync_Required (Flag14-Sem)
-- plus fields for expression
-------------------------------
@@ -3838,10 +3895,10 @@ package Sinfo is
-- Prefix (Node3)
-- Selector_Name (Node2)
-- Associated_Node (Node4-Sem)
- -- Do_Discriminant_Check (Flag1-Sem)
+ -- Do_Discriminant_Check (Flag3-Sem)
-- Is_In_Discriminant_Check (Flag11-Sem)
- -- Is_Prefixed_Call (Flag17-Sem)
-- Atomic_Sync_Required (Flag14-Sem)
+ -- Is_Prefixed_Call (Flag17-Sem)
-- plus fields for expression
--------------------------
@@ -3934,10 +3991,11 @@ package Sinfo is
-- Expressions (List1) (set to No_List if no associated expressions)
-- Entity (Node4-Sem) used if the attribute yields a type
-- Associated_Node (Node4-Sem)
- -- Do_Overflow_Check (Flag17-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
-- Header_Size_Added (Flag11-Sem)
- -- Must_Be_Byte_Aligned (Flag14-Sem)
-- Redundant_Use (Flag13-Sem)
+ -- Must_Be_Byte_Aligned (Flag14-Sem)
-- plus fields for expression
-- Note: in Modify_Tree_For_C mode, Max and Min attributes are expanded
@@ -4128,7 +4186,7 @@ package Sinfo is
----------------------------------
-- NAMED_ARRAY_AGGREGATE ::=
- -- | (ARRAY_COMPONENT_ASSOCIATION {, ARRAY_COMPONENT_ASSOCIATION})
+ -- (ARRAY_COMPONENT_ASSOCIATION {, ARRAY_COMPONENT_ASSOCIATION})
-- See Record_Aggregate (4.3.1) for node structure
@@ -4665,7 +4723,7 @@ package Sinfo is
-- Sloc points to first token of subtype mark
-- Subtype_Mark (Node4)
-- Expression (Node3)
- -- Do_Discriminant_Check (Flag1-Sem)
+ -- Do_Discriminant_Check (Flag3-Sem)
-- Do_Length_Check (Flag4-Sem)
-- Float_Truncate (Flag11-Sem)
-- Do_Tag_Check (Flag13-Sem)
@@ -4719,6 +4777,7 @@ package Sinfo is
-- Subpool_Handle_Name (Node4) (set to Empty if not present)
-- Storage_Pool (Node1-Sem)
-- Procedure_To_Call (Node2-Sem)
+ -- Alloc_For_BIP_Return (Flag1-Sem)
-- Null_Exclusion_Present (Flag11)
-- No_Initialization (Flag13-Sem)
-- Is_Static_Coextension (Flag14-Sem)
@@ -4830,13 +4889,15 @@ package Sinfo is
-- Sloc points to :=
-- Name (Node2)
-- Expression (Node3)
- -- Do_Discriminant_Check (Flag1-Sem)
- -- Do_Tag_Check (Flag13-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
+ -- Do_Discriminant_Check (Flag3-Sem)
-- Do_Length_Check (Flag4-Sem)
-- Forwards_OK (Flag5-Sem)
-- Backwards_OK (Flag6-Sem)
-- No_Ctrl_Actions (Flag7-Sem)
-- Has_Target_Names (Flag8-Sem)
+ -- Do_Tag_Check (Flag13-Sem)
-- Componentwise_Assignment (Flag14-Sem)
-- Suppress_Assignment_Checks (Flag18-Sem)
@@ -5092,15 +5153,16 @@ package Sinfo is
-- Identifier (Node1) block direct name (set to Empty if not present)
-- Declarations (List2) (set to No_List if no DECLARE part)
-- Handled_Statement_Sequence (Node4)
- -- Cleanup_Actions (List5-Sem)
- -- Is_Abort_Block (Flag4-Sem)
- -- Is_Task_Master (Flag5-Sem)
-- Activation_Chain_Entity (Node3-Sem)
+ -- Cleanup_Actions (List5-Sem)
-- Has_Created_Identifier (Flag15)
- -- Is_Task_Allocation_Block (Flag6)
-- Is_Asynchronous_Call_Block (Flag7)
+ -- Is_Task_Allocation_Block (Flag6)
-- Exception_Junk (Flag8-Sem)
+ -- Is_Abort_Block (Flag4-Sem)
-- Is_Finalization_Wrapper (Flag9-Sem)
+ -- Is_Initialization_Block (Flag1-Sem)
+ -- Is_Task_Master (Flag5-Sem)
-------------------------
-- 5.7 Exit Statement --
@@ -5264,8 +5326,8 @@ package Sinfo is
-- symbol turns out to be a normal string after all.
-- Entity (Node4-Sem)
-- Associated_Node (Node4-Sem)
- -- Has_Private_View (Flag11-Sem) set in generic units.
-- Etype (Node5-Sem)
+ -- Has_Private_View (Flag11-Sem) set in generic units
-- Note: the Strval field may be set to No_String for generated
-- operator symbols that are known not to be string literals
@@ -5390,6 +5452,7 @@ package Sinfo is
-- Is_Protected_Subprogram_Body (Flag7-Sem)
-- Is_Task_Body_Procedure (Flag1-Sem)
-- Is_Task_Master (Flag5-Sem)
+ -- Was_Attribute_Reference (Flag2-Sem)
-- Was_Expression_Function (Flag18-Sem)
-- Was_Originally_Stub (Flag13-Sem)
@@ -5413,9 +5476,9 @@ package Sinfo is
-- actual parameter part)
-- First_Named_Actual (Node4-Sem)
-- Controlling_Argument (Node1-Sem) (set to Empty if not dispatching)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
-- Do_Tag_Check (Flag13-Sem)
- -- No_Elaboration_Check (Flag14-Sem)
- -- ABE_Is_Certain (Flag18-Sem)
-- plus fields for expression
-- If any IN parameter requires a range check, then the corresponding
@@ -5443,11 +5506,11 @@ package Sinfo is
-- actual parameter part)
-- First_Named_Actual (Node4-Sem)
-- Controlling_Argument (Node1-Sem) (set to Empty if not dispatching)
- -- No_Side_Effect_Removal (Flag1-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
-- Is_Expanded_Build_In_Place_Call (Flag11-Sem)
-- Do_Tag_Check (Flag13-Sem)
- -- No_Elaboration_Check (Flag14-Sem)
- -- ABE_Is_Certain (Flag18-Sem)
+ -- No_Side_Effect_Removal (Flag17-Sem)
-- plus fields for expression
--------------------------------
@@ -5687,9 +5750,14 @@ package Sinfo is
-- N_Use_Package_Clause
-- Sloc points to USE
- -- Names (List2)
+ -- Prev_Use_Clause (Node1-Sem)
+ -- Name (Node2)
-- Next_Use_Clause (Node3-Sem)
- -- Hidden_By_Use_Clause (Elist4-Sem)
+ -- Associated_Node (Node4-Sem)
+ -- Hidden_By_Use_Clause (Elist5-Sem)
+ -- Is_Effective_Use_Clause (Flag1)
+ -- More_Ids (Flag5) (set to False if no more identifiers in list)
+ -- Prev_Ids (Flag6) (set to False if no previous identifiers in list)
--------------------------
-- 8.4 Use Type Clause --
@@ -5703,10 +5771,14 @@ package Sinfo is
-- N_Use_Type_Clause
-- Sloc points to USE
- -- Subtype_Marks (List2)
+ -- Prev_Use_Clause (Node1-Sem)
+ -- Used_Operations (Elist2-Sem)
-- Next_Use_Clause (Node3-Sem)
- -- Hidden_By_Use_Clause (Elist4-Sem)
- -- Used_Operations (Elist5-Sem)
+ -- Subtype_Mark (Node4)
+ -- Hidden_By_Use_Clause (Elist5-Sem)
+ -- Is_Effective_Use_Clause (Flag1)
+ -- More_Ids (Flag5) (set to False if no more identifiers in list)
+ -- Prev_Ids (Flag6) (set to False if no previous identifiers in list)
-- All_Present (Flag15)
-------------------------------
@@ -6147,6 +6219,8 @@ package Sinfo is
-- Parameter_Associations (List3) (set to No_List if no
-- actual parameter part)
-- First_Named_Actual (Node4-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
------------------------------
-- 9.5.4 Requeue Statement --
@@ -6162,6 +6236,8 @@ package Sinfo is
-- Sloc points to REQUEUE
-- Name (Node2)
-- Abort_Present (Flag15)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
--------------------------
-- 9.6 Delay Statement --
@@ -6957,7 +7033,11 @@ package Sinfo is
-- generic actual part)
-- Parent_Spec (Node4-Sem)
-- Instance_Spec (Node5-Sem)
- -- ABE_Is_Certain (Flag18-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
+ -- Is_Declaration_Level_Node (Flag5-Sem)
+ -- Is_Recorded_Scenario (Flag6-Sem)
+ -- Is_Known_Guaranteed_ABE (Flag18-Sem)
-- N_Procedure_Instantiation
-- Sloc points to PROCEDURE
@@ -6967,9 +7047,13 @@ package Sinfo is
-- Generic_Associations (List3) (set to No_List if no
-- generic actual part)
-- Instance_Spec (Node5-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
+ -- Is_Declaration_Level_Node (Flag5-Sem)
+ -- Is_Recorded_Scenario (Flag6-Sem)
-- Must_Override (Flag14) set if overriding indicator present
-- Must_Not_Override (Flag15) set if not_overriding indicator present
- -- ABE_Is_Certain (Flag18-Sem)
+ -- Is_Known_Guaranteed_ABE (Flag18-Sem)
-- N_Function_Instantiation
-- Sloc points to FUNCTION
@@ -6979,9 +7063,13 @@ package Sinfo is
-- generic actual part)
-- Parent_Spec (Node4-Sem)
-- Instance_Spec (Node5-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
+ -- Is_Declaration_Level_Node (Flag5-Sem)
+ -- Is_Recorded_Scenario (Flag6-Sem)
-- Must_Override (Flag14) set if overriding indicator present
-- Must_Not_Override (Flag15) set if not_overriding indicator present
- -- ABE_Is_Certain (Flag18-Sem)
+ -- Is_Known_Guaranteed_ABE (Flag18-Sem)
-- Note: overriding indicator is an Ada 2005 feature
@@ -7294,7 +7382,6 @@ package Sinfo is
-- empty generic actual part)
-- Box_Present (Flag15)
-- Instance_Spec (Node5-Sem)
- -- ABE_Is_Certain (Flag18-Sem)
--------------------------------------
-- 12.7 Formal Package Actual Part --
@@ -7704,6 +7791,42 @@ package Sinfo is
-- reconstructed tree printed by Sprint, and the node descriptions here
-- show this syntax.
+ -----------------
+ -- Call_Marker --
+ -----------------
+
+ -- This node is created during the analysis/resolution of entry calls,
+ -- requeues, and subprogram calls. It performs several functions:
+
+ -- * Call markers provide a uniform model for handling calls by the
+ -- ABE mechanism, regardless of whether expansion took place.
+
+ -- * The call marker captures the target of the related call along
+ -- with other attributes which are either unavailabe or expensive
+ -- to recompute once analysis, resolution, and expansion are over.
+
+ -- * The call marker aids the ABE Processing phase by signaling the
+ -- presence of a call in case the original call was transformed by
+ -- expansion.
+
+ -- * The call marker acts as a reference point for the insertion of
+ -- run-time conditional ABE checks or guaranteed ABE failures.
+
+ -- Sprint syntax: #target#
+
+ -- The Sprint syntax shown above is not enabled by default
+
+ -- N_Call_Marker
+ -- Sloc points to Sloc of original call
+ -- Target (Node1-Sem)
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
+ -- Is_Dispatching_Call (Flag3-Sem)
+ -- Is_Source_Call (Flag4-Sem)
+ -- Is_Declaration_Level_Node (Flag5-Sem)
+ -- Is_Recorded_Scenario (Flag6-Sem)
+ -- Is_Known_Guaranteed_ABE (Flag18-Sem)
+
------------------------
-- Compound Statement --
------------------------
@@ -7719,7 +7842,7 @@ package Sinfo is
-- The required semantics is that the set of actions is executed in
-- the order in which it appears, as though they appeared by themselves
- -- in the enclosing list of declarations of statements. Unlike what
+ -- in the enclosing list of declarations or statements. Unlike what
-- happens when using an N_Block_Statement, no new scope is introduced.
-- Note: for the time being, this is used only as a transient
@@ -7833,7 +7956,9 @@ package Sinfo is
-- Selector_Name (Node2)
-- Entity (Node4-Sem)
-- Associated_Node (Node4-Sem)
- -- Has_Private_View (Flag11-Sem) set in generic units.
+ -- Is_Elaboration_Checks_OK_Node (Flag1-Sem)
+ -- Is_SPARK_Mode_On_Node (Flag2-Sem)
+ -- Has_Private_View (Flag11-Sem) set in generic units
-- Redundant_Use (Flag13-Sem)
-- Atomic_Sync_Required (Flag14-Sem)
-- plus fields for expression
@@ -8334,8 +8459,8 @@ package Sinfo is
-- Empty --
-----------
- -- Used as the contents of the Nkind field of the dummy Empty node
- -- and in some other situations to indicate an uninitialized value.
+ -- Used as the contents of the Nkind field of the dummy Empty node and in
+ -- some other situations to indicate an uninitialized value.
-- N_Empty
-- Chars (Name1) is set to No_Name
@@ -8691,6 +8816,7 @@ package Sinfo is
N_Access_Definition,
N_Access_To_Object_Definition,
N_Aspect_Specification,
+ N_Call_Marker,
N_Case_Expression_Alternative,
N_Case_Statement_Alternative,
N_Compilation_Unit,
@@ -8959,9 +9085,6 @@ package Sinfo is
-- these routines check that they are being applied to an appropriate
-- node, as well as checking that the node is in range.
- function ABE_Is_Certain
- (N : Node_Id) return Boolean; -- Flag18
-
function Abort_Present
(N : Node_Id) return Boolean; -- Flag15
@@ -9007,6 +9130,9 @@ package Sinfo is
function Aliased_Present
(N : Node_Id) return Boolean; -- Flag4
+ function Alloc_For_BIP_Return
+ (N : Node_Id) return Boolean; -- Flag1
+
function All_Others
(N : Node_Id) return Boolean; -- Flag11
@@ -9233,7 +9359,7 @@ package Sinfo is
(N : Node_Id) return Boolean; -- Flag13
function Do_Discriminant_Check
- (N : Node_Id) return Boolean; -- Flag1
+ (N : Node_Id) return Boolean; -- Flag3
function Do_Division_Check
(N : Node_Id) return Boolean; -- Flag13
@@ -9455,7 +9581,7 @@ package Sinfo is
(N : Node_Id) return Boolean; -- Flag11
function Hidden_By_Use_Clause
- (N : Node_Id) return Elist_Id; -- Elist4
+ (N : Node_Id) return Elist_Id; -- Elist5
function High_Bound
(N : Node_Id) return Node_Id; -- Node2
@@ -9526,15 +9652,27 @@ package Sinfo is
function Is_Controlling_Actual
(N : Node_Id) return Boolean; -- Flag16
+ function Is_Declaration_Level_Node
+ (N : Node_Id) return Boolean; -- Flag5
+
function Is_Delayed_Aspect
(N : Node_Id) return Boolean; -- Flag14
function Is_Disabled
(N : Node_Id) return Boolean; -- Flag15
+ function Is_Dispatching_Call
+ (N : Node_Id) return Boolean; -- Flag3
+
function Is_Dynamic_Coextension
(N : Node_Id) return Boolean; -- Flag18
+ function Is_Effective_Use_Clause
+ (N : Node_Id) return Boolean; -- Flag1
+
+ function Is_Elaboration_Checks_OK_Node
+ (N : Node_Id) return Boolean; -- Flag1
+
function Is_Elsif
(N : Node_Id) return Boolean; -- Flag13
@@ -9568,6 +9706,12 @@ package Sinfo is
function Is_Inherited_Pragma
(N : Node_Id) return Boolean; -- Flag4
+ function Is_Initialization_Block
+ (N : Node_Id) return Boolean; -- Flag1
+
+ function Is_Known_Guaranteed_ABE
+ (N : Node_Id) return Boolean; -- Flag18
+
function Is_Machine_Number
(N : Node_Id) return Boolean; -- Flag11
@@ -9589,6 +9733,15 @@ package Sinfo is
function Is_Qualified_Universal_Literal
(N : Node_Id) return Boolean; -- Flag4
+ function Is_Recorded_Scenario
+ (N : Node_Id) return Boolean; -- Flag6
+
+ function Is_Source_Call
+ (N : Node_Id) return Boolean; -- Flag4
+
+ function Is_SPARK_Mode_On_Node
+ (N : Node_Id) return Boolean; -- Flag2
+
function Is_Static_Coextension
(N : Node_Id) return Boolean; -- Flag14
@@ -9706,9 +9859,6 @@ package Sinfo is
function No_Ctrl_Actions
(N : Node_Id) return Boolean; -- Flag7
- function No_Elaboration_Check
- (N : Node_Id) return Boolean; -- Flag14
-
function No_Entities_Ref_In_Spec
(N : Node_Id) return Boolean; -- Flag8
@@ -9719,7 +9869,7 @@ package Sinfo is
(N : Node_Id) return Boolean; -- Flag17
function No_Side_Effect_Removal
- (N : Node_Id) return Boolean; -- Flag1
+ (N : Node_Id) return Boolean; -- Flag17
function No_Truncation
(N : Node_Id) return Boolean; -- Flag17
@@ -9802,6 +9952,9 @@ package Sinfo is
function Prev_Ids
(N : Node_Id) return Boolean; -- Flag6
+ function Prev_Use_Clause
+ (N : Node_Id) return Node_Id; -- Node1
+
function Print_In_Hex
(N : Node_Id) return Boolean; -- Flag13
@@ -9937,6 +10090,9 @@ package Sinfo is
function Tagged_Present
(N : Node_Id) return Boolean; -- Flag15
+ function Target
+ (N : Node_Id) return Entity_Id; -- Node1
+
function Target_Type
(N : Node_Id) return Entity_Id; -- Node2
@@ -9995,7 +10151,10 @@ package Sinfo is
(N : Node_Id) return Node_Id; -- Node3
function Used_Operations
- (N : Node_Id) return Elist_Id; -- Elist5
+ (N : Node_Id) return Elist_Id; -- Elist2
+
+ function Was_Attribute_Reference
+ (N : Node_Id) return Boolean; -- Flag2
function Was_Expression_Function
(N : Node_Id) return Boolean; -- Flag18
@@ -10018,9 +10177,6 @@ package Sinfo is
-- tree pointers (List1-4), the parent pointer of the Val node is set to
-- point back to node N. This automates the setting of the parent pointer.
- procedure Set_ABE_Is_Certain
- (N : Node_Id; Val : Boolean := True); -- Flag18
-
procedure Set_Abort_Present
(N : Node_Id; Val : Boolean := True); -- Flag15
@@ -10066,6 +10222,9 @@ package Sinfo is
procedure Set_Aliased_Present
(N : Node_Id; Val : Boolean := True); -- Flag4
+ procedure Set_Alloc_For_BIP_Return
+ (N : Node_Id; Val : Boolean := True); -- Flag1
+
procedure Set_All_Others
(N : Node_Id; Val : Boolean := True); -- Flag11
@@ -10292,7 +10451,7 @@ package Sinfo is
(N : Node_Id; Val : Boolean := True); -- Flag13
procedure Set_Do_Discriminant_Check
- (N : Node_Id; Val : Boolean := True); -- Flag1
+ (N : Node_Id; Val : Boolean := True); -- Flag3
procedure Set_Do_Division_Check
(N : Node_Id; Val : Boolean := True); -- Flag13
@@ -10511,7 +10670,7 @@ package Sinfo is
(N : Node_Id; Val : Boolean := True); -- Flag11
procedure Set_Hidden_By_Use_Clause
- (N : Node_Id; Val : Elist_Id); -- Elist4
+ (N : Node_Id; Val : Elist_Id); -- Elist5
procedure Set_High_Bound
(N : Node_Id; Val : Node_Id); -- Node2
@@ -10582,15 +10741,27 @@ package Sinfo is
procedure Set_Is_Controlling_Actual
(N : Node_Id; Val : Boolean := True); -- Flag16
+ procedure Set_Is_Declaration_Level_Node
+ (N : Node_Id; Val : Boolean := True); -- Flag5
+
procedure Set_Is_Delayed_Aspect
(N : Node_Id; Val : Boolean := True); -- Flag14
procedure Set_Is_Disabled
(N : Node_Id; Val : Boolean := True); -- Flag15
+ procedure Set_Is_Dispatching_Call
+ (N : Node_Id; Val : Boolean := True); -- Flag3
+
procedure Set_Is_Dynamic_Coextension
(N : Node_Id; Val : Boolean := True); -- Flag18
+ procedure Set_Is_Effective_Use_Clause
+ (N : Node_Id; Val : Boolean := True); -- Flag1
+
+ procedure Set_Is_Elaboration_Checks_OK_Node
+ (N : Node_Id; Val : Boolean := True); -- Flag1
+
procedure Set_Is_Elsif
(N : Node_Id; Val : Boolean := True); -- Flag13
@@ -10624,6 +10795,12 @@ package Sinfo is
procedure Set_Is_Inherited_Pragma
(N : Node_Id; Val : Boolean := True); -- Flag4
+ procedure Set_Is_Initialization_Block
+ (N : Node_Id; Val : Boolean := True); -- Flag1
+
+ procedure Set_Is_Known_Guaranteed_ABE
+ (N : Node_Id; Val : Boolean := True); -- Flag18
+
procedure Set_Is_Machine_Number
(N : Node_Id; Val : Boolean := True); -- Flag11
@@ -10645,6 +10822,15 @@ package Sinfo is
procedure Set_Is_Qualified_Universal_Literal
(N : Node_Id; Val : Boolean := True); -- Flag4
+ procedure Set_Is_Recorded_Scenario
+ (N : Node_Id; Val : Boolean := True); -- Flag6
+
+ procedure Set_Is_Source_Call
+ (N : Node_Id; Val : Boolean := True); -- Flag4
+
+ procedure Set_Is_SPARK_Mode_On_Node
+ (N : Node_Id; Val : Boolean := True); -- Flag2
+
procedure Set_Is_Static_Coextension
(N : Node_Id; Val : Boolean := True); -- Flag14
@@ -10762,9 +10948,6 @@ package Sinfo is
procedure Set_No_Ctrl_Actions
(N : Node_Id; Val : Boolean := True); -- Flag7
- procedure Set_No_Elaboration_Check
- (N : Node_Id; Val : Boolean := True); -- Flag14
-
procedure Set_No_Entities_Ref_In_Spec
(N : Node_Id; Val : Boolean := True); -- Flag8
@@ -10775,7 +10958,7 @@ package Sinfo is
(N : Node_Id; Val : Boolean := True); -- Flag17
procedure Set_No_Side_Effect_Removal
- (N : Node_Id; Val : Boolean := True); -- Flag1
+ (N : Node_Id; Val : Boolean := True); -- Flag17
procedure Set_No_Truncation
(N : Node_Id; Val : Boolean := True); -- Flag17
@@ -10858,6 +11041,9 @@ package Sinfo is
procedure Set_Prev_Ids
(N : Node_Id; Val : Boolean := True); -- Flag6
+ procedure Set_Prev_Use_Clause
+ (N : Node_Id; Val : Node_Id); -- Node1
+
procedure Set_Print_In_Hex
(N : Node_Id; Val : Boolean := True); -- Flag13
@@ -10993,6 +11179,9 @@ package Sinfo is
procedure Set_Tagged_Present
(N : Node_Id; Val : Boolean := True); -- Flag15
+ procedure Set_Target
+ (N : Node_Id; Val : Entity_Id); -- Node1
+
procedure Set_Target_Type
(N : Node_Id; Val : Entity_Id); -- Node2
@@ -11051,7 +11240,10 @@ package Sinfo is
(N : Node_Id; Val : Node_Id); -- Node3
procedure Set_Used_Operations
- (N : Node_Id; Val : Elist_Id); -- Elist5
+ (N : Node_Id; Val : Elist_Id); -- Elist2
+
+ procedure Set_Was_Attribute_Reference
+ (N : Node_Id; Val : Boolean := True); -- Flag2
procedure Set_Was_Expression_Function
(N : Node_Id; Val : Boolean := True); -- Flag18
@@ -12053,18 +12245,18 @@ package Sinfo is
5 => True), -- Subtype_Indication (Node5)
N_Use_Package_Clause =>
- (1 => False, -- unused
- 2 => True, -- Names (List2)
+ (1 => False, -- Prev_Use_Clause (Node1-Sem)
+ 2 => True, -- Name (Node2)
3 => False, -- Next_Use_Clause (Node3-Sem)
- 4 => False, -- Hidden_By_Use_Clause (Elist4-Sem)
- 5 => False), -- unused
+ 4 => False, -- Associated_Node (Node4-Sem)
+ 5 => False), -- Hidden_By_Use_Clause (Elist5-Sem)
N_Use_Type_Clause =>
- (1 => False, -- unused
- 2 => True, -- Subtype_Marks (List2)
+ (1 => False, -- Prev_Use_Clause (Node1-Sem)
+ 2 => False, -- Used_Operations (Elist2-Sem)
3 => False, -- Next_Use_Clause (Node3-Sem)
- 4 => False, -- Hidden_By_Use_Clause (Elist4-Sem)
- 5 => False), -- unused
+ 4 => True, -- Subtype_Mark (Node4)
+ 5 => False), -- Hidden_By_Use_Clause (Elist5-Sem)
N_Object_Renaming_Declaration =>
(1 => True, -- Defining_Identifier (Node1)
@@ -12824,6 +13016,13 @@ package Sinfo is
4 => False, -- SCIL_Entity (Node4-Sem)
5 => False), -- SCIL_Tag_Value (Node5-Sem)
+ N_Call_Marker =>
+ (1 => False, -- Target (Node1-Sem)
+ 2 => False, -- unused
+ 3 => False, -- unused
+ 4 => False, -- unused
+ 5 => False), -- unused
+
-- Entries for Empty, Error and Unused. Even thought these have a Chars
-- field for debugging purposes, they are not really syntactic fields, so
-- we mark all fields as unused.
@@ -12860,7 +13059,6 @@ package Sinfo is
-- Inline Pragmas --
--------------------
- pragma Inline (ABE_Is_Certain);
pragma Inline (Abort_Present);
pragma Inline (Abortable_Part);
pragma Inline (Abstract_Present);
@@ -12876,6 +13074,7 @@ package Sinfo is
pragma Inline (Address_Warning_Posted);
pragma Inline (Aggregate_Bounds);
pragma Inline (Aliased_Present);
+ pragma Inline (Alloc_For_BIP_Return);
pragma Inline (All_Others);
pragma Inline (All_Present);
pragma Inline (Alternatives);
@@ -12958,10 +13157,10 @@ package Sinfo is
pragma Inline (Do_Range_Check);
pragma Inline (Do_Storage_Check);
pragma Inline (Do_Tag_Check);
- pragma Inline (Elaborate_Present);
pragma Inline (Elaborate_All_Desirable);
pragma Inline (Elaborate_All_Present);
pragma Inline (Elaborate_Desirable);
+ pragma Inline (Elaborate_Present);
pragma Inline (Else_Actions);
pragma Inline (Else_Statements);
pragma Inline (Elsif_Parts);
@@ -13050,9 +13249,13 @@ package Sinfo is
pragma Inline (Is_Component_Left_Opnd);
pragma Inline (Is_Component_Right_Opnd);
pragma Inline (Is_Controlling_Actual);
+ pragma Inline (Is_Declaration_Level_Node);
pragma Inline (Is_Delayed_Aspect);
pragma Inline (Is_Disabled);
+ pragma Inline (Is_Dispatching_Call);
pragma Inline (Is_Dynamic_Coextension);
+ pragma Inline (Is_Effective_Use_Clause);
+ pragma Inline (Is_Elaboration_Checks_OK_Node);
pragma Inline (Is_Elsif);
pragma Inline (Is_Entry_Barrier_Function);
pragma Inline (Is_Expanded_Build_In_Place_Call);
@@ -13064,6 +13267,8 @@ package Sinfo is
pragma Inline (Is_Ignored_Ghost_Pragma);
pragma Inline (Is_In_Discriminant_Check);
pragma Inline (Is_Inherited_Pragma);
+ pragma Inline (Is_Initialization_Block);
+ pragma Inline (Is_Known_Guaranteed_ABE);
pragma Inline (Is_Machine_Number);
pragma Inline (Is_Null_Loop);
pragma Inline (Is_Overloaded);
@@ -13071,6 +13276,9 @@ package Sinfo is
pragma Inline (Is_Prefixed_Call);
pragma Inline (Is_Protected_Subprogram_Body);
pragma Inline (Is_Qualified_Universal_Literal);
+ pragma Inline (Is_Recorded_Scenario);
+ pragma Inline (Is_Source_Call);
+ pragma Inline (Is_SPARK_Mode_On_Node);
pragma Inline (Is_Static_Coextension);
pragma Inline (Is_Static_Expression);
pragma Inline (Is_Subprogram_Descriptor);
@@ -13109,7 +13317,6 @@ package Sinfo is
pragma Inline (Next_Rep_Item);
pragma Inline (Next_Use_Clause);
pragma Inline (No_Ctrl_Actions);
- pragma Inline (No_Elaboration_Check);
pragma Inline (No_Entities_Ref_In_Spec);
pragma Inline (No_Initialization);
pragma Inline (No_Minimize_Eliminate);
@@ -13141,6 +13348,7 @@ package Sinfo is
pragma Inline (Premature_Use);
pragma Inline (Present_Expr);
pragma Inline (Prev_Ids);
+ pragma Inline (Prev_Use_Clause);
pragma Inline (Print_In_Hex);
pragma Inline (Private_Declarations);
pragma Inline (Private_Present);
@@ -13186,6 +13394,7 @@ package Sinfo is
pragma Inline (Suppress_Loop_Warnings);
pragma Inline (Synchronized_Present);
pragma Inline (Tagged_Present);
+ pragma Inline (Target);
pragma Inline (Target_Type);
pragma Inline (Task_Definition);
pragma Inline (Task_Present);
@@ -13206,11 +13415,11 @@ package Sinfo is
pragma Inline (Variants);
pragma Inline (Visible_Declarations);
pragma Inline (Used_Operations);
+ pragma Inline (Was_Attribute_Reference);
pragma Inline (Was_Expression_Function);
pragma Inline (Was_Originally_Stub);
pragma Inline (Withed_Body);
- pragma Inline (Set_ABE_Is_Certain);
pragma Inline (Set_Abort_Present);
pragma Inline (Set_Abortable_Part);
pragma Inline (Set_Abstract_Present);
@@ -13226,6 +13435,7 @@ package Sinfo is
pragma Inline (Set_Address_Warning_Posted);
pragma Inline (Set_Aggregate_Bounds);
pragma Inline (Set_Aliased_Present);
+ pragma Inline (Set_Alloc_For_BIP_Return);
pragma Inline (Set_All_Others);
pragma Inline (Set_All_Present);
pragma Inline (Set_Alternatives);
@@ -13397,9 +13607,13 @@ package Sinfo is
pragma Inline (Set_Is_Component_Left_Opnd);
pragma Inline (Set_Is_Component_Right_Opnd);
pragma Inline (Set_Is_Controlling_Actual);
+ pragma Inline (Set_Is_Declaration_Level_Node);
pragma Inline (Set_Is_Delayed_Aspect);
pragma Inline (Set_Is_Disabled);
+ pragma Inline (Set_Is_Dispatching_Call);
pragma Inline (Set_Is_Dynamic_Coextension);
+ pragma Inline (Set_Is_Effective_Use_Clause);
+ pragma Inline (Set_Is_Elaboration_Checks_OK_Node);
pragma Inline (Set_Is_Elsif);
pragma Inline (Set_Is_Entry_Barrier_Function);
pragma Inline (Set_Is_Expanded_Build_In_Place_Call);
@@ -13411,6 +13625,8 @@ package Sinfo is
pragma Inline (Set_Is_Ignored_Ghost_Pragma);
pragma Inline (Set_Is_In_Discriminant_Check);
pragma Inline (Set_Is_Inherited_Pragma);
+ pragma Inline (Set_Is_Initialization_Block);
+ pragma Inline (Set_Is_Known_Guaranteed_ABE);
pragma Inline (Set_Is_Machine_Number);
pragma Inline (Set_Is_Null_Loop);
pragma Inline (Set_Is_Overloaded);
@@ -13418,6 +13634,9 @@ package Sinfo is
pragma Inline (Set_Is_Prefixed_Call);
pragma Inline (Set_Is_Protected_Subprogram_Body);
pragma Inline (Set_Is_Qualified_Universal_Literal);
+ pragma Inline (Set_Is_Recorded_Scenario);
+ pragma Inline (Set_Is_Source_Call);
+ pragma Inline (Set_Is_SPARK_Mode_On_Node);
pragma Inline (Set_Is_Static_Coextension);
pragma Inline (Set_Is_Static_Expression);
pragma Inline (Set_Is_Subprogram_Descriptor);
@@ -13457,7 +13676,6 @@ package Sinfo is
pragma Inline (Set_Next_Rep_Item);
pragma Inline (Set_Next_Use_Clause);
pragma Inline (Set_No_Ctrl_Actions);
- pragma Inline (Set_No_Elaboration_Check);
pragma Inline (Set_No_Entities_Ref_In_Spec);
pragma Inline (Set_No_Initialization);
pragma Inline (Set_No_Minimize_Eliminate);
@@ -13489,6 +13707,7 @@ package Sinfo is
pragma Inline (Set_Premature_Use);
pragma Inline (Set_Present_Expr);
pragma Inline (Set_Prev_Ids);
+ pragma Inline (Set_Prev_Use_Clause);
pragma Inline (Set_Print_In_Hex);
pragma Inline (Set_Private_Declarations);
pragma Inline (Set_Private_Present);
@@ -13533,6 +13752,7 @@ package Sinfo is
pragma Inline (Set_Synchronized_Present);
pragma Inline (Set_TSS_Elist);
pragma Inline (Set_Tagged_Present);
+ pragma Inline (Set_Target);
pragma Inline (Set_Target_Type);
pragma Inline (Set_Task_Definition);
pragma Inline (Set_Task_Present);
@@ -13552,6 +13772,7 @@ package Sinfo is
pragma Inline (Set_Variant_Part);
pragma Inline (Set_Variants);
pragma Inline (Set_Visible_Declarations);
+ pragma Inline (Set_Was_Attribute_Reference);
pragma Inline (Set_Was_Expression_Function);
pragma Inline (Set_Was_Originally_Stub);
pragma Inline (Set_Withed_Body);
diff --git a/gcc/ada/sinput-c.adb b/gcc/ada/sinput-c.adb
index fe9285c..645f0da 100644
--- a/gcc/ada/sinput-c.adb
+++ b/gcc/ada/sinput-c.adb
@@ -28,8 +28,6 @@ with Opt; use Opt;
with Output; use Output;
with System; use System;
-with Ada.Unchecked_Conversion;
-
pragma Warnings (Off);
-- This package is used also by gnatcoll
with System.OS_Lib; use System.OS_Lib;
diff --git a/gcc/ada/sinput-d.adb b/gcc/ada/sinput-d.adb
index c9c128b..f8c4cb0 100644
--- a/gcc/ada/sinput-d.adb
+++ b/gcc/ada/sinput-d.adb
@@ -23,10 +23,11 @@
-- --
------------------------------------------------------------------------------
-with Debug; use Debug;
-with Osint; use Osint;
-with Osint.C; use Osint.C;
-with Output; use Output;
+with Debug; use Debug;
+with Osint; use Osint;
+with Osint.C; use Osint.C;
+with Output; use Output;
+with System.OS_Lib; use System.OS_Lib;
package body Sinput.D is
@@ -38,6 +39,7 @@ package body Sinput.D is
------------------------
procedure Close_Debug_Source is
+ FD : File_Descriptor;
SFR : Source_File_Record renames Source_File.Table (Dfile);
Src : Source_Buffer_Ptr;
begin
@@ -48,7 +50,7 @@ package body Sinput.D is
-- subsequent access.
Read_Source_File
- (SFR.Full_Debug_Name, SFR.Source_First, SFR.Source_Last, Src);
+ (SFR.Full_Debug_Name, SFR.Source_First, SFR.Source_Last, Src, FD);
SFR.Source_Text := Src;
pragma Assert (SFR.Source_Text'First = SFR.Source_First);
pragma Assert (SFR.Source_Text'Last = SFR.Source_Last);
diff --git a/gcc/ada/sinput-l.adb b/gcc/ada/sinput-l.adb
index 360e711..7f4b786 100644
--- a/gcc/ada/sinput-l.adb
+++ b/gcc/ada/sinput-l.adb
@@ -354,10 +354,11 @@ package body Sinput.L is
(N : File_Name_Type;
T : Osint.File_Type) return Source_File_Index
is
+ FD : File_Descriptor;
+ Hi : Source_Ptr;
+ Lo : Source_Ptr;
Src : Source_Buffer_Ptr;
X : Source_File_Index;
- Lo : Source_Ptr;
- Hi : Source_Ptr;
Preprocessing_Needed : Boolean := False;
@@ -411,12 +412,16 @@ package body Sinput.L is
Source_Align) * Source_Align;
end if;
- Osint.Read_Source_File (N, Lo, Hi, Src, T);
+ Osint.Read_Source_File (N, Lo, Hi, Src, FD, T);
if Null_Source_Buffer_Ptr (Src) then
Source_File.Decrement_Last;
- return No_Source_File;
+ if FD = Null_FD then
+ return No_Source_File;
+ else
+ return No_Access_To_Source_File;
+ end if;
else
if Debug_Flag_L then
Write_Eol;
diff --git a/gcc/ada/sinput.ads b/gcc/ada/sinput.ads
index bde59b1..ecbe83c 100644
--- a/gcc/ada/sinput.ads
+++ b/gcc/ada/sinput.ads
@@ -755,6 +755,8 @@ private
pragma Inline (Num_Source_Files);
pragma Inline (Num_Source_Lines);
+ pragma Inline (Line_Start);
+
No_Instance_Id : constant Instance_Id := 0;
-------------------------
diff --git a/gcc/ada/snames.ads-tmpl b/gcc/ada/snames.ads-tmpl
index 717225d..5fcf365 100644
--- a/gcc/ada/snames.ads-tmpl
+++ b/gcc/ada/snames.ads-tmpl
@@ -328,7 +328,7 @@ package Snames is
-- Operator Symbol entries. The actual names have an upper case O at the
-- start in place of the Op_ prefix (e.g. the actual name that corresponds
- -- to Name_Op_Abs is "Oabs".
+ -- to Name_Op_Abs is "Oabs").
First_Operator_Name : constant Name_Id := N + $;
Name_Op_Abs : constant Name_Id := N + $; -- "abs"
diff --git a/gcc/ada/sprint.adb b/gcc/ada/sprint.adb
index d97a1f7..ac2dcd8 100644
--- a/gcc/ada/sprint.adb
+++ b/gcc/ada/sprint.adb
@@ -1225,6 +1225,15 @@ package body Sprint is
Write_Char (';');
+ when N_Call_Marker =>
+ null;
+
+ -- Enable the following code for debugging purposes only
+
+ -- Write_Indent_Str ("#");
+ -- Write_Id (Target (Node));
+ -- Write_Char ('#');
+
when N_Case_Expression =>
declare
Has_Parens : constant Boolean := Paren_Count (Node) > 0;
@@ -3435,12 +3444,12 @@ package body Sprint is
when N_Use_Package_Clause =>
Write_Indent_Str_Sloc ("use ");
- Sprint_Comma_List (Names (Node));
+ Sprint_Node_Sloc (Name (Node));
Write_Char (';');
when N_Use_Type_Clause =>
Write_Indent_Str_Sloc ("use type ");
- Sprint_Comma_List (Subtype_Marks (Node));
+ Sprint_Node_Sloc (Subtype_Mark (Node));
Write_Char (';');
when N_Validate_Unchecked_Conversion =>
@@ -3752,7 +3761,7 @@ package body Sprint is
-- Ignore if there is no current source file, or we're not in dump
-- source text mode, or if in freeze actions.
- if Current_Source_File /= No_Source_File
+ if Current_Source_File > No_Source_File
and then Dump_Source_Text
and then Freeze_Indent = 0
then
diff --git a/gcc/ada/switch-b.adb b/gcc/ada/switch-b.adb
index 52a72e4..61fe440 100644
--- a/gcc/ada/switch-b.adb
+++ b/gcc/ada/switch-b.adb
@@ -391,6 +391,18 @@ package body Switch.B is
Ptr := Ptr + 1;
Quiet_Output := True;
+ -- Processing for Q switch
+
+ when 'Q' =>
+ if Ptr = Max then
+ Bad_Switch (Switch_Chars);
+ end if;
+
+ Ptr := Ptr + 1;
+ Scan_Pos
+ (Switch_Chars, Max, Ptr,
+ Quantity_Of_Default_Size_Sec_Stacks, C);
+
-- Processing for r switch
when 'r' =>
diff --git a/gcc/ada/switch-c.adb b/gcc/ada/switch-c.adb
index cd6b200..5ad10e3 100644
--- a/gcc/ada/switch-c.adb
+++ b/gcc/ada/switch-c.adb
@@ -548,7 +548,6 @@ package body Switch.C is
Warn_On_Bad_Fixed_Value := True; -- -gnatwb
Warn_On_Biased_Representation := True; -- -gnatw.b
Warn_On_Export_Import := True; -- -gnatwx
- Warn_On_Modified_Unread := True; -- -gnatwm
Warn_On_No_Value_Assigned := True; -- -gnatwv
Warn_On_Object_Renames_Function := True; -- -gnatw.r
Warn_On_Overlap := True; -- -gnatw.i
diff --git a/gcc/ada/sysdep.c b/gcc/ada/sysdep.c
index 455a78a..698c8ca 100644
--- a/gcc/ada/sysdep.c
+++ b/gcc/ada/sysdep.c
@@ -126,7 +126,7 @@ extern struct tm *localtime_r(const time_t *, struct tm *);
*/
-#if defined (WINNT) || defined (__CYGWIN__) || defined(__DJGPP__)
+#if defined (WINNT) || defined (__CYGWIN__) || defined (__DJGPP__)
const char __gnat_text_translation_required = 1;
@@ -137,7 +137,7 @@ const char __gnat_text_translation_required = 1;
#define WIN_SETMODE _setmode
#endif
-#if defined(__DJGPP__)
+#if defined (__DJGPP__)
#include <io.h>
#define _setmode setmode
#endif /* __DJGPP__ */
@@ -154,7 +154,7 @@ __gnat_set_text_mode (int handle)
WIN_SETMODE (handle, O_TEXT);
}
-#ifdef __DJGPP__
+#if defined (__CYGWIN__) || defined (__DJGPP__)
void
__gnat_set_mode (int handle, int mode)
{
@@ -826,7 +826,7 @@ __gnat_localtime_tzoff (const time_t *timer ATTRIBUTE_UNUSED,
#elif defined (__APPLE__) || defined (__FreeBSD__) || defined (__linux__) \
|| defined (__GLIBC__) || defined (__DragonFly__) || defined (__OpenBSD__) \
- || defined(__DJGPP__)
+ || defined (__DJGPP__)
{
localtime_r (timer, &tp);
*off = tp.tm_gmtoff;
diff --git a/gcc/ada/targparm.adb b/gcc/ada/targparm.adb
index 2ee9245..63b124a 100644
--- a/gcc/ada/targparm.adb
+++ b/gcc/ada/targparm.adb
@@ -23,10 +23,11 @@
-- --
------------------------------------------------------------------------------
-with Csets; use Csets;
-with Opt; use Opt;
-with Osint; use Osint;
-with Output; use Output;
+with Csets; use Csets;
+with Opt;
+with Osint; use Osint;
+with Output; use Output;
+with System.OS_Lib; use System.OS_Lib;
package body Targparm is
use ASCII;
@@ -156,8 +157,9 @@ package body Targparm is
Set_NUA : Set_NUA_Type := null;
Set_NUP : Set_NUP_Type := null)
is
- Text : Source_Buffer_Ptr;
+ FD : File_Descriptor;
Hi : Source_Ptr;
+ Text : Source_Buffer_Ptr;
begin
if Parameters_Obtained then
@@ -167,11 +169,17 @@ package body Targparm is
Name_Buffer (1 .. 10) := "system.ads";
Name_Len := 10;
- Read_Source_File (Name_Find, Lo => 0, Hi => Hi, Src => Text);
+ Read_Source_File (Name_Find, 0, Hi, Text, FD);
if Null_Source_Buffer_Ptr (Text) then
Write_Line ("fatal error, run-time library not installed correctly");
- Write_Line ("cannot locate file system.ads");
+
+ if FD = Null_FD then
+ Write_Line ("cannot locate file system.ads");
+ else
+ Write_Line ("no read access for file system.ads");
+ end if;
+
raise Unrecoverable_Error;
end if;
diff --git a/gcc/ada/types.ads b/gcc/ada/types.ads
index e0809f2..0d8eb06 100644
--- a/gcc/ada/types.ads
+++ b/gcc/ada/types.ads
@@ -572,12 +572,15 @@ package Types is
No_Unit : constant Unit_Number_Type := -1;
-- Special value used to signal no unit
- type Source_File_Index is new Int range 0 .. Int'Last;
+ type Source_File_Index is new Int range -1 .. Int'Last;
-- Type used to index the source file table (see package Sinput)
No_Source_File : constant Source_File_Index := 0;
-- Value used to indicate no source file present
+ No_Access_To_Source_File : constant Source_File_Index := -1;
+ -- Value used to indicate a source file is present but unreadable
+
-----------------------------------
-- Representation of Time Stamps --
-----------------------------------
diff --git a/gcc/ada/widechar.ads b/gcc/ada/widechar.ads
index a6e8293..3d2f917 100644
--- a/gcc/ada/widechar.ads
+++ b/gcc/ada/widechar.ads
@@ -6,7 +6,7 @@
-- --
-- S p e c --
-- --
--- Copyright (C) 1992-2014, Free Software Foundation, Inc. --
+-- Copyright (C) 1992-2017, 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- --
@@ -95,4 +95,7 @@ package Widechar is
P : Source_Ptr) return Boolean;
-- Determines if S (P) is the start of a wide character sequence
+private
+ pragma Inline (Is_Start_Of_Wide_Char);
+
end Widechar;
diff --git a/gcc/ada/xr_tabls.adb b/gcc/ada/xr_tabls.adb
index 8a6411c..8ae9e6d 100644
--- a/gcc/ada/xr_tabls.adb
+++ b/gcc/ada/xr_tabls.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1998-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1998-2017, 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- --
@@ -36,7 +36,7 @@ with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
with GNAT.OS_Lib; use GNAT.OS_Lib;
with GNAT.Directory_Operations; use GNAT.Directory_Operations;
-with GNAT.HTable; use GNAT.HTable;
+with GNAT.HTable;
with GNAT.Heap_Sort_G;
package body Xr_Tabls is
diff --git a/gcc/ada/xref_lib.adb b/gcc/ada/xref_lib.adb
index 9250841..b860978 100644
--- a/gcc/ada/xref_lib.adb
+++ b/gcc/ada/xref_lib.adb
@@ -6,7 +6,7 @@
-- --
-- B o d y --
-- --
--- Copyright (C) 1998-2016, Free Software Foundation, Inc. --
+-- Copyright (C) 1998-2017, 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- --
@@ -30,7 +30,7 @@ with Types; use Types;
with Unchecked_Deallocation;
with Ada.Strings.Fixed; use Ada.Strings.Fixed;
-with Ada.Text_IO; use Ada.Text_IO;
+with Ada.Text_IO;
with GNAT.Command_Line; use GNAT.Command_Line;
with GNAT.IO_Aux; use GNAT.IO_Aux;
diff --git a/gcc/alias.c b/gcc/alias.c
index e486572..cb57c6a 100644
--- a/gcc/alias.c
+++ b/gcc/alias.c
@@ -2047,13 +2047,15 @@ compare_base_decls (tree base1, tree base2)
return 1;
/* If we have two register decls with register specification we
- cannot decide unless their assembler name is the same. */
+ cannot decide unless their assembler names are the same. */
if (DECL_REGISTER (base1)
&& DECL_REGISTER (base2)
+ && HAS_DECL_ASSEMBLER_NAME_P (base1)
+ && HAS_DECL_ASSEMBLER_NAME_P (base2)
&& DECL_ASSEMBLER_NAME_SET_P (base1)
&& DECL_ASSEMBLER_NAME_SET_P (base2))
{
- if (DECL_ASSEMBLER_NAME (base1) == DECL_ASSEMBLER_NAME (base2))
+ if (DECL_ASSEMBLER_NAME_RAW (base1) == DECL_ASSEMBLER_NAME_RAW (base2))
return 1;
return -1;
}
diff --git a/gcc/asan.c b/gcc/asan.c
index 2aa0a79..302ac4f 100644
--- a/gcc/asan.c
+++ b/gcc/asan.c
@@ -628,10 +628,9 @@ handle_builtin_alloca (gcall *call, gimple_stmt_iterator *iter)
tree ptr_type = gimple_call_lhs (call) ? TREE_TYPE (gimple_call_lhs (call))
: ptr_type_node;
tree partial_size = NULL_TREE;
- bool alloca_with_align
- = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA_WITH_ALIGN;
unsigned int align
- = alloca_with_align ? tree_to_uhwi (gimple_call_arg (call, 1)) : 0;
+ = DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
+ ? 0 : tree_to_uhwi (gimple_call_arg (call, 1));
/* If ALIGN > ASAN_RED_ZONE_SIZE, we embed left redzone into first ALIGN
bytes of allocated space. Otherwise, align alloca to ASAN_RED_ZONE_SIZE
@@ -793,8 +792,7 @@ get_mem_refs_of_builtin_call (gcall *call,
handle_builtin_stack_restore (call, iter);
break;
- case BUILT_IN_ALLOCA_WITH_ALIGN:
- case BUILT_IN_ALLOCA:
+ CASE_BUILT_IN_ALLOCA:
handle_builtin_alloca (call, iter);
break;
/* And now the __atomic* and __sync builtins.
@@ -1809,7 +1807,6 @@ create_cond_insert_point (gimple_stmt_iterator *iter,
/* Set up the fallthrough basic block. */
e = find_edge (cond_bb, fallthru_bb);
e->flags = EDGE_FALSE_VALUE;
- e->count = cond_bb->count;
e->probability = fallthrough_probability;
/* Update dominance info for the newly created then_bb; note that
@@ -3400,6 +3397,10 @@ asan_expand_poison_ifn (gimple_stmt_iterator *iter,
{
edge e = gimple_phi_arg_edge (phi, i);
+ /* Do not insert on an edge we can't split. */
+ if (e->flags & EDGE_ABNORMAL)
+ continue;
+
if (call_to_insert == NULL)
call_to_insert = gimple_copy (call);
diff --git a/gcc/attribs.c b/gcc/attribs.c
index 4ef35b8..ed76a8d 100644
--- a/gcc/attribs.c
+++ b/gcc/attribs.c
@@ -1182,6 +1182,9 @@ comp_type_attributes (const_tree type1, const_tree type2)
}
if (lookup_attribute ("transaction_safe", CONST_CAST_TREE (a)))
return 0;
+ if ((lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type1)) != NULL)
+ ^ (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (type2)) != NULL))
+ return 0;
/* As some type combinations - like default calling-convention - might
be compatible, we have to call the target hook to get the final result. */
return targetm.comp_type_attributes (type1, type2);
diff --git a/gcc/auto-profile.c b/gcc/auto-profile.c
index 9226e20..378f480 100644
--- a/gcc/auto-profile.c
+++ b/gcc/auto-profile.c
@@ -1234,7 +1234,7 @@ afdo_propagate_edge (bool is_succ, bb_set *annotated_bb,
if (!is_edge_annotated (e, *annotated_edge))
num_unknown_edge++, unknown_edge = e;
else
- total_known_count += e->count;
+ total_known_count += e->count ();
if (num_unknown_edge == 0)
{
@@ -1251,7 +1251,8 @@ afdo_propagate_edge (bool is_succ, bb_set *annotated_bb,
}
else if (num_unknown_edge == 1 && is_bb_annotated (bb, *annotated_bb))
{
- unknown_edge->count = bb->count - total_known_count;
+ unknown_edge->probability
+ = total_known_count.probability_in (bb->count);
set_edge_annotated (unknown_edge, annotated_edge);
changed = true;
}
@@ -1349,15 +1350,13 @@ afdo_propagate_circuit (const bb_set &annotated_bb, edge_set *annotated_edge)
if (!e->probability.initialized_p ()
&& !is_edge_annotated (ep, *annotated_edge))
{
- ep->probability = profile_probability::never ();
- ep->count = profile_count::zero ().afdo ();
+ ep->probability = profile_probability::never ().afdo ();
set_edge_annotated (ep, annotated_edge);
}
}
if (total == 1 && !is_edge_annotated (only_one, *annotated_edge))
{
only_one->probability = e->probability;
- only_one->count = e->count;
set_edge_annotated (only_one, annotated_edge);
}
}
@@ -1433,23 +1432,16 @@ afdo_calculate_branch_prob (bb_set *annotated_bb, edge_set *annotated_edge)
if (!is_edge_annotated (e, *annotated_edge))
num_unknown_succ++;
else
- total_count += e->count;
+ total_count += e->count ();
}
if (num_unknown_succ == 0 && total_count > profile_count::zero ())
{
FOR_EACH_EDGE (e, ei, bb->succs)
- e->probability = e->count.probability_in (total_count);
+ e->probability = e->count ().probability_in (total_count);
}
}
FOR_ALL_BB_FN (bb, cfun)
- {
- edge e;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- e->count = bb->count.apply_probability (e->probability);
bb->aux = NULL;
- }
loop_optimizer_finalize ();
free_dominance_info (CDI_DOMINATORS);
@@ -1551,7 +1543,7 @@ afdo_annotate_cfg (const stmt_set &promoted_stmts)
counters are zero when not seen by autoFDO. */
bb->count = profile_count::zero ().afdo ();
FOR_EACH_EDGE (e, ei, bb->succs)
- e->count = profile_count::zero ().afdo ();
+ e->probability = profile_probability::uninitialized ();
if (afdo_set_bb_count (bb, promoted_stmts))
set_bb_annotated (bb, &annotated_bb);
diff --git a/gcc/basic-block.h b/gcc/basic-block.h
index c0c4778..1505cce 100644
--- a/gcc/basic-block.h
+++ b/gcc/basic-block.h
@@ -46,8 +46,9 @@ struct GTY((user)) edge_def {
int flags; /* see cfg-flags.def */
profile_probability probability;
- profile_count count; /* Expected number of executions calculated
- in profile.c */
+
+ /* Return count of edge E. */
+ inline profile_count count () const;
};
/* Masks for edge.flags. */
@@ -639,4 +640,10 @@ has_abnormal_call_or_eh_pred_edge_p (basic_block bb)
return false;
}
+/* Return count of edge E. */
+inline profile_count edge_def::count () const
+{
+ return src->count.apply_probability (probability);
+}
+
#endif /* GCC_BASIC_BLOCK_H */
diff --git a/gcc/bb-reorder.c b/gcc/bb-reorder.c
index 4dad298..dc2025f 100644
--- a/gcc/bb-reorder.c
+++ b/gcc/bb-reorder.c
@@ -374,11 +374,11 @@ rotate_loop (edge back_edge, struct trace *trace, int trace_n)
{
/* The current edge E is also preferred. */
int freq = EDGE_FREQUENCY (e);
- if (freq > best_freq || e->count > best_count)
+ if (freq > best_freq || e->count () > best_count)
{
best_freq = freq;
- if (e->count.initialized_p ())
- best_count = e->count;
+ if (e->count ().initialized_p ())
+ best_count = e->count ();
best_edge = e;
best_bb = bb;
}
@@ -392,17 +392,17 @@ rotate_loop (edge back_edge, struct trace *trace, int trace_n)
/* The current edge E is preferred. */
is_preferred = true;
best_freq = EDGE_FREQUENCY (e);
- best_count = e->count;
+ best_count = e->count ();
best_edge = e;
best_bb = bb;
}
else
{
int freq = EDGE_FREQUENCY (e);
- if (!best_edge || freq > best_freq || e->count > best_count)
+ if (!best_edge || freq > best_freq || e->count () > best_count)
{
best_freq = freq;
- best_count = e->count;
+ best_count = e->count ();
best_edge = e;
best_bb = bb;
}
@@ -571,7 +571,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
|| !prob.initialized_p ()
|| ((prob.to_reg_br_prob_base () < branch_th
|| EDGE_FREQUENCY (e) < exec_th
- || e->count < count_th) && (!for_size)))
+ || e->count () < count_th) && (!for_size)))
continue;
/* If partitioning hot/cold basic blocks, don't consider edges
@@ -656,7 +656,7 @@ find_traces_1_round (int branch_th, int exec_th, gcov_type count_th,
|| !prob.initialized_p ()
|| prob.to_reg_br_prob_base () < branch_th
|| freq < exec_th
- || e->count < count_th)
+ || e->count () < count_th)
{
/* When partitioning hot/cold basic blocks, make sure
the cold blocks (and only the cold blocks) all get
@@ -1285,7 +1285,7 @@ connect_traces (int n_traces, struct trace *traces)
&& !connected[bbd[di].start_of_trace]
&& BB_PARTITION (e2->dest) == current_partition
&& EDGE_FREQUENCY (e2) >= freq_threshold
- && e2->count >= count_threshold
+ && e2->count () >= count_threshold
&& (!best2
|| e2->probability > best2->probability
|| (e2->probability == best2->probability
@@ -1311,8 +1311,8 @@ connect_traces (int n_traces, struct trace *traces)
&& copy_bb_p (best->dest,
optimize_edge_for_speed_p (best)
&& EDGE_FREQUENCY (best) >= freq_threshold
- && (!best->count.initialized_p ()
- || best->count >= count_threshold)))
+ && (!best->count ().initialized_p ()
+ || best->count () >= count_threshold)))
{
basic_block new_bb;
@@ -1528,7 +1528,7 @@ sanitize_hot_paths (bool walk_up, unsigned int cold_bb_count,
/* Do not expect profile insanities when profile was not adjusted. */
if (e->probability == profile_probability::never ()
- || e->count == profile_count::zero ())
+ || e->count () == profile_count::zero ())
continue;
if (BB_PARTITION (reach_bb) != BB_COLD_PARTITION)
@@ -1539,8 +1539,8 @@ sanitize_hot_paths (bool walk_up, unsigned int cold_bb_count,
/* The following loop will look for the hottest edge via
the edge count, if it is non-zero, then fallback to the edge
frequency and finally the edge probability. */
- if (!highest_count.initialized_p () || e->count > highest_count)
- highest_count = e->count;
+ if (!highest_count.initialized_p () || e->count () > highest_count)
+ highest_count = e->count ();
int edge_freq = EDGE_FREQUENCY (e);
if (edge_freq > highest_freq)
highest_freq = edge_freq;
@@ -1563,14 +1563,14 @@ sanitize_hot_paths (bool walk_up, unsigned int cold_bb_count,
continue;
/* Do not expect profile insanities when profile was not adjusted. */
if (e->probability == profile_probability::never ()
- || e->count == profile_count::zero ())
+ || e->count () == profile_count::zero ())
continue;
/* Select the hottest edge using the edge count, if it is non-zero,
then fallback to the edge frequency and finally the edge
probability. */
if (highest_count > 0)
{
- if (e->count < highest_count)
+ if (e->count () < highest_count)
continue;
}
else if (highest_freq)
diff --git a/gcc/brig-builtins.def b/gcc/brig-builtins.def
index f525610..c2d8422 100644
--- a/gcc/brig-builtins.def
+++ b/gcc/brig-builtins.def
@@ -107,140 +107,140 @@ DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_GRIDGROUPS, BRIG_OPCODE_GRIDGROUPS,
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITEXTRACT_S32, BRIG_OPCODE_BITEXTRACT,
BRIG_TYPE_S32, "__hsail_bitextract_s32",
- BT_FN_INT_INT_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT_INT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITEXTRACT_U32, BRIG_OPCODE_BITEXTRACT,
BRIG_TYPE_U32, "__hsail_bitextract_u32",
- BT_FN_UINT_UINT_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_UINT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITEXTRACT_S64, BRIG_OPCODE_BITEXTRACT,
BRIG_TYPE_S64, "__hsail_bitextract_s64",
- BT_FN_LONG_LONG_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_LONG_LONG_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITEXTRACT_U64, BRIG_OPCODE_BITEXTRACT,
BRIG_TYPE_U64, "__hsail_bitextract_u64",
- BT_FN_ULONG_ULONG_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_ULONG_ULONG_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITINSERT_U32, BRIG_OPCODE_BITINSERT,
BRIG_TYPE_U32, "__hsail_bitinsert_u32",
- BT_FN_UINT_UINT_UINT_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_UINT_UINT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITINSERT_U64, BRIG_OPCODE_BITINSERT,
BRIG_TYPE_U64, "__hsail_bitinsert_u64",
BT_FN_ULONG_ULONG_ULONG_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITMASK_B32, BRIG_OPCODE_BITMASK,
BRIG_TYPE_B32, "__hsail_bitmask_u32", BT_FN_UINT_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITMASK_B64, BRIG_OPCODE_BITMASK,
BRIG_TYPE_B64, "__hsail_bitmask_u64", BT_FN_ULONG_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITREV_B32, BRIG_OPCODE_BITREV,
BRIG_TYPE_B32, "__hsail_bitrev_u32", BT_FN_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITREV_B64, BRIG_OPCODE_BITREV,
BRIG_TYPE_B64, "__hsail_bitrev_u64", BT_FN_ULONG_ULONG,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITSELECT_B32, BRIG_OPCODE_BITSELECT,
BRIG_TYPE_B32, "__hsail_bitselect_u32",
- BT_FN_UINT_UINT_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_UINT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITSELECT_U64, BRIG_OPCODE_BITSELECT,
BRIG_TYPE_B64, "__hsail_bitselect_u64",
- BT_FN_ULONG_ULONG_ULONG_ULONG, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_ULONG_ULONG_ULONG_ULONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_FIRSTBIT_U32, BRIG_OPCODE_FIRSTBIT,
BRIG_TYPE_U32, "__hsail_firstbit_u32", BT_FN_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_FIRSTBIT_S32, BRIG_OPCODE_FIRSTBIT,
BRIG_TYPE_S32, "__hsail_firstbit_s32", BT_FN_UINT_INT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_FIRSTBIT_U64, BRIG_OPCODE_FIRSTBIT,
BRIG_TYPE_U64, "__hsail_firstbit_u64", BT_FN_UINT_ULONG,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_FIRSTBIT_S64, BRIG_OPCODE_FIRSTBIT,
BRIG_TYPE_S64, "__hsail_firstbit_s64", BT_FN_UINT_LONG,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_LASTBIT_U32, BRIG_OPCODE_LASTBIT,
BRIG_TYPE_U32, "__hsail_lastbit_u32", BT_FN_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_LASTBIT_U64, BRIG_OPCODE_LASTBIT,
BRIG_TYPE_U64, "__hsail_lastbit_u64", BT_FN_UINT_ULONG,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BORROW_U32, BRIG_OPCODE_BORROW,
BRIG_TYPE_U32, "__hsail_borrow_u32", BT_FN_UINT_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BORROW_U64, BRIG_OPCODE_BORROW,
BRIG_TYPE_U64, "__hsail_borrow_u64", BT_FN_ULONG_ULONG_ULONG,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_CARRY_U32, BRIG_OPCODE_CARRY,
BRIG_TYPE_U32, "__hsail_carry_u32", BT_FN_UINT_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_CARRY_U64, BRIG_OPCODE_CARRY,
BRIG_TYPE_U64, "__hsail_carry_u64", BT_FN_ULONG_ULONG_ULONG,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_REM_S32, BRIG_OPCODE_REM,
BRIG_TYPE_S32, "__hsail_rem_s32", BT_FN_INT_INT_INT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_REM_S64, BRIG_OPCODE_REM,
BRIG_TYPE_S64, "__hsail_rem_s64", BT_FN_LONG_LONG_LONG,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_MIN_F32, BRIG_OPCODE_MIN,
BRIG_TYPE_F32, "__hsail_min_f32", BT_FN_FLOAT_FLOAT_FLOAT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_MAX_F32, BRIG_OPCODE_MAX,
BRIG_TYPE_F32, "__hsail_max_f32", BT_FN_FLOAT_FLOAT_FLOAT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_MIN_F64, BRIG_OPCODE_MIN,
BRIG_TYPE_F64, "__hsail_min_f64", BT_FN_DOUBLE_DOUBLE_DOUBLE,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_MAX_F64, BRIG_OPCODE_MAX,
BRIG_TYPE_F64, "__hsail_max_f64", BT_FN_DOUBLE_DOUBLE_DOUBLE,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_CLASS_F32, BRIG_OPCODE_CLASS,
BRIG_TYPE_F32, "__hsail_class_f32", BT_FN_UINT_FLOAT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_CLASS_F64, BRIG_OPCODE_CLASS,
BRIG_TYPE_F64, "__hsail_class_f64", BT_FN_UINT_DOUBLE_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_CLASS_F32_F16, BRIG_OPCODE_CLASS,
- BRIG_TYPE_F16, "__hsail_class_f32_f16", BT_FN_UINT_FLOAT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ BRIG_TYPE_F16, "__hsail_class_f32_f16",
+ BT_FN_UINT_FLOAT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_FRACT_F32, BRIG_OPCODE_FRACT,
BRIG_TYPE_F32, "__hsail_fract_f32", BT_FN_FLOAT_FLOAT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_FRACT_F64, BRIG_OPCODE_FRACT,
BRIG_TYPE_F64, "__hsail_fract_f64", BT_FN_DOUBLE_DOUBLE,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BARRIER, BRIG_OPCODE_BARRIER,
BRIG_TYPE_NONE, "__hsail_barrier", BT_FN_VOID_PTR,
- ATTR_NOTHROW_LIST)
+ ATTR_RT_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_INITFBAR, BRIG_OPCODE_INITFBAR,
BRIG_TYPE_NONE, "__hsail_initfbar", BT_FN_VOID_UINT_PTR,
@@ -252,11 +252,11 @@ DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_JOINFBAR, BRIG_OPCODE_JOINFBAR,
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_WAITFBAR, BRIG_OPCODE_WAITFBAR,
BRIG_TYPE_NONE, "__hsail_waitfbar", BT_FN_VOID_UINT_PTR,
- ATTR_NOTHROW_LIST)
+ ATTR_RT_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_ARRIVEFBAR, BRIG_OPCODE_ARRIVEFBAR,
BRIG_TYPE_NONE, "__hsail_arrivefbar", BT_FN_VOID_UINT_PTR,
- ATTR_NOTHROW_LIST)
+ ATTR_RT_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_LEAVEFBAR, BRIG_OPCODE_LEAVEFBAR,
BRIG_TYPE_NONE, "__hsail_leavefbar", BT_FN_VOID_UINT_PTR,
@@ -268,41 +268,41 @@ DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_RELEASEFBAR, BRIG_OPCODE_RELEASEFBAR,
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BITALIGN, BRIG_OPCODE_BITALIGN,
BRIG_TYPE_B32, "__hsail_bitalign",
- BT_FN_UINT_ULONG_ULONG_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_ULONG_ULONG_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_BYTEALIGN, BRIG_OPCODE_BYTEALIGN,
BRIG_TYPE_B32, "__hsail_bytealign",
- BT_FN_UINT_ULONG_ULONG_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_ULONG_ULONG_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_LERP, BRIG_OPCODE_LERP,
BRIG_TYPE_U8X4, "__hsail_lerp", BT_FN_UINT_UINT_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_PACKCVT, BRIG_OPCODE_PACKCVT,
BRIG_TYPE_U8X4, "__hsail_packcvt",
BT_FN_UINT_FLOAT_FLOAT_FLOAT_FLOAT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_UNPACKCVT, BRIG_OPCODE_UNPACKCVT,
BRIG_TYPE_F32, "__hsail_unpackcvt", BT_FN_FLOAT_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_SAD_U16X2, BRIG_OPCODE_SAD,
BRIG_TYPE_U16X2, "__hsail_sad_u16x2",
- BT_FN_UINT_UINT_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_UINT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_SAD_U32, BRIG_OPCODE_SAD,
BRIG_TYPE_U32, "__hsail_sad_u32", BT_FN_UINT_UINT_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_SAD_U8X4, BRIG_OPCODE_SAD,
- BRIG_TYPE_U8X4, "__hsail_sad_u8x4", BT_FN_UINT_UINT_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ BRIG_TYPE_U8X4, "__hsail_sad_u8x4",
+ BT_FN_UINT_UINT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_SADHI_U8X4, BRIG_OPCODE_SADHI,
BRIG_TYPE_U16X2, "__hsail_sadhi_u16x2_u8x4",
BT_FN_UINT_UINT_UINT_UINT,
- ATTR_PURE_NOTHROW_LEAF_LIST)
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_BUILTIN (BUILT_IN_HSAIL_CLOCK, BRIG_OPCODE_CLOCK,
BRIG_TYPE_U64, "__hsail_clock", BT_FN_ULONG,
@@ -447,112 +447,112 @@ DEF_HSAIL_ATOMIC_BUILTIN (BUILT_IN_HSAIL_ATOMIC_WRAPINC_U64,
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_ADD_U64, BRIG_OPCODE_ADD,
BRIG_TYPE_U64, "__hsail_sat_add_u64",
- BT_FN_ULONG_ULONG_ULONG, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_ULONG_ULONG_ULONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_ADD_S64, BRIG_OPCODE_ADD,
BRIG_TYPE_S64, "__hsail_sat_add_s64",
- BT_FN_LONG_LONG_LONG, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_LONG_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_ADD_U32, BRIG_OPCODE_ADD,
BRIG_TYPE_U32, "__hsail_sat_add_u32",
- BT_FN_UINT_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_ADD_S32, BRIG_OPCODE_ADD,
BRIG_TYPE_S32, "__hsail_sat_add_s32",
- BT_FN_INT_INT_INT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_ADD_U16, BRIG_OPCODE_ADD,
BRIG_TYPE_U16, "__hsail_sat_add_u16",
- BT_FN_UINT16_UINT16_UINT16, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT16_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_ADD_S16, BRIG_OPCODE_ADD,
BRIG_TYPE_S16, "__hsail_sat_add_s16",
- BT_FN_INT16_INT16_INT16, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT16_INT16_INT16, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_ADD_U8, BRIG_OPCODE_ADD,
BRIG_TYPE_U8, "__hsail_sat_add_u8",
- BT_FN_UINT8_UINT8_UINT8, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT8_UINT8_UINT8, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_ADD_S8, BRIG_OPCODE_ADD,
BRIG_TYPE_S8, "__hsail_sat_add_s8",
- BT_FN_INT8_INT8_INT8, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT8_INT8_INT8, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_SUB_U64, BRIG_OPCODE_SUB,
BRIG_TYPE_U64, "__hsail_sat_sub_u64",
- BT_FN_ULONG_ULONG_ULONG, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_ULONG_ULONG_ULONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_SUB_S64, BRIG_OPCODE_SUB,
BRIG_TYPE_S64, "__hsail_sat_sub_s64",
- BT_FN_LONG_LONG_LONG, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_LONG_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_SUB_U32, BRIG_OPCODE_SUB,
BRIG_TYPE_U32, "__hsail_sat_sub_u32",
- BT_FN_UINT_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_SUB_S32, BRIG_OPCODE_SUB,
BRIG_TYPE_S32, "__hsail_sat_sub_s32",
- BT_FN_INT_INT_INT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_SUB_U16, BRIG_OPCODE_SUB,
BRIG_TYPE_U16, "__hsail_sat_sub_u16",
- BT_FN_UINT16_UINT16_UINT16, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT16_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_SUB_S16, BRIG_OPCODE_SUB,
BRIG_TYPE_S16, "__hsail_sat_sub_s16",
- BT_FN_INT16_INT16_INT16, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT16_INT16_INT16, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_SUB_U8, BRIG_OPCODE_SUB,
BRIG_TYPE_U8, "__hsail_sat_sub_u8",
- BT_FN_UINT8_UINT8_UINT8, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT8_UINT8_UINT8, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_SUB_S8, BRIG_OPCODE_SUB,
BRIG_TYPE_S8, "__hsail_sat_sub_s8",
- BT_FN_INT8_INT8_INT8, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT8_INT8_INT8, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_MUL_U64, BRIG_OPCODE_MUL,
BRIG_TYPE_U64, "__hsail_sat_mul_u64",
- BT_FN_ULONG_ULONG_ULONG, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_ULONG_ULONG_ULONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_MUL_S64, BRIG_OPCODE_MUL,
BRIG_TYPE_S64, "__hsail_sat_mul_s64",
- BT_FN_LONG_LONG_LONG, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_LONG_LONG_LONG, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_MUL_U32, BRIG_OPCODE_MUL,
BRIG_TYPE_U32, "__hsail_sat_mul_u32",
- BT_FN_UINT_UINT_UINT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT_UINT_UINT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_MUL_S32, BRIG_OPCODE_MUL,
BRIG_TYPE_S32, "__hsail_sat_mul_s32",
- BT_FN_INT_INT_INT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT_INT_INT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_MUL_U16, BRIG_OPCODE_MUL,
BRIG_TYPE_U16, "__hsail_sat_mul_u16",
- BT_FN_UINT16_UINT16_UINT16, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT16_UINT16_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_MUL_S16, BRIG_OPCODE_MUL,
BRIG_TYPE_S16, "__hsail_sat_mul_s16",
- BT_FN_INT16_INT16_INT16, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT16_INT16_INT16, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_MUL_U8, BRIG_OPCODE_MUL,
BRIG_TYPE_U8, "__hsail_sat_mul_u8",
- BT_FN_UINT8_UINT8_UINT8, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT8_UINT8_UINT8, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_SAT_BUILTIN (BUILT_IN_HSAIL_SAT_MUL_S8, BRIG_OPCODE_MUL,
BRIG_TYPE_S8, "__hsail_sat_mul_s8",
- BT_FN_INT8_INT8_INT8, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT8_INT8_INT8, ATTR_CONST_NOTHROW_LEAF_LIST)
#ifndef DEF_HSAIL_INTR_BUILTIN
#define DEF_HSAIL_INTR_BUILTIN(ENUM, NAME, TYPE, ATTRS)
#endif
DEF_HSAIL_INTR_BUILTIN (BUILT_IN_HSAIL_FTZ_F32_F16, "__hsail_ftz_f32_f16",
- BT_FN_FLOAT_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_INTR_BUILTIN (BUILT_IN_HSAIL_FTZ_F32, "__hsail_ftz_f32",
- BT_FN_FLOAT_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_FLOAT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_INTR_BUILTIN (BUILT_IN_HSAIL_FTZ_F64, "__hsail_ftz_f64",
- BT_FN_DOUBLE_DOUBLE, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_DOUBLE_DOUBLE, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_INTR_BUILTIN (BUILT_IN_HSAIL_PUSH_FRAME, "__hsail_alloca_push_frame",
BT_FN_VOID_PTR, ATTR_NOTHROW_LEAF_LIST)
@@ -572,10 +572,10 @@ DEF_HSAIL_INTR_BUILTIN (BUILT_IN_HSAIL_LAUNCH_KERNEL,
BT_FN_VOID_PTR_PTR_PTR, ATTR_NOTHROW_LEAF_LIST)
DEF_HSAIL_INTR_BUILTIN (BUILT_IN_HSAIL_F32_TO_F16, "__hsail_f32_to_f16",
- BT_FN_UINT16_UINT32, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT16_UINT32, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_INTR_BUILTIN (BUILT_IN_HSAIL_F16_TO_F32, "__hsail_f16_to_f32",
- BT_FN_UINT32_UINT16, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT32_UINT16, ATTR_CONST_NOTHROW_LEAF_LIST)
#ifndef DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN
#define DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN(ENUM, HSAIL_DEST_TYPE, HSAIL_SRC_TYPE, \
@@ -585,79 +585,90 @@ DEF_HSAIL_INTR_BUILTIN (BUILT_IN_HSAIL_F16_TO_F32, "__hsail_f16_to_f32",
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_U8_F32,
BRIG_TYPE_U8, BRIG_TYPE_F32,
"__hsail_cvt_zeroi_sat_u8_f32",
- BT_FN_UINT8_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT8_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_S8_F32,
BRIG_TYPE_S8, BRIG_TYPE_F32,
"__hsail_cvt_zeroi_sat_s8_f32",
- BT_FN_INT8_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT8_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_U16_F32,
BRIG_TYPE_U16, BRIG_TYPE_F32,
"__hsail_cvt_zeroi_sat_u16_f32",
- BT_FN_UINT16_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT16_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_S16_F32,
BRIG_TYPE_S16, BRIG_TYPE_F32,
"__hsail_cvt_zeroi_sat_s16_f32",
- BT_FN_INT16_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT16_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_U32_F32,
BRIG_TYPE_U32, BRIG_TYPE_F32,
"__hsail_cvt_zeroi_sat_u32_f32",
- BT_FN_UINT32_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT32_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_S32_F32,
BRIG_TYPE_S32, BRIG_TYPE_F32,
"__hsail_cvt_zeroi_sat_s32_f32",
- BT_FN_INT_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_U64_F32,
BRIG_TYPE_U64, BRIG_TYPE_F32,
"__hsail_cvt_zeroi_sat_u64_f32",
- BT_FN_UINT64_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT64_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_S64_F32,
BRIG_TYPE_S64, BRIG_TYPE_F32,
"__hsail_cvt_zeroi_sat_s64_f32",
- BT_FN_LONG_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_LONG_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_U8_F64,
BRIG_TYPE_U8, BRIG_TYPE_F64,
"__hsail_cvt_zeroi_sat_u8_f64",
- BT_FN_UINT8_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT8_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_S8_F64,
BRIG_TYPE_S8, BRIG_TYPE_F64,
"__hsail_cvt_zeroi_sat_s8_f64",
- BT_FN_INT8_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT8_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_U16_F64,
BRIG_TYPE_U16, BRIG_TYPE_F64,
"__hsail_cvt_zeroi_sat_u16_f64",
- BT_FN_UINT16_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT16_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_S16_F64,
BRIG_TYPE_S16, BRIG_TYPE_F64,
"__hsail_cvt_zeroi_sat_s16_f64",
- BT_FN_INT16_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT16_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_U32_F64,
BRIG_TYPE_U32, BRIG_TYPE_F64,
"__hsail_cvt_zeroi_sat_u32_f64",
- BT_FN_UINT32_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT32_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_S32_F64,
BRIG_TYPE_S32, BRIG_TYPE_F64,
"__hsail_cvt_zeroi_sat_s32_f64",
- BT_FN_INT_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_INT_FLOAT, ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_U64_F64,
BRIG_TYPE_U64, BRIG_TYPE_F64,
"__hsail_cvt_zeroi_sat_u64_f64",
- BT_FN_UINT64_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_UINT64_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
DEF_HSAIL_CVT_ZEROI_SAT_BUILTIN (BUILT_IN_HSAIL_CVT_ZEROI_SAT_S64_F64,
BRIG_TYPE_S64, BRIG_TYPE_F64,
"__hsail_cvt_zeroi_sat_s64_f64",
- BT_FN_LONG_FLOAT, ATTR_PURE_NOTHROW_LEAF_LIST)
+ BT_FN_LONG_FLOAT,
+ ATTR_CONST_NOTHROW_LEAF_LIST)
diff --git a/gcc/brig/ChangeLog b/gcc/brig/ChangeLog
index ebf31c4..0177859 100644
--- a/gcc/brig/ChangeLog
+++ b/gcc/brig/ChangeLog
@@ -1,3 +1,71 @@
+2017-10-23 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * brig-lang.c (brig_langhook_type_for_mode): Use scalar_int_mode
+ and scalar_float_mode.
+
+2017-10-09 Pekka Jääskeläinen <pekka.jaaskelainen@parmance.com>
+
+ * brigfrontend/brig-to-generic.cc: Support BRIG_KIND_NONE
+ directives. These directives are legal everywhere. They
+ can be used to patch away BRIG entries at the binary level.
+ Also add extra error detection for zeroed regions: make sure
+ the byteCount field is never zero.
+ * brig/brigfrontend/phsa.h: Added a new error prefix for
+ errors which are due to corrupted BRIG modules.
+
+2017-10-09 Henry Linjamäki <henry.linjamaki@parmance.com>
+
+ * brigfrontend/brig-branch-inst-handler.cc: The call code
+ still failed a few test cases. Now all PRM cases pass again.
+
+2017-10-03 Henry Linjamäki <henry.linjamaki@parmance.com>
+
+ * brigfrontend/brig-branch-inst-handler.cc: Fix (more) crash with
+ calls with more than 4 args. It missed a reference which is required
+ because vector expansion can move the object to another location.
+
+2017-09-29 Henry Linjamäki <henry.linjamaki@parmance.com>
+
+ * brigfrontend/brig-branch-inst-handler.cc: Fix crash with
+ calls with more than 4 args. Also fix a misexecution issue
+ with kernels that have both unexpanded ID functions and
+ calls to subfunctions.
+
+2017-09-28 Henry Linjamäki <henry.linjamaki@parmance.com>
+
+ * brig-lang.c: Added function attributes and their handlers.
+ Make BRIGFE 3-level optimize by default.
+
+2017-09-27 Pekka Jääskeläinen <pekka.jaaskelainen@parmance.com>
+
+ * brig-lang.c: Improved support for function and module scope
+ group segment variables. PRM specs defines function and module
+ scope group segment variables as an experimental feature. However,
+ PRM test suite uses and hcc relies on them. In addition, hcc
+ assumes certain group variable layout in its dynamic group segment
+ allocation code. We cannot have global group memory offsets if we
+ want to both have kernel-specific group segment size and multiple
+ kernels calling the same functions that use function scope group memory
+ variables. Now group segment is handled by separate book keeping of
+ module scope and function (kernel) offsets. Each function has a "frame"
+ in the group segment offset to which is given as an argument.
+ * brigfrontend/brig-branch-inst-handler.cc: See above.
+ * brigfrontend/brig-code-entry-handler.cc: See above.
+ * brigfrontend/brig-fbarrier-handler.cc: See above.
+ * brigfrontend/brig-function-handler.cc: See above.
+ * brigfrontend/brig-function.cc: See above.
+ * brigfrontend/brig-function.h: See above.
+ * brigfrontend/brig-to-generic.cc: See above.
+ * brigfrontend/brig-to-generic.h: See above.
+ * brigfrontend/brig-util.cc: See above.
+ * brigfrontend/brig-util.h: See above.
+ * brigfrontend/brig-variable-handler.cc: See above.
+
+2017-09-25 Pekka Jääskeläinen <pekka.jaaskelainen@parmance.com>
+
+ * brigfrontend/brig-to-generic.cc: Ensure per WI copies of
+ private variables are aligned too.
+
2017-09-17 Thomas Schwinge <thomas@codesourcery.com>
* Make-lang.in (GO_TEXI_FILES): Rename to...
diff --git a/gcc/brig/brig-lang.c b/gcc/brig/brig-lang.c
index 13e738e..cff6055 100644
--- a/gcc/brig/brig-lang.c
+++ b/gcc/brig/brig-lang.c
@@ -51,6 +51,12 @@ along with GCC; see the file COPYING3. If not see
#include "brig-c.h"
#include "brig-builtins.h"
+static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
+static tree handle_const_attribute (tree *, tree, tree, int, bool *);
+static tree handle_pure_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
+static tree handle_returns_twice_attribute (tree *, tree, tree, int, bool *);
+
/* This file is based on Go frontent'd go-lang.c and gogo-tree.cc. */
/* If -v set. */
@@ -128,6 +134,8 @@ brig_langhook_init_options_struct (struct gcc_options *opts)
opts->x_flag_finite_math_only = 0;
opts->x_flag_signed_zeros = 1;
+
+ opts->x_optimize = 3;
}
/* Handle Brig specific options. Return 0 if we didn't do anything. */
@@ -160,7 +168,7 @@ brig_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED)
flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
/* gccbrig casts pointers around like crazy, TBAA produces
- broken code if not force disabling it. */
+ broken code if not force disabling it. */
flag_strict_aliasing = 0;
/* Returning false means that the backend should be used. */
@@ -182,6 +190,8 @@ brig_langhook_parse_file (void)
{
brig_to_generic brig_to_gen;
+ std::vector <char*> brig_blobs;
+
for (unsigned int i = 0; i < num_in_fnames; ++i)
{
@@ -194,11 +204,22 @@ brig_langhook_parse_file (void)
error ("could not read the BRIG file");
exit (1);
}
- brig_to_gen.parse (brig_blob);
fclose (f);
+
+ brig_to_gen.analyze (brig_blob);
+ brig_blobs.push_back (brig_blob);
+ }
+
+ for (size_t i = 0; i < brig_blobs.size(); ++i)
+ {
+ char *brig_blob = brig_blobs.at(i);
+ brig_to_gen.parse (brig_blob);
}
brig_to_gen.write_globals ();
+
+ for (size_t i = 0; i < brig_blobs.size (); ++i)
+ delete brig_blobs[i];
}
static tree
@@ -257,10 +278,11 @@ brig_langhook_type_for_mode (machine_mode mode, int unsignedp)
return NULL_TREE;
}
- enum mode_class mc = GET_MODE_CLASS (mode);
- if (mc == MODE_FLOAT)
+ scalar_int_mode imode;
+ scalar_float_mode fmode;
+ if (is_int_mode (mode, &imode))
{
- switch (GET_MODE_BITSIZE (mode))
+ switch (GET_MODE_BITSIZE (imode))
{
case 32:
return float_type_node;
@@ -269,15 +291,15 @@ brig_langhook_type_for_mode (machine_mode mode, int unsignedp)
default:
/* We have to check for long double in order to support
i386 excess precision. */
- if (mode == TYPE_MODE (long_double_type_node))
+ if (imode == TYPE_MODE (long_double_type_node))
return long_double_type_node;
gcc_unreachable ();
return NULL_TREE;
}
}
- else if (mc == MODE_INT)
- return brig_langhook_type_for_size(GET_MODE_BITSIZE(mode), unsignedp);
+ else if (is_float_mode (mode, &fmode))
+ return brig_langhook_type_for_size (GET_MODE_BITSIZE (fmode), unsignedp);
else
{
/* E.g., build_common_builtin_nodes () asks for modes/builtins
@@ -419,6 +441,124 @@ brig_localize_identifier (const char *ident)
return identifier_to_locale (ident);
}
+/* Define supported attributes and their handlers. Code copied from
+ lto-lang.c */
+
+/* Table of machine-independent attributes supported in GIMPLE. */
+const struct attribute_spec brig_attribute_table[] =
+{
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ do_diagnostic } */
+ { "leaf", 0, 0, true, false, false,
+ handle_leaf_attribute, false },
+ { "const", 0, 0, true, false, false,
+ handle_const_attribute, false },
+ { "pure", 0, 0, true, false, false,
+ handle_pure_attribute, false },
+ { "nothrow", 0, 0, true, false, false,
+ handle_nothrow_attribute, false },
+ { "returns_twice", 0, 0, true, false, false,
+ handle_returns_twice_attribute, false },
+ { NULL, 0, 0, false, false, false, NULL, false }
+};
+
+/* Attribute handlers. */
+/* Handle a "leaf" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_leaf_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_DECL)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ if (!TREE_PUBLIC (*node))
+ {
+ warning (OPT_Wattributes,
+ "%qE attribute has no effect on unit local functions", name);
+ *no_add_attrs = true;
+ }
+
+ 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 "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 "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 "returns_twice" attribute. */
+
+static tree
+handle_returns_twice_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_RETURNS_TWICE (*node) = 1;
+
+ return NULL_TREE;
+}
+
+
/* Built-in initialization code cribbed from lto-lang.c which cribbed it
from c-common.c. */
@@ -801,6 +941,10 @@ brig_langhook_init (void)
#define LANG_HOOKS_GIMPLIFY_EXPR brig_langhook_gimplify_expr
#define LANG_HOOKS_EH_PERSONALITY brig_langhook_eh_personality
+/* Attribute hooks. */
+#undef LANG_HOOKS_COMMON_ATTRIBUTE_TABLE
+#define LANG_HOOKS_COMMON_ATTRIBUTE_TABLE brig_attribute_table
+
struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER;
#include "gt-brig-brig-lang.h"
diff --git a/gcc/brig/brigfrontend/brig-branch-inst-handler.cc b/gcc/brig/brigfrontend/brig-branch-inst-handler.cc
index 9cec5b6..039f185 100644
--- a/gcc/brig/brigfrontend/brig-branch-inst-handler.cc
+++ b/gcc/brig/brigfrontend/brig-branch-inst-handler.cc
@@ -42,7 +42,8 @@ brig_branch_inst_handler::operator () (const BrigBase *base)
vec<tree, va_gc> *out_args;
vec_alloc (out_args, 1);
vec<tree, va_gc> *in_args;
- vec_alloc (in_args, 4);
+ /* Ten elem initially, more reserved if needed. */
+ vec_alloc (in_args, 10);
size_t operand_count = operand_entries->byteCount / 4;
gcc_assert (operand_count < 4);
@@ -69,7 +70,7 @@ brig_branch_inst_handler::operator () (const BrigBase *base)
const BrigOperandOffset32_t *operand_ptr
= (const BrigOperandOffset32_t *) data->bytes;
- vec<tree, va_gc> *args = i == 0 ? out_args : in_args;
+ bool out_args_p = i == 0;
while (bytes > 0)
{
@@ -84,7 +85,7 @@ brig_branch_inst_handler::operator () (const BrigBase *base)
if (brig_var->type & BRIG_TYPE_ARRAY)
{
/* Array return values are passed as the first argument. */
- args = in_args;
+ out_args_p = false;
/* Pass pointer to the element zero and use its element zero
as the base address. */
tree etype = TREE_TYPE (TREE_TYPE (var));
@@ -96,7 +97,7 @@ brig_branch_inst_handler::operator () (const BrigBase *base)
}
gcc_assert (var != NULL_TREE);
- vec_safe_push (args, var);
+ vec_safe_push (out_args_p ? out_args : in_args, var);
++operand_ptr;
bytes -= 4;
}
@@ -117,8 +118,18 @@ brig_branch_inst_handler::operator () (const BrigBase *base)
they might call builtins that need them or access group/private
memory. */
+ tree group_local_offset
+ = add_temp_var ("group_local_offset",
+ build_int_cst
+ (uint32_type_node,
+ m_parent.m_cf->m_local_group_variables.size()));
+
+ /* TODO: ensure the callee's frame is aligned! */
+
+ vec_safe_reserve (in_args, 4);
vec_safe_push (in_args, m_parent.m_cf->m_context_arg);
vec_safe_push (in_args, m_parent.m_cf->m_group_base_arg);
+ vec_safe_push (in_args, group_local_offset);
vec_safe_push (in_args, m_parent.m_cf->m_private_base_arg);
tree call = build_call_vec (ret_val_type, build_fold_addr_expr (func_ref),
@@ -138,7 +149,6 @@ brig_branch_inst_handler::operator () (const BrigBase *base)
m_parent.m_cf->append_statement (call);
}
- m_parent.m_cf->m_has_unexpanded_dp_builtins = false;
m_parent.m_cf->m_called_functions.push_back (func_ref);
return base->byteCount;
diff --git a/gcc/brig/brigfrontend/brig-code-entry-handler.cc b/gcc/brig/brigfrontend/brig-code-entry-handler.cc
index 8f07d37..a660739 100644
--- a/gcc/brig/brigfrontend/brig-code-entry-handler.cc
+++ b/gcc/brig/brigfrontend/brig-code-entry-handler.cc
@@ -88,10 +88,17 @@ brig_code_entry_handler::build_code_ref (const BrigBase &ref)
{
const BrigDirectiveFbarrier* fbar = (const BrigDirectiveFbarrier*)&ref;
- uint64_t offset = m_parent.group_variable_segment_offset
- (m_parent.get_mangled_name (fbar));
-
- return build_int_cst (uint32_type_node, offset);
+ std::string var_name = m_parent.get_mangled_name (fbar);
+ uint64_t offset
+ = m_parent.m_cf->group_variable_segment_offset (var_name);
+
+ tree local_offset = build_int_cst (uint32_type_node, offset);
+ if (m_parent.m_cf->m_local_group_variables.has_variable (var_name))
+ local_offset
+ = build2 (PLUS_EXPR, uint64_type_node, local_offset,
+ convert (uint64_type_node,
+ m_parent.m_cf->m_group_local_offset_arg));
+ return local_offset;
}
else
gcc_unreachable ();
@@ -264,9 +271,18 @@ brig_code_entry_handler::build_address_operand
}
else if (segment == BRIG_SEGMENT_GROUP)
{
-
- uint64_t offset = m_parent.group_variable_segment_offset (var_name);
+ uint64_t offset
+ = m_parent.m_cf->group_variable_segment_offset (var_name);
const_offset = build_int_cst (size_type_node, offset);
+
+ /* If it's a local group variable reference, substract the local
+ group segment offset to get the group base ptr offset. */
+ if (m_parent.m_cf->m_local_group_variables.has_variable (var_name))
+ const_offset
+ = build2 (PLUS_EXPR, uint64_type_node, const_offset,
+ convert (uint64_type_node,
+ m_parent.m_cf->m_group_local_offset_arg));
+
}
else if (segment == BRIG_SEGMENT_PRIVATE || segment == BRIG_SEGMENT_SPILL)
{
diff --git a/gcc/brig/brigfrontend/brig-fbarrier-handler.cc b/gcc/brig/brigfrontend/brig-fbarrier-handler.cc
index 802d51c..a033db6 100644
--- a/gcc/brig/brigfrontend/brig-fbarrier-handler.cc
+++ b/gcc/brig/brigfrontend/brig-fbarrier-handler.cc
@@ -39,6 +39,7 @@ brig_directive_fbarrier_handler::operator () (const BrigBase *base)
if (m_parent.m_cf != NULL)
m_parent.m_cf->m_function_scope_vars.insert (base);
std::string var_name = m_parent.get_mangled_name (fbar);
- m_parent.append_group_variable (var_name, FBARRIER_STRUCT_SIZE, 1);
+ m_parent.add_group_variable (var_name, FBARRIER_STRUCT_SIZE, 1,
+ m_parent.m_cf != NULL);
return base->byteCount;
}
diff --git a/gcc/brig/brigfrontend/brig-function-handler.cc b/gcc/brig/brigfrontend/brig-function-handler.cc
index ebfca39..7896c4a 100644
--- a/gcc/brig/brigfrontend/brig-function-handler.cc
+++ b/gcc/brig/brigfrontend/brig-function-handler.cc
@@ -39,7 +39,8 @@ extern int gccbrig_verbose;
size_t
brig_directive_function_handler::operator () (const BrigBase *base)
{
- m_parent.finish_function ();
+ if (!m_parent.m_analyzing)
+ m_parent.finish_function ();
size_t bytes_consumed = base->byteCount;
@@ -64,9 +65,20 @@ brig_directive_function_handler::operator () (const BrigBase *base)
if (is_kernel && !is_definition)
return bytes_consumed;
+ std::string func_name = m_parent.get_mangled_name (exec);
+ if (is_kernel)
+ /* The generated kernel function is not the one that should be
+ called by the host. */
+ func_name = std::string ("_") + func_name;
+
m_parent.m_cf = new brig_function (exec, &m_parent);
+ m_parent.m_cf->m_name = func_name;
+ m_parent.m_cf->m_is_kernel = is_kernel;
- std::string func_name = m_parent.get_mangled_name (exec);
+ /* During the analyze step, the above information is all we need per
+ function. */
+ if (m_parent.m_analyzing)
+ return bytes_consumed;
tree fndecl;
tree ret_value = NULL_TREE;
@@ -79,10 +91,6 @@ brig_directive_function_handler::operator () (const BrigBase *base)
if (is_kernel)
{
- /* The generated kernel function is not the one that should be
- called by the host. */
- func_name = std::string ("_") + func_name;
-
tree name_identifier
= get_identifier_with_length (func_name.c_str (), func_name.size ());
@@ -256,6 +264,23 @@ brig_directive_function_handler::operator () (const BrigBase *base)
DECL_ARTIFICIAL (group_base_arg) = 1;
TREE_READONLY (group_base_arg) = 1;
TREE_USED (group_base_arg) = 1;
+ m_parent.m_cf->m_group_base_arg = group_base_arg;
+
+ /* To implement call stack and (non-kernel) function scope group variables,
+ we need to pass an offset which describes how far are we from
+ group_base_ptr.
+ That must be substracted from any function local group variable offsets to
+ get the address related to the bottom of the group memory chunk. */
+ tree group_local_offset_arg
+ = build_decl (UNKNOWN_LOCATION, PARM_DECL,
+ get_identifier ("__group_local_offset"), uint32_type_node);
+ chainon (DECL_ARGUMENTS (fndecl), group_local_offset_arg);
+ DECL_ARG_TYPE (group_local_offset_arg) = uint32_type_node;
+ DECL_CONTEXT (group_local_offset_arg) = fndecl;
+ DECL_ARTIFICIAL (group_local_offset_arg) = 1;
+ TREE_READONLY (group_local_offset_arg) = 1;
+ TREE_USED (group_local_offset_arg) = 1;
+ m_parent.m_cf->m_group_local_offset_arg = group_local_offset_arg;
/* Same for private. */
tree private_base_arg
@@ -329,12 +354,9 @@ brig_directive_function_handler::operator () (const BrigBase *base)
m_parent.start_function (fndecl);
- m_parent.m_cf->m_name = func_name;
m_parent.m_cf->m_func_decl = fndecl;
m_parent.m_cf->m_current_bind_expr = bind_expr;
- m_parent.m_cf->m_is_kernel = is_kernel;
m_parent.m_cf->m_context_arg = context_arg;
- m_parent.m_cf->m_group_base_arg = group_base_arg;
m_parent.m_cf->m_private_base_arg = private_base_arg;
if (ret_value != NULL_TREE && TREE_TYPE (ret_value) != void_type_node)
diff --git a/gcc/brig/brigfrontend/brig-function.cc b/gcc/brig/brigfrontend/brig-function.cc
index 0ca9ebe..f3c3895 100644
--- a/gcc/brig/brigfrontend/brig-function.cc
+++ b/gcc/brig/brigfrontend/brig-function.cc
@@ -52,11 +52,10 @@ brig_function::brig_function (const BrigDirectiveExecutable *exec,
m_context_arg (NULL_TREE), m_group_base_arg (NULL_TREE),
m_private_base_arg (NULL_TREE), m_ret_value (NULL_TREE),
m_next_kernarg_offset (0), m_kernarg_max_align (0),
- m_ret_value_brig_var (NULL), m_has_barriers (false),
- m_has_allocas (false), m_has_function_calls_with_barriers (false),
- m_calls_analyzed (false), m_is_wg_function (false),
- m_has_unexpanded_dp_builtins (false), m_generating_arg_block (false),
- m_parent (parent)
+ m_ret_value_brig_var (NULL), m_has_barriers (false), m_has_allocas (false),
+ m_has_function_calls_with_barriers (false), m_calls_analyzed (false),
+ m_is_wg_function (false), m_has_unexpanded_dp_builtins (false),
+ m_generating_arg_block (false), m_parent (parent)
{
memset (m_regs, 0,
BRIG_2_TREE_HSAIL_TOTAL_REG_COUNT * sizeof (BrigOperandRegister *));
@@ -577,20 +576,31 @@ brig_function::emit_launcher_and_metadata ()
tree phsail_launch_kernel_call;
+ /* Compute the local group segment frame start pointer. */
+ tree group_local_offset_temp
+ = create_tmp_var (uint32_type_node, "group_local_offset");
+ tree group_local_offset_arg
+ = build2 (MODIFY_EXPR, uint32_type_node,
+ group_local_offset_temp,
+ build_int_cst (uint32_type_node,
+ m_parent->m_module_group_variables.size()));
+
/* Emit a launcher depending whether we converted the kernel function to
a work group function or not. */
if (m_is_wg_function)
phsail_launch_kernel_call
= call_builtin (builtin_decl_explicit (BUILT_IN_HSAIL_LAUNCH_WG_FUNC),
- 3, void_type_node,
+ 4, void_type_node,
ptr_type_node, kernel_func_ptr, ptr_type_node,
- context_arg, ptr_type_node, group_base_addr_arg);
+ context_arg, ptr_type_node, group_base_addr_arg,
+ uint32_type_node, group_local_offset_arg);
else
phsail_launch_kernel_call
= call_builtin (builtin_decl_explicit (BUILT_IN_HSAIL_LAUNCH_KERNEL),
- 3, void_type_node,
+ 4, void_type_node,
ptr_type_node, kernel_func_ptr, ptr_type_node,
- context_arg, ptr_type_node, group_base_addr_arg);
+ context_arg, ptr_type_node, group_base_addr_arg,
+ uint32_type_node, group_local_offset_arg);
append_to_statement_list_force (phsail_launch_kernel_call, &stmt_list);
@@ -722,3 +732,13 @@ brig_function::has_function_scope_var (const BrigBase* var) const
{
return m_function_scope_vars.find (var) != m_function_scope_vars.end ();
}
+
+size_t
+brig_function::group_variable_segment_offset (const std::string &name) const
+{
+ if (m_local_group_variables.has_variable (name))
+ return m_local_group_variables.segment_offset (name);
+
+ gcc_assert (m_parent->m_module_group_variables.has_variable (name));
+ return m_parent->m_module_group_variables.segment_offset (name);
+}
diff --git a/gcc/brig/brigfrontend/brig-function.h b/gcc/brig/brigfrontend/brig-function.h
index 71b5d3f..2a85f5e 100644
--- a/gcc/brig/brigfrontend/brig-function.h
+++ b/gcc/brig/brigfrontend/brig-function.h
@@ -30,8 +30,7 @@
#include "tree.h"
#include "tree-iterator.h"
#include "hsa-brig-format.h"
-
-class brig_to_generic;
+#include "brig-util.h"
#include <map>
#include <string>
@@ -40,6 +39,8 @@ class brig_to_generic;
#include "phsa.h"
+class brig_to_generic;
+
typedef std::map<std::string, tree> label_index;
typedef std::map<const BrigDirectiveVariable *, tree> variable_index;
typedef std::vector<tree> tree_stl_vec;
@@ -84,6 +85,12 @@ public:
tree add_local_variable (std::string name, tree type);
+ size_t group_variable_segment_offset (const std::string &name) const;
+
+ bool has_group_variable (const std::string &name) const;
+
+ size_t group_segment_size () const;
+
tree get_m_var_declfor_reg (const BrigOperandRegister *reg);
bool convert_to_wg_function ();
@@ -119,10 +126,16 @@ public:
/* The __context function argument. */
tree m_context_arg;
+
/* The __group_base_ptr argument in the current function.
- Points to the start of the group segment for the kernel
- instance. */
+ Points to the start of the group segment for the work-group. */
tree m_group_base_arg;
+
+ /* The __group_local_offset_ptr argument in the current function. It
+ contains the offset related to the group_base_ptr where the function's
+ local area for group variables resides. */
+ tree m_group_local_offset_arg;
+
/* The __private_base_ptr argument in the current function.
Points to the start of the private segment. */
tree m_private_base_arg;
@@ -159,7 +172,7 @@ public:
/* True if the function has at least one alloca instruction. */
bool m_has_allocas;
- /* If the kernel containts at least one function call that _may_
+ /* If the kernel contains at least one function call that _may_
contain a barrier call, this is set to true. */
bool m_has_function_calls_with_barriers;
@@ -199,6 +212,10 @@ public:
/* The functions called by this function. */
std::vector<tree> m_called_functions;
+ /* Stores the kernel scope group variable offsets if the function is
+ a kernel. */
+ group_variable_offset_index m_local_group_variables;
+
brig_to_generic *m_parent;
/* The metadata of the function that should be stored with the binary and
passed to the HSA runtime: */
diff --git a/gcc/brig/brigfrontend/brig-to-generic.cc b/gcc/brig/brigfrontend/brig-to-generic.cc
index 7559c05..41246ba 100644
--- a/gcc/brig/brigfrontend/brig-to-generic.cc
+++ b/gcc/brig/brigfrontend/brig-to-generic.cc
@@ -60,8 +60,8 @@ tree brig_to_generic::s_fp32_type;
tree brig_to_generic::s_fp64_type;
brig_to_generic::brig_to_generic ()
- : m_cf (NULL), m_brig (NULL), m_next_group_offset (0),
- m_next_private_offset (0)
+ : m_cf (NULL), m_analyzing (true), m_total_group_segment_usage (0),
+ m_brig (NULL), m_next_private_offset (0)
{
m_globals = NULL_TREE;
@@ -124,33 +124,32 @@ public:
}
};
-/* Parses the given BRIG blob. */
+/* Helper struct for pairing a BrigKind and a BrigCodeEntryHandler that
+ should handle its data. */
-void
-brig_to_generic::parse (const char *brig_blob)
+struct code_entry_handler_info
{
- m_brig = brig_blob;
- m_brig_blobs.push_back (brig_blob);
+ BrigKind kind;
+ brig_code_entry_handler *handler;
+};
- const BrigModuleHeader *mheader = (const BrigModuleHeader *) brig_blob;
- if (strncmp (mheader->identification, "HSA BRIG", 8) != 0)
- fatal_error (UNKNOWN_LOCATION, PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE
- "Unrecognized file format.");
- if (mheader->brigMajor != 1 || mheader->brigMinor != 0)
- fatal_error (UNKNOWN_LOCATION, PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE
- "BRIG version not supported. BRIG 1.0 required.");
+/* Finds the BRIG file sections in the currently processed file. */
+void
+brig_to_generic::find_brig_sections ()
+{
m_data = m_code = m_operand = NULL;
+ const BrigModuleHeader *mheader = (const BrigModuleHeader *) m_brig;
/* Find the positions of the different sections. */
for (uint32_t sec = 0; sec < mheader->sectionCount; ++sec)
{
uint64_t offset
- = ((const uint64_t *) (brig_blob + mheader->sectionIndex))[sec];
+ = ((const uint64_t *) (m_brig + mheader->sectionIndex))[sec];
const BrigSectionHeader *section_header
- = (const BrigSectionHeader *) (brig_blob + offset);
+ = (const BrigSectionHeader *) (m_brig + offset);
std::string name ((const char *) (&section_header->name),
section_header->nameLength);
@@ -183,6 +182,99 @@ brig_to_generic::parse (const char *brig_blob)
if (m_operand == NULL)
gcc_unreachable ();
+}
+
+/* Does a first pass over the given BRIG to collect data needed for the
+ actual parsing. Currently this includes only collecting the
+ group segment variable usage to support the experimental HSA PRM feature
+ where group variables can be declared also in module and function scope
+ (in addition to kernel scope).
+*/
+
+void
+brig_to_generic::analyze (const char *brig_blob)
+{
+ const BrigModuleHeader *mheader = (const BrigModuleHeader *) brig_blob;
+
+ if (strncmp (mheader->identification, "HSA BRIG", 8) != 0)
+ fatal_error (UNKNOWN_LOCATION, PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE
+ "Unrecognized file format.");
+ if (mheader->brigMajor != 1 || mheader->brigMinor != 0)
+ fatal_error (UNKNOWN_LOCATION, PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE
+ "BRIG version not supported. BRIG 1.0 required.");
+
+ m_brig = brig_blob;
+
+ find_brig_sections ();
+
+ brig_directive_variable_handler var_handler (*this);
+ brig_directive_fbarrier_handler fbar_handler (*this);
+ brig_directive_function_handler func_handler (*this);
+
+ /* Need this for grabbing the module names for mangling the
+ group variable names. */
+ brig_directive_module_handler module_handler (*this);
+ skipped_entry_handler skipped_handler (*this);
+
+ const BrigSectionHeader *csection_header = (const BrigSectionHeader *) m_code;
+
+ code_entry_handler_info handlers[]
+ = {{BRIG_KIND_DIRECTIVE_VARIABLE, &var_handler},
+ {BRIG_KIND_DIRECTIVE_FBARRIER, &fbar_handler},
+ {BRIG_KIND_DIRECTIVE_KERNEL, &func_handler},
+ {BRIG_KIND_DIRECTIVE_MODULE, &module_handler},
+ {BRIG_KIND_DIRECTIVE_FUNCTION, &func_handler}};
+
+ m_analyzing = true;
+ for (size_t b = csection_header->headerByteCount; b < m_code_size;)
+ {
+ const BrigBase *entry = (const BrigBase *) (m_code + b);
+
+ brig_code_entry_handler *handler = &skipped_handler;
+
+ if (m_cf != NULL && b >= m_cf->m_brig_def->nextModuleEntry)
+ {
+ /* The function definition ended. We can just discard the place
+ holder function. */
+ m_total_group_segment_usage += m_cf->m_local_group_variables.size ();
+ delete m_cf;
+ m_cf = NULL;
+ }
+
+ /* Find a handler. */
+ for (size_t i = 0;
+ i < sizeof (handlers) / sizeof (code_entry_handler_info); ++i)
+ {
+ if (handlers[i].kind == entry->kind)
+ handler = handlers[i].handler;
+ }
+
+ int bytes_processed = (*handler) (entry);
+ if (bytes_processed == 0)
+ fatal_error (UNKNOWN_LOCATION, PHSA_ERROR_PREFIX_CORRUPTED_MODULE
+ "Element with 0 bytes.");
+ b += bytes_processed;
+ }
+
+ if (m_cf != NULL)
+ {
+ m_total_group_segment_usage += m_cf->m_local_group_variables.size ();
+ delete m_cf;
+ m_cf = NULL;
+ }
+
+ m_total_group_segment_usage += m_module_group_variables.size ();
+ m_analyzing = false;
+}
+
+/* Parses the given BRIG blob. */
+
+void
+brig_to_generic::parse (const char *brig_blob)
+{
+ m_brig = brig_blob;
+ find_brig_sections ();
+
brig_basic_inst_handler inst_handler (*this);
brig_branch_inst_handler branch_inst_handler (*this);
brig_cvt_inst_handler cvt_inst_handler (*this);
@@ -248,7 +340,10 @@ brig_to_generic::parse (const char *brig_blob)
/* There are no supported pragmas at this moment. */
{BRIG_KIND_DIRECTIVE_PRAGMA, &skipped_handler},
{BRIG_KIND_DIRECTIVE_CONTROL, &control_handler},
- {BRIG_KIND_DIRECTIVE_EXTENSION, &skipped_handler}};
+ {BRIG_KIND_DIRECTIVE_EXTENSION, &skipped_handler},
+ /* BRIG_KIND_NONE entries are valid anywhere. They can be used
+ for patching BRIGs before finalization. */
+ {BRIG_KIND_NONE, &skipped_handler}};
const BrigSectionHeader *csection_header = (const BrigSectionHeader *) m_code;
@@ -269,7 +364,6 @@ brig_to_generic::parse (const char *brig_blob)
handler = handlers[i].handler;
}
b += (*handler) (entry);
- continue;
}
finish_function ();
@@ -519,6 +613,29 @@ brig_to_generic::get_finished_function (tree func_decl)
return NULL;
}
+/* Adds a group variable to a correct book keeping structure depending
+ on its segment. */
+
+void
+brig_to_generic::add_group_variable (const std::string &name, size_t size,
+ size_t alignment, bool function_scope)
+{
+ /* Module and function scope group region variables are an experimental
+ feature. We implement module scope group variables with a separate
+ book keeping inside brig_to_generic which is populated in the 'analyze()'
+ prepass. This is to ensure we know the group segment offsets when
+ processing the functions that might refer to them. */
+ if (!function_scope)
+ {
+ if (!m_module_group_variables.has_variable (name))
+ m_module_group_variables.add (name, size, alignment);
+ return;
+ }
+
+ if (!m_cf->m_local_group_variables.has_variable (name))
+ m_cf->m_local_group_variables.add (name, size, alignment);
+}
+
/* Finalizes the currently handled function. Should be called before
setting a new function. */
@@ -567,50 +684,34 @@ brig_to_generic::start_function (tree f)
m_cf->m_func_decl = f;
}
-/* Appends a new group variable (or an fbarrier) to the current kernel's
- group segment. */
-
-void
-brig_to_generic::append_group_variable (const std::string &name, size_t size,
- size_t alignment)
-{
- size_t align_padding = m_next_group_offset % alignment == 0 ?
- 0 : (alignment - m_next_group_offset % alignment);
- m_next_group_offset += align_padding;
- m_group_offsets[name] = m_next_group_offset;
- m_next_group_offset += size;
-}
-
-size_t
-brig_to_generic::group_variable_segment_offset (const std::string &name) const
-{
- var_offset_table::const_iterator i = m_group_offsets.find (name);
- gcc_assert (i != m_group_offsets.end ());
- return (*i).second;
-}
-
-/* The size of the group and private segments required by the currently
- processed kernel. Private segment size must be multiplied by the
- number of work-items in the launch, in case of a work-group function. */
-
-size_t
-brig_to_generic::group_segment_size () const
-{
- return m_next_group_offset;
-}
-
-/* Appends a new group variable to the current kernel's private segment. */
+/* Appends a new variable to the current kernel's private segment. */
void
brig_to_generic::append_private_variable (const std::string &name,
size_t size, size_t alignment)
{
+ /* We need to take care of two cases of alignment with private
+ variables because of the layout where the same variable for
+ each work-item is laid out in successive addresses.
+
+ 1) Ensure the first work-item's variable is in an aligned
+ offset: */
size_t align_padding = m_next_private_offset % alignment == 0 ?
0 : (alignment - m_next_private_offset % alignment);
+
+ /* 2) Each successive per-work-item copy should be aligned.
+ If the variable has wider alignment than size then we need
+ to add extra padding to ensure it. The padding must be
+ included in the size to allow per-work-item offset computation
+ to find their own aligned copy. */
+
+ size_t per_var_padding = size % alignment == 0 ?
+ 0 : (alignment - size % alignment);
+ m_private_data_sizes[name] = size + per_var_padding;
+
m_next_private_offset += align_padding;
m_private_offsets[name] = m_next_private_offset;
- m_next_private_offset += size;
- m_private_data_sizes[name] = size + align_padding;
+ m_next_private_offset += size + per_var_padding;
}
size_t
@@ -630,13 +731,6 @@ brig_to_generic::has_private_variable (const std::string &name) const
return i != m_private_data_sizes.end ();
}
-bool
-brig_to_generic::has_group_variable (const std::string &name) const
-{
- var_offset_table::const_iterator i = m_group_offsets.find (name);
- return i != m_group_offsets.end ();
-}
-
size_t
brig_to_generic::private_variable_size (const std::string &name) const
{
@@ -646,6 +740,10 @@ brig_to_generic::private_variable_size (const std::string &name) const
return (*i).second;
}
+
+/* The size of private segment required by a single work-item executing
+ the currently processed kernel. */
+
size_t
brig_to_generic::private_segment_size () const
{
@@ -719,10 +817,11 @@ brig_to_generic::write_globals ()
cgraph_node::finalize_function (f->m_func_decl, true);
f->m_descriptor.is_kernel = 1;
- /* TODO: analyze the kernel's actual group and private segment usage
- using a call graph. Now the private and group mem sizes are overly
- pessimistic in case of multiple kernels in the same module. */
- f->m_descriptor.group_segment_size = group_segment_size ();
+ /* TODO: analyze the kernel's actual private and group segment usage
+ using call graph. Now the mem size is overly
+ pessimistic in case of multiple kernels in the same module.
+ */
+ f->m_descriptor.group_segment_size = m_total_group_segment_usage;
f->m_descriptor.private_segment_size = private_segment_size ();
/* The kernarg size is rounded up to a multiple of 16 according to
@@ -758,8 +857,6 @@ brig_to_generic::write_globals ()
delete[] vec;
- for (size_t i = 0; i < m_brig_blobs.size (); ++i)
- delete m_brig_blobs[i];
}
/* Returns an type with unsigned int elements corresponding to the
diff --git a/gcc/brig/brigfrontend/brig-to-generic.h b/gcc/brig/brigfrontend/brig-to-generic.h
index b94ff7c..0070894 100644
--- a/gcc/brig/brigfrontend/brig-to-generic.h
+++ b/gcc/brig/brigfrontend/brig-to-generic.h
@@ -36,7 +36,6 @@
#include "hsa-brig-format.h"
#include "brig-function.h"
-
struct reg_decl_index_entry;
/* Converts an HSAIL BRIG input to GENERIC. This class holds global state
@@ -56,6 +55,7 @@ private:
public:
brig_to_generic ();
+ void analyze (const char *brig_blob);
void parse (const char *brig_blob);
void write_globals ();
@@ -78,17 +78,9 @@ public:
void start_function (tree f);
void finish_function ();
- void append_group_variable (const std::string &name, size_t size,
- size_t alignment);
-
void append_private_variable (const std::string &name, size_t size,
size_t alignment);
- size_t group_variable_segment_offset (const std::string &name) const;
-
- bool
- has_group_variable (const std::string &name) const;
-
size_t
private_variable_segment_offset (const std::string &name) const;
@@ -107,11 +99,13 @@ public:
{ return get_mangled_name_tmpl (var); }
std::string get_mangled_name (const BrigDirectiveExecutable *func) const;
- size_t group_segment_size () const;
size_t private_segment_size () const;
brig_function *get_finished_function (tree func_decl);
+ void add_group_variable (const std::string &name, size_t size,
+ size_t alignment, bool function_scope);
+
static tree s_fp16_type;
static tree s_fp32_type;
static tree s_fp64_type;
@@ -123,10 +117,21 @@ public:
/* The currently built function. */
brig_function *m_cf;
+ /* Stores the module and function scope group variable offsets. */
+ group_variable_offset_index m_module_group_variables;
+
/* The name of the currently handled BRIG module. */
std::string m_module_name;
+ /* Set to true if the compilation is in 'analyze' phase. */
+ bool m_analyzing;
+
+ /* Accumulates the total group segment usage. */
+ size_t m_total_group_segment_usage;
+
private:
+
+ void find_brig_sections ();
/* The BRIG blob and its different sections of the file currently being
parsed. */
const char *m_brig;
@@ -144,10 +149,6 @@ private:
/* The size of each private variable, including the alignment padding. */
std::map<std::string, size_t> m_private_data_sizes;
- /* The same for group variables. */
- size_t m_next_group_offset;
- var_offset_table m_group_offsets;
-
/* And private. */
size_t m_next_private_offset;
var_offset_table m_private_offsets;
@@ -162,9 +163,6 @@ private:
for some interprocedural analysis. */
std::map<std::string, brig_function *> m_finished_functions;
- /* The parsed BRIG blobs. Owned and will be deleted after use. */
- std::vector<const char *> m_brig_blobs;
-
/* The original dump file. */
FILE *m_dump_file;
diff --git a/gcc/brig/brigfrontend/brig-util.cc b/gcc/brig/brigfrontend/brig-util.cc
index f96ae6a..a8684de 100644
--- a/gcc/brig/brigfrontend/brig-util.cc
+++ b/gcc/brig/brigfrontend/brig-util.cc
@@ -27,6 +27,34 @@ along with GCC; see the file COPYING3. If not see
#include "errors.h"
#include "diagnostic-core.h"
+bool
+group_variable_offset_index::has_variable (const std::string &name) const
+{
+ varname_offset_table::const_iterator i = m_group_offsets.find (name);
+ return i != m_group_offsets.end ();
+}
+
+/* Adds a new group segment variable. */
+
+void
+group_variable_offset_index::add (const std::string &name, size_t size,
+ size_t alignment)
+{
+ size_t align_padding = m_next_group_offset % alignment == 0 ?
+ 0 : (alignment - m_next_group_offset % alignment);
+ m_next_group_offset += align_padding;
+ m_group_offsets[name] = m_next_group_offset;
+ m_next_group_offset += size;
+}
+
+size_t
+group_variable_offset_index::segment_offset (const std::string &name) const
+{
+ varname_offset_table::const_iterator i = m_group_offsets.find (name);
+ gcc_assert (i != m_group_offsets.end ());
+ return (*i).second;
+}
+
/* Return true if operand number OPNUM of instruction with OPCODE is an output.
False if it is an input. Some code reused from Martin Jambor's gcc-hsa
tree. */
diff --git a/gcc/brig/brigfrontend/brig-util.h b/gcc/brig/brigfrontend/brig-util.h
index 3060f5b..c90ff29 100644
--- a/gcc/brig/brigfrontend/brig-util.h
+++ b/gcc/brig/brigfrontend/brig-util.h
@@ -22,7 +22,33 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_BRIG_UTIL_H
#define GCC_BRIG_UTIL_H
-#include "brig-to-generic.h"
+#include <map>
+
+#include "config.h"
+#include "system.h"
+#include "ansidecl.h"
+#include "coretypes.h"
+#include "opts.h"
+#include "tree.h"
+
+/* Helper class for keeping book of group variable offsets. */
+
+class group_variable_offset_index
+{
+public:
+ group_variable_offset_index () : m_next_group_offset (0) {}
+
+ typedef std::map<std::string, size_t> varname_offset_table;
+
+ bool has_variable (const std::string &name) const;
+ void add (const std::string &name, size_t size, size_t alignment);
+ size_t segment_offset (const std::string &name) const;
+ size_t size () const { return m_next_group_offset; }
+
+private:
+ size_t m_next_group_offset;
+ varname_offset_table m_group_offsets;
+};
bool gccbrig_hsa_opcode_op_output_p (BrigOpcode16_t opcode, int opnum);
diff --git a/gcc/brig/brigfrontend/brig-variable-handler.cc b/gcc/brig/brigfrontend/brig-variable-handler.cc
index b2e869b..cd0e981 100644
--- a/gcc/brig/brigfrontend/brig-variable-handler.cc
+++ b/gcc/brig/brigfrontend/brig-variable-handler.cc
@@ -144,10 +144,25 @@ brig_directive_variable_handler::operator () (const BrigBase *base)
size_t alignment = get_brig_var_alignment (brigVar);
- if (m_parent.m_cf != NULL)
+ bool function_scope = m_parent.m_cf != NULL;
+
+ if (function_scope)
m_parent.m_cf->m_function_scope_vars.insert (base);
std::string var_name = m_parent.get_mangled_name (brigVar);
+ if (brigVar->segment == BRIG_SEGMENT_GROUP)
+ {
+ /* Non-kernel scope group variables have been added at the
+ 'analyze' stage. */
+ m_parent.add_group_variable (var_name, var_size, alignment,
+ function_scope);
+ return base->byteCount;
+ }
+
+ /* During analyze, handle only (module scope) group variables. */
+ if (m_parent.m_analyzing)
+ return base->byteCount;
+
if (brigVar->segment == BRIG_SEGMENT_KERNARG)
{
/* Do not create a real variable, but only a table of
@@ -158,18 +173,6 @@ brig_directive_variable_handler::operator () (const BrigBase *base)
m_parent.m_cf->append_kernel_arg (brigVar, var_size, alignment);
return base->byteCount;
}
- else if (brigVar->segment == BRIG_SEGMENT_GROUP)
- {
- /* Handle group region variables similarly as kernargs:
- assign offsets to the group region on the fly when
- a new module scope or function scope group variable is
- introduced. These offsets will be then added to the
- group_base hidden pointer passed to the kernel in order to
- get the flat address. */
- if (!m_parent.has_group_variable (var_name))
- m_parent.append_group_variable (var_name, var_size, alignment);
- return base->byteCount;
- }
else if (brigVar->segment == BRIG_SEGMENT_PRIVATE
|| brigVar->segment == BRIG_SEGMENT_SPILL)
{
diff --git a/gcc/brig/brigfrontend/phsa.h b/gcc/brig/brigfrontend/phsa.h
index 2da21c8..88e87eb 100644
--- a/gcc/brig/brigfrontend/phsa.h
+++ b/gcc/brig/brigfrontend/phsa.h
@@ -61,9 +61,10 @@ typedef struct __attribute__((__packed__))
#define PHSA_DESC_SECTION_PREFIX "phsa.desc."
#define PHSA_HOST_DEF_PTR_PREFIX "__phsa.host_def."
-/* The frontend error messages are parsed by the host runtime, known
+/* The frontend error messages are parsed by the host runtime. Known
prefix strings are used to separate the different runtime error
codes. */
-#define PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE "Incompatible module:"
+#define PHSA_ERROR_PREFIX_INCOMPATIBLE_MODULE "Incompatible module: "
+#define PHSA_ERROR_PREFIX_CORRUPTED_MODULE "Corrupted module: "
#endif
diff --git a/gcc/builtins.c b/gcc/builtins.c
index c8a5ea6..29778fc 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -283,7 +283,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
exp = DECL_INITIAL (exp);
align = TYPE_ALIGN (TREE_TYPE (exp));
if (CONSTANT_CLASS_P (exp))
- align = (unsigned) CONSTANT_ALIGNMENT (exp, align);
+ align = targetm.constant_alignment (exp, align);
known_alignment = true;
}
@@ -359,7 +359,7 @@ get_object_alignment_2 (tree exp, unsigned int *alignp,
wrapped inside a CONST_DECL. */
align = TYPE_ALIGN (TREE_TYPE (exp));
if (CONSTANT_CLASS_P (exp))
- align = (unsigned) CONSTANT_ALIGNMENT (exp, align);
+ align = targetm.constant_alignment (exp, align);
known_alignment = true;
}
@@ -900,7 +900,7 @@ expand_builtin_setjmp_receiver (rtx receiver_label)
to the underlying register (fp in this case) that makes
the original assignment true.
So the following insn will actually be decrementing fp by
- STARTING_FRAME_OFFSET. */
+ TARGET_STARTING_FRAME_OFFSET. */
emit_move_insn (virtual_stack_vars_rtx, hard_frame_pointer_rtx);
/* Restoring the frame pointer also modifies the hard frame pointer.
@@ -1199,6 +1199,7 @@ void
expand_builtin_update_setjmp_buf (rtx buf_addr)
{
machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
+ buf_addr = convert_memory_address (Pmode, buf_addr);
rtx stack_save
= gen_rtx_MEM (sa_mode,
memory_address
@@ -1608,7 +1609,7 @@ expand_builtin_apply (rtx function, rtx arguments, rtx argsize)
arguments to the outgoing arguments address. We can pass TRUE
as the 4th argument because we just saved the stack pointer
and will restore it right after the call. */
- allocate_dynamic_stack_space (argsize, 0, BIGGEST_ALIGNMENT, true);
+ allocate_dynamic_stack_space (argsize, 0, BIGGEST_ALIGNMENT, -1, true);
/* Set DRAP flag to true, even though allocate_dynamic_stack_space
may have already set current_function_calls_alloca to true.
@@ -4857,19 +4858,22 @@ expand_builtin_alloca (tree exp)
rtx result;
unsigned int align;
tree fndecl = get_callee_fndecl (exp);
- bool alloca_with_align = (DECL_FUNCTION_CODE (fndecl)
- == BUILT_IN_ALLOCA_WITH_ALIGN);
+ HOST_WIDE_INT max_size;
+ enum built_in_function fcode = DECL_FUNCTION_CODE (fndecl);
bool alloca_for_var = CALL_ALLOCA_FOR_VAR_P (exp);
bool valid_arglist
- = (alloca_with_align
- ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)
- : validate_arglist (exp, INTEGER_TYPE, VOID_TYPE));
+ = (fcode == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX
+ ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, INTEGER_TYPE,
+ VOID_TYPE)
+ : fcode == BUILT_IN_ALLOCA_WITH_ALIGN
+ ? validate_arglist (exp, INTEGER_TYPE, INTEGER_TYPE, VOID_TYPE)
+ : validate_arglist (exp, INTEGER_TYPE, VOID_TYPE));
if (!valid_arglist)
return NULL_RTX;
- if ((alloca_with_align && !warn_vla_limit)
- || (!alloca_with_align && !warn_alloca_limit))
+ if ((alloca_for_var && !warn_vla_limit)
+ || (!alloca_for_var && !warn_alloca_limit))
{
/* -Walloca-larger-than and -Wvla-larger-than settings override
the more general -Walloc-size-larger-than so unless either of
@@ -4884,13 +4888,19 @@ expand_builtin_alloca (tree exp)
op0 = expand_normal (CALL_EXPR_ARG (exp, 0));
/* Compute the alignment. */
- align = (alloca_with_align
- ? TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1))
- : BIGGEST_ALIGNMENT);
+ align = (fcode == BUILT_IN_ALLOCA
+ ? BIGGEST_ALIGNMENT
+ : TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 1)));
+
+ /* Compute the maximum size. */
+ max_size = (fcode == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX
+ ? TREE_INT_CST_LOW (CALL_EXPR_ARG (exp, 2))
+ : -1);
/* Allocate the desired space. If the allocation stems from the declaration
of a variable-sized object, it cannot accumulate. */
- result = allocate_dynamic_stack_space (op0, 0, align, alloca_for_var);
+ result
+ = allocate_dynamic_stack_space (op0, 0, align, max_size, alloca_for_var);
result = convert_memory_address (ptr_mode, result);
return result;
@@ -6481,8 +6491,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
&& fcode != BUILT_IN_EXECLE
&& fcode != BUILT_IN_EXECVP
&& fcode != BUILT_IN_EXECVE
- && fcode != BUILT_IN_ALLOCA
- && fcode != BUILT_IN_ALLOCA_WITH_ALIGN
+ && !ALLOCA_FUNCTION_CODE_P (fcode)
&& fcode != BUILT_IN_FREE
&& fcode != BUILT_IN_CHKP_SET_PTR_BOUNDS
&& fcode != BUILT_IN_CHKP_INIT_PTR_BOUNDS
@@ -6711,8 +6720,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, machine_mode mode,
else
return XEXP (DECL_RTL (DECL_RESULT (current_function_decl)), 0);
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
target = expand_builtin_alloca (exp);
if (target)
return target;
@@ -10424,8 +10432,7 @@ is_inexpensive_builtin (tree decl)
switch (DECL_FUNCTION_CODE (decl))
{
case BUILT_IN_ABS:
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
case BUILT_IN_BSWAP16:
case BUILT_IN_BSWAP32:
case BUILT_IN_BSWAP64:
diff --git a/gcc/builtins.def b/gcc/builtins.def
index 1c1efce..8802594 100644
--- a/gcc/builtins.def
+++ b/gcc/builtins.def
@@ -921,6 +921,7 @@ DEF_BUILTIN_STUB (BUILT_IN_SETJMP_RECEIVER, "__builtin_setjmp_receiver")
DEF_BUILTIN_STUB (BUILT_IN_STACK_SAVE, "__builtin_stack_save")
DEF_BUILTIN_STUB (BUILT_IN_STACK_RESTORE, "__builtin_stack_restore")
DEF_BUILTIN_STUB (BUILT_IN_ALLOCA_WITH_ALIGN, "__builtin_alloca_with_align")
+DEF_BUILTIN_STUB (BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX, "__builtin_alloca_with_align_and_max")
/* An internal version of memcmp, used when the result is only tested for
equality with zero. */
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 8003fb5..552c680 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,141 @@
+2017-10-23 Marek Polacek <polacek@redhat.com>
+
+ PR c/82681
+ * c-warn.c (warnings_for_convert_and_check): Fix typos.
+
+2017-10-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * c-common.c (check_builtin_function_arguments): Also check arguments
+ of __builtin_alloca_with_align_and_max.
+
+2017-10-17 David Malcolm <dmalcolm@redhat.com>
+
+ * c-format.c (format_warning_at_char): Pass UNKNOWN_LOCATION
+ rather than NULL to format_warning_va.
+ (check_format_types): Likewise when calling format_type_warning.
+ Remove code to extract source_ranges and source_range * in favor
+ of just a location_t.
+ (format_type_warning): Convert source_range * param to a
+ location_t.
+
+2017-10-13 Jakub Jelinek <jakub@redhat.com>
+
+ * c-gimplify.c (c_gimplify_expr): Handle [LR]ROTATE_EXPR like
+ [LR]SHIFT_EXPR.
+
+2017-10-12 David Malcolm <dmalcolm@redhat.com>
+
+ * c-common.c (enum missing_token_insertion_kind): New enum.
+ (get_missing_token_insertion_kind): New function.
+ (maybe_suggest_missing_token_insertion): New function.
+ * c-common.h (maybe_suggest_missing_token_insertion): New decl.
+
+2017-10-11 Nathan Sidwell <nathan@acm.org>
+
+ * c-opts.c (add_prefixed_path): Change chain to incpath_kind.
+ (c_common_handle_option): Update incpath_kind names.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82490
+ * c-attribs.c (handle_no_sanitize_attribute): Report directly
+ Wattributes warning.
+
+2017-10-10 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * c-ada-spec.c (dump_generic_ada_node): Use wi::to_wide when
+ operating on trees as wide_ints.
+ * c-common.c (pointer_int_sum): Likewise.
+ * c-pretty-print.c (pp_c_integer_constant): Likewise.
+ * c-warn.c (match_case_to_enum_1): Likewise.
+ (c_do_switch_warnings): Likewise.
+ (maybe_warn_shift_overflow): Likewise.
+
+2017-10-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/82437
+ * c-warn.c (warn_tautological_bitwise_comparison): Use wi::to_wide
+ instead of wide_int::from.
+
+2017-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/82437
+ * c-warn.c (warn_tautological_bitwise_comparison): Instead of
+ using to_widest use wide_int with the larger of the two precisions.
+
+2017-10-05 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * c-pretty-print.c (pp_c_parameter_type_list): Print ... for variadic
+ functions.
+
+2017-10-02 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * c-warn.c (warn_tautological_bitwise_comparison): Use wi::to_widest
+ when combining the original unconverted comparison operands.
+
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ * c-attribs.c (handle_noipa_attribute): Don't add "stack_protect"
+ attribute.
+
+2017-09-29 Eric Botcazou <ebotcazou@adacore.com>
+
+ * c-ada-spec.c (to_ada_name): Add index parameter.
+ (pp_ada_tree_identifier): Likewise.
+ (dump_ada_macros): Adjust call to to_ada_name.
+ (struct overloaded_name_hash): New type.
+ (struct overloaded_name_hasher): Likewise.
+ (overloaded_names): New hash table.
+ (compute_overloading_index): New function.
+ (dump_ada_decl_name): Call it and pass the result to
+ pp_ada_tree_identifier.
+ (dump_ada_double_name): Adjust calls to pp_ada_tree_identifier.
+ (dump_ada_function_declaration): Likewise.
+ (dump_generic_ada_node): Likewise.
+ (print_constructor): Likewise.
+ (print_destructor): Likewise.
+ (dump_ada_specs): Delete overloaded_names table.
+
+2017-09-29 Eric Botcazou <ebotcazou@adacore.com>
+
+ * c-ada-spec.c (max_ada_macros): Move around.
+ (store_ada_macro_index): Likewise.
+ (source_file): Rename into...
+ (macro_source_file): ...this.
+ (count_ada_macro): Move around.
+ (store_ada_macro): Likewise.
+ (compare_macro): Likewise.
+ (print_ada_macros): Merge in...
+ (dump_ada_macros): ...this.
+ (source_file_base): Rename into...
+ (current_source_file): ...this.
+ (print_comment): Move around.
+ (dump_ada_nodes): Call dump_ada_declaration directly.
+ (struct with): Change type of limited field to bool.
+ (append_withs): Change type of limited_access parameter to bool.
+ (pp_ada_tree_identifie): Likewise.
+ (dump_ada_decl_nam): Likewise.
+ (dump_generic_ada_node): Likewise. Do not print the return type.
+ (to_ada_name): Change type of space_found parameter to bool.
+ (dump_ada_function_declaration): Return void and change type of
+ parameters to bool. Also print the return type for a function.
+ (print_ada_methods): Rename into...
+ (dump_ada_methods): ...this.
+ (print_ada_declaration): Rename into ...
+ (dump_ada_declaration): ...this. Do not print the return type.
+ (print_ada_struct_decl): Rename into...
+ (dump_ada_struct_decl): ...this.
+
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ * c-attribs.c (handle_packed_attribute): Test DECL_C_BIT_FIELD
+ rather than DECL_INITIAL.
+ (common_handle_aligned_attribute): Likewise.
+
+2017-09-20 Alexandre Oliva <aoliva@redhat.com>
+
+ * c.opt (gen-decls): Add RejectNegative.
+
2017-09-15 Andrew Sutton <andrew.n.sutton@gmail.com>
Jakub Jelinek <jakub@redhat.com>
diff --git a/gcc/c-family/c-ada-spec.c b/gcc/c-family/c-ada-spec.c
index 0cd3d55..95aacd1 100644
--- a/gcc/c-family/c-ada-spec.c
+++ b/gcc/c-family/c-ada-spec.c
@@ -32,21 +32,11 @@ along with GCC; see the file COPYING3. If not see
#include "attribs.h"
/* Local functions, macros and variables. */
-static int dump_generic_ada_node (pretty_printer *, tree, tree, int, int,
- bool);
-static int print_ada_declaration (pretty_printer *, tree, tree, int);
-static void print_ada_struct_decl (pretty_printer *, tree, tree, int, bool);
-static void dump_sloc (pretty_printer *buffer, tree node);
-static void print_comment (pretty_printer *, const char *);
-static void print_generic_ada_decl (pretty_printer *, tree, const char *);
-static char *get_ada_package (const char *);
-static void dump_ada_nodes (pretty_printer *, const char *);
-static void reset_ada_withs (void);
-static void dump_ada_withs (FILE *);
-static void dump_ads (const char *, void (*)(const char *),
- int (*)(tree, cpp_operation));
-static char *to_ada_name (const char *, int *);
-static bool separate_class_package (tree);
+static int dump_generic_ada_node (pretty_printer *, tree, tree, int, bool,
+ bool);
+static int dump_ada_declaration (pretty_printer *, tree, tree, int);
+static void dump_ada_struct_decl (pretty_printer *, tree, tree, int, bool);
+static char *to_ada_name (const char *, unsigned int, bool *);
#define INDENT(SPACE) \
do { int i; for (i = 0; i<SPACE; i++) pp_space (buffer); } while (0)
@@ -56,6 +46,10 @@ static bool separate_class_package (tree);
/* Global hook used to perform C++ queries on nodes. */
static int (*cpp_check) (tree, cpp_operation) = NULL;
+/* Global variables used in macro-related callbacks. */
+static int max_ada_macros;
+static int store_ada_macro_index;
+static const char *macro_source_file;
/* Given a cpp MACRO, compute the max length BUFFER_LEN of the macro, as well
as max length PARAM_LEN of arguments for fun_like macros, and also set
@@ -170,15 +164,77 @@ handle_escape_character (unsigned char *buffer, char c)
return buffer;
}
-/* Dump into PP a set of MAX_ADA_MACROS MACROS (C/C++) as Ada constants when
- possible. */
+/* Callback used to count the number of macros from cpp_forall_identifiers.
+ PFILE and V are not used. NODE is the current macro to consider. */
+
+static int
+count_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *node,
+ void *v ATTRIBUTE_UNUSED)
+{
+ const cpp_macro *macro = node->value.macro;
+
+ if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)
+ && macro->count
+ && *NODE_NAME (node) != '_'
+ && LOCATION_FILE (macro->line) == macro_source_file)
+ max_ada_macros++;
+
+ return 1;
+}
+
+/* Callback used to store relevant macros from cpp_forall_identifiers.
+ PFILE is not used. NODE is the current macro to store if relevant.
+ MACROS is an array of cpp_hashnode* used to store NODE. */
+
+static int
+store_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED,
+ cpp_hashnode *node, void *macros)
+{
+ const cpp_macro *macro = node->value.macro;
+
+ if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)
+ && macro->count
+ && *NODE_NAME (node) != '_'
+ && LOCATION_FILE (macro->line) == macro_source_file)
+ ((cpp_hashnode **) macros)[store_ada_macro_index++] = node;
+
+ return 1;
+}
+
+/* Callback used to compare (during qsort) macros. NODE1 and NODE2 are the
+ two macro nodes to compare. */
+
+static int
+compare_macro (const void *node1, const void *node2)
+{
+ typedef const cpp_hashnode *const_hnode;
+
+ const_hnode n1 = *(const const_hnode *) node1;
+ const_hnode n2 = *(const const_hnode *) node2;
+
+ return n1->value.macro->line - n2->value.macro->line;
+}
+
+/* Dump in PP all relevant macros appearing in FILE. */
static void
-print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros)
+dump_ada_macros (pretty_printer *pp, const char* file)
{
- int j, num_macros = 0, prev_line = -1;
+ int num_macros = 0, prev_line = -1;
+ cpp_hashnode **macros;
- for (j = 0; j < max_ada_macros; j++)
+ /* Initialize file-scope variables. */
+ max_ada_macros = 0;
+ store_ada_macro_index = 0;
+ macro_source_file = file;
+
+ /* Count all potentially relevant macros, and then sort them by sloc. */
+ cpp_forall_identifiers (parse_in, count_ada_macro, NULL);
+ macros = XALLOCAVEC (cpp_hashnode *, max_ada_macros);
+ cpp_forall_identifiers (parse_in, store_ada_macro, macros);
+ qsort (macros, max_ada_macros, sizeof (cpp_hashnode *), compare_macro);
+
+ for (int j = 0; j < max_ada_macros; j++)
{
cpp_hashnode *node = macros[j];
const cpp_macro *macro = node->value.macro;
@@ -521,7 +577,7 @@ print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros)
prev_line = sloc.line;
pp_string (pp, " ");
- ada_name = to_ada_name ((const char *) NODE_NAME (node), NULL);
+ ada_name = to_ada_name ((const char *) NODE_NAME (node), 0, NULL);
pp_string (pp, ada_name);
free (ada_name);
pp_string (pp, " : ");
@@ -557,87 +613,8 @@ print_ada_macros (pretty_printer *pp, cpp_hashnode **macros, int max_ada_macros)
pp_newline (pp);
}
-static const char *source_file;
-static int max_ada_macros;
-
-/* Callback used to count the number of relevant macros from
- cpp_forall_identifiers. PFILE and V are not used. NODE is the current macro
- to consider. */
-
-static int
-count_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED, cpp_hashnode *node,
- void *v ATTRIBUTE_UNUSED)
-{
- const cpp_macro *macro = node->value.macro;
-
- if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)
- && macro->count
- && *NODE_NAME (node) != '_'
- && LOCATION_FILE (macro->line) == source_file)
- max_ada_macros++;
-
- return 1;
-}
-
-static int store_ada_macro_index;
-
-/* Callback used to store relevant macros from cpp_forall_identifiers.
- PFILE is not used. NODE is the current macro to store if relevant.
- MACROS is an array of cpp_hashnode* used to store NODE. */
-
-static int
-store_ada_macro (cpp_reader *pfile ATTRIBUTE_UNUSED,
- cpp_hashnode *node, void *macros)
-{
- const cpp_macro *macro = node->value.macro;
-
- if (node->type == NT_MACRO && !(node->flags & NODE_BUILTIN)
- && macro->count
- && *NODE_NAME (node) != '_'
- && LOCATION_FILE (macro->line) == source_file)
- ((cpp_hashnode **) macros)[store_ada_macro_index++] = node;
-
- return 1;
-}
-
-/* Callback used to compare (during qsort) macros. NODE1 and NODE2 are the
- two macro nodes to compare. */
-
-static int
-compare_macro (const void *node1, const void *node2)
-{
- typedef const cpp_hashnode *const_hnode;
-
- const_hnode n1 = *(const const_hnode *) node1;
- const_hnode n2 = *(const const_hnode *) node2;
-
- return n1->value.macro->line - n2->value.macro->line;
-}
-
-/* Dump in PP all relevant macros appearing in FILE. */
-
-static void
-dump_ada_macros (pretty_printer *pp, const char* file)
-{
- cpp_hashnode **macros;
-
- /* Initialize file-scope variables. */
- max_ada_macros = 0;
- store_ada_macro_index = 0;
- source_file = file;
-
- /* Count all potentially relevant macros, and then sort them by sloc. */
- cpp_forall_identifiers (parse_in, count_ada_macro, NULL);
- macros = XALLOCAVEC (cpp_hashnode *, max_ada_macros);
- cpp_forall_identifiers (parse_in, store_ada_macro, macros);
- qsort (macros, max_ada_macros, sizeof (cpp_hashnode *), compare_macro);
-
- print_ada_macros (pp, macros, max_ada_macros);
-}
-
/* Current source file being handled. */
-
-static const char *source_file_base;
+static const char *current_source_file;
/* Return sloc of DECL, using sloc of last field if LAST is true. */
@@ -751,6 +728,42 @@ unmark_visited_r (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED,
return NULL_TREE;
}
+/* Print a COMMENT to the output stream PP. */
+
+static void
+print_comment (pretty_printer *pp, const char *comment)
+{
+ int len = strlen (comment);
+ char *str = XALLOCAVEC (char, len + 1);
+ char *tok;
+ bool extra_newline = false;
+
+ memcpy (str, comment, len + 1);
+
+ /* Trim C/C++ comment indicators. */
+ if (str[len - 2] == '*' && str[len - 1] == '/')
+ {
+ str[len - 2] = ' ';
+ str[len - 1] = '\0';
+ }
+ str += 2;
+
+ tok = strtok (str, "\n");
+ while (tok) {
+ pp_string (pp, " --");
+ pp_string (pp, tok);
+ pp_newline (pp);
+ tok = strtok (NULL, "\n");
+
+ /* Leave a blank line after multi-line comments. */
+ if (tok)
+ extra_newline = true;
+ }
+
+ if (extra_newline)
+ pp_newline (pp);
+}
+
/* Dump nodes into PP relevant to SOURCE_FILE, as collected by previous calls
to collect_ada_nodes. */
@@ -792,7 +805,16 @@ dump_ada_nodes (pretty_printer *pp, const char *source_file)
if (j == comments->count
|| LOCATION_LINE (decl_sloc (to_dump[i], false))
< LOCATION_LINE (comments->entries[j].sloc))
- print_generic_ada_decl (pp, to_dump[i++], source_file);
+ {
+ current_source_file = source_file;
+
+ if (dump_ada_declaration (pp, to_dump[i++], NULL_TREE,
+ INDENT_INCR))
+ {
+ pp_newline (pp);
+ pp_newline (pp);
+ }
+ }
else
break;
}
@@ -816,57 +838,6 @@ dump_ada_nodes (pretty_printer *pp, const char *source_file)
}
}
-/* Print a COMMENT to the output stream PP. */
-
-static void
-print_comment (pretty_printer *pp, const char *comment)
-{
- int len = strlen (comment);
- char *str = XALLOCAVEC (char, len + 1);
- char *tok;
- bool extra_newline = false;
-
- memcpy (str, comment, len + 1);
-
- /* Trim C/C++ comment indicators. */
- if (str[len - 2] == '*' && str[len - 1] == '/')
- {
- str[len - 2] = ' ';
- str[len - 1] = '\0';
- }
- str += 2;
-
- tok = strtok (str, "\n");
- while (tok) {
- pp_string (pp, " --");
- pp_string (pp, tok);
- pp_newline (pp);
- tok = strtok (NULL, "\n");
-
- /* Leave a blank line after multi-line comments. */
- if (tok)
- extra_newline = true;
- }
-
- if (extra_newline)
- pp_newline (pp);
-}
-
-/* Print declaration DECL to PP in Ada syntax. The current source file being
- handled is SOURCE_FILE. */
-
-static void
-print_generic_ada_decl (pretty_printer *pp, tree decl, const char *source_file)
-{
- source_file_base = source_file;
-
- if (print_ada_declaration (pp, decl, NULL_TREE, INDENT_INCR))
- {
- pp_newline (pp);
- pp_newline (pp);
- }
-}
-
/* Dump a newline and indent BUFFER by SPC chars. */
static void
@@ -876,7 +847,7 @@ newline_and_indent (pretty_printer *buffer, int spc)
INDENT (spc);
}
-struct with { char *s; const char *in_file; int limited; };
+struct with { char *s; const char *in_file; bool limited; };
static struct with *withs = NULL;
static int withs_max = 4096;
static int with_len = 0;
@@ -885,7 +856,7 @@ static int with_len = 0;
true), if not already done. */
static void
-append_withs (const char *s, int limited_access)
+append_withs (const char *s, bool limited_access)
{
int i;
@@ -900,14 +871,14 @@ append_withs (const char *s, int limited_access)
for (i = 0; i < with_len; i++)
if (!strcmp (s, withs[i].s)
- && source_file_base == withs[i].in_file)
+ && current_source_file == withs[i].in_file)
{
withs[i].limited &= limited_access;
return;
}
withs[with_len].s = xstrdup (s);
- withs[with_len].in_file = source_file_base;
+ withs[with_len].in_file = current_source_file;
withs[with_len].limited = limited_access;
with_len++;
}
@@ -1107,24 +1078,26 @@ has_nontrivial_methods (tree type)
return false;
}
-/* Generate a legal Ada name from a C NAME, returning a malloc'd string.
- SPACE_FOUND, if not NULL, is used to indicate whether a space was found in
- NAME. */
+#define INDEX_LENGTH 8
+
+/* Generate a legal Ada name from a C/C++ NAME and return a malloc'ed string.
+ INDEX, if non-zero, is used to disambiguate overloaded names. SPACE_FOUND,
+ if not NULL, is used to indicate whether a space was found in NAME. */
static char *
-to_ada_name (const char *name, int *space_found)
+to_ada_name (const char *name, unsigned int index, bool *space_found)
{
const char **names;
- int len = strlen (name);
+ const int len = strlen (name);
int j, len2 = 0;
- int found = false;
- char *s = XNEWVEC (char, len * 2 + 5);
+ bool found = false;
+ char *s = XNEWVEC (char, len * 2 + 5 + (index ? INDEX_LENGTH : 0));
char c;
if (space_found)
*space_found = false;
- /* Add trailing "c_" if name is an Ada reserved word. */
+ /* Add "c_" prefix if name is an Ada reserved word. */
for (names = ada_reserved; *names; names++)
if (!strcasecmp (name, *names))
{
@@ -1135,7 +1108,7 @@ to_ada_name (const char *name, int *space_found)
}
if (!found)
- /* Add trailing "c_" if name is an potential case sensitive duplicate. */
+ /* Add "c_" prefix if name is a potential case sensitive duplicate. */
for (names = c_duplicates; *names; names++)
if (!strcmp (name, *names))
{
@@ -1161,7 +1134,6 @@ to_ada_name (const char *name, int *space_found)
}
/* Replace unsuitable characters for Ada identifiers. */
-
for (; j < len; j++)
switch (name[j])
{
@@ -1317,7 +1289,10 @@ to_ada_name (const char *name, int *space_found)
if (s[len2 - 1] == '_')
s[len2++] = 'u';
- s[len2] = '\0';
+ if (index)
+ snprintf (&s[len2], INDEX_LENGTH, "_u_%d", index + 1);
+ else
+ s[len2] = '\0';
return s;
}
@@ -1335,29 +1310,27 @@ separate_class_package (tree decl)
static bool package_prefix = true;
/* Dump in BUFFER the name of an identifier NODE of type TYPE, following Ada
- syntax. LIMITED_ACCESS indicates whether NODE can be accessed via a limited
+ syntax. INDEX, if non-zero, is used to disambiguate overloaded names.
+ LIMITED_ACCESS indicates whether NODE can be accessed via a limited
'with' clause rather than a regular 'with' clause. */
static void
pp_ada_tree_identifier (pretty_printer *buffer, tree node, tree type,
- int limited_access)
+ unsigned int index, bool limited_access)
{
const char *name = IDENTIFIER_POINTER (node);
- int space_found = false;
- char *s = to_ada_name (name, &space_found);
- tree decl;
-
- /* If the entity is a type and comes from another file, generate "package"
- prefix. */
- decl = get_underlying_decl (type);
+ bool space_found = false;
+ char *s = to_ada_name (name, index, &space_found);
+ tree decl = get_underlying_decl (type);
+ /* If the entity comes from another file, generate a package prefix. */
if (decl)
{
expanded_location xloc = expand_location (decl_sloc (decl, false));
if (xloc.file && xloc.line)
{
- if (xloc.file != source_file_base)
+ if (xloc.file != current_source_file)
{
switch (TREE_CODE (type))
{
@@ -1459,15 +1432,86 @@ pp_asm_name (pretty_printer *buffer, tree t)
pp_string (buffer, ada_name);
}
+/* Hash table of overloaded names associating identifier nodes with DECL_UIDs.
+ It is needed in Ada 2005 because we can have at most one import directive
+ per subprogram name in a given scope, so we have to mangle the subprogram
+ names on the Ada side to import overloaded subprograms from C++. */
+
+struct overloaded_name_hash {
+ hashval_t hash;
+ tree name;
+ tree context;
+ vec<unsigned int> homonyms;
+};
+
+struct overloaded_name_hasher : delete_ptr_hash<overloaded_name_hash>
+{
+ static inline hashval_t hash (overloaded_name_hash *t)
+ { return t->hash; }
+ static inline bool equal (overloaded_name_hash *a, overloaded_name_hash *b)
+ { return a->name == b->name && a->context == b->context; }
+};
+
+static hash_table<overloaded_name_hasher> *overloaded_names;
+
+/* Compute the overloading index of function DECL in its context. */
+
+static unsigned int
+compute_overloading_index (tree decl)
+{
+ const hashval_t hashcode
+ = iterative_hash_hashval_t (htab_hash_pointer (DECL_NAME (decl)),
+ htab_hash_pointer (DECL_CONTEXT (decl)));
+ struct overloaded_name_hash in, *h, **slot;
+ unsigned int index, *iter;
+
+ if (!overloaded_names)
+ overloaded_names = new hash_table<overloaded_name_hasher> (512);
+
+ /* Look up the list of homonyms in the table. */
+ in.hash = hashcode;
+ in.name = DECL_NAME (decl);
+ in.context = DECL_CONTEXT (decl);
+ slot = overloaded_names->find_slot_with_hash (&in, hashcode, INSERT);
+ if (*slot)
+ h = *slot;
+ else
+ {
+ h = new overloaded_name_hash;
+ h->hash = hashcode;
+ h->name = DECL_NAME (decl);
+ h->context = DECL_CONTEXT (decl);
+ h->homonyms.create (0);
+ *slot = h;
+ }
+
+ /* Look up the function in the list of homonyms. */
+ FOR_EACH_VEC_ELT (h->homonyms, index, iter)
+ if (*iter == DECL_UID (decl))
+ break;
+
+ /* If it is not present, push it onto the list. */
+ if (!iter)
+ h->homonyms.safe_push (DECL_UID (decl));
+
+ return index;
+}
+
/* Dump in BUFFER the name of a DECL node if set, following Ada syntax.
LIMITED_ACCESS indicates whether NODE can be accessed via a limited
'with' clause rather than a regular 'with' clause. */
static void
-dump_ada_decl_name (pretty_printer *buffer, tree decl, int limited_access)
+dump_ada_decl_name (pretty_printer *buffer, tree decl, bool limited_access)
{
if (DECL_NAME (decl))
- pp_ada_tree_identifier (buffer, DECL_NAME (decl), decl, limited_access);
+ {
+ const unsigned int index
+ = (TREE_CODE (decl) == FUNCTION_DECL && cpp_check)
+ ? compute_overloading_index (decl) : 0;
+ pp_ada_tree_identifier (buffer, DECL_NAME (decl), decl, index,
+ limited_access);
+ }
else
{
tree type_name = TYPE_NAME (TREE_TYPE (decl));
@@ -1481,7 +1525,7 @@ dump_ada_decl_name (pretty_printer *buffer, tree decl, int limited_access)
pp_scalar (buffer, "%d", TYPE_UID (TREE_TYPE (decl)));
}
else if (TREE_CODE (type_name) == IDENTIFIER_NODE)
- pp_ada_tree_identifier (buffer, type_name, decl, limited_access);
+ pp_ada_tree_identifier (buffer, type_name, decl, 0, limited_access);
}
}
@@ -1491,7 +1535,7 @@ static void
dump_ada_double_name (pretty_printer *buffer, tree t1, tree t2)
{
if (DECL_NAME (t1))
- pp_ada_tree_identifier (buffer, DECL_NAME (t1), t1, false);
+ pp_ada_tree_identifier (buffer, DECL_NAME (t1), t1, 0, false);
else
{
pp_string (buffer, "anon");
@@ -1501,7 +1545,7 @@ dump_ada_double_name (pretty_printer *buffer, tree t1, tree t2)
pp_underscore (buffer);
if (DECL_NAME (t2))
- pp_ada_tree_identifier (buffer, DECL_NAME (t2), t2, false);
+ pp_ada_tree_identifier (buffer, DECL_NAME (t2), t2, 0, false);
else
{
pp_string (buffer, "anon");
@@ -1586,10 +1630,10 @@ check_name (pretty_printer *buffer, tree t)
IS_DESTRUCTOR whether FUNC is a C++ destructor.
SPC is the current indentation level. */
-static int
+static void
dump_ada_function_declaration (pretty_printer *buffer, tree func,
- int is_method, int is_constructor,
- int is_destructor, int spc)
+ bool is_method, bool is_constructor,
+ bool is_destructor, int spc)
{
tree arg;
const tree node = TREE_TYPE (func);
@@ -1655,7 +1699,7 @@ dump_ada_function_declaration (pretty_printer *buffer, tree func,
if (DECL_NAME (arg))
{
check_name (buffer, arg);
- pp_ada_tree_identifier (buffer, DECL_NAME (arg), NULL_TREE,
+ pp_ada_tree_identifier (buffer, DECL_NAME (arg), NULL_TREE, 0,
false);
pp_string (buffer, " : ");
}
@@ -1708,7 +1752,13 @@ dump_ada_function_declaration (pretty_printer *buffer, tree func,
if (num_args > 0)
pp_right_paren (buffer);
- return num_args;
+
+ if (is_constructor || !VOID_TYPE_P (TREE_TYPE (node)))
+ {
+ pp_string (buffer, " return ");
+ tree type = is_constructor ? DECL_CONTEXT (func) : TREE_TYPE (node);
+ dump_generic_ada_node (buffer, type, type, spc, false, true);
+ }
}
/* Dump in BUFFER all the domains associated with an array NODE,
@@ -1973,7 +2023,7 @@ static bool bitfield_used = false;
static int
dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
- int limited_access, bool name_only)
+ bool limited_access, bool name_only)
{
if (node == NULL_TREE)
return 0;
@@ -1985,7 +2035,7 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
return 0;
case IDENTIFIER_NODE:
- pp_ada_tree_identifier (buffer, node, type, limited_access);
+ pp_ada_tree_identifier (buffer, node, type, 0, limited_access);
break;
case TREE_LIST:
@@ -2042,8 +2092,8 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
newline_and_indent (buffer, spc);
}
- pp_ada_tree_identifier
- (buffer, TREE_PURPOSE (value), node, false);
+ pp_ada_tree_identifier (buffer, TREE_PURPOSE (value), node,
+ 0, false);
}
pp_string (buffer, ");");
spc -= INDENT_INCR;
@@ -2065,8 +2115,8 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
pp_semicolon (buffer);
newline_and_indent (buffer, spc);
- pp_ada_tree_identifier
- (buffer, TREE_PURPOSE (value), node, false);
+ pp_ada_tree_identifier (buffer, TREE_PURPOSE (value), node,
+ 0, false);
pp_string (buffer, " : constant ");
dump_generic_ada_node
@@ -2096,8 +2146,8 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
if (tclass == tcc_declaration)
{
if (DECL_NAME (node))
- pp_ada_tree_identifier
- (buffer, DECL_NAME (node), NULL_TREE, limited_access);
+ pp_ada_tree_identifier (buffer, DECL_NAME (node), NULL_TREE, 0,
+ limited_access);
else
pp_string (buffer, "<unnamed type decl>");
}
@@ -2106,8 +2156,8 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
if (TYPE_NAME (node))
{
if (TREE_CODE (TYPE_NAME (node)) == IDENTIFIER_NODE)
- pp_ada_tree_identifier (buffer, TYPE_NAME (node),
- node, limited_access);
+ pp_ada_tree_identifier (buffer, TYPE_NAME (node), node, 0,
+ limited_access);
else if (TREE_CODE (TYPE_NAME (node)) == TYPE_DECL
&& DECL_NAME (TYPE_NAME (node)))
dump_ada_decl_name (buffer, TYPE_NAME (node), limited_access);
@@ -2143,41 +2193,24 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
else if (TREE_CODE (TREE_TYPE (node)) == FUNCTION_TYPE)
{
- tree fnode = TREE_TYPE (node);
- bool is_function;
-
- if (VOID_TYPE_P (TREE_TYPE (fnode)))
- {
- is_function = false;
- pp_string (buffer, "access procedure");
- }
+ if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (node))))
+ pp_string (buffer, "access procedure ");
else
- {
- is_function = true;
- pp_string (buffer, "access function");
- }
+ pp_string (buffer, "access function ");
dump_ada_function_declaration
(buffer, node, false, false, false, spc + INDENT_INCR);
- if (is_function)
+ /* If we are dumping the full type, it means we are part of a
+ type definition and need also a Convention C pragma. */
+ if (!name_only)
{
- pp_string (buffer, " return ");
- dump_generic_ada_node
- (buffer, TREE_TYPE (fnode), type, spc, 0, true);
+ pp_semicolon (buffer);
+ newline_and_indent (buffer, spc);
+ pp_string (buffer, "pragma Convention (C, ");
+ dump_generic_ada_node (buffer, type, 0, spc, false, true);
+ pp_right_paren (buffer);
}
-
- /* If we are dumping the full type, it means we are part of a
- type definition and need also a Convention C pragma. */
- if (!name_only)
- {
- pp_semicolon (buffer);
- newline_and_indent (buffer, spc);
- pp_string (buffer, "pragma Convention (C, ");
- dump_generic_ada_node
- (buffer, type, 0, spc, false, true);
- pp_right_paren (buffer);
- }
}
else
{
@@ -2229,7 +2262,7 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
|| !decl
|| (!enclosing_decl
&& !TREE_VISITED (decl)
- && DECL_SOURCE_FILE (decl) == source_file_base)
+ && DECL_SOURCE_FILE (decl) == current_source_file)
|| (enclosing_decl
&& !TREE_VISITED (decl)
&& DECL_SOURCE_FILE (decl)
@@ -2314,7 +2347,7 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
}
}
else
- print_ada_struct_decl (buffer, node, type, spc, true);
+ dump_ada_struct_decl (buffer, node, type, spc, true);
break;
case INTEGER_CST:
@@ -2329,7 +2362,7 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
pp_unsigned_wide_integer (buffer, tree_to_uhwi (node));
else
{
- wide_int val = node;
+ wide_int val = wi::to_wide (node);
int i;
if (wi::neg_p (val))
{
@@ -2353,11 +2386,6 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
case VECTOR_CST:
return 0;
- case FUNCTION_DECL:
- case CONST_DECL:
- dump_ada_decl_name (buffer, node, limited_access);
- break;
-
case TYPE_DECL:
if (DECL_IS_BUILTIN (node))
{
@@ -2416,6 +2444,8 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
}
break;
+ case FUNCTION_DECL:
+ case CONST_DECL:
case VAR_DECL:
case PARM_DECL:
case FIELD_DECL:
@@ -2435,7 +2465,7 @@ dump_generic_ada_node (pretty_printer *buffer, tree node, tree type, int spc,
methods were printed, 0 otherwise. */
static int
-print_ada_methods (pretty_printer *buffer, tree node, int spc)
+dump_ada_methods (pretty_printer *buffer, tree node, int spc)
{
if (!has_nontrivial_methods (node))
return 0;
@@ -2451,8 +2481,8 @@ print_ada_methods (pretty_printer *buffer, tree node, int spc)
pp_newline (buffer);
pp_newline (buffer);
}
-
- res = print_ada_declaration (buffer, fld, node, spc);
+
+ res = dump_ada_declaration (buffer, fld, node, spc);
}
return 1;
@@ -2597,7 +2627,7 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
if (TREE_CODE (field_type) == UNION_TYPE)
pp_string (buffer, " (discr : unsigned := 0)");
pp_string (buffer, " is ");
- print_ada_struct_decl (buffer, field_type, t, spc, false);
+ dump_ada_struct_decl (buffer, field_type, t, spc, false);
pp_string (buffer, "pragma Convention (C_Pass_By_Copy, ");
dump_generic_ada_node (buffer, field_type, 0, spc, false, true);
@@ -2617,7 +2647,7 @@ dump_nested_type (pretty_printer *buffer, tree field, tree t, tree parent,
if (TREE_CODE (field_type) == UNION_TYPE)
pp_string (buffer, " (discr : unsigned := 0)");
pp_string (buffer, " is ");
- print_ada_struct_decl (buffer, field_type, t, spc, false);
+ dump_ada_struct_decl (buffer, field_type, t, spc, false);
pp_string (buffer, "pragma Convention (C_Pass_By_Copy, ");
dump_ada_double_name (buffer, parent, field);
@@ -2645,7 +2675,7 @@ print_constructor (pretty_printer *buffer, tree t, tree type)
tree decl_name = DECL_NAME (TYPE_NAME (type));
pp_string (buffer, "New_");
- pp_ada_tree_identifier (buffer, decl_name, t, false);
+ pp_ada_tree_identifier (buffer, decl_name, t, 0, false);
}
/* Dump in BUFFER destructor spec corresponding to T. */
@@ -2656,7 +2686,7 @@ print_destructor (pretty_printer *buffer, tree t, tree type)
tree decl_name = DECL_NAME (TYPE_NAME (type));
pp_string (buffer, "Delete_");
- pp_ada_tree_identifier (buffer, decl_name, t, false);
+ pp_ada_tree_identifier (buffer, decl_name, t, 0, false);
}
/* Return the name of type T. */
@@ -2672,12 +2702,12 @@ type_name (tree t)
return IDENTIFIER_POINTER (DECL_NAME (n));
}
-/* Print in BUFFER the declaration of a variable T of type TYPE in Ada syntax.
+/* Dump in BUFFER the declaration of a variable T of type TYPE in Ada syntax.
SPC is the indentation level. Return 1 if a declaration was printed,
0 otherwise. */
static int
-print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
+dump_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
{
int is_var = 0, need_indent = 0;
int is_class = false;
@@ -2722,7 +2752,7 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
else
{
if (RECORD_OR_UNION_TYPE_P (typ)
- && DECL_SOURCE_FILE (stub) == source_file_base)
+ && DECL_SOURCE_FILE (stub) == current_source_file)
dump_nested_types (buffer, stub, stub, true, spc);
pp_string (buffer, "subtype ");
@@ -2876,7 +2906,7 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
}
else if (TREE_CODE (t) == FUNCTION_DECL)
{
- bool is_function, is_abstract_class = false;
+ bool is_abstract_class = false;
bool is_method = TREE_CODE (TREE_TYPE (t)) == METHOD_TYPE;
tree decl_name = DECL_NAME (t);
bool is_abstract = false;
@@ -2927,15 +2957,9 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
INDENT (spc);
if (VOID_TYPE_P (TREE_TYPE (TREE_TYPE (t))) && !is_constructor)
- {
- pp_string (buffer, "procedure ");
- is_function = false;
- }
+ pp_string (buffer, "procedure ");
else
- {
- pp_string (buffer, "function ");
- is_function = true;
- }
+ pp_string (buffer, "function ");
if (is_constructor)
print_constructor (buffer, t, type);
@@ -2947,14 +2971,6 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
dump_ada_function_declaration
(buffer, t, is_method, is_constructor, is_destructor, spc);
- if (is_function)
- {
- pp_string (buffer, " return ");
- tree ret_type
- = is_constructor ? DECL_CONTEXT (t) : TREE_TYPE (TREE_TYPE (t));
- dump_generic_ada_node (buffer, ret_type, type, spc, false, true);
- }
-
if (is_constructor && RECORD_OR_UNION_TYPE_P (type))
for (tree fld = TYPE_FIELDS (type); fld; fld = DECL_CHAIN (fld))
if (TREE_CODE (fld) == FUNCTION_DECL && cpp_check (fld, IS_ABSTRACT))
@@ -2992,9 +3008,7 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
pp_string (buffer, "\");");
}
else
- {
- dump_ada_import (buffer, t);
- }
+ dump_ada_import (buffer, t);
return 1;
}
@@ -3059,7 +3073,7 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
(buffer, TYPE_NAME (TREE_TYPE (t)), type, spc, false, true);
pp_right_paren (buffer);
- print_ada_methods (buffer, TREE_TYPE (t), spc);
+ dump_ada_methods (buffer, TREE_TYPE (t), spc);
}
else
{
@@ -3156,12 +3170,12 @@ print_ada_declaration (pretty_printer *buffer, tree t, tree type, int spc)
return 1;
}
-/* Prints in BUFFER a structure NODE of type TYPE: name, fields, and methods
+/* Dump in BUFFER a structure NODE of type TYPE: name, fields, and methods
with Ada syntax. SPC is the indentation level. If DISPLAY_CONVENTION is
true, also print the pragma Convention for NODE. */
static void
-print_ada_struct_decl (pretty_printer *buffer, tree node, tree type, int spc,
+dump_ada_struct_decl (pretty_printer *buffer, tree node, tree type, int spc,
bool display_convention)
{
tree tmp;
@@ -3196,7 +3210,7 @@ print_ada_struct_decl (pretty_printer *buffer, tree node, tree type, int spc,
if (!is_tagged_type (TREE_TYPE (tmp)))
{
if (!TYPE_NAME (TREE_TYPE (tmp)))
- print_ada_declaration (buffer, tmp, type, field_spc);
+ dump_ada_declaration (buffer, tmp, type, field_spc);
else
{
INDENT (field_spc);
@@ -3235,7 +3249,7 @@ print_ada_struct_decl (pretty_printer *buffer, tree node, tree type, int spc,
pp_newline (buffer);
}
- if (print_ada_declaration (buffer, tmp, type, field_spc))
+ if (dump_ada_declaration (buffer, tmp, type, field_spc))
{
pp_newline (buffer);
field_num++;
@@ -3305,7 +3319,7 @@ print_ada_struct_decl (pretty_printer *buffer, tree node, tree type, int spc,
bitfield_used = false;
}
- need_semicolon = !print_ada_methods (buffer, node, spc);
+ need_semicolon = !dump_ada_methods (buffer, node, spc);
/* Print the static fields of the structure, if any. */
for (tmp = TYPE_FIELDS (node); tmp; tmp = TREE_CHAIN (tmp))
@@ -3319,7 +3333,7 @@ print_ada_struct_decl (pretty_printer *buffer, tree node, tree type, int spc,
}
pp_newline (buffer);
pp_newline (buffer);
- print_ada_declaration (buffer, tmp, type, spc);
+ dump_ada_declaration (buffer, tmp, type, spc);
}
}
}
@@ -3434,12 +3448,11 @@ void
dump_ada_specs (void (*collect_all_refs)(const char *),
int (*check)(tree, cpp_operation))
{
- int i;
-
- /* Iterate over the list of files to dump specs for */
- for (i = 0; i < source_refs_used; i++)
+ /* Iterate over the list of files to dump specs for. */
+ for (int i = 0; i < source_refs_used; i++)
dump_ads (source_refs[i], collect_all_refs, check);
- /* Free files table. */
+ /* Free various tables. */
free (source_refs);
+ delete overloaded_names;
}
diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 0337537..bb75cba 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -65,6 +65,7 @@ static tree handle_asan_odr_indicator_attribute (tree *, tree, tree, int,
static tree handle_stack_protect_attribute (tree *, tree, tree, int, bool *);
static tree handle_noinline_attribute (tree *, tree, tree, int, bool *);
static tree handle_noclone_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nocf_check_attribute (tree *, tree, tree, int, bool *);
static tree handle_noicf_attribute (tree *, tree, tree, int, bool *);
static tree handle_noipa_attribute (tree *, tree, tree, int, bool *);
static tree handle_leaf_attribute (tree *, tree, tree, int, bool *);
@@ -367,6 +368,8 @@ const struct attribute_spec c_common_attribute_table[] =
{ "patchable_function_entry", 1, 2, true, false, false,
handle_patchable_function_entry_attribute,
false },
+ { "nocf_check", 0, 0, false, true, true,
+ handle_nocf_check_attribute, true },
{ NULL, 0, 0, false, false, false, NULL, false }
};
@@ -426,7 +429,7 @@ handle_packed_attribute (tree *node, tree name, tree ARG_UNUSED (args),
{
if (TYPE_ALIGN (TREE_TYPE (*node)) <= BITS_PER_UNIT
/* Still pack bitfields. */
- && ! DECL_INITIAL (*node))
+ && ! DECL_C_BIT_FIELD (*node))
warning (OPT_Wattributes,
"%qE attribute ignored for field of type %qT",
name, TREE_TYPE (*node));
@@ -613,15 +616,8 @@ handle_no_sanitize_attribute (tree *node, tree name, tree args, int,
return NULL_TREE;
}
- char *error_value = NULL;
char *string = ASTRDUP (TREE_STRING_POINTER (id));
- unsigned int flags = parse_no_sanitize_attribute (string, &error_value);
-
- if (error_value)
- {
- error ("wrong argument: \"%s\"", error_value);
- return NULL_TREE;
- }
+ unsigned int flags = parse_no_sanitize_attribute (string);
add_no_sanitize_value (*node, flags);
@@ -730,10 +726,6 @@ handle_noipa_attribute (tree *node, tree name, tree, int, bool *no_add_attrs)
warning (OPT_Wattributes, "%qE attribute ignored", name);
*no_add_attrs = true;
}
- else
- DECL_ATTRIBUTES (*node)
- = tree_cons (get_identifier ("stack_protect"),
- NULL_TREE, DECL_ATTRIBUTES (*node));
return NULL_TREE;
}
@@ -783,6 +775,30 @@ handle_noclone_attribute (tree *node, tree name,
return NULL_TREE;
}
+/* Handle a "nocf_check" attribute; arguments as in
+ struct attribute_spec.handler. */
+
+static tree
+handle_nocf_check_attribute (tree *node, tree name,
+ tree ARG_UNUSED (args),
+ int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+ if (TREE_CODE (*node) != FUNCTION_TYPE
+ && TREE_CODE (*node) != METHOD_TYPE)
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored", name);
+ *no_add_attrs = true;
+ }
+ else if (!(flag_cf_protection & CF_BRANCH))
+ {
+ warning (OPT_Wattributes, "%qE attribute ignored. Use "
+ "-fcf-protection option to enable it", name);
+ *no_add_attrs = true;
+ }
+
+ return NULL_TREE;
+}
+
/* Handle a "no_icf" attribute; arguments as in
struct attribute_spec.handler. */
@@ -1773,7 +1789,7 @@ common_handle_aligned_attribute (tree *node, tree args, int flags,
{
if (warn_if_not_aligned_p)
{
- if (TREE_CODE (decl) == FIELD_DECL && !DECL_INITIAL (decl))
+ if (TREE_CODE (decl) == FIELD_DECL && !DECL_C_BIT_FIELD (decl))
{
SET_DECL_WARN_IF_NOT_ALIGN (decl, (1U << i) * BITS_PER_UNIT);
warn_if_not_aligned_p = false;
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index b3ec3a0..8f36c77 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -3158,7 +3158,7 @@ pointer_int_sum (location_t loc, enum tree_code resultcode,
convert (TREE_TYPE (intop), size_exp));
intop = convert (sizetype, t);
if (TREE_OVERFLOW_P (intop) && !TREE_OVERFLOW (t))
- intop = wide_int_to_tree (TREE_TYPE (intop), intop);
+ intop = wide_int_to_tree (TREE_TYPE (intop), wi::to_wide (intop));
}
/* Create the sum or difference. */
@@ -5695,6 +5695,16 @@ check_builtin_function_arguments (location_t loc, vec<location_t> arg_loc,
switch (DECL_FUNCTION_CODE (fndecl))
{
+ case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX:
+ if (!tree_fits_uhwi_p (args[2]))
+ {
+ error_at (ARG_LOCATION (2),
+ "third argument to function %qE must be a constant integer",
+ fndecl);
+ return false;
+ }
+ /* fall through */
+
case BUILT_IN_ALLOCA_WITH_ALIGN:
{
/* Get the requested alignment (in bits) if it's a constant
@@ -7946,6 +7956,164 @@ c_flt_eval_method (bool maybe_c11_only_p)
return c_ts18661_flt_eval_method ();
}
+/* An enum for get_missing_token_insertion_kind for describing the best
+ place to insert a missing token, if there is one. */
+
+enum missing_token_insertion_kind
+{
+ MTIK_IMPOSSIBLE,
+ MTIK_INSERT_BEFORE_NEXT,
+ MTIK_INSERT_AFTER_PREV
+};
+
+/* Given a missing token of TYPE, determine if it is reasonable to
+ emit a fix-it hint suggesting the insertion of the token, and,
+ if so, where the token should be inserted relative to other tokens.
+
+ It only makes sense to do this for values of TYPE that are symbols.
+
+ Some symbols should go before the next token, e.g. in:
+ if flag)
+ we want to insert the missing '(' immediately before "flag",
+ giving:
+ if (flag)
+ rather than:
+ if( flag)
+ These use MTIK_INSERT_BEFORE_NEXT.
+
+ Other symbols should go after the previous token, e.g. in:
+ if (flag
+ do_something ();
+ we want to insert the missing ')' immediately after the "flag",
+ giving:
+ if (flag)
+ do_something ();
+ rather than:
+ if (flag
+ )do_something ();
+ These use MTIK_INSERT_AFTER_PREV. */
+
+static enum missing_token_insertion_kind
+get_missing_token_insertion_kind (enum cpp_ttype type)
+{
+ switch (type)
+ {
+ /* Insert missing "opening" brackets immediately
+ before the next token. */
+ case CPP_OPEN_SQUARE:
+ case CPP_OPEN_PAREN:
+ return MTIK_INSERT_BEFORE_NEXT;
+
+ /* Insert other missing symbols immediately after
+ the previous token. */
+ case CPP_CLOSE_PAREN:
+ case CPP_CLOSE_SQUARE:
+ case CPP_SEMICOLON:
+ case CPP_COMMA:
+ case CPP_COLON:
+ return MTIK_INSERT_AFTER_PREV;
+
+ /* Other kinds of token don't get fix-it hints. */
+ default:
+ return MTIK_IMPOSSIBLE;
+ }
+}
+
+/* Given RICHLOC, a location for a diagnostic describing a missing token
+ of kind TOKEN_TYPE, potentially add a fix-it hint suggesting the
+ insertion of the token.
+
+ The location of the attempted fix-it hint depends on TOKEN_TYPE:
+ it will either be:
+ (a) immediately after PREV_TOKEN_LOC, or
+
+ (b) immediately before the primary location within RICHLOC (taken to
+ be that of the token following where the token was expected).
+
+ If we manage to add a fix-it hint, then the location of the
+ fix-it hint is likely to be more useful as the primary location
+ of the diagnostic than that of the following token, so we swap
+ these locations.
+
+ For example, given this bogus code:
+ 123456789012345678901234567890
+ 1 | int missing_semicolon (void)
+ 2 | {
+ 3 | return 42
+ 4 | }
+
+ we will emit:
+
+ "expected ';' before '}'"
+
+ RICHLOC's primary location is at the closing brace, so before "swapping"
+ we would emit the error at line 4 column 1:
+
+ 123456789012345678901234567890
+ 3 | return 42 |< fix-it hint emitted for this line
+ | ; |
+ 4 | } |< "expected ';' before '}'" emitted at this line
+ | ^ |
+
+ It's more useful for the location of the diagnostic to be at the
+ fix-it hint, so we swap the locations, so the primary location
+ is at the fix-it hint, with the old primary location inserted
+ as a secondary location, giving this, with the error at line 3
+ column 12:
+
+ 123456789012345678901234567890
+ 3 | return 42 |< "expected ';' before '}'" emitted at this line,
+ | ^ | with fix-it hint
+ 4 | ; |
+ | } |< secondary range emitted here
+ | ~ |. */
+
+void
+maybe_suggest_missing_token_insertion (rich_location *richloc,
+ enum cpp_ttype token_type,
+ location_t prev_token_loc)
+{
+ gcc_assert (richloc);
+
+ enum missing_token_insertion_kind mtik
+ = get_missing_token_insertion_kind (token_type);
+
+ switch (mtik)
+ {
+ default:
+ gcc_unreachable ();
+ break;
+
+ case MTIK_IMPOSSIBLE:
+ return;
+
+ case MTIK_INSERT_BEFORE_NEXT:
+ /* Attempt to add the fix-it hint before the primary location
+ of RICHLOC. */
+ richloc->add_fixit_insert_before (cpp_type2name (token_type, 0));
+ break;
+
+ case MTIK_INSERT_AFTER_PREV:
+ /* Attempt to add the fix-it hint after PREV_TOKEN_LOC. */
+ richloc->add_fixit_insert_after (prev_token_loc,
+ cpp_type2name (token_type, 0));
+ break;
+ }
+
+ /* If we were successful, use the fix-it hint's location as the
+ primary location within RICHLOC, adding the old primary location
+ back as a secondary location. */
+ if (!richloc->seen_impossible_fixit_p ())
+ {
+ fixit_hint *hint = richloc->get_last_fixit_hint ();
+ location_t hint_loc = hint->get_start_loc ();
+ location_t old_loc = richloc->get_loc ();
+
+ richloc->set_range (line_table, 0, hint_loc, true);
+ richloc->add_range (old_loc, false);
+ }
+}
+
#if CHECKING_P
namespace selftest {
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index da6a0be..7e1877e 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -1550,6 +1550,9 @@ extern int c_flt_eval_method (bool ts18661_p);
extern void add_no_sanitize_value (tree node, unsigned int flags);
extern void maybe_add_include_fixit (rich_location *, const char *);
+extern void maybe_suggest_missing_token_insertion (rich_location *richloc,
+ enum cpp_ttype token_type,
+ location_t prev_token_loc);
#if CHECKING_P
namespace selftest {
diff --git a/gcc/c-family/c-format.c b/gcc/c-family/c-format.c
index 0dba979..164d035 100644
--- a/gcc/c-family/c-format.c
+++ b/gcc/c-family/c-format.c
@@ -97,7 +97,8 @@ format_warning_at_char (location_t fmt_string_loc, tree format_string_cst,
substring_loc fmt_loc (fmt_string_loc, string_type, char_idx, char_idx,
char_idx);
- bool warned = format_warning_va (fmt_loc, NULL, NULL, opt, gmsgid, &ap);
+ bool warned = format_warning_va (fmt_loc, UNKNOWN_LOCATION, NULL, opt,
+ gmsgid, &ap);
va_end (ap);
return warned;
@@ -1039,7 +1040,7 @@ static void check_format_types (const substring_loc &fmt_loc,
char conversion_char,
vec<location_t> *arglocs);
static void format_type_warning (const substring_loc &fmt_loc,
- source_range *param_range,
+ location_t param_loc,
format_wanted_type *, tree,
tree,
const format_kind_info *fki,
@@ -3073,8 +3074,9 @@ check_format_types (const substring_loc &fmt_loc,
cur_param = types->param;
if (!cur_param)
{
- format_type_warning (fmt_loc, NULL, types, wanted_type, NULL, fki,
- offset_to_type_start, conversion_char);
+ format_type_warning (fmt_loc, UNKNOWN_LOCATION, types, wanted_type,
+ NULL, fki, offset_to_type_start,
+ conversion_char);
continue;
}
@@ -3084,23 +3086,15 @@ check_format_types (const substring_loc &fmt_loc,
orig_cur_type = cur_type;
char_type_flag = 0;
- source_range param_range;
- source_range *param_range_ptr;
+ location_t param_loc = UNKNOWN_LOCATION;
if (EXPR_HAS_LOCATION (cur_param))
- {
- param_range = EXPR_LOCATION_RANGE (cur_param);
- param_range_ptr = &param_range;
- }
+ param_loc = EXPR_LOCATION (cur_param);
else if (arglocs)
{
/* arg_num is 1-based. */
gcc_assert (types->arg_num > 0);
- location_t param_loc = (*arglocs)[types->arg_num - 1];
- param_range = get_range_from_loc (line_table, param_loc);
- param_range_ptr = &param_range;
+ param_loc = (*arglocs)[types->arg_num - 1];
}
- else
- param_range_ptr = NULL;
STRIP_NOPS (cur_param);
@@ -3166,7 +3160,7 @@ check_format_types (const substring_loc &fmt_loc,
}
else
{
- format_type_warning (fmt_loc, param_range_ptr,
+ format_type_warning (fmt_loc, param_loc,
types, wanted_type, orig_cur_type, fki,
offset_to_type_start, conversion_char);
break;
@@ -3236,7 +3230,7 @@ check_format_types (const substring_loc &fmt_loc,
&& TYPE_PRECISION (cur_type) == TYPE_PRECISION (wanted_type))
continue;
/* Now we have a type mismatch. */
- format_type_warning (fmt_loc, param_range_ptr, types,
+ format_type_warning (fmt_loc, param_loc, types,
wanted_type, orig_cur_type, fki,
offset_to_type_start, conversion_char);
}
@@ -3544,8 +3538,9 @@ get_corrected_substring (const substring_loc &fmt_loc,
/* Give a warning about a format argument of different type from that expected.
The range of the diagnostic is taken from WHOLE_FMT_LOC; the caret location
is based on the location of the char at TYPE->offset_loc.
- If non-NULL, PARAM_RANGE is the source range of the
- relevant argument. WANTED_TYPE is the type the argument should have,
+ PARAM_LOC is the location of the relevant argument, or UNKNOWN_LOCATION
+ if this is unavailable.
+ WANTED_TYPE is the type the argument should have,
possibly stripped of pointer dereferences. The description (such as "field
precision"), the placement in the format string, a possibly more
friendly name of WANTED_TYPE, and the number of pointer dereferences
@@ -3566,7 +3561,7 @@ get_corrected_substring (const substring_loc &fmt_loc,
V~~~~~~~~ : range of WHOLE_FMT_LOC, from cols 23-31
sprintf (d, "before %-+*.*lld after", int_expr, int_expr, long_expr);
^ ^ ^~~~~~~~~
- | ` CONVERSION_CHAR: 'd' *PARAM_RANGE
+ | ` CONVERSION_CHAR: 'd' PARAM_LOC
type starts here
OFFSET_TO_TYPE_START is 13, the offset to the "lld" within the
@@ -3574,7 +3569,7 @@ get_corrected_substring (const substring_loc &fmt_loc,
static void
format_type_warning (const substring_loc &whole_fmt_loc,
- source_range *param_range,
+ location_t param_loc,
format_wanted_type *type,
tree wanted_type, tree arg_type,
const format_kind_info *fki,
@@ -3636,7 +3631,7 @@ format_type_warning (const substring_loc &whole_fmt_loc,
{
if (arg_type)
format_warning_at_substring
- (fmt_loc, param_range,
+ (fmt_loc, param_loc,
corrected_substring, OPT_Wformat_,
"%s %<%s%.*s%> expects argument of type %<%s%s%>, "
"but argument %d has type %qT",
@@ -3646,7 +3641,7 @@ format_type_warning (const substring_loc &whole_fmt_loc,
wanted_type_name, p, arg_num, arg_type);
else
format_warning_at_substring
- (fmt_loc, param_range,
+ (fmt_loc, param_loc,
corrected_substring, OPT_Wformat_,
"%s %<%s%.*s%> expects a matching %<%s%s%> argument",
gettext (kind_descriptions[kind]),
@@ -3657,7 +3652,7 @@ format_type_warning (const substring_loc &whole_fmt_loc,
{
if (arg_type)
format_warning_at_substring
- (fmt_loc, param_range,
+ (fmt_loc, param_loc,
corrected_substring, OPT_Wformat_,
"%s %<%s%.*s%> expects argument of type %<%T%s%>, "
"but argument %d has type %qT",
@@ -3667,7 +3662,7 @@ format_type_warning (const substring_loc &whole_fmt_loc,
wanted_type, p, arg_num, arg_type);
else
format_warning_at_substring
- (fmt_loc, param_range,
+ (fmt_loc, param_loc,
corrected_substring, OPT_Wformat_,
"%s %<%s%.*s%> expects a matching %<%T%s%> argument",
gettext (kind_descriptions[kind]),
diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c
index 6a4b7c7..91f9bf9 100644
--- a/gcc/c-family/c-gimplify.c
+++ b/gcc/c-family/c-gimplify.c
@@ -229,6 +229,8 @@ c_gimplify_expr (tree *expr_p, gimple_seq *pre_p ATTRIBUTE_UNUSED,
{
case LSHIFT_EXPR:
case RSHIFT_EXPR:
+ case LROTATE_EXPR:
+ case RROTATE_EXPR:
{
/* We used to convert the right operand of a shift-expression
to an integer_type_node in the FEs. But it is unnecessary
diff --git a/gcc/c-family/c-opts.c b/gcc/c-family/c-opts.c
index 3662aa3..6bd5355 100644
--- a/gcc/c-family/c-opts.c
+++ b/gcc/c-family/c-opts.c
@@ -118,7 +118,7 @@ static void set_std_c11 (int);
static void check_deps_environment_vars (void);
static void handle_deferred_opts (void);
static void sanitize_cpp_opts (void);
-static void add_prefixed_path (const char *, size_t);
+static void add_prefixed_path (const char *, incpath_kind);
static void push_command_line_include (void);
static void cb_file_change (cpp_reader *, const line_map_ordinary *);
static void cb_dir_change (cpp_reader *, const char *);
@@ -316,7 +316,7 @@ c_common_handle_option (size_t scode, const char *arg, int value,
case OPT_I:
if (strcmp (arg, "-"))
- add_path (xstrdup (arg), BRACKET, 0, true);
+ add_path (xstrdup (arg), INC_BRACKET, 0, true);
else
{
if (quote_chain_split)
@@ -550,7 +550,7 @@ c_common_handle_option (size_t scode, const char *arg, int value,
break;
case OPT_idirafter:
- add_path (xstrdup (arg), AFTER, 0, true);
+ add_path (xstrdup (arg), INC_AFTER, 0, true);
break;
case OPT_imacros:
@@ -567,7 +567,7 @@ c_common_handle_option (size_t scode, const char *arg, int value,
break;
case OPT_iquote:
- add_path (xstrdup (arg), QUOTE, 0, true);
+ add_path (xstrdup (arg), INC_QUOTE, 0, true);
break;
case OPT_isysroot:
@@ -575,15 +575,15 @@ c_common_handle_option (size_t scode, const char *arg, int value,
break;
case OPT_isystem:
- add_path (xstrdup (arg), SYSTEM, 0, true);
+ add_path (xstrdup (arg), INC_SYSTEM, 0, true);
break;
case OPT_iwithprefix:
- add_prefixed_path (arg, SYSTEM);
+ add_prefixed_path (arg, INC_SYSTEM);
break;
case OPT_iwithprefixbefore:
- add_prefixed_path (arg, BRACKET);
+ add_prefixed_path (arg, INC_BRACKET);
break;
case OPT_lang_asm:
@@ -1326,7 +1326,7 @@ sanitize_cpp_opts (void)
/* Add include path with a prefix at the front of its name. */
static void
-add_prefixed_path (const char *suffix, size_t chain)
+add_prefixed_path (const char *suffix, incpath_kind chain)
{
char *path;
const char *prefix;
diff --git a/gcc/c-family/c-pretty-print.c b/gcc/c-family/c-pretty-print.c
index b8b8f66..0f48b9e 100644
--- a/gcc/c-family/c-pretty-print.c
+++ b/gcc/c-family/c-pretty-print.c
@@ -521,6 +521,11 @@ pp_c_parameter_type_list (c_pretty_printer *pp, tree t)
else
pp->abstract_declarator (TREE_VALUE (parms));
}
+ if (!first && !parms)
+ {
+ pp_separate_with (pp, ',');
+ pp_c_ws_string (pp, "...");
+ }
}
pp_c_right_paren (pp);
}
@@ -911,9 +916,9 @@ pp_c_integer_constant (c_pretty_printer *pp, tree i)
pp_unsigned_wide_integer (pp, tree_to_uhwi (i));
else
{
- wide_int wi = i;
+ wide_int wi = wi::to_wide (i);
- if (wi::lt_p (i, 0, TYPE_SIGN (TREE_TYPE (i))))
+ if (wi::lt_p (wi::to_wide (i), 0, TYPE_SIGN (TREE_TYPE (i))))
{
pp_minus (pp);
wi = -wi;
diff --git a/gcc/c-family/c-warn.c b/gcc/c-family/c-warn.c
index 0749d16..78f6ba8 100644
--- a/gcc/c-family/c-warn.c
+++ b/gcc/c-family/c-warn.c
@@ -355,15 +355,25 @@ warn_tautological_bitwise_comparison (location_t loc, tree_code code,
else
return;
+ /* Note that the two operands are from before the usual integer
+ conversions, so their types might not be the same.
+ Use the larger of the two precisions and ignore bits outside
+ of that. */
+ int prec = MAX (TYPE_PRECISION (TREE_TYPE (cst)),
+ TYPE_PRECISION (TREE_TYPE (bitopcst)));
+
+ wide_int bitopcstw = wi::to_wide (bitopcst, prec);
+ wide_int cstw = wi::to_wide (cst, prec);
+
wide_int res;
if (TREE_CODE (bitop) == BIT_AND_EXPR)
- res = wi::bit_and (bitopcst, cst);
+ res = bitopcstw & cstw;
else
- res = wi::bit_or (bitopcst, cst);
+ res = bitopcstw | cstw;
/* For BIT_AND only warn if (CST2 & CST1) != CST1, and
for BIT_OR only if (CST2 | CST1) != CST1. */
- if (res == cst)
+ if (res == cstw)
return;
if (code == EQ_EXPR)
@@ -1205,12 +1215,12 @@ warnings_for_convert_and_check (location_t loc, tree type, tree expr,
if (cst)
warning_at (loc, OPT_Woverflow,
"overflow in conversion from %qT to %qT "
- "chages value from %qE to %qE",
+ "changes value from %qE to %qE",
exprtype, type, expr, result);
else
warning_at (loc, OPT_Woverflow,
"overflow in conversion from %qT to %qT "
- "chages the value of %qE",
+ "changes the value of %qE",
exprtype, type, expr);
}
else
@@ -1230,11 +1240,11 @@ match_case_to_enum_1 (tree key, tree type, tree label)
char buf[WIDE_INT_PRINT_BUFFER_SIZE];
if (tree_fits_uhwi_p (key))
- print_dec (key, buf, UNSIGNED);
+ print_dec (wi::to_wide (key), buf, UNSIGNED);
else if (tree_fits_shwi_p (key))
- print_dec (key, buf, SIGNED);
+ print_dec (wi::to_wide (key), buf, SIGNED);
else
- print_hex (key, buf);
+ print_hex (wi::to_wide (key), buf);
if (TYPE_NAME (type) == NULL_TREE)
warning_at (DECL_SOURCE_LOCATION (CASE_LABEL (label)),
@@ -1336,8 +1346,8 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,
/* If there's a case value > 1 or < 0, that is outside bool
range, warn. */
if (outside_range_p
- || (max && wi::gts_p (max, 1))
- || (min && wi::lts_p (min, 0))
+ || (max && wi::gts_p (wi::to_wide (max), 1))
+ || (min && wi::lts_p (wi::to_wide (min), 0))
/* And handle the
switch (boolean)
{
@@ -1347,8 +1357,8 @@ c_do_switch_warnings (splay_tree cases, location_t switch_location,
}
case, where we want to warn. */
|| (default_node
- && max && wi::eq_p (max, 1)
- && min && wi::eq_p (min, 0)))
+ && max && wi::to_wide (max) == 1
+ && min && wi::to_wide (min) == 0))
warning_at (switch_location, OPT_Wswitch_bool,
"switch condition has boolean value");
}
@@ -2253,7 +2263,7 @@ maybe_warn_shift_overflow (location_t loc, tree op0, tree op1)
if (TYPE_UNSIGNED (type0))
return false;
- unsigned int min_prec = (wi::min_precision (op0, SIGNED)
+ unsigned int min_prec = (wi::min_precision (wi::to_wide (op0), SIGNED)
+ TREE_INT_CST_LOW (op1));
/* Handle the case of left-shifting 1 into the sign bit.
* However, shifting 1 _out_ of the sign bit, as in
diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 3c2c107..13d2a59 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1810,7 +1810,7 @@ ObjC ObjC++ Var(flag_zero_link)
Generate lazy class lookup (via objc_getClass()) for use in Zero-Link mode.
gen-decls
-ObjC ObjC++ Driver Var(flag_gen_declaration)
+ObjC ObjC++ Driver Var(flag_gen_declaration) RejectNegative
Dump declarations to a .decl file.
femit-struct-debug-baseonly
diff --git a/gcc/c/ChangeLog b/gcc/c/ChangeLog
index 135445e..c260f62 100644
--- a/gcc/c/ChangeLog
+++ b/gcc/c/ChangeLog
@@ -1,3 +1,60 @@
+2017-10-24 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82466
+ * c-decl.c (diagnose_mismatched_decls): Use
+ OPT_Wbuiltin_declaration_mismatch.
+
+2017-10-12 David Malcolm <dmalcolm@redhat.com>
+
+ * c-parser.c (c_parser_require): Add "type_is_unique" param and
+ use it to guard calls to maybe_suggest_missing_token_insertion.
+ (c_parser_parms_list_declarator): Override default value of new
+ "type_is_unique" param to c_parser_require.
+ (c_parser_asm_statement): Likewise.
+ * c-parser.h (c_parser_require): Add "type_is_unique" param,
+ defaulting to true.
+
+2017-10-11 Nathan Sidwell <nathan@acm.org>
+
+ * c-decl.c (grokdeclarator): Check HAS_DECL_ASSEMBLER_NAME_P too.
+
+2017-10-10 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * c-parser.c (c_parser_cilk_clause_vectorlength): Use wi::to_wide when
+ operating on trees as wide_ints.
+ * c-typeck.c (build_c_cast, c_finish_omp_clauses): Likewise.
+ (c_tree_equal): Likewise.
+
+2017-10-04 David Malcolm <dmalcolm@redhat.com>
+
+ * c-decl.c (push_parm_decl): Store c_parm's location into the
+ PARAM_DECL.
+ (build_c_parm): Add "loc" param and store it within the c_parm.
+ * c-parser.c (struct c_parser): Add "last_token_location" field.
+ (c_parser_consume_token): Store location of the token into the
+ new field.
+ (c_parser_declaration_or_fndef): Store params into DECL_ARGUMENTS
+ when handling a FUNCTION_DECL, if it doesn't already have them.
+ (c_parser_parameter_declaration): Generate a location for the
+ parameter, and pass it to the call to build_c_parm.
+ * c-tree.h (struct c_parm): Add field "loc".
+ (build_c_parm): Add location_t param.
+ * c-typeck.c (get_fndecl_argument_location): New function.
+ (inform_for_arg): New function.
+ (convert_for_assignment): Use inform_for_arg when dealing with
+ ic_argpass.
+
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ * c-decl.c (grokfield): Use SET_DECL_C_BIT_FIELD here if
+ width is non-NULL.
+ (finish_struct): Test DECL_C_BIT_FIELD instead of DECL_INITIAL,
+ don't SET_DECL_C_BIT_FIELD here.
+
+ PR c/82340
+ * c-decl.c (build_compound_literal): Use c_apply_type_quals_to_decl
+ instead of trying to set just TREE_READONLY manually.
+
2017-09-16 Tom de Vries <tom@codesourcery.com>
PR c/81875
diff --git a/gcc/c/c-decl.c b/gcc/c/c-decl.c
index 7121498..5c472e6 100644
--- a/gcc/c/c-decl.c
+++ b/gcc/c/c-decl.c
@@ -1837,7 +1837,8 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
locate_old_decl (olddecl);
}
else if (TREE_PUBLIC (newdecl))
- warning (0, "built-in function %q+D declared as non-function",
+ warning (OPT_Wbuiltin_declaration_mismatch,
+ "built-in function %q+D declared as non-function",
newdecl);
else
warning (OPT_Wshadow, "declaration of %q+D shadows "
@@ -5190,6 +5191,8 @@ push_parm_decl (const struct c_parm *parm, tree *expr)
decl = grokdeclarator (parm->declarator, parm->specs, PARM, false, NULL,
&attrs, expr, NULL, DEPRECATED_NORMAL);
+ if (decl && DECL_P (decl))
+ DECL_SOURCE_LOCATION (decl) = parm->loc;
decl_attributes (&decl, attrs, 0);
decl = pushdecl (decl);
@@ -5247,9 +5250,7 @@ build_compound_literal (location_t loc, tree type, tree init, bool non_const)
DECL_ARTIFICIAL (decl) = 1;
DECL_IGNORED_P (decl) = 1;
TREE_TYPE (decl) = type;
- TREE_READONLY (decl) = (TYPE_READONLY (type)
- || (TREE_CODE (type) == ARRAY_TYPE
- && TYPE_READONLY (TREE_TYPE (type))));
+ c_apply_type_quals_to_decl (TYPE_QUALS (strip_array_types (type)), decl);
store_init_value (loc, decl, init, NULL_TREE);
if (TREE_CODE (type) == ARRAY_TYPE && !COMPLETE_TYPE_P (type))
@@ -7011,7 +7012,8 @@ grokdeclarator (const struct c_declarator *declarator,
/* This is the earliest point at which we might know the assembler
name of a variable. Thus, if it's known before this, die horribly. */
- gcc_assert (!DECL_ASSEMBLER_NAME_SET_P (decl));
+ gcc_assert (!HAS_DECL_ASSEMBLER_NAME_P (decl)
+ || !DECL_ASSEMBLER_NAME_SET_P (decl));
if (warn_cxx_compat
&& VAR_P (decl)
@@ -7602,6 +7604,8 @@ grokfield (location_t loc,
finish_decl (value, loc, NULL_TREE, NULL_TREE, NULL_TREE);
DECL_INITIAL (value) = width;
+ if (width)
+ SET_DECL_C_BIT_FIELD (value);
if (warn_cxx_compat && DECL_NAME (value) != NULL_TREE)
{
@@ -7946,12 +7950,11 @@ finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
if (C_DECL_VARIABLE_SIZE (x))
C_TYPE_VARIABLE_SIZE (t) = 1;
- if (DECL_INITIAL (x))
+ if (DECL_C_BIT_FIELD (x))
{
unsigned HOST_WIDE_INT width = tree_to_uhwi (DECL_INITIAL (x));
DECL_SIZE (x) = bitsize_int (width);
DECL_BIT_FIELD (x) = 1;
- SET_DECL_C_BIT_FIELD (x);
}
if (TYPE_PACKED (t)
@@ -9701,12 +9704,14 @@ build_void_list_node (void)
struct c_parm *
build_c_parm (struct c_declspecs *specs, tree attrs,
- struct c_declarator *declarator)
+ struct c_declarator *declarator,
+ location_t loc)
{
struct c_parm *ret = XOBNEW (&parser_obstack, struct c_parm);
ret->specs = specs;
ret->attrs = attrs;
ret->declarator = declarator;
+ ret->loc = loc;
return ret;
}
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index a36397b..6b84324 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -206,6 +206,9 @@ struct GTY(()) c_parser {
/* Buffer to hold all the tokens from parsing the vector attribute for the
SIMD-enabled functions (formerly known as elemental functions). */
vec <c_token, va_gc> *cilk_simd_fn_tokens;
+
+ /* Location of the last consumed token. */
+ location_t last_token_location;
};
/* Return a pointer to the Nth token in PARSERs tokens_buf. */
@@ -770,6 +773,7 @@ c_parser_consume_token (c_parser *parser)
gcc_assert (parser->tokens[0].type != CPP_EOF);
gcc_assert (!parser->in_pragma || parser->tokens[0].type != CPP_PRAGMA_EOL);
gcc_assert (parser->error || parser->tokens[0].type != CPP_PRAGMA);
+ parser->last_token_location = parser->tokens[0].location;
if (parser->tokens != &parser->tokens_buf[0])
parser->tokens++;
else if (parser->tokens_avail == 2)
@@ -1037,13 +1041,21 @@ get_matching_symbol (enum cpp_ttype type)
If MATCHING_LOCATION is not UNKNOWN_LOCATION, then highlight it
within any error as the location of an "opening" token matching
the close token TYPE (e.g. the location of the '(' when TYPE is
- CPP_CLOSE_PAREN). */
+ CPP_CLOSE_PAREN).
+
+ If TYPE_IS_UNIQUE is true (the default) then msgid describes exactly
+ one type (e.g. "expected %<)%>") and thus it may be reasonable to
+ attempt to generate a fix-it hint for the problem.
+ Otherwise msgid describes multiple token types (e.g.
+ "expected %<;%>, %<,%> or %<)%>"), and thus we shouldn't attempt to
+ generate a fix-it hint. */
bool
c_parser_require (c_parser *parser,
enum cpp_ttype type,
const char *msgid,
- location_t matching_location)
+ location_t matching_location,
+ bool type_is_unique)
{
if (c_parser_next_token_is (parser, type))
{
@@ -1055,6 +1067,13 @@ c_parser_require (c_parser *parser,
location_t next_token_loc = c_parser_peek_token (parser)->location;
gcc_rich_location richloc (next_token_loc);
+ /* Potentially supply a fix-it hint, suggesting to add the
+ missing token immediately after the *previous* token.
+ This may move the primary location within richloc. */
+ if (!parser->error && type_is_unique)
+ maybe_suggest_missing_token_insertion (&richloc, type,
+ parser->last_token_location);
+
/* If matching_location != UNKNOWN_LOCATION, highlight it.
Attempt to consolidate diagnostics by printing it as a
secondary range within the main diagnostic. */
@@ -2120,6 +2139,10 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
tree d = start_decl (declarator, specs, false,
chainon (postfix_attrs,
all_prefix_attrs));
+ if (d && TREE_CODE (d) == FUNCTION_DECL)
+ if (declarator->kind == cdk_function)
+ if (DECL_ARGUMENTS (d) == NULL_TREE)
+ DECL_ARGUMENTS (d) = declarator->u.arg_info->parms;
if (omp_declare_simd_clauses.exists ()
|| !vec_safe_is_empty (parser->cilk_simd_fn_tokens))
{
@@ -3967,7 +3990,8 @@ c_parser_parms_list_declarator (c_parser *parser, tree attrs, tree expr)
return get_parm_info (false, expr);
}
if (!c_parser_require (parser, CPP_COMMA,
- "expected %<;%>, %<,%> or %<)%>"))
+ "expected %<;%>, %<,%> or %<)%>",
+ UNKNOWN_LOCATION, false))
{
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
return NULL;
@@ -4039,6 +4063,9 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
c_parser_skip_to_end_of_parameter (parser);
return NULL;
}
+
+ location_t start_loc = c_parser_peek_token (parser)->location;
+
specs = build_null_declspecs ();
if (attrs)
{
@@ -4061,8 +4088,33 @@ c_parser_parameter_declaration (c_parser *parser, tree attrs)
}
if (c_parser_next_token_is_keyword (parser, RID_ATTRIBUTE))
postfix_attrs = c_parser_attributes (parser);
+
+ /* Generate a location for the parameter, ranging from the start of the
+ initial token to the end of the final token.
+
+ If we have a identifier, then use it for the caret location, e.g.
+
+ extern int callee (int one, int (*two)(int, int), float three);
+ ~~~~~~^~~~~~~~~~~~~~
+
+ otherwise, reuse the start location for the caret location e.g.:
+
+ extern int callee (int one, int (*)(int, int), float three);
+ ^~~~~~~~~~~~~~~~~
+ */
+ location_t end_loc = parser->last_token_location;
+
+ /* Find any cdk_id declarator; determine if we have an identifier. */
+ c_declarator *id_declarator = declarator;
+ while (id_declarator && id_declarator->kind != cdk_id)
+ id_declarator = id_declarator->declarator;
+ location_t caret_loc = (id_declarator->u.id
+ ? id_declarator->id_loc
+ : start_loc);
+ location_t param_loc = make_location (caret_loc, start_loc, end_loc);
+
return build_c_parm (specs, chainon (postfix_attrs, prefix_attrs),
- declarator);
+ declarator, param_loc);
}
/* Parse a string literal in an asm expression. It should not be
@@ -6393,7 +6445,8 @@ c_parser_asm_statement (c_parser *parser)
if (!c_parser_require (parser, CPP_COLON,
is_goto
? G_("expected %<:%>")
- : G_("expected %<:%> or %<)%>")))
+ : G_("expected %<:%> or %<)%>"),
+ UNKNOWN_LOCATION, is_goto))
goto error_close_paren;
/* Once past any colon, we're no longer a simple asm. */
@@ -17796,7 +17849,7 @@ c_parser_cilk_clause_vectorlength (c_parser *parser, tree clauses,
|| !INTEGRAL_TYPE_P (TREE_TYPE (expr)))
error_at (loc, "vectorlength must be an integer constant");
- else if (wi::exact_log2 (expr) == -1)
+ else if (wi::exact_log2 (wi::to_wide (expr)) == -1)
error_at (loc, "vectorlength must be a power of 2");
else
{
diff --git a/gcc/c/c-parser.h b/gcc/c/c-parser.h
index 01a7b72..21e4054 100644
--- a/gcc/c/c-parser.h
+++ b/gcc/c/c-parser.h
@@ -137,7 +137,8 @@ extern c_token * c_parser_peek_2nd_token (c_parser *parser);
extern c_token * c_parser_peek_nth_token (c_parser *parser, unsigned int n);
extern bool c_parser_require (c_parser *parser, enum cpp_ttype type,
const char *msgid,
- location_t matching_location = UNKNOWN_LOCATION);
+ location_t matching_location = UNKNOWN_LOCATION,
+ bool type_is_unique=true);
extern bool c_parser_error (c_parser *parser, const char *gmsgid);
extern void c_parser_consume_token (c_parser *parser);
extern void c_parser_skip_until_found (c_parser *parser, enum cpp_ttype type,
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 96c7ae7..1135647 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h
@@ -477,6 +477,8 @@ struct c_parm {
tree attrs;
/* The declarator. */
struct c_declarator *declarator;
+ /* The location of the parameter. */
+ location_t loc;
};
/* Used when parsing an enum. Initialized by start_enum. */
@@ -581,7 +583,7 @@ extern void temp_pop_parm_decls (void);
extern tree xref_tag (enum tree_code, tree);
extern struct c_typespec parser_xref_tag (location_t, enum tree_code, tree);
extern struct c_parm *build_c_parm (struct c_declspecs *, tree,
- struct c_declarator *);
+ struct c_declarator *, location_t);
extern struct c_declarator *build_attrs_declarator (tree,
struct c_declarator *);
extern struct c_declarator *build_function_declarator (struct c_arg_info *,
diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index 73e7460..cb9c589 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -5684,7 +5684,7 @@ build_c_cast (location_t loc, tree type, tree expr)
}
else if (TREE_OVERFLOW (value))
/* Reset VALUE's overflow flags, ensuring constant sharing. */
- value = wide_int_to_tree (TREE_TYPE (value), value);
+ value = wide_int_to_tree (TREE_TYPE (value), wi::to_wide (value));
}
}
@@ -6180,6 +6180,50 @@ maybe_warn_string_init (location_t loc, tree type, struct c_expr expr)
"array initialized from parenthesized string constant");
}
+/* Attempt to locate the parameter with the given index within FNDECL,
+ returning DECL_SOURCE_LOCATION (FNDECL) if it can't be found. */
+
+static location_t
+get_fndecl_argument_location (tree fndecl, int argnum)
+{
+ int i;
+ tree param;
+
+ /* Locate param by index within DECL_ARGUMENTS (fndecl). */
+ for (i = 0, param = DECL_ARGUMENTS (fndecl);
+ i < argnum && param;
+ i++, param = TREE_CHAIN (param))
+ ;
+
+ /* If something went wrong (e.g. if we have a builtin and thus no arguments),
+ return DECL_SOURCE_LOCATION (FNDECL). */
+ if (param == NULL)
+ return DECL_SOURCE_LOCATION (fndecl);
+
+ return DECL_SOURCE_LOCATION (param);
+}
+
+/* Issue a note about a mismatching argument for parameter PARMNUM
+ to FUNDECL, for types EXPECTED_TYPE and ACTUAL_TYPE.
+ Attempt to issue the note at the pertinent parameter of the decl;
+ failing that issue it at the location of FUNDECL; failing that
+ issue it at PLOC. */
+
+static void
+inform_for_arg (tree fundecl, location_t ploc, int parmnum,
+ tree expected_type, tree actual_type)
+{
+ location_t loc;
+ if (fundecl && !DECL_IS_BUILTIN (fundecl))
+ loc = get_fndecl_argument_location (fundecl, parmnum - 1);
+ else
+ loc = ploc;
+
+ inform (loc,
+ "expected %qT but argument is of type %qT",
+ expected_type, actual_type);
+}
+
/* Convert value RHS to type TYPE as preparation for an assignment to
an lvalue of type TYPE. If ORIGTYPE is not NULL_TREE, it is the
original type of RHS; this differs from TREE_TYPE (RHS) for enum
@@ -6251,10 +6295,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
{ \
case ic_argpass: \
if (pedwarn (PLOC, OPT, AR, parmnum, rname)) \
- inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
- ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \
- "expected %qT but argument is of type %qT", \
- type, rhstype); \
+ inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \
break; \
case ic_assign: \
pedwarn (LOCATION, OPT, AS); \
@@ -6280,10 +6321,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
{ \
case ic_argpass: \
if (pedwarn (PLOC, OPT, AR, parmnum, rname, QUALS)) \
- inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
- ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \
- "expected %qT but argument is of type %qT", \
- type, rhstype); \
+ inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \
break; \
case ic_assign: \
pedwarn (LOCATION, OPT, AS, QUALS); \
@@ -6309,10 +6347,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
{ \
case ic_argpass: \
if (warning_at (PLOC, OPT, AR, parmnum, rname, QUALS)) \
- inform ((fundecl && !DECL_IS_BUILTIN (fundecl)) \
- ? DECL_SOURCE_LOCATION (fundecl) : PLOC, \
- "expected %qT but argument is of type %qT", \
- type, rhstype); \
+ inform_for_arg (fundecl, (PLOC), parmnum, type, rhstype); \
break; \
case ic_assign: \
warning_at (LOCATION, OPT, AS, QUALS); \
@@ -6864,10 +6899,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
if (pedwarn (expr_loc, OPT_Wincompatible_pointer_types,
"passing argument %d of %qE from incompatible "
"pointer type", parmnum, rname))
- inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
- ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
- "expected %qT but argument is of type %qT",
- type, rhstype);
+ inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
break;
case ic_assign:
pedwarn (location, OPT_Wincompatible_pointer_types,
@@ -6910,10 +6942,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
if (pedwarn (expr_loc, OPT_Wint_conversion,
"passing argument %d of %qE makes pointer from "
"integer without a cast", parmnum, rname))
- inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
- ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
- "expected %qT but argument is of type %qT",
- type, rhstype);
+ inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
break;
case ic_assign:
pedwarn (location, OPT_Wint_conversion,
@@ -6944,10 +6973,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
if (pedwarn (expr_loc, OPT_Wint_conversion,
"passing argument %d of %qE makes integer from "
"pointer without a cast", parmnum, rname))
- inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
- ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
- "expected %qT but argument is of type %qT",
- type, rhstype);
+ inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
break;
case ic_assign:
pedwarn (location, OPT_Wint_conversion,
@@ -6985,9 +7011,7 @@ convert_for_assignment (location_t location, location_t expr_loc, tree type,
case ic_argpass:
error_at (expr_loc, "incompatible type for argument %d of %qE", parmnum,
rname);
- inform ((fundecl && !DECL_IS_BUILTIN (fundecl))
- ? DECL_SOURCE_LOCATION (fundecl) : expr_loc,
- "expected %qT but argument is of type %qT", type, rhstype);
+ inform_for_arg (fundecl, expr_loc, parmnum, type, rhstype);
break;
case ic_assign:
error_at (location, "incompatible types when assigning to type %qT from "
@@ -13480,7 +13504,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE)
{
tree offset = TREE_PURPOSE (t);
- bool neg = wi::neg_p ((wide_int) offset);
+ bool neg = wi::neg_p (wi::to_wide (offset));
offset = fold_unary (ABS_EXPR, TREE_TYPE (offset), offset);
tree t2 = pointer_int_sum (OMP_CLAUSE_LOCATION (c),
neg ? MINUS_EXPR : PLUS_EXPR,
@@ -14213,7 +14237,7 @@ c_tree_equal (tree t1, tree t2)
switch (code1)
{
case INTEGER_CST:
- return wi::eq_p (t1, t2);
+ return wi::to_wide (t1) == wi::to_wide (t2);
case REAL_CST:
return real_equal (&TREE_REAL_CST (t1), &TREE_REAL_CST (t2));
diff --git a/gcc/c/gimple-parser.c b/gcc/c/gimple-parser.c
index 22f58f4..c2e31df 100644
--- a/gcc/c/gimple-parser.c
+++ b/gcc/c/gimple-parser.c
@@ -276,7 +276,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
&& TREE_CODE (lhs.value) == CALL_EXPR)
{
gimple *call;
- call = gimple_build_call_from_tree (lhs.value);
+ call = gimple_build_call_from_tree (lhs.value, NULL);
gimple_seq_add_stmt (seq, call);
gimple_set_location (call, loc);
return;
@@ -407,7 +407,7 @@ c_parser_gimple_statement (c_parser *parser, gimple_seq *seq)
rhs = c_parser_gimple_unary_expression (parser);
if (rhs.value != error_mark_node)
{
- gimple *call = gimple_build_call_from_tree (rhs.value);
+ gimple *call = gimple_build_call_from_tree (rhs.value, NULL);
gimple_call_set_lhs (call, lhs.value);
gimple_seq_add_stmt (seq, call);
gimple_set_location (call, loc);
diff --git a/gcc/caller-save.c b/gcc/caller-save.c
index 6e4ffc1..7c787f7 100644
--- a/gcc/caller-save.c
+++ b/gcc/caller-save.c
@@ -1132,17 +1132,7 @@ replace_reg_with_saved_mem (rtx *loc,
{
/* This is gen_lowpart_if_possible(), but without validating
the newly-formed address. */
- int offset = 0;
-
- if (WORDS_BIG_ENDIAN)
- offset = (MAX (GET_MODE_SIZE (GET_MODE (mem)), UNITS_PER_WORD)
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
- if (BYTES_BIG_ENDIAN)
- /* Adjust the address so that the address-after-the-data is
- unchanged. */
- offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (mem))));
-
+ HOST_WIDE_INT offset = byte_lowpart_offset (mode, GET_MODE (mem));
mem = adjust_address_nv (mem, mode, offset);
}
}
@@ -1265,7 +1255,7 @@ insert_restore (struct insn_chain *chain, int before_p, int regno,
static int
insert_save (struct insn_chain *chain, int before_p, int regno,
- HARD_REG_SET (*to_save), machine_mode *save_mode)
+ HARD_REG_SET *to_save, machine_mode *save_mode)
{
int i;
unsigned int k;
diff --git a/gcc/calls.c b/gcc/calls.c
index f55e898..3730f43 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -607,16 +607,9 @@ special_function_p (const_tree fndecl, int flags)
flags |= ECF_RETURNS_TWICE;
}
- if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
- switch (DECL_FUNCTION_CODE (fndecl))
- {
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
- flags |= ECF_MAY_BE_ALLOCA;
- break;
- default:
- break;
- }
+ if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
+ && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (fndecl)))
+ flags |= ECF_MAY_BE_ALLOCA;
return flags;
}
@@ -698,8 +691,7 @@ gimple_alloca_call_p (const gimple *stmt)
if (fndecl && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
return true;
default:
break;
@@ -719,8 +711,7 @@ alloca_call_p (const_tree exp)
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
return true;
default:
break;
@@ -1252,9 +1243,8 @@ alloc_max_size (void)
if (unit)
{
- wide_int w = wi::uhwi (limit, HOST_BITS_PER_WIDE_INT + 64);
- w *= unit;
- if (wi::ltu_p (w, alloc_object_size_limit))
+ widest_int w = wi::mul (limit, unit);
+ if (w < wi::to_widest (alloc_object_size_limit))
alloc_object_size_limit = wide_int_to_tree (ssizetype, w);
}
}
@@ -1294,8 +1284,6 @@ get_size_range (tree exp, tree range[2])
tree exptype = TREE_TYPE (exp);
unsigned expprec = TYPE_PRECISION (exptype);
- wide_int wzero = wi::zero (expprec);
- wide_int wmaxval = wide_int (TYPE_MAX_VALUE (exptype));
bool signed_p = !TYPE_UNSIGNED (exptype);
@@ -1303,7 +1291,7 @@ get_size_range (tree exp, tree range[2])
{
if (signed_p)
{
- if (wi::les_p (max, wzero))
+ if (wi::les_p (max, 0))
{
/* EXP is not in a strictly negative range. That means
it must be in some (not necessarily strictly) positive
@@ -1311,24 +1299,24 @@ get_size_range (tree exp, tree range[2])
conversions negative values end up converted to large
positive values, and otherwise they are not valid sizes,
the resulting range is in both cases [0, TYPE_MAX]. */
- min = wzero;
- max = wmaxval;
+ min = wi::zero (expprec);
+ max = wi::to_wide (TYPE_MAX_VALUE (exptype));
}
- else if (wi::les_p (min - 1, wzero))
+ else if (wi::les_p (min - 1, 0))
{
/* EXP is not in a negative-positive range. That means EXP
is either negative, or greater than max. Since negative
sizes are invalid make the range [MAX + 1, TYPE_MAX]. */
min = max + 1;
- max = wmaxval;
+ max = wi::to_wide (TYPE_MAX_VALUE (exptype));
}
else
{
max = min - 1;
- min = wzero;
+ min = wi::zero (expprec);
}
}
- else if (wi::eq_p (wzero, min - 1))
+ else if (wi::eq_p (0, min - 1))
{
/* EXP is unsigned and not in the range [1, MAX]. That means
it's either zero or greater than MAX. Even though 0 would
@@ -1336,12 +1324,12 @@ get_size_range (tree exp, tree range[2])
[MAX, TYPE_MAX] so that when MAX is greater than the limit
the whole range is diagnosed. */
min = max + 1;
- max = wmaxval;
+ max = wi::to_wide (TYPE_MAX_VALUE (exptype));
}
else
{
max = min - 1;
- min = wzero;
+ min = wi::zero (expprec);
}
}
@@ -1822,6 +1810,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
copy = allocate_dynamic_stack_space (size_rtx,
TYPE_ALIGN (type),
TYPE_ALIGN (type),
+ max_int_size_in_bytes
+ (type),
true);
copy = gen_rtx_MEM (BLKmode, copy);
set_mem_attributes (copy, type, 1);
@@ -2197,11 +2187,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
if (POINTER_BOUNDS_P (args[i].tree_value))
continue;
- if (CONST_INT_P (offset))
- addr = plus_constant (Pmode, arg_reg, INTVAL (offset));
- else
- addr = gen_rtx_PLUS (Pmode, arg_reg, offset);
-
+ addr = simplify_gen_binary (PLUS, Pmode, arg_reg, offset);
addr = plus_constant (Pmode, addr, arg_offset);
if (args[i].partial != 0)
@@ -2231,11 +2217,7 @@ compute_argument_addresses (struct arg_data *args, rtx argblock, int num_actuals
}
set_mem_align (args[i].stack, align);
- if (CONST_INT_P (slot_offset))
- addr = plus_constant (Pmode, arg_reg, INTVAL (slot_offset));
- else
- addr = gen_rtx_PLUS (Pmode, arg_reg, slot_offset);
-
+ addr = simplify_gen_binary (PLUS, Pmode, arg_reg, slot_offset);
addr = plus_constant (Pmode, addr, arg_offset);
if (args[i].partial != 0)
@@ -3649,8 +3631,8 @@ expand_call (tree exp, rtx target, int ignore)
/* We can pass TRUE as the 4th argument because we just
saved the stack pointer and will restore it right after
the call. */
- allocate_dynamic_stack_space (push_size, 0,
- BIGGEST_ALIGNMENT, true);
+ allocate_dynamic_stack_space (push_size, 0, BIGGEST_ALIGNMENT,
+ -1, true);
}
/* If argument evaluation might modify the stack pointer,
@@ -4128,7 +4110,6 @@ expand_call (tree exp, rtx target, int ignore)
{
tree type = rettype;
int unsignedp = TYPE_UNSIGNED (type);
- int offset = 0;
machine_mode pmode;
/* Ensure we promote as expected, and get the new unsignedness. */
@@ -4136,18 +4117,8 @@ expand_call (tree exp, rtx target, int ignore)
funtype, 1);
gcc_assert (GET_MODE (target) == pmode);
- if ((WORDS_BIG_ENDIAN || BYTES_BIG_ENDIAN)
- && (GET_MODE_SIZE (GET_MODE (target))
- > GET_MODE_SIZE (TYPE_MODE (type))))
- {
- offset = GET_MODE_SIZE (GET_MODE (target))
- - GET_MODE_SIZE (TYPE_MODE (type));
- if (! BYTES_BIG_ENDIAN)
- offset = (offset / UNITS_PER_WORD) * UNITS_PER_WORD;
- else if (! WORDS_BIG_ENDIAN)
- offset %= UNITS_PER_WORD;
- }
-
+ unsigned int offset = subreg_lowpart_offset (TYPE_MODE (type),
+ GET_MODE (target));
target = gen_rtx_SUBREG (TYPE_MODE (type), target, offset);
SUBREG_PROMOTED_VAR_P (target) = 1;
SUBREG_PROMOTED_SET (target, unsignedp);
diff --git a/gcc/cfg.c b/gcc/cfg.c
index 01e68ae..41002ec 100644
--- a/gcc/cfg.c
+++ b/gcc/cfg.c
@@ -263,7 +263,6 @@ unchecked_make_edge (basic_block src, basic_block dst, int flags)
e = ggc_cleared_alloc<edge_def> ();
n_edges_for_fn (cfun)++;
- e->count = profile_count::uninitialized ();
e->probability = profile_probability::uninitialized ();
e->src = src;
e->dest = dst;
@@ -334,7 +333,6 @@ make_single_succ_edge (basic_block src, basic_block dest, int flags)
edge e = make_edge (src, dest, flags);
e->probability = profile_probability::always ();
- e->count = src->count;
return e;
}
@@ -445,18 +443,6 @@ check_bb_profile (basic_block bb, FILE * file, int indent)
";; %sInvalid sum of outgoing probabilities %.1f%%\n",
s_indent, isum * 100.0 / REG_BR_PROB_BASE);
}
- profile_count lsum = profile_count::zero ();
- FOR_EACH_EDGE (e, ei, bb->succs)
- lsum += e->count;
- if (EDGE_COUNT (bb->succs) && lsum.differs_from_p (bb->count))
- {
- fprintf (file, ";; %sInvalid sum of outgoing counts ",
- s_indent);
- lsum.dump (file);
- fprintf (file, ", should be ");
- bb->count.dump (file);
- fprintf (file, "\n");
- }
}
}
if (bb != ENTRY_BLOCK_PTR_FOR_FN (fun))
@@ -468,18 +454,6 @@ check_bb_profile (basic_block bb, FILE * file, int indent)
fprintf (file,
";; %sInvalid sum of incoming frequencies %i, should be %i\n",
s_indent, sum, bb->frequency);
- profile_count lsum = profile_count::zero ();
- FOR_EACH_EDGE (e, ei, bb->preds)
- lsum += e->count;
- if (lsum.differs_from_p (bb->count))
- {
- fprintf (file, ";; %sInvalid sum of incoming counts ",
- s_indent);
- lsum.dump (file);
- fprintf (file, ", should be ");
- bb->count.dump (file);
- fprintf (file, "\n");
- }
}
if (BB_PARTITION (bb) == BB_COLD_PARTITION)
{
@@ -522,10 +496,10 @@ dump_edge_info (FILE *file, edge e, dump_flags_t flags, int do_succ)
fprintf (file, "] ");
}
- if (e->count.initialized_p () && do_details)
+ if (e->count ().initialized_p () && do_details)
{
fputs (" count:", file);
- e->count.dump (file);
+ e->count ().dump (file);
}
if (e->flags && do_details)
@@ -941,10 +915,6 @@ update_bb_profile_for_threading (basic_block bb, int edge_frequency,
}
gcc_assert (bb == taken_edge->src);
- if (dump_file && taken_edge->count < count)
- fprintf (dump_file, "edge %i->%i count became negative after threading",
- taken_edge->src->index, taken_edge->dest->index);
- taken_edge->count -= count;
}
/* Multiply all frequencies of basic blocks in array BBS of length NBBS
@@ -953,7 +923,6 @@ void
scale_bbs_frequencies_int (basic_block *bbs, int nbbs, int num, int den)
{
int i;
- edge e;
if (num < 0)
num = 0;
@@ -973,14 +942,11 @@ scale_bbs_frequencies_int (basic_block *bbs, int nbbs, int num, int den)
for (i = 0; i < nbbs; i++)
{
- edge_iterator ei;
bbs[i]->frequency = RDIV (bbs[i]->frequency * num, den);
/* Make sure the frequencies do not grow over BB_FREQ_MAX. */
if (bbs[i]->frequency > BB_FREQ_MAX)
bbs[i]->frequency = BB_FREQ_MAX;
bbs[i]->count = bbs[i]->count.apply_scale (num, den);
- FOR_EACH_EDGE (e, ei, bbs[i]->succs)
- e->count = e->count.apply_scale (num, den);
}
}
@@ -996,7 +962,6 @@ scale_bbs_frequencies_gcov_type (basic_block *bbs, int nbbs, gcov_type num,
gcov_type den)
{
int i;
- edge e;
gcov_type fraction = RDIV (num * 65536, den);
gcc_assert (fraction >= 0);
@@ -1004,29 +969,20 @@ scale_bbs_frequencies_gcov_type (basic_block *bbs, int nbbs, gcov_type num,
if (num < MAX_SAFE_MULTIPLIER)
for (i = 0; i < nbbs; i++)
{
- edge_iterator ei;
bbs[i]->frequency = RDIV (bbs[i]->frequency * num, den);
if (bbs[i]->count <= MAX_SAFE_MULTIPLIER)
bbs[i]->count = bbs[i]->count.apply_scale (num, den);
else
bbs[i]->count = bbs[i]->count.apply_scale (fraction, 65536);
- FOR_EACH_EDGE (e, ei, bbs[i]->succs)
- if (bbs[i]->count <= MAX_SAFE_MULTIPLIER)
- e->count = e->count.apply_scale (num, den);
- else
- e->count = e->count.apply_scale (fraction, 65536);
}
else
for (i = 0; i < nbbs; i++)
{
- edge_iterator ei;
if (sizeof (gcov_type) > sizeof (int))
bbs[i]->frequency = RDIV (bbs[i]->frequency * num, den);
else
bbs[i]->frequency = RDIV (bbs[i]->frequency * fraction, 65536);
bbs[i]->count = bbs[i]->count.apply_scale (fraction, 65536);
- FOR_EACH_EDGE (e, ei, bbs[i]->succs)
- e->count = e->count.apply_scale (fraction, 65536);
}
}
@@ -1038,16 +994,12 @@ scale_bbs_frequencies_profile_count (basic_block *bbs, int nbbs,
profile_count num, profile_count den)
{
int i;
- edge e;
for (i = 0; i < nbbs; i++)
{
- edge_iterator ei;
bbs[i]->frequency = RDIV (bbs[i]->frequency * num.to_gcov_type (),
den.to_gcov_type ());
bbs[i]->count = bbs[i]->count.apply_scale (num, den);
- FOR_EACH_EDGE (e, ei, bbs[i]->succs)
- e->count = e->count.apply_scale (num, den);
}
}
@@ -1059,15 +1011,11 @@ scale_bbs_frequencies (basic_block *bbs, int nbbs,
profile_probability p)
{
int i;
- edge e;
for (i = 0; i < nbbs; i++)
{
- edge_iterator ei;
bbs[i]->frequency = p.apply (bbs[i]->frequency);
bbs[i]->count = bbs[i]->count.apply_probability (p);
- FOR_EACH_EDGE (e, ei, bbs[i]->succs)
- e->count = e->count.apply_probability (p);
}
}
diff --git a/gcc/cfganal.c b/gcc/cfganal.c
index 394d986..c506067 100644
--- a/gcc/cfganal.c
+++ b/gcc/cfganal.c
@@ -612,7 +612,6 @@ connect_infinite_loops_to_exit (void)
basic_block deadend_block = dfs_find_deadend (unvisited_block);
edge e = make_edge (deadend_block, EXIT_BLOCK_PTR_FOR_FN (cfun),
EDGE_FAKE);
- e->count = profile_count::zero ();
e->probability = profile_probability::never ();
dfs.add_bb (deadend_block);
}
diff --git a/gcc/cfgbuild.c b/gcc/cfgbuild.c
index 62956b2..c6d506a 100644
--- a/gcc/cfgbuild.c
+++ b/gcc/cfgbuild.c
@@ -576,10 +576,8 @@ compute_outgoing_frequencies (basic_block b)
e = BRANCH_EDGE (b);
e->probability
= profile_probability::from_reg_br_prob_note (probability);
- e->count = b->count.apply_probability (e->probability);
f = FALLTHRU_EDGE (b);
f->probability = e->probability.invert ();
- f->count = b->count - e->count;
return;
}
else
@@ -591,7 +589,6 @@ compute_outgoing_frequencies (basic_block b)
{
e = single_succ_edge (b);
e->probability = profile_probability::always ();
- e->count = b->count;
return;
}
else
@@ -610,10 +607,6 @@ compute_outgoing_frequencies (basic_block b)
if (complex_edge)
guess_outgoing_edge_probabilities (b);
}
-
- if (b->count.initialized_p ())
- FOR_EACH_EDGE (e, ei, b->succs)
- e->count = b->count.apply_probability (e->probability);
}
/* Assume that some pass has inserted labels or control flow
@@ -679,9 +672,9 @@ find_many_sub_basic_blocks (sbitmap blocks)
bb->frequency = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
{
- if (e->count.initialized_p ())
+ if (e->count ().initialized_p ())
{
- bb->count += e->count;
+ bb->count += e->count ();
initialized_src = true;
}
else
diff --git a/gcc/cfgcleanup.c b/gcc/cfgcleanup.c
index 365c971..c2b0434 100644
--- a/gcc/cfgcleanup.c
+++ b/gcc/cfgcleanup.c
@@ -558,7 +558,7 @@ try_forward_edges (int mode, basic_block b)
else
{
/* Save the values now, as the edge may get removed. */
- profile_count edge_count = e->count;
+ profile_count edge_count = e->count ();
profile_probability edge_probability = e->probability;
int edge_frequency;
int n = 0;
@@ -616,7 +616,6 @@ try_forward_edges (int mode, basic_block b)
t = single_succ_edge (first);
}
- t->count -= edge_count;
first = t->dest;
}
while (first != target);
@@ -2129,22 +2128,16 @@ try_crossjump_to_edge (int mode, edge e1, edge e2,
break;
}
- s->count += s2->count;
-
/* Take care to update possible forwarder blocks. We verified
that there is no more than one in the chain, so we can't run
into infinite loop. */
if (FORWARDER_BLOCK_P (s->dest))
{
- single_succ_edge (s->dest)->count += s2->count;
- s->dest->count += s2->count;
s->dest->frequency += EDGE_FREQUENCY (s);
}
if (FORWARDER_BLOCK_P (s2->dest))
{
- single_succ_edge (s2->dest)->count -= s2->count;
- s2->dest->count -= s2->count;
s2->dest->frequency -= EDGE_FREQUENCY (s);
if (s2->dest->frequency < 0)
s2->dest->frequency = 0;
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index bd3312e..ec8c845 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -1391,10 +1391,18 @@ expand_one_ssa_partition (tree var)
}
machine_mode reg_mode = promote_ssa_mode (var, NULL);
-
rtx x = gen_reg_rtx (reg_mode);
set_rtl (var, x);
+
+ /* For a promoted variable, X will not be used directly but wrapped in a
+ SUBREG with SUBREG_PROMOTED_VAR_P set, which means that the RTL land
+ will assume that its upper bits can be inferred from its lower bits.
+ Therefore, if X isn't initialized on every path from the entry, then
+ we must do it manually in order to fulfill the above assumption. */
+ if (reg_mode != TYPE_MODE (TREE_TYPE (var))
+ && bitmap_bit_p (SA.partitions_for_undefined_values, part))
+ emit_move_insn (x, CONST0_RTX (reg_mode));
}
/* Record the association between the RTL generated for partition PART
@@ -2025,7 +2033,7 @@ expand_used_vars (void)
/* Compute the phase of the stack frame for this function. */
{
int align = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
- int off = STARTING_FRAME_OFFSET % align;
+ int off = targetm.starting_frame_offset () % align;
frame_phase = off ? align - off : 0;
}
@@ -2507,7 +2515,7 @@ expand_gimple_cond (basic_block bb, gcond *stmt)
dest = false_edge->dest;
redirect_edge_succ (false_edge, new_bb);
false_edge->flags |= EDGE_FALLTHRU;
- new_bb->count = false_edge->count;
+ new_bb->count = false_edge->count ();
new_bb->frequency = EDGE_FREQUENCY (false_edge);
loop_p loop = find_common_loop (bb->loop_father, dest->loop_father);
add_bb_to_loop (new_bb, loop);
@@ -2634,8 +2642,7 @@ expand_call_stmt (gcall *stmt)
CALL_EXPR_RETURN_SLOT_OPT (exp) = gimple_call_return_slot_opt_p (stmt);
if (decl
&& DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
- && (DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA
- || DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA_WITH_ALIGN))
+ && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (decl)))
CALL_ALLOCA_FOR_VAR_P (exp) = gimple_call_alloca_for_var_p (stmt);
else
CALL_FROM_THUNK_P (exp) = gimple_call_from_thunk_p (stmt);
@@ -2659,12 +2666,28 @@ expand_call_stmt (gcall *stmt)
}
}
+ rtx_insn *before_call = get_last_insn ();
lhs = gimple_call_lhs (stmt);
if (lhs)
expand_assignment (lhs, exp, false);
else
expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
+ /* If the gimple call is an indirect call and has 'nocf_check'
+ attribute find a generated CALL insn to mark it as no
+ control-flow verification is needed. */
+ if (gimple_call_nocf_check_p (stmt)
+ && !gimple_call_fndecl (stmt))
+ {
+ rtx_insn *last = get_last_insn ();
+ while (!CALL_P (last)
+ && last != before_call)
+ last = PREV_INSN (last);
+
+ if (last != before_call)
+ add_reg_note (last, REG_CALL_NOCF_CHECK, const0_rtx);
+ }
+
mark_transaction_restart_calls (stmt);
}
@@ -3818,7 +3841,6 @@ expand_gimple_tailcall (basic_block bb, gcall *stmt, bool *can_fallthru)
the exit block. */
probability = profile_probability::never ();
- profile_count count = profile_count::zero ();
for (ei = ei_start (bb->succs); (e = ei_safe_edge (ei)); )
{
@@ -3826,12 +3848,10 @@ expand_gimple_tailcall (basic_block bb, gcall *stmt, bool *can_fallthru)
{
if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
{
- e->dest->count -= e->count;
e->dest->frequency -= EDGE_FREQUENCY (e);
if (e->dest->frequency < 0)
e->dest->frequency = 0;
}
- count += e->count;
probability += e->probability;
remove_edge (e);
}
@@ -3861,7 +3881,6 @@ expand_gimple_tailcall (basic_block bb, gcall *stmt, bool *can_fallthru)
e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_ABNORMAL
| EDGE_SIBCALL);
e->probability = probability;
- e->count = count;
BB_END (bb) = last;
update_bb_for_insn (bb);
@@ -4326,9 +4345,11 @@ expand_debug_expr (tree exp)
if (FLOAT_MODE_P (mode) && FLOAT_MODE_P (inner_mode))
{
- if (GET_MODE_BITSIZE (mode) == GET_MODE_BITSIZE (inner_mode))
+ if (GET_MODE_UNIT_BITSIZE (mode)
+ == GET_MODE_UNIT_BITSIZE (inner_mode))
op0 = simplify_gen_subreg (mode, op0, inner_mode, 0);
- else if (GET_MODE_BITSIZE (mode) < GET_MODE_BITSIZE (inner_mode))
+ else if (GET_MODE_UNIT_BITSIZE (mode)
+ < GET_MODE_UNIT_BITSIZE (inner_mode))
op0 = simplify_gen_unary (FLOAT_TRUNCATE, mode, op0, inner_mode);
else
op0 = simplify_gen_unary (FLOAT_EXTEND, mode, op0, inner_mode);
@@ -4348,9 +4369,12 @@ expand_debug_expr (tree exp)
else
op0 = simplify_gen_unary (FIX, mode, op0, inner_mode);
}
- else if (CONSTANT_P (op0)
- || GET_MODE_PRECISION (mode) <= GET_MODE_PRECISION (inner_mode))
+ else if (GET_MODE_UNIT_PRECISION (mode)
+ == GET_MODE_UNIT_PRECISION (inner_mode))
op0 = lowpart_subreg (mode, op0, inner_mode);
+ else if (GET_MODE_UNIT_PRECISION (mode)
+ < GET_MODE_UNIT_PRECISION (inner_mode))
+ op0 = simplify_gen_unary (TRUNCATE, mode, op0, inner_mode);
else if (UNARY_CLASS_P (exp)
? TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (exp, 0)))
: unsignedp)
@@ -5191,9 +5215,11 @@ expand_debug_source_expr (tree exp)
if (FLOAT_MODE_P (mode) && FLOAT_MODE_P (inner_mode))
{
- if (GET_MODE_BITSIZE (mode) == GET_MODE_BITSIZE (inner_mode))
+ if (GET_MODE_UNIT_BITSIZE (mode)
+ == GET_MODE_UNIT_BITSIZE (inner_mode))
op0 = simplify_gen_subreg (mode, op0, inner_mode, 0);
- else if (GET_MODE_BITSIZE (mode) < GET_MODE_BITSIZE (inner_mode))
+ else if (GET_MODE_UNIT_BITSIZE (mode)
+ < GET_MODE_UNIT_BITSIZE (inner_mode))
op0 = simplify_gen_unary (FLOAT_TRUNCATE, mode, op0, inner_mode);
else
op0 = simplify_gen_unary (FLOAT_EXTEND, mode, op0, inner_mode);
@@ -5207,9 +5233,12 @@ expand_debug_source_expr (tree exp)
else
op0 = simplify_gen_unary (FIX, mode, op0, inner_mode);
}
- else if (CONSTANT_P (op0)
- || GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (inner_mode))
+ else if (GET_MODE_UNIT_PRECISION (mode)
+ == GET_MODE_UNIT_PRECISION (inner_mode))
op0 = lowpart_subreg (mode, op0, inner_mode);
+ else if (GET_MODE_UNIT_PRECISION (mode)
+ < GET_MODE_UNIT_PRECISION (inner_mode))
+ op0 = simplify_gen_unary (TRUNCATE, mode, op0, inner_mode);
else if (TYPE_UNSIGNED (TREE_TYPE (exp)))
op0 = simplify_gen_unary (ZERO_EXTEND, mode, op0, inner_mode);
else
@@ -5927,8 +5956,7 @@ construct_exit_block (void)
FOR_EACH_EDGE (e2, ei, EXIT_BLOCK_PTR_FOR_FN (cfun)->preds)
if (e2 != e)
{
- e->count -= e2->count;
- exit_block->count -= e2->count;
+ exit_block->count -= e2->count ();
exit_block->frequency -= EDGE_FREQUENCY (e2);
}
if (exit_block->frequency < 0)
diff --git a/gcc/cfghooks.c b/gcc/cfghooks.c
index 18dc49a..320036b 100644
--- a/gcc/cfghooks.c
+++ b/gcc/cfghooks.c
@@ -152,6 +152,7 @@ verify_flow_info (void)
bb->index, bb->frequency);
err = 1;
}
+
FOR_EACH_EDGE (e, ei, bb->succs)
{
if (last_visited [e->dest->index] == bb)
@@ -160,15 +161,18 @@ verify_flow_info (void)
e->src->index, e->dest->index);
err = 1;
}
- if (!e->probability.verify ())
+ /* FIXME: Graphite and SLJL and target code still tends to produce
+ edges with no probablity. */
+ if (profile_status_for_fn (cfun) >= PROFILE_GUESSED
+ && !e->probability.initialized_p () && 0)
{
- error ("verify_flow_info: Wrong probability of edge %i->%i",
- e->src->index, e->dest->index);
+ error ("Uninitialized probability of edge %i->%i", e->src->index,
+ e->dest->index);
err = 1;
}
- if (!e->count.verify ())
+ if (!e->probability.verify ())
{
- error ("verify_flow_info: Wrong count of edge %i->%i",
+ error ("verify_flow_info: Wrong probability of edge %i->%i",
e->src->index, e->dest->index);
err = 1;
}
@@ -443,7 +447,6 @@ redirect_edge_succ_nodup (edge e, basic_block new_succ)
{
s->flags |= e->flags;
s->probability += e->probability;
- s->count += e->count;
/* FIXME: This should be called via a hook and only for IR_GIMPLE. */
redirect_edge_var_map_dup (s, e);
remove_edge (e);
@@ -622,7 +625,7 @@ basic_block
split_edge (edge e)
{
basic_block ret;
- profile_count count = e->count;
+ profile_count count = e->count ();
int freq = EDGE_FREQUENCY (e);
edge f;
bool irr = (e->flags & EDGE_IRREDUCIBLE_LOOP) != 0;
@@ -639,7 +642,6 @@ split_edge (edge e)
ret->count = count;
ret->frequency = freq;
single_succ_edge (ret)->probability = profile_probability::always ();
- single_succ_edge (ret)->count = count;
if (irr)
{
@@ -868,7 +870,6 @@ make_forwarder_block (basic_block bb, bool (*redirect_edge_p) (edge),
dummy = fallthru->src;
dummy->count = profile_count::zero ();
dummy->frequency = 0;
- fallthru->count = profile_count::zero ();
bb = fallthru->dest;
/* Redirect back edges we want to keep. */
@@ -882,8 +883,7 @@ make_forwarder_block (basic_block bb, bool (*redirect_edge_p) (edge),
if (dummy->frequency > BB_FREQ_MAX)
dummy->frequency = BB_FREQ_MAX;
- dummy->count += e->count;
- fallthru->count += e->count;
+ dummy->count += e->count ();
ei_next (&ei);
continue;
}
@@ -1069,7 +1069,7 @@ duplicate_block (basic_block bb, edge e, basic_block after)
{
edge s, n;
basic_block new_bb;
- profile_count new_count = e ? e->count : profile_count::uninitialized ();
+ profile_count new_count = e ? e->count (): profile_count::uninitialized ();
edge_iterator ei;
if (!cfg_hooks->duplicate_block)
@@ -1093,13 +1093,6 @@ duplicate_block (basic_block bb, edge e, basic_block after)
is no need to actually check for duplicated edges. */
n = unchecked_make_edge (new_bb, s->dest, s->flags);
n->probability = s->probability;
- if (e && bb->count > profile_count::zero ())
- {
- n->count = s->count.apply_scale (new_count, bb->count);
- s->count -= n->count;
- }
- else
- n->count = s->count;
n->aux = s->aux;
}
@@ -1463,7 +1456,7 @@ account_profile_record (struct profile_record *record, int after_pass)
record->num_mismatched_freq_out[after_pass]++;
profile_count lsum = profile_count::zero ();
FOR_EACH_EDGE (e, ei, bb->succs)
- lsum += e->count;
+ lsum += e->count ();
if (EDGE_COUNT (bb->succs) && (lsum.differs_from_p (bb->count)))
record->num_mismatched_count_out[after_pass]++;
}
@@ -1479,7 +1472,7 @@ account_profile_record (struct profile_record *record, int after_pass)
record->num_mismatched_freq_in[after_pass]++;
profile_count lsum = profile_count::zero ();
FOR_EACH_EDGE (e, ei, bb->preds)
- lsum += e->count;
+ lsum += e->count ();
if (lsum.differs_from_p (bb->count))
record->num_mismatched_count_in[after_pass]++;
}
diff --git a/gcc/cfgloop.c b/gcc/cfgloop.c
index a1e778b..4b0374a 100644
--- a/gcc/cfgloop.c
+++ b/gcc/cfgloop.c
@@ -521,6 +521,58 @@ flow_loops_find (struct loops *loops)
return loops;
}
+/* qsort helper for sort_sibling_loops. */
+
+static int *sort_sibling_loops_cmp_rpo;
+static int
+sort_sibling_loops_cmp (const void *la_, const void *lb_)
+{
+ const struct loop *la = *(const struct loop * const *)la_;
+ const struct loop *lb = *(const struct loop * const *)lb_;
+ return (sort_sibling_loops_cmp_rpo[la->header->index]
+ - sort_sibling_loops_cmp_rpo[lb->header->index]);
+}
+
+/* Sort sibling loops in RPO order. */
+
+void
+sort_sibling_loops (function *fn)
+{
+ /* Match flow_loops_find in the order we sort sibling loops. */
+ sort_sibling_loops_cmp_rpo = XNEWVEC (int, last_basic_block_for_fn (cfun));
+ int *rc_order = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
+ pre_and_rev_post_order_compute_fn (fn, NULL, rc_order, false);
+ for (int i = 0; i < n_basic_blocks_for_fn (cfun) - NUM_FIXED_BLOCKS; ++i)
+ sort_sibling_loops_cmp_rpo[rc_order[i]] = i;
+ free (rc_order);
+
+ auto_vec<loop_p, 3> siblings;
+ loop_p loop;
+ FOR_EACH_LOOP_FN (fn, loop, LI_INCLUDE_ROOT)
+ if (loop->inner && loop->inner->next)
+ {
+ loop_p sibling = loop->inner;
+ do
+ {
+ siblings.safe_push (sibling);
+ sibling = sibling->next;
+ }
+ while (sibling);
+ siblings.qsort (sort_sibling_loops_cmp);
+ loop_p *siblingp = &loop->inner;
+ for (unsigned i = 0; i < siblings.length (); ++i)
+ {
+ *siblingp = siblings[i];
+ siblingp = &(*siblingp)->next;
+ }
+ *siblingp = NULL;
+ siblings.truncate (0);
+ }
+
+ free (sort_sibling_loops_cmp_rpo);
+ sort_sibling_loops_cmp_rpo = NULL;
+}
+
/* Ratio of frequencies of edges so that one of more latch edges is
considered to belong to inner loop with same header. */
#define HEAVY_EDGE_RATIO 8
@@ -547,12 +599,12 @@ find_subloop_latch_edge_by_profile (vec<edge> latches)
FOR_EACH_VEC_ELT (latches, i, e)
{
- if (e->count > mcount)
+ if (e->count ()> mcount)
{
me = e;
- mcount = e->count;
+ mcount = e->count();
}
- tcount += e->count;
+ tcount += e->count();
}
if (!tcount.initialized_p () || tcount < HEAVY_EDGE_MIN_SAMPLES
@@ -1661,12 +1713,19 @@ loop_preheader_edge (const struct loop *loop)
edge e;
edge_iterator ei;
- gcc_assert (loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS));
+ gcc_assert (loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS)
+ && ! loops_state_satisfies_p (LOOPS_MAY_HAVE_MULTIPLE_LATCHES));
FOR_EACH_EDGE (e, ei, loop->header->preds)
if (e->src != loop->latch)
break;
+ if (! e)
+ {
+ gcc_assert (! loop_outer (loop));
+ return single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun));
+ }
+
return e;
}
diff --git a/gcc/cfgloop.h b/gcc/cfgloop.h
index fcf3667..0b164e9 100644
--- a/gcc/cfgloop.h
+++ b/gcc/cfgloop.h
@@ -333,6 +333,7 @@ bool mark_irreducible_loops (void);
void release_recorded_exits (function *);
void record_loop_exits (void);
void rescan_loop_exit (edge, bool, bool);
+void sort_sibling_loops (function *);
/* Loop data structure manipulation/querying. */
extern void flow_loop_tree_node_add (struct loop *, struct loop *);
diff --git a/gcc/cfgloopanal.c b/gcc/cfgloopanal.c
index 73710ab..15b39e3 100644
--- a/gcc/cfgloopanal.c
+++ b/gcc/cfgloopanal.c
@@ -253,9 +253,9 @@ expected_loop_iterations_unbounded (const struct loop *loop,
FOR_EACH_EDGE (e, ei, loop->header->preds)
if (e->src == loop->latch)
- count_latch = e->count;
+ count_latch = e->count ();
else
- count_in += e->count;
+ count_in += e->count ();
if (!count_latch.initialized_p ())
;
diff --git a/gcc/cfgloopmanip.c b/gcc/cfgloopmanip.c
index fd335c3..af65183 100644
--- a/gcc/cfgloopmanip.c
+++ b/gcc/cfgloopmanip.c
@@ -546,16 +546,12 @@ scale_loop_profile (struct loop *loop, profile_probability p,
/* Probability of exit must be 1/iterations. */
freq_delta = EDGE_FREQUENCY (e);
+ count_delta = e->count ();
e->probability = profile_probability::always ()
.apply_scale (1, iteration_bound);
other_e->probability = e->probability.invert ();
freq_delta -= EDGE_FREQUENCY (e);
-
- /* Adjust counts accordingly. */
- count_delta = e->count;
- e->count = e->src->count.apply_probability (e->probability);
- other_e->count = e->src->count.apply_probability (other_e->probability);
- count_delta -= e->count;
+ count_delta -= e->count ();
/* If latch exists, change its frequency and count, since we changed
probability of exit. Theoretically we should update everything from
@@ -582,7 +578,7 @@ scale_loop_profile (struct loop *loop, profile_probability p,
FOR_EACH_EDGE (e, ei, loop->header->preds)
if (e->src != loop->latch)
- count_in += e->count;
+ count_in += e->count ();
if (count_in > profile_count::zero () )
{
@@ -872,14 +868,12 @@ loopify (edge latch_edge, edge header_edge,
struct loop *outer = loop_outer (succ_bb->loop_father);
int freq;
profile_count cnt;
- edge e;
- edge_iterator ei;
loop->header = header_edge->dest;
loop->latch = latch_edge->src;
freq = EDGE_FREQUENCY (header_edge);
- cnt = header_edge->count;
+ cnt = header_edge->count ();
/* Redirect edges. */
loop_redirect_edge (latch_edge, loop->header);
@@ -912,10 +906,6 @@ loopify (edge latch_edge, edge header_edge,
{
switch_bb->frequency = freq;
switch_bb->count = cnt;
- FOR_EACH_EDGE (e, ei, switch_bb->succs)
- {
- e->count = switch_bb->count.apply_probability (e->probability);
- }
}
scale_loop_frequencies (loop, false_scale);
scale_loop_frequencies (succ_bb->loop_father, true_scale);
@@ -1650,8 +1640,6 @@ lv_adjust_loop_entry_edge (basic_block first_head, basic_block second_head,
current_ir_type () == IR_GIMPLE ? EDGE_TRUE_VALUE : 0);
e1->probability = then_prob;
e->probability = else_prob;
- e1->count = e->count.apply_probability (e1->probability);
- e->count = e->count.apply_probability (e->probability);
set_immediate_dominator (CDI_DOMINATORS, first_head, new_head);
set_immediate_dominator (CDI_DOMINATORS, second_head, new_head);
diff --git a/gcc/cfgrtl.c b/gcc/cfgrtl.c
index 6ef47b7..65e25dc 100644
--- a/gcc/cfgrtl.c
+++ b/gcc/cfgrtl.c
@@ -1156,7 +1156,6 @@ try_redirect_by_replacing_jump (edge e, basic_block target, bool in_cfglayout)
e->flags = 0;
e->probability = profile_probability::always ();
- e->count = src->count;
if (e->dest != target)
redirect_edge_succ (e, target);
@@ -1505,9 +1504,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
int prob = XINT (note, 0);
b->probability = profile_probability::from_reg_br_prob_note (prob);
- b->count = e->count.apply_probability (b->probability);
e->probability -= e->probability;
- e->count -= b->count;
}
}
@@ -1615,7 +1612,7 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
if (EDGE_COUNT (e->src->succs) >= 2 || abnormal_edge_flags || asm_goto_edge)
{
rtx_insn *new_head;
- profile_count count = e->count;
+ profile_count count = e->count ();
profile_probability probability = e->probability;
/* Create the new structures. */
@@ -1640,7 +1637,6 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
/* Wire edge in. */
new_edge = make_edge (e->src, jump_block, EDGE_FALLTHRU);
new_edge->probability = probability;
- new_edge->count = count;
/* Redirect old edge. */
redirect_edge_pred (e, jump_block);
@@ -1655,13 +1651,11 @@ force_nonfallthru_and_redirect (edge e, basic_block target, rtx jump_label)
if (asm_goto_edge)
{
new_edge->probability = new_edge->probability.apply_scale (1, 2);
- new_edge->count = new_edge->count.apply_scale (1, 2);
jump_block->count = jump_block->count.apply_scale (1, 2);
jump_block->frequency /= 2;
edge new_edge2 = make_edge (new_edge->src, target,
e->flags & ~EDGE_FALLTHRU);
new_edge2->probability = probability - new_edge->probability;
- new_edge2->count = count - new_edge->count;
}
new_bb = jump_block;
@@ -3155,7 +3149,6 @@ purge_dead_edges (basic_block bb)
if (single_succ_p (bb))
{
single_succ_edge (bb)->probability = profile_probability::always ();
- single_succ_edge (bb)->count = bb->count;
}
else
{
@@ -3168,8 +3161,6 @@ purge_dead_edges (basic_block bb)
b->probability = profile_probability::from_reg_br_prob_note
(XINT (note, 0));
f->probability = b->probability.invert ();
- b->count = bb->count.apply_probability (b->probability);
- f->count = bb->count.apply_probability (f->probability);
}
return purged;
@@ -3221,7 +3212,6 @@ purge_dead_edges (basic_block bb)
gcc_assert (single_succ_p (bb));
single_succ_edge (bb)->probability = profile_probability::always ();
- single_succ_edge (bb)->count = bb->count;
if (dump_file)
fprintf (dump_file, "Purged non-fallthru edges from bb %i\n",
@@ -4906,7 +4896,6 @@ rtl_flow_call_edges_add (sbitmap blocks)
edge ne = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
ne->probability = profile_probability::guessed_never ();
- ne->count = profile_count::guessed_zero ();
}
if (insn == BB_HEAD (bb))
@@ -5039,14 +5028,13 @@ rtl_account_profile_record (basic_block bb, int after_pass,
FOR_BB_INSNS (bb, insn)
if (INSN_P (insn))
{
- record->size[after_pass]
- += insn_rtx_cost (PATTERN (insn), false);
+ record->size[after_pass] += insn_cost (insn, false);
if (bb->count.initialized_p ())
record->time[after_pass]
- += insn_rtx_cost (PATTERN (insn), true) * bb->count.to_gcov_type ();
+ += insn_cost (insn, true) * bb->count.to_gcov_type ();
else if (profile_status_for_fn (cfun) == PROFILE_GUESSED)
record->time[after_pass]
- += insn_rtx_cost (PATTERN (insn), true) * bb->frequency;
+ += insn_cost (insn, true) * bb->frequency;
}
}
diff --git a/gcc/cgraph.c b/gcc/cgraph.c
index 8bffdec..d8da3dd 100644
--- a/gcc/cgraph.c
+++ b/gcc/cgraph.c
@@ -190,30 +190,34 @@ cgraph_node::insert_new_function_version (void)
return version_info_node;
}
-/* Remove the cgraph_function_version_info and cgraph_node for DECL. This
- DECL is a duplicate declaration. */
-void
-cgraph_node::delete_function_version (tree decl)
+/* Remove the cgraph_function_version_info node given by DECL_V. */
+static void
+delete_function_version (cgraph_function_version_info *decl_v)
{
- cgraph_node *decl_node = cgraph_node::get (decl);
- cgraph_function_version_info *decl_v = NULL;
-
- if (decl_node == NULL)
- return;
-
- decl_v = decl_node->function_version ();
-
if (decl_v == NULL)
return;
if (decl_v->prev != NULL)
- decl_v->prev->next = decl_v->next;
+ decl_v->prev->next = decl_v->next;
if (decl_v->next != NULL)
decl_v->next->prev = decl_v->prev;
if (cgraph_fnver_htab != NULL)
cgraph_fnver_htab->remove_elt (decl_v);
+}
+
+/* Remove the cgraph_function_version_info and cgraph_node for DECL. This
+ DECL is a duplicate declaration. */
+void
+cgraph_node::delete_function_version_by_decl (tree decl)
+{
+ cgraph_node *decl_node = cgraph_node::get (decl);
+
+ if (decl_node == NULL)
+ return;
+
+ delete_function_version (decl_node->function_version ());
decl_node->remove ();
}
@@ -622,7 +626,7 @@ cgraph_node::create_thunk (tree alias, tree, bool this_adjusting,
/* Make sure that if VIRTUAL_OFFSET is in sync with VIRTUAL_VALUE. */
gcc_checking_assert (virtual_offset
- ? wi::eq_p (virtual_offset, virtual_value)
+ ? virtual_value == wi::to_wide (virtual_offset)
: virtual_value == 0);
node->thunk.fixed_offset = fixed_offset;
@@ -1844,6 +1848,7 @@ cgraph_node::remove (void)
remove_callers ();
remove_callees ();
ipa_transforms_to_apply.release ();
+ delete_function_version (function_version ());
/* Incremental inlining access removed nodes stored in the postorder list.
*/
diff --git a/gcc/cgraph.h b/gcc/cgraph.h
index 7daca1e..1758e8b 100644
--- a/gcc/cgraph.h
+++ b/gcc/cgraph.h
@@ -1272,7 +1272,7 @@ public:
/* Remove the cgraph_function_version_info and cgraph_node for DECL. This
DECL is a duplicate declaration. */
- static void delete_function_version (tree decl);
+ static void delete_function_version_by_decl (tree decl);
/* Add the function FNDECL to the call graph.
Unlike finalize_function, this function is intended to be used
diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c
index 8c1acf7..ea52f43 100644
--- a/gcc/cgraphunit.c
+++ b/gcc/cgraphunit.c
@@ -1296,6 +1296,93 @@ analyze_functions (bool first_time)
input_location = saved_loc;
}
+/* Check declaration of the type of ALIAS for compatibility with its TARGET
+ (which may be an ifunc resolver) and issue a diagnostic when they are
+ not compatible according to language rules (plus a C++ extension for
+ non-static member functions). */
+
+static void
+maybe_diag_incompatible_alias (tree alias, tree target)
+{
+ tree altype = TREE_TYPE (alias);
+ tree targtype = TREE_TYPE (target);
+
+ bool ifunc = lookup_attribute ("ifunc", DECL_ATTRIBUTES (alias));
+ tree funcptr = altype;
+
+ if (ifunc)
+ {
+ /* Handle attribute ifunc first. */
+ if (TREE_CODE (altype) == METHOD_TYPE)
+ {
+ /* Set FUNCPTR to the type of the alias target. If the type
+ is a non-static member function of class C, construct a type
+ of an ordinary function taking C* as the first argument,
+ followed by the member function argument list, and use it
+ instead to check for incompatibility. This conversion is
+ not defined by the language but an extension provided by
+ G++. */
+
+ tree rettype = TREE_TYPE (altype);
+ tree args = TYPE_ARG_TYPES (altype);
+ altype = build_function_type (rettype, args);
+ funcptr = altype;
+ }
+
+ targtype = TREE_TYPE (targtype);
+
+ if (POINTER_TYPE_P (targtype))
+ {
+ targtype = TREE_TYPE (targtype);
+
+ /* Only issue Wattribute-alias for conversions to void* with
+ -Wextra. */
+ if (VOID_TYPE_P (targtype) && !extra_warnings)
+ return;
+
+ /* Proceed to handle incompatible ifunc resolvers below. */
+ }
+ else
+ {
+ funcptr = build_pointer_type (funcptr);
+
+ error_at (DECL_SOURCE_LOCATION (target),
+ "%<ifunc%> resolver for %qD must return %qT",
+ alias, funcptr);
+ inform (DECL_SOURCE_LOCATION (alias),
+ "resolver indirect function declared here");
+ return;
+ }
+ }
+
+ if ((!FUNC_OR_METHOD_TYPE_P (targtype)
+ || (prototype_p (altype)
+ && prototype_p (targtype)
+ && !types_compatible_p (altype, targtype))))
+ {
+ /* Warn for incompatibilities. Avoid warning for functions
+ without a prototype to make it possible to declare aliases
+ without knowing the exact type, as libstdc++ does. */
+ if (ifunc)
+ {
+ funcptr = build_pointer_type (funcptr);
+
+ if (warning_at (DECL_SOURCE_LOCATION (target),
+ OPT_Wattribute_alias,
+ "%<ifunc%> resolver for %qD should return %qT",
+ alias, funcptr))
+ inform (DECL_SOURCE_LOCATION (alias),
+ "resolver indirect function declared here");
+ }
+ else if (warning_at (DECL_SOURCE_LOCATION (alias),
+ OPT_Wattribute_alias,
+ "%qD alias between functions of incompatible "
+ "types %qT and %qT", alias, altype, targtype))
+ inform (DECL_SOURCE_LOCATION (target),
+ "aliased declaration here");
+ }
+}
+
/* Translate the ugly representation of aliases as alias pairs into nice
representation in callgraph. We don't handle all cases yet,
unfortunately. */
@@ -1305,7 +1392,7 @@ handle_alias_pairs (void)
{
alias_pair *p;
unsigned i;
-
+
for (i = 0; alias_pairs && alias_pairs->iterate (i, &p);)
{
symtab_node *target_node = symtab_node::get_for_asmname (p->target);
@@ -1352,65 +1439,7 @@ handle_alias_pairs (void)
if (TREE_CODE (p->decl) == FUNCTION_DECL
&& target_node && is_a <cgraph_node *> (target_node))
{
- tree t1 = TREE_TYPE (p->decl);
- tree t2 = TREE_TYPE (target_node->decl);
-
- if (lookup_attribute ("ifunc", DECL_ATTRIBUTES (p->decl)))
- {
- t2 = TREE_TYPE (t2);
- if (POINTER_TYPE_P (t2))
- {
- t2 = TREE_TYPE (t2);
- if (!FUNC_OR_METHOD_TYPE_P (t2))
- {
- if (warning_at (DECL_SOURCE_LOCATION (p->decl),
- OPT_Wattributes,
- "%q+D %<ifunc%> resolver should return "
- "a function pointer",
- p->decl))
- inform (DECL_SOURCE_LOCATION (target_node->decl),
- "resolver declaration here");
-
- t2 = NULL_TREE;
- }
- }
- else
- {
- /* Deal with static member function pointers. */
- if (TREE_CODE (t2) == RECORD_TYPE
- && TYPE_FIELDS (t2)
- && TREE_CODE (TREE_TYPE (TYPE_FIELDS (t2))) == POINTER_TYPE
- && (TREE_CODE (TREE_TYPE (TREE_TYPE (TYPE_FIELDS (t2))))
- == METHOD_TYPE))
- t2 = TREE_TYPE (TREE_TYPE (TYPE_FIELDS (t2)));
- else
- {
- error ("%q+D %<ifunc%> resolver must return a function "
- "pointer",
- p->decl);
- inform (DECL_SOURCE_LOCATION (target_node->decl),
- "resolver declaration here");
-
- t2 = NULL_TREE;
- }
- }
- }
-
- if (t2
- && (!FUNC_OR_METHOD_TYPE_P (t2)
- || (prototype_p (t1)
- && prototype_p (t2)
- && !types_compatible_p (t1, t2))))
- {
- /* Warn for incompatibilities. Avoid warning for functions
- without a prototype to make it possible to declare aliases
- without knowing the exact type, as libstdc++ does. */
- if (warning_at (DECL_SOURCE_LOCATION (p->decl), OPT_Wattributes,
- "%q+D alias between functions of incompatible "
- "types %qT and %qT", p->decl, t1, t2))
- inform (DECL_SOURCE_LOCATION (target_node->decl),
- "aliased declaration here");
- }
+ maybe_diag_incompatible_alias (p->decl, target_node->decl);
cgraph_node *src_node = cgraph_node::get (p->decl);
if (src_node && src_node->definition)
@@ -1579,10 +1608,8 @@ init_lowered_empty_function (tree decl, bool in_ssa, profile_count count)
bb->count = count;
bb->frequency = BB_FREQ_MAX;
e = make_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun), bb, EDGE_FALLTHRU);
- e->count = count;
e->probability = profile_probability::always ();
e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
- e->count = count;
e->probability = profile_probability::always ();
add_bb_to_loop (bb, ENTRY_BLOCK_PTR_FOR_FN (cfun)->loop_father);
@@ -1959,17 +1986,14 @@ cgraph_node::expand_thunk (bool output_asm_thunks, bool force_gimple_thunk)
e = make_edge (bb, then_bb, EDGE_TRUE_VALUE);
e->probability = profile_probability::guessed_always ()
.apply_scale (1, 16);
- e->count = count - count.apply_scale (1, 16);
e = make_edge (bb, else_bb, EDGE_FALSE_VALUE);
e->probability = profile_probability::guessed_always ()
.apply_scale (1, 16);
- e->count = count.apply_scale (1, 16);
make_single_succ_edge (return_bb,
EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
make_single_succ_edge (then_bb, return_bb, EDGE_FALLTHRU);
e = make_edge (else_bb, return_bb, EDGE_FALLTHRU);
e->probability = profile_probability::always ();
- e->count = count.apply_scale (1, 16);
bsi = gsi_last_bb (then_bb);
}
diff --git a/gcc/combine-stack-adj.c b/gcc/combine-stack-adj.c
index 9ec14a3..82d6dba 100644
--- a/gcc/combine-stack-adj.c
+++ b/gcc/combine-stack-adj.c
@@ -508,6 +508,8 @@ combine_stack_adjustments_for_block (basic_block bb)
continue;
set = single_set_for_csa (insn);
+ if (set && find_reg_note (insn, REG_STACK_CHECK, NULL_RTX))
+ set = NULL_RTX;
if (set)
{
rtx dest = SET_DEST (set);
diff --git a/gcc/combine.c b/gcc/combine.c
index e502fa1..d71e50f 100644
--- a/gcc/combine.c
+++ b/gcc/combine.c
@@ -311,7 +311,7 @@ static bool optimize_this_for_speed_p;
static int max_uid_known;
-/* The following array records the insn_rtx_cost for every insn
+/* The following array records the insn_cost for every insn
in the instruction stream. */
static int *uid_insn_cost;
@@ -841,7 +841,7 @@ do_SUBST_LINK (struct insn_link **into, struct insn_link *newval)
#define SUBST_LINK(oldval, newval) do_SUBST_LINK (&oldval, newval)
/* Subroutine of try_combine. Determine whether the replacement patterns
- NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_rtx_cost
+ NEWPAT, NEWI2PAT and NEWOTHERPAT are cheaper according to insn_cost
than the original sequence I0, I1, I2, I3 and undobuf.other_insn. Note
that I0, I1 and/or NEWI2PAT may be NULL_RTX. Similarly, NEWOTHERPAT and
undobuf.other_insn may also both be NULL_RTX. Return false if the cost
@@ -856,7 +856,7 @@ combine_validate_cost (rtx_insn *i0, rtx_insn *i1, rtx_insn *i2, rtx_insn *i3,
int new_i2_cost, new_i3_cost;
int old_cost, new_cost;
- /* Lookup the original insn_rtx_costs. */
+ /* Lookup the original insn_costs. */
i2_cost = INSN_COST (i2);
i3_cost = INSN_COST (i3);
@@ -888,11 +888,23 @@ combine_validate_cost (rtx_insn *i0, rtx_insn *i1, rtx_insn *i2, rtx_insn *i3,
old_cost -= i1_cost;
- /* Calculate the replacement insn_rtx_costs. */
- new_i3_cost = insn_rtx_cost (newpat, optimize_this_for_speed_p);
+ /* Calculate the replacement insn_costs. */
+ rtx tmp = PATTERN (i3);
+ PATTERN (i3) = newpat;
+ int tmpi = INSN_CODE (i3);
+ INSN_CODE (i3) = -1;
+ new_i3_cost = insn_cost (i3, optimize_this_for_speed_p);
+ PATTERN (i3) = tmp;
+ INSN_CODE (i3) = tmpi;
if (newi2pat)
{
- new_i2_cost = insn_rtx_cost (newi2pat, optimize_this_for_speed_p);
+ tmp = PATTERN (i2);
+ PATTERN (i2) = newi2pat;
+ tmpi = INSN_CODE (i2);
+ INSN_CODE (i2) = -1;
+ new_i2_cost = insn_cost (i2, optimize_this_for_speed_p);
+ PATTERN (i2) = tmp;
+ INSN_CODE (i2) = tmpi;
new_cost = (new_i2_cost > 0 && new_i3_cost > 0)
? new_i2_cost + new_i3_cost : 0;
}
@@ -907,7 +919,14 @@ combine_validate_cost (rtx_insn *i0, rtx_insn *i1, rtx_insn *i2, rtx_insn *i3,
int old_other_cost, new_other_cost;
old_other_cost = INSN_COST (undobuf.other_insn);
- new_other_cost = insn_rtx_cost (newotherpat, optimize_this_for_speed_p);
+ tmp = PATTERN (undobuf.other_insn);
+ PATTERN (undobuf.other_insn) = newotherpat;
+ tmpi = INSN_CODE (undobuf.other_insn);
+ INSN_CODE (undobuf.other_insn) = -1;
+ new_other_cost = insn_cost (undobuf.other_insn,
+ optimize_this_for_speed_p);
+ PATTERN (undobuf.other_insn) = tmp;
+ INSN_CODE (undobuf.other_insn) = tmpi;
if (old_other_cost > 0 && new_other_cost > 0)
{
old_cost += old_other_cost;
@@ -1208,10 +1227,9 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
set_nonzero_bits_and_sign_copies (XEXP (links, 0), NULL_RTX,
insn);
- /* Record the current insn_rtx_cost of this instruction. */
+ /* Record the current insn_cost of this instruction. */
if (NONJUMP_INSN_P (insn))
- INSN_COST (insn) = insn_rtx_cost (PATTERN (insn),
- optimize_this_for_speed_p);
+ INSN_COST (insn) = insn_cost (insn, optimize_this_for_speed_p);
if (dump_file)
{
fprintf (dump_file, "insn_cost %d for ", INSN_COST (insn));
@@ -1232,6 +1250,12 @@ combine_instructions (rtx_insn *f, unsigned int nregs)
FOR_EACH_BB_FN (this_basic_block, cfun)
{
rtx_insn *last_combined_insn = NULL;
+
+ /* Ignore instruction combination in basic blocks that are going to
+ be removed as unreachable anyway. See PR82386. */
+ if (EDGE_COUNT (this_basic_block->preds) == 0)
+ continue;
+
optimize_this_for_speed_p = optimize_bb_for_speed_p (this_basic_block);
last_call_luid = 0;
mem_last_set = -1;
@@ -2451,6 +2475,12 @@ can_change_dest_mode (rtx x, int added_sets, machine_mode mode)
if (!REG_P (x))
return false;
+ /* Don't change between modes with different underlying register sizes,
+ since this could lead to invalid subregs. */
+ if (REGMODE_NATURAL_SIZE (mode)
+ != REGMODE_NATURAL_SIZE (GET_MODE (x)))
+ return false;
+
regno = REGNO (x);
/* Allow hard registers if the new mode is legal, and occupies no more
registers than the old mode. */
@@ -4075,7 +4105,7 @@ try_combine (rtx_insn *i3, rtx_insn *i2, rtx_insn *i1, rtx_insn *i0,
}
}
- /* Only allow this combination if insn_rtx_costs reports that the
+ /* Only allow this combination if insn_cost reports that the
replacement instructions are cheaper than the originals. */
if (!combine_validate_cost (i0, i1, i2, i3, newpat, newi2pat, other_pat))
{
@@ -5856,7 +5886,7 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
if (GET_CODE (temp) == ASHIFTRT
&& CONST_INT_P (XEXP (temp, 1))
- && INTVAL (XEXP (temp, 1)) == GET_MODE_PRECISION (mode) - 1)
+ && INTVAL (XEXP (temp, 1)) == GET_MODE_UNIT_PRECISION (mode) - 1)
return simplify_shift_const (NULL_RTX, LSHIFTRT, mode, XEXP (temp, 0),
INTVAL (XEXP (temp, 1)));
@@ -6280,7 +6310,8 @@ combine_simplify_rtx (rtx x, machine_mode op0_mode, int in_dest,
SUBST (XEXP (x, 1),
force_to_mode (XEXP (x, 1), GET_MODE (XEXP (x, 1)),
(HOST_WIDE_INT_1U
- << exact_log2 (GET_MODE_BITSIZE (GET_MODE (x))))
+ << exact_log2 (GET_MODE_UNIT_BITSIZE
+ (GET_MODE (x))))
- 1,
0));
break;
@@ -9495,13 +9526,9 @@ rtx_equal_for_field_assignment_p (rtx x, rtx y, bool widen_x)
return 0;
if (BYTES_BIG_ENDIAN != WORDS_BIG_ENDIAN)
return 0;
- /* For big endian, adjust the memory offset. */
- if (BYTES_BIG_ENDIAN)
- x = adjust_address_nv (x, GET_MODE (y),
- -subreg_lowpart_offset (GET_MODE (x),
- GET_MODE (y)));
- else
- x = adjust_address_nv (x, GET_MODE (y), 0);
+ x = adjust_address_nv (x, GET_MODE (y),
+ byte_lowpart_offset (GET_MODE (y),
+ GET_MODE (x)));
}
if (x == y || rtx_equal_p (x, y))
@@ -11594,8 +11621,6 @@ gen_lowpart_for_combine (machine_mode omode, rtx x)
if (MEM_P (x))
{
- int offset = 0;
-
/* Refuse to work on a volatile memory ref or one with a mode-dependent
address. */
if (MEM_VOLATILE_P (x)
@@ -11608,14 +11633,7 @@ gen_lowpart_for_combine (machine_mode omode, rtx x)
if (paradoxical_subreg_p (omode, imode))
return gen_rtx_SUBREG (omode, x, 0);
- if (WORDS_BIG_ENDIAN)
- offset = MAX (isize, UNITS_PER_WORD) - MAX (osize, UNITS_PER_WORD);
-
- /* Adjust the address so that the address-after-the-data is
- unchanged. */
- if (BYTES_BIG_ENDIAN)
- offset -= MIN (UNITS_PER_WORD, osize) - MIN (UNITS_PER_WORD, isize);
-
+ HOST_WIDE_INT offset = byte_lowpart_offset (omode, imode);
return adjust_address_nv (x, omode, offset);
}
@@ -11769,6 +11787,7 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
const_op -= 1;
code = LEU;
/* ... fall through ... */
+ gcc_fallthrough ();
}
/* (unsigned) < 0x80000000 is equivalent to >= 0. */
else if (is_a <scalar_int_mode> (mode, &int_mode)
@@ -11806,6 +11825,7 @@ simplify_compare_const (enum rtx_code code, machine_mode mode,
const_op -= 1;
code = GTU;
/* ... fall through ... */
+ gcc_fallthrough ();
}
/* (unsigned) >= 0x80000000 is equivalent to < 0. */
@@ -11952,10 +11972,9 @@ simplify_comparison (enum rtx_code code, rtx *pop0, rtx *pop1)
if (paradoxical_subreg_p (inner_op0)
&& GET_CODE (inner_op1) == SUBREG
+ && HWI_COMPUTABLE_MODE_P (GET_MODE (SUBREG_REG (inner_op0)))
&& (GET_MODE (SUBREG_REG (inner_op0))
== GET_MODE (SUBREG_REG (inner_op1)))
- && (GET_MODE_PRECISION (GET_MODE (SUBREG_REG (inner_op0)))
- <= HOST_BITS_PER_WIDE_INT)
&& (0 == ((~c0) & nonzero_bits (SUBREG_REG (inner_op0),
GET_MODE (SUBREG_REG (inner_op0)))))
&& (0 == ((~c1) & nonzero_bits (SUBREG_REG (inner_op1),
@@ -13294,7 +13313,7 @@ record_promoted_value (rtx_insn *insn, rtx subreg)
unsigned int regno = REGNO (SUBREG_REG (subreg));
machine_mode mode = GET_MODE (subreg);
- if (GET_MODE_PRECISION (mode) > HOST_BITS_PER_WIDE_INT)
+ if (!HWI_COMPUTABLE_MODE_P (mode))
return;
for (links = LOG_LINKS (insn); links;)
@@ -14161,6 +14180,7 @@ distribute_notes (rtx notes, rtx_insn *from_insn, rtx_insn *i3, rtx_insn *i2,
case REG_SETJMP:
case REG_TM:
case REG_CALL_DECL:
+ case REG_CALL_NOCF_CHECK:
/* These notes must remain with the call. It should not be
possible for both I2 and I3 to be a call. */
if (CALL_P (i3))
diff --git a/gcc/common.opt b/gcc/common.opt
index fa6dd84..836f05b 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -534,13 +534,13 @@ Common RejectNegative Warning Alias(Wextra)
This switch is deprecated; use -Wextra instead.
Wa,
-Driver JoinedOrMissing
+Driver JoinedOrMissing RejectNegative
Wl,
-Driver JoinedOrMissing
+Driver JoinedOrMissing RejectNegative
Wp,
-Driver JoinedOrMissing
+Driver JoinedOrMissing RejectNegative
Waggregate-return
Common Var(warn_aggregate_return) Warning
@@ -562,6 +562,10 @@ Wattributes
Common Var(warn_attributes) Init(1) Warning
Warn about inappropriate attribute usage.
+Wattribute-alias
+Common Var(warn_attributes) Init(1) Warning
+Warn about type safety and similar errors in attribute alias and related.
+
Wcast-align
Common Var(warn_cast_align) Warning
Warn about pointer casts which increase alignment.
@@ -721,6 +725,10 @@ Wstrict-overflow=
Common Joined RejectNegative UInteger Var(warn_strict_overflow) Warning
Warn about optimizations that assume that signed overflow is undefined.
+Wsuggest-attribute=cold
+Common Var(warn_suggest_attribute_cold) Warning
+Warn about functions which might be candidates for __attribute__((cold)).
+
Wsuggest-attribute=const
Common Var(warn_suggest_attribute_const) Warning
Warn about functions which might be candidates for __attribute__((const)).
@@ -1612,6 +1620,29 @@ finline-atomics
Common Report Var(flag_inline_atomics) Init(1) Optimization
Inline __atomic operations when a lock free instruction sequence is available.
+fcf-protection
+Common RejectNegative Alias(fcf-protection=,full)
+
+fcf-protection=
+Common Report Joined RejectNegative Enum(cf_protection_level) Var(flag_cf_protection) Init(CF_NONE)
+-fcf-protection=[full|branch|return|none] Instrument functions with checks to verify jump/call/return control-flow transfer
+instructions have valid targets.
+
+Enum
+Name(cf_protection_level) Type(enum cf_protection_level) UnknownError(unknown Cotrol-Flow Protection Level %qs)
+
+EnumValue
+Enum(cf_protection_level) String(full) Value(CF_FULL)
+
+EnumValue
+Enum(cf_protection_level) String(branch) Value(CF_BRANCH)
+
+EnumValue
+Enum(cf_protection_level) String(return) Value(CF_RETURN)
+
+EnumValue
+Enum(cf_protection_level) String(none) Value(CF_NONE)
+
finstrument-functions
Common Report Var(flag_instrument_function_entry_exit)
Instrument function entry and exit with profiling calls.
@@ -2320,13 +2351,18 @@ Common Report Var(flag_variable_expansion_in_unroller) Optimization
Apply variable expansion when loops are unrolled.
fstack-check=
-Common Report RejectNegative Joined
+Common Report RejectNegative Joined Optimization
-fstack-check=[no|generic|specific] Insert stack checking code into the program.
fstack-check
Common Alias(fstack-check=, specific, no)
Insert stack checking code into the program. Same as -fstack-check=specific.
+fstack-clash-protection
+Common Report Var(flag_stack_clash_protection) Optimization
+Insert code to probe each page of stack space as it is allocated to protect
+from stack-clash style attacks.
+
fstack-limit
Common Var(common_deferred_options) Defer
@@ -2829,19 +2865,15 @@ Common Report Var(flag_zero_initialized_in_bss) Init(1)
Put zero initialized data in the bss section.
g
-Common Driver JoinedOrMissing
+Common Driver RejectNegative JoinedOrMissing
Generate debug information in default format.
gcoff
Common Driver JoinedOrMissing Negative(gdwarf)
Generate debug information in COFF format.
-gno-column-info
-Common Driver RejectNegative Var(debug_column_info,0) Init(0)
-Don't record DW_AT_decl_column and DW_AT_call_column in DWARF.
-
gcolumn-info
-Common Driver RejectNegative Var(debug_column_info,1)
+Common Driver Var(debug_column_info,1) Init(1)
Record DW_AT_decl_column and DW_AT_call_column in DWARF.
gdwarf
@@ -2856,6 +2888,10 @@ ggdb
Common Driver JoinedOrMissing
Generate debug information in default extended format.
+gno-
+RejectNegative Joined Undocumented
+; Catch the gno- prefix, so it doesn't backtrack to g<level>.
+
gno-pubnames
Common Driver Negative(gpubnames) Var(debug_generate_pub_sections, 0) Init(-1)
Don't generate DWARF pubnames and pubtypes sections.
@@ -2868,20 +2904,12 @@ ggnu-pubnames
Common Driver Negative(gno-pubnames) Var(debug_generate_pub_sections, 2)
Generate DWARF pubnames and pubtypes sections with GNU extensions.
-gno-record-gcc-switches
-Common Driver RejectNegative Var(dwarf_record_gcc_switches,0) Init(1)
-Don't record gcc command line switches in DWARF DW_AT_producer.
-
grecord-gcc-switches
-Common Driver RejectNegative Var(dwarf_record_gcc_switches,1)
+Common Driver Var(dwarf_record_gcc_switches) Init(1)
Record gcc command line switches in DWARF DW_AT_producer.
-gno-split-dwarf
-Common Driver RejectNegative Var(dwarf_split_debug_info,0) Init(0)
-Don't generate debug information in separate .dwo files.
-
gsplit-dwarf
-Common Driver RejectNegative Var(dwarf_split_debug_info,1)
+Common Driver Var(dwarf_split_debug_info) Init(0)
Generate debug information in separate .dwo files.
gstabs
@@ -2892,12 +2920,8 @@ gstabs+
Common Driver JoinedOrMissing Negative(gvms)
Generate debug information in extended STABS format.
-gno-strict-dwarf
-Common Driver RejectNegative Var(dwarf_strict,0) Init(0)
-Emit DWARF additions beyond selected version.
-
gstrict-dwarf
-Common Driver Report RejectNegative Var(dwarf_strict,1)
+Common Driver Report Var(dwarf_strict) Init(0)
Don't emit DWARF additions beyond selected version.
gtoggle
@@ -2935,7 +2959,7 @@ Common Driver
Generate compressed debug sections.
gz=
-Common Driver Joined Enum(compressed_debug_sections)
+Common Driver RejectNegative Joined Enum(compressed_debug_sections)
-gz=<format> Generate compressed debug sections in format <format>.
h
diff --git a/gcc/common/config/arm/arm-common.c b/gcc/common/config/arm/arm-common.c
index 38bd3a7..1588ca8 100644
--- a/gcc/common/config/arm/arm-common.c
+++ b/gcc/common/config/arm/arm-common.c
@@ -63,7 +63,13 @@ arm_except_unwind_info (struct gcc_options *opts)
return UI_TARGET;
}
- /* ... we use sjlj exceptions for backwards compatibility. */
+ /* ... honor target configurations requesting DWARF2 EH... */
+#ifdef DWARF2_UNWIND_INFO
+ if (DWARF2_UNWIND_INFO)
+ return UI_DWARF2;
+#endif
+
+ /* ... or fallback to sjlj exceptions for backwards compatibility. */
return UI_SJLJ;
}
@@ -574,7 +580,7 @@ arm_canon_arch_option (int argc, const char **argv)
{
/* The easiest and safest way to remove the default fpu
capabilities is to look for a '+no..' option that removes
- the base FPU bit (isa_bit_VFPv2). If that doesn't exist
+ the base FPU bit (isa_bit_vfpv2). If that doesn't exist
then the best we can do is strip out all the bits that
might be part of the most capable FPU we know about,
which is "crypto-neon-fp-armv8". */
@@ -586,7 +592,7 @@ arm_canon_arch_option (int argc, const char **argv)
++ext)
{
if (ext->remove
- && check_isa_bits_for (ext->isa_bits, isa_bit_VFPv2))
+ && check_isa_bits_for (ext->isa_bits, isa_bit_vfpv2))
{
arm_initialize_isa (fpu_isa, ext->isa_bits);
bitmap_and_compl (target_isa, target_isa, fpu_isa);
@@ -620,7 +626,7 @@ arm_canon_arch_option (int argc, const char **argv)
{
/* Clearing the VFPv2 bit is sufficient to stop any extention that
builds on the FPU from matching. */
- bitmap_clear_bit (target_isa, isa_bit_VFPv2);
+ bitmap_clear_bit (target_isa, isa_bit_vfpv2);
}
/* If we don't have a selected architecture by now, something's
@@ -692,8 +698,8 @@ arm_canon_arch_option (int argc, const char **argv)
capable FPU variant that we do support. This is sufficient for
multilib selection. */
- if (bitmap_bit_p (target_isa_unsatisfied, isa_bit_VFPv2)
- && bitmap_bit_p (fpu_isa, isa_bit_VFPv2))
+ if (bitmap_bit_p (target_isa_unsatisfied, isa_bit_vfpv2)
+ && bitmap_bit_p (fpu_isa, isa_bit_vfpv2))
{
std::list<candidate_extension *>::iterator ipoint = extensions.begin ();
diff --git a/gcc/common/config/i386/i386-common.c b/gcc/common/config/i386/i386-common.c
index 4185176..ada918e 100644
--- a/gcc/common/config/i386/i386-common.c
+++ b/gcc/common/config/i386/i386-common.c
@@ -137,6 +137,9 @@ along with GCC; see the file COPYING3. If not see
#define OPTION_MASK_ISA_CLZERO_SET OPTION_MASK_ISA_CLZERO
#define OPTION_MASK_ISA_PKU_SET OPTION_MASK_ISA_PKU
#define OPTION_MASK_ISA_RDPID_SET OPTION_MASK_ISA_RDPID
+#define OPTION_MASK_ISA_GFNI_SET OPTION_MASK_ISA_GFNI
+#define OPTION_MASK_ISA_IBT_SET OPTION_MASK_ISA_IBT
+#define OPTION_MASK_ISA_SHSTK_SET OPTION_MASK_ISA_SHSTK
/* Define a set of ISAs which aren't available when a given ISA is
disabled. MMX and SSE ISAs are handled separately. */
@@ -202,6 +205,9 @@ along with GCC; see the file COPYING3. If not see
#define OPTION_MASK_ISA_CLZERO_UNSET OPTION_MASK_ISA_CLZERO
#define OPTION_MASK_ISA_PKU_UNSET OPTION_MASK_ISA_PKU
#define OPTION_MASK_ISA_RDPID_UNSET OPTION_MASK_ISA_RDPID
+#define OPTION_MASK_ISA_GFNI_UNSET OPTION_MASK_ISA_GFNI
+#define OPTION_MASK_ISA_IBT_UNSET OPTION_MASK_ISA_IBT
+#define OPTION_MASK_ISA_SHSTK_UNSET OPTION_MASK_ISA_SHSTK
/* SSE4 includes both SSE4.1 and SSE4.2. -mno-sse4 should the same
as -mno-sse4.1. */
@@ -484,6 +490,48 @@ ix86_handle_option (struct gcc_options *opts,
}
return true;
+ case OPT_mgfni:
+ if (value)
+ {
+ opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA_GFNI_SET;
+ opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA_GFNI_SET;
+ }
+ else
+ {
+ opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA_GFNI_UNSET;
+ opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA_GFNI_UNSET;
+ }
+ return true;
+
+ case OPT_mcet:
+ case OPT_mibt:
+ if (value)
+ {
+ opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA_IBT_SET;
+ opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA_IBT_SET;
+ }
+ else
+ {
+ opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA_IBT_UNSET;
+ opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA_IBT_UNSET;
+ }
+ if (code != OPT_mcet)
+ return true;
+ /* fall through. */
+
+ case OPT_mshstk:
+ if (value)
+ {
+ opts->x_ix86_isa_flags2 |= OPTION_MASK_ISA_SHSTK_SET;
+ opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA_SHSTK_SET;
+ }
+ else
+ {
+ opts->x_ix86_isa_flags2 &= ~OPTION_MASK_ISA_SHSTK_UNSET;
+ opts->x_ix86_isa_flags2_explicit |= OPTION_MASK_ISA_SHSTK_UNSET;
+ }
+ return true;
+
case OPT_mavx5124fmaps:
if (value)
{
diff --git a/gcc/compare-elim.c b/gcc/compare-elim.c
index 7e557a2..086fbc7 100644
--- a/gcc/compare-elim.c
+++ b/gcc/compare-elim.c
@@ -65,6 +65,7 @@ along with GCC; see the file COPYING3. If not see
#include "tm_p.h"
#include "insn-config.h"
#include "recog.h"
+#include "emit-rtl.h"
#include "cfgrtl.h"
#include "tree-pass.h"
#include "domwalk.h"
@@ -579,6 +580,143 @@ equivalent_reg_at_start (rtx reg, rtx_insn *end, rtx_insn *start)
return reg;
}
+/* Return true if it is okay to merge the comparison CMP_INSN with
+ the instruction ARITH_INSN. Both instructions are assumed to be in the
+ same basic block with ARITH_INSN appearing before CMP_INSN. This checks
+ that there are no uses or defs of the condition flags or control flow
+ changes between the two instructions. */
+
+static bool
+can_merge_compare_into_arith (rtx_insn *cmp_insn, rtx_insn *arith_insn)
+{
+ for (rtx_insn *insn = PREV_INSN (cmp_insn);
+ insn && insn != arith_insn;
+ insn = PREV_INSN (insn))
+ {
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+ /* Bail if there are jumps or calls in between. */
+ if (!NONJUMP_INSN_P (insn))
+ return false;
+
+ /* Bail on old-style asm statements because they lack
+ data flow information. */
+ if (GET_CODE (PATTERN (insn)) == ASM_INPUT)
+ return false;
+
+ df_ref ref;
+ /* Find a USE of the flags register. */
+ FOR_EACH_INSN_USE (ref, insn)
+ if (DF_REF_REGNO (ref) == targetm.flags_regnum)
+ return false;
+
+ /* Find a DEF of the flags register. */
+ FOR_EACH_INSN_DEF (ref, insn)
+ if (DF_REF_REGNO (ref) == targetm.flags_regnum)
+ return false;
+ }
+ return true;
+}
+
+/* Given two SET expressions, SET_A and SET_B determine whether they form
+ a recognizable pattern when emitted in parallel. Return that parallel
+ if so. Otherwise return NULL. */
+
+static rtx
+try_validate_parallel (rtx set_a, rtx set_b)
+{
+ rtx par
+ = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, set_a, set_b));
+
+ rtx_insn *insn;
+ insn = gen_rtx_INSN (VOIDmode, 0, 0, 0, par, 0, -1, 0);
+
+ return recog_memoized (insn) > 0 ? par : NULL_RTX;
+}
+
+/* For a comparison instruction described by CMP check if it compares a
+ register with zero i.e. it is of the form CC := CMP R1, 0.
+ If it is, find the instruction defining R1 (say I1) and try to create a
+ PARALLEL consisting of I1 and the comparison, representing a flag-setting
+ arithmetic instruction. Example:
+ I1: R1 := R2 + R3
+ <instructions that don't read the condition register>
+ I2: CC := CMP R1 0
+ I2 can be merged with I1 into:
+ I1: { R1 := R2 + R3 ; CC := CMP (R2 + R3) 0 }
+ This catches cases where R1 is used between I1 and I2 and therefore
+ combine and other RTL optimisations will not try to propagate it into
+ I2. Return true if we succeeded in merging CMP. */
+
+static bool
+try_merge_compare (struct comparison *cmp)
+{
+ rtx_insn *cmp_insn = cmp->insn;
+
+ if (!REG_P (cmp->in_a) || cmp->in_b != const0_rtx)
+ return false;
+ rtx in_a = cmp->in_a;
+ df_ref use;
+
+ FOR_EACH_INSN_USE (use, cmp_insn)
+ if (DF_REF_REGNO (use) == REGNO (in_a))
+ break;
+ if (!use)
+ return false;
+
+ /* Validate the data flow information before attempting to
+ find the instruction that defines in_a. */
+
+ struct df_link *ref_chain;
+ ref_chain = DF_REF_CHAIN (use);
+ if (!ref_chain || !ref_chain->ref
+ || !DF_REF_INSN_INFO (ref_chain->ref) || ref_chain->next != NULL)
+ return false;
+
+ rtx_insn *def_insn = DF_REF_INSN (ref_chain->ref);
+ /* We found the insn that defines in_a. Only consider the cases where
+ it is in the same block as the comparison. */
+ if (BLOCK_FOR_INSN (cmp_insn) != BLOCK_FOR_INSN (def_insn))
+ return false;
+
+ rtx set = single_set (def_insn);
+ if (!set)
+ return false;
+
+ if (!can_merge_compare_into_arith (cmp_insn, def_insn))
+ return false;
+
+ rtx src = SET_SRC (set);
+ rtx flags = maybe_select_cc_mode (cmp, src, CONST0_RTX (GET_MODE (src)));
+ if (!flags)
+ {
+ /* We may already have a change group going through maybe_select_cc_mode.
+ Discard it properly. */
+ cancel_changes (0);
+ return false;
+ }
+
+ rtx flag_set
+ = gen_rtx_SET (flags, gen_rtx_COMPARE (GET_MODE (flags),
+ copy_rtx (src),
+ CONST0_RTX (GET_MODE (src))));
+ rtx arith_set = copy_rtx (PATTERN (def_insn));
+ rtx par = try_validate_parallel (flag_set, arith_set);
+ if (!par)
+ {
+ /* We may already have a change group going through maybe_select_cc_mode.
+ Discard it properly. */
+ cancel_changes (0);
+ return false;
+ }
+ if (!apply_change_group ())
+ return false;
+ emit_insn_after (par, def_insn);
+ delete_insn (def_insn);
+ delete_insn (cmp->insn);
+ return true;
+}
+
/* Attempt to replace a comparison with a prior arithmetic insn that can
compute the same flags value as the comparison itself. Return true if
successful, having made all rtl modifications necessary. */
@@ -588,6 +726,9 @@ try_eliminate_compare (struct comparison *cmp)
{
rtx flags, in_a, in_b, cmp_src;
+ if (try_merge_compare (cmp))
+ return true;
+
/* We must have found an interesting "clobber" preceding the compare. */
if (cmp->prev_clobber == NULL)
return false;
@@ -714,6 +855,7 @@ try_eliminate_compare (struct comparison *cmp)
static unsigned int
execute_compare_elim_after_reload (void)
{
+ df_chain_add_problem (DF_UD_CHAIN + DF_DU_CHAIN);
df_analyze ();
gcc_checking_assert (!all_compares.exists ());
diff --git a/gcc/config.gcc b/gcc/config.gcc
index 630832f..c3dab84 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -360,6 +360,7 @@ i[34567]86-*-*)
cpu_type=i386
c_target_objs="i386-c.o"
cxx_target_objs="i386-c.o"
+ extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o"
extra_options="${extra_options} fused-madd.opt"
extra_headers="cpuid.h mmintrin.h mm3dnow.h xmmintrin.h emmintrin.h
pmmintrin.h tmmintrin.h ammintrin.h smmintrin.h
@@ -377,13 +378,14 @@ i[34567]86-*-*)
avx512ifmaintrin.h avx512ifmavlintrin.h avx512vbmiintrin.h
avx512vbmivlintrin.h avx5124fmapsintrin.h avx5124vnniwintrin.h
avx512vpopcntdqintrin.h clwbintrin.h mwaitxintrin.h
- clzerointrin.h pkuintrin.h sgxintrin.h"
+ clzerointrin.h pkuintrin.h sgxintrin.h cetintrin.h"
;;
x86_64-*-*)
cpu_type=i386
c_target_objs="i386-c.o"
cxx_target_objs="i386-c.o"
extra_options="${extra_options} fused-madd.opt"
+ extra_objs="x86-tune-sched.o x86-tune-sched-bd.o x86-tune-sched-atom.o x86-tune-sched-core.o"
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
@@ -400,7 +402,7 @@ x86_64-*-*)
avx512ifmaintrin.h avx512ifmavlintrin.h avx512vbmiintrin.h
avx512vbmivlintrin.h avx5124fmapsintrin.h avx5124vnniwintrin.h
avx512vpopcntdqintrin.h clwbintrin.h mwaitxintrin.h
- clzerointrin.h pkuintrin.h sgxintrin.h"
+ clzerointrin.h pkuintrin.h sgxintrin.h cetintrin.h"
;;
ia64-*-*)
extra_headers=ia64intrin.h
@@ -461,6 +463,7 @@ powerpc*-*-*)
extra_headers="${extra_headers} mmintrin.h x86intrin.h"
extra_headers="${extra_headers} ppu_intrinsics.h spu2vmx.h vec_types.h si2vmx.h"
extra_headers="${extra_headers} paired.h"
+ extra_headers="${extra_headers} amo.h"
case x$with_cpu in
xpowerpc64|xdefault64|x6[23]0|x970|xG5|xpower[3456789]|xpower6x|xrs64a|xcell|xa2|xe500mc64|xe5500|xe6500)
cpu_is_64bit=yes
@@ -593,7 +596,7 @@ x86_64-*-*)
tm_file="vxworks-dummy.h ${tm_file}"
;;
arm*-*-*)
- tm_p_file="arm/arm-flags.h arm/arm-isa.h ${tm_p_file} arm/aarch-common-protos.h"
+ tm_p_file="arm/arm-flags.h ${tm_p_file} arm/aarch-common-protos.h"
tm_file="vxworks-dummy.h ${tm_file}"
;;
mips*-*-* | sh*-*-* | sparc*-*-*)
@@ -623,7 +626,7 @@ pentium4 pentium4m pentiumpro prescott lakemont"
x86_64_archs="amdfam10 athlon64 athlon64-sse3 barcelona bdver1 bdver2 \
bdver3 bdver4 znver1 btver1 btver2 k8 k8-sse3 opteron opteron-sse3 nocona \
core2 corei7 corei7-avx core-avx-i core-avx2 atom slm nehalem westmere \
-sandybridge ivybridge haswell broadwell bonnell silvermont knl \
+sandybridge ivybridge haswell broadwell bonnell silvermont knl knm \
skylake-avx512 x86-64 native"
# Additional x86 processors supported by --with-cpu=. Each processor
@@ -792,13 +795,16 @@ case ${target} in
target_has_targetcm=yes
;;
*-*-netbsd*)
- tmake_file="t-slibgcc"
+ tm_p_file="${tm_p_file} netbsd-protos.h"
+ tmake_file="t-netbsd t-slibgcc"
+ extra_objs="${extra_objs} netbsd.o"
gas=yes
gnu_ld=yes
use_gcc_stdint=wrap
case ${enable_threads} in
"" | yes | posix) thread_file='posix' ;;
esac
+ nbsd_tm_file="netbsd.h netbsd-stdint.h netbsd-elf.h"
default_use_cxa_atexit=yes
;;
*-*-openbsd*)
@@ -868,7 +874,7 @@ case ${target} in
tmake_file="${tmake_file} t-sol2 t-slibgcc"
c_target_objs="${c_target_objs} sol2-c.o"
cxx_target_objs="${cxx_target_objs} sol2-c.o sol2-cxx.o"
- extra_objs="sol2.o sol2-stubs.o"
+ extra_objs="${extra_objs} sol2.o sol2-stubs.o"
extra_options="${extra_options} sol2.opt"
case ${enable_threads}:${have_pthread_h}:${have_thread_h} in
"":yes:* | yes:yes:* )
@@ -1002,7 +1008,7 @@ alpha*-*-freebsd*)
extra_options="${extra_options} alpha/elf.opt"
;;
alpha*-*-netbsd*)
- tm_file="elfos.h ${tm_file} netbsd.h alpha/elf.h netbsd-elf.h alpha/netbsd.h"
+ tm_file="elfos.h ${tm_file} ${nbsd_tm_file} alpha/elf.h alpha/netbsd.h"
tmake_file="${tmake_file} alpha/t-alpha"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt \
alpha/elf.opt"
@@ -1090,11 +1096,14 @@ arm*-*-freebsd*) # ARM FreeBSD EABI
case $target in
armv6*-*-freebsd*)
target_cpu_cname="arm1176jzf-s"
- tm_defines="${tm_defines} TARGET_FREEBSD_ARMv6=1"
if test $fbsd_major -ge 11; then
tm_defines="${tm_defines} TARGET_FREEBSD_ARM_HARD_FLOAT=1"
fi
;;
+ armv7*-*-freebsd*)
+ target_cpu_cname="generic-armv7-a"
+ tm_defines="${tm_defines} TARGET_FREEBSD_ARM_HARD_FLOAT=1"
+ ;;
*)
target_cpu_cname="arm9"
;;
@@ -1102,7 +1111,7 @@ arm*-*-freebsd*) # ARM FreeBSD EABI
with_tls=${with_tls:-gnu}
;;
arm*-*-netbsdelf*)
- tm_file="dbxelf.h elfos.h netbsd.h netbsd-elf.h arm/elf.h arm/aout.h ${tm_file} arm/netbsd-elf.h"
+ tm_file="dbxelf.h elfos.h ${nbsd_tm_file} arm/elf.h arm/aout.h ${tm_file} arm/netbsd-elf.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
tmake_file="${tmake_file} arm/t-arm"
target_cpu_cname="arm6"
@@ -1487,11 +1496,11 @@ x86_64-*-freebsd*)
tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h ${fbsd_tm_file} i386/x86-64.h i386/freebsd.h i386/freebsd64.h"
;;
i[34567]86-*-netbsdelf*)
- tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h netbsd.h netbsd-stdint.h netbsd-elf.h i386/netbsd-elf.h"
+ tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h ${nbsd_tm_file} i386/netbsd-elf.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
;;
x86_64-*-netbsd*)
- tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h netbsd.h netbsd-stdint.h netbsd-elf.h i386/x86-64.h i386/netbsd64.h"
+ tm_file="${tm_file} i386/unix.h i386/att.h dbxelf.h elfos.h ${nbsd_tm_file} i386/x86-64.h i386/netbsd64.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
;;
i[34567]86-*-openbsd*)
@@ -1516,14 +1525,6 @@ i[34567]86-*-linux* | i[34567]86-*-kfreebsd*-gnu | i[34567]86-*-gnu* | i[34567]8
i[34567]86-*-linux*)
tm_file="${tm_file} linux.h linux-android.h"
extra_options="${extra_options} linux-android.opt"
- # Assume modern glibc if not targeting Android nor uclibc.
- case ${target} in
- *-*-*android*|*-*-*uclibc*|*-*-*musl*)
- ;;
- *)
- default_gnu_indirect_function=yes
- ;;
- esac
if test x$enable_targets = xall; then
tm_file="${tm_file} i386/x86-64.h i386/gnu-user-common.h i386/gnu-user64.h i386/linux-common.h i386/linux64.h"
tm_defines="${tm_defines} TARGET_BI_ARCH=1"
@@ -1582,14 +1583,6 @@ x86_64-*-linux* | x86_64-*-kfreebsd*-gnu)
x86_64-*-linux*)
tm_file="${tm_file} linux.h linux-android.h i386/linux-common.h i386/linux64.h"
extra_options="${extra_options} linux-android.opt"
- # Assume modern glibc if not targeting Android nor uclibc.
- case ${target} in
- *-*-*android*|*-*-*uclibc*|*-*-*musl*)
- ;;
- *)
- default_gnu_indirect_function=yes
- ;;
- esac
;;
x86_64-*-kfreebsd*-gnu)
tm_file="${tm_file} kfreebsd-gnu.h i386/kfreebsd-gnu64.h"
@@ -1699,7 +1692,7 @@ i[34567]86-*-cygwin*)
tmake_file="${tmake_file} i386/t-cygming t-slibgcc"
target_gtfiles="\$(srcdir)/config/i386/winnt.c"
extra_options="${extra_options} i386/cygming.opt i386/cygwin.opt"
- extra_objs="winnt.o winnt-stubs.o"
+ extra_objs="${extra_objs} winnt.o winnt-stubs.o"
c_target_objs="${c_target_objs} msformat-c.o"
cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o"
if test x$enable_threads = xyes; then
@@ -1715,7 +1708,7 @@ x86_64-*-cygwin*)
tmake_file="${tmake_file} i386/t-cygming t-slibgcc i386/t-cygwin-w64"
target_gtfiles="\$(srcdir)/config/i386/winnt.c"
extra_options="${extra_options} i386/cygming.opt i386/cygwin.opt"
- extra_objs="winnt.o winnt-stubs.o"
+ extra_objs="${extra_objs} winnt.o winnt-stubs.o"
c_target_objs="${c_target_objs} msformat-c.o"
cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o"
if test x$enable_threads = xyes; then
@@ -1790,7 +1783,7 @@ i[34567]86-*-mingw* | x86_64-*-mingw*)
*)
;;
esac
- extra_objs="winnt.o winnt-stubs.o"
+ extra_objs="${extra_objs} winnt.o winnt-stubs.o"
c_target_objs="${c_target_objs} msformat-c.o"
cxx_target_objs="${cxx_target_objs} winnt-cxx.o msformat-c.o"
gas=yes
@@ -1945,9 +1938,9 @@ m68k-*-elf* | fido-*-elf*)
m68k*-*-netbsdelf*)
default_m68k_cpu=68020
default_cf_cpu=5475
- tm_file="${tm_file} dbxelf.h elfos.h netbsd.h netbsd-elf.h m68k/netbsd-elf.h"
+ tm_file="${tm_file} dbxelf.h elfos.h ${nbsd_tm_file} m68k/netbsd-elf.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
- tm_defines="${tm_defines} MOTOROLA=1"
+ tm_defines="${tm_defines} MOTOROLA=1 CHAR_FAST8=1 SHORT_FAST16=1"
;;
m68k*-*-openbsd*)
default_m68k_cpu=68020
@@ -2074,7 +2067,7 @@ riscv*-*-elf* | riscv*-*-rtems*)
;;
mips*-*-netbsd*) # NetBSD/mips, either endian.
target_cpu_default="MASK_ABICALLS"
- tm_file="elfos.h ${tm_file} mips/elf.h netbsd.h netbsd-elf.h mips/netbsd.h"
+ tm_file="elfos.h ${tm_file} mips/elf.h ${nbsd_tm_file} mips/netbsd.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
;;
mips*-img-linux*)
@@ -2390,7 +2383,7 @@ powerpc*-*-freebsd*)
esac
;;
powerpc-*-netbsd*)
- tm_file="${tm_file} dbxelf.h elfos.h netbsd.h netbsd-elf.h freebsd-spec.h rs6000/sysv4.h rs6000/netbsd.h"
+ tm_file="${tm_file} dbxelf.h elfos.h ${nbsd_tm_file} freebsd-spec.h rs6000/sysv4.h rs6000/netbsd.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
tmake_file="${tmake_file} rs6000/t-netbsd"
extra_options="${extra_options} rs6000/sysv4.opt"
@@ -2455,7 +2448,6 @@ powerpc*-*-linux*spe*)
tm_file="${tm_file} powerpcspe/linux.h glibc-stdint.h"
tmake_file="${tmake_file} powerpcspe/t-ppcos powerpcspe/t-linux"
tm_file="${tm_file} powerpcspe/linuxspe.h powerpcspe/e500.h"
- default_gnu_indirect_function=yes
;;
powerpc*-*-linux*)
tm_file="${tm_file} dbxelf.h elfos.h gnu-user.h freebsd-spec.h rs6000/sysv4.h"
@@ -2535,14 +2527,6 @@ powerpc*-*-linux*)
if test x${enable_secureplt} = xyes; then
tm_file="rs6000/secureplt.h ${tm_file}"
fi
- # Assume modern glibc if not targeting Android nor uclibc.
- case ${target} in
- *-*-*android*|*-*-*uclibc*|*-*-*musl*)
- ;;
- *)
- default_gnu_indirect_function=yes
- ;;
- esac
;;
powerpc-wrs-vxworks*spe)
tm_file="${tm_file} elfos.h freebsd-spec.h powerpcspe/sysv4.h"
@@ -2649,7 +2633,7 @@ rs6000-ibm-aix[789].* | powerpc-ibm-aix[789].*)
use_collect2=yes
thread_file='aix'
use_gcc_stdint=wrap
- extra_headers=altivec.h
+ extra_headers="altivec.h amo.h"
default_use_cxa_atexit=yes
;;
rl78-*-elf*)
@@ -2664,7 +2648,6 @@ rx-*-elf*)
tmake_file="${tmake_file} rx/t-rx"
;;
s390-*-linux*)
- default_gnu_indirect_function=yes
tm_file="s390/s390.h dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h s390/linux.h"
c_target_objs="${c_target_objs} s390-c.o"
cxx_target_objs="${cxx_target_objs} s390-c.o"
@@ -2674,7 +2657,6 @@ s390-*-linux*)
tmake_file="${tmake_file} s390/t-s390"
;;
s390x-*-linux*)
- default_gnu_indirect_function=yes
tm_file="s390/s390x.h s390/s390.h dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h s390/linux.h"
tm_p_file="linux-protos.h s390/s390-protos.h"
c_target_objs="${c_target_objs} s390-c.o"
@@ -2732,7 +2714,7 @@ sh-*-elf* | sh[12346l]*-*-elf* | \
fi
tm_file="${tm_file} gnu-user.h linux.h glibc-stdint.h sh/linux.h" ;;
sh*-*-netbsd*)
- tm_file="${tm_file} netbsd.h netbsd-elf.h sh/netbsd-elf.h"
+ tm_file="${tm_file} ${nbsd_tm_file} sh/netbsd-elf.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
;;
@@ -2892,7 +2874,7 @@ sparc-*-linux*)
fi
;;
sparc-*-netbsdelf*)
- tm_file="${tm_file} dbxelf.h elfos.h sparc/sysv4.h netbsd.h netbsd-elf.h sparc/netbsd-elf.h"
+ tm_file="${tm_file} dbxelf.h elfos.h sparc/sysv4.h ${nbsd_tm_file} sparc/netbsd-elf.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
extra_options="${extra_options} sparc/long-double-switch.opt"
tmake_file="${tmake_file} sparc/t-sparc"
@@ -2940,7 +2922,7 @@ sparc64-*-freebsd*|ultrasparc-*-freebsd*)
;;
sparc64-*-netbsd*)
tm_file="sparc/biarch64.h ${tm_file}"
- tm_file="${tm_file} dbxelf.h elfos.h sparc/sysv4.h netbsd.h netbsd-elf.h sparc/netbsd-elf.h"
+ tm_file="${tm_file} dbxelf.h elfos.h sparc/sysv4.h ${nbsd_tm_file} sparc/netbsd-elf.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt"
extra_options="${extra_options} sparc/long-double-switch.opt"
tmake_file="${tmake_file} sparc/t-sparc sparc/t-netbsd64"
@@ -3044,8 +3026,9 @@ vax-*-linux*)
extra_options="${extra_options} vax/elf.opt"
;;
vax-*-netbsdelf*)
- tm_file="${tm_file} elfos.h netbsd.h netbsd-elf.h vax/elf.h vax/netbsd-elf.h"
+ tm_file="${tm_file} elfos.h ${nbsd_tm_file} vax/elf.h vax/netbsd-elf.h"
extra_options="${extra_options} netbsd.opt netbsd-elf.opt vax/elf.opt"
+ tm_defines="${tm_defines} CHAR_FAST8=1 SHORT_FAST16=1"
;;
vax-*-openbsd*)
tm_file="vax/vax.h vax/openbsd1.h openbsd.h openbsd-stdint.h openbsd-libpthread.h vax/openbsd.h"
@@ -3120,6 +3103,20 @@ case ${target} in
;;
esac
+# Assume the existence of indirect function support and allow the use of the
+# resolver attribute.
+case ${target} in
+*-*-linux*android*|*-*-linux*uclibc*|*-*-linux*musl*)
+ ;;
+*-*-linux*)
+ case ${target} in
+ aarch64*-* | arm*-* | i[34567]86-* | powerpc*-* | s390*-* | sparc*-* | x86_64-*)
+ default_gnu_indirect_function=yes
+ ;;
+ esac
+ ;;
+esac
+
# Build mkoffload tool
case ${target} in
*-intelmic-* | *-intelmicemul-*)
@@ -3440,11 +3437,18 @@ if test x$with_cpu = x ; then
esac
;;
powerpc*-*-*spe*)
+ # For SPE, start with 8540, then upgrade to 8548 if
+ # --enable-e500-double was requested explicitly or if we were
+ # configured for e500v2.
+ with_cpu=8540
if test x$enable_e500_double = xyes; then
- with_cpu=8548
- else
- with_cpu=8540
- fi
+ with_cpu=8548
+ fi
+ case ${target_noncanonical} in
+ e500v2*)
+ with_cpu=8548
+ ;;
+ esac
;;
sparc*-*-*)
case ${target} in
@@ -4547,7 +4551,8 @@ case ${target} in
i[34567]86-*-darwin* | x86_64-*-darwin*)
;;
i[34567]86-*-linux* | x86_64-*-linux*)
- tmake_file="$tmake_file i386/t-linux"
+ extra_objs="${extra_objs} cet.o"
+ tmake_file="$tmake_file i386/t-linux i386/t-cet"
;;
i[34567]86-*-kfreebsd*-gnu | x86_64-*-kfreebsd*-gnu)
tmake_file="$tmake_file i386/t-kfreebsd"
diff --git a/gcc/config/aarch64/aarch64-builtins.c b/gcc/config/aarch64/aarch64-builtins.c
index 7edf75c..242b2e3 100644
--- a/gcc/config/aarch64/aarch64-builtins.c
+++ b/gcc/config/aarch64/aarch64-builtins.c
@@ -168,6 +168,11 @@ aarch64_types_quadop_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
= { qualifier_none, qualifier_none, qualifier_none,
qualifier_none, qualifier_lane_index };
#define TYPES_QUADOP_LANE (aarch64_types_quadop_lane_qualifiers)
+static enum aarch64_type_qualifiers
+aarch64_types_quadopu_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
+ qualifier_unsigned, qualifier_lane_index };
+#define TYPES_QUADOPU_LANE (aarch64_types_quadopu_lane_qualifiers)
static enum aarch64_type_qualifiers
aarch64_types_binop_imm_p_qualifiers[SIMD_MAX_BUILTIN_ARGS]
diff --git a/gcc/config/aarch64/aarch64-c.c b/gcc/config/aarch64/aarch64-c.c
index 177e638..c7d866f 100644
--- a/gcc/config/aarch64/aarch64-c.c
+++ b/gcc/config/aarch64/aarch64-c.c
@@ -106,6 +106,7 @@ aarch64_update_cpp_builtins (cpp_reader *pfile)
aarch64_def_or_undef (TARGET_CRC32, "__ARM_FEATURE_CRC32", pfile);
+ aarch64_def_or_undef (TARGET_DOTPROD, "__ARM_FEATURE_DOTPROD", pfile);
cpp_undef (pfile, "__AARCH64_CMODEL_TINY__");
cpp_undef (pfile, "__AARCH64_CMODEL_SMALL__");
diff --git a/gcc/config/aarch64/aarch64-cores.def b/gcc/config/aarch64/aarch64-cores.def
index 1089332..16e4485 100644
--- a/gcc/config/aarch64/aarch64-cores.def
+++ b/gcc/config/aarch64/aarch64-cores.def
@@ -83,8 +83,8 @@ AARCH64_CORE("thunderx2t99", thunderx2t99, thunderx2t99, 8_1A, AARCH64_FL_FOR
/* ARMv8.2-A Architecture Processors. */
/* ARM ('A') cores. */
-AARCH64_CORE("cortex-a55", cortexa55, cortexa53, 8_2A, AARCH64_FL_FOR_ARCH8_2 | AARCH64_FL_RCPC, cortexa53, 0x41, 0xd05, -1)
-AARCH64_CORE("cortex-a75", cortexa75, cortexa57, 8_2A, AARCH64_FL_FOR_ARCH8_2 | AARCH64_FL_RCPC, cortexa73, 0x41, 0xd0a, -1)
+AARCH64_CORE("cortex-a55", cortexa55, cortexa53, 8_2A, AARCH64_FL_FOR_ARCH8_2 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD, cortexa53, 0x41, 0xd05, -1)
+AARCH64_CORE("cortex-a75", cortexa75, cortexa57, 8_2A, AARCH64_FL_FOR_ARCH8_2 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD, cortexa73, 0x41, 0xd0a, -1)
/* ARMv8-A big.LITTLE implementations. */
@@ -95,6 +95,6 @@ AARCH64_CORE("cortex-a73.cortex-a53", cortexa73cortexa53, cortexa53, 8A, AARCH
/* ARM DynamIQ big.LITTLE configurations. */
-AARCH64_CORE("cortex-a75.cortex-a55", cortexa75cortexa55, cortexa53, 8_2A, AARCH64_FL_FOR_ARCH8_2 | AARCH64_FL_RCPC, cortexa73, 0x41, AARCH64_BIG_LITTLE (0xd0a, 0xd05), -1)
+AARCH64_CORE("cortex-a75.cortex-a55", cortexa75cortexa55, cortexa53, 8_2A, AARCH64_FL_FOR_ARCH8_2 | AARCH64_FL_RCPC | AARCH64_FL_DOTPROD, cortexa73, 0x41, AARCH64_BIG_LITTLE (0xd0a, 0xd05), -1)
#undef AARCH64_CORE
diff --git a/gcc/config/aarch64/aarch64-option-extensions.def b/gcc/config/aarch64/aarch64-option-extensions.def
index a989a2e..2c808f0 100644
--- a/gcc/config/aarch64/aarch64-option-extensions.def
+++ b/gcc/config/aarch64/aarch64-option-extensions.def
@@ -43,8 +43,8 @@
AARCH64_OPT_EXTENSION("fp", AARCH64_FL_FP, 0, AARCH64_FL_SIMD | AARCH64_FL_CRYPTO | AARCH64_FL_F16, "fp")
/* Enabling "simd" also enables "fp".
- Disabling "simd" also disables "crypto". */
-AARCH64_OPT_EXTENSION("simd", AARCH64_FL_SIMD, AARCH64_FL_FP, AARCH64_FL_CRYPTO, "asimd")
+ Disabling "simd" also disables "crypto" and "dotprod". */
+AARCH64_OPT_EXTENSION("simd", AARCH64_FL_SIMD, AARCH64_FL_FP, AARCH64_FL_CRYPTO | AARCH64_FL_DOTPROD, "asimd")
/* Enabling "crypto" also enables "fp", "simd".
Disabling "crypto" just disables "crypto". */
@@ -67,4 +67,8 @@ AARCH64_OPT_EXTENSION("rcpc", AARCH64_FL_RCPC, 0, 0, "lrcpc")
Disabling "rdma" just disables "rdma". */
AARCH64_OPT_EXTENSION("rdma", AARCH64_FL_RDMA, AARCH64_FL_FP | AARCH64_FL_SIMD, 0, "asimdrdm")
+/* Enabling "dotprod" also enables "simd".
+ Disabling "dotprod" only disables "dotprod". */
+AARCH64_OPT_EXTENSION("dotprod", AARCH64_FL_DOTPROD, AARCH64_FL_SIMD, 0, "asimddp")
+
#undef AARCH64_OPT_EXTENSION
diff --git a/gcc/config/aarch64/aarch64-protos.h b/gcc/config/aarch64/aarch64-protos.h
index e67c2ed..5d7c5df 100644
--- a/gcc/config/aarch64/aarch64-protos.h
+++ b/gcc/config/aarch64/aarch64-protos.h
@@ -308,6 +308,16 @@ enum aarch64_parse_opt_result
AARCH64_PARSE_INVALID_ARG /* Invalid arch, tune, cpu arg. */
};
+/* Enum to distinguish which type of check is to be done in
+ aarch64_simd_valid_immediate. This is used as a bitmask where
+ AARCH64_CHECK_MOV has both bits set. Thus AARCH64_CHECK_MOV will
+ perform all checks. Adding new types would require changes accordingly. */
+enum simd_immediate_check {
+ AARCH64_CHECK_ORR = 1 << 0,
+ AARCH64_CHECK_BIC = 1 << 1,
+ AARCH64_CHECK_MOV = AARCH64_CHECK_ORR | AARCH64_CHECK_BIC
+};
+
extern struct tune_params aarch64_tune_params;
HOST_WIDE_INT aarch64_initial_elimination_offset (unsigned, unsigned);
@@ -345,7 +355,8 @@ bool aarch64_mov_operand_p (rtx, machine_mode);
rtx aarch64_reverse_mask (machine_mode);
bool aarch64_offset_7bit_signed_scaled_p (machine_mode, HOST_WIDE_INT);
char *aarch64_output_scalar_simd_mov_immediate (rtx, scalar_int_mode);
-char *aarch64_output_simd_mov_immediate (rtx, machine_mode, unsigned);
+char *aarch64_output_simd_mov_immediate (rtx, machine_mode, unsigned,
+ enum simd_immediate_check w = AARCH64_CHECK_MOV);
bool aarch64_pad_reg_upward (machine_mode, const_tree, bool);
bool aarch64_regno_ok_for_base_p (int, bool);
bool aarch64_regno_ok_for_index_p (int, bool);
@@ -356,7 +367,8 @@ bool aarch64_simd_imm_zero_p (rtx, machine_mode);
bool aarch64_simd_scalar_immediate_valid_for_move (rtx, scalar_int_mode);
bool aarch64_simd_shift_imm_p (rtx, machine_mode, bool);
bool aarch64_simd_valid_immediate (rtx, machine_mode, bool,
- struct simd_immediate_info *);
+ struct simd_immediate_info *,
+ enum simd_immediate_check w = AARCH64_CHECK_MOV);
bool aarch64_split_dimode_const_store (rtx, rtx);
bool aarch64_symbolic_address_p (rtx);
bool aarch64_uimm12_shift (HOST_WIDE_INT);
diff --git a/gcc/config/aarch64/aarch64-simd-builtins.def b/gcc/config/aarch64/aarch64-simd-builtins.def
index d713d5d..52d0134 100644
--- a/gcc/config/aarch64/aarch64-simd-builtins.def
+++ b/gcc/config/aarch64/aarch64-simd-builtins.def
@@ -205,6 +205,14 @@
BUILTIN_VSDQ_I_DI (BINOP, srshl, 0)
BUILTIN_VSDQ_I_DI (BINOP_UUS, urshl, 0)
+ /* Implemented by aarch64_<sur><dotprod>{_lane}{q}<dot_mode>. */
+ BUILTIN_VB (TERNOP, sdot, 0)
+ BUILTIN_VB (TERNOPU, udot, 0)
+ BUILTIN_VB (QUADOP_LANE, sdot_lane, 0)
+ BUILTIN_VB (QUADOPU_LANE, udot_lane, 0)
+ BUILTIN_VB (QUADOP_LANE, sdot_laneq, 0)
+ BUILTIN_VB (QUADOPU_LANE, udot_laneq, 0)
+
BUILTIN_VDQ_I (SHIFTIMM, ashr, 3)
VAR1 (SHIFTIMM, ashr_simd, 0, di)
BUILTIN_VDQ_I (SHIFTIMM, lshr, 3)
diff --git a/gcc/config/aarch64/aarch64-simd.md b/gcc/config/aarch64/aarch64-simd.md
index 70e9339..49f615c 100644
--- a/gcc/config/aarch64/aarch64-simd.md
+++ b/gcc/config/aarch64/aarch64-simd.md
@@ -393,6 +393,87 @@
}
)
+;; These instructions map to the __builtins for the Dot Product operations.
+(define_insn "aarch64_<sur>dot<vsi2qi>"
+ [(set (match_operand:VS 0 "register_operand" "=w")
+ (plus:VS (match_operand:VS 1 "register_operand" "0")
+ (unspec:VS [(match_operand:<VSI2QI> 2 "register_operand" "w")
+ (match_operand:<VSI2QI> 3 "register_operand" "w")]
+ DOTPROD)))]
+ "TARGET_DOTPROD"
+ "<sur>dot\\t%0.<Vtype>, %2.<Vdottype>, %3.<Vdottype>"
+ [(set_attr "type" "neon_dot")]
+)
+
+;; These expands map to the Dot Product optab the vectorizer checks for.
+;; The auto-vectorizer expects a dot product builtin that also does an
+;; accumulation into the provided register.
+;; Given the following pattern
+;;
+;; for (i=0; i<len; i++) {
+;; c = a[i] * b[i];
+;; r += c;
+;; }
+;; return result;
+;;
+;; This can be auto-vectorized to
+;; r = a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3];
+;;
+;; given enough iterations. However the vectorizer can keep unrolling the loop
+;; r += a[4]*b[4] + a[5]*b[5] + a[6]*b[6] + a[7]*b[7];
+;; r += a[8]*b[8] + a[9]*b[9] + a[10]*b[10] + a[11]*b[11];
+;; ...
+;;
+;; and so the vectorizer provides r, in which the result has to be accumulated.
+(define_expand "<sur>dot_prod<vsi2qi>"
+ [(set (match_operand:VS 0 "register_operand")
+ (plus:VS (unspec:VS [(match_operand:<VSI2QI> 1 "register_operand")
+ (match_operand:<VSI2QI> 2 "register_operand")]
+ DOTPROD)
+ (match_operand:VS 3 "register_operand")))]
+ "TARGET_DOTPROD"
+{
+ emit_insn (
+ gen_aarch64_<sur>dot<vsi2qi> (operands[3], operands[3], operands[1],
+ operands[2]));
+ emit_insn (gen_rtx_SET (operands[0], operands[3]));
+ DONE;
+})
+
+;; These instructions map to the __builtins for the Dot Product
+;; indexed operations.
+(define_insn "aarch64_<sur>dot_lane<vsi2qi>"
+ [(set (match_operand:VS 0 "register_operand" "=w")
+ (plus:VS (match_operand:VS 1 "register_operand" "0")
+ (unspec:VS [(match_operand:<VSI2QI> 2 "register_operand" "w")
+ (match_operand:V8QI 3 "register_operand" "<h_con>")
+ (match_operand:SI 4 "immediate_operand" "i")]
+ DOTPROD)))]
+ "TARGET_DOTPROD"
+ {
+ operands[4]
+ = GEN_INT (ENDIAN_LANE_N (V8QImode, INTVAL (operands[4])));
+ return "<sur>dot\\t%0.<Vtype>, %2.<Vdottype>, %3.4b[%4]";
+ }
+ [(set_attr "type" "neon_dot")]
+)
+
+(define_insn "aarch64_<sur>dot_laneq<vsi2qi>"
+ [(set (match_operand:VS 0 "register_operand" "=w")
+ (plus:VS (match_operand:VS 1 "register_operand" "0")
+ (unspec:VS [(match_operand:<VSI2QI> 2 "register_operand" "w")
+ (match_operand:V16QI 3 "register_operand" "<h_con>")
+ (match_operand:SI 4 "immediate_operand" "i")]
+ DOTPROD)))]
+ "TARGET_DOTPROD"
+ {
+ operands[4]
+ = GEN_INT (ENDIAN_LANE_N (V16QImode, INTVAL (operands[4])));
+ return "<sur>dot\\t%0.<Vtype>, %2.<Vdottype>, %3.4b[%4]";
+ }
+ [(set_attr "type" "neon_dot")]
+)
+
(define_expand "copysign<mode>3"
[(match_operand:VHSDF 0 "register_operand")
(match_operand:VHSDF 1 "register_operand")
@@ -558,21 +639,45 @@
[(set_attr "type" "neon_fp_abd_<stype><q>")]
)
+;; For AND (vector, register) and BIC (vector, immediate)
(define_insn "and<mode>3"
- [(set (match_operand:VDQ_I 0 "register_operand" "=w")
- (and:VDQ_I (match_operand:VDQ_I 1 "register_operand" "w")
- (match_operand:VDQ_I 2 "register_operand" "w")))]
+ [(set (match_operand:VDQ_I 0 "register_operand" "=w,w")
+ (and:VDQ_I (match_operand:VDQ_I 1 "register_operand" "w,0")
+ (match_operand:VDQ_I 2 "aarch64_reg_or_bic_imm" "w,Db")))]
"TARGET_SIMD"
- "and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>"
+ {
+ switch (which_alternative)
+ {
+ case 0:
+ return "and\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>";
+ case 1:
+ return aarch64_output_simd_mov_immediate (operands[2],
+ <MODE>mode, GET_MODE_BITSIZE (<MODE>mode), AARCH64_CHECK_BIC);
+ default:
+ gcc_unreachable ();
+ }
+ }
[(set_attr "type" "neon_logic<q>")]
)
+;; For ORR (vector, register) and ORR (vector, immediate)
(define_insn "ior<mode>3"
- [(set (match_operand:VDQ_I 0 "register_operand" "=w")
- (ior:VDQ_I (match_operand:VDQ_I 1 "register_operand" "w")
- (match_operand:VDQ_I 2 "register_operand" "w")))]
+ [(set (match_operand:VDQ_I 0 "register_operand" "=w,w")
+ (ior:VDQ_I (match_operand:VDQ_I 1 "register_operand" "w,0")
+ (match_operand:VDQ_I 2 "aarch64_reg_or_orr_imm" "w,Do")))]
"TARGET_SIMD"
- "orr\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>"
+ {
+ switch (which_alternative)
+ {
+ case 0:
+ return "orr\t%0.<Vbtype>, %1.<Vbtype>, %2.<Vbtype>";
+ case 1:
+ return aarch64_output_simd_mov_immediate (operands[2],
+ <MODE>mode, GET_MODE_BITSIZE (<MODE>mode), AARCH64_CHECK_ORR);
+ default:
+ gcc_unreachable ();
+ }
+ }
[(set_attr "type" "neon_logic<q>")]
)
diff --git a/gcc/config/aarch64/aarch64.c b/gcc/config/aarch64/aarch64.c
index 1c14008..d1aaf19 100644
--- a/gcc/config/aarch64/aarch64.c
+++ b/gcc/config/aarch64/aarch64.c
@@ -141,8 +141,8 @@ static void aarch64_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED;
static void aarch64_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED;
static void aarch64_override_options_after_change (void);
static bool aarch64_vector_mode_supported_p (machine_mode);
-static bool aarch64_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel);
+static bool aarch64_vectorize_vec_perm_const_ok (machine_mode,
+ vec_perm_indices);
static int aarch64_address_cost (rtx, machine_mode, addr_space_t, bool);
static bool aarch64_builtin_support_vector_misalignment (machine_mode mode,
const_tree type,
@@ -1142,6 +1142,17 @@ aarch64_hard_regno_caller_save_mode (unsigned regno, unsigned nregs,
return choose_hard_reg_mode (regno, nregs, false);
}
+/* Implement TARGET_CONSTANT_ALIGNMENT. Make strings word-aligned so
+ that strcpy from constants will be faster. */
+
+static HOST_WIDE_INT
+aarch64_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST && !optimize_size)
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
/* Return true if calls to DECL should be treated as
long-calls (ie called via a register). */
static bool
@@ -1479,7 +1490,8 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
tp = gen_lowpart (mode, tp);
emit_insn (gen_rtx_SET (dest, gen_rtx_PLUS (mode, tp, x0)));
- set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
+ if (REG_P (dest))
+ set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
return;
}
@@ -1513,7 +1525,8 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
}
emit_insn (gen_rtx_SET (dest, gen_rtx_PLUS (mode, tp, tmp_reg)));
- set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
+ if (REG_P (dest))
+ set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
return;
}
@@ -1554,7 +1567,8 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
gcc_unreachable ();
}
- set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
+ if (REG_P (dest))
+ set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
return;
}
@@ -1583,7 +1597,8 @@ aarch64_load_symref_appropriately (rtx dest, rtx imm,
emit_insn (gen_tlsie_tiny_sidi (dest, imm, tp));
}
- set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
+ if (REG_P (dest))
+ set_unique_reg_note (get_last_insn (), REG_EQUIV, imm);
return;
}
@@ -2852,12 +2867,13 @@ aarch64_output_probe_stack_range (rtx reg1, rtx reg2)
static bool
aarch64_frame_pointer_required (void)
{
- /* In aarch64_override_options_after_change
- flag_omit_leaf_frame_pointer turns off the frame pointer by
- default. Turn it back on now if we've not got a leaf
- function. */
- if (flag_omit_leaf_frame_pointer
- && (!crtl->is_leaf || df_regs_ever_live_p (LR_REGNUM)))
+ /* Use the frame pointer if enabled and it is not a leaf function, unless
+ leaf frame pointer omission is disabled. If the frame pointer is enabled,
+ force the frame pointer in leaf functions which use LR. */
+ if (flag_omit_frame_pointer == 2
+ && !(flag_omit_leaf_frame_pointer
+ && crtl->is_leaf
+ && !df_regs_ever_live_p (LR_REGNUM)))
return true;
/* Force a frame pointer for EH returns so the return address is at FP+8. */
@@ -3666,12 +3682,14 @@ aarch64_expand_prologue (void)
{
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (frame_size > PROBE_INTERVAL && frame_size > STACK_CHECK_PROTECT)
- aarch64_emit_probe_stack_range (STACK_CHECK_PROTECT,
- frame_size - STACK_CHECK_PROTECT);
+ if (frame_size > PROBE_INTERVAL
+ && frame_size > get_stack_check_protect ())
+ aarch64_emit_probe_stack_range (get_stack_check_protect (),
+ (frame_size
+ - get_stack_check_protect ()));
}
else if (frame_size > 0)
- aarch64_emit_probe_stack_range (STACK_CHECK_PROTECT, frame_size);
+ aarch64_emit_probe_stack_range (get_stack_check_protect (), frame_size);
}
aarch64_sub_sp (IP0_REGNUM, initial_adjust, true);
@@ -4620,7 +4638,7 @@ aarch64_classify_address (struct aarch64_address_info *info,
{
tree exp = SYMBOL_REF_DECL (sym);
align = TYPE_ALIGN (TREE_TYPE (exp));
- align = CONSTANT_ALIGNMENT (exp, align);
+ align = aarch64_constant_alignment (exp, align);
}
else if (SYMBOL_REF_DECL (sym))
align = DECL_ALIGN (SYMBOL_REF_DECL (sym));
@@ -5909,6 +5927,7 @@ aarch64_can_eliminate (const int from, const int to)
LR in the function, then we'll want a frame pointer after all, so
prevent this elimination to ensure a frame pointer is used. */
if (to == STACK_POINTER_REGNUM
+ && flag_omit_frame_pointer == 2
&& flag_omit_leaf_frame_pointer
&& df_regs_ever_live_p (LR_REGNUM))
return false;
@@ -6009,6 +6028,7 @@ aarch64_class_max_nregs (reg_class_t regclass, machine_mode mode)
case POINTER_REGS:
case GENERAL_REGS:
case ALL_REGS:
+ case POINTER_AND_FP_REGS:
case FP_REGS:
case FP_LO_REGS:
return
@@ -6082,7 +6102,7 @@ aarch64_elf_asm_constructor (rtx symbol, int priority)
-Wformat-truncation false positive, use a larger size. */
char buf[23];
snprintf (buf, sizeof (buf), ".init_array.%.5u", priority);
- s = get_section (buf, SECTION_WRITE, NULL);
+ s = get_section (buf, SECTION_WRITE | SECTION_NOTYPE, NULL);
switch_to_section (s);
assemble_align (POINTER_SIZE);
assemble_aligned_integer (POINTER_BYTES, symbol);
@@ -6102,7 +6122,7 @@ aarch64_elf_asm_destructor (rtx symbol, int priority)
-Wformat-truncation false positive, use a larger size. */
char buf[23];
snprintf (buf, sizeof (buf), ".fini_array.%.5u", priority);
- s = get_section (buf, SECTION_WRITE, NULL);
+ s = get_section (buf, SECTION_WRITE | SECTION_NOTYPE, NULL);
switch_to_section (s);
assemble_align (POINTER_SIZE);
assemble_aligned_integer (POINTER_BYTES, symbol);
@@ -8541,9 +8561,11 @@ aarch64_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return costs->scalar_to_vec_cost;
case unaligned_load:
+ case vector_gather_load:
return costs->vec_unalign_load_cost;
case unaligned_store:
+ case vector_scatter_store:
return costs->vec_unalign_store_cost;
case cond_branch_taken:
@@ -8945,24 +8967,16 @@ aarch64_parse_override_string (const char* input_string,
static void
aarch64_override_options_after_change_1 (struct gcc_options *opts)
{
- /* The logic here is that if we are disabling all frame pointer generation
- then we do not need to disable leaf frame pointer generation as a
- separate operation. But if we are *only* disabling leaf frame pointer
- generation then we set flag_omit_frame_pointer to true, but in
- aarch64_frame_pointer_required we return false only for leaf functions.
-
- PR 70044: We have to be careful about being called multiple times for the
- same function. Once we have decided to set flag_omit_frame_pointer just
- so that we can omit leaf frame pointers, we must then not interpret a
- second call as meaning that all frame pointer generation should be
- omitted. We do this by setting flag_omit_frame_pointer to a special,
- non-zero value. */
- if (opts->x_flag_omit_frame_pointer == 2)
- opts->x_flag_omit_frame_pointer = 0;
-
- if (opts->x_flag_omit_frame_pointer)
- opts->x_flag_omit_leaf_frame_pointer = false;
- else if (opts->x_flag_omit_leaf_frame_pointer)
+ /* PR 70044: We have to be careful about being called multiple times for the
+ same function. This means all changes should be repeatable. */
+
+ /* If the frame pointer is enabled, set it to a special value that behaves
+ similar to frame pointer omission. If we don't do this all leaf functions
+ will get a frame pointer even if flag_omit_leaf_frame_pointer is set.
+ If flag_omit_frame_pointer has this special value, we must force the
+ frame pointer if not in a leaf function. We also need to force it in a
+ leaf function if flag_omit_frame_pointer is not set or if LR is used. */
+ if (opts->x_flag_omit_frame_pointer == 0)
opts->x_flag_omit_frame_pointer = 2;
/* If not optimizing for size, set the default
@@ -11025,7 +11039,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
- tree_to_uhwi (TYPE_MIN_VALUE (index)));
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -11055,7 +11070,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
}
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -11087,7 +11103,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
}
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -11469,7 +11486,8 @@ aarch64_vect_float_const_representable_p (rtx x)
/* Return true for valid and false for invalid. */
bool
aarch64_simd_valid_immediate (rtx op, machine_mode mode, bool inverse,
- struct simd_immediate_info *info)
+ struct simd_immediate_info *info,
+ enum simd_immediate_check which)
{
#define CHECK(STRIDE, ELSIZE, CLASS, TEST, SHIFT, NEG) \
matches = 1; \
@@ -11537,54 +11555,65 @@ aarch64_simd_valid_immediate (rtx op, machine_mode mode, bool inverse,
do
{
- CHECK (4, 32, 0, bytes[i] == bytes[0] && bytes[i + 1] == 0
- && bytes[i + 2] == 0 && bytes[i + 3] == 0, 0, 0);
+ if (which & AARCH64_CHECK_ORR)
+ {
+ CHECK (4, 32, 0, bytes[i] == bytes[0] && bytes[i + 1] == 0
+ && bytes[i + 2] == 0 && bytes[i + 3] == 0, 0, 0);
- CHECK (4, 32, 1, bytes[i] == 0 && bytes[i + 1] == bytes[1]
- && bytes[i + 2] == 0 && bytes[i + 3] == 0, 8, 0);
+ CHECK (4, 32, 1, bytes[i] == 0 && bytes[i + 1] == bytes[1]
+ && bytes[i + 2] == 0 && bytes[i + 3] == 0, 8, 0);
- CHECK (4, 32, 2, bytes[i] == 0 && bytes[i + 1] == 0
- && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0, 16, 0);
+ CHECK (4, 32, 2, bytes[i] == 0 && bytes[i + 1] == 0
+ && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0, 16, 0);
- CHECK (4, 32, 3, bytes[i] == 0 && bytes[i + 1] == 0
- && bytes[i + 2] == 0 && bytes[i + 3] == bytes[3], 24, 0);
+ CHECK (4, 32, 3, bytes[i] == 0 && bytes[i + 1] == 0
+ && bytes[i + 2] == 0 && bytes[i + 3] == bytes[3], 24, 0);
- CHECK (2, 16, 4, bytes[i] == bytes[0] && bytes[i + 1] == 0, 0, 0);
+ CHECK (2, 16, 4, bytes[i] == bytes[0] && bytes[i + 1] == 0, 0, 0);
- CHECK (2, 16, 5, bytes[i] == 0 && bytes[i + 1] == bytes[1], 8, 0);
+ CHECK (2, 16, 5, bytes[i] == 0 && bytes[i + 1] == bytes[1], 8, 0);
+ }
- CHECK (4, 32, 6, bytes[i] == bytes[0] && bytes[i + 1] == 0xff
- && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 0, 1);
+ if (which & AARCH64_CHECK_BIC)
+ {
+ CHECK (4, 32, 6, bytes[i] == bytes[0] && bytes[i + 1] == 0xff
+ && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 0, 1);
- CHECK (4, 32, 7, bytes[i] == 0xff && bytes[i + 1] == bytes[1]
- && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 8, 1);
+ CHECK (4, 32, 7, bytes[i] == 0xff && bytes[i + 1] == bytes[1]
+ && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 8, 1);
- CHECK (4, 32, 8, bytes[i] == 0xff && bytes[i + 1] == 0xff
- && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0xff, 16, 1);
+ CHECK (4, 32, 8, bytes[i] == 0xff && bytes[i + 1] == 0xff
+ && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0xff, 16, 1);
- CHECK (4, 32, 9, bytes[i] == 0xff && bytes[i + 1] == 0xff
- && bytes[i + 2] == 0xff && bytes[i + 3] == bytes[3], 24, 1);
+ CHECK (4, 32, 9, bytes[i] == 0xff && bytes[i + 1] == 0xff
+ && bytes[i + 2] == 0xff && bytes[i + 3] == bytes[3], 24, 1);
- CHECK (2, 16, 10, bytes[i] == bytes[0] && bytes[i + 1] == 0xff, 0, 1);
+ CHECK (2, 16, 10, bytes[i] == bytes[0] && bytes[i + 1] == 0xff, 0, 1);
- CHECK (2, 16, 11, bytes[i] == 0xff && bytes[i + 1] == bytes[1], 8, 1);
+ CHECK (2, 16, 11, bytes[i] == 0xff && bytes[i + 1] == bytes[1], 8, 1);
+ }
- CHECK (4, 32, 12, bytes[i] == 0xff && bytes[i + 1] == bytes[1]
- && bytes[i + 2] == 0 && bytes[i + 3] == 0, 8, 0);
+ /* Shifting ones / 8-bit / 64-bit variants only checked
+ for 'ALL' (MOVI/MVNI). */
+ if (which == AARCH64_CHECK_MOV)
+ {
+ CHECK (4, 32, 12, bytes[i] == 0xff && bytes[i + 1] == bytes[1]
+ && bytes[i + 2] == 0 && bytes[i + 3] == 0, 8, 0);
- CHECK (4, 32, 13, bytes[i] == 0 && bytes[i + 1] == bytes[1]
- && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 8, 1);
+ CHECK (4, 32, 13, bytes[i] == 0 && bytes[i + 1] == bytes[1]
+ && bytes[i + 2] == 0xff && bytes[i + 3] == 0xff, 8, 1);
- CHECK (4, 32, 14, bytes[i] == 0xff && bytes[i + 1] == 0xff
- && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0, 16, 0);
+ CHECK (4, 32, 14, bytes[i] == 0xff && bytes[i + 1] == 0xff
+ && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0, 16, 0);
- CHECK (4, 32, 15, bytes[i] == 0 && bytes[i + 1] == 0
- && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0xff, 16, 1);
+ CHECK (4, 32, 15, bytes[i] == 0 && bytes[i + 1] == 0
+ && bytes[i + 2] == bytes[2] && bytes[i + 3] == 0xff, 16, 1);
- CHECK (1, 8, 16, bytes[i] == bytes[0], 0, 0);
+ CHECK (1, 8, 16, bytes[i] == bytes[0], 0, 0);
- CHECK (1, 64, 17, (bytes[i] == 0 || bytes[i] == 0xff)
- && bytes[i] == bytes[(i + 8) % idx], 0, 0);
+ CHECK (1, 64, 17, (bytes[i] == 0 || bytes[i] == 0xff)
+ && bytes[i] == bytes[(i + 8) % idx], 0, 0);
+ }
}
while (0);
@@ -11889,19 +11918,9 @@ aarch64_builtin_support_vector_misalignment (machine_mode mode,
if (optab_handler (movmisalign_optab, mode) == CODE_FOR_nothing)
return false;
+ /* Misalignment factor is unknown at compile time. */
if (misalignment == -1)
- {
- /* Misalignment factor is unknown at compile time but we know
- it's word aligned. */
- if (aarch64_simd_vector_alignment_reachable (type, is_packed))
- {
- int element_size = TREE_INT_CST_LOW (TYPE_SIZE (type));
-
- if (element_size != 64)
- return true;
- }
- return false;
- }
+ return false;
}
return default_builtin_support_vector_misalignment (mode, type, misalignment,
is_packed);
@@ -12996,10 +13015,14 @@ aarch64_float_const_representable_p (rtx x)
return (exponent >= 0 && exponent <= 7);
}
+/* Returns the string with the instruction for AdvSIMD MOVI, MVNI, ORR or BIC
+ immediate with a CONST_VECTOR of MODE and WIDTH. WHICH selects whether to
+ output MOVI/MVNI, ORR or BIC immediate. */
char*
aarch64_output_simd_mov_immediate (rtx const_vector,
machine_mode mode,
- unsigned width)
+ unsigned width,
+ enum simd_immediate_check which)
{
bool is_valid;
static char templ[40];
@@ -13011,9 +13034,11 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
struct simd_immediate_info info = { NULL_RTX, 0, 0, false, false };
/* This will return true to show const_vector is legal for use as either
- a AdvSIMD MOVI instruction (or, implicitly, MVNI) immediate. It will
- also update INFO to show how the immediate should be generated. */
- is_valid = aarch64_simd_valid_immediate (const_vector, mode, false, &info);
+ a AdvSIMD MOVI instruction (or, implicitly, MVNI), ORR or BIC immediate.
+ It will also update INFO to show how the immediate should be generated.
+ WHICH selects whether to check for MOVI/MVNI, ORR or BIC. */
+ is_valid = aarch64_simd_valid_immediate (const_vector, mode, false,
+ &info, which);
gcc_assert (is_valid);
element_char = sizetochar (info.element_width);
@@ -13044,20 +13069,37 @@ aarch64_output_simd_mov_immediate (rtx const_vector,
}
}
- mnemonic = info.mvn ? "mvni" : "movi";
- shift_op = info.msl ? "msl" : "lsl";
-
gcc_assert (CONST_INT_P (info.value));
- if (lane_count == 1)
- snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX,
- mnemonic, UINTVAL (info.value));
- else if (info.shift)
- snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " HOST_WIDE_INT_PRINT_HEX
- ", %s %d", mnemonic, lane_count, element_char,
- UINTVAL (info.value), shift_op, info.shift);
+
+ if (which == AARCH64_CHECK_MOV)
+ {
+ mnemonic = info.mvn ? "mvni" : "movi";
+ shift_op = info.msl ? "msl" : "lsl";
+ if (lane_count == 1)
+ snprintf (templ, sizeof (templ), "%s\t%%d0, " HOST_WIDE_INT_PRINT_HEX,
+ mnemonic, UINTVAL (info.value));
+ else if (info.shift)
+ snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, "
+ HOST_WIDE_INT_PRINT_HEX ", %s %d", mnemonic, lane_count,
+ element_char, UINTVAL (info.value), shift_op, info.shift);
+ else
+ snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, "
+ HOST_WIDE_INT_PRINT_HEX, mnemonic, lane_count,
+ element_char, UINTVAL (info.value));
+ }
else
- snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, " HOST_WIDE_INT_PRINT_HEX,
- mnemonic, lane_count, element_char, UINTVAL (info.value));
+ {
+ /* For AARCH64_CHECK_BIC and AARCH64_CHECK_ORR. */
+ mnemonic = info.mvn ? "bic" : "orr";
+ if (info.shift)
+ snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #"
+ HOST_WIDE_INT_PRINT_DEC ", %s #%d", mnemonic, lane_count,
+ element_char, UINTVAL (info.value), "lsl", info.shift);
+ else
+ snprintf (templ, sizeof (templ), "%s\t%%0.%d%c, #"
+ HOST_WIDE_INT_PRINT_DEC, mnemonic, lane_count,
+ element_char, UINTVAL (info.value));
+ }
return templ;
}
@@ -13144,9 +13186,8 @@ aarch64_split_combinev16qi (rtx operands[3])
struct expand_vec_perm_d
{
rtx target, op0, op1;
- unsigned char perm[MAX_VECT_LEN];
+ auto_vec_perm_indices perm;
machine_mode vmode;
- unsigned char nelt;
bool one_vector_p;
bool testing_p;
};
@@ -13229,7 +13270,7 @@ aarch64_expand_vec_perm (rtx target, rtx op0, rtx op1, rtx sel)
static bool
aarch64_evpc_trn (struct expand_vec_perm_d *d)
{
- unsigned int i, odd, mask, nelt = d->nelt;
+ unsigned int i, odd, mask, nelt = d->perm.length ();
rtx out, in0, in1, x;
rtx (*gen) (rtx, rtx, rtx);
machine_mode vmode = d->vmode;
@@ -13317,7 +13358,7 @@ aarch64_evpc_trn (struct expand_vec_perm_d *d)
static bool
aarch64_evpc_uzp (struct expand_vec_perm_d *d)
{
- unsigned int i, odd, mask, nelt = d->nelt;
+ unsigned int i, odd, mask, nelt = d->perm.length ();
rtx out, in0, in1, x;
rtx (*gen) (rtx, rtx, rtx);
machine_mode vmode = d->vmode;
@@ -13404,7 +13445,7 @@ aarch64_evpc_uzp (struct expand_vec_perm_d *d)
static bool
aarch64_evpc_zip (struct expand_vec_perm_d *d)
{
- unsigned int i, high, mask, nelt = d->nelt;
+ unsigned int i, high, mask, nelt = d->perm.length ();
rtx out, in0, in1, x;
rtx (*gen) (rtx, rtx, rtx);
machine_mode vmode = d->vmode;
@@ -13497,7 +13538,7 @@ aarch64_evpc_zip (struct expand_vec_perm_d *d)
static bool
aarch64_evpc_ext (struct expand_vec_perm_d *d)
{
- unsigned int i, nelt = d->nelt;
+ unsigned int i, nelt = d->perm.length ();
rtx (*gen) (rtx, rtx, rtx, rtx);
rtx offset;
@@ -13561,7 +13602,7 @@ aarch64_evpc_ext (struct expand_vec_perm_d *d)
static bool
aarch64_evpc_rev (struct expand_vec_perm_d *d)
{
- unsigned int i, j, diff, nelt = d->nelt;
+ unsigned int i, j, diff, nelt = d->perm.length ();
rtx (*gen) (rtx, rtx);
if (!d->one_vector_p)
@@ -13639,7 +13680,7 @@ aarch64_evpc_dup (struct expand_vec_perm_d *d)
rtx out = d->target;
rtx in0;
machine_mode vmode = d->vmode;
- unsigned int i, elt, nelt = d->nelt;
+ unsigned int i, elt, nelt = d->perm.length ();
rtx lane;
elt = d->perm[0];
@@ -13684,7 +13725,7 @@ aarch64_evpc_tbl (struct expand_vec_perm_d *d)
{
rtx rperm[MAX_VECT_LEN], sel;
machine_mode vmode = d->vmode;
- unsigned int i, nelt = d->nelt;
+ unsigned int i, nelt = d->perm.length ();
if (d->testing_p)
return true;
@@ -13718,12 +13759,11 @@ aarch64_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
/* The pattern matching functions above are written to look for a small
number to begin the sequence (0, 1, N/2). If we begin with an index
from the second operand, we can swap the operands. */
- if (d->perm[0] >= d->nelt)
+ unsigned int nelt = d->perm.length ();
+ if (d->perm[0] >= nelt)
{
- unsigned i, nelt = d->nelt;
-
gcc_assert (nelt == (nelt & -nelt));
- for (i = 0; i < nelt; ++i)
+ for (unsigned int i = 0; i < nelt; ++i)
d->perm[i] ^= nelt; /* Keep the same index, but in the other vector. */
std::swap (d->op0, d->op1);
@@ -13762,15 +13802,16 @@ aarch64_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel)
d.vmode = GET_MODE (target);
gcc_assert (VECTOR_MODE_P (d.vmode));
- d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
d.testing_p = false;
+ nelt = GET_MODE_NUNITS (d.vmode);
+ d.perm.reserve (nelt);
for (i = which = 0; i < nelt; ++i)
{
rtx e = XVECEXP (sel, 0, i);
int ei = INTVAL (e) & (2 * nelt - 1);
which |= (ei < nelt ? 1 : 2);
- d.perm[i] = ei;
+ d.perm.quick_push (ei);
}
switch (which)
@@ -13805,22 +13846,21 @@ aarch64_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel)
}
static bool
-aarch64_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel)
+aarch64_vectorize_vec_perm_const_ok (machine_mode vmode, vec_perm_indices sel)
{
struct expand_vec_perm_d d;
unsigned int i, nelt, which;
bool ret;
d.vmode = vmode;
- d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
d.testing_p = true;
- memcpy (d.perm, sel, nelt);
+ d.perm.safe_splice (sel);
/* Calculate whether all elements are in one vector. */
+ nelt = sel.length ();
for (i = which = 0; i < nelt; ++i)
{
- unsigned char e = d.perm[i];
+ unsigned int e = d.perm[i];
gcc_assert (e < 2 * nelt);
which |= (e < nelt ? 1 : 2);
}
@@ -15687,6 +15727,9 @@ aarch64_libgcc_floating_mode_supported_p
#define TARGET_HARD_REGNO_CALL_PART_CLOBBERED \
aarch64_hard_regno_call_part_clobbered
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT aarch64_constant_alignment
+
#if CHECKING_P
#undef TARGET_RUN_TARGET_SELFTESTS
#define TARGET_RUN_TARGET_SELFTESTS selftest::aarch64_run_selftests
diff --git a/gcc/config/aarch64/aarch64.h b/gcc/config/aarch64/aarch64.h
index 128006d..75fda01 100644
--- a/gcc/config/aarch64/aarch64.h
+++ b/gcc/config/aarch64/aarch64.h
@@ -90,14 +90,6 @@
port. */
#define TARGET_PTRMEMFUNC_VBIT_LOCATION ptrmemfunc_vbit_in_delta
-/* Make strings word-aligned so that strcpy from constants will be
- faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && !optimize_size \
- && (ALIGN) < BITS_PER_WORD) \
- ? BITS_PER_WORD : ALIGN)
-
/* Align definitions of arrays, unions and structures so that
initializations and copies can be made more efficient. This is not
ABI-changing, so it only affects places where we can see the
@@ -144,14 +136,15 @@ extern unsigned aarch64_architecture_version;
#define AARCH64_FL_CRC (1 << 3) /* Has CRC. */
/* ARMv8.1-A architecture extensions. */
#define AARCH64_FL_LSE (1 << 4) /* Has Large System Extensions. */
-#define AARCH64_FL_RDMA (1 << 5) /* Has Round Double Multiply Add. */
-#define AARCH64_FL_V8_1 (1 << 6) /* Has ARMv8.1-A extensions. */
+#define AARCH64_FL_RDMA (1 << 5) /* Has Round Double Multiply Add. */
+#define AARCH64_FL_V8_1 (1 << 6) /* Has ARMv8.1-A extensions. */
/* ARMv8.2-A architecture extensions. */
-#define AARCH64_FL_V8_2 (1 << 8) /* Has ARMv8.2-A features. */
+#define AARCH64_FL_V8_2 (1 << 8) /* Has ARMv8.2-A features. */
#define AARCH64_FL_F16 (1 << 9) /* Has ARMv8.2-A FP16 extensions. */
/* ARMv8.3-A architecture extensions. */
-#define AARCH64_FL_V8_3 (1 << 10) /* Has ARMv8.3-A features. */
-#define AARCH64_FL_RCPC (1 << 11) /* Has support for RCpc model. */
+#define AARCH64_FL_V8_3 (1 << 10) /* Has ARMv8.3-A features. */
+#define AARCH64_FL_RCPC (1 << 11) /* Has support for RCpc model. */
+#define AARCH64_FL_DOTPROD (1 << 12) /* Has ARMv8.2-A Dot Product ins. */
/* Has FP and SIMD. */
#define AARCH64_FL_FPSIMD (AARCH64_FL_FP | AARCH64_FL_SIMD)
@@ -180,6 +173,7 @@ extern unsigned aarch64_architecture_version;
#define AARCH64_ISA_V8_2 (aarch64_isa_flags & AARCH64_FL_V8_2)
#define AARCH64_ISA_F16 (aarch64_isa_flags & AARCH64_FL_F16)
#define AARCH64_ISA_V8_3 (aarch64_isa_flags & AARCH64_FL_V8_3)
+#define AARCH64_ISA_DOTPROD (aarch64_isa_flags & AARCH64_FL_DOTPROD)
/* Crypto is an optional extension to AdvSIMD. */
#define TARGET_CRYPTO (TARGET_SIMD && AARCH64_ISA_CRYPTO)
@@ -194,6 +188,9 @@ extern unsigned aarch64_architecture_version;
#define TARGET_FP_F16INST (TARGET_FLOAT && AARCH64_ISA_F16)
#define TARGET_SIMD_F16INST (TARGET_SIMD && AARCH64_ISA_F16)
+/* Dot Product is an optional extension to AdvSIMD enabled through +dotprod. */
+#define TARGET_DOTPROD (TARGET_SIMD && AARCH64_ISA_DOTPROD)
+
/* ARMv8.3-A features. */
#define TARGET_ARMV8_3 (AARCH64_ISA_V8_3)
@@ -452,6 +449,7 @@ enum reg_class
POINTER_REGS,
FP_LO_REGS,
FP_REGS,
+ POINTER_AND_FP_REGS,
ALL_REGS,
LIM_REG_CLASSES /* Last */
};
@@ -467,6 +465,7 @@ enum reg_class
"POINTER_REGS", \
"FP_LO_REGS", \
"FP_REGS", \
+ "POINTER_AND_FP_REGS", \
"ALL_REGS" \
}
@@ -479,6 +478,7 @@ enum reg_class
{ 0xffffffff, 0x00000000, 0x00000003 }, /* POINTER_REGS */ \
{ 0x00000000, 0x0000ffff, 0x00000000 }, /* FP_LO_REGS */ \
{ 0x00000000, 0xffffffff, 0x00000000 }, /* FP_REGS */ \
+ { 0xffffffff, 0xffffffff, 0x00000003 }, /* POINTER_AND_FP_REGS */\
{ 0xffffffff, 0xffffffff, 0x00000007 } /* ALL_REGS */ \
}
@@ -541,8 +541,6 @@ extern enum aarch64_processor aarch64_tune;
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
-
#define ACCUMULATE_OUTGOING_ARGS 1
#define FIRST_PARM_OFFSET(FNDECL) 0
@@ -954,4 +952,12 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
extern tree aarch64_fp16_type_node;
extern tree aarch64_fp16_ptr_type_node;
+/* The generic unwind code in libgcc does not initialize the frame pointer.
+ So in order to unwind a function using a frame pointer, the very first
+ function that is unwound must save the frame pointer. That way the frame
+ pointer is restored and its value is now valid - otherwise _Unwind_GetGR
+ crashes. Libgcc can now be safely built with -fomit-frame-pointer. */
+#define LIBGCC2_UNWIND_ATTRIBUTE \
+ __attribute__((optimize ("no-omit-frame-pointer")))
+
#endif /* GCC_AARCH64_H */
diff --git a/gcc/config/aarch64/aarch64.md b/gcc/config/aarch64/aarch64.md
index f8cdb06..389f2f9 100644
--- a/gcc/config/aarch64/aarch64.md
+++ b/gcc/config/aarch64/aarch64.md
@@ -4125,6 +4125,35 @@
[(set_attr "type" "shift_reg")]
)
+(define_insn_and_split "*aarch64_reg_<optab>_minus<mode>3"
+ [(set (match_operand:GPI 0 "register_operand" "=&r")
+ (ASHIFT:GPI
+ (match_operand:GPI 1 "register_operand" "r")
+ (minus:QI (match_operand 2 "const_int_operand" "n")
+ (match_operand:QI 3 "register_operand" "r"))))]
+ "INTVAL (operands[2]) == GET_MODE_BITSIZE (<MODE>mode)"
+ "#"
+ "&& true"
+ [(const_int 0)]
+ {
+ rtx subreg_tmp = gen_lowpart (SImode, operands[3]);
+
+ rtx tmp = (can_create_pseudo_p () ? gen_reg_rtx (SImode)
+ : gen_lowpart (SImode, operands[0]));
+
+ emit_insn (gen_negsi2 (tmp, subreg_tmp));
+
+ rtx and_op = gen_rtx_AND (SImode, tmp,
+ GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - 1));
+
+ rtx subreg_tmp2 = gen_lowpart_SUBREG (QImode, and_op);
+
+ emit_insn (gen_<optab><mode>3 (operands[0], operands[1], subreg_tmp2));
+ DONE;
+ }
+ [(set_attr "length" "8")]
+)
+
;; Logical left shift using SISD or Integer instruction
(define_insn "*aarch64_ashl_sisd_or_int_<mode>3"
[(set (match_operand:GPI 0 "register_operand" "=r,r,w,w")
diff --git a/gcc/config/aarch64/arm_neon.h b/gcc/config/aarch64/arm_neon.h
index d7b30b0..96e740f 100644
--- a/gcc/config/aarch64/arm_neon.h
+++ b/gcc/config/aarch64/arm_neon.h
@@ -31541,6 +31541,99 @@ vminnmvq_f16 (float16x8_t __a)
#pragma GCC pop_options
+/* AdvSIMD Dot Product intrinsics. */
+
+#pragma GCC push_options
+#pragma GCC target ("arch=armv8.2-a+dotprod")
+
+__extension__ extern __inline uint32x2_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdot_u32 (uint32x2_t __r, uint8x8_t __a, uint8x8_t __b)
+{
+ return __builtin_aarch64_udotv8qi_uuuu (__r, __a, __b);
+}
+
+__extension__ extern __inline uint32x4_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdotq_u32 (uint32x4_t __r, uint8x16_t __a, uint8x16_t __b)
+{
+ return __builtin_aarch64_udotv16qi_uuuu (__r, __a, __b);
+}
+
+__extension__ extern __inline int32x2_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdot_s32 (int32x2_t __r, int8x8_t __a, int8x8_t __b)
+{
+ return __builtin_aarch64_sdotv8qi (__r, __a, __b);
+}
+
+__extension__ extern __inline int32x4_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdotq_s32 (int32x4_t __r, int8x16_t __a, int8x16_t __b)
+{
+ return __builtin_aarch64_sdotv16qi (__r, __a, __b);
+}
+
+__extension__ extern __inline uint32x2_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdot_lane_u32 (uint32x2_t __r, uint8x8_t __a, uint8x8_t __b, const int __index)
+{
+ return __builtin_aarch64_udot_lanev8qi_uuuus (__r, __a, __b, __index);
+}
+
+__extension__ extern __inline uint32x2_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdot_laneq_u32 (uint32x2_t __r, uint8x8_t __a, uint8x16_t __b,
+ const int __index)
+{
+ return __builtin_aarch64_udot_laneqv8qi_uuuus (__r, __a, __b, __index);
+}
+
+__extension__ extern __inline uint32x4_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdotq_lane_u32 (uint32x4_t __r, uint8x16_t __a, uint8x8_t __b,
+ const int __index)
+{
+ return __builtin_aarch64_udot_lanev16qi_uuuus (__r, __a, __b, __index);
+}
+
+__extension__ extern __inline uint32x4_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdotq_laneq_u32 (uint32x4_t __r, uint8x16_t __a, uint8x16_t __b,
+ const int __index)
+{
+ return __builtin_aarch64_udot_laneqv16qi_uuuus (__r, __a, __b, __index);
+}
+
+__extension__ extern __inline int32x2_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdot_lane_s32 (int32x2_t __r, int8x8_t __a, int8x8_t __b, const int __index)
+{
+ return __builtin_aarch64_sdot_lanev8qi (__r, __a, __b, __index);
+}
+
+__extension__ extern __inline int32x2_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdot_laneq_s32 (int32x2_t __r, int8x8_t __a, int8x16_t __b, const int __index)
+{
+ return __builtin_aarch64_sdot_laneqv8qi (__r, __a, __b, __index);
+}
+
+__extension__ extern __inline int32x4_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdotq_lane_s32 (int32x4_t __r, int8x16_t __a, int8x8_t __b, const int __index)
+{
+ return __builtin_aarch64_sdot_lanev16qi (__r, __a, __b, __index);
+}
+
+__extension__ extern __inline int32x4_t
+__attribute__ ((__always_inline__, __gnu_inline__, __artificial__))
+vdotq_laneq_s32 (int32x4_t __r, int8x16_t __a, int8x16_t __b, const int __index)
+{
+ return __builtin_aarch64_sdot_laneqv16qi (__r, __a, __b, __index);
+}
+#pragma GCC pop_options
+
#undef __aarch64_vget_lane_any
#undef __aarch64_vdup_lane_any
diff --git a/gcc/config/aarch64/constraints.md b/gcc/config/aarch64/constraints.md
index 3649fb4..77c510c 100644
--- a/gcc/config/aarch64/constraints.md
+++ b/gcc/config/aarch64/constraints.md
@@ -190,6 +190,20 @@
(and (match_code "const_double")
(match_test "aarch64_can_const_movi_rtx_p (op, GET_MODE (op))")))
+(define_constraint "Do"
+ "@internal
+ A constraint that matches vector of immediates for orr."
+ (and (match_code "const_vector")
+ (match_test "aarch64_simd_valid_immediate (op, mode, false,
+ NULL, AARCH64_CHECK_ORR)")))
+
+(define_constraint "Db"
+ "@internal
+ A constraint that matches vector of immediates for bic."
+ (and (match_code "const_vector")
+ (match_test "aarch64_simd_valid_immediate (op, mode, false,
+ NULL, AARCH64_CHECK_BIC)")))
+
(define_constraint "Dn"
"@internal
A constraint that matches vector of immediates."
diff --git a/gcc/config/aarch64/iterators.md b/gcc/config/aarch64/iterators.md
index 477dc35..48cedbe 100644
--- a/gcc/config/aarch64/iterators.md
+++ b/gcc/config/aarch64/iterators.md
@@ -354,6 +354,8 @@
UNSPEC_SQRDMLSH ; Used in aarch64-simd.md.
UNSPEC_FMAXNM ; Used in aarch64-simd.md.
UNSPEC_FMINNM ; Used in aarch64-simd.md.
+ UNSPEC_SDOT ; Used in aarch64-simd.md.
+ UNSPEC_UDOT ; Used in aarch64-simd.md.
])
;; ------------------------------------------------------------------
@@ -800,6 +802,10 @@
(define_mode_attr vsi2qi [(V2SI "v8qi") (V4SI "v16qi")])
(define_mode_attr VSI2QI [(V2SI "V8QI") (V4SI "V16QI")])
+
+;; Register suffix for DOTPROD input types from the return type.
+(define_mode_attr Vdottype [(V2SI "8b") (V4SI "16b")])
+
;; Sum of lengths of instructions needed to move vector registers of a mode.
(define_mode_attr insn_count [(OI "8") (CI "12") (XI "16")])
@@ -1029,6 +1035,7 @@
UNSPEC_SHSUB UNSPEC_UHSUB
UNSPEC_SRHSUB UNSPEC_URHSUB])
+(define_int_iterator DOTPROD [UNSPEC_SDOT UNSPEC_UDOT])
(define_int_iterator ADDSUBHN [UNSPEC_ADDHN UNSPEC_RADDHN
UNSPEC_SUBHN UNSPEC_RSUBHN])
@@ -1166,6 +1173,7 @@
(UNSPEC_USHLL "u") (UNSPEC_SSHLL "s")
(UNSPEC_URSHL "ur") (UNSPEC_SRSHL "sr")
(UNSPEC_UQRSHL "u") (UNSPEC_SQRSHL "s")
+ (UNSPEC_SDOT "s") (UNSPEC_UDOT "u")
])
(define_int_attr r [(UNSPEC_SQDMULH "") (UNSPEC_SQRDMULH "r")
diff --git a/gcc/config/aarch64/predicates.md b/gcc/config/aarch64/predicates.md
index 11243c4..bf23b88 100644
--- a/gcc/config/aarch64/predicates.md
+++ b/gcc/config/aarch64/predicates.md
@@ -69,6 +69,18 @@
(ior (match_test "op == constm1_rtx")
(match_test "op == const1_rtx"))))))
+(define_predicate "aarch64_reg_or_orr_imm"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_vector")
+ (match_test "aarch64_simd_valid_immediate (op, mode, false,
+ NULL, AARCH64_CHECK_ORR)"))))
+
+(define_predicate "aarch64_reg_or_bic_imm"
+ (ior (match_operand 0 "register_operand")
+ (and (match_code "const_vector")
+ (match_test "aarch64_simd_valid_immediate (op, mode, false,
+ NULL, AARCH64_CHECK_BIC)"))))
+
(define_predicate "aarch64_fp_compare_operand"
(ior (match_operand 0 "register_operand")
(and (match_code "const_double")
diff --git a/gcc/config/alpha/alpha.c b/gcc/config/alpha/alpha.c
index e0f458c..ece8879 100644
--- a/gcc/config/alpha/alpha.c
+++ b/gcc/config/alpha/alpha.c
@@ -2910,8 +2910,8 @@ alpha_split_conditional_move (enum rtx_code code, rtx dest, rtx cond,
|| (code == GE || code == GT))
{
code = reverse_condition (code);
- diff = t, t = f, f = diff;
- diff = t - f;
+ std::swap (t, f);
+ diff = -diff;
}
subtarget = target = dest;
@@ -6078,10 +6078,8 @@ alpha_stdarg_optimize_hook (struct stdarg_info *si, const gimple *stmt)
else if (code2 == COMPONENT_REF
&& (code1 == MINUS_EXPR || code1 == PLUS_EXPR))
{
- gimple *tem = arg1_stmt;
+ std::swap (arg1_stmt, arg2_stmt);
code2 = code1;
- arg1_stmt = arg2_stmt;
- arg2_stmt = tem;
}
else
goto escapes;
@@ -7760,8 +7758,8 @@ alpha_expand_prologue (void)
Note that we are only allowed to adjust sp once in the prologue. */
probed_size = frame_size;
- if (flag_stack_check)
- probed_size += STACK_CHECK_PROTECT;
+ if (flag_stack_check || flag_stack_clash_protection)
+ probed_size += get_stack_check_protect ();
if (probed_size <= 32768)
{
@@ -7775,7 +7773,7 @@ alpha_expand_prologue (void)
/* We only have to do this probe if we aren't saving registers or
if we are probing beyond the frame because of -fstack-check. */
if ((sa_size == 0 && probed_size > probed - 4096)
- || flag_stack_check)
+ || flag_stack_check || flag_stack_clash_protection)
emit_insn (gen_probe_stack (GEN_INT (-probed_size)));
}
@@ -7805,7 +7803,8 @@ alpha_expand_prologue (void)
late in the compilation, generate the loop as a single insn. */
emit_insn (gen_prologue_stack_probe_loop (count, ptr));
- if ((leftover > 4096 && sa_size == 0) || flag_stack_check)
+ if ((leftover > 4096 && sa_size == 0)
+ || flag_stack_check || flag_stack_clash_protection)
{
rtx last = gen_rtx_MEM (DImode,
plus_constant (Pmode, ptr, -leftover));
@@ -7813,7 +7812,7 @@ alpha_expand_prologue (void)
emit_move_insn (last, const0_rtx);
}
- if (flag_stack_check)
+ if (flag_stack_check || flag_stack_clash_protection)
{
/* If -fstack-check is specified we have to load the entire
constant into a register and subtract from the sp in one go,
@@ -9830,9 +9829,7 @@ alpha_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
&& (*code == GE || *code == GT || *code == GEU || *code == GTU)
&& (REG_P (*op1) || *op1 == const0_rtx))
{
- rtx tem = *op0;
- *op0 = *op1;
- *op1 = tem;
+ std::swap (*op0, *op1);
*code = (int)swap_condition ((enum rtx_code)*code);
}
diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h
index 82d04d6..257c1de 100644
--- a/gcc/config/alpha/alpha.h
+++ b/gcc/config/alpha/alpha.h
@@ -289,7 +289,6 @@ extern enum alpha_fp_trap_mode alpha_fptm;
/* ??? Only if block-move stuff knows about different source/destination
alignment. */
#if 0
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD)
#define DATA_ALIGNMENT(EXP, ALIGN) MAX ((ALIGN), BITS_PER_WORD)
#endif
@@ -494,13 +493,6 @@ enum reg_class {
goes at a more negative offset in the frame. */
/* #define FRAME_GROWS_DOWNWARD 0 */
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-
-#define STARTING_FRAME_OFFSET 0
-
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
On Alpha, don't define this because there are no push insns. */
diff --git a/gcc/config/arc/arc.c b/gcc/config/arc/arc.c
index 61c83fc..a0b66758 100644
--- a/gcc/config/arc/arc.c
+++ b/gcc/config/arc/arc.c
@@ -10657,6 +10657,9 @@ arc_use_anchors_for_symbol_p (const_rtx symbol)
#undef TARGET_USE_ANCHORS_FOR_SYMBOL_P
#define TARGET_USE_ANCHORS_FOR_SYMBOL_P arc_use_anchors_for_symbol_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-arc.h"
diff --git a/gcc/config/arc/arc.h b/gcc/config/arc/arc.h
index 6c63430..1d9063a 100644
--- a/gcc/config/arc/arc.h
+++ b/gcc/config/arc/arc.h
@@ -271,13 +271,6 @@ if (GET_MODE_CLASS (MODE) == MODE_INT \
/* The best alignment to use in cases where we have a choice. */
#define FASTEST_ALIGNMENT 32
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
-
/* Make arrays of chars word-aligned for the same reasons. */
#define LOCAL_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
@@ -665,12 +658,6 @@ extern enum reg_class arc_regno_reg_class[];
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* Offset from the stack pointer register to the first location at which
outgoing arguments are placed. */
#define STACK_POINTER_OFFSET (0)
diff --git a/gcc/config/arm/arm-builtins.c b/gcc/config/arm/arm-builtins.c
index 569f960..6d1b20c 100644
--- a/gcc/config/arm/arm-builtins.c
+++ b/gcc/config/arm/arm-builtins.c
@@ -105,6 +105,13 @@ arm_ternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
= { qualifier_none, qualifier_none, qualifier_none, qualifier_none };
#define TERNOP_QUALIFIERS (arm_ternop_qualifiers)
+/* unsigned T (unsigned T, unsigned T, unsigned T). */
+static enum arm_type_qualifiers
+arm_unsigned_uternop_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
+ qualifier_unsigned };
+#define UTERNOP_QUALIFIERS (arm_unsigned_uternop_qualifiers)
+
/* T (T, immediate). */
static enum arm_type_qualifiers
arm_binop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
@@ -131,6 +138,13 @@ arm_mac_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
qualifier_none, qualifier_lane_index };
#define MAC_LANE_QUALIFIERS (arm_mac_lane_qualifiers)
+/* unsigned T (unsigned T, unsigned T, unsigend T, lane index). */
+static enum arm_type_qualifiers
+arm_umac_lane_qualifiers[SIMD_MAX_BUILTIN_ARGS]
+ = { qualifier_unsigned, qualifier_unsigned, qualifier_unsigned,
+ qualifier_unsigned, qualifier_lane_index };
+#define UMAC_LANE_QUALIFIERS (arm_umac_lane_qualifiers)
+
/* T (T, T, immediate). */
static enum arm_type_qualifiers
arm_ternop_imm_qualifiers[SIMD_MAX_BUILTIN_ARGS]
diff --git a/gcc/config/arm/arm-c.c b/gcc/config/arm/arm-c.c
index 9178937..295f03b 100644
--- a/gcc/config/arm/arm-c.c
+++ b/gcc/config/arm/arm-c.c
@@ -72,11 +72,11 @@ arm_cpu_builtins (struct cpp_reader* pfile)
def_or_undef_macro (pfile, "__ARM_FEATURE_QRDMX", TARGET_NEON_RDMA);
- if (TARGET_CRC32)
- builtin_define ("__ARM_FEATURE_CRC32");
-
+ def_or_undef_macro (pfile, "__ARM_FEATURE_CRC32", TARGET_CRC32);
+ def_or_undef_macro (pfile, "__ARM_FEATURE_DOTPROD", TARGET_DOTPROD);
def_or_undef_macro (pfile, "__ARM_32BIT_STATE", TARGET_32BIT);
+ cpp_undef (pfile, "__ARM_FEATURE_CMSE");
if (arm_arch8 && !arm_arch_notm)
{
if (arm_arch_cmse && use_cmse)
diff --git a/gcc/config/arm/arm-cpus.in b/gcc/config/arm/arm-cpus.in
index d009a9e..0820ad7 100644
--- a/gcc/config/arm/arm-cpus.in
+++ b/gcc/config/arm/arm-cpus.in
@@ -40,6 +40,225 @@
# names in the final compiler. The order within each group is preserved and
# forms the order for the list within the compiler.
+# Most objects in this file support forward references. The major
+# exception is feature groups, which may only refer to previously
+# defined features or feature groups. This is done to avoid the risk
+# of feature groups recursively referencing each other and causing
+# the parser to hang.
+
+# Features - general convention: all lower case.
+
+# Extended multiply
+define feature armv3m
+
+# 26-bit mode support
+define feature mode26
+
+# 32-bit mode support
+define feature mode32
+
+# Architecture rel 4
+define feature armv4
+
+# Architecture rel 5
+define feature armv5
+
+# Thumb aware.
+define feature thumb
+
+# Architecture rel 5e.
+define feature armv5e
+
+# XScale.
+define feature xscale
+
+# Architecture rel 6.
+define feature armv6
+
+# Architecture rel 6k.
+define feature armv6k
+
+# Thumb-2.
+define feature thumb2
+
+# Instructions not present in 'M' profile.
+define feature notm
+
+# Architecture uses be8 mode in big-endian.
+define feature be8
+
+# Thumb division instructions.
+define feature tdiv
+
+# Architecture rel 7e-m.
+define feature armv7em
+
+# Architecture rel 7.
+define feature armv7
+
+# ARM division instructions.
+define feature adiv
+
+# Architecture rel 8.
+define feature armv8
+
+# ARMv8 CRC32 instructions.
+define feature crc32
+
+# XScale v2 (Wireless MMX).
+define feature iwmmxt
+
+# XScale Wireless MMX2.
+define feature iwmmxt2
+
+# Architecture rel 8.1.
+define feature armv8_1
+
+# Architecutre rel 8.2.
+define feature armv8_2
+
+# M-Profile security extensions.
+define feature cmse
+
+# Floating point and Neon extensions.
+# VFPv1 is not supported in GCC.
+
+# Vector floating point v2.
+define feature vfpv2
+
+# Vector floating point v3.
+define feature vfpv3
+
+# Vector floating point v4.
+define feature vfpv4
+
+# Floating point v5.
+define feature fpv5
+
+# ARMv7-A LPAE.
+define feature lpae
+
+# Advanced SIMD instructions.
+define feature neon
+
+# Conversions to/from fp16 (VFPv3 extension).
+define feature fp16conv
+
+# Double precision operations supported.
+define feature fp_dbl
+
+# 32 Double precision registers.
+define feature fp_d32
+
+# Crypto extension to ARMv8.
+define feature crypto
+
+# FP16 data processing (half-precision float).
+define feature fp16
+
+# Dot Product instructions extension to ARMv8.2-a.
+define feature dotprod
+
+# ISA Quirks (errata?). Don't forget to add this to the fgroup
+# ALL_QUIRKS below.
+
+# No volatile memory in IT blocks.
+define feature quirk_no_volatile_ce
+
+# Previously mis-identified by GCC.
+define feature quirk_armv6kz
+
+# Cortex-M3 LDRD quirk.
+define feature quirk_cm3_ldrd
+
+# (Very) slow multiply operations. Should probably be a tuning bit.
+define feature smallmul
+
+# Feature groups. Conventionally all (or mostly) upper case.
+# ALL_FPU lists all the feature bits associated with the floating-point
+# unit; these will all be removed if the floating-point unit is disabled
+# (eg -mfloat-abi=soft). ALL_FPU_INTERNAL must ONLY contain features that
+# form part of a named -mfpu option; it is used to map the capabilities
+# back to a named FPU for the benefit of the assembler.
+#
+# ALL_SIMD_INTERNAL and ALL_SIMD are similarly defined to help with the
+# construction of ALL_FPU and ALL_FPU_INTERNAL; they describe the SIMD
+# extensions that are either part of a named FPU or optional extensions
+# respectively.
+
+
+# List of all cryptographic extensions to stripout if crypto is
+# disabled. Currently, that's trivial, but we define it anyway for
+# consistency with the SIMD and FP disable lists.
+define fgroup ALL_CRYPTO crypto
+
+# List of all SIMD bits to strip out if SIMD is disabled. This does
+# strip off 32 D-registers, but does not remove support for
+# double-precision FP.
+define fgroup ALL_SIMD_INTERNAL fp_d32 neon ALL_CRYPTO
+define fgroup ALL_SIMD ALL_SIMD_INTERNAL dotprod
+
+# List of all FPU bits to strip out if -mfpu is used to override the
+# default. fp16 is deliberately missing from this list.
+define fgroup ALL_FPU_INTERNAL vfpv2 vfpv3 vfpv4 fpv5 fp16conv fp_dbl ALL_SIMD_INTERNAL
+
+# Similarly, but including fp16 and other extensions that aren't part of
+# -mfpu support.
+define fgroup ALL_FP fp16 ALL_FPU_INTERNAL
+
+define fgroup ARMv2 notm
+define fgroup ARMv3 ARMv2 mode32
+define fgroup ARMv3m ARMv3 armv3m
+define fgroup ARMv4 ARMv3m armv4
+define fgroup ARMv4t ARMv4 thumb
+define fgroup ARMv5 ARMv4 armv5
+define fgroup ARMv5t ARMv5 thumb
+define fgroup ARMv5e ARMv5 armv5e
+define fgroup ARMv5te ARMv5e thumb
+define fgroup ARMv5tej ARMv5te
+define fgroup ARMv6 ARMv5te armv6 be8
+define fgroup ARMv6j ARMv6
+define fgroup ARMv6k ARMv6 armv6k
+define fgroup ARMv6z ARMv6
+define fgroup ARMv6kz ARMv6k quirk_armv6kz
+define fgroup ARMv6zk ARMv6k
+define fgroup ARMv6t2 ARMv6 thumb2
+# This is suspect. ARMv6-m doesn't really pull in any useful features
+# from ARMv5* or ARMv6.
+define fgroup ARMv6m mode32 armv3m armv4 thumb armv5 armv5e armv6
+# This is suspect, the 'common' ARMv7 subset excludes the thumb2 'DSP' and
+# integer SIMD instructions that are in ARMv6T2. */
+define fgroup ARMv7 ARMv6m thumb2 armv7
+
+define fgroup ARMv7a ARMv7 notm armv6k
+define fgroup ARMv7ve ARMv7a adiv tdiv lpae
+define fgroup ARMv7r ARMv7a tdiv
+define fgroup ARMv7m ARMv7 tdiv
+define fgroup ARMv7em ARMv7m armv7em
+define fgroup ARMv8a ARMv7ve armv8
+define fgroup ARMv8_1a ARMv8a crc32 armv8_1
+define fgroup ARMv8_2a ARMv8_1a armv8_2
+define fgroup ARMv8m_base ARMv6m armv8 cmse tdiv
+define fgroup ARMv8m_main ARMv7m armv8 cmse
+define fgroup ARMv8r ARMv8a
+
+# Useful combinations.
+define fgroup VFPv2 vfpv2
+define fgroup VFPv3 VFPv2 vfpv3
+define fgroup VFPv4 VFPv3 vfpv4 fp16conv
+define fgroup FPv5 VFPv4 fpv5
+
+define fgroup FP_DBL fp_dbl
+define fgroup FP_D32 FP_DBL fp_d32
+define fgroup FP_ARMv8 FPv5 FP_D32
+define fgroup NEON FP_D32 neon
+define fgroup CRYPTO NEON crypto
+define fgroup DOTPROD NEON dotprod
+
+# List of all quirk bits to strip out when comparing CPU features with
+# architectures.
+define fgroup ALL_QUIRKS quirk_no_volatile_ce quirk_armv6kz quirk_cm3_ldrd
+
# Architecture entries
# format:
# begin arch <name>
@@ -55,38 +274,38 @@ begin arch armv2
tune for arm2
tune flags CO_PROC NO_MODE32
base 2
- isa ARMv2 bit_mode26
+ isa ARMv2 mode26
end arch armv2
begin arch armv2a
tune for arm2
tune flags CO_PROC NO_MODE32
base 2
- isa ARMv2 bit_mode26
+ isa ARMv2 mode26
end arch armv2a
begin arch armv3
tune for arm6
tune flags CO_PROC
base 3
- isa ARMv3 bit_mode26
+ isa ARMv3 mode26
end arch armv3
begin arch armv3m
tune for arm7m
tune flags CO_PROC
base 3M
- isa ARMv3m bit_mode26
+ isa ARMv3m mode26
end arch armv3m
begin arch armv4
tune for arm7tdmi
tune flags CO_PROC
base 4
- isa ARMv4 bit_mode26
+ isa ARMv4 mode26
end arch armv4
-# Strictly, bit_mode26 is a permitted option for v4t, but there are no
+# Strictly, mode26 is a permitted option for v4t, but there are no
# implementations that support it, so we will leave it out for now.
begin arch armv4t
tune for arm7tdmi
@@ -244,14 +463,14 @@ begin arch armv7-a
option fp add VFPv3 FP_DBL
optalias vfpv3-d16 fp
option vfpv3 add VFPv3 FP_D32
- option vfpv3-d16-fp16 add VFPv3 FP_DBL bit_fp16conv
- option vfpv3-fp16 add VFPv3 FP_DBL FP_D32 bit_fp16conv
+ option vfpv3-d16-fp16 add VFPv3 FP_DBL fp16conv
+ option vfpv3-fp16 add VFPv3 FP_DBL FP_D32 fp16conv
option vfpv4-d16 add VFPv4 FP_DBL
option vfpv4 add VFPv4 FP_D32
option simd add VFPv3 NEON
optalias neon simd
optalias neon-vfpv3 simd
- option neon-fp16 add VFPv3 NEON bit_fp16conv
+ option neon-fp16 add VFPv3 NEON fp16conv
option neon-vfpv4 add VFPv4 NEON
option nosimd remove ALL_SIMD
option nofp remove ALL_FP
@@ -266,14 +485,14 @@ begin arch armv7ve
# fp => VFPv4-d16, simd => neon-vfpv4
option vfpv3-d16 add VFPv3 FP_DBL
option vfpv3 add VFPv3 FP_D32
- option vfpv3-d16-fp16 add VFPv3 FP_DBL bit_fp16conv
- option vfpv3-fp16 add VFPv3 FP_DBL FP_D32 bit_fp16conv
+ option vfpv3-d16-fp16 add VFPv3 FP_DBL fp16conv
+ option vfpv3-fp16 add VFPv3 FP_DBL FP_D32 fp16conv
option fp add VFPv4 FP_DBL
optalias vfpv4-d16 fp
option vfpv4 add VFPv4 FP_D32
option neon add VFPv3 NEON
optalias neon-vfpv3 neon
- option neon-fp16 add VFPv3 NEON bit_fp16conv
+ option neon-fp16 add VFPv3 NEON fp16conv
option simd add VFPv4 NEON
optalias neon-vfpv4 simd
option nosimd remove ALL_SIMD
@@ -291,9 +510,9 @@ begin arch armv7-r
optalias vfpv3xd fp.sp
option fp add VFPv3 FP_DBL
optalias vfpv3-d16 fp
- option idiv add bit_adiv
+ option idiv add adiv
option nofp remove ALL_FP
- option noidiv remove bit_adiv
+ option noidiv remove adiv
end arch armv7-r
begin arch armv7-m
@@ -327,7 +546,7 @@ begin arch armv8-a
base 8A
profile A
isa ARMv8a
- option crc add bit_crc32
+ option crc add crc32
option simd add FP_ARMv8 NEON
option crypto add FP_ARMv8 CRYPTO
option nocrypto remove ALL_CRYPTO
@@ -353,10 +572,11 @@ begin arch armv8.2-a
profile A
isa ARMv8_2a
option simd add FP_ARMv8 NEON
- option fp16 add bit_fp16 FP_ARMv8 NEON
+ option fp16 add fp16 FP_ARMv8 NEON
option crypto add FP_ARMv8 CRYPTO
option nocrypto remove ALL_CRYPTO
option nofp remove ALL_FP
+ option dotprod add FP_ARMv8 DOTPROD
end arch armv8.2-a
begin arch armv8-m.base
@@ -372,12 +592,12 @@ begin arch armv8-m.main
base 8M_MAIN
profile M
isa ARMv8m_main
- option dsp add bit_ARMv7em
+ option dsp add armv7em
# fp => FPv5-sp-d16; fp.dp => FPv5-d16
option fp add FPv5
option fp.dp add FPv5 FP_DBL
option nofp remove ALL_FP
- option nodsp remove bit_ARMv7em
+ option nodsp remove armv7em
end arch armv8-m.main
begin arch armv8-r
@@ -386,7 +606,7 @@ begin arch armv8-r
base 8R
profile R
isa ARMv8r
- option crc add bit_crc32
+ option crc add crc32
# fp.sp => fp-armv8 (d16); simd => simd + fp-armv8 + d32 + double precision
# note: no fp option for fp-armv8 (d16) + double precision at the moment
option fp.sp add FPv5
@@ -400,14 +620,14 @@ begin arch iwmmxt
tune for iwmmxt
tune flags LDSCHED STRONG XSCALE
base 5TE
- isa ARMv5te bit_xscale bit_iwmmxt
+ isa ARMv5te xscale iwmmxt
end arch iwmmxt
begin arch iwmmxt2
tune for iwmmxt2
tune flags LDSCHED STRONG XSCALE
base 5TE
- isa ARMv5te bit_xscale bit_iwmmxt bit_iwmmxt2
+ isa ARMv5te xscale iwmmxt iwmmxt2
end arch iwmmxt2
# CPU entries
@@ -783,7 +1003,7 @@ end cpu arm1022e
begin cpu xscale
tune flags LDSCHED XSCALE
architecture armv5te
- isa bit_xscale
+ isa xscale
costs xscale
end cpu xscale
@@ -961,14 +1181,14 @@ begin cpu generic-armv7-a
fpu vfpv3-d16
option vfpv3-d16 add VFPv3 FP_DBL
option vfpv3 add VFPv3 FP_D32
- option vfpv3-d16-fp16 add VFPv3 FP_DBL bit_fp16conv
- option vfpv3-fp16 add VFPv3 FP_D32 bit_fp16conv
+ option vfpv3-d16-fp16 add VFPv3 FP_DBL fp16conv
+ option vfpv3-fp16 add VFPv3 FP_D32 fp16conv
option vfpv4-d16 add VFPv4 FP_DBL
option vfpv4 add VFPv4 FP_D32
option simd add VFPv3 NEON
optalias neon simd
optalias neon-vfpv3 simd
- option neon-fp16 add VFPv3 NEON bit_fp16conv
+ option neon-fp16 add VFPv3 NEON fp16conv
option neon-vfpv4 add VFPv4 NEON
option nosimd remove ALL_SIMD
option nofp remove ALL_FP
@@ -1269,7 +1489,7 @@ begin cpu cortex-a55
cname cortexa55
tune for cortex-a53
tune flags LDSCHED
- architecture armv8.2-a+fp16
+ architecture armv8.2-a+fp16+dotprod
fpu neon-fp-armv8
option crypto add FP_ARMv8 CRYPTO
option nofp remove ALL_FP
@@ -1280,7 +1500,7 @@ begin cpu cortex-a75
cname cortexa75
tune for cortex-a57
tune flags LDSCHED
- architecture armv8.2-a+fp16
+ architecture armv8.2-a+fp16+dotprod
fpu neon-fp-armv8
option crypto add FP_ARMv8 CRYPTO
costs cortex_a73
@@ -1292,7 +1512,7 @@ begin cpu cortex-a75.cortex-a55
cname cortexa75cortexa55
tune for cortex-a53
tune flags LDSCHED
- architecture armv8.2-a+fp16
+ architecture armv8.2-a+fp16+dotprod
fpu neon-fp-armv8
option crypto add FP_ARMv8 CRYPTO
costs cortex_a73
@@ -1312,6 +1532,7 @@ begin cpu cortex-m33
architecture armv8-m.main+dsp
fpu fpv5-sp-d16
option nofp remove ALL_FP
+ option nodsp remove armv7em
costs v7m
end cpu cortex-m33
@@ -1344,7 +1565,7 @@ begin fpu vfpv3
end fpu vfpv3
begin fpu vfpv3-fp16
- isa VFPv3 FP_D32 bit_fp16conv
+ isa VFPv3 FP_D32 fp16conv
end fpu vfpv3-fp16
begin fpu vfpv3-d16
@@ -1352,7 +1573,7 @@ begin fpu vfpv3-d16
end fpu vfpv3-d16
begin fpu vfpv3-d16-fp16
- isa VFPv3 FP_DBL bit_fp16conv
+ isa VFPv3 FP_DBL fp16conv
end fpu vfpv3-d16-fp16
begin fpu vfpv3xd
@@ -1360,7 +1581,7 @@ begin fpu vfpv3xd
end fpu vfpv3xd
begin fpu vfpv3xd-fp16
- isa VFPv3 bit_fp16conv
+ isa VFPv3 fp16conv
end fpu vfpv3xd-fp16
begin fpu neon
@@ -1372,7 +1593,7 @@ begin fpu neon-vfpv3
end fpu neon-vfpv3
begin fpu neon-fp16
- isa VFPv3 NEON bit_fp16conv
+ isa VFPv3 NEON fp16conv
end fpu neon-fp16
begin fpu vfpv4
diff --git a/gcc/config/arm/arm-isa.h b/gcc/config/arm/arm-isa.h
deleted file mode 100644
index dbd29ea..0000000
--- a/gcc/config/arm/arm-isa.h
+++ /dev/null
@@ -1,172 +0,0 @@
-/* ISA feature bits for ARM.
- Copyright (C) 2016-2017 Free Software Foundation, Inc.
- Contributed by ARM Ltd.
-
- 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
- <http://www.gnu.org/licenses/>. */
-
-#ifndef ARM_ISA_FEATURE_H
-#define ARM_ISA_FEATURE_H
-
-enum isa_feature
- {
- isa_nobit, /* Must be first. */
- isa_bit_ARMv3m, /* Extended multiply. */
- isa_bit_mode26, /* 26-bit mode support. */
- isa_bit_mode32, /* 32-bit mode support. */
- isa_bit_ARMv4, /* Architecture rel 4. */
- isa_bit_ARMv5, /* Architecture rel 5. */
- isa_bit_thumb, /* Thumb aware. */
- isa_bit_ARMv5e, /* Architecture rel 5e. */
- isa_bit_xscale, /* XScale. */
- isa_bit_ARMv6, /* Architecture rel 6. */
- isa_bit_ARMv6k, /* Architecture rel 6k. */
- isa_bit_thumb2, /* Thumb-2. */
- isa_bit_notm, /* Instructions not present in 'M' profile. */
- isa_bit_be8, /* Architecture uses be8 mode in big-endian. */
- isa_bit_tdiv, /* Thumb division instructions. */
- isa_bit_ARMv7em, /* Architecture rel 7e-m. */
- isa_bit_ARMv7, /* Architecture rel 7. */
- isa_bit_adiv, /* ARM division instructions. */
- isa_bit_ARMv8, /* Architecture rel 8. */
- isa_bit_crc32, /* ARMv8 CRC32 instructions. */
- isa_bit_iwmmxt, /* XScale v2 (Wireless MMX). */
- isa_bit_iwmmxt2, /* XScale Wireless MMX2. */
- isa_bit_ARMv8_1, /* Architecture rel 8.1. */
- isa_bit_ARMv8_2, /* Architecutre rel 8.2. */
- isa_bit_cmse, /* M-Profile security extensions. */
- /* Floating point and Neon extensions. */
- /* VFPv1 is not supported in GCC. */
- isa_bit_VFPv2, /* Vector floating point v2. */
- isa_bit_VFPv3, /* Vector floating point v3. */
- isa_bit_VFPv4, /* Vector floating point v4. */
- isa_bit_FPv5, /* Floating point v5. */
- isa_bit_lpae, /* ARMv7-A LPAE. */
- isa_bit_neon, /* Advanced SIMD instructions. */
- isa_bit_fp16conv, /* Conversions to/from fp16 (VFPv3 extension). */
- isa_bit_fp_dbl, /* Double precision operations supported. */
- isa_bit_fp_d32, /* 32 Double precision registers. */
- isa_bit_crypto, /* Crypto extension to ARMv8. */
- isa_bit_fp16, /* FP16 data processing (half-precision float). */
-
- /* ISA Quirks (errata?). Don't forget to add this to the list of
- all quirks below. */
- isa_quirk_no_volatile_ce, /* No volatile memory in IT blocks. */
- isa_quirk_ARMv6kz, /* Previously mis-identified by GCC. */
- isa_quirk_cm3_ldrd, /* Cortex-M3 LDRD quirk. */
-
- /* Aren't currently, but probably should be tuning bits. */
- isa_bit_smallmul, /* Slow multiply operations. */
-
- /* Tuning bits. Should be elsewhere. */
- isa_tune_co_proc, /* Has co-processor bus. */
- isa_tune_ldsched, /* Load scheduling necessary. */
- isa_tune_strong, /* StrongARM. */
- isa_tune_wbuf, /* Schedule for write buffer ops (ARM6 & 7 only). */
-
- /* Must be last, used to dimension arrays. */
- isa_num_bits
- };
-
-/* Helper macros for use when defining CPUs and architectures.
-
- There must be no parenthesees in these lists, since they are used
- to initialize arrays. */
-
-#define ISA_ARMv2 isa_bit_notm
-#define ISA_ARMv3 ISA_ARMv2, isa_bit_mode32
-#define ISA_ARMv3m ISA_ARMv3, isa_bit_ARMv3m
-#define ISA_ARMv4 ISA_ARMv3m, isa_bit_ARMv4
-#define ISA_ARMv4t ISA_ARMv4, isa_bit_thumb
-#define ISA_ARMv5 ISA_ARMv4, isa_bit_ARMv5
-#define ISA_ARMv5t ISA_ARMv5, isa_bit_thumb
-#define ISA_ARMv5e ISA_ARMv5, isa_bit_ARMv5e
-#define ISA_ARMv5te ISA_ARMv5e, isa_bit_thumb
-#define ISA_ARMv5tej ISA_ARMv5te
-#define ISA_ARMv6 ISA_ARMv5te, isa_bit_ARMv6, isa_bit_be8
-#define ISA_ARMv6j ISA_ARMv6
-#define ISA_ARMv6k ISA_ARMv6, isa_bit_ARMv6k
-#define ISA_ARMv6z ISA_ARMv6
-#define ISA_ARMv6kz ISA_ARMv6k, isa_quirk_ARMv6kz
-#define ISA_ARMv6zk ISA_ARMv6k
-#define ISA_ARMv6t2 ISA_ARMv6, isa_bit_thumb2
-
-/* This is suspect. ARMv6-m doesn't really pull in any useful features
- from ARMv5* or ARMv6. */
-#define ISA_ARMv6m isa_bit_mode32, isa_bit_ARMv3m, isa_bit_ARMv4, \
- isa_bit_thumb, isa_bit_ARMv5, isa_bit_ARMv5e, isa_bit_ARMv6
-/* This is suspect, the 'common' ARMv7 subset excludes the thumb2 'DSP' and
- integer SIMD instructions that are in ARMv6T2. */
-#define ISA_ARMv7 ISA_ARMv6m, isa_bit_thumb2, isa_bit_ARMv7
-#define ISA_ARMv7a ISA_ARMv7, isa_bit_notm, isa_bit_ARMv6k
-#define ISA_ARMv7ve ISA_ARMv7a, isa_bit_adiv, isa_bit_tdiv, isa_bit_lpae
-#define ISA_ARMv7r ISA_ARMv7a, isa_bit_tdiv
-#define ISA_ARMv7m ISA_ARMv7, isa_bit_tdiv
-#define ISA_ARMv7em ISA_ARMv7m, isa_bit_ARMv7em
-#define ISA_ARMv8a ISA_ARMv7ve, isa_bit_ARMv8
-#define ISA_ARMv8_1a ISA_ARMv8a, isa_bit_crc32, isa_bit_ARMv8_1
-#define ISA_ARMv8_2a ISA_ARMv8_1a, isa_bit_ARMv8_2
-#define ISA_ARMv8m_base ISA_ARMv6m, isa_bit_ARMv8, isa_bit_cmse, isa_bit_tdiv
-#define ISA_ARMv8m_main ISA_ARMv7m, isa_bit_ARMv8, isa_bit_cmse
-#define ISA_ARMv8r ISA_ARMv8a
-
-/* List of all cryptographic extensions to stripout if crypto is
- disabled. Currently, that's trivial, but we define it anyway for
- consistency with the SIMD and FP disable lists. */
-#define ISA_ALL_CRYPTO isa_bit_crypto
-
-/* List of all SIMD bits to strip out if SIMD is disabled. This does
- strip off 32 D-registers, but does not remove support for
- double-precision FP. */
-#define ISA_ALL_SIMD isa_bit_fp_d32, isa_bit_neon, ISA_ALL_CRYPTO
-
-/* List of all FPU bits to strip out if -mfpu is used to override the
- default. isa_bit_fp16 is deliberately missing from this list. */
-#define ISA_ALL_FPU_INTERNAL \
- isa_bit_VFPv2, isa_bit_VFPv3, isa_bit_VFPv4, isa_bit_FPv5, \
- isa_bit_fp16conv, isa_bit_fp_dbl, ISA_ALL_SIMD
-
-/* Similarly, but including fp16 and other extensions that aren't part of
- -mfpu support. */
-#define ISA_ALL_FP isa_bit_fp16, ISA_ALL_FPU_INTERNAL
-
-/* Useful combinations. */
-#define ISA_VFPv2 isa_bit_VFPv2
-#define ISA_VFPv3 ISA_VFPv2, isa_bit_VFPv3
-#define ISA_VFPv4 ISA_VFPv3, isa_bit_VFPv4, isa_bit_fp16conv
-#define ISA_FPv5 ISA_VFPv4, isa_bit_FPv5
-
-#define ISA_FP_DBL isa_bit_fp_dbl
-#define ISA_FP_D32 ISA_FP_DBL, isa_bit_fp_d32
-#define ISA_FP_ARMv8 ISA_FPv5, ISA_FP_D32
-#define ISA_NEON ISA_FP_D32, isa_bit_neon
-#define ISA_CRYPTO ISA_NEON, isa_bit_crypto
-
-/* List of all quirk bits to strip out when comparing CPU features with
- architectures. */
-#define ISA_ALL_QUIRKS isa_quirk_no_volatile_ce, isa_quirk_ARMv6kz, \
- isa_quirk_cm3_ldrd
-
-/* Helper macro so that we can concatenate multiple features together
- with arm-*.def files, since macro substitution can't have commas within an
- argument that lacks parenthesis. */
-#define ISA_FEAT(X) X,
-#endif
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index bc802ad..22e1693 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -287,8 +287,7 @@ static int arm_cortex_a5_branch_cost (bool, bool);
static int arm_cortex_m_branch_cost (bool, bool);
static int arm_cortex_m7_branch_cost (bool, bool);
-static bool arm_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel);
+static bool arm_vectorize_vec_perm_const_ok (machine_mode, vec_perm_indices);
static bool aarch_macro_fusion_pair_p (rtx_insn*, rtx_insn*);
@@ -317,6 +316,7 @@ static opt_scalar_float_mode arm_floatn_mode (int, bool);
static unsigned int arm_hard_regno_nregs (unsigned int, machine_mode);
static bool arm_hard_regno_mode_ok (unsigned int, machine_mode);
static bool arm_modes_tieable_p (machine_mode, machine_mode);
+static HOST_WIDE_INT arm_constant_alignment (const_tree, HOST_WIDE_INT);
/* Table of machine attributes. */
static const struct attribute_spec arm_attribute_table[] =
@@ -796,6 +796,9 @@ static const struct attribute_spec arm_attribute_table[] =
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS arm_can_change_mode_class
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT arm_constant_alignment
/* Obstack for minipool constant handling. */
static struct obstack minipool_obstack;
@@ -968,6 +971,9 @@ int arm_condexec_masklen = 0;
/* Nonzero if chip supports the ARMv8 CRC instructions. */
int arm_arch_crc = 0;
+/* Nonzero if chip supports the AdvSIMD Dot Product instructions. */
+int arm_arch_dotprod = 0;
+
/* Nonzero if chip supports the ARMv8-M security extensions. */
int arm_arch_cmse = 0;
@@ -3367,22 +3373,22 @@ arm_option_override (void)
/* Initialize boolean versions of the architectural flags, for use
in the arm.md file. */
- arm_arch3m = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv3m);
- arm_arch4 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv4);
+ arm_arch3m = bitmap_bit_p (arm_active_target.isa, isa_bit_armv3m);
+ arm_arch4 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv4);
arm_arch4t = arm_arch4 && bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
- arm_arch5 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv5);
- arm_arch5e = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv5e);
+ arm_arch5 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv5);
+ arm_arch5e = bitmap_bit_p (arm_active_target.isa, isa_bit_armv5e);
arm_arch5te = arm_arch5e
&& bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
- arm_arch6 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv6);
- arm_arch6k = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv6k);
+ arm_arch6 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv6);
+ arm_arch6k = bitmap_bit_p (arm_active_target.isa, isa_bit_armv6k);
arm_arch_notm = bitmap_bit_p (arm_active_target.isa, isa_bit_notm);
arm_arch6m = arm_arch6 && !arm_arch_notm;
- arm_arch7 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv7);
- arm_arch7em = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv7em);
- arm_arch8 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv8);
- arm_arch8_1 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv8_1);
- arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_ARMv8_2);
+ arm_arch7 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv7);
+ arm_arch7em = bitmap_bit_p (arm_active_target.isa, isa_bit_armv7em);
+ arm_arch8 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8);
+ arm_arch8_1 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_1);
+ arm_arch8_2 = bitmap_bit_p (arm_active_target.isa, isa_bit_armv8_2);
arm_arch_thumb1 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb);
arm_arch_thumb2 = bitmap_bit_p (arm_active_target.isa, isa_bit_thumb2);
arm_arch_xscale = bitmap_bit_p (arm_active_target.isa, isa_bit_xscale);
@@ -3412,9 +3418,9 @@ arm_option_override (void)
/* And finally, set up some quirks. */
arm_arch_no_volatile_ce
- = bitmap_bit_p (arm_active_target.isa, isa_quirk_no_volatile_ce);
- arm_arch6kz
- = arm_arch6k && bitmap_bit_p (arm_active_target.isa, isa_quirk_ARMv6kz);
+ = bitmap_bit_p (arm_active_target.isa, isa_bit_quirk_no_volatile_ce);
+ arm_arch6kz = arm_arch6k && bitmap_bit_p (arm_active_target.isa,
+ isa_bit_quirk_armv6kz);
/* V5 code we generate is completely interworking capable, so we turn off
TARGET_INTERWORK here to avoid many tests later on. */
@@ -3459,7 +3465,7 @@ arm_option_override (void)
else if (TARGET_HARD_FLOAT_ABI)
{
arm_pcs_default = ARM_PCS_AAPCS_VFP;
- if (!bitmap_bit_p (arm_active_target.isa, isa_bit_VFPv2))
+ if (!bitmap_bit_p (arm_active_target.isa, isa_bit_vfpv2))
error ("-mfloat-abi=hard: selected processor lacks an FPU");
}
else
@@ -3562,7 +3568,7 @@ arm_option_override (void)
/* Enable -mfix-cortex-m3-ldrd by default for Cortex-M3 cores. */
if (fix_cm3_ldrd == 2)
{
- if (bitmap_bit_p (arm_active_target.isa, isa_quirk_cm3_ldrd))
+ if (bitmap_bit_p (arm_active_target.isa, isa_bit_quirk_cm3_ldrd))
fix_cm3_ldrd = 1;
else
fix_cm3_ldrd = 0;
@@ -3666,6 +3672,11 @@ arm_option_override (void)
if (use_cmse && !arm_arch_cmse)
error ("target CPU does not support ARMv8-M Security Extensions");
+ /* We don't clear D16-D31 VFP registers for cmse_nonsecure_call functions
+ and ARMv8-M Baseline and Mainline do not allow such configuration. */
+ if (use_cmse && LAST_VFP_REGNUM > LAST_LO_VFP_REGNUM)
+ error ("ARMv8-M Security Extensions incompatible with selected FPU");
+
/* Disable scheduling fusion by default if it's not armv7 processor
or doesn't prefer ldrd/strd. */
if (flag_schedule_fusion == 2
@@ -5875,7 +5886,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
- tree_to_uhwi (TYPE_MIN_VALUE (index)));
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -5905,7 +5917,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
}
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -5937,7 +5950,8 @@ aapcs_vfp_sub_candidate (const_tree type, machine_mode *modep)
}
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -11239,9 +11253,11 @@ arm_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return current_tune->vec_costs->scalar_to_vec_cost;
case unaligned_load:
+ case vector_gather_load:
return current_tune->vec_costs->vec_unalign_load_cost;
case unaligned_store:
+ case vector_scatter_store:
return current_tune->vec_costs->vec_unalign_store_cost;
case cond_branch_taken:
@@ -15280,12 +15296,23 @@ operands_ok_ldrd_strd (rtx rt, rtx rt2, rtx rn, HOST_WIDE_INT offset,
return true;
}
+/* Return true if a 64-bit access with alignment ALIGN and with a
+ constant offset OFFSET from the base pointer is permitted on this
+ architecture. */
+static bool
+align_ok_ldrd_strd (HOST_WIDE_INT align, HOST_WIDE_INT offset)
+{
+ return (unaligned_access
+ ? (align >= BITS_PER_WORD && (offset & 3) == 0)
+ : (align >= 2 * BITS_PER_WORD && (offset & 7) == 0));
+}
+
/* Helper for gen_operands_ldrd_strd. Returns true iff the memory
operand MEM's address contains an immediate offset from the base
- register and has no side effects, in which case it sets BASE and
- OFFSET accordingly. */
+ register and has no side effects, in which case it sets BASE,
+ OFFSET and ALIGN accordingly. */
static bool
-mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset)
+mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset, HOST_WIDE_INT *align)
{
rtx addr;
@@ -15304,6 +15331,7 @@ mem_ok_for_ldrd_strd (rtx mem, rtx *base, rtx *offset)
gcc_assert (MEM_P (mem));
*offset = const0_rtx;
+ *align = MEM_ALIGN (mem);
addr = XEXP (mem, 0);
@@ -15344,7 +15372,7 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
bool const_store, bool commute)
{
int nops = 2;
- HOST_WIDE_INT offsets[2], offset;
+ HOST_WIDE_INT offsets[2], offset, align[2];
rtx base = NULL_RTX;
rtx cur_base, cur_offset, tmp;
int i, gap;
@@ -15356,7 +15384,8 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
registers, and the corresponding memory offsets. */
for (i = 0; i < nops; i++)
{
- if (!mem_ok_for_ldrd_strd (operands[nops+i], &cur_base, &cur_offset))
+ if (!mem_ok_for_ldrd_strd (operands[nops+i], &cur_base, &cur_offset,
+ &align[i]))
return false;
if (i == 0)
@@ -15470,6 +15499,7 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
/* Swap the instructions such that lower memory is accessed first. */
std::swap (operands[0], operands[1]);
std::swap (operands[2], operands[3]);
+ std::swap (align[0], align[1]);
if (const_store)
std::swap (operands[4], operands[5]);
}
@@ -15483,6 +15513,9 @@ gen_operands_ldrd_strd (rtx *operands, bool load,
if (gap != 4)
return false;
+ if (!align_ok_ldrd_strd (align[0], offset))
+ return false;
+
/* Make sure we generate legal instructions. */
if (operands_ok_ldrd_strd (operands[0], operands[1], base, offset,
false, load))
@@ -19164,7 +19197,8 @@ arm_compute_static_chain_stack_bytes (void)
/* See the defining assertion in arm_expand_prologue. */
if (IS_NESTED (arm_current_func_type ())
&& ((TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
- || (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
&& !df_regs_ever_live_p (LR_REGNUM)))
&& arm_r3_live_at_start_p ()
&& crtl->args.pretend_args_size == 0)
@@ -21466,7 +21500,8 @@ arm_expand_prologue (void)
clobbered when creating the frame, we need to save and restore it. */
clobber_ip = IS_NESTED (func_type)
&& ((TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
- || (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
&& !df_regs_ever_live_p (LR_REGNUM)
&& arm_r3_live_at_start_p ()));
@@ -21680,7 +21715,8 @@ arm_expand_prologue (void)
stack checking. We use IP as the first scratch register, except for the
non-APCS nested functions if LR or r3 are available (see clobber_ip). */
if (!IS_INTERRUPT (func_type)
- && flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ && (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection))
{
unsigned int regno;
@@ -21693,13 +21729,13 @@ arm_expand_prologue (void)
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
- arm_emit_probe_stack_range (STACK_CHECK_PROTECT,
- size - STACK_CHECK_PROTECT,
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+ arm_emit_probe_stack_range (get_stack_check_protect (),
+ size - get_stack_check_protect (),
regno, live_regs_mask);
}
else if (size > 0)
- arm_emit_probe_stack_range (STACK_CHECK_PROTECT, size,
+ arm_emit_probe_stack_range (get_stack_check_protect (), size,
regno, live_regs_mask);
}
@@ -24991,7 +25027,9 @@ thumb1_expand_prologue (void)
current_function_static_stack_size = size;
/* If we have a frame, then do stack checking. FIXME: not implemented. */
- if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK && size)
+ if ((flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
+ && size)
sorry ("-fstack-check=specific for Thumb-1");
amount = offsets->outgoing_args - offsets->saved_regs;
@@ -25067,42 +25105,37 @@ thumb1_expand_prologue (void)
void
cmse_nonsecure_entry_clear_before_return (void)
{
- uint64_t to_clear_mask[2];
+ int regno, maxregno = TARGET_HARD_FLOAT ? LAST_VFP_REGNUM : IP_REGNUM;
uint32_t padding_bits_to_clear = 0;
uint32_t * padding_bits_to_clear_ptr = &padding_bits_to_clear;
- int regno, maxregno = IP_REGNUM;
+ auto_sbitmap to_clear_bitmap (maxregno + 1);
tree result_type;
rtx result_rtl;
- to_clear_mask[0] = (1ULL << (NUM_ARG_REGS)) - 1;
- to_clear_mask[0] |= (1ULL << IP_REGNUM);
+ bitmap_clear (to_clear_bitmap);
+ bitmap_set_range (to_clear_bitmap, R0_REGNUM, NUM_ARG_REGS);
+ bitmap_set_bit (to_clear_bitmap, IP_REGNUM);
/* If we are not dealing with -mfloat-abi=soft we will need to clear VFP
- registers. We also check that TARGET_HARD_FLOAT and !TARGET_THUMB1 hold
- to make sure the instructions used to clear them are present. */
- if (TARGET_HARD_FLOAT && !TARGET_THUMB1)
+ registers. */
+ if (TARGET_HARD_FLOAT)
{
- uint64_t float_mask = (1ULL << (D7_VFP_REGNUM + 1)) - 1;
- maxregno = LAST_VFP_REGNUM;
-
- float_mask &= ~((1ULL << FIRST_VFP_REGNUM) - 1);
- to_clear_mask[0] |= float_mask;
+ int float_bits = D7_VFP_REGNUM - FIRST_VFP_REGNUM + 1;
- float_mask = (1ULL << (maxregno - 63)) - 1;
- to_clear_mask[1] = float_mask;
+ bitmap_set_range (to_clear_bitmap, FIRST_VFP_REGNUM, float_bits);
/* Make sure we don't clear the two scratch registers used to clear the
relevant FPSCR bits in output_return_instruction. */
emit_use (gen_rtx_REG (SImode, IP_REGNUM));
- to_clear_mask[0] &= ~(1ULL << IP_REGNUM);
+ bitmap_clear_bit (to_clear_bitmap, IP_REGNUM);
emit_use (gen_rtx_REG (SImode, 4));
- to_clear_mask[0] &= ~(1ULL << 4);
+ bitmap_clear_bit (to_clear_bitmap, 4);
}
/* If the user has defined registers to be caller saved, these are no longer
restored by the function before returning and must thus be cleared for
security purposes. */
- for (regno = NUM_ARG_REGS; regno < LAST_VFP_REGNUM; regno++)
+ for (regno = NUM_ARG_REGS; regno <= maxregno; regno++)
{
/* We do not touch registers that can be used to pass arguments as per
the AAPCS, since these should never be made callee-saved by user
@@ -25112,29 +25145,45 @@ cmse_nonsecure_entry_clear_before_return (void)
if (IN_RANGE (regno, IP_REGNUM, PC_REGNUM))
continue;
if (call_used_regs[regno])
- to_clear_mask[regno / 64] |= (1ULL << (regno % 64));
+ bitmap_set_bit (to_clear_bitmap, regno);
}
/* Make sure we do not clear the registers used to return the result in. */
result_type = TREE_TYPE (DECL_RESULT (current_function_decl));
if (!VOID_TYPE_P (result_type))
{
+ uint64_t to_clear_return_mask;
result_rtl = arm_function_value (result_type, current_function_decl, 0);
/* No need to check that we return in registers, because we don't
support returning on stack yet. */
- to_clear_mask[0]
- &= ~compute_not_to_clear_mask (result_type, result_rtl, 0,
- padding_bits_to_clear_ptr);
+ gcc_assert (REG_P (result_rtl));
+ to_clear_return_mask
+ = compute_not_to_clear_mask (result_type, result_rtl, 0,
+ padding_bits_to_clear_ptr);
+ if (to_clear_return_mask)
+ {
+ gcc_assert ((unsigned) maxregno < sizeof (long long) * __CHAR_BIT__);
+ for (regno = R0_REGNUM; regno <= maxregno; regno++)
+ {
+ if (to_clear_return_mask & (1ULL << regno))
+ bitmap_clear_bit (to_clear_bitmap, regno);
+ }
+ }
}
if (padding_bits_to_clear != 0)
{
rtx reg_rtx;
+ auto_sbitmap to_clear_arg_regs_bitmap (R0_REGNUM + NUM_ARG_REGS);
+
/* Padding bits to clear is not 0 so we know we are dealing with
returning a composite type, which only uses r0. Let's make sure that
r1-r3 is cleared too, we will use r1 as a scratch register. */
- gcc_assert ((to_clear_mask[0] & 0xe) == 0xe);
+ bitmap_clear (to_clear_arg_regs_bitmap);
+ bitmap_set_range (to_clear_arg_regs_bitmap, R0_REGNUM + 1,
+ NUM_ARG_REGS - 1);
+ gcc_assert (bitmap_subset_p (to_clear_arg_regs_bitmap, to_clear_bitmap));
reg_rtx = gen_rtx_REG (SImode, R1_REGNUM);
@@ -25156,7 +25205,7 @@ cmse_nonsecure_entry_clear_before_return (void)
for (regno = R0_REGNUM; regno <= maxregno; regno++)
{
- if (!(to_clear_mask[regno / 64] & (1ULL << (regno % 64))))
+ if (!bitmap_bit_p (to_clear_bitmap, regno))
continue;
if (IS_VFP_REGNUM (regno))
@@ -25165,7 +25214,7 @@ cmse_nonsecure_entry_clear_before_return (void)
be cleared, use vmov. */
if (TARGET_VFP_DOUBLE
&& VFP_REGNO_OK_FOR_DOUBLE (regno)
- && to_clear_mask[regno / 64] & (1ULL << ((regno % 64) + 1)))
+ && bitmap_bit_p (to_clear_bitmap, regno + 1))
{
emit_move_insn (gen_rtx_REG (DFmode, regno),
CONST1_RTX (DFmode));
@@ -26835,7 +26884,7 @@ arm_set_return_address (rtx source, rtx scratch)
{
arm_stack_offsets *offsets;
HOST_WIDE_INT delta;
- rtx addr;
+ rtx addr, mem;
unsigned long saved_regs;
offsets = arm_get_frame_offsets ();
@@ -26865,11 +26914,12 @@ arm_set_return_address (rtx source, rtx scratch)
addr = plus_constant (Pmode, addr, delta);
}
- /* The store needs to be marked as frame related in order to prevent
- DSE from deleting it as dead if it is based on fp. */
- rtx insn = emit_move_insn (gen_frame_mem (Pmode, addr), source);
- RTX_FRAME_RELATED_P (insn) = 1;
- add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (Pmode, LR_REGNUM));
+
+ /* The store needs to be marked to prevent DSE from deleting
+ it as dead if it is based on fp. */
+ mem = gen_frame_mem (Pmode, addr);
+ MEM_VOLATILE_P (mem) = true;
+ emit_move_insn (mem, source);
}
}
@@ -26881,7 +26931,7 @@ thumb_set_return_address (rtx source, rtx scratch)
HOST_WIDE_INT delta;
HOST_WIDE_INT limit;
int reg;
- rtx addr;
+ rtx addr, mem;
unsigned long mask;
emit_use (source);
@@ -26921,11 +26971,11 @@ thumb_set_return_address (rtx source, rtx scratch)
else
addr = plus_constant (Pmode, addr, delta);
- /* The store needs to be marked as frame related in order to prevent
- DSE from deleting it as dead if it is based on fp. */
- rtx insn = emit_move_insn (gen_frame_mem (Pmode, addr), source);
- RTX_FRAME_RELATED_P (insn) = 1;
- add_reg_note (insn, REG_CFA_RESTORE, gen_rtx_REG (Pmode, LR_REGNUM));
+ /* The store needs to be marked to prevent DSE from deleting
+ it as dead if it is based on fp. */
+ mem = gen_frame_mem (Pmode, addr);
+ MEM_VOLATILE_P (mem) = true;
+ emit_move_insn (mem, source);
}
else
emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
@@ -27871,7 +27921,8 @@ arm_frame_pointer_required (void)
instruction prior to the stack adjustment and this requires a frame
pointer if we want to catch the exception using the EABI unwinder. */
if (!IS_INTERRUPT (arm_current_func_type ())
- && flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ && (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
&& arm_except_unwind_info (&global_options) == UI_TARGET
&& cfun->can_throw_non_call_exceptions)
{
@@ -27886,7 +27937,7 @@ arm_frame_pointer_required (void)
{
/* We don't have the final size of the frame so adjust. */
size += 32 * UNITS_PER_WORD;
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
return true;
}
else
@@ -28651,9 +28702,8 @@ arm_split_atomic_op (enum rtx_code code, rtx old_out, rtx new_out, rtx mem,
struct expand_vec_perm_d
{
rtx target, op0, op1;
- unsigned char perm[MAX_VECT_LEN];
+ auto_vec_perm_indices perm;
machine_mode vmode;
- unsigned char nelt;
bool one_vector_p;
bool testing_p;
};
@@ -28760,7 +28810,7 @@ neon_pair_endian_lane_map (machine_mode mode, int lane)
static bool
arm_evpc_neon_vuzp (struct expand_vec_perm_d *d)
{
- unsigned int i, odd, mask, nelt = d->nelt;
+ unsigned int i, odd, mask, nelt = d->perm.length ();
rtx out0, out1, in0, in1;
rtx (*gen)(rtx, rtx, rtx, rtx);
int first_elem;
@@ -28772,7 +28822,7 @@ arm_evpc_neon_vuzp (struct expand_vec_perm_d *d)
/* arm_expand_vec_perm_const_1 () helpfully swaps the operands for the
big endian pattern on 64 bit vectors, so we correct for that. */
swap_nelt = BYTES_BIG_ENDIAN && !d->one_vector_p
- && GET_MODE_SIZE (d->vmode) == 8 ? d->nelt : 0;
+ && GET_MODE_SIZE (d->vmode) == 8 ? nelt : 0;
first_elem = d->perm[neon_endian_lane_map (d->vmode, 0)] ^ swap_nelt;
@@ -28831,7 +28881,7 @@ arm_evpc_neon_vuzp (struct expand_vec_perm_d *d)
static bool
arm_evpc_neon_vzip (struct expand_vec_perm_d *d)
{
- unsigned int i, high, mask, nelt = d->nelt;
+ unsigned int i, high, mask, nelt = d->perm.length ();
rtx out0, out1, in0, in1;
rtx (*gen)(rtx, rtx, rtx, rtx);
int first_elem;
@@ -28906,7 +28956,7 @@ arm_evpc_neon_vzip (struct expand_vec_perm_d *d)
static bool
arm_evpc_neon_vrev (struct expand_vec_perm_d *d)
{
- unsigned int i, j, diff, nelt = d->nelt;
+ unsigned int i, j, diff, nelt = d->perm.length ();
rtx (*gen)(rtx, rtx);
if (!d->one_vector_p)
@@ -28982,7 +29032,7 @@ arm_evpc_neon_vrev (struct expand_vec_perm_d *d)
static bool
arm_evpc_neon_vtrn (struct expand_vec_perm_d *d)
{
- unsigned int i, odd, mask, nelt = d->nelt;
+ unsigned int i, odd, mask, nelt = d->perm.length ();
rtx out0, out1, in0, in1;
rtx (*gen)(rtx, rtx, rtx, rtx);
@@ -29048,7 +29098,7 @@ arm_evpc_neon_vtrn (struct expand_vec_perm_d *d)
static bool
arm_evpc_neon_vext (struct expand_vec_perm_d *d)
{
- unsigned int i, nelt = d->nelt;
+ unsigned int i, nelt = d->perm.length ();
rtx (*gen) (rtx, rtx, rtx, rtx);
rtx offset;
@@ -29122,7 +29172,7 @@ arm_evpc_neon_vtbl (struct expand_vec_perm_d *d)
{
rtx rperm[MAX_VECT_LEN], sel;
machine_mode vmode = d->vmode;
- unsigned int i, nelt = d->nelt;
+ unsigned int i, nelt = d->perm.length ();
/* TODO: ARM's VTBL indexing is little-endian. In order to handle GCC's
numbering of elements for big-endian, we must reverse the order. */
@@ -29159,11 +29209,10 @@ arm_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
/* The pattern matching functions above are written to look for a small
number to begin the sequence (0, 1, N/2). If we begin with an index
from the second operand, we can swap the operands. */
- if (d->perm[0] >= d->nelt)
+ unsigned int nelt = d->perm.length ();
+ if (d->perm[0] >= nelt)
{
- unsigned i, nelt = d->nelt;
-
- for (i = 0; i < nelt; ++i)
+ for (unsigned int i = 0; i < nelt; ++i)
d->perm[i] = (d->perm[i] + nelt) & (2 * nelt - 1);
std::swap (d->op0, d->op1);
@@ -29198,15 +29247,16 @@ arm_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel)
d.vmode = GET_MODE (target);
gcc_assert (VECTOR_MODE_P (d.vmode));
- d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
d.testing_p = false;
+ nelt = GET_MODE_NUNITS (d.vmode);
+ d.perm.reserve (nelt);
for (i = which = 0; i < nelt; ++i)
{
rtx e = XVECEXP (sel, 0, i);
int ei = INTVAL (e) & (2 * nelt - 1);
which |= (ei < nelt ? 1 : 2);
- d.perm[i] = ei;
+ d.perm.quick_push (ei);
}
switch (which)
@@ -29243,22 +29293,21 @@ arm_expand_vec_perm_const (rtx target, rtx op0, rtx op1, rtx sel)
/* Implement TARGET_VECTORIZE_VEC_PERM_CONST_OK. */
static bool
-arm_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel)
+arm_vectorize_vec_perm_const_ok (machine_mode vmode, vec_perm_indices sel)
{
struct expand_vec_perm_d d;
unsigned int i, nelt, which;
bool ret;
d.vmode = vmode;
- d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
d.testing_p = true;
- memcpy (d.perm, sel, nelt);
+ d.perm.safe_splice (sel);
/* Categorize the set of elements in the selector. */
+ nelt = GET_MODE_NUNITS (d.vmode);
for (i = which = 0; i < nelt; ++i)
{
- unsigned char e = d.perm[i];
+ unsigned int e = d.perm[i];
gcc_assert (e < 2 * nelt);
which |= (e < nelt ? 1 : 2);
}
@@ -30342,6 +30391,8 @@ arm_const_not_ok_for_debug_p (rtx p)
tree decl_op0 = NULL;
tree decl_op1 = NULL;
+ if (GET_CODE (p) == UNSPEC)
+ return true;
if (GET_CODE (p) == MINUS)
{
if (GET_CODE (XEXP (p, 1)) == SYMBOL_REF)
@@ -31273,6 +31324,18 @@ arm_can_change_mode_class (machine_mode from, machine_mode to,
return true;
}
+/* Implement TARGET_CONSTANT_ALIGNMENT. Make strings word-aligned so
+ strcpy from constants will be faster. */
+
+static HOST_WIDE_INT
+arm_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ unsigned int factor = (TARGET_THUMB || ! arm_tune_xscale ? 1 : 2);
+ if (TREE_CODE (exp) == STRING_CST && !optimize_size)
+ return MAX (align, BITS_PER_WORD * factor);
+ return align;
+}
+
#if CHECKING_P
namespace selftest {
@@ -31358,10 +31421,43 @@ arm_test_cpu_arch_data (void)
}
}
+/* Scan the static data tables generated by parsecpu.awk looking for
+ potential issues with the data. Here we check for consistency between the
+ fpu bits, in particular we check that ISA_ALL_FPU_INTERNAL does not contain
+ a feature bit that is not defined by any FPU flag. */
+static void
+arm_test_fpu_data (void)
+{
+ auto_sbitmap isa_all_fpubits (isa_num_bits);
+ auto_sbitmap fpubits (isa_num_bits);
+ auto_sbitmap tmpset (isa_num_bits);
+
+ static const enum isa_feature fpu_bitlist[]
+ = { ISA_ALL_FPU_INTERNAL, isa_nobit };
+ arm_initialize_isa (isa_all_fpubits, fpu_bitlist);
+
+ for (unsigned int i = 0; i < TARGET_FPU_auto; i++)
+ {
+ arm_initialize_isa (fpubits, all_fpus[i].isa_bits);
+ bitmap_and_compl (tmpset, isa_all_fpubits, fpubits);
+ bitmap_clear (isa_all_fpubits);
+ bitmap_copy (isa_all_fpubits, tmpset);
+ }
+
+ if (!bitmap_empty_p (isa_all_fpubits))
+ {
+ fprintf (stderr, "Error: found feature bits in the ALL_FPU_INTERAL"
+ " group that are not defined by any FPU.\n"
+ " Check your arm-cpus.in.\n");
+ ASSERT_TRUE (bitmap_empty_p (isa_all_fpubits));
+ }
+}
+
static void
arm_run_selftests (void)
{
arm_test_cpu_arch_data ();
+ arm_test_fpu_data ();
}
} /* Namespace selftest. */
diff --git a/gcc/config/arm/arm.h b/gcc/config/arm/arm.h
index e359946..9567f6d 100644
--- a/gcc/config/arm/arm.h
+++ b/gcc/config/arm/arm.h
@@ -122,7 +122,7 @@ extern tree arm_fp16_type_node;
/* Use hardware floating point instructions. */
#define TARGET_HARD_FLOAT (arm_float_abi != ARM_FLOAT_ABI_SOFT \
&& bitmap_bit_p (arm_active_target.isa, \
- isa_bit_VFPv2))
+ isa_bit_vfpv2))
#define TARGET_SOFT_FLOAT (!TARGET_HARD_FLOAT)
/* User has permitted use of FP instructions, if they exist for this
target. */
@@ -169,10 +169,10 @@ extern tree arm_fp16_type_node;
#define TARGET_VFPD32 (bitmap_bit_p (arm_active_target.isa, isa_bit_fp_d32))
/* FPU supports VFPv3 instructions. */
-#define TARGET_VFP3 (bitmap_bit_p (arm_active_target.isa, isa_bit_VFPv3))
+#define TARGET_VFP3 (bitmap_bit_p (arm_active_target.isa, isa_bit_vfpv3))
/* FPU supports FPv5 instructions. */
-#define TARGET_VFP5 (bitmap_bit_p (arm_active_target.isa, isa_bit_FPv5))
+#define TARGET_VFP5 (bitmap_bit_p (arm_active_target.isa, isa_bit_fpv5))
/* FPU only supports VFP single-precision instructions. */
#define TARGET_VFP_SINGLE (!TARGET_VFP_DOUBLE)
@@ -194,7 +194,7 @@ extern tree arm_fp16_type_node;
(TARGET_HARD_FLOAT && (TARGET_FP16 && TARGET_VFP5))
/* FPU supports fused-multiply-add operations. */
-#define TARGET_FMA (bitmap_bit_p (arm_active_target.isa, isa_bit_VFPv4))
+#define TARGET_FMA (bitmap_bit_p (arm_active_target.isa, isa_bit_vfpv4))
/* FPU supports Crypto extensions. */
#define TARGET_CRYPTO (bitmap_bit_p (arm_active_target.isa, isa_bit_crypto))
@@ -210,6 +210,11 @@ extern tree arm_fp16_type_node;
/* FPU supports ARMv8.1 Adv.SIMD extensions. */
#define TARGET_NEON_RDMA (TARGET_NEON && arm_arch8_1)
+/* Supports for Dot Product AdvSIMD extensions. */
+#define TARGET_DOTPROD (TARGET_NEON \
+ && bitmap_bit_p (arm_active_target.isa, \
+ isa_bit_dotprod))
+
/* FPU supports the floating point FP16 instructions for ARMv8.2 and later. */
#define TARGET_VFP_FP16INST \
(TARGET_32BIT && TARGET_HARD_FLOAT && TARGET_VFP5 && arm_fp16_inst)
@@ -592,15 +597,6 @@ extern int arm_arch_cmse;
#define BIGGEST_FIELD_ALIGNMENT 64
#endif
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT_FACTOR (TARGET_THUMB || ! arm_tune_xscale ? 1 : 2)
-
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && !optimize_size \
- && (ALIGN) < BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR) \
- ? BITS_PER_WORD * CONSTANT_ALIGNMENT_FACTOR : (ALIGN))
-
/* Align definitions of arrays, unions and structures so that
initializations and copies can be made more efficient. This is not
ABI-changing, so it only affects places where we can see the
@@ -1260,12 +1256,6 @@ enum reg_class
&& crtl->outgoing_args_size != 0 \
? UNITS_PER_WORD : 0)
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by. */
/* The push insns do not do this rounding implicitly.
@@ -2237,9 +2227,12 @@ const char *arm_be8_option (int argc, const char **argv);
" %{mfloat-abi=*: abi %*}" \
" %<march=*) "
+/* Complete set of specs for the driver. Commas separate the
+ individual rules so that any option suppression (%<opt...)is
+ completed before starting subsequent rules. */
#define DRIVER_SELF_SPECS \
- MCPU_MTUNE_NATIVE_SPECS \
- TARGET_MODE_SPECS \
+ MCPU_MTUNE_NATIVE_SPECS, \
+ TARGET_MODE_SPECS, \
ARCH_CANONICAL_SPECS
#define TARGET_SUPPORTS_WIDE_INT 1
diff --git a/gcc/config/arm/arm_neon_builtins.def b/gcc/config/arm/arm_neon_builtins.def
index 07f0368..982eec8 100644
--- a/gcc/config/arm/arm_neon_builtins.def
+++ b/gcc/config/arm/arm_neon_builtins.def
@@ -331,3 +331,7 @@ VAR11 (STORE1, vst4,
v8qi, v4hi, v4hf, v2si, v2sf, di, v16qi, v8hi, v8hf, v4si, v4sf)
VAR9 (STORE1LANE, vst4_lane,
v8qi, v4hi, v4hf, v2si, v2sf, v8hi, v8hf, v4si, v4sf)
+VAR2 (TERNOP, sdot, v8qi, v16qi)
+VAR2 (UTERNOP, udot, v8qi, v16qi)
+VAR2 (MAC_LANE, sdot_lane, v8qi, v16qi)
+VAR2 (UMAC_LANE, udot_lane, v8qi, v16qi)
diff --git a/gcc/config/arm/iterators.md b/gcc/config/arm/iterators.md
index 7acbaf1..a4fb234 100644
--- a/gcc/config/arm/iterators.md
+++ b/gcc/config/arm/iterators.md
@@ -410,6 +410,8 @@
(define_int_iterator VFM_LANE_AS [UNSPEC_VFMA_LANE UNSPEC_VFMS_LANE])
+(define_int_iterator DOTPROD [UNSPEC_DOT_S UNSPEC_DOT_U])
+
;;----------------------------------------------------------------------------
;; Mode attributes
;;----------------------------------------------------------------------------
@@ -720,6 +722,9 @@
(define_mode_attr pf [(V8QI "p") (V16QI "p") (V2SF "f") (V4SF "f")])
+(define_mode_attr VSI2QI [(V2SI "V8QI") (V4SI "V16QI")])
+(define_mode_attr vsi2qi [(V2SI "v8qi") (V4SI "v16qi")])
+
;;----------------------------------------------------------------------------
;; Code attributes
;;----------------------------------------------------------------------------
@@ -816,6 +821,7 @@
(UNSPEC_VSRA_S_N "s") (UNSPEC_VSRA_U_N "u")
(UNSPEC_VRSRA_S_N "s") (UNSPEC_VRSRA_U_N "u")
(UNSPEC_VCVTH_S "s") (UNSPEC_VCVTH_U "u")
+ (UNSPEC_DOT_S "s") (UNSPEC_DOT_U "u")
])
(define_int_attr vcvth_op
@@ -1003,3 +1009,6 @@
(define_int_attr mrrc [(VUNSPEC_MRRC "mrrc") (VUNSPEC_MRRC2 "mrrc2")])
(define_int_attr MRRC [(VUNSPEC_MRRC "MRRC") (VUNSPEC_MRRC2 "MRRC2")])
+
+(define_int_attr opsuffix [(UNSPEC_DOT_S "s8")
+ (UNSPEC_DOT_U "u8")])
diff --git a/gcc/config/arm/neon.md b/gcc/config/arm/neon.md
index 12ba2d9..e715a5c 100644
--- a/gcc/config/arm/neon.md
+++ b/gcc/config/arm/neon.md
@@ -3044,6 +3044,76 @@
DONE;
})
+;; These instructions map to the __builtins for the Dot Product operations.
+(define_insn "neon_<sup>dot<vsi2qi>"
+ [(set (match_operand:VCVTI 0 "register_operand" "=w")
+ (plus:VCVTI (match_operand:VCVTI 1 "register_operand" "0")
+ (unspec:VCVTI [(match_operand:<VSI2QI> 2
+ "register_operand" "w")
+ (match_operand:<VSI2QI> 3
+ "register_operand" "w")]
+ DOTPROD)))]
+ "TARGET_DOTPROD"
+ "v<sup>dot.<opsuffix>\\t%<V_reg>0, %<V_reg>2, %<V_reg>3"
+ [(set_attr "type" "neon_dot")]
+)
+
+;; These instructions map to the __builtins for the Dot Product
+;; indexed operations.
+(define_insn "neon_<sup>dot_lane<vsi2qi>"
+ [(set (match_operand:VCVTI 0 "register_operand" "=w")
+ (plus:VCVTI (match_operand:VCVTI 1 "register_operand" "0")
+ (unspec:VCVTI [(match_operand:<VSI2QI> 2
+ "register_operand" "w")
+ (match_operand:V8QI 3 "register_operand" "t")
+ (match_operand:SI 4 "immediate_operand" "i")]
+ DOTPROD)))]
+ "TARGET_DOTPROD"
+ {
+ operands[4]
+ = GEN_INT (NEON_ENDIAN_LANE_N (V8QImode, INTVAL (operands[4])));
+ return "v<sup>dot.<opsuffix>\\t%<V_reg>0, %<V_reg>2, %P3[%c4]";
+ }
+ [(set_attr "type" "neon_dot")]
+)
+
+;; These expands map to the Dot Product optab the vectorizer checks for.
+;; The auto-vectorizer expects a dot product builtin that also does an
+;; accumulation into the provided register.
+;; Given the following pattern
+;;
+;; for (i=0; i<len; i++) {
+;; c = a[i] * b[i];
+;; r += c;
+;; }
+;; return result;
+;;
+;; This can be auto-vectorized to
+;; r = a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3];
+;;
+;; given enough iterations. However the vectorizer can keep unrolling the loop
+;; r += a[4]*b[4] + a[5]*b[5] + a[6]*b[6] + a[7]*b[7];
+;; r += a[8]*b[8] + a[9]*b[9] + a[10]*b[10] + a[11]*b[11];
+;; ...
+;;
+;; and so the vectorizer provides r, in which the result has to be accumulated.
+(define_expand "<sup>dot_prod<vsi2qi>"
+ [(set (match_operand:VCVTI 0 "register_operand")
+ (plus:VCVTI (unspec:VCVTI [(match_operand:<VSI2QI> 1
+ "register_operand")
+ (match_operand:<VSI2QI> 2
+ "register_operand")]
+ DOTPROD)
+ (match_operand:VCVTI 3 "register_operand")))]
+ "TARGET_DOTPROD"
+{
+ emit_insn (
+ gen_neon_<sup>dot<vsi2qi> (operands[3], operands[3], operands[1],
+ operands[2]));
+ emit_insn (gen_rtx_SET (operands[0], operands[3]));
+ DONE;
+})
+
(define_expand "neon_copysignf<mode>"
[(match_operand:VCVTF 0 "register_operand")
(match_operand:VCVTF 1 "register_operand")
diff --git a/gcc/config/arm/parsecpu.awk b/gcc/config/arm/parsecpu.awk
index 070d193..0b4fc68 100644
--- a/gcc/config/arm/parsecpu.awk
+++ b/gcc/config/arm/parsecpu.awk
@@ -22,6 +22,7 @@
# data: Print the standard 'C' data tables for the CPUs
# common-data: Print the 'C' data for shared driver/compiler files
# headers: Print the standard 'C' headers for the CPUs
+# isa: Generate the arm-isa.h header
# md: Print the machine description fragment
# opt: Print the option tables fragment
# chkcpu <name>: Checks that <name> is a valid CPU
@@ -31,7 +32,8 @@
function fatal (m) {
print "error ("lineno"): " m > "/dev/stderr"
- exit 1
+ fatal_err = 1
+ if (parse_done) exit 1
}
function toplevel () {
@@ -83,9 +85,44 @@ function tune_flag_pfx (f) {
return "TF_" f
}
-function isa_pfx (f) {
- if (f ~ /^(bit|quirk)_.*/) return "isa_" f
- return "ISA_" f
+# Print out the bits for the features in FLIST, which may be a
+# mixture of fgroup and individual bits. Print each feature needed
+# exactly once. Terminate the list with isa_nobit. Prefix each line by
+# INDENT. Does not print a new line at the end.
+function print_isa_bits_for (flist, indent) {
+ nbits = split (flist, bits)
+
+ for (bit = 1; bit <= nbits; bit++) {
+ if (bits[bit] in features) {
+ pbit[bits[bit]] = 1
+ } else if (bits[bit] in fgroup) {
+ for (gbits in fgrp_bits) {
+ split (gbits, bitsep, SUBSEP)
+ if (bitsep[1] == bits[bit]) {
+ pbit[bitsep[2]] = 1
+ }
+ }
+ } else fatal("feature " bits[bit] " not declared")
+ }
+ zbit = ORS
+ ORS = ""
+ print indent "{\n" indent " "
+ ORS = ", "
+ count = 0
+ for (bname in pbit) {
+ print "isa_bit_" bname
+ count++
+ if (count == 4) {
+ count = 0
+ ORS = ""
+ print "\n" indent " "
+ ORS = ", "
+ }
+ }
+ ORS = ""
+ print "isa_nobit\n" indent "}"
+ ORS = zbit
+ delete pbit
}
function gen_headers () {
@@ -125,6 +162,35 @@ function gen_headers () {
print "};"
}
+function gen_isa () {
+ boilerplate("C")
+ print "enum isa_feature {"
+ print " isa_nobit = 0,"
+ for (fbit in features) {
+ print " isa_bit_" fbit ","
+ }
+ print " isa_num_bits"
+ print "};\n"
+
+ for (fgrp in fgroup) {
+ print "#define ISA_"fgrp " \\"
+ z = ORS
+ ORS = ""
+ first = 1
+ for (bitcomb in fgrp_bits) {
+ split (bitcomb, bitsep, SUBSEP)
+ if (bitsep[1] == fgrp) {
+ if (first) {
+ first = 0
+ } else print ", \\\n"
+ print " isa_bit_" bitsep[2]
+ }
+ }
+ ORS = z
+ print "\n"
+ }
+}
+
function gen_data () {
boilerplate("C")
@@ -155,7 +221,6 @@ function gen_data () {
}
print " {TARGET_CPU_arm_none, 0, NULL}"
print "};"
-
}
function gen_comm_data () {
@@ -172,8 +237,8 @@ function gen_comm_data () {
print " {"
print " \"" opts[opt] "\", " \
cpu_opt_remove[cpus[n],opts[opt]] ", false,"
- print " { " cpu_opt_isa[cpus[n],opts[opt]] ", isa_nobit }"
- print " },"
+ print_isa_bits_for(cpu_opt_isa[cpus[n],opts[opt]], " ")
+ print "\n },"
}
if (cpus[n] in cpu_optaliases) {
naliases = split (cpu_optaliases[cpus[n]], aliases)
@@ -188,8 +253,8 @@ function gen_comm_data () {
print " {"
print " \"" aliases[alias] "\", " \
cpu_opt_remove[cpus[n],equiv] ", true, "
- print " { " cpu_opt_isa[cpus[n],equiv] ", isa_nobit }"
- print " },"
+ print_isa_bits_for(cpu_opt_isa[cpus[n],equiv], " ")
+ print "\n },"
}
}
print " { NULL, false, false, {isa_nobit}}"
@@ -214,8 +279,7 @@ function gen_comm_data () {
if (! (feats[1] in arch_isa)) {
fatal("unknown arch " feats[1] " for cpu " cpus[n])
}
- print " {"
- print " " arch_isa[feats[1]] ","
+ all_isa_bits = arch_isa[feats[1]]
for (m = 2; m <= nfeats; m++) {
if (! ((feats[1], feats[m]) in arch_opt_isa)) {
fatal("unknown feature " feats[m] " for architecture " feats[1])
@@ -223,42 +287,16 @@ function gen_comm_data () {
if (arch_opt_remove[feats[1],feats[m]] == "true") {
fatal("cannot remove features from architecture specs")
}
- # The isa_features array that is being initialized here has a length
- # of max isa_bit_num, which is the last entry in the enum.
- # Logically this means that the number of features is implicitly
- # never more than the number of feature bits we have. This is only
- # true if we don't emit duplicates here. So keep track of which
- # options we have already emitted so we don't emit them twice.
- nopts = split (arch_opt_isa[feats[1],feats[m]], opts, ",")
- for (i = 1; i <= nopts; i++) {
- if (! (opts[i] in seen)) {
- print " " opts[i] ","
- seen[opts[i]]
- }
- }
+ all_isa_bits = all_isa_bits " " arch_opt_isa[feats[1],feats[m]]
}
if (cpus[n] in cpu_fpu) {
- nopts = split (fpu_isa[cpu_fpu[cpus[n]]], opts, ",")
- for (i = 1; i <= nopts; i++) {
- if (! (opts[i] in seen)) {
- print " " opts[i] ","
- seen[opts[i]]
- }
- }
+ all_isa_bits = all_isa_bits " " fpu_isa[cpu_fpu[cpus[n]]]
}
if (cpus[n] in cpu_isa) {
- nopts = split (cpu_isa[cpus[n]], opts, ",")
- for (i = 1; i <= nopts; i++) {
- if (! (opts[i] in seen)) {
- print " " opts[i] ","
- seen[opts[i]]
- }
- }
+ all_isa_bits = all_isa_bits " " cpu_isa[cpus[n]]
}
- delete seen
- print " isa_nobit"
- print " }"
- print " },"
+ print_isa_bits_for(all_isa_bits, " ")
+ print "\n },"
# arch
print " TARGET_ARCH_" arch_cnames[feats[1]]
print " },"
@@ -278,8 +316,8 @@ function gen_comm_data () {
print " {"
print " \"" opts[opt] "\", " \
arch_opt_remove[archs[n],opts[opt]] ", false,"
- print " { " arch_opt_isa[archs[n],opts[opt]] ", isa_nobit }"
- print " },"
+ print_isa_bits_for(arch_opt_isa[archs[n],opts[opt]], " ")
+ print "\n },"
}
if (archs[n] in arch_optaliases) {
naliases = split (arch_optaliases[archs[n]], aliases)
@@ -294,8 +332,8 @@ function gen_comm_data () {
print " {"
print " \"" aliases[alias] "\", " \
arch_opt_remove[archs[n],equiv] ", true, "
- print " { " arch_opt_isa[archs[n],equiv] ", isa_nobit }"
- print " },"
+ print_isa_bits_for(arch_opt_isa[archs[n],equiv], " ")
+ print "\n },"
}
}
print " { NULL, false, false, {isa_nobit}}"
@@ -321,10 +359,8 @@ function gen_comm_data () {
print " arch_opttab_" arch_cnames[archs[n]] ","
} else print " NULL,"
# common.isa_bits
- print " {"
- print " " arch_isa[archs[n]] ","
- print " isa_nobit"
- print " },"
+ print_isa_bits_for(arch_isa[archs[n]], " ")
+ print ","
# arch, base_arch
print " \"" arch_base[archs[n]] "\", BASE_ARCH_" \
arch_base[archs[n]] ","
@@ -351,11 +387,8 @@ function gen_comm_data () {
for (n = 1; n <= nfpus; n++) {
print " {"
print " \"" fpus[n] "\","
- print " {"
- print " " fpu_isa[fpus[n]] ","
- print " isa_nobit"
- print " }"
- print " },"
+ print_isa_bits_for(fpu_isa[fpus[n]], " ")
+ print "\n },"
}
print "};"
@@ -470,25 +503,68 @@ BEGIN {
arch_name = ""
fpu_name = ""
lineno = 0
+ fatal_err = 0
+ parse_done = 0
if (cmd == "") fatal("Usage parsecpu.awk -v cmd=<xyz>")
}
+# New line. Reset parse status and increment line count for error messages
// {
lineno++
parse_ok = 0
}
+# Comments must be on a line on their own.
/^#/ {
parse_ok = 1
}
+/^define feature / {
+ if (NF != 3) fatal("syntax: define feature <name>")
+ toplevel()
+ fbit = $3
+ if (fbit in features) fatal("feature " fbit " already defined")
+ features[fbit] = 1
+ parse_ok = 1
+}
+
+/^define fgroup / {
+ if (NF < 4) fatal("syntax: define fgroup <name> <feature> [<feature>]*")
+ toplevel()
+ fgrp = $3
+ if (fgrp in fgroup) fatal("feature group " fgrp " already defined")
+ if (fgrp in features) fatal("feature group " fgrp " aliases a feature")
+ fcount = NF
+ for (n = 4; n <= fcount; n++) {
+ feat = $n
+ if (feat in features) {
+ fgrp_bits[fgrp,feat] = 1
+ } else if (feat in fgroup) {
+ # fgroups may reference other fgroups, copy their bits
+ # to our bits. To avoid recursion we don't set fgroup[fgrp]
+ # until after we have done this, so such attempts will result
+ # in an invalid group definition.
+ for (bitcomb in fgrp_bits) {
+ split (bitcomb, bitsep, SUBSEP)
+ if (bitsep[1] == feat) {
+ fgrp_bits[fgrp,bitsep[2]] = 1
+ }
+ }
+ } else fatal("feature group member " feat " unrecognized")
+ }
+ fgroup[fgrp] = 1
+ parse_ok = 1
+}
+
/^begin fpu / {
+ if (NF != 3) fatal("syntax: begin fpu <name>")
toplevel()
fpu_name = $3
parse_ok = 1
}
/^end fpu / {
+ if (NF != 3) fatal("syntax: end fpu <name>")
if (fpu_name != $3) fatal("mimatched end fpu")
if (! (fpu_name in fpu_isa)) {
fatal("fpu definition \"" fpu_name "\" lacks an \"isa\" statement")
@@ -501,24 +577,28 @@ BEGIN {
}
/^begin arch / {
+ if (NF != 3) fatal("syntax: begin arch <name>")
toplevel()
arch_name = $3
parse_ok = 1
}
/^[ ]*base / {
+ if (NF != 2) fatal("syntax: base <architecture-base-name>")
if (arch_name == "") fatal("\"base\" statement outside of arch block")
arch_base[arch_name] = $2
parse_ok = 1
}
/^[ ]*profile / {
+ if (NF != 2) fatal("syntax: profile <profile-name>")
if (arch_name == "") fatal("\"profile\" statement outside of arch block")
arch_prof[arch_name] = $2
parse_ok = 1
}
/^end arch / {
+ if (NF != 3) fatal("syntax: end arch <name>")
if (arch_name != $3) fatal("mimatched end arch")
if (! arch_name in arch_tune_for) {
fatal("arch definition lacks a \"tune for\" statement")
@@ -534,18 +614,21 @@ BEGIN {
}
/^begin cpu / {
+ if (NF != 3) fatal("syntax: begin cpu <name>")
toplevel()
cpu_name = $3
parse_ok = 1
}
/^[ ]*cname / {
+ if (NF != 2) fatal("syntax: cname <identifier>")
if (cpu_name == "") fatal("\"cname\" outside of cpu block")
cpu_cnames[cpu_name] = $2
parse_ok = 1
}
/^[ ]*tune for / {
+ if (NF != 3) fatal("syntax: tune for <cpu-name>")
if (cpu_name != "") {
cpu_tune_for[cpu_name] = $3
} else if (arch_name != "") {
@@ -555,6 +638,7 @@ BEGIN {
}
/^[ ]*tune flags / {
+ if (NF < 3) fatal("syntax: tune flags <flag> [<flag>]*")
flags=""
flag_count = NF
for (n = 3; n <= flag_count; n++) {
@@ -571,24 +655,27 @@ BEGIN {
}
/^[ ]*architecture / {
+ if (NF != 2) fatal("syntax: architecture <arch-name>")
if (cpu_name == "") fatal("\"architecture\" outside of cpu block")
cpu_arch[cpu_name] = $2
parse_ok = 1
}
/^[ ]*fpu / {
+ if (NF != 2) fatal("syntax: fpu <fpu-name>")
if (cpu_name == "") fatal("\"fpu\" outside of cpu block")
cpu_fpu[cpu_name] = $2
parse_ok = 1
}
/^[ ]*isa / {
+ if (NF < 2) fatal("syntax: isa <feature-or-fgroup> [<feature-or-fgroup>]*")
flags=""
flag_count = NF
for (n = 2; n <= flag_count; n++) {
if (n == 2) {
- flags = isa_pfx($n)
- } else flags = flags "," isa_pfx($n)
+ flags = $n
+ } else flags = flags " " $n
}
if (cpu_name != "") {
cpu_isa[cpu_name] = flags
@@ -601,6 +688,7 @@ BEGIN {
}
/^[ ]*option / {
+ if (NF < 4) fatal("syntax: option <name> add|remove <feature-or-fgroup>+")
name=$2
if ($3 == "add") {
remove = "false"
@@ -611,8 +699,8 @@ BEGIN {
flag_count = NF
for (n = 4; n <= flag_count; n++) {
if (n == 4) {
- flags = isa_pfx($n)
- } else flags = flags "," isa_pfx($n)
+ flags = $n
+ } else flags = flags " " $n
}
if (cpu_name != "") {
cpu_opts[cpu_name] = cpu_opts[cpu_name] " " name
@@ -627,6 +715,7 @@ BEGIN {
}
/^[ ]*optalias / {
+ if (NF != 3) fatal("syntax: optalias <name> <option-name>")
name=$2
alias=$3
if (cpu_name != "") {
@@ -640,12 +729,14 @@ BEGIN {
}
/^[ ]*costs / {
+ if (NF != 2) fatal("syntax: costs <identifier>")
if (cpu_name == "") fatal("\"costs\" outside of cpu block")
cpu_cost[cpu_name] = $2
parse_ok = 1
}
/^end cpu / {
+ if (NF != 3) fatal("syntax: end cpu <name>")
if (cpu_name != $3) fatal("mimatched end cpu")
if (! (cpu_name in cpu_cnames)) {
cpu_cnames[cpu_name] = cpu_name
@@ -662,6 +753,8 @@ BEGIN {
}
END {
+ parse_done = 1
+ if (fatal_err) exit 1
toplevel()
if (cmd == "data") {
gen_data()
@@ -669,6 +762,8 @@ END {
gen_comm_data()
} else if (cmd == "headers") {
gen_headers()
+ } else if (cmd == "isa") {
+ gen_isa()
} else if (cmd == "md") {
gen_md()
} else if (cmd == "opt") {
diff --git a/gcc/config/arm/t-arm b/gcc/config/arm/t-arm
index 16177e0..d9ff654 100644
--- a/gcc/config/arm/t-arm
+++ b/gcc/config/arm/t-arm
@@ -18,8 +18,7 @@
# along with GCC; see the file COPYING3. If not see
# <http://www.gnu.org/licenses/>.
-TM_H += arm-cpu.h
-GTM_H += arm-cpu.h
+GTM_H += arm-cpu.h arm-isa.h
# All md files - except for arm.md.
# This list should be kept in alphabetical order and updated whenever an md
@@ -87,6 +86,14 @@ s-arm-cpu: $(srcdir)/config/arm/parsecpu.awk \
$(SHELL) $(srcdir)/../move-if-change tmp-arm-cpu.h arm-cpu.h
$(STAMP) s-arm-cpu
+arm-isa.h: s-arm-isa ; @true
+s-arm-isa: $(srcdir)/config/arm/parsecpu.awk \
+ $(srcdir)/config/arm/arm-cpus.in
+ $(AWK) -f $(srcdir)/config/arm/parsecpu.awk -v cmd=isa \
+ $(srcdir)/config/arm/arm-cpus.in > tmp-arm-isa.h
+ $(SHELL) $(srcdir)/../move-if-change tmp-arm-isa.h arm-isa.h
+ $(STAMP) s-arm-isa
+
arm-cpu-data.h: s-arm-data ; @true
s-arm-data: $(srcdir)/config/arm/parsecpu.awk \
$(srcdir)/config/arm/arm-cpus.in
diff --git a/gcc/config/arm/t-multilib b/gcc/config/arm/t-multilib
index ec4b76d..47f3673 100644
--- a/gcc/config/arm/t-multilib
+++ b/gcc/config/arm/t-multilib
@@ -68,7 +68,7 @@ v7ve_vfpv4_simd_variants := +simd
v8_a_nosimd_variants := +crc
v8_a_simd_variants := $(call all_feat_combs, simd crypto)
v8_1_a_simd_variants := $(call all_feat_combs, simd crypto)
-v8_2_a_simd_variants := $(call all_feat_combs, simd fp16 crypto)
+v8_2_a_simd_variants := $(call all_feat_combs, simd fp16 crypto dotprod)
ifneq (,$(HAS_APROFILE))
diff --git a/gcc/config/arm/types.md b/gcc/config/arm/types.md
index 22d993d..03e9cde 100644
--- a/gcc/config/arm/types.md
+++ b/gcc/config/arm/types.md
@@ -316,6 +316,8 @@
; neon_cls_q
; neon_cnt
; neon_cnt_q
+; neon_dot
+; neon_dot_q
; neon_ext
; neon_ext_q
; neon_rbit
@@ -764,6 +766,8 @@
\
neon_abs,\
neon_abs_q,\
+ neon_dot,\
+ neon_dot_q,\
neon_neg,\
neon_neg_q,\
neon_qneg,\
@@ -1110,8 +1114,8 @@
neon_sub, neon_sub_q, neon_sub_widen, neon_sub_long, neon_qsub,\
neon_qsub_q, neon_sub_halve, neon_sub_halve_q,\
neon_sub_halve_narrow_q,\
- neon_abs, neon_abs_q, neon_neg, neon_neg_q, neon_qneg,\
- neon_qneg_q, neon_qabs, neon_qabs_q, neon_abd, neon_abd_q,\
+ neon_abs, neon_abs_q, neon_dot, neon_dot_q, neon_neg, neon_neg_q,\
+ neon_qneg, neon_qneg_q, neon_qabs, neon_qabs_q, neon_abd, neon_abd_q,\
neon_abd_long, neon_minmax, neon_minmax_q, neon_compare,\
neon_compare_q, neon_compare_zero, neon_compare_zero_q,\
neon_arith_acc, neon_arith_acc_q, neon_reduc_add,\
diff --git a/gcc/config/arm/unspecs.md b/gcc/config/arm/unspecs.md
index 99cfa41..c474f4b 100644
--- a/gcc/config/arm/unspecs.md
+++ b/gcc/config/arm/unspecs.md
@@ -410,4 +410,6 @@
UNSPEC_VRNDN
UNSPEC_VRNDP
UNSPEC_VRNDX
+ UNSPEC_DOT_S
+ UNSPEC_DOT_U
])
diff --git a/gcc/config/avr/avr-protos.h b/gcc/config/avr/avr-protos.h
index e4306ea..9ed9480 100644
--- a/gcc/config/avr/avr-protos.h
+++ b/gcc/config/avr/avr-protos.h
@@ -84,7 +84,6 @@ extern void avr_expand_prologue (void);
extern void avr_expand_epilogue (bool);
extern bool avr_emit_movmemhi (rtx*);
extern int avr_epilogue_uses (int regno);
-extern int avr_starting_frame_offset (void);
extern void avr_output_addr_vec (rtx_insn*, rtx);
extern const char *avr_out_sbxx_branch (rtx_insn *insn, rtx operands[]);
diff --git a/gcc/config/avr/avr.c b/gcc/config/avr/avr.c
index 62ddc57..b1d8a84 100644
--- a/gcc/config/avr/avr.c
+++ b/gcc/config/avr/avr.c
@@ -1153,11 +1153,11 @@ avr_outgoing_args_size (void)
}
-/* Implement `STARTING_FRAME_OFFSET'. */
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
/* This is the offset from the frame pointer register to the first stack slot
that contains a variable living in the frame. */
-int
+static HOST_WIDE_INT
avr_starting_frame_offset (void)
{
return 1 + avr_outgoing_args_size ();
@@ -1314,8 +1314,8 @@ avr_build_builtin_va_list (void)
/* Implement `TARGET_BUILTIN_SETJMP_FRAME_VALUE'. */
/* Actual start of frame is virtual_stack_vars_rtx this is offset from
- frame pointer by +STARTING_FRAME_OFFSET.
- Using saved frame = virtual_stack_vars_rtx - STARTING_FRAME_OFFSET
+ frame pointer by +TARGET_STARTING_FRAME_OFFSET.
+ Using saved frame = virtual_stack_vars_rtx - TARGET_STARTING_FRAME_OFFSET
avoids creating add/sub of offset in nonlocal goto and setjmp. */
static rtx
@@ -1323,7 +1323,7 @@ avr_builtin_setjmp_frame_value (void)
{
rtx xval = gen_reg_rtx (Pmode);
emit_insn (gen_subhi3 (xval, virtual_stack_vars_rtx,
- gen_int_mode (STARTING_FRAME_OFFSET, Pmode)));
+ gen_int_mode (avr_starting_frame_offset (), Pmode)));
return xval;
}
@@ -14495,7 +14495,7 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg,
break;
}
- tmap = wide_int_to_tree (map_type, arg[0]);
+ tmap = wide_int_to_tree (map_type, wi::to_wide (arg[0]));
map = TREE_INT_CST_LOW (tmap);
if (TREE_CODE (tval) != INTEGER_CST
@@ -14789,6 +14789,9 @@ avr_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED, tree *arg,
#undef TARGET_LEGITIMATE_COMBINED_INSN
#define TARGET_LEGITIMATE_COMBINED_INSN avr_legitimate_combined_insn
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET avr_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/avr/avr.h b/gcc/config/avr/avr.h
index 6d00dbd..2272df4 100644
--- a/gcc/config/avr/avr.h
+++ b/gcc/config/avr/avr.h
@@ -284,8 +284,6 @@ enum reg_class {
#define STACK_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET avr_starting_frame_offset()
-
#define STACK_POINTER_OFFSET 1
#define FIRST_PARM_OFFSET(FUNDECL) 0
diff --git a/gcc/config/avr/avr.md b/gcc/config/avr/avr.md
index fe5ca30..14f9298 100644
--- a/gcc/config/avr/avr.md
+++ b/gcc/config/avr/avr.md
@@ -334,10 +334,9 @@
(unspec_volatile:HI [(const_int 0)] UNSPECV_GOTO_RECEIVER))]
""
{
+ rtx offset = gen_int_mode (targetm.starting_frame_offset (), Pmode);
emit_move_insn (virtual_stack_vars_rtx,
- gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx,
- gen_int_mode (STARTING_FRAME_OFFSET,
- Pmode)));
+ gen_rtx_PLUS (Pmode, hard_frame_pointer_rtx, offset));
/* ; This might change the hard frame pointer in ways that aren't
; apparent to early optimization passes, so force a clobber. */
emit_clobber (hard_frame_pointer_rtx);
@@ -6804,11 +6803,11 @@
(define_insn_and_split "*iorhi3.ashift8-ext.zerox"
- [(set (match_operand:HI 0 "register_operand" "=r")
+ [(set (match_operand:HI 0 "register_operand" "=r,r")
(ior:HI (ashift:HI (any_extend:HI
- (match_operand:QI 1 "register_operand" "r"))
+ (match_operand:QI 1 "register_operand" "r,r"))
(const_int 8))
- (zero_extend:HI (match_operand:QI 2 "register_operand" "r"))))]
+ (zero_extend:HI (match_operand:QI 2 "register_operand" "0,r"))))]
"optimize"
{ gcc_unreachable(); }
"&& reload_completed"
diff --git a/gcc/config/bfin/bfin.c b/gcc/config/bfin/bfin.c
index 7ef173a..c95f82d 100644
--- a/gcc/config/bfin/bfin.c
+++ b/gcc/config/bfin/bfin.c
@@ -3318,7 +3318,7 @@ bfin_local_alignment (tree type, unsigned align)
memcpy can use 32 bit loads/stores. */
if (TYPE_SIZE (type)
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
- && wi::gtu_p (TYPE_SIZE (type), 8)
+ && wi::gtu_p (wi::to_wide (TYPE_SIZE (type)), 8)
&& align < 32)
return 32;
return align;
@@ -5882,4 +5882,7 @@ bfin_conditional_register_usage (void)
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P bfin_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/bfin/bfin.h b/gcc/config/bfin/bfin.h
index e0443da..e15a05d 100644
--- a/gcc/config/bfin/bfin.h
+++ b/gcc/config/bfin/bfin.h
@@ -252,12 +252,6 @@ extern const char *bfin_library_id_string;
it. */
#define FIRST_PARM_OFFSET(DECL) 0
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* Register to use for pushing function arguments. */
#define STACK_POINTER_REGNUM REG_P6
@@ -321,11 +315,6 @@ extern const char *bfin_library_id_string;
#define LOCAL_ALIGNMENT(TYPE, ALIGN) bfin_local_alignment ((TYPE), (ALIGN))
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
#define TRAMPOLINE_SIZE (TARGET_FDPIC ? 30 : 18)
/* Definitions for register eliminations.
diff --git a/gcc/config/c6x/c6x.h b/gcc/config/c6x/c6x.h
index c8c4073..233ac13 100644
--- a/gcc/config/c6x/c6x.h
+++ b/gcc/config/c6x/c6x.h
@@ -298,7 +298,6 @@ enum reg_class
#define STACK_POINTER_OFFSET 4
/* Likewise for AP (which is the incoming stack pointer). */
#define FIRST_PARM_OFFSET(fundecl) 4
-#define STARTING_FRAME_OFFSET 0
#define FRAME_GROWS_DOWNWARD 1
#define STACK_GROWS_DOWNWARD 1
diff --git a/gcc/config/cr16/cr16.c b/gcc/config/cr16/cr16.c
index c410071..55e0965 100644
--- a/gcc/config/cr16/cr16.c
+++ b/gcc/config/cr16/cr16.c
@@ -200,6 +200,9 @@ static void cr16_print_operand_address (FILE *, machine_mode, rtx);
#undef TARGET_MEMORY_MOVE_COST
#define TARGET_MEMORY_MOVE_COST cr16_memory_move_cost
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
/* Table of machine attributes. */
static const struct attribute_spec cr16_attribute_table[] = {
/* ISRs have special prologue and epilogue requirements. */
diff --git a/gcc/config/cr16/cr16.h b/gcc/config/cr16/cr16.h
index ce54dd74..29f5b85 100644
--- a/gcc/config/cr16/cr16.h
+++ b/gcc/config/cr16/cr16.h
@@ -114,11 +114,6 @@ while (0)
&& ((ALIGN) < BITS_PER_WORD)) \
? (BITS_PER_WORD) : (ALIGN))
-/* In CR16 strings are word-aligned; strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(CONSTANT, ALIGN) \
- (((TREE_CODE (CONSTANT) == STRING_CST) && ((ALIGN) < BITS_PER_WORD)) \
- ? (BITS_PER_WORD) : (ALIGN))
-
#define STRICT_ALIGNMENT 0
#define PCC_BITFIELD_TYPE_MATTERS 1
@@ -354,8 +349,6 @@ enum reg_class
/* Stack layout and calling conventions. */
#define STACK_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
-
#define STACK_POINTER_REGNUM 15
#define FRAME_POINTER_REGNUM 13
diff --git a/gcc/config/cris/cris.c b/gcc/config/cris/cris.c
index 1b2add0..fe80a27 100644
--- a/gcc/config/cris/cris.c
+++ b/gcc/config/cris/cris.c
@@ -165,6 +165,7 @@ static bool cris_function_value_regno_p (const unsigned int);
static void cris_file_end (void);
static unsigned int cris_hard_regno_nregs (unsigned int, machine_mode);
static bool cris_hard_regno_mode_ok (unsigned int, machine_mode);
+static HOST_WIDE_INT cris_constant_alignment (const_tree, HOST_WIDE_INT);
/* This is the parsed result of the "-max-stack-stackframe=" option. If
it (still) is zero, then there was no such option given. */
@@ -287,6 +288,9 @@ int cris_cpu_version = CRIS_DEFAULT_CPU_VERSION;
#undef TARGET_HARD_REGNO_MODE_OK
#define TARGET_HARD_REGNO_MODE_OK cris_hard_regno_mode_ok
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT cris_constant_alignment
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Helper for cris_load_multiple_op and cris_ret_movem_op. */
@@ -4325,6 +4329,23 @@ cris_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
|| (regno != CRIS_MOF_REGNUM && regno != CRIS_ACR_REGNUM)));
}
+/* Implement TARGET_CONSTANT_ALIGNMENT. Note that this hook has the
+ effect of making gcc believe that ALL references to constant stuff
+ (in code segment, like strings) have this alignment. That is a rather
+ rushed assumption. Luckily we do not care about the "alignment"
+ operand to builtin memcpy (only place where it counts), so it doesn't
+ affect any bad spots. */
+
+static HOST_WIDE_INT
+cris_constant_alignment (const_tree, HOST_WIDE_INT basic_align)
+{
+ if (!TARGET_CONST_ALIGN)
+ return basic_align;
+ if (TARGET_ALIGN_BY_32)
+ return MAX (basic_align, 32);
+ return MAX (basic_align, 16);
+}
+
#if 0
/* Various small functions to replace macros. Only called from a
debugger. They might collide with gcc functions or system functions,
diff --git a/gcc/config/cris/cris.h b/gcc/config/cris/cris.h
index b44164f..f9149c7 100644
--- a/gcc/config/cris/cris.h
+++ b/gcc/config/cris/cris.h
@@ -368,17 +368,6 @@ extern int cris_cpu_version;
? (BASIC_ALIGN < 32 ? 32 : BASIC_ALIGN) \
: (BASIC_ALIGN < 16 ? 16 : BASIC_ALIGN)) : BASIC_ALIGN)
-/* Note that CONSTANT_ALIGNMENT has the effect of making gcc believe that
- ALL references to constant stuff (in code segment, like strings) has
- this alignment. That is a rather rushed assumption. Luckily we do not
- care about the "alignment" operand to builtin memcpy (only place where
- it counts), so it doesn't affect any bad spots. */
-#define CONSTANT_ALIGNMENT(CONSTANT, BASIC_ALIGN) \
- (TARGET_CONST_ALIGN \
- ? (TARGET_ALIGN_BY_32 \
- ? (BASIC_ALIGN < 32 ? 32 : BASIC_ALIGN) \
- : (BASIC_ALIGN < 16 ? 16 : BASIC_ALIGN)) : BASIC_ALIGN)
-
/* FIXME: Define LOCAL_ALIGNMENT for word and dword or arrays and
structures (if -mstack-align=), and check that it is good. */
@@ -600,10 +589,6 @@ enum reg_class
#define STACK_GROWS_DOWNWARD 1
#define FRAME_GROWS_DOWNWARD 1
-/* It seems to be indicated in the code (at least 2.1) that this is
- better a constant, and best 0. */
-#define STARTING_FRAME_OFFSET 0
-
#define FIRST_PARM_OFFSET(FNDECL) 0
#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \
diff --git a/gcc/config/darwin-c.c b/gcc/config/darwin-c.c
index 157c2fd..91f08a0 100644
--- a/gcc/config/darwin-c.c
+++ b/gcc/config/darwin-c.c
@@ -433,7 +433,7 @@ add_system_framework_path (char *path)
p->construct = framework_construct_pathname;
using_frameworks = 1;
- add_cpp_dir_path (p, SYSTEM);
+ add_cpp_dir_path (p, INC_SYSTEM);
}
/* Add PATH to the bracket includes. PATH must be malloc-ed and
@@ -451,7 +451,7 @@ add_framework_path (char *path)
p->construct = framework_construct_pathname;
using_frameworks = 1;
- add_cpp_dir_path (p, BRACKET);
+ add_cpp_dir_path (p, INC_BRACKET);
}
static const char *framework_defaults [] =
@@ -488,7 +488,7 @@ darwin_register_objc_includes (const char *sysroot, const char *iprefix,
{
str = concat (iprefix, fname + len, NULL);
/* FIXME: wrap the headers for C++awareness. */
- add_path (str, SYSTEM, /*c++aware=*/false, false);
+ add_path (str, INC_SYSTEM, /*c++aware=*/false, false);
}
/* Should this directory start with the sysroot? */
@@ -497,7 +497,7 @@ darwin_register_objc_includes (const char *sysroot, const char *iprefix,
else
str = update_path (fname, "");
- add_path (str, SYSTEM, /*c++aware=*/false, false);
+ add_path (str, INC_SYSTEM, /*c++aware=*/false, false);
}
}
diff --git a/gcc/config/darwin.c b/gcc/config/darwin.c
index b6dad70..e633b88 100644
--- a/gcc/config/darwin.c
+++ b/gcc/config/darwin.c
@@ -1319,13 +1319,13 @@ darwin_mergeable_constant_section (tree exp,
if (TREE_CODE (size) == INTEGER_CST)
{
- if (wi::eq_p (size, 4))
+ if (wi::to_wide (size) == 4)
return darwin_sections[literal4_section];
- else if (wi::eq_p (size, 8))
+ else if (wi::to_wide (size) == 8)
return darwin_sections[literal8_section];
else if (HAVE_GAS_LITERAL16
&& TARGET_64BIT
- && wi::eq_p (size, 16))
+ && wi::to_wide (size) == 16)
return darwin_sections[literal16_section];
}
}
diff --git a/gcc/config/darwin.opt b/gcc/config/darwin.opt
index 135a9c0..4871014 100644
--- a/gcc/config/darwin.opt
+++ b/gcc/config/darwin.opt
@@ -92,10 +92,10 @@ fterminated-vtables
Driver RejectNegative
gfull
-Driver
+Driver RejectNegative
gused
-Driver
+Driver RejectNegative
headerpad_max_install_names
Driver
diff --git a/gcc/config/epiphany/epiphany.c b/gcc/config/epiphany/epiphany.c
index 67d52b8..26b0f3c 100644
--- a/gcc/config/epiphany/epiphany.c
+++ b/gcc/config/epiphany/epiphany.c
@@ -173,6 +173,12 @@ static rtx_insn *frame_insn (rtx);
#undef TARGET_HARD_REGNO_MODE_OK
#define TARGET_HARD_REGNO_MODE_OK epiphany_hard_regno_mode_ok
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT epiphany_constant_alignment
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET epiphany_starting_frame_offset
bool
epiphany_is_interrupt_p (tree decl)
@@ -3014,4 +3020,23 @@ epiphany_start_function (FILE *file, const char *name, tree decl)
ASM_OUTPUT_FUNCTION_LABEL (file, name, decl);
}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+epiphany_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST)
+ return MAX (align, FASTEST_ALIGNMENT);
+ return align;
+}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
+
+static HOST_WIDE_INT
+epiphany_starting_frame_offset (void)
+{
+ return epiphany_stack_offset;
+}
+
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/epiphany/epiphany.h b/gcc/config/epiphany/epiphany.h
index 303ac5e..c0767b4 100644
--- a/gcc/config/epiphany/epiphany.h
+++ b/gcc/config/epiphany/epiphany.h
@@ -147,12 +147,6 @@ along with GCC; see the file COPYING3. If not see
#define MALLOC_ABI_ALIGNMENT BIGGEST_ALIGNMENT
-/* Make strings dword-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* Make arrays of chars dword-aligned for the same reasons.
Also, align arrays of SImode items. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
@@ -453,12 +447,6 @@ typedef struct GTY (()) machine_function
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET epiphany_stack_offset
-
/* Offset from the stack pointer register to the first location at which
outgoing arguments are placed. */
#define STACK_POINTER_OFFSET epiphany_stack_offset
diff --git a/gcc/config/fr30/fr30.c b/gcc/config/fr30/fr30.c
index d83b2f3..9188481 100644
--- a/gcc/config/fr30/fr30.c
+++ b/gcc/config/fr30/fr30.c
@@ -190,6 +190,9 @@ static int fr30_num_arg_regs (machine_mode, const_tree);
#undef TARGET_TRAMPOLINE_INIT
#define TARGET_TRAMPOLINE_INIT fr30_trampoline_init
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/fr30/fr30.h b/gcc/config/fr30/fr30.h
index 2e6b793..8bcabf5 100644
--- a/gcc/config/fr30/fr30.h
+++ b/gcc/config/fr30/fr30.h
@@ -88,10 +88,6 @@ along with GCC; see the file COPYING3. If not see
&& TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
#define STRICT_ALIGNMENT 1
#define PCC_BITFIELD_TYPE_MATTERS 1
@@ -349,15 +345,6 @@ enum reg_class
are at negative offsets from the frame pointer. */
#define FRAME_GROWS_DOWNWARD 1
-/* Offset from the frame pointer to the first local variable slot to be
- allocated.
-
- If `FRAME_GROWS_DOWNWARD', find the next slot's offset by subtracting the
- first slot's length from `STARTING_FRAME_OFFSET'. Otherwise, it is found by
- adding the length of the first slot to the value `STARTING_FRAME_OFFSET'. */
-/* #define STARTING_FRAME_OFFSET -4 */
-#define STARTING_FRAME_OFFSET 0
-
/* Offset from the stack pointer register to the first location at which
outgoing arguments are placed. If not specified, the default value of zero
is used. This is the proper value for most machines.
diff --git a/gcc/config/frv/frv.c b/gcc/config/frv/frv.c
index 85e22c7..c9877e7 100644
--- a/gcc/config/frv/frv.c
+++ b/gcc/config/frv/frv.c
@@ -523,6 +523,8 @@ static bool frv_modes_tieable_p (machine_mode, machine_mode);
#define TARGET_HARD_REGNO_MODE_OK frv_hard_regno_mode_ok
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P frv_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/frv/frv.h b/gcc/config/frv/frv.h
index 350a59f..7403e1a 100644
--- a/gcc/config/frv/frv.h
+++ b/gcc/config/frv/frv.h
@@ -351,20 +351,6 @@
&& TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-/* If defined, a C expression to compute the alignment given to a constant that
- is being placed in memory. CONSTANT is the constant and ALIGN is the
- alignment that the object would ordinarily have. The value of this macro is
- used instead of that alignment to align the object.
-
- If this macro is not defined, then ALIGN is used.
-
- The typical use of this macro is to increase alignment for string constants
- to be word aligned so that `strcpy' calls that copy constants can be done
- inline. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
/* Define this macro to be the value 1 if instructions will fail to work if
given data not on the nominal alignment. If instructions will merely go
slower in that case, define this macro as 0. */
@@ -980,14 +966,6 @@ typedef struct frv_stack {
are at negative offsets from the frame pointer. */
#define FRAME_GROWS_DOWNWARD 1
-/* Offset from the frame pointer to the first local variable slot to be
- allocated.
-
- If `FRAME_GROWS_DOWNWARD', find the next slot's offset by subtracting the
- first slot's length from `STARTING_FRAME_OFFSET'. Otherwise, it is found by
- adding the length of the first slot to the value `STARTING_FRAME_OFFSET'. */
-#define STARTING_FRAME_OFFSET 0
-
/* Offset from the stack pointer register to the first location at which
outgoing arguments are placed. If not specified, the default value of zero
is used. This is the proper value for most machines.
diff --git a/gcc/config/ft32/ft32.c b/gcc/config/ft32/ft32.c
index fada924..0386e06 100644
--- a/gcc/config/ft32/ft32.c
+++ b/gcc/config/ft32/ft32.c
@@ -940,6 +940,9 @@ ft32_elf_encode_section_info (tree decl, rtx rtl, int first)
}
}
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-ft32.h"
diff --git a/gcc/config/ft32/ft32.h b/gcc/config/ft32/ft32.h
index 6438393..d52bb9a 100644
--- a/gcc/config/ft32/ft32.h
+++ b/gcc/config/ft32/ft32.h
@@ -233,10 +233,6 @@ enum reg_class
pointer to a smaller address. */
#define STACK_GROWS_DOWNWARD 1
-/* Offset from the frame pointer to the first local variable slot to
- be allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* Offset from the argument pointer register to the first argument's
address. On some machines it may depend on the data type of the
function. */
@@ -354,12 +350,6 @@ enum reg_class
is GET_MODE_SIZE(DImode). */
#define MAX_FIXED_MODE_SIZE 32
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* Set this nonzero if move instructions will actually fail to work
when given unaligned data. */
#define STRICT_ALIGNMENT 1
diff --git a/gcc/config/gnu-user.h b/gcc/config/gnu-user.h
index a967b69..df17b18 100644
--- a/gcc/config/gnu-user.h
+++ b/gcc/config/gnu-user.h
@@ -162,11 +162,13 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
LD_STATIC_OPTION " --whole-archive -lasan --no-whole-archive " \
LD_DYNAMIC_OPTION "}}%{!static-libasan:-lasan}"
#undef LIBTSAN_EARLY_SPEC
-#define LIBTSAN_EARLY_SPEC "%{static-libtsan:%{!shared:" \
+#define LIBTSAN_EARLY_SPEC "%{!shared:libtsan_preinit%O%s} " \
+ "%{static-libtsan:%{!shared:" \
LD_STATIC_OPTION " --whole-archive -ltsan --no-whole-archive " \
LD_DYNAMIC_OPTION "}}%{!static-libtsan:-ltsan}"
#undef LIBLSAN_EARLY_SPEC
-#define LIBLSAN_EARLY_SPEC "%{static-liblsan:%{!shared:" \
+#define LIBLSAN_EARLY_SPEC "%{!shared:liblsan_preinit%O%s} " \
+ "%{static-liblsan:%{!shared:" \
LD_STATIC_OPTION " --whole-archive -llsan --no-whole-archive " \
LD_DYNAMIC_OPTION "}}%{!static-liblsan:-llsan}"
#endif
diff --git a/gcc/config/h8300/h8300.h b/gcc/config/h8300/h8300.h
index 8ff3860..9ba82a7 100644
--- a/gcc/config/h8300/h8300.h
+++ b/gcc/config/h8300/h8300.h
@@ -352,13 +352,6 @@ enum reg_class {
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-
-#define STARTING_FRAME_OFFSET 0
-
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
diff --git a/gcc/config/i386/avx512dqintrin.h b/gcc/config/i386/avx512dqintrin.h
index 88e8adb..8e887d8 100644
--- a/gcc/config/i386/avx512dqintrin.h
+++ b/gcc/config/i386/avx512dqintrin.h
@@ -1160,16 +1160,63 @@ extern __inline __m128d
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
_mm_reduce_sd (__m128d __A, __m128d __B, int __C)
{
- return (__m128d) __builtin_ia32_reducesd ((__v2df) __A,
- (__v2df) __B, __C);
+ return (__m128d) __builtin_ia32_reducesd_mask ((__v2df) __A,
+ (__v2df) __B, __C,
+ (__v2df) _mm_setzero_pd (),
+ (__mmask8) -1);
+}
+
+extern __inline __m128d
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+_mm_mask_reduce_sd (__m128d __W, __mmask8 __U, __m128d __A,
+ __m128d __B, int __C)
+{
+ return (__m128d) __builtin_ia32_reducesd_mask ((__v2df) __A,
+ (__v2df) __B, __C,
+ (__v2df) __W,
+ (__mmask8) __U);
+}
+
+extern __inline __m128d
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+_mm_maskz_reduce_sd (__mmask8 __U, __m128d __A, __m128d __B, int __C)
+{
+ return (__m128d) __builtin_ia32_reducesd_mask ((__v2df) __A,
+ (__v2df) __B, __C,
+ (__v2df) _mm_setzero_pd (),
+ (__mmask8) __U);
}
extern __inline __m128
__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
_mm_reduce_ss (__m128 __A, __m128 __B, int __C)
{
- return (__m128) __builtin_ia32_reducess ((__v4sf) __A,
- (__v4sf) __B, __C);
+ return (__m128) __builtin_ia32_reducess_mask ((__v4sf) __A,
+ (__v4sf) __B, __C,
+ (__v4sf) _mm_setzero_ps (),
+ (__mmask8) -1);
+}
+
+
+extern __inline __m128
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+_mm_mask_reduce_ss (__m128 __W, __mmask8 __U, __m128 __A,
+ __m128 __B, int __C)
+{
+ return (__m128) __builtin_ia32_reducess_mask ((__v4sf) __A,
+ (__v4sf) __B, __C,
+ (__v4sf) __W,
+ (__mmask8) __U);
+}
+
+extern __inline __m128
+__attribute__ ((__gnu_inline__, __always_inline__, __artificial__))
+_mm_maskz_reduce_ss (__mmask8 __U, __m128 __A, __m128 __B, int __C)
+{
+ return (__m128) __builtin_ia32_reducess_mask ((__v4sf) __A,
+ (__v4sf) __B, __C,
+ (__v4sf) _mm_setzero_ps (),
+ (__mmask8) __U);
}
extern __inline __m128d
@@ -2449,12 +2496,34 @@ _mm512_fpclass_ps_mask (__m512 __A, const int __imm)
(int) (c),(__mmask8)-1))
#define _mm_reduce_sd(A, B, C) \
- ((__m128d) __builtin_ia32_reducesd ((__v2df)(__m128d)(A), \
- (__v2df)(__m128d)(B), (int)(C))) \
+ ((__m128d) __builtin_ia32_reducesd_mask ((__v2df)(__m128d)(A), \
+ (__v2df)(__m128d)(B), (int)(C), (__v2df) _mm_setzero_pd (), \
+ (__mmask8)-1))
+
+#define _mm_mask_reduce_sd(W, U, A, B, C) \
+ ((__m128d) __builtin_ia32_reducesd_mask ((__v2df)(__m128d)(A), \
+ (__v2df)(__m128d)(B), (int)(C), (__v2df)(__m128d)(W), (__mmask8)(U)))
+
+#define _mm_maskz_reduce_sd(U, A, B, C) \
+ ((__m128d) __builtin_ia32_reducesd_mask ((__v2df)(__m128d)(A), \
+ (__v2df)(__m128d)(B), (int)(C), (__v2df) _mm_setzero_pd (), \
+ (__mmask8)(U)))
#define _mm_reduce_ss(A, B, C) \
- ((__m128) __builtin_ia32_reducess ((__v4sf)(__m128)(A), \
- (__v4sf)(__m128)(A), (int)(C))) \
+ ((__m128) __builtin_ia32_reducess_mask ((__v4sf)(__m128)(A), \
+ (__v4sf)(__m128)(B), (int)(C), (__v4sf) _mm_setzero_ps (), \
+ (__mmask8)-1))
+
+#define _mm_mask_reduce_ss(W, U, A, B, C) \
+ ((__m128) __builtin_ia32_reducess_mask ((__v4sf)(__m128)(A), \
+ (__v4sf)(__m128)(B), (int)(C), (__v4sf)(__m128)(W), (__mmask8)(U)))
+
+#define _mm_maskz_reduce_ss(U, A, B, C) \
+ ((__m128) __builtin_ia32_reducess_mask ((__v4sf)(__m128)(A), \
+ (__v4sf)(__m128)(B), (int)(C), (__v4sf) _mm_setzero_ps (), \
+ (__mmask8)(U)))
+
+
#endif
diff --git a/gcc/config/i386/cet.c b/gcc/config/i386/cet.c
new file mode 100644
index 0000000..a53c499
--- /dev/null
+++ b/gcc/config/i386/cet.c
@@ -0,0 +1,76 @@
+/* Functions for CET/x86.
+ Copyright (C) 2017 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "output.h"
+#include "linux-common.h"
+
+void
+file_end_indicate_exec_stack_and_cet (void)
+{
+ file_end_indicate_exec_stack ();
+
+ if (flag_cf_protection == CF_NONE)
+ return;
+
+ unsigned int feature_1 = 0;
+
+ if (TARGET_IBT)
+ /* GNU_PROPERTY_X86_FEATURE_1_IBT. */
+ feature_1 |= 0x1;
+
+ if (TARGET_SHSTK)
+ /* GNU_PROPERTY_X86_FEATURE_1_SHSTK. */
+ feature_1 |= 0x2;
+
+ if (feature_1)
+ {
+ int p2align = ptr_mode == SImode ? 2 : 3;
+
+ /* Generate GNU_PROPERTY_X86_FEATURE_1_XXX. */
+ switch_to_section (get_section (".note.gnu.property",
+ SECTION_NOTYPE, NULL));
+
+ ASM_OUTPUT_ALIGN (asm_out_file, p2align);
+ /* name length. */
+ fprintf (asm_out_file, ASM_LONG " 1f - 0f\n");
+ /* data length. */
+ fprintf (asm_out_file, ASM_LONG " 4f - 1f\n");
+ /* note type: NT_GNU_PROPERTY_TYPE_0. */
+ fprintf (asm_out_file, ASM_LONG " 5\n");
+ ASM_OUTPUT_LABEL (asm_out_file, "0");
+ /* vendor name: "GNU". */
+ fprintf (asm_out_file, STRING_ASM_OP " \"GNU\"\n");
+ ASM_OUTPUT_LABEL (asm_out_file, "1");
+ ASM_OUTPUT_ALIGN (asm_out_file, p2align);
+ /* pr_type: GNU_PROPERTY_X86_FEATURE_1_AND. */
+ fprintf (asm_out_file, ASM_LONG " 0xc0000002\n");
+ /* pr_datasz. */\
+ fprintf (asm_out_file, ASM_LONG " 3f - 2f\n");
+ ASM_OUTPUT_LABEL (asm_out_file, "2");
+ /* GNU_PROPERTY_X86_FEATURE_1_XXX. */
+ fprintf (asm_out_file, ASM_LONG " 0x%x\n", feature_1);
+ ASM_OUTPUT_LABEL (asm_out_file, "3");
+ ASM_OUTPUT_ALIGN (asm_out_file, p2align);
+ ASM_OUTPUT_LABEL (asm_out_file, "4");
+ }
+}
diff --git a/gcc/config/i386/cetintrin.h b/gcc/config/i386/cetintrin.h
new file mode 100644
index 0000000..b15a776
--- /dev/null
+++ b/gcc/config/i386/cetintrin.h
@@ -0,0 +1,134 @@
+/* Copyright (C) 2015-2017 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
+ <http://www.gnu.org/licenses/>. */
+
+#if !defined _IMMINTRIN_H_INCLUDED
+# error "Never use <cetintrin.h> directly; include <x86intrin.h> instead."
+#endif
+
+#ifndef _CETINTRIN_H_INCLUDED
+#define _CETINTRIN_H_INCLUDED
+
+#ifndef __SHSTK__
+#pragma GCC push_options
+#pragma GCC target ("shstk")
+#define __DISABLE_SHSTK__
+#endif /* __SHSTK__ */
+
+extern __inline unsigned int
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_rdsspd (unsigned int __B)
+{
+ return __builtin_ia32_rdsspd (__B);
+}
+
+#ifdef __x86_64__
+extern __inline unsigned long long
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_rdsspq (unsigned long long __B)
+{
+ return __builtin_ia32_rdsspq (__B);
+}
+#endif
+
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_incsspd (unsigned int __B)
+{
+ __builtin_ia32_incsspd (__B);
+}
+
+#ifdef __x86_64__
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_incsspq (unsigned long long __B)
+{
+ __builtin_ia32_incsspq (__B);
+}
+#endif
+
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_saveprevssp (void)
+{
+ __builtin_ia32_saveprevssp ();
+}
+
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_rstorssp (void *__B)
+{
+ __builtin_ia32_rstorssp (__B);
+}
+
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_wrssd (unsigned int __B, void *__C)
+{
+ __builtin_ia32_wrssd (__B, __C);
+}
+
+#ifdef __x86_64__
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_wrssq (unsigned long long __B, void *__C)
+{
+ __builtin_ia32_wrssq (__B, __C);
+}
+#endif
+
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_wrussd (unsigned int __B, void *__C)
+{
+ __builtin_ia32_wrussd (__B, __C);
+}
+
+#ifdef __x86_64__
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_wrussq (unsigned long long __B, void *__C)
+{
+ __builtin_ia32_wrussq (__B, __C);
+}
+#endif
+
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_setssbsy (void)
+{
+ __builtin_ia32_setssbsy ();
+}
+
+extern __inline void
+__attribute__((__gnu_inline__, __always_inline__, __artificial__))
+_clrssbsy (void *__B)
+{
+ __builtin_ia32_clrssbsy (__B);
+}
+
+#ifdef __DISABLE_SHSTK__
+#undef __DISABLE_SHSTK__
+#pragma GCC pop_options
+#endif /* __DISABLE_SHSTK__ */
+
+#endif /* _CETINTRIN_H_INCLUDED. */
diff --git a/gcc/config/i386/constraints.md b/gcc/config/i386/constraints.md
index 98c05c9..619b465 100644
--- a/gcc/config/i386/constraints.md
+++ b/gcc/config/i386/constraints.md
@@ -332,6 +332,11 @@
of it satisfies the e constraint."
(match_operand 0 "x86_64_hilo_int_operand"))
+(define_constraint "Wf"
+ "32-bit signed integer constant zero extended from word size
+ to double word size."
+ (match_operand 0 "x86_64_dwzext_immediate_operand"))
+
(define_constraint "Z"
"32-bit unsigned integer constant, or a symbolic reference known
to fit that range (for immediate operands in zero-extending x86-64
diff --git a/gcc/config/i386/cpuid.h b/gcc/config/i386/cpuid.h
index b3b0f91..8cb1848 100644
--- a/gcc/config/i386/cpuid.h
+++ b/gcc/config/i386/cpuid.h
@@ -97,12 +97,15 @@
#define bit_AVX512VBMI (1 << 1)
#define bit_PKU (1 << 3)
#define bit_OSPKE (1 << 4)
+#define bit_SHSTK (1 << 7)
+#define bit_GFNI (1 << 8)
#define bit_AVX512VPOPCNTDQ (1 << 14)
#define bit_RDPID (1 << 22)
/* %edx */
#define bit_AVX5124VNNIW (1 << 2)
#define bit_AVX5124FMAPS (1 << 3)
+#define bit_IBT (1 << 20)
/* XFEATURE_ENABLED_MASK register bits (%eax == 13, %ecx == 0) */
#define bit_BNDREGS (1 << 3)
diff --git a/gcc/config/i386/darwin.h b/gcc/config/i386/darwin.h
index fccaf7e..321ed27 100644
--- a/gcc/config/i386/darwin.h
+++ b/gcc/config/i386/darwin.h
@@ -39,6 +39,32 @@ along with GCC; see the file COPYING3. If not see
#endif
#endif
+/* WORKAROUND pr80556:
+ For x86_64 Darwin10 and later, the unwinder is in libunwind (redirected
+ from libSystem). This doesn't use the keymgr (see keymgr.c) and therefore
+ the calls that libgcc makes to obtain the KEYMGR_GCC3_DW2_OBJ_LIST are not
+ updated to include new images, and might not even be valid for a single
+ image.
+ Therefore, for 64b exes at least, we must use the libunwind implementation,
+ even when static-libgcc is specified. We put libSystem first so that
+ unwinder symbols are satisfied from there. */
+#undef REAL_LIBGCC_SPEC
+#define REAL_LIBGCC_SPEC \
+ "%{static-libgcc|static: \
+ %{m64:%:version-compare(>= 10.6 mmacosx-version-min= -lSystem)} \
+ -lgcc_eh -lgcc; \
+ shared-libgcc|fexceptions|fgnu-runtime: \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_s.10.4) \
+ %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_ext.10.4) \
+ %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \
+ -lgcc ; \
+ :%:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \
+ %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_ext.10.4) \
+ %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \
+ -lgcc }"
+
/* Size of the Obj-C jump buffer. */
#define OBJC_JBLEN ((TARGET_64BIT) ? ((9 * 2) + 3 + 16) : (18))
diff --git a/gcc/config/i386/darwin64.h b/gcc/config/i386/darwin64.h
index f2982ed..32cb789 100644
--- a/gcc/config/i386/darwin64.h
+++ b/gcc/config/i386/darwin64.h
@@ -21,6 +21,32 @@ along with GCC; see the file COPYING3. If not see
#undef DARWIN_ARCH_SPEC
#define DARWIN_ARCH_SPEC "%{m32:i386;:x86_64}"
+/* WORKAROUND pr80556:
+ For x86_64 Darwin10 and later, the unwinder is in libunwind (redirected
+ from libSystem). This doesn't use the keymgr (see keymgr.c) and therefore
+ the calls that libgcc makes to obtain the KEYMGR_GCC3_DW2_OBJ_LIST are not
+ updated to include new images, and might not even be valid for a single
+ image.
+ Therefore, for 64b exes at least, we must use the libunwind implementation,
+ even when static-libgcc is specified. We put libSystem first so that
+ unwinder symbols are satisfied from there. */
+#undef REAL_LIBGCC_SPEC
+#define REAL_LIBGCC_SPEC \
+ "%{static-libgcc|static: \
+ %{!m32:%:version-compare(>= 10.6 mmacosx-version-min= -lSystem)} \
+ -lgcc_eh -lgcc; \
+ shared-libgcc|fexceptions|fgnu-runtime: \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_s.10.4) \
+ %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_ext.10.4) \
+ %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \
+ -lgcc ; \
+ :%:version-compare(>< 10.3.9 10.5 mmacosx-version-min= -lgcc_s.10.4) \
+ %:version-compare(>< 10.5 10.6 mmacosx-version-min= -lgcc_s.10.5) \
+ %:version-compare(!> 10.5 mmacosx-version-min= -lgcc_ext.10.4) \
+ %:version-compare(>= 10.5 mmacosx-version-min= -lgcc_ext.10.5) \
+ -lgcc }"
+
#undef DARWIN_SUBARCH_SPEC
#define DARWIN_SUBARCH_SPEC DARWIN_ARCH_SPEC
diff --git a/gcc/config/i386/driver-i386.c b/gcc/config/i386/driver-i386.c
index 570c490..8028399 100644
--- a/gcc/config/i386/driver-i386.c
+++ b/gcc/config/i386/driver-i386.c
@@ -415,6 +415,8 @@ const char *host_detect_local_cpu (int argc, const char **argv)
unsigned int has_avx512vbmi = 0, has_avx512ifma = 0, has_clwb = 0;
unsigned int has_mwaitx = 0, has_clzero = 0, has_pku = 0, has_rdpid = 0;
unsigned int has_avx5124fmaps = 0, has_avx5124vnniw = 0;
+ unsigned int has_gfni = 0;
+ unsigned int has_ibt = 0, has_shstk = 0;
bool arch;
@@ -504,9 +506,13 @@ const char *host_detect_local_cpu (int argc, const char **argv)
has_avx512vbmi = ecx & bit_AVX512VBMI;
has_pku = ecx & bit_OSPKE;
has_rdpid = ecx & bit_RDPID;
+ has_gfni = ecx & bit_GFNI;
has_avx5124vnniw = edx & bit_AVX5124VNNIW;
has_avx5124fmaps = edx & bit_AVX5124FMAPS;
+
+ has_shstk = ecx & bit_SHSTK;
+ has_ibt = edx & bit_IBT;
}
if (max_level >= 13)
@@ -790,6 +796,10 @@ const char *host_detect_local_cpu (int argc, const char **argv)
/* Knights Landing. */
cpu = "knl";
break;
+ case 0x85:
+ /* Knights Mill. */
+ cpu = "knm";
+ break;
default:
if (arch)
{
@@ -797,6 +807,9 @@ const char *host_detect_local_cpu (int argc, const char **argv)
/* Assume Knights Landing. */
if (has_avx512f)
cpu = "knl";
+ /* Assume Knights Mill */
+ else if (has_avx5124vnniw)
+ cpu = "knm";
/* Assume Skylake. */
else if (has_clflushopt)
cpu = "skylake";
@@ -1041,6 +1054,9 @@ const char *host_detect_local_cpu (int argc, const char **argv)
const char *clzero = has_clzero ? " -mclzero" : " -mno-clzero";
const char *pku = has_pku ? " -mpku" : " -mno-pku";
const char *rdpid = has_rdpid ? " -mrdpid" : " -mno-rdpid";
+ const char *gfni = has_gfni ? " -mgfni" : " -mno-gfni";
+ const char *ibt = has_ibt ? " -mibt" : " -mno-ibt";
+ const char *shstk = has_shstk ? " -mshstk" : " -mno-shstk";
options = concat (options, mmx, mmx3dnow, sse, sse2, sse3, ssse3,
sse4a, cx16, sahf, movbe, aes, sha, pclmul,
popcnt, abm, lwp, fma, fma4, xop, bmi, sgx, bmi2,
@@ -1050,7 +1066,7 @@ const char *host_detect_local_cpu (int argc, const char **argv)
avx512cd, avx512pf, prefetchwt1, clflushopt,
xsavec, xsaves, avx512dq, avx512bw, avx512vl,
avx512ifma, avx512vbmi, avx5124fmaps, avx5124vnniw,
- clwb, mwaitx, clzero, pku, rdpid, NULL);
+ clwb, mwaitx, clzero, pku, rdpid, gfni, ibt, shstk, NULL);
}
done:
diff --git a/gcc/config/i386/i386-builtin-types.def b/gcc/config/i386/i386-builtin-types.def
index 8d584db..1c0c6b4 100644
--- a/gcc/config/i386/i386-builtin-types.def
+++ b/gcc/config/i386/i386-builtin-types.def
@@ -286,7 +286,9 @@ DEF_FUNCTION_TYPE (V8SI, V8SI)
DEF_FUNCTION_TYPE (VOID, PCVOID)
DEF_FUNCTION_TYPE (VOID, PVOID)
DEF_FUNCTION_TYPE (VOID, UINT64)
+DEF_FUNCTION_TYPE (VOID, UINT64, PVOID)
DEF_FUNCTION_TYPE (VOID, UNSIGNED)
+DEF_FUNCTION_TYPE (VOID, UNSIGNED, PVOID)
DEF_FUNCTION_TYPE (INT, PUSHORT)
DEF_FUNCTION_TYPE (INT, PUNSIGNED)
DEF_FUNCTION_TYPE (INT, PULONGLONG)
diff --git a/gcc/config/i386/i386-builtin.def b/gcc/config/i386/i386-builtin.def
index 7ff1bb1..5a58b94 100644
--- a/gcc/config/i386/i386-builtin.def
+++ b/gcc/config/i386/i386-builtin.def
@@ -137,7 +137,7 @@ BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_storelps, "__builtin_ia32_storelps", IX
/* SSE or 3DNow!A */
BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_sse_sfence, "__builtin_ia32_sfence", IX86_BUILTIN_SFENCE, UNKNOWN, (int) VOID_FTYPE_VOID)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_sse_movntq, "__builtin_ia32_movntq", IX86_BUILTIN_MOVNTQ, UNKNOWN, (int) VOID_FTYPE_PULONGLONG_ULONGLONG)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_sse_movntq, "__builtin_ia32_movntq", IX86_BUILTIN_MOVNTQ, UNKNOWN, (int) VOID_FTYPE_PULONGLONG_ULONGLONG)
/* SSE2 */
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_lfence, "__builtin_ia32_lfence", IX86_BUILTIN_LFENCE, UNKNOWN, (int) VOID_FTYPE_VOID)
@@ -505,10 +505,10 @@ BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sqrtv4sf2, "__builtin_ia32_sqrtps_nr", IX86
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_rsqrtv4sf2, "__builtin_ia32_rsqrtps", IX86_BUILTIN_RSQRTPS, UNKNOWN, (int) V4SF_FTYPE_V4SF)
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_rsqrtv4sf2, "__builtin_ia32_rsqrtps_nr", IX86_BUILTIN_RSQRTPS_NR, UNKNOWN, (int) V4SF_FTYPE_V4SF)
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_rcpv4sf2, "__builtin_ia32_rcpps", IX86_BUILTIN_RCPPS, UNKNOWN, (int) V4SF_FTYPE_V4SF)
-BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_cvtps2pi, "__builtin_ia32_cvtps2pi", IX86_BUILTIN_CVTPS2PI, UNKNOWN, (int) V2SI_FTYPE_V4SF)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_MMX, CODE_FOR_sse_cvtps2pi, "__builtin_ia32_cvtps2pi", IX86_BUILTIN_CVTPS2PI, UNKNOWN, (int) V2SI_FTYPE_V4SF)
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_cvtss2si, "__builtin_ia32_cvtss2si", IX86_BUILTIN_CVTSS2SI, UNKNOWN, (int) INT_FTYPE_V4SF)
BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_64BIT, CODE_FOR_sse_cvtss2siq, "__builtin_ia32_cvtss2si64", IX86_BUILTIN_CVTSS2SI64, UNKNOWN, (int) INT64_FTYPE_V4SF)
-BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_cvttps2pi, "__builtin_ia32_cvttps2pi", IX86_BUILTIN_CVTTPS2PI, UNKNOWN, (int) V2SI_FTYPE_V4SF)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_MMX, CODE_FOR_sse_cvttps2pi, "__builtin_ia32_cvttps2pi", IX86_BUILTIN_CVTTPS2PI, UNKNOWN, (int) V2SI_FTYPE_V4SF)
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_cvttss2si, "__builtin_ia32_cvttss2si", IX86_BUILTIN_CVTTSS2SI, UNKNOWN, (int) INT_FTYPE_V4SF)
BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_64BIT, CODE_FOR_sse_cvttss2siq, "__builtin_ia32_cvttss2si64", IX86_BUILTIN_CVTTSS2SI64, UNKNOWN, (int) INT64_FTYPE_V4SF)
@@ -562,7 +562,7 @@ BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_movlhps_exp, "__builtin_ia32_movlhps",
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_vec_interleave_highv4sf, "__builtin_ia32_unpckhps", IX86_BUILTIN_UNPCKHPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF)
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_vec_interleave_lowv4sf, "__builtin_ia32_unpcklps", IX86_BUILTIN_UNPCKLPS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF)
-BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_cvtpi2ps, "__builtin_ia32_cvtpi2ps", IX86_BUILTIN_CVTPI2PS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V2SI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_MMX, CODE_FOR_sse_cvtpi2ps, "__builtin_ia32_cvtpi2ps", IX86_BUILTIN_CVTPI2PS, UNKNOWN, (int) V4SF_FTYPE_V4SF_V2SI)
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse_cvtsi2ss, "__builtin_ia32_cvtsi2ss", IX86_BUILTIN_CVTSI2SS, UNKNOWN, (int) V4SF_FTYPE_V4SF_SI)
BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_64BIT, CODE_FOR_sse_cvtsi2ssq, "__builtin_ia32_cvtsi642ss", IX86_BUILTIN_CVTSI642SS, UNKNOWN, V4SF_FTYPE_V4SF_DI)
@@ -576,19 +576,19 @@ BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_abstf2, 0, IX86_BUILTIN_FABSQ, UNKNOWN, (in
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_copysigntf3, 0, IX86_BUILTIN_COPYSIGNQ, UNKNOWN, (int) FLOAT128_FTYPE_FLOAT128_FLOAT128)
/* SSE MMX or 3Dnow!A */
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_uavgv8qi3, "__builtin_ia32_pavgb", IX86_BUILTIN_PAVGB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_uavgv4hi3, "__builtin_ia32_pavgw", IX86_BUILTIN_PAVGW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_umulv4hi3_highpart, "__builtin_ia32_pmulhuw", IX86_BUILTIN_PMULHUW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_uavgv8qi3, "__builtin_ia32_pavgb", IX86_BUILTIN_PAVGB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_uavgv4hi3, "__builtin_ia32_pavgw", IX86_BUILTIN_PAVGW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_umulv4hi3_highpart, "__builtin_ia32_pmulhuw", IX86_BUILTIN_PMULHUW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_umaxv8qi3, "__builtin_ia32_pmaxub", IX86_BUILTIN_PMAXUB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_smaxv4hi3, "__builtin_ia32_pmaxsw", IX86_BUILTIN_PMAXSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_uminv8qi3, "__builtin_ia32_pminub", IX86_BUILTIN_PMINUB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_sminv4hi3, "__builtin_ia32_pminsw", IX86_BUILTIN_PMINSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_umaxv8qi3, "__builtin_ia32_pmaxub", IX86_BUILTIN_PMAXUB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_smaxv4hi3, "__builtin_ia32_pmaxsw", IX86_BUILTIN_PMAXSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_uminv8qi3, "__builtin_ia32_pminub", IX86_BUILTIN_PMINUB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_sminv4hi3, "__builtin_ia32_pminsw", IX86_BUILTIN_PMINSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_psadbw, "__builtin_ia32_psadbw", IX86_BUILTIN_PSADBW, UNKNOWN, (int) V1DI_FTYPE_V8QI_V8QI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_pmovmskb, "__builtin_ia32_pmovmskb", IX86_BUILTIN_PMOVMSKB, UNKNOWN, (int) INT_FTYPE_V8QI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_psadbw, "__builtin_ia32_psadbw", IX86_BUILTIN_PSADBW, UNKNOWN, (int) V1DI_FTYPE_V8QI_V8QI)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_pmovmskb, "__builtin_ia32_pmovmskb", IX86_BUILTIN_PMOVMSKB, UNKNOWN, (int) INT_FTYPE_V8QI)
-BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A, CODE_FOR_mmx_pshufw, "__builtin_ia32_pshufw", IX86_BUILTIN_PSHUFW, UNKNOWN, (int) V4HI_FTYPE_V4HI_INT)
+BDESC (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_pshufw, "__builtin_ia32_pshufw", IX86_BUILTIN_PSHUFW, UNKNOWN, (int) V4HI_FTYPE_V4HI_INT)
/* SSE2 */
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_shufpd, "__builtin_ia32_shufpd", IX86_BUILTIN_SHUFPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF_INT)
@@ -600,12 +600,12 @@ BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtdq2pd, "__builtin_ia32_cvtdq2pd",
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_floatv4siv4sf2, "__builtin_ia32_cvtdq2ps", IX86_BUILTIN_CVTDQ2PS, UNKNOWN, (int) V4SF_FTYPE_V4SI)
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtpd2dq, "__builtin_ia32_cvtpd2dq", IX86_BUILTIN_CVTPD2DQ, UNKNOWN, (int) V4SI_FTYPE_V2DF)
-BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtpd2pi, "__builtin_ia32_cvtpd2pi", IX86_BUILTIN_CVTPD2PI, UNKNOWN, (int) V2SI_FTYPE_V2DF)
+BDESC (OPTION_MASK_ISA_SSE2 | OPTION_MASK_ISA_MMX, CODE_FOR_sse2_cvtpd2pi, "__builtin_ia32_cvtpd2pi", IX86_BUILTIN_CVTPD2PI, UNKNOWN, (int) V2SI_FTYPE_V2DF)
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtpd2ps, "__builtin_ia32_cvtpd2ps", IX86_BUILTIN_CVTPD2PS, UNKNOWN, (int) V4SF_FTYPE_V2DF)
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvttpd2dq, "__builtin_ia32_cvttpd2dq", IX86_BUILTIN_CVTTPD2DQ, UNKNOWN, (int) V4SI_FTYPE_V2DF)
-BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvttpd2pi, "__builtin_ia32_cvttpd2pi", IX86_BUILTIN_CVTTPD2PI, UNKNOWN, (int) V2SI_FTYPE_V2DF)
+BDESC (OPTION_MASK_ISA_SSE2 | OPTION_MASK_ISA_MMX, CODE_FOR_sse2_cvttpd2pi, "__builtin_ia32_cvttpd2pi", IX86_BUILTIN_CVTTPD2PI, UNKNOWN, (int) V2SI_FTYPE_V2DF)
-BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtpi2pd, "__builtin_ia32_cvtpi2pd", IX86_BUILTIN_CVTPI2PD, UNKNOWN, (int) V2DF_FTYPE_V2SI)
+BDESC (OPTION_MASK_ISA_SSE2 | OPTION_MASK_ISA_MMX, CODE_FOR_sse2_cvtpi2pd, "__builtin_ia32_cvtpi2pd", IX86_BUILTIN_CVTPI2PD, UNKNOWN, (int) V2DF_FTYPE_V2SI)
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvtsd2si, "__builtin_ia32_cvtsd2si", IX86_BUILTIN_CVTSD2SI, UNKNOWN, (int) INT_FTYPE_V2DF)
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_cvttsd2si, "__builtin_ia32_cvttsd2si", IX86_BUILTIN_CVTTSD2SI, UNKNOWN, (int) INT_FTYPE_V2DF)
@@ -721,7 +721,7 @@ BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_packuswb, "__builtin_ia32_packuswb128
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_umulv8hi3_highpart, "__builtin_ia32_pmulhuw128", IX86_BUILTIN_PMULHUW128, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI)
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_psadbw, "__builtin_ia32_psadbw128", IX86_BUILTIN_PSADBW128, UNKNOWN, (int) V2DI_FTYPE_V16QI_V16QI)
-BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_umulv1siv1di3, "__builtin_ia32_pmuludq", IX86_BUILTIN_PMULUDQ, UNKNOWN, (int) V1DI_FTYPE_V2SI_V2SI)
+BDESC (OPTION_MASK_ISA_SSE2 | OPTION_MASK_ISA_MMX, CODE_FOR_sse2_umulv1siv1di3, "__builtin_ia32_pmuludq", IX86_BUILTIN_PMULUDQ, UNKNOWN, (int) V1DI_FTYPE_V2SI_V2SI)
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_vec_widen_umult_even_v4si, "__builtin_ia32_pmuludq128", IX86_BUILTIN_PMULUDQ128, UNKNOWN, (int) V2DI_FTYPE_V4SI_V4SI)
BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_pmaddwd, "__builtin_ia32_pmaddwd128", IX86_BUILTIN_PMADDWD128, UNKNOWN, (int) V4SI_FTYPE_V8HI_V8HI)
@@ -761,8 +761,8 @@ BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_sse2_vmsqrtv2df2, "__builtin_ia32_sqrtsd",
BDESC (OPTION_MASK_ISA_SSE, CODE_FOR_sse2_movq128, "__builtin_ia32_movq128", IX86_BUILTIN_MOVQ128, UNKNOWN, (int) V2DI_FTYPE_V2DI)
/* SSE2 MMX */
-BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_mmx_addv1di3, "__builtin_ia32_paddq", IX86_BUILTIN_PADDQ, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI)
-BDESC (OPTION_MASK_ISA_SSE2, CODE_FOR_mmx_subv1di3, "__builtin_ia32_psubq", IX86_BUILTIN_PSUBQ, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI)
+BDESC (OPTION_MASK_ISA_SSE2 | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_addv1di3, "__builtin_ia32_paddq", IX86_BUILTIN_PADDQ, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI)
+BDESC (OPTION_MASK_ISA_SSE2 | OPTION_MASK_ISA_MMX, CODE_FOR_mmx_subv1di3, "__builtin_ia32_psubq", IX86_BUILTIN_PSUBQ, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI)
/* SSE3 */
BDESC (OPTION_MASK_ISA_SSE3, CODE_FOR_sse3_movshdup, "__builtin_ia32_movshdup", IX86_BUILTIN_MOVSHDUP, UNKNOWN, (int) V4SF_FTYPE_V4SF)
@@ -777,40 +777,40 @@ BDESC (OPTION_MASK_ISA_SSE3, CODE_FOR_sse3_hsubv2df3, "__builtin_ia32_hsubpd", I
/* SSSE3 */
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv16qi2, "__builtin_ia32_pabsb128", IX86_BUILTIN_PABSB128, UNKNOWN, (int) V16QI_FTYPE_V16QI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv8qi2, "__builtin_ia32_pabsb", IX86_BUILTIN_PABSB, UNKNOWN, (int) V8QI_FTYPE_V8QI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_absv8qi2, "__builtin_ia32_pabsb", IX86_BUILTIN_PABSB, UNKNOWN, (int) V8QI_FTYPE_V8QI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv8hi2, "__builtin_ia32_pabsw128", IX86_BUILTIN_PABSW128, UNKNOWN, (int) V8HI_FTYPE_V8HI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv4hi2, "__builtin_ia32_pabsw", IX86_BUILTIN_PABSW, UNKNOWN, (int) V4HI_FTYPE_V4HI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_absv4hi2, "__builtin_ia32_pabsw", IX86_BUILTIN_PABSW, UNKNOWN, (int) V4HI_FTYPE_V4HI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv4si2, "__builtin_ia32_pabsd128", IX86_BUILTIN_PABSD128, UNKNOWN, (int) V4SI_FTYPE_V4SI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_absv2si2, "__builtin_ia32_pabsd", IX86_BUILTIN_PABSD, UNKNOWN, (int) V2SI_FTYPE_V2SI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_absv2si2, "__builtin_ia32_pabsd", IX86_BUILTIN_PABSD, UNKNOWN, (int) V2SI_FTYPE_V2SI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phaddwv8hi3, "__builtin_ia32_phaddw128", IX86_BUILTIN_PHADDW128, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phaddwv4hi3, "__builtin_ia32_phaddw", IX86_BUILTIN_PHADDW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_phaddwv4hi3, "__builtin_ia32_phaddw", IX86_BUILTIN_PHADDW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phadddv4si3, "__builtin_ia32_phaddd128", IX86_BUILTIN_PHADDD128, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phadddv2si3, "__builtin_ia32_phaddd", IX86_BUILTIN_PHADDD, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_phadddv2si3, "__builtin_ia32_phaddd", IX86_BUILTIN_PHADDD, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phaddswv8hi3, "__builtin_ia32_phaddsw128", IX86_BUILTIN_PHADDSW128, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phaddswv4hi3, "__builtin_ia32_phaddsw", IX86_BUILTIN_PHADDSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_phaddswv4hi3, "__builtin_ia32_phaddsw", IX86_BUILTIN_PHADDSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phsubwv8hi3, "__builtin_ia32_phsubw128", IX86_BUILTIN_PHSUBW128, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phsubwv4hi3, "__builtin_ia32_phsubw", IX86_BUILTIN_PHSUBW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_phsubwv4hi3, "__builtin_ia32_phsubw", IX86_BUILTIN_PHSUBW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phsubdv4si3, "__builtin_ia32_phsubd128", IX86_BUILTIN_PHSUBD128, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phsubdv2si3, "__builtin_ia32_phsubd", IX86_BUILTIN_PHSUBD, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_phsubdv2si3, "__builtin_ia32_phsubd", IX86_BUILTIN_PHSUBD, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phsubswv8hi3, "__builtin_ia32_phsubsw128", IX86_BUILTIN_PHSUBSW128, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_phsubswv4hi3, "__builtin_ia32_phsubsw", IX86_BUILTIN_PHSUBSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_phsubswv4hi3, "__builtin_ia32_phsubsw", IX86_BUILTIN_PHSUBSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_pmaddubsw128, "__builtin_ia32_pmaddubsw128", IX86_BUILTIN_PMADDUBSW128, UNKNOWN, (int) V8HI_FTYPE_V16QI_V16QI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_pmaddubsw, "__builtin_ia32_pmaddubsw", IX86_BUILTIN_PMADDUBSW, UNKNOWN, (int) V4HI_FTYPE_V8QI_V8QI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_pmaddubsw, "__builtin_ia32_pmaddubsw", IX86_BUILTIN_PMADDUBSW, UNKNOWN, (int) V4HI_FTYPE_V8QI_V8QI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_pmulhrswv8hi3, "__builtin_ia32_pmulhrsw128", IX86_BUILTIN_PMULHRSW128, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_pmulhrswv4hi3, "__builtin_ia32_pmulhrsw", IX86_BUILTIN_PMULHRSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_pmulhrswv4hi3, "__builtin_ia32_pmulhrsw", IX86_BUILTIN_PMULHRSW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_pshufbv16qi3, "__builtin_ia32_pshufb128", IX86_BUILTIN_PSHUFB128, UNKNOWN, (int) V16QI_FTYPE_V16QI_V16QI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_pshufbv8qi3, "__builtin_ia32_pshufb", IX86_BUILTIN_PSHUFB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_pshufbv8qi3, "__builtin_ia32_pshufb", IX86_BUILTIN_PSHUFB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_psignv16qi3, "__builtin_ia32_psignb128", IX86_BUILTIN_PSIGNB128, UNKNOWN, (int) V16QI_FTYPE_V16QI_V16QI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_psignv8qi3, "__builtin_ia32_psignb", IX86_BUILTIN_PSIGNB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_psignv8qi3, "__builtin_ia32_psignb", IX86_BUILTIN_PSIGNB, UNKNOWN, (int) V8QI_FTYPE_V8QI_V8QI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_psignv8hi3, "__builtin_ia32_psignw128", IX86_BUILTIN_PSIGNW128, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_psignv4hi3, "__builtin_ia32_psignw", IX86_BUILTIN_PSIGNW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_psignv4hi3, "__builtin_ia32_psignw", IX86_BUILTIN_PSIGNW, UNKNOWN, (int) V4HI_FTYPE_V4HI_V4HI)
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_psignv4si3, "__builtin_ia32_psignd128", IX86_BUILTIN_PSIGND128, UNKNOWN, (int) V4SI_FTYPE_V4SI_V4SI)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_psignv2si3, "__builtin_ia32_psignd", IX86_BUILTIN_PSIGND, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_psignv2si3, "__builtin_ia32_psignd", IX86_BUILTIN_PSIGND, UNKNOWN, (int) V2SI_FTYPE_V2SI_V2SI)
/* SSSE3. */
BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_palignrti, "__builtin_ia32_palignr128", IX86_BUILTIN_PALIGNR128, UNKNOWN, (int) V2DI_FTYPE_V2DI_V2DI_INT_CONVERT)
-BDESC (OPTION_MASK_ISA_SSSE3, CODE_FOR_ssse3_palignrdi, "__builtin_ia32_palignr", IX86_BUILTIN_PALIGNR, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI_INT_CONVERT)
+BDESC (OPTION_MASK_ISA_SSSE3 | OPTION_MASK_ISA_MMX, CODE_FOR_ssse3_palignrdi, "__builtin_ia32_palignr", IX86_BUILTIN_PALIGNR, UNKNOWN, (int) V1DI_FTYPE_V1DI_V1DI_INT_CONVERT)
/* SSE4.1 */
BDESC (OPTION_MASK_ISA_SSE4_1, CODE_FOR_sse4_1_blendpd, "__builtin_ia32_blendpd", IX86_BUILTIN_BLENDPD, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF_INT)
@@ -1666,8 +1666,8 @@ BDESC (OPTION_MASK_ISA_AVX512DQ | OPTION_MASK_ISA_AVX512VL, CODE_FOR_reducepv4df
BDESC (OPTION_MASK_ISA_AVX512DQ | OPTION_MASK_ISA_AVX512VL, CODE_FOR_reducepv2df_mask, "__builtin_ia32_reducepd128_mask", IX86_BUILTIN_REDUCEPD128_MASK, UNKNOWN, (int) V2DF_FTYPE_V2DF_INT_V2DF_UQI)
BDESC (OPTION_MASK_ISA_AVX512DQ | OPTION_MASK_ISA_AVX512VL, CODE_FOR_reducepv8sf_mask, "__builtin_ia32_reduceps256_mask", IX86_BUILTIN_REDUCEPS256_MASK, UNKNOWN, (int) V8SF_FTYPE_V8SF_INT_V8SF_UQI)
BDESC (OPTION_MASK_ISA_AVX512DQ | OPTION_MASK_ISA_AVX512VL, CODE_FOR_reducepv4sf_mask, "__builtin_ia32_reduceps128_mask", IX86_BUILTIN_REDUCEPS128_MASK, UNKNOWN, (int) V4SF_FTYPE_V4SF_INT_V4SF_UQI)
-BDESC (OPTION_MASK_ISA_AVX512DQ, CODE_FOR_reducesv2df, "__builtin_ia32_reducesd", IX86_BUILTIN_REDUCESD_MASK, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF_INT)
-BDESC (OPTION_MASK_ISA_AVX512DQ, CODE_FOR_reducesv4sf, "__builtin_ia32_reducess", IX86_BUILTIN_REDUCESS_MASK, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF_INT)
+BDESC (OPTION_MASK_ISA_AVX512DQ, CODE_FOR_reducesv2df_mask, "__builtin_ia32_reducesd_mask", IX86_BUILTIN_REDUCESD128_MASK, UNKNOWN, (int) V2DF_FTYPE_V2DF_V2DF_INT_V2DF_UQI)
+BDESC (OPTION_MASK_ISA_AVX512DQ, CODE_FOR_reducesv4sf_mask, "__builtin_ia32_reducess_mask", IX86_BUILTIN_REDUCESS128_MASK, UNKNOWN, (int) V4SF_FTYPE_V4SF_V4SF_INT_V4SF_UQI)
BDESC (OPTION_MASK_ISA_AVX512BW | OPTION_MASK_ISA_AVX512VL, CODE_FOR_avx512vl_permvarv16hi_mask, "__builtin_ia32_permvarhi256_mask", IX86_BUILTIN_VPERMVARHI256_MASK, UNKNOWN, (int) V16HI_FTYPE_V16HI_V16HI_V16HI_UHI)
BDESC (OPTION_MASK_ISA_AVX512BW | OPTION_MASK_ISA_AVX512VL, CODE_FOR_avx512vl_permvarv8hi_mask, "__builtin_ia32_permvarhi128_mask", IX86_BUILTIN_VPERMVARHI128_MASK, UNKNOWN, (int) V8HI_FTYPE_V8HI_V8HI_V8HI_UQI)
BDESC (OPTION_MASK_ISA_AVX512BW | OPTION_MASK_ISA_AVX512VL, CODE_FOR_avx512vl_vpermt2varv16hi3_mask, "__builtin_ia32_vpermt2varhi256_mask", IX86_BUILTIN_VPERMT2VARHI256, UNKNOWN, (int) V16HI_FTYPE_V16HI_V16HI_V16HI_UHI)
@@ -2779,4 +2779,25 @@ BDESC (OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v4sf3, "__builtin_ia32_vper
BDESC (OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v4df3, "__builtin_ia32_vpermil2pd256", IX86_BUILTIN_VPERMIL2PD256, UNKNOWN, (int)MULTI_ARG_4_DF2_DI_I1)
BDESC (OPTION_MASK_ISA_XOP, CODE_FOR_xop_vpermil2v8sf3, "__builtin_ia32_vpermil2ps256", IX86_BUILTIN_VPERMIL2PS256, UNKNOWN, (int)MULTI_ARG_4_SF2_SI_I1)
-BDESC_END (MULTI_ARG, MAX)
+BDESC_END (MULTI_ARG, CET)
+
+/* CET. */
+BDESC_FIRST (cet, CET,
+ OPTION_MASK_ISA_SHSTK, CODE_FOR_incsspsi, "__builtin_ia32_incsspd", IX86_BUILTIN_INCSSPD, UNKNOWN, (int) VOID_FTYPE_UNSIGNED)
+BDESC (OPTION_MASK_ISA_SHSTK | OPTION_MASK_ISA_64BIT, CODE_FOR_incsspdi, "__builtin_ia32_incsspq", IX86_BUILTIN_INCSSPQ, UNKNOWN, (int) VOID_FTYPE_UINT64)
+BDESC (OPTION_MASK_ISA_SHSTK, CODE_FOR_saveprevssp, "__builtin_ia32_saveprevssp", IX86_BUILTIN_SAVEPREVSSP, UNKNOWN, (int) VOID_FTYPE_VOID)
+BDESC (OPTION_MASK_ISA_SHSTK, CODE_FOR_rstorssp, "__builtin_ia32_rstorssp", IX86_BUILTIN_RSTORSSP, UNKNOWN, (int) VOID_FTYPE_PVOID)
+BDESC (OPTION_MASK_ISA_SHSTK, CODE_FOR_wrsssi, "__builtin_ia32_wrssd", IX86_BUILTIN_WRSSD, UNKNOWN, (int) VOID_FTYPE_UNSIGNED_PVOID)
+BDESC (OPTION_MASK_ISA_SHSTK | OPTION_MASK_ISA_64BIT, CODE_FOR_wrssdi, "__builtin_ia32_wrssq", IX86_BUILTIN_WRSSQ, UNKNOWN, (int) VOID_FTYPE_UINT64_PVOID)
+BDESC (OPTION_MASK_ISA_SHSTK, CODE_FOR_wrusssi, "__builtin_ia32_wrussd", IX86_BUILTIN_WRUSSD, UNKNOWN, (int) VOID_FTYPE_UNSIGNED_PVOID)
+BDESC (OPTION_MASK_ISA_SHSTK | OPTION_MASK_ISA_64BIT, CODE_FOR_wrussdi, "__builtin_ia32_wrussq", IX86_BUILTIN_WRUSSQ, UNKNOWN, (int) VOID_FTYPE_UINT64_PVOID)
+BDESC (OPTION_MASK_ISA_SHSTK, CODE_FOR_setssbsy, "__builtin_ia32_setssbsy", IX86_BUILTIN_SETSSBSY, UNKNOWN, (int) VOID_FTYPE_VOID)
+BDESC (OPTION_MASK_ISA_SHSTK, CODE_FOR_clrssbsy, "__builtin_ia32_clrssbsy", IX86_BUILTIN_CLRSSBSY, UNKNOWN, (int) VOID_FTYPE_PVOID)
+
+BDESC_END (CET, CET_NORMAL)
+
+BDESC_FIRST (cet_rdssp, CET_NORMAL,
+ OPTION_MASK_ISA_SHSTK, CODE_FOR_rdsspsi, "__builtin_ia32_rdsspd", IX86_BUILTIN_RDSSPD, UNKNOWN, (int) UINT_FTYPE_UINT)
+BDESC (OPTION_MASK_ISA_SHSTK | OPTION_MASK_ISA_64BIT, CODE_FOR_rdsspdi, "__builtin_ia32_rdsspq", IX86_BUILTIN_RDSSPQ, UNKNOWN, (int) UINT64_FTYPE_UINT64)
+
+BDESC_END (CET_NORMAL, MAX)
diff --git a/gcc/config/i386/i386-c.c b/gcc/config/i386/i386-c.c
index 9a79a21..7f88bef 100644
--- a/gcc/config/i386/i386-c.c
+++ b/gcc/config/i386/i386-c.c
@@ -176,6 +176,10 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
def_or_undef (parse_in, "__knl");
def_or_undef (parse_in, "__knl__");
break;
+ case PROCESSOR_KNM:
+ def_or_undef (parse_in, "__knm");
+ def_or_undef (parse_in, "__knm__");
+ break;
case PROCESSOR_SKYLAKE_AVX512:
def_or_undef (parse_in, "__skylake_avx512");
def_or_undef (parse_in, "__skylake_avx512__");
@@ -292,6 +296,9 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
case PROCESSOR_KNL:
def_or_undef (parse_in, "__tune_knl__");
break;
+ case PROCESSOR_KNM:
+ def_or_undef (parse_in, "__tune_knm__");
+ break;
case PROCESSOR_SKYLAKE_AVX512:
def_or_undef (parse_in, "__tune_skylake_avx512__");
break;
@@ -450,6 +457,20 @@ ix86_target_macros_internal (HOST_WIDE_INT isa_flag,
def_or_undef (parse_in, "__PKU__");
if (isa_flag2 & OPTION_MASK_ISA_RDPID)
def_or_undef (parse_in, "__RDPID__");
+ if (isa_flag2 & OPTION_MASK_ISA_GFNI)
+ def_or_undef (parse_in, "__GFNI__");
+ if (isa_flag2 & OPTION_MASK_ISA_IBT)
+ {
+ def_or_undef (parse_in, "__IBT__");
+ if (flag_cf_protection != CF_NONE)
+ def_or_undef (parse_in, "__CET__");
+ }
+ if (isa_flag2 & OPTION_MASK_ISA_SHSTK)
+ {
+ def_or_undef (parse_in, "__SHSTK__");
+ if (flag_cf_protection != CF_NONE)
+ def_or_undef (parse_in, "__CET__");
+ }
if (TARGET_IAMCU)
{
def_or_undef (parse_in, "__iamcu");
diff --git a/gcc/config/i386/i386-modes.def b/gcc/config/i386/i386-modes.def
index 83216e3..16bc1d8 100644
--- a/gcc/config/i386/i386-modes.def
+++ b/gcc/config/i386/i386-modes.def
@@ -39,19 +39,22 @@ ADJUST_ALIGNMENT (XF, TARGET_128BIT_LONG_DOUBLE ? 16 : 4);
For the i386, we need separate modes when floating-point
equality comparisons are being done.
- Add CCNO to indicate comparisons against zero that requires
+ Add CCNO to indicate comparisons against zero that require
Overflow flag to be unset. Sign bit test is used instead and
thus can be used to form "a&b>0" type of tests.
- Add CCGC to indicate comparisons against zero that allows
+ Add CCGC to indicate comparisons against zero that allow
unspecified garbage in the Carry flag. This mode is used
by inc/dec instructions.
- Add CCGOC to indicate comparisons against zero that allows
+ Add CCGOC to indicate comparisons against zero that allow
unspecified garbage in the Carry and Overflow flag. This
mode is used to simulate comparisons of (a-b) and (a+b)
against zero using sub/cmp/add operations.
+ Add CCGZ to indicate comparisons that allow unspecified garbage
+ in the Zero flag. This mode is used in double-word comparisons.
+
Add CCA to indicate that only the Above flag is valid.
Add CCC to indicate that only the Carry flag is valid.
Add CCO to indicate that only the Overflow flag is valid.
@@ -62,6 +65,7 @@ ADJUST_ALIGNMENT (XF, TARGET_128BIT_LONG_DOUBLE ? 16 : 4);
CC_MODE (CCGC);
CC_MODE (CCGOC);
CC_MODE (CCNO);
+CC_MODE (CCGZ);
CC_MODE (CCA);
CC_MODE (CCC);
CC_MODE (CCO);
diff --git a/gcc/config/i386/i386-passes.def b/gcc/config/i386/i386-passes.def
index 4953461..5c6e9c3 100644
--- a/gcc/config/i386/i386-passes.def
+++ b/gcc/config/i386/i386-passes.def
@@ -29,3 +29,5 @@ along with GCC; see the file COPYING3. If not see
/* Run the 64-bit STV pass before the CSE pass so that CONST0_RTX and
CONSTM1_RTX generated by the STV pass can be CSEed. */
INSERT_PASS_BEFORE (pass_cse2, 1, pass_stv, true /* timode_p */);
+
+ INSERT_PASS_BEFORE (pass_shorten_branches, 1, pass_insert_endbranch);
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index 4df6274..c94cccd 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -27,6 +27,7 @@ extern bool ix86_handle_option (struct gcc_options *opts,
extern bool ix86_target_stack_probe (void);
extern bool ix86_can_use_return_insn_p (void);
extern void ix86_setup_frame_addresses (void);
+extern bool ix86_rip_relative_addr_p (struct ix86_address *parts);
extern HOST_WIDE_INT ix86_initial_elimination_offset (int, int);
extern void ix86_expand_prologue (void);
@@ -165,9 +166,6 @@ extern void ix86_asm_output_function_label (FILE *, const char *, tree);
extern void ix86_call_abi_override (const_tree);
extern int ix86_reg_parm_stack_space (const_tree);
-extern void ix86_split_fp_branch (enum rtx_code code, rtx, rtx,
- rtx, rtx, rtx);
-
extern bool ix86_libc_has_function (enum function_class fn_class);
extern void x86_order_regs_for_local_alloc (void);
@@ -209,7 +207,6 @@ extern unsigned int ix86_local_alignment (tree, machine_mode,
unsigned int);
extern unsigned int ix86_minimum_alignment (tree, machine_mode,
unsigned int);
-extern int ix86_constant_alignment (tree, int);
extern tree ix86_handle_shared_attribute (tree *, tree, tree, int, bool *);
extern tree ix86_handle_selectany_attribute (tree *, tree, tree, int, bool *);
extern int x86_field_alignment (tree, int);
@@ -315,6 +312,21 @@ extern enum attr_cpu ix86_schedule;
extern const char * ix86_output_call_insn (rtx_insn *insn, rtx call_op);
extern bool ix86_operands_ok_for_move_multiple (rtx *operands, bool load,
machine_mode mode);
+extern int ix86_min_insn_size (rtx_insn *);
+
+extern int ix86_issue_rate (void);
+extern int ix86_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn,
+ int cost, unsigned int);
+extern int ia32_multipass_dfa_lookahead (void);
+extern bool ix86_macro_fusion_p (void);
+extern bool ix86_macro_fusion_pair_p (rtx_insn *condgen, rtx_insn *condjmp);
+
+extern bool ix86_bd_has_dispatch (rtx_insn *insn, int action);
+extern void ix86_bd_do_dispatch (rtx_insn *insn, int mode);
+
+extern void ix86_core2i7_init_hooks (void);
+
+extern int ix86_atom_sched_reorder (FILE *, int, rtx_insn **, int *, int);
#ifdef RTX_CODE
/* Target data for multipass lookahead scheduling.
@@ -342,3 +354,4 @@ class rtl_opt_pass;
extern rtl_opt_pass *make_pass_insert_vzeroupper (gcc::context *);
extern rtl_opt_pass *make_pass_stv (gcc::context *);
+extern rtl_opt_pass *make_pass_insert_endbranch (gcc::context *);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 1c765fb..367cade 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -92,12 +92,15 @@ along with GCC; see the file COPYING3. If not see
/* This file should be included last. */
#include "target-def.h"
+#include "x86-tune-costs.h"
+
static rtx legitimize_dllimport_symbol (rtx, bool);
static rtx legitimize_pe_coff_extern_decl (rtx, bool);
static rtx legitimize_pe_coff_symbol (rtx, bool);
static void ix86_print_operand_address_as (FILE *, rtx, addr_space_t, bool);
static bool ix86_save_reg (unsigned int, bool, bool);
static bool ix86_function_naked (const_tree);
+static bool ix86_notrack_prefixed_insn_p (rtx);
#ifndef CHECK_STACK_LIMIT
#define CHECK_STACK_LIMIT (-1)
@@ -111,2069 +114,12 @@ static bool ix86_function_naked (const_tree);
: (mode) == DImode ? 3 \
: 4)
-/* Processor costs (relative to an add) */
-/* We assume COSTS_N_INSNS is defined as (N)*4 and an addition is 2 bytes. */
-#define COSTS_N_BYTES(N) ((N) * 2)
-
-#define DUMMY_STRINGOP_ALGS {libcall, {{-1, libcall, false}}}
-
-static stringop_algs ix86_size_memcpy[2] = {
- {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}},
- {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}}};
-static stringop_algs ix86_size_memset[2] = {
- {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}},
- {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}}};
-
-const
-struct processor_costs ix86_size_cost = {/* costs for tuning for size */
- COSTS_N_BYTES (2), /* cost of an add instruction */
- COSTS_N_BYTES (3), /* cost of a lea instruction */
- COSTS_N_BYTES (2), /* variable shift costs */
- COSTS_N_BYTES (3), /* constant shift costs */
- {COSTS_N_BYTES (3), /* cost of starting multiply for QI */
- COSTS_N_BYTES (3), /* HI */
- COSTS_N_BYTES (3), /* SI */
- COSTS_N_BYTES (3), /* DI */
- COSTS_N_BYTES (5)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_BYTES (3), /* cost of a divide/mod for QI */
- COSTS_N_BYTES (3), /* HI */
- COSTS_N_BYTES (3), /* SI */
- COSTS_N_BYTES (3), /* DI */
- COSTS_N_BYTES (5)}, /* other */
- COSTS_N_BYTES (3), /* cost of movsx */
- COSTS_N_BYTES (3), /* cost of movzx */
- 0, /* "large" insn */
- 2, /* MOVE_RATIO */
- 2, /* cost for loading QImode using movzbl */
- {2, 2, 2}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {2, 2, 2}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {2, 2, 2}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {2, 2, 2}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 3, /* cost of moving MMX register */
- {3, 3}, /* cost of loading MMX registers
- in SImode and DImode */
- {3, 3}, /* cost of storing MMX registers
- in SImode and DImode */
- 3, /* cost of moving SSE register */
- {3, 3, 3}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {3, 3, 3}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- 0, /* size of l1 cache */
- 0, /* size of l2 cache */
- 0, /* size of prefetch block */
- 0, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_BYTES (2), /* cost of FADD and FSUB insns. */
- COSTS_N_BYTES (2), /* cost of FMUL instruction. */
- COSTS_N_BYTES (2), /* cost of FDIV instruction. */
- COSTS_N_BYTES (2), /* cost of FABS instruction. */
- COSTS_N_BYTES (2), /* cost of FCHS instruction. */
- COSTS_N_BYTES (2), /* cost of FSQRT instruction. */
- ix86_size_memcpy,
- ix86_size_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 1, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 1, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-/* Processor costs (relative to an add) */
-static stringop_algs i386_memcpy[2] = {
- {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}},
- DUMMY_STRINGOP_ALGS};
-static stringop_algs i386_memset[2] = {
- {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}},
- DUMMY_STRINGOP_ALGS};
-
-static const
-struct processor_costs i386_cost = { /* 386 specific costs */
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (3), /* variable shift costs */
- COSTS_N_INSNS (2), /* constant shift costs */
- {COSTS_N_INSNS (6), /* cost of starting multiply for QI */
- COSTS_N_INSNS (6), /* HI */
- COSTS_N_INSNS (6), /* SI */
- COSTS_N_INSNS (6), /* DI */
- COSTS_N_INSNS (6)}, /* other */
- COSTS_N_INSNS (1), /* cost of multiply per each bit set */
- {COSTS_N_INSNS (23), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (23), /* HI */
- COSTS_N_INSNS (23), /* SI */
- COSTS_N_INSNS (23), /* DI */
- COSTS_N_INSNS (23)}, /* other */
- COSTS_N_INSNS (3), /* cost of movsx */
- COSTS_N_INSNS (2), /* cost of movzx */
- 15, /* "large" insn */
- 3, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {2, 4, 2}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {2, 4, 2}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {8, 8, 8}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {8, 8, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {4, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 8, 16}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 8, 16}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- 0, /* size of l1 cache */
- 0, /* size of l2 cache */
- 0, /* size of prefetch block */
- 0, /* number of parallel prefetches */
- 1, /* Branch cost */
- COSTS_N_INSNS (23), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (27), /* cost of FMUL instruction. */
- COSTS_N_INSNS (88), /* cost of FDIV instruction. */
- COSTS_N_INSNS (22), /* cost of FABS instruction. */
- COSTS_N_INSNS (24), /* cost of FCHS instruction. */
- COSTS_N_INSNS (122), /* cost of FSQRT instruction. */
- i386_memcpy,
- i386_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs i486_memcpy[2] = {
- {rep_prefix_4_byte, {{-1, rep_prefix_4_byte, false}}},
- DUMMY_STRINGOP_ALGS};
-static stringop_algs i486_memset[2] = {
- {rep_prefix_4_byte, {{-1, rep_prefix_4_byte, false}}},
- DUMMY_STRINGOP_ALGS};
-
-static const
-struct processor_costs i486_cost = { /* 486 specific costs */
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (3), /* variable shift costs */
- COSTS_N_INSNS (2), /* constant shift costs */
- {COSTS_N_INSNS (12), /* cost of starting multiply for QI */
- COSTS_N_INSNS (12), /* HI */
- COSTS_N_INSNS (12), /* SI */
- COSTS_N_INSNS (12), /* DI */
- COSTS_N_INSNS (12)}, /* other */
- 1, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (40), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (40), /* HI */
- COSTS_N_INSNS (40), /* SI */
- COSTS_N_INSNS (40), /* DI */
- COSTS_N_INSNS (40)}, /* other */
- COSTS_N_INSNS (3), /* cost of movsx */
- COSTS_N_INSNS (2), /* cost of movzx */
- 15, /* "large" insn */
- 3, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {2, 4, 2}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {2, 4, 2}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {8, 8, 8}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {8, 8, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {4, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 8, 16}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 8, 16}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- 4, /* size of l1 cache. 486 has 8kB cache
- shared for code and data, so 4kB is
- not really precise. */
- 4, /* size of l2 cache */
- 0, /* size of prefetch block */
- 0, /* number of parallel prefetches */
- 1, /* Branch cost */
- COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (16), /* cost of FMUL instruction. */
- COSTS_N_INSNS (73), /* cost of FDIV instruction. */
- COSTS_N_INSNS (3), /* cost of FABS instruction. */
- COSTS_N_INSNS (3), /* cost of FCHS instruction. */
- COSTS_N_INSNS (83), /* cost of FSQRT instruction. */
- i486_memcpy,
- i486_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs pentium_memcpy[2] = {
- {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-static stringop_algs pentium_memset[2] = {
- {libcall, {{-1, rep_prefix_4_byte, false}}},
- DUMMY_STRINGOP_ALGS};
-
-static const
-struct processor_costs pentium_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (4), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (11), /* cost of starting multiply for QI */
- COSTS_N_INSNS (11), /* HI */
- COSTS_N_INSNS (11), /* SI */
- COSTS_N_INSNS (11), /* DI */
- COSTS_N_INSNS (11)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (25), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (25), /* HI */
- COSTS_N_INSNS (25), /* SI */
- COSTS_N_INSNS (25), /* DI */
- COSTS_N_INSNS (25)}, /* other */
- COSTS_N_INSNS (3), /* cost of movsx */
- COSTS_N_INSNS (2), /* cost of movzx */
- 8, /* "large" insn */
- 6, /* MOVE_RATIO */
- 6, /* cost for loading QImode using movzbl */
- {2, 4, 2}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {2, 4, 2}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {2, 2, 6}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 6}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 8, /* cost of moving MMX register */
- {8, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {8, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 8, 16}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 8, 16}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- 8, /* size of l1 cache. */
- 8, /* size of l2 cache */
- 0, /* size of prefetch block */
- 0, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (3), /* cost of FMUL instruction. */
- COSTS_N_INSNS (39), /* cost of FDIV instruction. */
- COSTS_N_INSNS (1), /* cost of FABS instruction. */
- COSTS_N_INSNS (1), /* cost of FCHS instruction. */
- COSTS_N_INSNS (70), /* cost of FSQRT instruction. */
- pentium_memcpy,
- pentium_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static const
-struct processor_costs lakemont_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (11), /* cost of starting multiply for QI */
- COSTS_N_INSNS (11), /* HI */
- COSTS_N_INSNS (11), /* SI */
- COSTS_N_INSNS (11), /* DI */
- COSTS_N_INSNS (11)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (25), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (25), /* HI */
- COSTS_N_INSNS (25), /* SI */
- COSTS_N_INSNS (25), /* DI */
- COSTS_N_INSNS (25)}, /* other */
- COSTS_N_INSNS (3), /* cost of movsx */
- COSTS_N_INSNS (2), /* cost of movzx */
- 8, /* "large" insn */
- 17, /* MOVE_RATIO */
- 6, /* cost for loading QImode using movzbl */
- {2, 4, 2}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {2, 4, 2}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {2, 2, 6}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 6}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 8, /* cost of moving MMX register */
- {8, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {8, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 8, 16}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 8, 16}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- 8, /* size of l1 cache. */
- 8, /* size of l2 cache */
- 0, /* size of prefetch block */
- 0, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (3), /* cost of FMUL instruction. */
- COSTS_N_INSNS (39), /* cost of FDIV instruction. */
- COSTS_N_INSNS (1), /* cost of FABS instruction. */
- COSTS_N_INSNS (1), /* cost of FCHS instruction. */
- COSTS_N_INSNS (70), /* cost of FSQRT instruction. */
- pentium_memcpy,
- pentium_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-/* PentiumPro has optimized rep instructions for blocks aligned by 8 bytes
- (we ensure the alignment). For small blocks inline loop is still a
- noticeable win, for bigger blocks either rep movsl or rep movsb is
- way to go. Rep movsb has apparently more expensive startup time in CPU,
- but after 4K the difference is down in the noise. */
-static stringop_algs pentiumpro_memcpy[2] = {
- {rep_prefix_4_byte, {{128, loop, false}, {1024, unrolled_loop, false},
- {8192, rep_prefix_4_byte, false},
- {-1, rep_prefix_1_byte, false}}},
- DUMMY_STRINGOP_ALGS};
-static stringop_algs pentiumpro_memset[2] = {
- {rep_prefix_4_byte, {{1024, unrolled_loop, false},
- {8192, rep_prefix_4_byte, false},
- {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-static const
-struct processor_costs pentiumpro_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (4), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (4)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (17), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (17), /* HI */
- COSTS_N_INSNS (17), /* SI */
- COSTS_N_INSNS (17), /* DI */
- COSTS_N_INSNS (17)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 6, /* MOVE_RATIO */
- 2, /* cost for loading QImode using movzbl */
- {4, 4, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {2, 2, 2}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {2, 2, 6}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 6}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {2, 2}, /* cost of loading MMX registers
- in SImode and DImode */
- {2, 2}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {2, 2, 8}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {2, 2, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- 8, /* size of l1 cache. */
- 256, /* size of l2 cache */
- 32, /* size of prefetch block */
- 6, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (5), /* cost of FMUL instruction. */
- COSTS_N_INSNS (56), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (56), /* cost of FSQRT instruction. */
- pentiumpro_memcpy,
- pentiumpro_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs geode_memcpy[2] = {
- {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-static stringop_algs geode_memset[2] = {
- {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-static const
-struct processor_costs geode_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (2), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (7), /* SI */
- COSTS_N_INSNS (7), /* DI */
- COSTS_N_INSNS (7)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (15), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (23), /* HI */
- COSTS_N_INSNS (39), /* SI */
- COSTS_N_INSNS (39), /* DI */
- COSTS_N_INSNS (39)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 4, /* MOVE_RATIO */
- 1, /* cost for loading QImode using movzbl */
- {1, 1, 1}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {1, 1, 1}, /* cost of storing integer registers */
- 1, /* cost of reg,reg fld/fst */
- {1, 1, 1}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 6, 6}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
-
- 2, /* cost of moving MMX register */
- {2, 2}, /* cost of loading MMX registers
- in SImode and DImode */
- {2, 2}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {2, 2, 8}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {2, 2, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- 64, /* size of l1 cache. */
- 128, /* size of l2 cache. */
- 32, /* size of prefetch block */
- 1, /* number of parallel prefetches */
- 1, /* Branch cost */
- COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (11), /* cost of FMUL instruction. */
- COSTS_N_INSNS (47), /* cost of FDIV instruction. */
- COSTS_N_INSNS (1), /* cost of FABS instruction. */
- COSTS_N_INSNS (1), /* cost of FCHS instruction. */
- COSTS_N_INSNS (54), /* cost of FSQRT instruction. */
- geode_memcpy,
- geode_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs k6_memcpy[2] = {
- {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-static stringop_algs k6_memset[2] = {
- {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-static const
-struct processor_costs k6_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (2), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (3), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (3), /* DI */
- COSTS_N_INSNS (3)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (18), /* HI */
- COSTS_N_INSNS (18), /* SI */
- COSTS_N_INSNS (18), /* DI */
- COSTS_N_INSNS (18)}, /* other */
- COSTS_N_INSNS (2), /* cost of movsx */
- COSTS_N_INSNS (2), /* cost of movzx */
- 8, /* "large" insn */
- 4, /* MOVE_RATIO */
- 3, /* cost for loading QImode using movzbl */
- {4, 5, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {2, 3, 2}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {6, 6, 6}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 4}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {2, 2}, /* cost of loading MMX registers
- in SImode and DImode */
- {2, 2}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {2, 2, 8}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {2, 2, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 6, /* MMX or SSE register to integer */
- 32, /* size of l1 cache. */
- 32, /* size of l2 cache. Some models
- have integrated l2 cache, but
- optimizing for k6 is not important
- enough to worry about that. */
- 32, /* size of prefetch block */
- 1, /* number of parallel prefetches */
- 1, /* Branch cost */
- COSTS_N_INSNS (2), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (2), /* cost of FMUL instruction. */
- COSTS_N_INSNS (56), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (56), /* cost of FSQRT instruction. */
- k6_memcpy,
- k6_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-/* For some reason, Athlon deals better with REP prefix (relative to loops)
- compared to K8. Alignment becomes important after 8 bytes for memcpy and
- 128 bytes for memset. */
-static stringop_algs athlon_memcpy[2] = {
- {libcall, {{2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-static stringop_algs athlon_memset[2] = {
- {libcall, {{2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-static const
-struct processor_costs athlon_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (2), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (5), /* cost of starting multiply for QI */
- COSTS_N_INSNS (5), /* HI */
- COSTS_N_INSNS (5), /* SI */
- COSTS_N_INSNS (5), /* DI */
- COSTS_N_INSNS (5)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (26), /* HI */
- COSTS_N_INSNS (42), /* SI */
- COSTS_N_INSNS (74), /* DI */
- COSTS_N_INSNS (74)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {3, 4, 3}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {3, 4, 3}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {4, 4, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {4, 4}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 4, 6}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 5}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 5, /* MMX or SSE register to integer */
- 64, /* size of l1 cache. */
- 256, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 6, /* number of parallel prefetches */
- 5, /* Branch cost */
- COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (4), /* cost of FMUL instruction. */
- COSTS_N_INSNS (24), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
- athlon_memcpy,
- athlon_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-/* K8 has optimized REP instruction for medium sized blocks, but for very
- small blocks it is better to use loop. For large blocks, libcall can
- do nontemporary accesses and beat inline considerably. */
-static stringop_algs k8_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs k8_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false},
- {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
-static const
-struct processor_costs k8_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (2), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (5)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (26), /* HI */
- COSTS_N_INSNS (42), /* SI */
- COSTS_N_INSNS (74), /* DI */
- COSTS_N_INSNS (74)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {3, 4, 3}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {3, 4, 3}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {4, 4, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {3, 3}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 3, 6}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 5}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 5, /* MMX or SSE register to integer */
- 64, /* size of l1 cache. */
- 512, /* size of l2 cache. */
- 64, /* size of prefetch block */
- /* New AMD processors never drop prefetches; if they cannot be performed
- immediately, they are queued. We set number of simultaneous prefetches
- to a large constant to reflect this (it probably is not a good idea not
- to limit number of prefetches at all, as their execution also takes some
- time). */
- 100, /* number of parallel prefetches */
- 3, /* Branch cost */
- COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (4), /* cost of FMUL instruction. */
- COSTS_N_INSNS (19), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
-
- k8_memcpy,
- k8_memset,
- 4, /* scalar_stmt_cost. */
- 2, /* scalar load_cost. */
- 2, /* scalar_store_cost. */
- 5, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 2, /* vec_align_load_cost. */
- 3, /* vec_unalign_load_cost. */
- 3, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 2, /* cond_not_taken_branch_cost. */
-};
-
-/* AMDFAM10 has optimized REP instruction for medium sized blocks, but for
- very small blocks it is better to use loop. For large blocks, libcall can
- do nontemporary accesses and beat inline considerably. */
-static stringop_algs amdfam10_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs amdfam10_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-struct processor_costs amdfam10_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (2), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (5)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (35), /* HI */
- COSTS_N_INSNS (51), /* SI */
- COSTS_N_INSNS (83), /* DI */
- COSTS_N_INSNS (83)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {3, 4, 3}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {3, 4, 3}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {4, 4, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {3, 3}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 4, 3}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 5}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- /* On K8:
- MOVD reg64, xmmreg Double FSTORE 4
- MOVD reg32, xmmreg Double FSTORE 4
- On AMDFAM10:
- MOVD reg64, xmmreg Double FADD 3
- 1/1 1/1
- MOVD reg32, xmmreg Double FADD 3
- 1/1 1/1 */
- 64, /* size of l1 cache. */
- 512, /* size of l2 cache. */
- 64, /* size of prefetch block */
- /* New AMD processors never drop prefetches; if they cannot be performed
- immediately, they are queued. We set number of simultaneous prefetches
- to a large constant to reflect this (it probably is not a good idea not
- to limit number of prefetches at all, as their execution also takes some
- time). */
- 100, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (4), /* cost of FMUL instruction. */
- COSTS_N_INSNS (19), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
-
- amdfam10_memcpy,
- amdfam10_memset,
- 4, /* scalar_stmt_cost. */
- 2, /* scalar load_cost. */
- 2, /* scalar_store_cost. */
- 6, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 2, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 2, /* vec_store_cost. */
- 2, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-/* BDVER1 has optimized REP instruction for medium sized blocks, but for
- very small blocks it is better to use loop. For large blocks, libcall
- can do nontemporary accesses and beat inline considerably. */
-static stringop_algs bdver1_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs bdver1_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-
-const struct processor_costs bdver1_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (4), /* SI */
- COSTS_N_INSNS (6), /* DI */
- COSTS_N_INSNS (6)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (35), /* HI */
- COSTS_N_INSNS (51), /* SI */
- COSTS_N_INSNS (83), /* DI */
- COSTS_N_INSNS (83)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {5, 5, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {5, 5, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {4, 4}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 4, 4}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 4}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 2, /* MMX or SSE register to integer */
- /* On K8:
- MOVD reg64, xmmreg Double FSTORE 4
- MOVD reg32, xmmreg Double FSTORE 4
- On AMDFAM10:
- MOVD reg64, xmmreg Double FADD 3
- 1/1 1/1
- MOVD reg32, xmmreg Double FADD 3
- 1/1 1/1 */
- 16, /* size of l1 cache. */
- 2048, /* size of l2 cache. */
- 64, /* size of prefetch block */
- /* New AMD processors never drop prefetches; if they cannot be performed
- immediately, they are queued. We set number of simultaneous prefetches
- to a large constant to reflect this (it probably is not a good idea not
- to limit number of prefetches at all, as their execution also takes some
- time). */
- 100, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (6), /* cost of FMUL instruction. */
- COSTS_N_INSNS (42), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
-
- bdver1_memcpy,
- bdver1_memset,
- 6, /* scalar_stmt_cost. */
- 4, /* scalar load_cost. */
- 4, /* scalar_store_cost. */
- 6, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 4, /* vec_align_load_cost. */
- 4, /* vec_unalign_load_cost. */
- 4, /* vec_store_cost. */
- 4, /* cond_taken_branch_cost. */
- 2, /* cond_not_taken_branch_cost. */
-};
-
-/* BDVER2 has optimized REP instruction for medium sized blocks, but for
- very small blocks it is better to use loop. For large blocks, libcall
- can do nontemporary accesses and beat inline considerably. */
-
-static stringop_algs bdver2_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs bdver2_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-
-const struct processor_costs bdver2_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (4), /* SI */
- COSTS_N_INSNS (6), /* DI */
- COSTS_N_INSNS (6)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (35), /* HI */
- COSTS_N_INSNS (51), /* SI */
- COSTS_N_INSNS (83), /* DI */
- COSTS_N_INSNS (83)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {5, 5, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {5, 5, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {4, 4}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 4, 4}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 4}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 2, /* MMX or SSE register to integer */
- /* On K8:
- MOVD reg64, xmmreg Double FSTORE 4
- MOVD reg32, xmmreg Double FSTORE 4
- On AMDFAM10:
- MOVD reg64, xmmreg Double FADD 3
- 1/1 1/1
- MOVD reg32, xmmreg Double FADD 3
- 1/1 1/1 */
- 16, /* size of l1 cache. */
- 2048, /* size of l2 cache. */
- 64, /* size of prefetch block */
- /* New AMD processors never drop prefetches; if they cannot be performed
- immediately, they are queued. We set number of simultaneous prefetches
- to a large constant to reflect this (it probably is not a good idea not
- to limit number of prefetches at all, as their execution also takes some
- time). */
- 100, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (6), /* cost of FMUL instruction. */
- COSTS_N_INSNS (42), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
-
- bdver2_memcpy,
- bdver2_memset,
- 6, /* scalar_stmt_cost. */
- 4, /* scalar load_cost. */
- 4, /* scalar_store_cost. */
- 6, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 4, /* vec_align_load_cost. */
- 4, /* vec_unalign_load_cost. */
- 4, /* vec_store_cost. */
- 4, /* cond_taken_branch_cost. */
- 2, /* cond_not_taken_branch_cost. */
-};
-
-
- /* BDVER3 has optimized REP instruction for medium sized blocks, but for
- very small blocks it is better to use loop. For large blocks, libcall
- can do nontemporary accesses and beat inline considerably. */
-static stringop_algs bdver3_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs bdver3_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-struct processor_costs bdver3_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (4), /* SI */
- COSTS_N_INSNS (6), /* DI */
- COSTS_N_INSNS (6)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (35), /* HI */
- COSTS_N_INSNS (51), /* SI */
- COSTS_N_INSNS (83), /* DI */
- COSTS_N_INSNS (83)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {5, 5, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {5, 5, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {4, 4}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 4, 4}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 4}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 2, /* MMX or SSE register to integer */
- 16, /* size of l1 cache. */
- 2048, /* size of l2 cache. */
- 64, /* size of prefetch block */
- /* New AMD processors never drop prefetches; if they cannot be performed
- immediately, they are queued. We set number of simultaneous prefetches
- to a large constant to reflect this (it probably is not a good idea not
- to limit number of prefetches at all, as their execution also takes some
- time). */
- 100, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (6), /* cost of FMUL instruction. */
- COSTS_N_INSNS (42), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
-
- bdver3_memcpy,
- bdver3_memset,
- 6, /* scalar_stmt_cost. */
- 4, /* scalar load_cost. */
- 4, /* scalar_store_cost. */
- 6, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 4, /* vec_align_load_cost. */
- 4, /* vec_unalign_load_cost. */
- 4, /* vec_store_cost. */
- 4, /* cond_taken_branch_cost. */
- 2, /* cond_not_taken_branch_cost. */
-};
-
-/* BDVER4 has optimized REP instruction for medium sized blocks, but for
- very small blocks it is better to use loop. For large blocks, libcall
- can do nontemporary accesses and beat inline considerably. */
-static stringop_algs bdver4_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs bdver4_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-struct processor_costs bdver4_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (4), /* SI */
- COSTS_N_INSNS (6), /* DI */
- COSTS_N_INSNS (6)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (35), /* HI */
- COSTS_N_INSNS (51), /* SI */
- COSTS_N_INSNS (83), /* DI */
- COSTS_N_INSNS (83)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {5, 5, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {5, 5, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {4, 4}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 4, 4}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 4}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 2, /* MMX or SSE register to integer */
- 16, /* size of l1 cache. */
- 2048, /* size of l2 cache. */
- 64, /* size of prefetch block */
- /* New AMD processors never drop prefetches; if they cannot be performed
- immediately, they are queued. We set number of simultaneous prefetches
- to a large constant to reflect this (it probably is not a good idea not
- to limit number of prefetches at all, as their execution also takes some
- time). */
- 100, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (6), /* cost of FMUL instruction. */
- COSTS_N_INSNS (42), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
-
- bdver4_memcpy,
- bdver4_memset,
- 6, /* scalar_stmt_cost. */
- 4, /* scalar load_cost. */
- 4, /* scalar_store_cost. */
- 6, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 4, /* vec_align_load_cost. */
- 4, /* vec_unalign_load_cost. */
- 4, /* vec_store_cost. */
- 4, /* cond_taken_branch_cost. */
- 2, /* cond_not_taken_branch_cost. */
-};
-
-
-/* ZNVER1 has optimized REP instruction for medium sized blocks, but for
- very small blocks it is better to use loop. For large blocks, libcall
- can do nontemporary accesses and beat inline considerably. */
-static stringop_algs znver1_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs znver1_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-struct processor_costs znver1_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction. */
- COSTS_N_INSNS (1), /* cost of a lea instruction. */
- COSTS_N_INSNS (1), /* variable shift costs. */
- COSTS_N_INSNS (1), /* constant shift costs. */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI. */
- COSTS_N_INSNS (3), /* HI. */
- COSTS_N_INSNS (3), /* SI. */
- COSTS_N_INSNS (4), /* DI. */
- COSTS_N_INSNS (4)}, /* other. */
- 0, /* cost of multiply per each bit
- set. */
- {COSTS_N_INSNS (19), /* cost of a divide/mod for QI. */
- COSTS_N_INSNS (35), /* HI. */
- COSTS_N_INSNS (51), /* SI. */
- COSTS_N_INSNS (83), /* DI. */
- COSTS_N_INSNS (83)}, /* other. */
- COSTS_N_INSNS (1), /* cost of movsx. */
- COSTS_N_INSNS (1), /* cost of movzx. */
- 8, /* "large" insn. */
- 9, /* MOVE_RATIO. */
- 4, /* cost for loading QImode using
- movzbl. */
- {5, 5, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer
- registers. */
- 2, /* cost of reg,reg fld/fst. */
- {5, 5, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode. */
- {4, 4, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode. */
- 2, /* cost of moving MMX register. */
- {4, 4}, /* cost of loading MMX registers
- in SImode and DImode. */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode. */
- 2, /* cost of moving SSE register. */
- {4, 4, 4}, /* cost of loading SSE registers
- in SImode, DImode and TImode. */
- {4, 4, 4}, /* cost of storing SSE registers
- in SImode, DImode and TImode. */
- 2, /* MMX or SSE register to integer. */
- 32, /* size of l1 cache. */
- 512, /* size of l2 cache. */
- 64, /* size of prefetch block. */
- /* New AMD processors never drop prefetches; if they cannot be performed
- immediately, they are queued. We set number of simultaneous prefetches
- to a large constant to reflect this (it probably is not a good idea not
- to limit number of prefetches at all, as their execution also takes some
- time). */
- 100, /* number of parallel prefetches. */
- 2, /* Branch cost. */
- COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (6), /* cost of FMUL instruction. */
- COSTS_N_INSNS (42), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
-
- znver1_memcpy,
- znver1_memset,
- 6, /* scalar_stmt_cost. */
- 4, /* scalar load_cost. */
- 4, /* scalar_store_cost. */
- 6, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 4, /* vec_align_load_cost. */
- 4, /* vec_unalign_load_cost. */
- 4, /* vec_store_cost. */
- 4, /* cond_taken_branch_cost. */
- 2, /* cond_not_taken_branch_cost. */
-};
-
- /* BTVER1 has optimized REP instruction for medium sized blocks, but for
- very small blocks it is better to use loop. For large blocks, libcall can
- do nontemporary accesses and beat inline considerably. */
-static stringop_algs btver1_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs btver1_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-const struct processor_costs btver1_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (2), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (5)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (35), /* HI */
- COSTS_N_INSNS (51), /* SI */
- COSTS_N_INSNS (83), /* DI */
- COSTS_N_INSNS (83)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {3, 4, 3}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {3, 4, 3}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {4, 4, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {3, 3}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 4, 3}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 5}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- /* On K8:
- MOVD reg64, xmmreg Double FSTORE 4
- MOVD reg32, xmmreg Double FSTORE 4
- On AMDFAM10:
- MOVD reg64, xmmreg Double FADD 3
- 1/1 1/1
- MOVD reg32, xmmreg Double FADD 3
- 1/1 1/1 */
- 32, /* size of l1 cache. */
- 512, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 100, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (4), /* cost of FMUL instruction. */
- COSTS_N_INSNS (19), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
-
- btver1_memcpy,
- btver1_memset,
- 4, /* scalar_stmt_cost. */
- 2, /* scalar load_cost. */
- 2, /* scalar_store_cost. */
- 6, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 2, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 2, /* vec_store_cost. */
- 2, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs btver2_memcpy[2] = {
- {libcall, {{6, loop, false}, {14, unrolled_loop, false},
- {-1, rep_prefix_4_byte, false}}},
- {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs btver2_memset[2] = {
- {libcall, {{8, loop, false}, {24, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-const struct processor_costs btver2_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (2), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (5)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (35), /* HI */
- COSTS_N_INSNS (51), /* SI */
- COSTS_N_INSNS (83), /* DI */
- COSTS_N_INSNS (83)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 9, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {3, 4, 3}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {3, 4, 3}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {4, 4, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {3, 3}, /* cost of loading MMX registers
- in SImode and DImode */
- {4, 4}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {4, 4, 3}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {4, 4, 5}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 3, /* MMX or SSE register to integer */
- /* On K8:
- MOVD reg64, xmmreg Double FSTORE 4
- MOVD reg32, xmmreg Double FSTORE 4
- On AMDFAM10:
- MOVD reg64, xmmreg Double FADD 3
- 1/1 1/1
- MOVD reg32, xmmreg Double FADD 3
- 1/1 1/1 */
- 32, /* size of l1 cache. */
- 2048, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 100, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (4), /* cost of FMUL instruction. */
- COSTS_N_INSNS (19), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
- btver2_memcpy,
- btver2_memset,
- 4, /* scalar_stmt_cost. */
- 2, /* scalar load_cost. */
- 2, /* scalar_store_cost. */
- 6, /* vec_stmt_cost. */
- 0, /* vec_to_scalar_cost. */
- 2, /* scalar_to_vec_cost. */
- 2, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 2, /* vec_store_cost. */
- 2, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs pentium4_memcpy[2] = {
- {libcall, {{12, loop_1_byte, false}, {-1, rep_prefix_4_byte, false}}},
- DUMMY_STRINGOP_ALGS};
-static stringop_algs pentium4_memset[2] = {
- {libcall, {{6, loop_1_byte, false}, {48, loop, false},
- {20480, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- DUMMY_STRINGOP_ALGS};
-
-static const
-struct processor_costs pentium4_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (3), /* cost of a lea instruction */
- COSTS_N_INSNS (4), /* variable shift costs */
- COSTS_N_INSNS (4), /* constant shift costs */
- {COSTS_N_INSNS (15), /* cost of starting multiply for QI */
- COSTS_N_INSNS (15), /* HI */
- COSTS_N_INSNS (15), /* SI */
- COSTS_N_INSNS (15), /* DI */
- COSTS_N_INSNS (15)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (56), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (56), /* HI */
- COSTS_N_INSNS (56), /* SI */
- COSTS_N_INSNS (56), /* DI */
- COSTS_N_INSNS (56)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 16, /* "large" insn */
- 6, /* MOVE_RATIO */
- 2, /* cost for loading QImode using movzbl */
- {4, 5, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {2, 3, 2}, /* cost of storing integer registers */
- 2, /* cost of reg,reg fld/fst */
- {2, 2, 6}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 6}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {2, 2}, /* cost of loading MMX registers
- in SImode and DImode */
- {2, 2}, /* cost of storing MMX registers
- in SImode and DImode */
- 12, /* cost of moving SSE register */
- {12, 12, 12}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {2, 2, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 10, /* MMX or SSE register to integer */
- 8, /* size of l1 cache. */
- 256, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 6, /* number of parallel prefetches */
- 2, /* Branch cost */
- COSTS_N_INSNS (5), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (7), /* cost of FMUL instruction. */
- COSTS_N_INSNS (43), /* cost of FDIV instruction. */
- COSTS_N_INSNS (2), /* cost of FABS instruction. */
- COSTS_N_INSNS (2), /* cost of FCHS instruction. */
- COSTS_N_INSNS (43), /* cost of FSQRT instruction. */
- pentium4_memcpy,
- pentium4_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs nocona_memcpy[2] = {
- {libcall, {{12, loop_1_byte, false}, {-1, rep_prefix_4_byte, false}}},
- {libcall, {{32, loop, false}, {20000, rep_prefix_8_byte, false},
- {100000, unrolled_loop, false}, {-1, libcall, false}}}};
-
-static stringop_algs nocona_memset[2] = {
- {libcall, {{6, loop_1_byte, false}, {48, loop, false},
- {20480, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{24, loop, false}, {64, unrolled_loop, false},
- {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
-
-static const
-struct processor_costs nocona_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1), /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (10), /* cost of starting multiply for QI */
- COSTS_N_INSNS (10), /* HI */
- COSTS_N_INSNS (10), /* SI */
- COSTS_N_INSNS (10), /* DI */
- COSTS_N_INSNS (10)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (66), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (66), /* HI */
- COSTS_N_INSNS (66), /* SI */
- COSTS_N_INSNS (66), /* DI */
- COSTS_N_INSNS (66)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 16, /* "large" insn */
- 17, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {4, 4, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 3, /* cost of reg,reg fld/fst */
- {12, 12, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {4, 4, 4}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 6, /* cost of moving MMX register */
- {12, 12}, /* cost of loading MMX registers
- in SImode and DImode */
- {12, 12}, /* cost of storing MMX registers
- in SImode and DImode */
- 6, /* cost of moving SSE register */
- {12, 12, 12}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {12, 12, 12}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 8, /* MMX or SSE register to integer */
- 8, /* size of l1 cache. */
- 1024, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 8, /* number of parallel prefetches */
- 1, /* Branch cost */
- COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (8), /* cost of FMUL instruction. */
- COSTS_N_INSNS (40), /* cost of FDIV instruction. */
- COSTS_N_INSNS (3), /* cost of FABS instruction. */
- COSTS_N_INSNS (3), /* cost of FCHS instruction. */
- COSTS_N_INSNS (44), /* cost of FSQRT instruction. */
- nocona_memcpy,
- nocona_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs atom_memcpy[2] = {
- {libcall, {{11, loop, false}, {-1, rep_prefix_4_byte, false}}},
- {libcall, {{32, loop, false}, {64, rep_prefix_4_byte, false},
- {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
-static stringop_algs atom_memset[2] = {
- {libcall, {{8, loop, false}, {15, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{24, loop, false}, {32, unrolled_loop, false},
- {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
-static const
-struct processor_costs atom_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (2)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (26), /* HI */
- COSTS_N_INSNS (42), /* SI */
- COSTS_N_INSNS (74), /* DI */
- COSTS_N_INSNS (74)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 17, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {4, 4, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {12, 12, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {8, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {8, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {8, 8, 8}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {8, 8, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 5, /* MMX or SSE register to integer */
- 32, /* size of l1 cache. */
- 256, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 6, /* number of parallel prefetches */
- 3, /* Branch cost */
- COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (8), /* cost of FMUL instruction. */
- COSTS_N_INSNS (20), /* cost of FDIV instruction. */
- COSTS_N_INSNS (8), /* cost of FABS instruction. */
- COSTS_N_INSNS (8), /* cost of FCHS instruction. */
- COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
- atom_memcpy,
- atom_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs slm_memcpy[2] = {
- {libcall, {{11, loop, false}, {-1, rep_prefix_4_byte, false}}},
- {libcall, {{32, loop, false}, {64, rep_prefix_4_byte, false},
- {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
-static stringop_algs slm_memset[2] = {
- {libcall, {{8, loop, false}, {15, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{24, loop, false}, {32, unrolled_loop, false},
- {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
-static const
-struct processor_costs slm_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (3), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (2)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (26), /* HI */
- COSTS_N_INSNS (42), /* SI */
- COSTS_N_INSNS (74), /* DI */
- COSTS_N_INSNS (74)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 17, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {4, 4, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {12, 12, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {8, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {8, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {8, 8, 8}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {8, 8, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 5, /* MMX or SSE register to integer */
- 32, /* size of l1 cache. */
- 256, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 6, /* number of parallel prefetches */
- 3, /* Branch cost */
- COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (8), /* cost of FMUL instruction. */
- COSTS_N_INSNS (20), /* cost of FDIV instruction. */
- COSTS_N_INSNS (8), /* cost of FABS instruction. */
- COSTS_N_INSNS (8), /* cost of FCHS instruction. */
- COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
- slm_memcpy,
- slm_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 4, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-static stringop_algs intel_memcpy[2] = {
- {libcall, {{11, loop, false}, {-1, rep_prefix_4_byte, false}}},
- {libcall, {{32, loop, false}, {64, rep_prefix_4_byte, false},
- {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
-static stringop_algs intel_memset[2] = {
- {libcall, {{8, loop, false}, {15, unrolled_loop, false},
- {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
- {libcall, {{24, loop, false}, {32, unrolled_loop, false},
- {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
-static const
-struct processor_costs intel_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (3), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (2)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (26), /* HI */
- COSTS_N_INSNS (42), /* SI */
- COSTS_N_INSNS (74), /* DI */
- COSTS_N_INSNS (74)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 17, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {4, 4, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {12, 12, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {8, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {8, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {8, 8, 8}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {8, 8, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 5, /* MMX or SSE register to integer */
- 32, /* size of l1 cache. */
- 256, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 6, /* number of parallel prefetches */
- 3, /* Branch cost */
- COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (8), /* cost of FMUL instruction. */
- COSTS_N_INSNS (20), /* cost of FDIV instruction. */
- COSTS_N_INSNS (8), /* cost of FABS instruction. */
- COSTS_N_INSNS (8), /* cost of FCHS instruction. */
- COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
- intel_memcpy,
- intel_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 4, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-/* Generic should produce code tuned for Core-i7 (and newer chips)
- and btver1 (and newer chips). */
-
-static stringop_algs generic_memcpy[2] = {
- {libcall, {{32, loop, false}, {8192, rep_prefix_4_byte, false},
- {-1, libcall, false}}},
- {libcall, {{32, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static stringop_algs generic_memset[2] = {
- {libcall, {{32, loop, false}, {8192, rep_prefix_4_byte, false},
- {-1, libcall, false}}},
- {libcall, {{32, loop, false}, {8192, rep_prefix_8_byte, false},
- {-1, libcall, false}}}};
-static const
-struct processor_costs generic_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- /* On all chips taken into consideration lea is 2 cycles and more. With
- this cost however our current implementation of synth_mult results in
- use of unnecessary temporary registers causing regression on several
- SPECfp benchmarks. */
- COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (2)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (26), /* HI */
- COSTS_N_INSNS (42), /* SI */
- COSTS_N_INSNS (74), /* DI */
- COSTS_N_INSNS (74)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 17, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {4, 4, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {12, 12, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {8, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {8, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {8, 8, 8}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {8, 8, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 5, /* MMX or SSE register to integer */
- 32, /* size of l1 cache. */
- 512, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 6, /* number of parallel prefetches */
- /* Benchmarks shows large regressions on K8 sixtrack benchmark when this
- value is increased to perhaps more appropriate value of 5. */
- 3, /* Branch cost */
- COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (8), /* cost of FMUL instruction. */
- COSTS_N_INSNS (20), /* cost of FDIV instruction. */
- COSTS_N_INSNS (8), /* cost of FABS instruction. */
- COSTS_N_INSNS (8), /* cost of FCHS instruction. */
- COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
- generic_memcpy,
- generic_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
-/* core_cost should produce code tuned for Core familly of CPUs. */
-static stringop_algs core_memcpy[2] = {
- {libcall, {{1024, rep_prefix_4_byte, true}, {-1, libcall, false}}},
- {libcall, {{24, loop, true}, {128, rep_prefix_8_byte, true},
- {-1, libcall, false}}}};
-static stringop_algs core_memset[2] = {
- {libcall, {{6, loop_1_byte, true},
- {24, loop, true},
- {8192, rep_prefix_4_byte, true},
- {-1, libcall, false}}},
- {libcall, {{24, loop, true}, {512, rep_prefix_8_byte, true},
- {-1, libcall, false}}}};
-
-static const
-struct processor_costs core_cost = {
- COSTS_N_INSNS (1), /* cost of an add instruction */
- /* On all chips taken into consideration lea is 2 cycles and more. With
- this cost however our current implementation of synth_mult results in
- use of unnecessary temporary registers causing regression on several
- SPECfp benchmarks. */
- COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
- COSTS_N_INSNS (1), /* variable shift costs */
- COSTS_N_INSNS (1), /* constant shift costs */
- {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
- COSTS_N_INSNS (4), /* HI */
- COSTS_N_INSNS (3), /* SI */
- COSTS_N_INSNS (4), /* DI */
- COSTS_N_INSNS (2)}, /* other */
- 0, /* cost of multiply per each bit set */
- {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
- COSTS_N_INSNS (26), /* HI */
- COSTS_N_INSNS (42), /* SI */
- COSTS_N_INSNS (74), /* DI */
- COSTS_N_INSNS (74)}, /* other */
- COSTS_N_INSNS (1), /* cost of movsx */
- COSTS_N_INSNS (1), /* cost of movzx */
- 8, /* "large" insn */
- 17, /* MOVE_RATIO */
- 4, /* cost for loading QImode using movzbl */
- {4, 4, 4}, /* cost of loading integer registers
- in QImode, HImode and SImode.
- Relative to reg-reg move (2). */
- {4, 4, 4}, /* cost of storing integer registers */
- 4, /* cost of reg,reg fld/fst */
- {12, 12, 12}, /* cost of loading fp registers
- in SFmode, DFmode and XFmode */
- {6, 6, 8}, /* cost of storing fp registers
- in SFmode, DFmode and XFmode */
- 2, /* cost of moving MMX register */
- {8, 8}, /* cost of loading MMX registers
- in SImode and DImode */
- {8, 8}, /* cost of storing MMX registers
- in SImode and DImode */
- 2, /* cost of moving SSE register */
- {8, 8, 8}, /* cost of loading SSE registers
- in SImode, DImode and TImode */
- {8, 8, 8}, /* cost of storing SSE registers
- in SImode, DImode and TImode */
- 5, /* MMX or SSE register to integer */
- 64, /* size of l1 cache. */
- 512, /* size of l2 cache. */
- 64, /* size of prefetch block */
- 6, /* number of parallel prefetches */
- /* FIXME perhaps more appropriate value is 5. */
- 3, /* Branch cost */
- COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
- COSTS_N_INSNS (8), /* cost of FMUL instruction. */
- COSTS_N_INSNS (20), /* cost of FDIV instruction. */
- COSTS_N_INSNS (8), /* cost of FABS instruction. */
- COSTS_N_INSNS (8), /* cost of FCHS instruction. */
- COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
- core_memcpy,
- core_memset,
- 1, /* scalar_stmt_cost. */
- 1, /* scalar load_cost. */
- 1, /* scalar_store_cost. */
- 1, /* vec_stmt_cost. */
- 1, /* vec_to_scalar_cost. */
- 1, /* scalar_to_vec_cost. */
- 1, /* vec_align_load_cost. */
- 2, /* vec_unalign_load_cost. */
- 1, /* vec_store_cost. */
- 3, /* cond_taken_branch_cost. */
- 1, /* cond_not_taken_branch_cost. */
-};
-
/* Set by -mtune. */
-const struct processor_costs *ix86_tune_cost = &pentium_cost;
+const struct processor_costs *ix86_tune_cost = NULL;
/* Set by -mtune or -Os. */
-const struct processor_costs *ix86_cost = &pentium_cost;
+const struct processor_costs *ix86_cost = NULL;
/* Processor feature/optimization bitmasks. */
#define m_386 (1U<<PROCESSOR_I386)
@@ -2192,6 +138,7 @@ const struct processor_costs *ix86_cost = &pentium_cost;
#define m_BONNELL (1U<<PROCESSOR_BONNELL)
#define m_SILVERMONT (1U<<PROCESSOR_SILVERMONT)
#define m_KNL (1U<<PROCESSOR_KNL)
+#define m_KNM (1U<<PROCESSOR_KNM)
#define m_SKYLAKE_AVX512 (1U<<PROCESSOR_SKYLAKE_AVX512)
#define m_INTEL (1U<<PROCESSOR_INTEL)
@@ -2903,6 +850,7 @@ static const struct ptt processor_target_table[PROCESSOR_max] =
{"bonnell", &atom_cost, 16, 15, 16, 7, 16},
{"silvermont", &slm_cost, 16, 15, 16, 7, 16},
{"knl", &slm_cost, 16, 15, 16, 7, 16},
+ {"knm", &slm_cost, 16, 15, 16, 7, 16},
{"skylake-avx512", &core_cost, 16, 10, 16, 10, 16},
{"intel", &intel_cost, 16, 15, 16, 7, 16},
{"geode", &geode_cost, 0, 0, 0, 0, 0},
@@ -3653,7 +1601,7 @@ dimode_scalar_chain::compute_convert_gain ()
rtx dst = SET_DEST (def_set);
if (REG_P (src) && REG_P (dst))
- gain += COSTS_N_INSNS (2) - ix86_cost->sse_move;
+ gain += COSTS_N_INSNS (2) - ix86_cost->xmm_move;
else if (REG_P (src) && MEM_P (dst))
gain += 2 * ix86_cost->int_store[2] - ix86_cost->sse_store[1];
else if (MEM_P (src) && REG_P (dst))
@@ -4621,6 +2569,151 @@ make_pass_stv (gcc::context *ctxt)
return new pass_stv (ctxt);
}
+/* Inserting ENDBRANCH instructions. */
+
+static unsigned int
+rest_of_insert_endbranch (void)
+{
+ timevar_push (TV_MACH_DEP);
+
+ rtx cet_eb;
+ rtx_insn *insn;
+ basic_block bb;
+
+ /* Currently emit EB if it's a tracking function, i.e. 'nocf_check' is
+ absent among function attributes. Later an optimization will be
+ introduced to make analysis if an address of a static function is
+ taken. A static function whose address is not taken will get a
+ nocf_check attribute. This will allow to reduce the number of EB. */
+
+ if (!lookup_attribute ("nocf_check",
+ TYPE_ATTRIBUTES (TREE_TYPE (cfun->decl)))
+ && !cgraph_node::get (cfun->decl)->only_called_directly_p ())
+ {
+ cet_eb = gen_nop_endbr ();
+
+ bb = ENTRY_BLOCK_PTR_FOR_FN (cfun)->next_bb;
+ insn = BB_HEAD (bb);
+ emit_insn_before (cet_eb, insn);
+ }
+
+ bb = 0;
+ FOR_EACH_BB_FN (bb, cfun)
+ {
+ for (insn = BB_HEAD (bb); insn != NEXT_INSN (BB_END (bb));
+ insn = NEXT_INSN (insn))
+ {
+ if (INSN_P (insn) && GET_CODE (insn) == CALL_INSN)
+ {
+ rtx_insn *next_insn = insn;
+
+ while ((next_insn != BB_END (bb))
+ && (DEBUG_INSN_P (NEXT_INSN (next_insn))
+ || NOTE_P (NEXT_INSN (next_insn))
+ || BARRIER_P (NEXT_INSN (next_insn))))
+ next_insn = NEXT_INSN (next_insn);
+
+ /* Generate ENDBRANCH after CALL, which can return more than
+ twice, setjmp-like functions. */
+ if (find_reg_note (insn, REG_SETJMP, NULL) != NULL)
+ {
+ cet_eb = gen_nop_endbr ();
+ emit_insn_after (cet_eb, next_insn);
+ }
+ continue;
+ }
+
+ if (INSN_P (insn) && JUMP_P (insn) && flag_cet_switch)
+ {
+ rtx target = JUMP_LABEL (insn);
+ if (target == NULL_RTX || ANY_RETURN_P (target))
+ continue;
+
+ /* Check the jump is a switch table. */
+ rtx_insn *label = as_a<rtx_insn *> (target);
+ rtx_insn *table = next_insn (label);
+ if (table == NULL_RTX || !JUMP_TABLE_DATA_P (table))
+ continue;
+
+ /* For the indirect jump find out all places it jumps and insert
+ ENDBRANCH there. It should be done under a special flag to
+ control ENDBRANCH generation for switch stmts. */
+ edge_iterator ei;
+ edge e;
+ basic_block dest_blk;
+
+ FOR_EACH_EDGE (e, ei, bb->succs)
+ {
+ rtx_insn *insn;
+
+ dest_blk = e->dest;
+ insn = BB_HEAD (dest_blk);
+ gcc_assert (LABEL_P (insn));
+ cet_eb = gen_nop_endbr ();
+ emit_insn_after (cet_eb, insn);
+ }
+ continue;
+ }
+
+ if ((LABEL_P (insn) && LABEL_PRESERVE_P (insn))
+ || (NOTE_P (insn)
+ && NOTE_KIND (insn) == NOTE_INSN_DELETED_LABEL))
+/* TODO. Check /s bit also. */
+ {
+ cet_eb = gen_nop_endbr ();
+ emit_insn_after (cet_eb, insn);
+ continue;
+ }
+ }
+ }
+
+ timevar_pop (TV_MACH_DEP);
+ return 0;
+}
+
+namespace {
+
+const pass_data pass_data_insert_endbranch =
+{
+ RTL_PASS, /* type. */
+ "cet", /* name. */
+ OPTGROUP_NONE, /* optinfo_flags. */
+ TV_MACH_DEP, /* tv_id. */
+ 0, /* properties_required. */
+ 0, /* properties_provided. */
+ 0, /* properties_destroyed. */
+ 0, /* todo_flags_start. */
+ 0, /* todo_flags_finish. */
+};
+
+class pass_insert_endbranch : public rtl_opt_pass
+{
+public:
+ pass_insert_endbranch (gcc::context *ctxt)
+ : rtl_opt_pass (pass_data_insert_endbranch, ctxt)
+ {}
+
+ /* opt_pass methods: */
+ virtual bool gate (function *)
+ {
+ return ((flag_cf_protection & CF_BRANCH) && TARGET_IBT);
+ }
+
+ virtual unsigned int execute (function *)
+ {
+ return rest_of_insert_endbranch ();
+ }
+
+}; // class pass_insert_endbranch
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_insert_endbranch (gcc::context *ctxt)
+{
+ return new pass_insert_endbranch (ctxt);
+}
+
/* Return true if a red-zone is in use. */
bool
@@ -4648,11 +2741,14 @@ ix86_target_string (HOST_WIDE_INT isa, HOST_WIDE_INT isa2,
ISAs come first. Target string will be displayed in the same order. */
static struct ix86_target_opts isa2_opts[] =
{
+ { "-mgfni", OPTION_MASK_ISA_GFNI },
{ "-mrdpid", OPTION_MASK_ISA_RDPID },
{ "-msgx", OPTION_MASK_ISA_SGX },
{ "-mavx5124vnniw", OPTION_MASK_ISA_AVX5124VNNIW },
{ "-mavx5124fmaps", OPTION_MASK_ISA_AVX5124FMAPS },
- { "-mavx512vpopcntdq", OPTION_MASK_ISA_AVX512VPOPCNTDQ }
+ { "-mavx512vpopcntdq", OPTION_MASK_ISA_AVX512VPOPCNTDQ },
+ { "-mibt", OPTION_MASK_ISA_IBT },
+ { "-mshstk", OPTION_MASK_ISA_SHSTK }
};
static struct ix86_target_opts isa_opts[] =
{
@@ -4756,6 +2852,7 @@ ix86_target_string (HOST_WIDE_INT isa, HOST_WIDE_INT isa2,
static struct ix86_target_opts flag2_opts[] =
{
{ "-mgeneral-regs-only", OPTION_MASK_GENERAL_REGS_ONLY },
+ { "-mprefer-avx256", OPTION_MASK_PREFER_AVX256 },
};
const char *opts[ARRAY_SIZE (isa_opts) + ARRAY_SIZE (isa2_opts)
@@ -5352,6 +3449,8 @@ ix86_option_override_internal (bool main_args_p,
(PTA_CORE2 | PTA_MOVBE)
#define PTA_SILVERMONT \
(PTA_WESTMERE | PTA_MOVBE)
+#define PTA_KNM \
+ (PTA_KNL | PTA_AVX5124VNNIW | PTA_AVX5124FMAPS | PTA_AVX512VPOPCNTDQ)
/* if this reaches 64, need to widen struct pta flags below */
@@ -5422,6 +3521,7 @@ ix86_option_override_internal (bool main_args_p,
{"silvermont", PROCESSOR_SILVERMONT, CPU_SLM, PTA_SILVERMONT},
{"slm", PROCESSOR_SILVERMONT, CPU_SLM, PTA_SILVERMONT},
{"knl", PROCESSOR_KNL, CPU_SLM, PTA_KNL},
+ {"knm", PROCESSOR_KNM, CPU_SLM, PTA_KNM},
{"intel", PROCESSOR_INTEL, CPU_SLM, PTA_NEHALEM},
{"geode", PROCESSOR_GEODE, CPU_GEODE,
PTA_MMX | PTA_3DNOW | PTA_3DNOW_A | PTA_PREFETCH_SSE},
@@ -6741,6 +4841,37 @@ ix86_option_override_internal (bool main_args_p,
target_option_default_node = target_option_current_node
= build_target_option_node (opts);
+ /* Do not support control flow instrumentation if CET is not enabled. */
+ if (opts->x_flag_cf_protection != CF_NONE)
+ {
+ if (!(TARGET_IBT_P (opts->x_ix86_isa_flags2)
+ || TARGET_SHSTK_P (opts->x_ix86_isa_flags2)))
+ {
+ if (flag_cf_protection == CF_FULL)
+ {
+ error ("%<-fcf-protection=full%> requires CET support "
+ "on this target. Use -mcet or one of -mibt, "
+ "-mshstk options to enable CET");
+ }
+ else if (flag_cf_protection == CF_BRANCH)
+ {
+ error ("%<-fcf-protection=branch%> requires CET support "
+ "on this target. Use -mcet or one of -mibt, "
+ "-mshstk options to enable CET");
+ }
+ else if (flag_cf_protection == CF_RETURN)
+ {
+ error ("%<-fcf-protection=return%> requires CET support "
+ "on this target. Use -mcet or one of -mibt, "
+ "-mshstk options to enable CET");
+ }
+ flag_cf_protection = CF_NONE;
+ return false;
+ }
+ opts->x_flag_cf_protection =
+ (cf_protection_level) (opts->x_flag_cf_protection | CF_SET);
+ }
+
return true;
}
@@ -6841,6 +4972,30 @@ ix86_conditional_register_usage (void)
fixed_regs[i] = call_used_regs[i] = 1, reg_names[i] = "";
}
+/* Canonicalize a comparison from one we don't have to one we do have. */
+
+static void
+ix86_canonicalize_comparison (int *code, rtx *op0, rtx *op1,
+ bool op0_preserve_value)
+{
+ /* The order of operands in x87 ficom compare is forced by combine in
+ simplify_comparison () function. Float operator is treated as RTX_OBJ
+ with a precedence over other operators and is always put in the first
+ place. Swap condition and operands to match ficom instruction. */
+ if (!op0_preserve_value
+ && GET_CODE (*op0) == FLOAT && MEM_P (XEXP (*op0, 0)) && REG_P (*op1))
+ {
+ enum rtx_code scode = swap_condition ((enum rtx_code) *code);
+
+ /* We are called only for compares that are split to SAHF instruction.
+ Ensure that we have setcc/jcc insn for the swapped condition. */
+ if (ix86_fp_compare_code_to_integer (scode) != UNKNOWN)
+ {
+ std::swap (*op0, *op1);
+ *code = (int) scode;
+ }
+ }
+}
/* Save the current options */
@@ -7146,6 +5301,9 @@ ix86_valid_target_attribute_inner_p (tree args, char *p_strings[],
IX86_ATTR_ISA ("mpx", OPT_mmpx),
IX86_ATTR_ISA ("clwb", OPT_mclwb),
IX86_ATTR_ISA ("rdpid", OPT_mrdpid),
+ IX86_ATTR_ISA ("gfni", OPT_mgfni),
+ IX86_ATTR_ISA ("ibt", OPT_mibt),
+ IX86_ATTR_ISA ("shstk", OPT_mshstk),
/* enum options */
IX86_ATTR_ENUM ("fpmath=", OPT_mfpmath_),
@@ -13547,7 +11705,7 @@ ix86_add_queued_cfa_restore_notes (rtx insn)
zero if %r11 register is live and cannot be freely used and positive
otherwise. */
-static void
+static rtx
pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset,
int style, bool set_cfa)
{
@@ -13638,6 +11796,7 @@ pro_epilogue_adjust_stack (rtx dest, rtx src, rtx offset,
m->fs.sp_valid = valid;
m->fs.sp_realigned = realigned;
}
+ return insn;
}
/* Find an available register to be used as dynamic realign argument
@@ -13924,6 +12083,155 @@ release_scratch_register_on_entry (struct scratch_reg *sr)
#define PROBE_INTERVAL (1 << STACK_CHECK_PROBE_INTERVAL_EXP)
+/* Emit code to adjust the stack pointer by SIZE bytes while probing it.
+
+ This differs from the next routine in that it tries hard to prevent
+ attacks that jump the stack guard. Thus it is never allowed to allocate
+ more than PROBE_INTERVAL bytes of stack space without a suitable
+ probe. */
+
+static void
+ix86_adjust_stack_and_probe_stack_clash (const HOST_WIDE_INT size)
+{
+ struct machine_function *m = cfun->machine;
+
+ /* If this function does not statically allocate stack space, then
+ no probes are needed. */
+ if (!size)
+ {
+ /* However, the allocation of space via pushes for register
+ saves could be viewed as allocating space, but without the
+ need to probe. */
+ if (m->frame.nregs || m->frame.nsseregs || frame_pointer_needed)
+ dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME, true);
+ else
+ dump_stack_clash_frame_info (NO_PROBE_NO_FRAME, false);
+ return;
+ }
+
+ /* If we are a noreturn function, then we have to consider the
+ possibility that we're called via a jump rather than a call.
+
+ Thus we don't have the implicit probe generated by saving the
+ return address into the stack at the call. Thus, the stack
+ pointer could be anywhere in the guard page. The safe thing
+ to do is emit a probe now.
+
+ ?!? This should be revamped to work like aarch64 and s390 where
+ we track the offset from the most recent probe. Normally that
+ offset would be zero. For a noreturn function we would reset
+ it to PROBE_INTERVAL - (STACK_BOUNDARY / BITS_PER_UNIT). Then
+ we just probe when we cross PROBE_INTERVAL. */
+ if (TREE_THIS_VOLATILE (cfun->decl))
+ {
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ -GET_MODE_SIZE (word_mode)));
+ emit_insn (gen_blockage ());
+ }
+
+ /* If we allocate less than the size of the guard statically,
+ then no probing is necessary, but we do need to allocate
+ the stack. */
+ if (size < (1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE)))
+ {
+ pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (-size), -1,
+ m->fs.cfa_reg == stack_pointer_rtx);
+ dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME, true);
+ return;
+ }
+
+ /* We're allocating a large enough stack frame that we need to
+ emit probes. Either emit them inline or in a loop depending
+ on the size. */
+ HOST_WIDE_INT probe_interval
+ = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL);
+ if (size <= 4 * probe_interval)
+ {
+ HOST_WIDE_INT i;
+ for (i = probe_interval; i <= size; i += probe_interval)
+ {
+ /* Allocate PROBE_INTERVAL bytes. */
+ rtx insn
+ = pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (-PROBE_INTERVAL), -1,
+ m->fs.cfa_reg == stack_pointer_rtx);
+ add_reg_note (insn, REG_STACK_CHECK, const0_rtx);
+
+ /* And probe at *sp. */
+ emit_stack_probe (stack_pointer_rtx);
+ emit_insn (gen_blockage ());
+ }
+
+ /* We need to allocate space for the residual, but we do not need
+ to probe the residual. */
+ HOST_WIDE_INT residual = (i - probe_interval - size);
+ if (residual)
+ pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (residual), -1,
+ m->fs.cfa_reg == stack_pointer_rtx);
+ dump_stack_clash_frame_info (PROBE_INLINE, residual != 0);
+ }
+ else
+ {
+ struct scratch_reg sr;
+ get_scratch_register_on_entry (&sr);
+
+ /* Step 1: round SIZE down to a multiple of the interval. */
+ HOST_WIDE_INT rounded_size = size & -probe_interval;
+
+ /* Step 2: compute final value of the loop counter. Use lea if
+ possible. */
+ rtx addr = plus_constant (Pmode, stack_pointer_rtx, -rounded_size);
+ rtx insn;
+ if (address_no_seg_operand (addr, Pmode))
+ insn = emit_insn (gen_rtx_SET (sr.reg, addr));
+ else
+ {
+ emit_move_insn (sr.reg, GEN_INT (-rounded_size));
+ insn = emit_insn (gen_rtx_SET (sr.reg,
+ gen_rtx_PLUS (Pmode, sr.reg,
+ stack_pointer_rtx)));
+ }
+ if (m->fs.cfa_reg == stack_pointer_rtx)
+ {
+ add_reg_note (insn, REG_CFA_DEF_CFA,
+ plus_constant (Pmode, sr.reg,
+ m->fs.cfa_offset + rounded_size));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* Step 3: the loop. */
+ rtx size_rtx = GEN_INT (rounded_size);
+ insn = emit_insn (ix86_gen_adjust_stack_and_probe (sr.reg, sr.reg,
+ size_rtx));
+ if (m->fs.cfa_reg == stack_pointer_rtx)
+ {
+ m->fs.cfa_offset += rounded_size;
+ add_reg_note (insn, REG_CFA_DEF_CFA,
+ plus_constant (Pmode, stack_pointer_rtx,
+ m->fs.cfa_offset));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ m->fs.sp_offset += rounded_size;
+ emit_insn (gen_blockage ());
+
+ /* Step 4: adjust SP if we cannot assert at compile-time that SIZE
+ is equal to ROUNDED_SIZE. */
+
+ if (size != rounded_size)
+ pro_epilogue_adjust_stack (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (rounded_size - size), -1,
+ m->fs.cfa_reg == stack_pointer_rtx);
+ dump_stack_clash_frame_info (PROBE_LOOP, size != rounded_size);
+
+ release_scratch_register_on_entry (&sr);
+ }
+
+ /* Make sure nothing is scheduled before we are done. */
+ emit_insn (gen_blockage ());
+}
+
/* Emit code to adjust the stack pointer by SIZE bytes while probing it. */
static void
@@ -14385,10 +12693,13 @@ ix86_finalize_stack_frame_flags (void)
for (ref = DF_REG_USE_CHAIN (HARD_FRAME_POINTER_REGNUM);
ref; ref = next)
{
- rtx_insn *insn = DF_REF_INSN (ref);
+ next = DF_REF_NEXT_REG (ref);
+ if (!DF_REF_INSN_INFO (ref))
+ continue;
+
/* Make sure the next ref is for a different instruction,
so that we're not affected by the rescan. */
- next = DF_REF_NEXT_REG (ref);
+ rtx_insn *insn = DF_REF_INSN (ref);
while (next && DF_REF_INSN (next) == insn)
next = DF_REF_NEXT_REG (next);
@@ -14852,12 +13163,19 @@ ix86_expand_prologue (void)
/* The stack has already been decremented by the instruction calling us
so probe if the size is non-negative to preserve the protection area. */
- if (allocate >= 0 && flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ if (allocate >= 0
+ && (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection))
{
/* We expect the GP registers to be saved when probes are used. */
gcc_assert (int_registers_saved);
- if (STACK_CHECK_MOVING_SP)
+ if (flag_stack_clash_protection)
+ {
+ ix86_adjust_stack_and_probe_stack_clash (allocate);
+ allocate = 0;
+ }
+ else if (STACK_CHECK_MOVING_SP)
{
if (!(crtl->is_leaf && !cfun->calls_alloca
&& allocate <= PROBE_INTERVAL))
@@ -14871,7 +13189,7 @@ ix86_expand_prologue (void)
HOST_WIDE_INT size = allocate;
if (TARGET_64BIT && size >= HOST_WIDE_INT_C (0x80000000))
- size = 0x80000000 - STACK_CHECK_PROTECT - 1;
+ size = 0x80000000 - get_stack_check_protect () - 1;
if (TARGET_STACK_PROBE)
{
@@ -14881,18 +13199,20 @@ ix86_expand_prologue (void)
ix86_emit_probe_stack_range (0, size);
}
else
- ix86_emit_probe_stack_range (0, size + STACK_CHECK_PROTECT);
+ ix86_emit_probe_stack_range (0,
+ size + get_stack_check_protect ());
}
else
{
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
- ix86_emit_probe_stack_range (STACK_CHECK_PROTECT,
- size - STACK_CHECK_PROTECT);
+ if (size > PROBE_INTERVAL
+ && size > get_stack_check_protect ())
+ ix86_emit_probe_stack_range (get_stack_check_protect (),
+ size - get_stack_check_protect ());
}
else
- ix86_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
+ ix86_emit_probe_stack_range (get_stack_check_protect (), size);
}
}
}
@@ -18521,13 +16841,17 @@ ix86_delegitimize_address_1 (rtx x, bool base_term_p)
movl foo@GOTOFF(%ecx), %edx
in which case we return (%ecx - %ebx) + foo
or (%ecx - _GLOBAL_OFFSET_TABLE_) + foo if pseudo_pic_reg
- and reload has completed. */
+ and reload has completed. Don't do the latter for debug,
+ as _GLOBAL_OFFSET_TABLE_ can't be expressed in the assembly. */
if (pic_offset_table_rtx
&& (!reload_completed || !ix86_use_pseudo_pic_reg ()))
result = gen_rtx_PLUS (Pmode, gen_rtx_MINUS (Pmode, copy_rtx (addend),
pic_offset_table_rtx),
result);
- else if (pic_offset_table_rtx && !TARGET_MACHO && !TARGET_VXWORKS_RTP)
+ else if (base_term_p
+ && pic_offset_table_rtx
+ && !TARGET_MACHO
+ && !TARGET_VXWORKS_RTP)
{
rtx tmp = gen_rtx_SYMBOL_REF (Pmode, GOT_SYMBOL_NAME);
tmp = gen_rtx_MINUS (Pmode, copy_rtx (addend), tmp);
@@ -18580,6 +16904,25 @@ ix86_find_base_term (rtx x)
return ix86_delegitimize_address_1 (x, true);
}
+
+/* Return true if X shouldn't be emitted into the debug info.
+ Disallow UNSPECs other than @gotoff - we can't emit _GLOBAL_OFFSET_TABLE_
+ symbol easily into the .debug_info section, so we need not to
+ delegitimize, but instead assemble as @gotoff.
+ Disallow _GLOBAL_OFFSET_TABLE_ SYMBOL_REF - the assembler magically
+ assembles that as _GLOBAL_OFFSET_TABLE_-. expression. */
+
+static bool
+ix86_const_not_ok_for_debug_p (rtx x)
+{
+ if (GET_CODE (x) == UNSPEC && XINT (x, 1) != UNSPEC_GOTOFF)
+ return true;
+
+ if (SYMBOL_REF_P (x) && strcmp (XSTR (x, 0), GOT_SYMBOL_NAME) == 0)
+ return true;
+
+ return false;
+}
static void
put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
@@ -18598,6 +16941,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
switch (code)
{
case EQ:
+ gcc_assert (mode != CCGZmode);
switch (mode)
{
case E_CCAmode:
@@ -18621,6 +16965,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
}
break;
case NE:
+ gcc_assert (mode != CCGZmode);
switch (mode)
{
case E_CCAmode:
@@ -18665,6 +17010,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
case E_CCmode:
case E_CCGCmode:
+ case E_CCGZmode:
suffix = "l";
break;
@@ -18673,7 +17019,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
}
break;
case LTU:
- if (mode == CCmode)
+ if (mode == CCmode || mode == CCGZmode)
suffix = "b";
else if (mode == CCCmode)
suffix = fp ? "b" : "c";
@@ -18690,6 +17036,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
case E_CCmode:
case E_CCGCmode:
+ case E_CCGZmode:
suffix = "ge";
break;
@@ -18698,7 +17045,7 @@ put_condition_code (enum rtx_code code, machine_mode mode, bool reverse,
}
break;
case GEU:
- if (mode == CCmode)
+ if (mode == CCmode || mode == CCGZmode)
suffix = "nb";
else if (mode == CCCmode)
suffix = fp ? "nb" : "nc";
@@ -19477,6 +17824,8 @@ ix86_print_operand (FILE *file, rtx x, int code)
case '!':
if (ix86_bnd_prefixed_insn_p (current_output_insn))
fputs ("bnd ", file);
+ if (ix86_notrack_prefixed_insn_p (current_output_insn))
+ fputs ("notrack ", file);
return;
default:
@@ -19788,6 +18137,13 @@ ix86_print_operand_address_as (FILE *file, rtx addr,
code = 'k';
}
+ /* Since the upper 32 bits of RSP are always zero for x32,
+ we can encode %esp as %rsp to avoid 0x67 prefix if
+ there is no index register. */
+ if (TARGET_X32 && Pmode == SImode
+ && !index && base && REG_P (base) && REGNO (base) == SP_REG)
+ code = 'q';
+
if (ASSEMBLER_DIALECT == ASM_ATT)
{
if (disp)
@@ -19885,6 +18241,10 @@ i386_asm_output_addr_const_extra (FILE *file, rtx x)
op = XVECEXP (x, 0, 0);
switch (XINT (x, 1))
{
+ case UNSPEC_GOTOFF:
+ output_addr_const (file, op);
+ fputs ("@gotoff", file);
+ break;
case UNSPEC_GOTTPOFF:
output_addr_const (file, op);
/* FIXME: This might be @TPOFF in Sun ld. */
@@ -20004,89 +18364,66 @@ output_387_binary_op (rtx_insn *insn, rtx *operands)
{
static char buf[40];
const char *p;
- const char *ssep;
- int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]) || SSE_REG_P (operands[2]);
+ bool is_sse
+ = (SSE_REG_P (operands[0])
+ || SSE_REG_P (operands[1]) || SSE_REG_P (operands[2]));
- /* Even if we do not want to check the inputs, this documents input
- constraints. Which helps in understanding the following code. */
- if (flag_checking)
- {
- if (STACK_REG_P (operands[0])
- && ((REG_P (operands[1])
- && REGNO (operands[0]) == REGNO (operands[1])
- && (STACK_REG_P (operands[2]) || MEM_P (operands[2])))
- || (REG_P (operands[2])
- && REGNO (operands[0]) == REGNO (operands[2])
- && (STACK_REG_P (operands[1]) || MEM_P (operands[1]))))
- && (STACK_TOP_P (operands[1]) || STACK_TOP_P (operands[2])))
- ; /* ok */
- else
- gcc_assert (is_sse);
- }
+ if (is_sse)
+ p = "%v";
+ else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
+ || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
+ p = "fi";
+ else
+ p = "f";
+
+ strcpy (buf, p);
switch (GET_CODE (operands[3]))
{
case PLUS:
- if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
- || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
- p = "fiadd";
- else
- p = "fadd";
- ssep = "vadd";
- break;
-
+ p = "add"; break;
case MINUS:
- if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
- || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
- p = "fisub";
- else
- p = "fsub";
- ssep = "vsub";
- break;
-
+ p = "sub"; break;
case MULT:
- if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
- || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
- p = "fimul";
- else
- p = "fmul";
- ssep = "vmul";
- break;
-
+ p = "mul"; break;
case DIV:
- if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
- || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
- p = "fidiv";
- else
- p = "fdiv";
- ssep = "vdiv";
- break;
-
+ p = "div"; break;
default:
gcc_unreachable ();
}
+ strcat (buf, p);
+
if (is_sse)
{
+ p = (GET_MODE (operands[0]) == SFmode) ? "ss" : "sd";
+ strcat (buf, p);
+
if (TARGET_AVX)
- {
- strcpy (buf, ssep);
- if (GET_MODE (operands[0]) == SFmode)
- strcat (buf, "ss\t{%2, %1, %0|%0, %1, %2}");
- else
- strcat (buf, "sd\t{%2, %1, %0|%0, %1, %2}");
- }
+ p = "\t{%2, %1, %0|%0, %1, %2}";
else
- {
- strcpy (buf, ssep + 1);
- if (GET_MODE (operands[0]) == SFmode)
- strcat (buf, "ss\t{%2, %0|%0, %2}");
- else
- strcat (buf, "sd\t{%2, %0|%0, %2}");
- }
- return buf;
+ p = "\t{%2, %0|%0, %2}";
+
+ strcat (buf, p);
+ return buf;
}
- strcpy (buf, p);
+
+ /* Even if we do not want to check the inputs, this documents input
+ constraints. Which helps in understanding the following code. */
+ if (flag_checking)
+ {
+ if (STACK_REG_P (operands[0])
+ && ((REG_P (operands[1])
+ && REGNO (operands[0]) == REGNO (operands[1])
+ && (STACK_REG_P (operands[2]) || MEM_P (operands[2])))
+ || (REG_P (operands[2])
+ && REGNO (operands[0]) == REGNO (operands[2])
+ && (STACK_REG_P (operands[1]) || MEM_P (operands[1]))))
+ && (STACK_TOP_P (operands[1]) || STACK_TOP_P (operands[2])))
+ ; /* ok */
+ else
+ gcc_unreachable ();
+ }
switch (GET_CODE (operands[3]))
{
@@ -20675,10 +19012,13 @@ ix86_emit_mode_set (int entity, int mode, int prev_mode ATTRIBUTE_UNUSED,
const char *
output_fix_trunc (rtx_insn *insn, rtx *operands, bool fisttp)
{
- int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
- int dimode_p = GET_MODE (operands[0]) == DImode;
+ bool stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG);
+ bool dimode_p = GET_MODE (operands[0]) == DImode;
int round_mode = get_attr_i387_cw (insn);
+ static char buf[40];
+ const char *p;
+
/* Jump through a hoop or two for DImode, since the hardware has no
non-popping instruction. We used to do this a different way, but
that was somewhat fragile and broke with post-reload splitters. */
@@ -20690,18 +19030,20 @@ output_fix_trunc (rtx_insn *insn, rtx *operands, bool fisttp)
gcc_assert (GET_MODE (operands[1]) != TFmode);
if (fisttp)
- output_asm_insn ("fisttp%Z0\t%0", operands);
- else
- {
- if (round_mode != I387_CW_ANY)
- output_asm_insn ("fldcw\t%3", operands);
- if (stack_top_dies || dimode_p)
- output_asm_insn ("fistp%Z0\t%0", operands);
- else
- output_asm_insn ("fist%Z0\t%0", operands);
- if (round_mode != I387_CW_ANY)
- output_asm_insn ("fldcw\t%2", operands);
- }
+ return "fisttp%Z0\t%0";
+
+ strcpy (buf, "fist");
+
+ if (round_mode != I387_CW_ANY)
+ output_asm_insn ("fldcw\t%3", operands);
+
+ p = "p%Z0\t%0";
+ strcat (buf, p + !(stack_top_dies || dimode_p));
+
+ output_asm_insn (buf, operands);
+
+ if (round_mode != I387_CW_ANY)
+ output_asm_insn ("fldcw\t%2", operands);
return "";
}
@@ -20738,120 +19080,65 @@ output_387_ffreep (rtx *operands ATTRIBUTE_UNUSED, int opno)
should be used. UNORDERED_P is true when fucom should be used. */
const char *
-output_fp_compare (rtx_insn *insn, rtx *operands, bool eflags_p, bool unordered_p)
+output_fp_compare (rtx_insn *insn, rtx *operands,
+ bool eflags_p, bool unordered_p)
{
- int stack_top_dies;
- rtx cmp_op0, cmp_op1;
- int is_sse = SSE_REG_P (operands[0]) || SSE_REG_P (operands[1]);
+ rtx *xops = eflags_p ? &operands[0] : &operands[1];
+ bool stack_top_dies;
- if (eflags_p)
- {
- cmp_op0 = operands[0];
- cmp_op1 = operands[1];
- }
- else
- {
- cmp_op0 = operands[1];
- cmp_op1 = operands[2];
- }
-
- if (is_sse)
- {
- if (GET_MODE (operands[0]) == SFmode)
- if (unordered_p)
- return "%vucomiss\t{%1, %0|%0, %1}";
- else
- return "%vcomiss\t{%1, %0|%0, %1}";
- else
- if (unordered_p)
- return "%vucomisd\t{%1, %0|%0, %1}";
- else
- return "%vcomisd\t{%1, %0|%0, %1}";
- }
+ static char buf[40];
+ const char *p;
- gcc_assert (STACK_TOP_P (cmp_op0));
+ gcc_assert (STACK_TOP_P (xops[0]));
- stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
+ stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG);
- if (cmp_op1 == CONST0_RTX (GET_MODE (cmp_op1)))
+ if (eflags_p)
{
- if (stack_top_dies)
- {
- output_asm_insn ("ftst\n\tfnstsw\t%0", operands);
- return output_387_ffreep (operands, 1);
- }
- else
- return "ftst\n\tfnstsw\t%0";
+ p = unordered_p ? "fucomi" : "fcomi";
+ strcpy (buf, p);
+
+ p = "p\t{%y1, %0|%0, %y1}";
+ strcat (buf, p + !stack_top_dies);
+
+ return buf;
}
- if (STACK_REG_P (cmp_op1)
+ if (STACK_REG_P (xops[1])
&& stack_top_dies
- && find_regno_note (insn, REG_DEAD, REGNO (cmp_op1))
- && REGNO (cmp_op1) != FIRST_STACK_REG)
+ && find_regno_note (insn, REG_DEAD, FIRST_STACK_REG + 1))
{
- /* If both the top of the 387 stack dies, and the other operand
- is also a stack register that dies, then this must be a
- `fcompp' float compare */
+ gcc_assert (REGNO (xops[1]) == FIRST_STACK_REG + 1);
- if (eflags_p)
- {
- /* There is no double popping fcomi variant. Fortunately,
- eflags is immune from the fstp's cc clobbering. */
- if (unordered_p)
- output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands);
- else
- output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands);
- return output_387_ffreep (operands, 0);
- }
- else
- {
- if (unordered_p)
- return "fucompp\n\tfnstsw\t%0";
- else
- return "fcompp\n\tfnstsw\t%0";
- }
+ /* If both the top of the 387 stack die, and the other operand
+ is also a stack register that dies, then this must be a
+ `fcompp' float compare. */
+ p = unordered_p ? "fucompp" : "fcompp";
+ strcpy (buf, p);
+ }
+ else if (const0_operand (xops[1], VOIDmode))
+ {
+ gcc_assert (!unordered_p);
+ strcpy (buf, "ftst");
}
else
{
- /* Encoded here as eflags_p | intmode | unordered_p | stack_top_dies. */
-
- static const char * const alt[16] =
- {
- "fcom%Z2\t%y2\n\tfnstsw\t%0",
- "fcomp%Z2\t%y2\n\tfnstsw\t%0",
- "fucom%Z2\t%y2\n\tfnstsw\t%0",
- "fucomp%Z2\t%y2\n\tfnstsw\t%0",
-
- "ficom%Z2\t%y2\n\tfnstsw\t%0",
- "ficomp%Z2\t%y2\n\tfnstsw\t%0",
- NULL,
- NULL,
-
- "fcomi\t{%y1, %0|%0, %y1}",
- "fcomip\t{%y1, %0|%0, %y1}",
- "fucomi\t{%y1, %0|%0, %y1}",
- "fucomip\t{%y1, %0|%0, %y1}",
-
- NULL,
- NULL,
- NULL,
- NULL
- };
-
- int mask;
- const char *ret;
-
- mask = eflags_p << 3;
- mask |= (GET_MODE_CLASS (GET_MODE (cmp_op1)) == MODE_INT) << 2;
- mask |= unordered_p << 1;
- mask |= stack_top_dies;
+ if (GET_MODE_CLASS (GET_MODE (xops[1])) == MODE_INT)
+ {
+ gcc_assert (!unordered_p);
+ p = "ficom";
+ }
+ else
+ p = unordered_p ? "fucom" : "fcom";
- gcc_assert (mask < 16);
- ret = alt[mask];
- gcc_assert (ret);
+ strcpy (buf, p);
- return ret;
+ p = "p%Z2\t%y2";
+ strcat (buf, p + !stack_top_dies);
}
+
+ output_asm_insn (buf, operands);
+ return "fnstsw\t%0";
}
void
@@ -21755,9 +20042,22 @@ ix86_split_idivmod (machine_mode mode, rtx operands[],
switch (mode)
{
case E_SImode:
- gen_divmod4_1 = signed_p ? gen_divmodsi4_1 : gen_udivmodsi4_1;
+ if (GET_MODE (operands[0]) == SImode)
+ {
+ if (GET_MODE (operands[1]) == SImode)
+ gen_divmod4_1 = signed_p ? gen_divmodsi4_1 : gen_udivmodsi4_1;
+ else
+ gen_divmod4_1
+ = signed_p ? gen_divmodsi4_zext_2 : gen_udivmodsi4_zext_2;
+ gen_zero_extend = gen_zero_extendqisi2;
+ }
+ else
+ {
+ gen_divmod4_1
+ = signed_p ? gen_divmodsi4_zext_1 : gen_udivmodsi4_zext_1;
+ gen_zero_extend = gen_zero_extendqidi2;
+ }
gen_test_ccno_1 = gen_testsi_ccno_1;
- gen_zero_extend = gen_zero_extendqisi2;
break;
case E_DImode:
gen_divmod4_1 = signed_p ? gen_divmoddi4_1 : gen_udivmoddi4_1;
@@ -21808,24 +20108,32 @@ ix86_split_idivmod (machine_mode mode, rtx operands[],
if (signed_p)
{
- div = gen_rtx_DIV (SImode, operands[2], operands[3]);
- mod = gen_rtx_MOD (SImode, operands[2], operands[3]);
+ div = gen_rtx_DIV (mode, operands[2], operands[3]);
+ mod = gen_rtx_MOD (mode, operands[2], operands[3]);
}
else
{
- div = gen_rtx_UDIV (SImode, operands[2], operands[3]);
- mod = gen_rtx_UMOD (SImode, operands[2], operands[3]);
+ div = gen_rtx_UDIV (mode, operands[2], operands[3]);
+ mod = gen_rtx_UMOD (mode, operands[2], operands[3]);
+ }
+ if (mode == SImode)
+ {
+ if (GET_MODE (operands[0]) != SImode)
+ div = gen_rtx_ZERO_EXTEND (DImode, div);
+ if (GET_MODE (operands[1]) != SImode)
+ mod = gen_rtx_ZERO_EXTEND (DImode, mod);
}
/* Extract remainder from AH. */
- tmp1 = gen_rtx_ZERO_EXTRACT (mode, tmp0, GEN_INT (8), GEN_INT (8));
+ tmp1 = gen_rtx_ZERO_EXTRACT (GET_MODE (operands[1]),
+ tmp0, GEN_INT (8), GEN_INT (8));
if (REG_P (operands[1]))
insn = emit_move_insn (operands[1], tmp1);
else
{
/* Need a new scratch register since the old one has result
of 8bit divide. */
- scratch = gen_reg_rtx (mode);
+ scratch = gen_reg_rtx (GET_MODE (operands[1]));
emit_move_insn (scratch, tmp1);
insn = emit_move_insn (operands[1], scratch);
}
@@ -23362,6 +21670,8 @@ ix86_match_ccmode (rtx insn, machine_mode req_mode)
case E_CCZmode:
break;
+ case E_CCGZmode:
+
case E_CCAmode:
case E_CCCmode:
case E_CCOmode:
@@ -23403,14 +21713,35 @@ ix86_expand_int_compare (enum rtx_code code, rtx op0, rtx op1)
Return the appropriate mode to use. */
machine_mode
-ix86_fp_compare_mode (enum rtx_code)
+ix86_fp_compare_mode (enum rtx_code code)
{
- /* ??? In order to make all comparisons reversible, we do all comparisons
- non-trapping when compiling for IEEE. Once gcc is able to distinguish
- all forms trapping and nontrapping comparisons, we can make inequality
- comparisons trapping again, since it results in better code when using
- FCOM based compares. */
- return TARGET_IEEE_FP ? CCFPUmode : CCFPmode;
+ if (!TARGET_IEEE_FP)
+ return CCFPmode;
+
+ switch (code)
+ {
+ case GT:
+ case GE:
+ case LT:
+ case LE:
+ return CCFPmode;
+
+ case EQ:
+ case NE:
+
+ case LTGT:
+ case UNORDERED:
+ case ORDERED:
+ case UNLT:
+ case UNLE:
+ case UNGT:
+ case UNGE:
+ case UNEQ:
+ return CCFPUmode;
+
+ default:
+ gcc_unreachable ();
+ }
}
machine_mode
@@ -23650,7 +21981,7 @@ ix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1)
machine_mode fpcmp_mode = ix86_fp_compare_mode (code);
rtx op0 = *pop0, op1 = *pop1;
machine_mode op_mode = GET_MODE (op0);
- int is_sse = TARGET_SSE_MATH && SSE_FLOAT_MODE_P (op_mode);
+ bool is_sse = TARGET_SSE_MATH && SSE_FLOAT_MODE_P (op_mode);
/* All of the unordered compare instructions only work on registers.
The same is true of the fcomi compare instructions. The XFmode
@@ -24070,6 +22401,62 @@ ix86_expand_branch (enum rtx_code code, rtx op0, rtx op1, rtx label)
break;
}
+ /* Emulate comparisons that do not depend on Zero flag with
+ double-word subtraction. Note that only Overflow, Sign
+ and Carry flags are valid, so swap arguments and condition
+ of comparisons that would otherwise test Zero flag. */
+
+ switch (code)
+ {
+ case LE: case LEU: case GT: case GTU:
+ std::swap (lo[0], lo[1]);
+ std::swap (hi[0], hi[1]);
+ code = swap_condition (code);
+ /* FALLTHRU */
+
+ case LT: case LTU: case GE: case GEU:
+ {
+ rtx (*cmp_insn) (rtx, rtx);
+ rtx (*sbb_insn) (rtx, rtx, rtx);
+ bool uns = (code == LTU || code == GEU);
+
+ if (TARGET_64BIT)
+ {
+ cmp_insn = gen_cmpdi_1;
+ sbb_insn
+ = uns ? gen_subdi3_carry_ccc : gen_subdi3_carry_ccgz;
+ }
+ else
+ {
+ cmp_insn = gen_cmpsi_1;
+ sbb_insn
+ = uns ? gen_subsi3_carry_ccc : gen_subsi3_carry_ccgz;
+ }
+
+ if (!nonimmediate_operand (lo[0], submode))
+ lo[0] = force_reg (submode, lo[0]);
+ if (!x86_64_general_operand (lo[1], submode))
+ lo[1] = force_reg (submode, lo[1]);
+
+ if (!register_operand (hi[0], submode))
+ hi[0] = force_reg (submode, hi[0]);
+ if ((uns && !nonimmediate_operand (hi[1], submode))
+ || (!uns && !x86_64_general_operand (hi[1], submode)))
+ hi[1] = force_reg (submode, hi[1]);
+
+ emit_insn (cmp_insn (lo[0], lo[1]));
+ emit_insn (sbb_insn (gen_rtx_SCRATCH (submode), hi[0], hi[1]));
+
+ tmp = gen_rtx_REG (uns ? CCCmode : CCGZmode, FLAGS_REG);
+
+ ix86_expand_branch (code, tmp, const0_rtx, label);
+ return;
+ }
+
+ default:
+ break;
+ }
+
/* Otherwise, we need two or three jumps. */
label2 = gen_label_rtx ();
@@ -24121,31 +22508,6 @@ ix86_expand_branch (enum rtx_code code, rtx op0, rtx op1, rtx label)
}
}
-/* Split branch based on floating point condition. */
-void
-ix86_split_fp_branch (enum rtx_code code, rtx op1, rtx op2,
- rtx target1, rtx target2, rtx tmp)
-{
- rtx condition;
- rtx_insn *i;
-
- if (target2 != pc_rtx)
- {
- std::swap (target1, target2);
- code = reverse_condition_maybe_unordered (code);
- }
-
- condition = ix86_expand_fp_compare (code, op1, op2,
- tmp);
-
- i = emit_jump_insn (gen_rtx_SET
- (pc_rtx,
- gen_rtx_IF_THEN_ELSE (VOIDmode,
- condition, target1, target2)));
- if (split_branch_probability.initialized_p ())
- add_reg_br_prob_note (i, split_branch_probability);
-}
-
void
ix86_expand_setcc (rtx dest, enum rtx_code code, rtx op0, rtx op1)
{
@@ -25687,10 +24049,10 @@ struct expand_vec_perm_d
};
static bool
-ix86_expand_vec_perm_vpermi2 (rtx target, rtx op0, rtx mask, rtx op1,
+ix86_expand_vec_perm_vpermt2 (rtx target, rtx mask, rtx op0, rtx op1,
struct expand_vec_perm_d *d)
{
- /* ix86_expand_vec_perm_vpermi2 is called from both const and non-const
+ /* ix86_expand_vec_perm_vpermt2 is called from both const and non-const
expander, so args are either in d, or in op0, op1 etc. */
machine_mode mode = GET_MODE (d ? d->op0 : op0);
machine_mode maskmode = mode;
@@ -25700,83 +24062,83 @@ ix86_expand_vec_perm_vpermi2 (rtx target, rtx op0, rtx mask, rtx op1,
{
case E_V8HImode:
if (TARGET_AVX512VL && TARGET_AVX512BW)
- gen = gen_avx512vl_vpermi2varv8hi3;
+ gen = gen_avx512vl_vpermt2varv8hi3;
break;
case E_V16HImode:
if (TARGET_AVX512VL && TARGET_AVX512BW)
- gen = gen_avx512vl_vpermi2varv16hi3;
+ gen = gen_avx512vl_vpermt2varv16hi3;
break;
case E_V64QImode:
if (TARGET_AVX512VBMI)
- gen = gen_avx512bw_vpermi2varv64qi3;
+ gen = gen_avx512bw_vpermt2varv64qi3;
break;
case E_V32HImode:
if (TARGET_AVX512BW)
- gen = gen_avx512bw_vpermi2varv32hi3;
+ gen = gen_avx512bw_vpermt2varv32hi3;
break;
case E_V4SImode:
if (TARGET_AVX512VL)
- gen = gen_avx512vl_vpermi2varv4si3;
+ gen = gen_avx512vl_vpermt2varv4si3;
break;
case E_V8SImode:
if (TARGET_AVX512VL)
- gen = gen_avx512vl_vpermi2varv8si3;
+ gen = gen_avx512vl_vpermt2varv8si3;
break;
case E_V16SImode:
if (TARGET_AVX512F)
- gen = gen_avx512f_vpermi2varv16si3;
+ gen = gen_avx512f_vpermt2varv16si3;
break;
case E_V4SFmode:
if (TARGET_AVX512VL)
{
- gen = gen_avx512vl_vpermi2varv4sf3;
+ gen = gen_avx512vl_vpermt2varv4sf3;
maskmode = V4SImode;
}
break;
case E_V8SFmode:
if (TARGET_AVX512VL)
{
- gen = gen_avx512vl_vpermi2varv8sf3;
+ gen = gen_avx512vl_vpermt2varv8sf3;
maskmode = V8SImode;
}
break;
case E_V16SFmode:
if (TARGET_AVX512F)
{
- gen = gen_avx512f_vpermi2varv16sf3;
+ gen = gen_avx512f_vpermt2varv16sf3;
maskmode = V16SImode;
}
break;
case E_V2DImode:
if (TARGET_AVX512VL)
- gen = gen_avx512vl_vpermi2varv2di3;
+ gen = gen_avx512vl_vpermt2varv2di3;
break;
case E_V4DImode:
if (TARGET_AVX512VL)
- gen = gen_avx512vl_vpermi2varv4di3;
+ gen = gen_avx512vl_vpermt2varv4di3;
break;
case E_V8DImode:
if (TARGET_AVX512F)
- gen = gen_avx512f_vpermi2varv8di3;
+ gen = gen_avx512f_vpermt2varv8di3;
break;
case E_V2DFmode:
if (TARGET_AVX512VL)
{
- gen = gen_avx512vl_vpermi2varv2df3;
+ gen = gen_avx512vl_vpermt2varv2df3;
maskmode = V2DImode;
}
break;
case E_V4DFmode:
if (TARGET_AVX512VL)
{
- gen = gen_avx512vl_vpermi2varv4df3;
+ gen = gen_avx512vl_vpermt2varv4df3;
maskmode = V4DImode;
}
break;
case E_V8DFmode:
if (TARGET_AVX512F)
{
- gen = gen_avx512f_vpermi2varv8df3;
+ gen = gen_avx512f_vpermt2varv8df3;
maskmode = V8DImode;
}
break;
@@ -25787,7 +24149,7 @@ ix86_expand_vec_perm_vpermi2 (rtx target, rtx op0, rtx mask, rtx op1,
if (gen == NULL)
return false;
- /* ix86_expand_vec_perm_vpermi2 is called from both const and non-const
+ /* ix86_expand_vec_perm_vpermt2 is called from both const and non-const
expander, so args are either in d, or in op0, op1 etc. */
if (d)
{
@@ -25800,7 +24162,7 @@ ix86_expand_vec_perm_vpermi2 (rtx target, rtx op0, rtx mask, rtx op1,
mask = gen_rtx_CONST_VECTOR (maskmode, gen_rtvec_v (d->nelt, vec));
}
- emit_insn (gen (target, op0, force_reg (maskmode, mask), op1));
+ emit_insn (gen (target, force_reg (maskmode, mask), op0, op1));
return true;
}
@@ -25851,7 +24213,7 @@ ix86_expand_vec_perm (rtx operands[])
}
}
- if (ix86_expand_vec_perm_vpermi2 (target, op0, mask, op1, NULL))
+ if (ix86_expand_vec_perm_vpermt2 (target, mask, op0, op1, NULL))
return;
if (TARGET_AVX2)
@@ -28729,6 +27091,9 @@ ix86_expand_set_or_movmem (rtx dst, rtx src, rtx count_exp, rtx val_exp,
&& optab_handler (mov_optab, wider_mode) != CODE_FOR_nothing)
move_mode = wider_mode;
+ if (TARGET_AVX128_OPTIMAL && GET_MODE_BITSIZE (move_mode) > 128)
+ move_mode = TImode;
+
/* Find the corresponding vector mode with the same size as MOVE_MODE.
MOVE_MODE is an integer mode at the moment (SI, DI, TI, etc.). */
if (GET_MODE_SIZE (move_mode) > GET_MODE_SIZE (word_mode))
@@ -29830,8 +28195,8 @@ ix86_get_modrm_for_rop (rtx_insn *insn, rtx *operands, int noperands,
/* Check whether x86 address PARTS is a pc-relative address. */
-static bool
-rip_relative_addr_p (struct ix86_address *parts)
+bool
+ix86_rip_relative_addr_p (struct ix86_address *parts)
{
rtx base, index, disp;
@@ -29935,7 +28300,7 @@ memory_address_length (rtx addr, bool lea)
else if (disp && !base && !index)
{
len += 4;
- if (!rip_relative_addr_p (&parts))
+ if (!ix86_rip_relative_addr_p (&parts))
len++;
}
else
@@ -30117,801 +28482,6 @@ ix86_attr_length_vex_default (rtx_insn *insn, bool has_0f_opcode,
return 2 + 1;
}
-/* Return the maximum number of instructions a cpu can issue. */
-
-static int
-ix86_issue_rate (void)
-{
- switch (ix86_tune)
- {
- case PROCESSOR_PENTIUM:
- case PROCESSOR_LAKEMONT:
- case PROCESSOR_BONNELL:
- case PROCESSOR_SILVERMONT:
- case PROCESSOR_KNL:
- case PROCESSOR_INTEL:
- case PROCESSOR_K6:
- case PROCESSOR_BTVER2:
- case PROCESSOR_PENTIUM4:
- case PROCESSOR_NOCONA:
- return 2;
-
- case PROCESSOR_PENTIUMPRO:
- case PROCESSOR_ATHLON:
- case PROCESSOR_K8:
- case PROCESSOR_AMDFAM10:
- case PROCESSOR_GENERIC:
- case PROCESSOR_BTVER1:
- return 3;
-
- case PROCESSOR_BDVER1:
- case PROCESSOR_BDVER2:
- case PROCESSOR_BDVER3:
- case PROCESSOR_BDVER4:
- case PROCESSOR_ZNVER1:
- case PROCESSOR_CORE2:
- case PROCESSOR_NEHALEM:
- case PROCESSOR_SANDYBRIDGE:
- case PROCESSOR_HASWELL:
- return 4;
-
- default:
- return 1;
- }
-}
-
-/* A subroutine of ix86_adjust_cost -- return TRUE iff INSN reads flags set
- by DEP_INSN and nothing set by DEP_INSN. */
-
-static bool
-ix86_flags_dependent (rtx_insn *insn, rtx_insn *dep_insn, enum attr_type insn_type)
-{
- rtx set, set2;
-
- /* Simplify the test for uninteresting insns. */
- if (insn_type != TYPE_SETCC
- && insn_type != TYPE_ICMOV
- && insn_type != TYPE_FCMOV
- && insn_type != TYPE_IBR)
- return false;
-
- if ((set = single_set (dep_insn)) != 0)
- {
- set = SET_DEST (set);
- set2 = NULL_RTX;
- }
- else if (GET_CODE (PATTERN (dep_insn)) == PARALLEL
- && XVECLEN (PATTERN (dep_insn), 0) == 2
- && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 0)) == SET
- && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 1)) == SET)
- {
- set = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
- set2 = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
- }
- else
- return false;
-
- if (!REG_P (set) || REGNO (set) != FLAGS_REG)
- return false;
-
- /* This test is true if the dependent insn reads the flags but
- not any other potentially set register. */
- if (!reg_overlap_mentioned_p (set, PATTERN (insn)))
- return false;
-
- if (set2 && reg_overlap_mentioned_p (set2, PATTERN (insn)))
- return false;
-
- return true;
-}
-
-/* Return true iff USE_INSN has a memory address with operands set by
- SET_INSN. */
-
-bool
-ix86_agi_dependent (rtx_insn *set_insn, rtx_insn *use_insn)
-{
- int i;
- extract_insn_cached (use_insn);
- for (i = recog_data.n_operands - 1; i >= 0; --i)
- if (MEM_P (recog_data.operand[i]))
- {
- rtx addr = XEXP (recog_data.operand[i], 0);
- if (modified_in_p (addr, set_insn) != 0)
- {
- /* No AGI stall if SET_INSN is a push or pop and USE_INSN
- has SP based memory (unless index reg is modified in a pop). */
- rtx set = single_set (set_insn);
- if (set
- && (push_operand (SET_DEST (set), GET_MODE (SET_DEST (set)))
- || pop_operand (SET_SRC (set), GET_MODE (SET_SRC (set)))))
- {
- struct ix86_address parts;
- if (ix86_decompose_address (addr, &parts)
- && parts.base == stack_pointer_rtx
- && (parts.index == NULL_RTX
- || MEM_P (SET_DEST (set))
- || !modified_in_p (parts.index, set_insn)))
- return false;
- }
- return true;
- }
- return false;
- }
- return false;
-}
-
-/* Helper function for exact_store_load_dependency.
- Return true if addr is found in insn. */
-static bool
-exact_dependency_1 (rtx addr, rtx insn)
-{
- enum rtx_code code;
- const char *format_ptr;
- int i, j;
-
- code = GET_CODE (insn);
- switch (code)
- {
- case MEM:
- if (rtx_equal_p (addr, insn))
- return true;
- break;
- case REG:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case CODE_LABEL:
- case PC:
- case CC0:
- case EXPR_LIST:
- return false;
- default:
- break;
- }
-
- format_ptr = GET_RTX_FORMAT (code);
- for (i = 0; i < GET_RTX_LENGTH (code); i++)
- {
- switch (*format_ptr++)
- {
- case 'e':
- if (exact_dependency_1 (addr, XEXP (insn, i)))
- return true;
- break;
- case 'E':
- for (j = 0; j < XVECLEN (insn, i); j++)
- if (exact_dependency_1 (addr, XVECEXP (insn, i, j)))
- return true;
- break;
- }
- }
- return false;
-}
-
-/* Return true if there exists exact dependency for store & load, i.e.
- the same memory address is used in them. */
-static bool
-exact_store_load_dependency (rtx_insn *store, rtx_insn *load)
-{
- rtx set1, set2;
-
- set1 = single_set (store);
- if (!set1)
- return false;
- if (!MEM_P (SET_DEST (set1)))
- return false;
- set2 = single_set (load);
- if (!set2)
- return false;
- if (exact_dependency_1 (SET_DEST (set1), SET_SRC (set2)))
- return true;
- return false;
-}
-
-static int
-ix86_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
- unsigned int)
-{
- enum attr_type insn_type, dep_insn_type;
- enum attr_memory memory;
- rtx set, set2;
- int dep_insn_code_number;
-
- /* Anti and output dependencies have zero cost on all CPUs. */
- if (dep_type != 0)
- return 0;
-
- dep_insn_code_number = recog_memoized (dep_insn);
-
- /* If we can't recognize the insns, we can't really do anything. */
- if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
- return cost;
-
- insn_type = get_attr_type (insn);
- dep_insn_type = get_attr_type (dep_insn);
-
- switch (ix86_tune)
- {
- case PROCESSOR_PENTIUM:
- case PROCESSOR_LAKEMONT:
- /* Address Generation Interlock adds a cycle of latency. */
- if (insn_type == TYPE_LEA)
- {
- rtx addr = PATTERN (insn);
-
- if (GET_CODE (addr) == PARALLEL)
- addr = XVECEXP (addr, 0, 0);
-
- gcc_assert (GET_CODE (addr) == SET);
-
- addr = SET_SRC (addr);
- if (modified_in_p (addr, dep_insn))
- cost += 1;
- }
- else if (ix86_agi_dependent (dep_insn, insn))
- cost += 1;
-
- /* ??? Compares pair with jump/setcc. */
- if (ix86_flags_dependent (insn, dep_insn, insn_type))
- cost = 0;
-
- /* Floating point stores require value to be ready one cycle earlier. */
- if (insn_type == TYPE_FMOV
- && get_attr_memory (insn) == MEMORY_STORE
- && !ix86_agi_dependent (dep_insn, insn))
- cost += 1;
- break;
-
- case PROCESSOR_PENTIUMPRO:
- /* INT->FP conversion is expensive. */
- if (get_attr_fp_int_src (dep_insn))
- cost += 5;
-
- /* There is one cycle extra latency between an FP op and a store. */
- if (insn_type == TYPE_FMOV
- && (set = single_set (dep_insn)) != NULL_RTX
- && (set2 = single_set (insn)) != NULL_RTX
- && rtx_equal_p (SET_DEST (set), SET_SRC (set2))
- && MEM_P (SET_DEST (set2)))
- cost += 1;
-
- memory = get_attr_memory (insn);
-
- /* Show ability of reorder buffer to hide latency of load by executing
- in parallel with previous instruction in case
- previous instruction is not needed to compute the address. */
- if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
- && !ix86_agi_dependent (dep_insn, insn))
- {
- /* Claim moves to take one cycle, as core can issue one load
- at time and the next load can start cycle later. */
- if (dep_insn_type == TYPE_IMOV
- || dep_insn_type == TYPE_FMOV)
- cost = 1;
- else if (cost > 1)
- cost--;
- }
- break;
-
- case PROCESSOR_K6:
- /* The esp dependency is resolved before
- the instruction is really finished. */
- if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
- && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
- return 1;
-
- /* INT->FP conversion is expensive. */
- if (get_attr_fp_int_src (dep_insn))
- cost += 5;
-
- memory = get_attr_memory (insn);
-
- /* Show ability of reorder buffer to hide latency of load by executing
- in parallel with previous instruction in case
- previous instruction is not needed to compute the address. */
- if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
- && !ix86_agi_dependent (dep_insn, insn))
- {
- /* Claim moves to take one cycle, as core can issue one load
- at time and the next load can start cycle later. */
- if (dep_insn_type == TYPE_IMOV
- || dep_insn_type == TYPE_FMOV)
- cost = 1;
- else if (cost > 2)
- cost -= 2;
- else
- cost = 1;
- }
- break;
-
- case PROCESSOR_AMDFAM10:
- case PROCESSOR_BDVER1:
- case PROCESSOR_BDVER2:
- case PROCESSOR_BDVER3:
- case PROCESSOR_BDVER4:
- case PROCESSOR_ZNVER1:
- case PROCESSOR_BTVER1:
- case PROCESSOR_BTVER2:
- case PROCESSOR_GENERIC:
- /* Stack engine allows to execute push&pop instructions in parall. */
- if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
- && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
- return 0;
- /* FALLTHRU */
-
- case PROCESSOR_ATHLON:
- case PROCESSOR_K8:
- memory = get_attr_memory (insn);
-
- /* Show ability of reorder buffer to hide latency of load by executing
- in parallel with previous instruction in case
- previous instruction is not needed to compute the address. */
- if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
- && !ix86_agi_dependent (dep_insn, insn))
- {
- enum attr_unit unit = get_attr_unit (insn);
- int loadcost = 3;
-
- /* Because of the difference between the length of integer and
- floating unit pipeline preparation stages, the memory operands
- for floating point are cheaper.
-
- ??? For Athlon it the difference is most probably 2. */
- if (unit == UNIT_INTEGER || unit == UNIT_UNKNOWN)
- loadcost = 3;
- else
- loadcost = TARGET_ATHLON ? 2 : 0;
-
- if (cost >= loadcost)
- cost -= loadcost;
- else
- cost = 0;
- }
- break;
-
- case PROCESSOR_CORE2:
- case PROCESSOR_NEHALEM:
- case PROCESSOR_SANDYBRIDGE:
- case PROCESSOR_HASWELL:
- /* Stack engine allows to execute push&pop instructions in parall. */
- if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
- && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
- return 0;
-
- memory = get_attr_memory (insn);
-
- /* Show ability of reorder buffer to hide latency of load by executing
- in parallel with previous instruction in case
- previous instruction is not needed to compute the address. */
- if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
- && !ix86_agi_dependent (dep_insn, insn))
- {
- if (cost >= 4)
- cost -= 4;
- else
- cost = 0;
- }
- break;
-
- case PROCESSOR_SILVERMONT:
- case PROCESSOR_KNL:
- case PROCESSOR_INTEL:
- if (!reload_completed)
- return cost;
-
- /* Increase cost of integer loads. */
- memory = get_attr_memory (dep_insn);
- if (memory == MEMORY_LOAD || memory == MEMORY_BOTH)
- {
- enum attr_unit unit = get_attr_unit (dep_insn);
- if (unit == UNIT_INTEGER && cost == 1)
- {
- if (memory == MEMORY_LOAD)
- cost = 3;
- else
- {
- /* Increase cost of ld/st for short int types only
- because of store forwarding issue. */
- rtx set = single_set (dep_insn);
- if (set && (GET_MODE (SET_DEST (set)) == QImode
- || GET_MODE (SET_DEST (set)) == HImode))
- {
- /* Increase cost of store/load insn if exact
- dependence exists and it is load insn. */
- enum attr_memory insn_memory = get_attr_memory (insn);
- if (insn_memory == MEMORY_LOAD
- && exact_store_load_dependency (dep_insn, insn))
- cost = 3;
- }
- }
- }
- }
-
- default:
- break;
- }
-
- return cost;
-}
-
-/* How many alternative schedules to try. This should be as wide as the
- scheduling freedom in the DFA, but no wider. Making this value too
- large results extra work for the scheduler. */
-
-static int
-ia32_multipass_dfa_lookahead (void)
-{
- switch (ix86_tune)
- {
- case PROCESSOR_PENTIUM:
- case PROCESSOR_LAKEMONT:
- return 2;
-
- case PROCESSOR_PENTIUMPRO:
- case PROCESSOR_K6:
- return 1;
-
- case PROCESSOR_BDVER1:
- case PROCESSOR_BDVER2:
- case PROCESSOR_BDVER3:
- case PROCESSOR_BDVER4:
- /* We use lookahead value 4 for BD both before and after reload
- schedules. Plan is to have value 8 included for O3. */
- return 4;
-
- case PROCESSOR_CORE2:
- case PROCESSOR_NEHALEM:
- case PROCESSOR_SANDYBRIDGE:
- case PROCESSOR_HASWELL:
- case PROCESSOR_BONNELL:
- case PROCESSOR_SILVERMONT:
- case PROCESSOR_KNL:
- case PROCESSOR_INTEL:
- /* Generally, we want haifa-sched:max_issue() to look ahead as far
- as many instructions can be executed on a cycle, i.e.,
- issue_rate. I wonder why tuning for many CPUs does not do this. */
- if (reload_completed)
- return ix86_issue_rate ();
- /* Don't use lookahead for pre-reload schedule to save compile time. */
- return 0;
-
- default:
- return 0;
- }
-}
-
-/* Return true if target platform supports macro-fusion. */
-
-static bool
-ix86_macro_fusion_p ()
-{
- return TARGET_FUSE_CMP_AND_BRANCH;
-}
-
-/* Check whether current microarchitecture support macro fusion
- for insn pair "CONDGEN + CONDJMP". Refer to
- "Intel Architectures Optimization Reference Manual". */
-
-static bool
-ix86_macro_fusion_pair_p (rtx_insn *condgen, rtx_insn *condjmp)
-{
- rtx src, dest;
- enum rtx_code ccode;
- rtx compare_set = NULL_RTX, test_if, cond;
- rtx alu_set = NULL_RTX, addr = NULL_RTX;
-
- if (!any_condjump_p (condjmp))
- return false;
-
- unsigned int condreg1, condreg2;
- rtx cc_reg_1;
- ix86_fixed_condition_code_regs (&condreg1, &condreg2);
- cc_reg_1 = gen_rtx_REG (CCmode, condreg1);
- if (!reg_referenced_p (cc_reg_1, PATTERN (condjmp))
- || !condgen
- || !modified_in_p (cc_reg_1, condgen))
- return false;
-
- if (get_attr_type (condgen) != TYPE_TEST
- && get_attr_type (condgen) != TYPE_ICMP
- && get_attr_type (condgen) != TYPE_INCDEC
- && get_attr_type (condgen) != TYPE_ALU)
- return false;
-
- compare_set = single_set (condgen);
- if (compare_set == NULL_RTX
- && !TARGET_FUSE_ALU_AND_BRANCH)
- return false;
-
- if (compare_set == NULL_RTX)
- {
- int i;
- rtx pat = PATTERN (condgen);
- for (i = 0; i < XVECLEN (pat, 0); i++)
- if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
- {
- rtx set_src = SET_SRC (XVECEXP (pat, 0, i));
- if (GET_CODE (set_src) == COMPARE)
- compare_set = XVECEXP (pat, 0, i);
- else
- alu_set = XVECEXP (pat, 0, i);
- }
- }
- if (compare_set == NULL_RTX)
- return false;
- src = SET_SRC (compare_set);
- if (GET_CODE (src) != COMPARE)
- return false;
-
- /* Macro-fusion for cmp/test MEM-IMM + conditional jmp is not
- supported. */
- if ((MEM_P (XEXP (src, 0))
- && CONST_INT_P (XEXP (src, 1)))
- || (MEM_P (XEXP (src, 1))
- && CONST_INT_P (XEXP (src, 0))))
- return false;
-
- /* No fusion for RIP-relative address. */
- if (MEM_P (XEXP (src, 0)))
- addr = XEXP (XEXP (src, 0), 0);
- else if (MEM_P (XEXP (src, 1)))
- addr = XEXP (XEXP (src, 1), 0);
-
- if (addr) {
- ix86_address parts;
- int ok = ix86_decompose_address (addr, &parts);
- gcc_assert (ok);
-
- if (rip_relative_addr_p (&parts))
- return false;
- }
-
- test_if = SET_SRC (pc_set (condjmp));
- cond = XEXP (test_if, 0);
- ccode = GET_CODE (cond);
- /* Check whether conditional jump use Sign or Overflow Flags. */
- if (!TARGET_FUSE_CMP_AND_BRANCH_SOFLAGS
- && (ccode == GE
- || ccode == GT
- || ccode == LE
- || ccode == LT))
- return false;
-
- /* Return true for TYPE_TEST and TYPE_ICMP. */
- if (get_attr_type (condgen) == TYPE_TEST
- || get_attr_type (condgen) == TYPE_ICMP)
- return true;
-
- /* The following is the case that macro-fusion for alu + jmp. */
- if (!TARGET_FUSE_ALU_AND_BRANCH || !alu_set)
- return false;
-
- /* No fusion for alu op with memory destination operand. */
- dest = SET_DEST (alu_set);
- if (MEM_P (dest))
- return false;
-
- /* Macro-fusion for inc/dec + unsigned conditional jump is not
- supported. */
- if (get_attr_type (condgen) == TYPE_INCDEC
- && (ccode == GEU
- || ccode == GTU
- || ccode == LEU
- || ccode == LTU))
- return false;
-
- return true;
-}
-
-/* Try to reorder ready list to take advantage of Atom pipelined IMUL
- execution. It is applied if
- (1) IMUL instruction is on the top of list;
- (2) There exists the only producer of independent IMUL instruction in
- ready list.
- Return index of IMUL producer if it was found and -1 otherwise. */
-static int
-do_reorder_for_imul (rtx_insn **ready, int n_ready)
-{
- rtx_insn *insn;
- rtx set, insn1, insn2;
- sd_iterator_def sd_it;
- dep_t dep;
- int index = -1;
- int i;
-
- if (!TARGET_BONNELL)
- return index;
-
- /* Check that IMUL instruction is on the top of ready list. */
- insn = ready[n_ready - 1];
- set = single_set (insn);
- if (!set)
- return index;
- if (!(GET_CODE (SET_SRC (set)) == MULT
- && GET_MODE (SET_SRC (set)) == SImode))
- return index;
-
- /* Search for producer of independent IMUL instruction. */
- for (i = n_ready - 2; i >= 0; i--)
- {
- insn = ready[i];
- if (!NONDEBUG_INSN_P (insn))
- continue;
- /* Skip IMUL instruction. */
- insn2 = PATTERN (insn);
- if (GET_CODE (insn2) == PARALLEL)
- insn2 = XVECEXP (insn2, 0, 0);
- if (GET_CODE (insn2) == SET
- && GET_CODE (SET_SRC (insn2)) == MULT
- && GET_MODE (SET_SRC (insn2)) == SImode)
- continue;
-
- FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
- {
- rtx con;
- con = DEP_CON (dep);
- if (!NONDEBUG_INSN_P (con))
- continue;
- insn1 = PATTERN (con);
- if (GET_CODE (insn1) == PARALLEL)
- insn1 = XVECEXP (insn1, 0, 0);
-
- if (GET_CODE (insn1) == SET
- && GET_CODE (SET_SRC (insn1)) == MULT
- && GET_MODE (SET_SRC (insn1)) == SImode)
- {
- sd_iterator_def sd_it1;
- dep_t dep1;
- /* Check if there is no other dependee for IMUL. */
- index = i;
- FOR_EACH_DEP (con, SD_LIST_BACK, sd_it1, dep1)
- {
- rtx pro;
- pro = DEP_PRO (dep1);
- if (!NONDEBUG_INSN_P (pro))
- continue;
- if (pro != insn)
- index = -1;
- }
- if (index >= 0)
- break;
- }
- }
- if (index >= 0)
- break;
- }
- return index;
-}
-
-/* Try to find the best candidate on the top of ready list if two insns
- have the same priority - candidate is best if its dependees were
- scheduled earlier. Applied for Silvermont only.
- Return true if top 2 insns must be interchanged. */
-static bool
-swap_top_of_ready_list (rtx_insn **ready, int n_ready)
-{
- rtx_insn *top = ready[n_ready - 1];
- rtx_insn *next = ready[n_ready - 2];
- rtx set;
- sd_iterator_def sd_it;
- dep_t dep;
- int clock1 = -1;
- int clock2 = -1;
- #define INSN_TICK(INSN) (HID (INSN)->tick)
-
- if (!TARGET_SILVERMONT && !TARGET_INTEL)
- return false;
-
- if (!NONDEBUG_INSN_P (top))
- return false;
- if (!NONJUMP_INSN_P (top))
- return false;
- if (!NONDEBUG_INSN_P (next))
- return false;
- if (!NONJUMP_INSN_P (next))
- return false;
- set = single_set (top);
- if (!set)
- return false;
- set = single_set (next);
- if (!set)
- return false;
-
- if (INSN_PRIORITY_KNOWN (top) && INSN_PRIORITY_KNOWN (next))
- {
- if (INSN_PRIORITY (top) != INSN_PRIORITY (next))
- return false;
- /* Determine winner more precise. */
- FOR_EACH_DEP (top, SD_LIST_RES_BACK, sd_it, dep)
- {
- rtx pro;
- pro = DEP_PRO (dep);
- if (!NONDEBUG_INSN_P (pro))
- continue;
- if (INSN_TICK (pro) > clock1)
- clock1 = INSN_TICK (pro);
- }
- FOR_EACH_DEP (next, SD_LIST_RES_BACK, sd_it, dep)
- {
- rtx pro;
- pro = DEP_PRO (dep);
- if (!NONDEBUG_INSN_P (pro))
- continue;
- if (INSN_TICK (pro) > clock2)
- clock2 = INSN_TICK (pro);
- }
-
- if (clock1 == clock2)
- {
- /* Determine winner - load must win. */
- enum attr_memory memory1, memory2;
- memory1 = get_attr_memory (top);
- memory2 = get_attr_memory (next);
- if (memory2 == MEMORY_LOAD && memory1 != MEMORY_LOAD)
- return true;
- }
- return (bool) (clock2 < clock1);
- }
- return false;
- #undef INSN_TICK
-}
-
-/* Perform possible reodering of ready list for Atom/Silvermont only.
- Return issue rate. */
-static int
-ix86_sched_reorder (FILE *dump, int sched_verbose, rtx_insn **ready,
- int *pn_ready, int clock_var)
-{
- int issue_rate = -1;
- int n_ready = *pn_ready;
- int i;
- rtx_insn *insn;
- int index = -1;
-
- /* Set up issue rate. */
- issue_rate = ix86_issue_rate ();
-
- /* Do reodering for BONNELL/SILVERMONT only. */
- if (!TARGET_BONNELL && !TARGET_SILVERMONT && !TARGET_INTEL)
- return issue_rate;
-
- /* Nothing to do if ready list contains only 1 instruction. */
- if (n_ready <= 1)
- return issue_rate;
-
- /* Do reodering for post-reload scheduler only. */
- if (!reload_completed)
- return issue_rate;
-
- if ((index = do_reorder_for_imul (ready, n_ready)) >= 0)
- {
- if (sched_verbose > 1)
- fprintf (dump, ";;\tatom sched_reorder: put %d insn on top\n",
- INSN_UID (ready[index]));
-
- /* Put IMUL producer (ready[index]) at the top of ready list. */
- insn = ready[index];
- for (i = index; i < n_ready - 1; i++)
- ready[i] = ready[i + 1];
- ready[n_ready - 1] = insn;
- return issue_rate;
- }
-
- /* Skip selective scheduling since HID is not populated in it. */
- if (clock_var != 0
- && !sel_sched_p ()
- && swap_top_of_ready_list (ready, n_ready))
- {
- if (sched_verbose > 1)
- fprintf (dump, ";;\tslm sched_reorder: swap %d and %d insns\n",
- INSN_UID (ready[n_ready - 1]), INSN_UID (ready[n_ready - 2]));
- /* Swap 2 top elements of ready list. */
- insn = ready[n_ready - 1];
- ready[n_ready - 1] = ready[n_ready - 2];
- ready[n_ready - 2] = insn;
- }
- return issue_rate;
-}
static bool
ix86_class_likely_spilled_p (reg_class_t);
@@ -31137,204 +28707,6 @@ ix86_adjust_priority (rtx_insn *insn, int priority)
return priority;
}
-/* Model decoder of Core 2/i7.
- Below hooks for multipass scheduling (see haifa-sched.c:max_issue)
- track the instruction fetch block boundaries and make sure that long
- (9+ bytes) instructions are assigned to D0. */
-
-/* Maximum length of an insn that can be handled by
- a secondary decoder unit. '8' for Core 2/i7. */
-static int core2i7_secondary_decoder_max_insn_size;
-
-/* Ifetch block size, i.e., number of bytes decoder reads per cycle.
- '16' for Core 2/i7. */
-static int core2i7_ifetch_block_size;
-
-/* Maximum number of instructions decoder can handle per cycle.
- '6' for Core 2/i7. */
-static int core2i7_ifetch_block_max_insns;
-
-typedef struct ix86_first_cycle_multipass_data_ *
- ix86_first_cycle_multipass_data_t;
-typedef const struct ix86_first_cycle_multipass_data_ *
- const_ix86_first_cycle_multipass_data_t;
-
-/* A variable to store target state across calls to max_issue within
- one cycle. */
-static struct ix86_first_cycle_multipass_data_ _ix86_first_cycle_multipass_data,
- *ix86_first_cycle_multipass_data = &_ix86_first_cycle_multipass_data;
-
-/* Initialize DATA. */
-static void
-core2i7_first_cycle_multipass_init (void *_data)
-{
- ix86_first_cycle_multipass_data_t data
- = (ix86_first_cycle_multipass_data_t) _data;
-
- data->ifetch_block_len = 0;
- data->ifetch_block_n_insns = 0;
- data->ready_try_change = NULL;
- data->ready_try_change_size = 0;
-}
-
-/* Advancing the cycle; reset ifetch block counts. */
-static void
-core2i7_dfa_post_advance_cycle (void)
-{
- ix86_first_cycle_multipass_data_t data = ix86_first_cycle_multipass_data;
-
- gcc_assert (data->ifetch_block_n_insns <= core2i7_ifetch_block_max_insns);
-
- data->ifetch_block_len = 0;
- data->ifetch_block_n_insns = 0;
-}
-
-static int min_insn_size (rtx_insn *);
-
-/* Filter out insns from ready_try that the core will not be able to issue
- on current cycle due to decoder. */
-static void
-core2i7_first_cycle_multipass_filter_ready_try
-(const_ix86_first_cycle_multipass_data_t data,
- signed char *ready_try, int n_ready, bool first_cycle_insn_p)
-{
- while (n_ready--)
- {
- rtx_insn *insn;
- int insn_size;
-
- if (ready_try[n_ready])
- continue;
-
- insn = get_ready_element (n_ready);
- insn_size = min_insn_size (insn);
-
- if (/* If this is a too long an insn for a secondary decoder ... */
- (!first_cycle_insn_p
- && insn_size > core2i7_secondary_decoder_max_insn_size)
- /* ... or it would not fit into the ifetch block ... */
- || data->ifetch_block_len + insn_size > core2i7_ifetch_block_size
- /* ... or the decoder is full already ... */
- || data->ifetch_block_n_insns + 1 > core2i7_ifetch_block_max_insns)
- /* ... mask the insn out. */
- {
- ready_try[n_ready] = 1;
-
- if (data->ready_try_change)
- bitmap_set_bit (data->ready_try_change, n_ready);
- }
- }
-}
-
-/* Prepare for a new round of multipass lookahead scheduling. */
-static void
-core2i7_first_cycle_multipass_begin (void *_data,
- signed char *ready_try, int n_ready,
- bool first_cycle_insn_p)
-{
- ix86_first_cycle_multipass_data_t data
- = (ix86_first_cycle_multipass_data_t) _data;
- const_ix86_first_cycle_multipass_data_t prev_data
- = ix86_first_cycle_multipass_data;
-
- /* Restore the state from the end of the previous round. */
- data->ifetch_block_len = prev_data->ifetch_block_len;
- data->ifetch_block_n_insns = prev_data->ifetch_block_n_insns;
-
- /* Filter instructions that cannot be issued on current cycle due to
- decoder restrictions. */
- core2i7_first_cycle_multipass_filter_ready_try (data, ready_try, n_ready,
- first_cycle_insn_p);
-}
-
-/* INSN is being issued in current solution. Account for its impact on
- the decoder model. */
-static void
-core2i7_first_cycle_multipass_issue (void *_data,
- signed char *ready_try, int n_ready,
- rtx_insn *insn, const void *_prev_data)
-{
- ix86_first_cycle_multipass_data_t data
- = (ix86_first_cycle_multipass_data_t) _data;
- const_ix86_first_cycle_multipass_data_t prev_data
- = (const_ix86_first_cycle_multipass_data_t) _prev_data;
-
- int insn_size = min_insn_size (insn);
-
- data->ifetch_block_len = prev_data->ifetch_block_len + insn_size;
- data->ifetch_block_n_insns = prev_data->ifetch_block_n_insns + 1;
- gcc_assert (data->ifetch_block_len <= core2i7_ifetch_block_size
- && data->ifetch_block_n_insns <= core2i7_ifetch_block_max_insns);
-
- /* Allocate or resize the bitmap for storing INSN's effect on ready_try. */
- if (!data->ready_try_change)
- {
- data->ready_try_change = sbitmap_alloc (n_ready);
- data->ready_try_change_size = n_ready;
- }
- else if (data->ready_try_change_size < n_ready)
- {
- data->ready_try_change = sbitmap_resize (data->ready_try_change,
- n_ready, 0);
- data->ready_try_change_size = n_ready;
- }
- bitmap_clear (data->ready_try_change);
-
- /* Filter out insns from ready_try that the core will not be able to issue
- on current cycle due to decoder. */
- core2i7_first_cycle_multipass_filter_ready_try (data, ready_try, n_ready,
- false);
-}
-
-/* Revert the effect on ready_try. */
-static void
-core2i7_first_cycle_multipass_backtrack (const void *_data,
- signed char *ready_try,
- int n_ready ATTRIBUTE_UNUSED)
-{
- const_ix86_first_cycle_multipass_data_t data
- = (const_ix86_first_cycle_multipass_data_t) _data;
- unsigned int i = 0;
- sbitmap_iterator sbi;
-
- gcc_assert (bitmap_last_set_bit (data->ready_try_change) < n_ready);
- EXECUTE_IF_SET_IN_BITMAP (data->ready_try_change, 0, i, sbi)
- {
- ready_try[i] = 0;
- }
-}
-
-/* Save the result of multipass lookahead scheduling for the next round. */
-static void
-core2i7_first_cycle_multipass_end (const void *_data)
-{
- const_ix86_first_cycle_multipass_data_t data
- = (const_ix86_first_cycle_multipass_data_t) _data;
- ix86_first_cycle_multipass_data_t next_data
- = ix86_first_cycle_multipass_data;
-
- if (data != NULL)
- {
- next_data->ifetch_block_len = data->ifetch_block_len;
- next_data->ifetch_block_n_insns = data->ifetch_block_n_insns;
- }
-}
-
-/* Deallocate target data. */
-static void
-core2i7_first_cycle_multipass_fini (void *_data)
-{
- ix86_first_cycle_multipass_data_t data
- = (ix86_first_cycle_multipass_data_t) _data;
-
- if (data->ready_try_change)
- {
- sbitmap_free (data->ready_try_change);
- data->ready_try_change = NULL;
- data->ready_try_change_size = 0;
- }
-}
-
/* Prepare for scheduling pass. */
static void
ix86_sched_init_global (FILE *, int, int)
@@ -31352,25 +28724,7 @@ ix86_sched_init_global (FILE *, int, int)
to save compile time. */
if (reload_completed)
{
- targetm.sched.dfa_post_advance_cycle
- = core2i7_dfa_post_advance_cycle;
- targetm.sched.first_cycle_multipass_init
- = core2i7_first_cycle_multipass_init;
- targetm.sched.first_cycle_multipass_begin
- = core2i7_first_cycle_multipass_begin;
- targetm.sched.first_cycle_multipass_issue
- = core2i7_first_cycle_multipass_issue;
- targetm.sched.first_cycle_multipass_backtrack
- = core2i7_first_cycle_multipass_backtrack;
- targetm.sched.first_cycle_multipass_end
- = core2i7_first_cycle_multipass_end;
- targetm.sched.first_cycle_multipass_fini
- = core2i7_first_cycle_multipass_fini;
-
- /* Set decoder parameters. */
- core2i7_secondary_decoder_max_insn_size = 8;
- core2i7_ifetch_block_size = 16;
- core2i7_ifetch_block_max_insns = 6;
+ ix86_core2i7_init_hooks ();
break;
}
/* Fall through. */
@@ -31387,14 +28741,10 @@ ix86_sched_init_global (FILE *, int, int)
}
-/* Compute the alignment given to a constant that is being placed in memory.
- EXP is the constant and ALIGN is the alignment that the object would
- ordinarily have.
- The value of this function is used instead of that alignment to align
- the object. */
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
-int
-ix86_constant_alignment (tree exp, int align)
+static HOST_WIDE_INT
+ix86_constant_alignment (const_tree exp, HOST_WIDE_INT align)
{
if (TREE_CODE (exp) == REAL_CST || TREE_CODE (exp) == VECTOR_CST
|| TREE_CODE (exp) == INTEGER_CST)
@@ -31481,12 +28831,12 @@ ix86_data_alignment (tree type, int align, bool opt)
&& TYPE_SIZE (type)
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
{
- if (wi::geu_p (TYPE_SIZE (type), max_align_compat)
+ if (wi::geu_p (wi::to_wide (TYPE_SIZE (type)), max_align_compat)
&& align < max_align_compat)
align = max_align_compat;
- if (wi::geu_p (TYPE_SIZE (type), max_align)
- && align < max_align)
- align = max_align;
+ if (wi::geu_p (wi::to_wide (TYPE_SIZE (type)), max_align)
+ && align < max_align)
+ align = max_align;
}
/* x86-64 ABI requires arrays greater than 16 bytes to be aligned
@@ -31496,7 +28846,7 @@ ix86_data_alignment (tree type, int align, bool opt)
if ((opt ? AGGREGATE_TYPE_P (type) : TREE_CODE (type) == ARRAY_TYPE)
&& TYPE_SIZE (type)
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
- && wi::geu_p (TYPE_SIZE (type), 128)
+ && wi::geu_p (wi::to_wide (TYPE_SIZE (type)), 128)
&& align < 128)
return 128;
}
@@ -31615,7 +28965,7 @@ ix86_local_alignment (tree exp, machine_mode mode,
!= TYPE_MAIN_VARIANT (va_list_type_node)))
&& TYPE_SIZE (type)
&& TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST
- && wi::geu_p (TYPE_SIZE (type), 128)
+ && wi::geu_p (wi::to_wide (TYPE_SIZE (type)), 128)
&& align < 128)
return 128;
}
@@ -32672,8 +30022,12 @@ BDESC_VERIFYS (IX86_BUILTIN__BDESC_MPX_CONST_FIRST,
IX86_BUILTIN__BDESC_MPX_LAST, 1);
BDESC_VERIFYS (IX86_BUILTIN__BDESC_MULTI_ARG_FIRST,
IX86_BUILTIN__BDESC_MPX_CONST_LAST, 1);
-BDESC_VERIFYS (IX86_BUILTIN_MAX,
+BDESC_VERIFYS (IX86_BUILTIN__BDESC_CET_FIRST,
IX86_BUILTIN__BDESC_MULTI_ARG_LAST, 1);
+BDESC_VERIFYS (IX86_BUILTIN__BDESC_CET_NORMAL_FIRST,
+ IX86_BUILTIN__BDESC_CET_LAST, 1);
+BDESC_VERIFYS (IX86_BUILTIN_MAX,
+ IX86_BUILTIN__BDESC_CET_NORMAL_LAST, 1);
/* Set up all the MMX/SSE builtins, even builtins for instructions that are not
in the current target ISA to allow the user to compile particular modules
@@ -32799,7 +30153,9 @@ ix86_init_mmx_sse_builtins (void)
UNSIGNED_FTYPE_VOID, IX86_BUILTIN_STMXCSR);
/* SSE or 3DNow!A */
- def_builtin (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A,
+ def_builtin (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A
+ /* As it uses V4HImode, we have to require -mmmx too. */
+ | OPTION_MASK_ISA_MMX,
"__builtin_ia32_maskmovq", VOID_FTYPE_V8QI_V8QI_PCHAR,
IX86_BUILTIN_MASKMOVQ);
@@ -33237,7 +30593,9 @@ ix86_init_mmx_sse_builtins (void)
def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_vec_ext_v8hi",
HI_FTYPE_V8HI_INT, IX86_BUILTIN_VEC_EXT_V8HI);
- def_builtin_const (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A,
+ def_builtin_const (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A
+ /* As it uses V4HImode, we have to require -mmmx too. */
+ | OPTION_MASK_ISA_MMX,
"__builtin_ia32_vec_ext_v4hi",
HI_FTYPE_V4HI_INT, IX86_BUILTIN_VEC_EXT_V4HI);
@@ -33261,7 +30619,9 @@ ix86_init_mmx_sse_builtins (void)
def_builtin_const (OPTION_MASK_ISA_SSE2, "__builtin_ia32_vec_set_v8hi",
V8HI_FTYPE_V8HI_HI_INT, IX86_BUILTIN_VEC_SET_V8HI);
- def_builtin_const (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A,
+ def_builtin_const (OPTION_MASK_ISA_SSE | OPTION_MASK_ISA_3DNOW_A
+ /* As it uses V4HImode, we have to require -mmmx too. */
+ | OPTION_MASK_ISA_MMX,
"__builtin_ia32_vec_set_v4hi",
V4HI_FTYPE_V4HI_HI_INT, IX86_BUILTIN_VEC_SET_V4HI);
@@ -33334,6 +30694,35 @@ ix86_init_mmx_sse_builtins (void)
BDESC_VERIFYS (IX86_BUILTIN__BDESC_MULTI_ARG_LAST,
IX86_BUILTIN__BDESC_MULTI_ARG_FIRST,
ARRAY_SIZE (bdesc_multi_arg) - 1);
+
+ /* Add CET inrinsics. */
+ for (i = 0, d = bdesc_cet; i < ARRAY_SIZE (bdesc_cet); i++, d++)
+ {
+ BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_CET_FIRST, i);
+ if (d->name == 0)
+ continue;
+
+ ftype = (enum ix86_builtin_func_type) d->flag;
+ def_builtin2 (d->mask, d->name, ftype, d->code);
+ }
+ BDESC_VERIFYS (IX86_BUILTIN__BDESC_CET_LAST,
+ IX86_BUILTIN__BDESC_CET_FIRST,
+ ARRAY_SIZE (bdesc_cet) - 1);
+
+ for (i = 0, d = bdesc_cet_rdssp;
+ i < ARRAY_SIZE (bdesc_cet_rdssp);
+ i++, d++)
+ {
+ BDESC_VERIFY (d->code, IX86_BUILTIN__BDESC_CET_NORMAL_FIRST, i);
+ if (d->name == 0)
+ continue;
+
+ ftype = (enum ix86_builtin_func_type) d->flag;
+ def_builtin2 (d->mask, d->name, ftype, d->code);
+ }
+ BDESC_VERIFYS (IX86_BUILTIN__BDESC_CET_NORMAL_LAST,
+ IX86_BUILTIN__BDESC_CET_NORMAL_FIRST,
+ ARRAY_SIZE (bdesc_cet_rdssp) - 1);
}
static void
@@ -33691,6 +31080,10 @@ get_builtin_code_for_version (tree decl, tree *predicate_list)
arg_str = "knl";
priority = P_PROC_AVX512F;
break;
+ case PROCESSOR_KNM:
+ arg_str = "knm";
+ priority = P_PROC_AVX512F;
+ break;
case PROCESSOR_SILVERMONT:
arg_str = "silvermont";
priority = P_PROC_SSE4_2;
@@ -34374,6 +31767,7 @@ fold_builtin_cpu (tree fndecl, tree *args)
M_AMD_BTVER1,
M_AMD_BTVER2,
M_AMDFAM17H,
+ M_INTEL_KNM,
M_CPU_SUBTYPE_START,
M_INTEL_COREI7_NEHALEM,
M_INTEL_COREI7_WESTMERE,
@@ -34417,6 +31811,7 @@ fold_builtin_cpu (tree fndecl, tree *args)
{"bonnell", M_INTEL_BONNELL},
{"silvermont", M_INTEL_SILVERMONT},
{"knl", M_INTEL_KNL},
+ {"knm", M_INTEL_KNM},
{"amdfam10h", M_AMDFAM10H},
{"barcelona", M_AMDFAM10H_BARCELONA},
{"shanghai", M_AMDFAM10H_SHANGHAI},
@@ -37686,10 +35081,10 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget,
machine_mode mode, int ignore)
{
size_t i;
- enum insn_code icode;
+ enum insn_code icode, icode2;
tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0);
tree arg0, arg1, arg2, arg3, arg4;
- rtx op0, op1, op2, op3, op4, pat, insn;
+ rtx op0, op1, op2, op3, op4, pat, pat2, insn;
machine_mode mode0, mode1, mode2, mode3, mode4;
unsigned int fcode = DECL_FUNCTION_CODE (fndecl);
@@ -37719,18 +35114,23 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget,
Originally the builtin was not created if it wasn't applicable to the
current ISA based on the command line switches. With function specific
options, we need to check in the context of the function making the call
- whether it is supported. Treat AVX512VL specially. For other flags,
+ whether it is supported. Treat AVX512VL and MMX specially. For other flags,
if isa includes more than one ISA bit, treat those are requiring any
of them. For AVX512VL, require both AVX512VL and the non-AVX512VL
- ISAs. Similarly for 64BIT, but we shouldn't be building such builtins
+ ISAs. Likewise for MMX, require both MMX and the non-MMX ISAs.
+ Similarly for 64BIT, but we shouldn't be building such builtins
at all, -m64 is a whole TU option. */
if (((ix86_builtins_isa[fcode].isa
- & ~(OPTION_MASK_ISA_AVX512VL | OPTION_MASK_ISA_64BIT))
+ & ~(OPTION_MASK_ISA_AVX512VL | OPTION_MASK_ISA_MMX
+ | OPTION_MASK_ISA_64BIT))
&& !(ix86_builtins_isa[fcode].isa
- & ~(OPTION_MASK_ISA_AVX512VL | OPTION_MASK_ISA_64BIT)
+ & ~(OPTION_MASK_ISA_AVX512VL | OPTION_MASK_ISA_MMX
+ | OPTION_MASK_ISA_64BIT)
& ix86_isa_flags))
|| ((ix86_builtins_isa[fcode].isa & OPTION_MASK_ISA_AVX512VL)
&& !(ix86_isa_flags & OPTION_MASK_ISA_AVX512VL))
+ || ((ix86_builtins_isa[fcode].isa & OPTION_MASK_ISA_MMX)
+ && !(ix86_isa_flags & OPTION_MASK_ISA_MMX))
|| (ix86_builtins_isa[fcode].isa2
&& !(ix86_builtins_isa[fcode].isa2 & ix86_isa_flags2)))
{
@@ -38659,22 +36059,34 @@ rdseed_step:
case IX86_BUILTIN_SBB32:
icode = CODE_FOR_subborrowsi;
+ icode2 = CODE_FOR_subborrowsi_0;
mode0 = SImode;
+ mode1 = DImode;
+ mode2 = CCmode;
goto handlecarry;
case IX86_BUILTIN_SBB64:
icode = CODE_FOR_subborrowdi;
+ icode2 = CODE_FOR_subborrowdi_0;
mode0 = DImode;
+ mode1 = TImode;
+ mode2 = CCmode;
goto handlecarry;
case IX86_BUILTIN_ADDCARRYX32:
icode = CODE_FOR_addcarrysi;
+ icode2 = CODE_FOR_addcarrysi_0;
mode0 = SImode;
+ mode1 = DImode;
+ mode2 = CCCmode;
goto handlecarry;
case IX86_BUILTIN_ADDCARRYX64:
icode = CODE_FOR_addcarrydi;
+ icode2 = CODE_FOR_addcarrydi_0;
mode0 = DImode;
+ mode1 = TImode;
+ mode2 = CCCmode;
handlecarry:
arg0 = CALL_EXPR_ARG (exp, 0); /* unsigned char c_in. */
@@ -38683,7 +36095,8 @@ rdseed_step:
arg3 = CALL_EXPR_ARG (exp, 3); /* unsigned int *sum_out. */
op1 = expand_normal (arg0);
- op1 = copy_to_mode_reg (QImode, convert_to_mode (QImode, op1, 1));
+ if (!integer_zerop (arg0))
+ op1 = copy_to_mode_reg (QImode, convert_to_mode (QImode, op1, 1));
op2 = expand_normal (arg1);
if (!register_operand (op2, mode0))
@@ -38700,21 +36113,31 @@ rdseed_step:
op4 = copy_addr_to_reg (op4);
}
- /* Generate CF from input operand. */
- emit_insn (gen_addqi3_cconly_overflow (op1, constm1_rtx));
-
- /* Generate instruction that consumes CF. */
op0 = gen_reg_rtx (mode0);
+ if (integer_zerop (arg0))
+ {
+ /* If arg0 is 0, optimize right away into add or sub
+ instruction that sets CCCmode flags. */
+ op1 = gen_rtx_REG (mode2, FLAGS_REG);
+ emit_insn (GEN_FCN (icode2) (op0, op2, op3));
+ }
+ else
+ {
+ /* Generate CF from input operand. */
+ emit_insn (gen_addqi3_cconly_overflow (op1, constm1_rtx));
- op1 = gen_rtx_REG (CCCmode, FLAGS_REG);
- pat = gen_rtx_LTU (mode0, op1, const0_rtx);
- emit_insn (GEN_FCN (icode) (op0, op2, op3, op1, pat));
+ /* Generate instruction that consumes CF. */
+ op1 = gen_rtx_REG (CCCmode, FLAGS_REG);
+ pat = gen_rtx_LTU (mode1, op1, const0_rtx);
+ pat2 = gen_rtx_LTU (mode0, op1, const0_rtx);
+ emit_insn (GEN_FCN (icode) (op0, op2, op3, op1, pat, pat2));
+ }
/* Return current CF value. */
if (target == 0)
target = gen_reg_rtx (QImode);
- PUT_MODE (pat, QImode);
+ pat = gen_rtx_LTU (QImode, op1, const0_rtx);
emit_insn (gen_rtx_SET (target, pat));
/* Store the result. */
@@ -39507,6 +36930,57 @@ rdseed_step:
emit_insn (gen_xabort (op0));
return 0;
+ case IX86_BUILTIN_RSTORSSP:
+ case IX86_BUILTIN_CLRSSBSY:
+ arg0 = CALL_EXPR_ARG (exp, 0);
+ op0 = expand_normal (arg0);
+ icode = (fcode == IX86_BUILTIN_RSTORSSP
+ ? CODE_FOR_rstorssp
+ : CODE_FOR_clrssbsy);
+ if (!address_operand (op0, VOIDmode))
+ {
+ op1 = convert_memory_address (Pmode, op0);
+ op0 = copy_addr_to_reg (op1);
+ }
+ emit_insn (GEN_FCN (icode) (gen_rtx_MEM (Pmode, op0)));
+ return 0;
+
+ case IX86_BUILTIN_WRSSD:
+ case IX86_BUILTIN_WRSSQ:
+ case IX86_BUILTIN_WRUSSD:
+ case IX86_BUILTIN_WRUSSQ:
+ arg0 = CALL_EXPR_ARG (exp, 0);
+ op0 = expand_normal (arg0);
+ arg1 = CALL_EXPR_ARG (exp, 1);
+ op1 = expand_normal (arg1);
+ switch (fcode)
+ {
+ case IX86_BUILTIN_WRSSD:
+ icode = CODE_FOR_wrsssi;
+ mode = SImode;
+ break;
+ case IX86_BUILTIN_WRSSQ:
+ icode = CODE_FOR_wrssdi;
+ mode = DImode;
+ break;
+ case IX86_BUILTIN_WRUSSD:
+ icode = CODE_FOR_wrusssi;
+ mode = SImode;
+ break;
+ case IX86_BUILTIN_WRUSSQ:
+ icode = CODE_FOR_wrussdi;
+ mode = DImode;
+ break;
+ }
+ op0 = force_reg (mode, op0);
+ if (!address_operand (op1, VOIDmode))
+ {
+ op2 = convert_memory_address (Pmode, op1);
+ op1 = copy_addr_to_reg (op2);
+ }
+ emit_insn (GEN_FCN (icode) (op0, gen_rtx_MEM (mode, op1)));
+ return 0;
+
default:
break;
}
@@ -39809,6 +37283,22 @@ s4fma_expand:
d->flag, d->comparison);
}
+ if (fcode >= IX86_BUILTIN__BDESC_CET_FIRST
+ && fcode <= IX86_BUILTIN__BDESC_CET_LAST)
+ {
+ i = fcode - IX86_BUILTIN__BDESC_CET_FIRST;
+ return ix86_expand_special_args_builtin (bdesc_cet + i, exp,
+ target);
+ }
+
+ if (fcode >= IX86_BUILTIN__BDESC_CET_NORMAL_FIRST
+ && fcode <= IX86_BUILTIN__BDESC_CET_NORMAL_LAST)
+ {
+ i = fcode - IX86_BUILTIN__BDESC_CET_NORMAL_FIRST;
+ return ix86_expand_args_builtin (bdesc_cet_rdssp + i, exp,
+ target);
+ }
+
gcc_unreachable ();
}
@@ -41198,6 +38688,28 @@ ix86_can_change_mode_class (machine_mode from, machine_mode to,
return true;
}
+/* Return index of MODE in the sse load/store tables. */
+
+static inline int
+sse_store_index (machine_mode mode)
+{
+ switch (GET_MODE_SIZE (mode))
+ {
+ case 4:
+ return 0;
+ case 8:
+ return 1;
+ case 16:
+ return 2;
+ case 32:
+ return 3;
+ case 64:
+ return 4;
+ default:
+ return -1;
+ }
+}
+
/* Return the cost of moving data of mode M between a
register and memory. A value of 2 is the default; this cost is
relative to those in `REGISTER_MOVE_COST'.
@@ -41241,21 +38753,9 @@ inline_memory_move_cost (machine_mode mode, enum reg_class regclass,
}
if (SSE_CLASS_P (regclass))
{
- int index;
- switch (GET_MODE_SIZE (mode))
- {
- case 4:
- index = 0;
- break;
- case 8:
- index = 1;
- break;
- case 16:
- index = 2;
- break;
- default:
- return 100;
- }
+ int index = sse_store_index (mode);
+ if (index == -1)
+ return 100;
if (in == 2)
return MAX (ix86_cost->sse_load [index], ix86_cost->sse_store [index]);
return in ? ix86_cost->sse_load [index] : ix86_cost->sse_store [index];
@@ -41358,8 +38858,10 @@ ix86_register_move_cost (machine_mode mode, reg_class_t class1_i,
/* In case of copying from general_purpose_register we may emit multiple
stores followed by single load causing memory size mismatch stall.
Count this as arbitrarily high cost of 20. */
- if (targetm.class_max_nregs (class1, mode)
- > targetm.class_max_nregs (class2, mode))
+ if (GET_MODE_BITSIZE (mode) > BITS_PER_WORD
+ && TARGET_MEMORY_MISMATCH_STALL
+ && targetm.class_max_nregs (class1, mode)
+ > targetm.class_max_nregs (class2, mode))
cost += 20;
/* In the case of FP/MMX moves, the registers actually overlap, and we
@@ -41381,12 +38883,19 @@ ix86_register_move_cost (machine_mode mode, reg_class_t class1_i,
where integer modes in MMX/SSE registers are not tieable
because of missing QImode and HImode moves to, from or between
MMX/SSE registers. */
- return MAX (8, ix86_cost->mmxsse_to_integer);
+ return MAX (8, MMX_CLASS_P (class1) || MMX_CLASS_P (class2)
+ ? ix86_cost->mmxsse_to_integer : ix86_cost->ssemmx_to_integer);
if (MAYBE_FLOAT_CLASS_P (class1))
return ix86_cost->fp_move;
if (MAYBE_SSE_CLASS_P (class1))
- return ix86_cost->sse_move;
+ {
+ if (GET_MODE_BITSIZE (mode) <= 128)
+ return ix86_cost->xmm_move;
+ if (GET_MODE_BITSIZE (mode) <= 256)
+ return ix86_cost->ymm_move;
+ return ix86_cost->zmm_move;
+ }
if (MAYBE_MMX_CLASS_P (class1))
return ix86_cost->mmx_move;
return 2;
@@ -41657,6 +39166,27 @@ ix86_set_reg_reg_cost (machine_mode mode)
return COSTS_N_INSNS (CEIL (GET_MODE_SIZE (mode), units));
}
+/* Return cost of vector operation in MODE given that scalar version has
+ COST. If PARALLEL is true assume that CPU has more than one unit
+ performing the operation. */
+
+static int
+ix86_vec_cost (machine_mode mode, int cost, bool parallel)
+{
+ if (!VECTOR_MODE_P (mode))
+ return cost;
+
+ if (!parallel)
+ return cost * GET_MODE_NUNITS (mode);
+ if (GET_MODE_BITSIZE (mode) == 128
+ && TARGET_SSE_SPLIT_REGS)
+ return cost * 2;
+ if (GET_MODE_BITSIZE (mode) > 128
+ && TARGET_AVX128_OPTIMAL)
+ return cost * GET_MODE_BITSIZE (mode) / 128;
+ return cost;
+}
+
/* Compute a (partial) cost for rtx X. Return true if the complete
cost has been computed, and false if subexpressions should be
scanned. In either case, *TOTAL contains the cost result. */
@@ -41670,6 +39200,9 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
enum rtx_code outer_code = (enum rtx_code) outer_code_i;
const struct processor_costs *cost = speed ? ix86_cost : &ix86_size_cost;
int src_cost;
+ machine_mode inner_mode = mode;
+ if (VECTOR_MODE_P (mode))
+ inner_mode = GET_MODE_INNER (mode);
switch (code)
{
@@ -41814,19 +39347,20 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
shift with one insn set the cost to prefer paddb. */
if (CONSTANT_P (XEXP (x, 1)))
{
- *total = (cost->fabs
+ *total = ix86_vec_cost (mode,
+ cost->sse_op
+ rtx_cost (XEXP (x, 0), mode, code, 0, speed)
- + (speed ? 2 : COSTS_N_BYTES (16)));
+ + (speed ? 2 : COSTS_N_BYTES (16)), true);
return true;
}
count = 3;
}
else if (TARGET_SSSE3)
count = 7;
- *total = cost->fabs * count;
+ *total = ix86_vec_cost (mode, cost->sse_op * count, true);
}
else
- *total = cost->fabs;
+ *total = ix86_vec_cost (mode, cost->sse_op, true);
}
else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
{
@@ -41868,9 +39402,9 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
gcc_assert (FLOAT_MODE_P (mode));
gcc_assert (TARGET_FMA || TARGET_FMA4 || TARGET_AVX512F);
- /* ??? SSE scalar/vector cost should be used here. */
- /* ??? Bald assumption that fma has the same cost as fmul. */
- *total = cost->fmul;
+ *total = ix86_vec_cost (mode,
+ mode == SFmode ? cost->fmass : cost->fmasd,
+ true);
*total += rtx_cost (XEXP (x, 1), mode, FMA, 1, speed);
/* Negate in op0 or op2 is free: FMS, FNMA, FNMS. */
@@ -41889,8 +39423,7 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
case MULT:
if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
{
- /* ??? SSE scalar cost should be used here. */
- *total = cost->fmul;
+ *total = inner_mode == DFmode ? cost->mulsd : cost->mulss;
return false;
}
else if (X87_FLOAT_MODE_P (mode))
@@ -41900,8 +39433,9 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
}
else if (FLOAT_MODE_P (mode))
{
- /* ??? SSE vector cost should be used here. */
- *total = cost->fmul;
+ *total = ix86_vec_cost (mode,
+ inner_mode == DFmode
+ ? cost->mulsd : cost->mulss, true);
return false;
}
else if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
@@ -41914,22 +39448,29 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
extra = 5;
else if (TARGET_SSSE3)
extra = 6;
- *total = cost->fmul * 2 + cost->fabs * extra;
+ *total = ix86_vec_cost (mode,
+ cost->mulss * 2 + cost->sse_op * extra,
+ true);
}
/* V*DImode is emulated with 5-8 insns. */
else if (mode == V2DImode || mode == V4DImode)
{
if (TARGET_XOP && mode == V2DImode)
- *total = cost->fmul * 2 + cost->fabs * 3;
+ *total = ix86_vec_cost (mode,
+ cost->mulss * 2 + cost->sse_op * 3,
+ true);
else
- *total = cost->fmul * 3 + cost->fabs * 5;
+ *total = ix86_vec_cost (mode,
+ cost->mulss * 3 + cost->sse_op * 5,
+ true);
}
/* Without sse4.1, we don't have PMULLD; it's emulated with 7
insns, including two PMULUDQ. */
else if (mode == V4SImode && !(TARGET_SSE4_1 || TARGET_AVX))
- *total = cost->fmul * 2 + cost->fabs * 5;
+ *total = ix86_vec_cost (mode, cost->mulss * 2 + cost->sse_op * 5,
+ true);
else
- *total = cost->fmul;
+ *total = ix86_vec_cost (mode, cost->mulss, true);
return false;
}
else
@@ -41983,13 +39524,13 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
case MOD:
case UMOD:
if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
- /* ??? SSE cost should be used here. */
- *total = cost->fdiv;
+ *total = inner_mode == DFmode ? cost->divsd : cost->divss;
else if (X87_FLOAT_MODE_P (mode))
*total = cost->fdiv;
else if (FLOAT_MODE_P (mode))
- /* ??? SSE vector cost should be used here. */
- *total = cost->fdiv;
+ *total = ix86_vec_cost (mode,
+ inner_mode == DFmode ? cost->divsd : cost->divss,
+ true);
else
*total = cost->divide[MODE_INDEX (mode)];
return false;
@@ -42068,8 +39609,7 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
{
- /* ??? SSE cost should be used here. */
- *total = cost->fadd;
+ *total = cost->addss;
return false;
}
else if (X87_FLOAT_MODE_P (mode))
@@ -42079,8 +39619,7 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
}
else if (FLOAT_MODE_P (mode))
{
- /* ??? SSE vector cost should be used here. */
- *total = cost->fadd;
+ *total = ix86_vec_cost (mode, cost->addss, true);
return false;
}
/* FALLTHRU */
@@ -42103,8 +39642,7 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
case NEG:
if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
{
- /* ??? SSE cost should be used here. */
- *total = cost->fchs;
+ *total = cost->sse_op;
return false;
}
else if (X87_FLOAT_MODE_P (mode))
@@ -42114,20 +39652,14 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
}
else if (FLOAT_MODE_P (mode))
{
- /* ??? SSE vector cost should be used here. */
- *total = cost->fchs;
+ *total = ix86_vec_cost (mode, cost->sse_op, true);
return false;
}
/* FALLTHRU */
case NOT:
if (GET_MODE_CLASS (mode) == MODE_VECTOR_INT)
- {
- /* ??? Should be SSE vector operation cost. */
- /* At least for published AMD latencies, this really is the same
- as the latency for a simple fpu operation like fabs. */
- *total = cost->fabs;
- }
+ *total = ix86_vec_cost (mode, cost->sse_op, true);
else if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
*total = cost->add * 2;
else
@@ -42160,28 +39692,38 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
case FLOAT_EXTEND:
if (!(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH))
*total = 0;
+ else
+ *total = ix86_vec_cost (mode, cost->addss, true);
+ return false;
+
+ case FLOAT_TRUNCATE:
+ if (!(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH))
+ *total = cost->fadd;
+ else
+ *total = ix86_vec_cost (mode, cost->addss, true);
return false;
case ABS:
+ /* SSE requires memory load for the constant operand. It may make
+ sense to account for this. Of course the constant operand may or
+ may not be reused. */
if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
- /* ??? SSE cost should be used here. */
- *total = cost->fabs;
+ *total = cost->sse_op;
else if (X87_FLOAT_MODE_P (mode))
*total = cost->fabs;
else if (FLOAT_MODE_P (mode))
- /* ??? SSE vector cost should be used here. */
- *total = cost->fabs;
+ *total = ix86_vec_cost (mode, cost->sse_op, true);
return false;
case SQRT:
if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
- /* ??? SSE cost should be used here. */
- *total = cost->fsqrt;
+ *total = mode == SFmode ? cost->sqrtss : cost->sqrtsd;
else if (X87_FLOAT_MODE_P (mode))
*total = cost->fsqrt;
else if (FLOAT_MODE_P (mode))
- /* ??? SSE vector cost should be used here. */
- *total = cost->fsqrt;
+ *total = ix86_vec_cost (mode,
+ mode == SFmode ? cost->sqrtss : cost->sqrtsd,
+ true);
return false;
case UNSPEC:
@@ -42195,7 +39737,7 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
/* ??? Assume all of these vector manipulation patterns are
recognizable. In which case they all pretty much have the
same cost. */
- *total = cost->fabs;
+ *total = cost->sse_op;
return true;
case VEC_MERGE:
mask = XEXP (x, 2);
@@ -42204,7 +39746,7 @@ ix86_rtx_costs (rtx x, machine_mode mode, int outer_code_i, int opno,
if (TARGET_AVX512F && register_operand (mask, GET_MODE (mask)))
*total = rtx_cost (XEXP (x, 0), mode, outer_code, opno, speed);
else
- *total = cost->fabs;
+ *total = cost->sse_op;
return true;
default:
@@ -42669,6 +40211,10 @@ x86_output_mi_thunk (FILE *file, tree, HOST_WIDE_INT delta,
emit_note (NOTE_INSN_PROLOGUE_END);
+ /* CET is enabled, insert EB instruction. */
+ if ((flag_cf_protection & CF_BRANCH) && TARGET_IBT)
+ emit_insn (gen_nop_endbr ());
+
/* If VCALL_OFFSET, we'll need THIS in a register. Might as well
pull it in now and let DELTA benefit. */
if (REG_P (this_param))
@@ -42922,8 +40468,8 @@ x86_function_profiler (FILE *file, int labelno ATTRIBUTE_UNUSED)
address sizes. This is enough to eliminate unnecessary padding in
99% of cases. */
-static int
-min_insn_size (rtx_insn *insn)
+int
+ix86_min_insn_size (rtx_insn *insn)
{
int l = 0, len;
@@ -43032,13 +40578,13 @@ ix86_avoid_jump_mispredicts (void)
njumps--, isjump = true;
else
isjump = false;
- nbytes -= min_insn_size (start);
+ nbytes -= ix86_min_insn_size (start);
}
}
continue;
}
- min_size = min_insn_size (insn);
+ min_size = ix86_min_insn_size (insn);
nbytes += min_size;
if (dump_file)
fprintf (dump_file, "Insn %i estimated to %i bytes\n",
@@ -43057,7 +40603,7 @@ ix86_avoid_jump_mispredicts (void)
njumps--, isjump = true;
else
isjump = false;
- nbytes -= min_insn_size (start);
+ nbytes -= ix86_min_insn_size (start);
}
gcc_assert (njumps >= 0);
if (dump_file)
@@ -43066,7 +40612,7 @@ ix86_avoid_jump_mispredicts (void)
if (njumps == 3 && isjump && nbytes < 16)
{
- int padsize = 15 - nbytes + min_insn_size (insn);
+ int padsize = 15 - nbytes + ix86_min_insn_size (insn);
if (dump_file)
fprintf (dump_file, "Padding insn %i by %i bytes!\n",
@@ -46895,35 +44441,69 @@ static int
ix86_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
tree vectype, int)
{
+ bool fp = false;
+ machine_mode mode = TImode;
+ int index;
+ if (vectype != NULL)
+ {
+ fp = FLOAT_TYPE_P (vectype);
+ mode = TYPE_MODE (vectype);
+ }
+
switch (type_of_cost)
{
case scalar_stmt:
- return ix86_cost->scalar_stmt_cost;
+ return fp ? ix86_cost->addss : COSTS_N_INSNS (1);
case scalar_load:
- return ix86_cost->scalar_load_cost;
+ /* load/store costs are relative to register move which is 2. Recompute
+ it to COSTS_N_INSNS so everything have same base. */
+ return COSTS_N_INSNS (fp ? ix86_cost->sse_load[0]
+ : ix86_cost->int_load [2]) / 2;
case scalar_store:
- return ix86_cost->scalar_store_cost;
+ return COSTS_N_INSNS (fp ? ix86_cost->sse_store[0]
+ : ix86_cost->int_store [2]) / 2;
case vector_stmt:
- return ix86_cost->vec_stmt_cost;
+ return ix86_vec_cost (mode,
+ fp ? ix86_cost->addss : ix86_cost->sse_op,
+ true);
case vector_load:
- return ix86_cost->vec_align_load_cost;
+ index = sse_store_index (mode);
+ gcc_assert (index >= 0);
+ return ix86_vec_cost (mode,
+ COSTS_N_INSNS (ix86_cost->sse_load[index]) / 2,
+ true);
case vector_store:
- return ix86_cost->vec_store_cost;
+ index = sse_store_index (mode);
+ return ix86_vec_cost (mode,
+ COSTS_N_INSNS (ix86_cost->sse_store[index]) / 2,
+ true);
case vec_to_scalar:
- return ix86_cost->vec_to_scalar_cost;
-
case scalar_to_vec:
- return ix86_cost->scalar_to_vec_cost;
+ return ix86_vec_cost (mode, ix86_cost->sse_op, true);
+ /* We should have separate costs for unaligned loads and gather/scatter.
+ Do that incrementally. */
case unaligned_load:
+ case vector_gather_load:
+ index = sse_store_index (mode);
+ return ix86_vec_cost (mode,
+ COSTS_N_INSNS
+ (ix86_cost->sse_unaligned_load[index]) / 2,
+ true);
+
case unaligned_store:
- return ix86_cost->vec_unalign_load_cost;
+ case vector_scatter_store:
+ index = sse_store_index (mode);
+ return ix86_vec_cost (mode,
+ COSTS_N_INSNS
+ (ix86_cost->sse_unaligned_store[index]) / 2,
+ true);
case cond_branch_taken:
return ix86_cost->cond_taken_branch_cost;
@@ -46933,10 +44513,11 @@ ix86_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
case vec_perm:
case vec_promote_demote:
- return ix86_cost->vec_stmt_cost;
+ return ix86_vec_cost (mode,
+ ix86_cost->sse_op, true);
case vec_construct:
- return ix86_cost->vec_stmt_cost * (TYPE_VECTOR_SUBPARTS (vectype) - 1);
+ return ix86_vec_cost (mode, ix86_cost->sse_op, false);
default:
gcc_unreachable ();
@@ -47814,8 +45395,8 @@ expand_vec_perm_1 (struct expand_vec_perm_d *d)
if (ix86_expand_vec_one_operand_perm_avx512 (d))
return true;
- /* Try the AVX512F vpermi2 instructions. */
- if (ix86_expand_vec_perm_vpermi2 (NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX, d))
+ /* Try the AVX512F vpermt2/vpermi2 instructions. */
+ if (ix86_expand_vec_perm_vpermt2 (NULL_RTX, NULL_RTX, NULL_RTX, NULL_RTX, d))
return true;
/* See if we can get the same permutation in different vector integer
@@ -49474,9 +47055,9 @@ expand_vec_perm_broadcast (struct expand_vec_perm_d *d)
}
/* Implement arbitrary permutations of two V64QImode operands
- will 2 vpermi2w, 2 vpshufb and one vpor instruction. */
+ with 2 vperm[it]2w, 2 vpshufb and one vpor instruction. */
static bool
-expand_vec_perm_vpermi2_vpshub2 (struct expand_vec_perm_d *d)
+expand_vec_perm_vpermt2_vpshub2 (struct expand_vec_perm_d *d)
{
if (!TARGET_AVX512BW || !(d->vmode == V64QImode))
return false;
@@ -49721,7 +47302,7 @@ ix86_expand_vec_perm_const_1 (struct expand_vec_perm_d *d)
if (expand_vec_perm_vpshufb2_vpermq_even_odd (d))
return true;
- if (expand_vec_perm_vpermi2_vpshub2 (d))
+ if (expand_vec_perm_vpermt2_vpshub2 (d))
return true;
/* ??? Look for narrow permutations whose element orderings would
@@ -49850,8 +47431,7 @@ ix86_expand_vec_perm_const (rtx operands[4])
/* Implement targetm.vectorize.vec_perm_const_ok. */
static bool
-ix86_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel)
+ix86_vectorize_vec_perm_const_ok (machine_mode vmode, vec_perm_indices sel)
{
struct expand_vec_perm_d d;
unsigned int i, nelt, which;
@@ -49870,17 +47450,17 @@ ix86_vectorize_vec_perm_const_ok (machine_mode vmode,
case E_V8DImode:
case E_V8DFmode:
if (TARGET_AVX512F)
- /* All implementable with a single vpermi2 insn. */
+ /* All implementable with a single vperm[it]2 insn. */
return true;
break;
case E_V32HImode:
if (TARGET_AVX512BW)
- /* All implementable with a single vpermi2 insn. */
+ /* All implementable with a single vperm[it]2 insn. */
return true;
break;
case E_V64QImode:
if (TARGET_AVX512BW)
- /* Implementable with 2 vpermi2, 2 vpshufb and 1 or insn. */
+ /* Implementable with 2 vperm[it]2, 2 vpshufb and 1 or insn. */
return true;
break;
case E_V8SImode:
@@ -49888,7 +47468,7 @@ ix86_vectorize_vec_perm_const_ok (machine_mode vmode,
case E_V4DFmode:
case E_V4DImode:
if (TARGET_AVX512VL)
- /* All implementable with a single vpermi2 insn. */
+ /* All implementable with a single vperm[it]2 insn. */
return true;
break;
case E_V16HImode:
@@ -49922,11 +47502,11 @@ ix86_vectorize_vec_perm_const_ok (machine_mode vmode,
/* Extract the values from the vector CST into the permutation
array in D. */
- memcpy (d.perm, sel, nelt);
for (i = which = 0; i < nelt; ++i)
{
- unsigned char e = d.perm[i];
+ unsigned char e = sel[i];
gcc_assert (e < 2 * nelt);
+ d.perm[i] = e;
which |= (e < nelt ? 1 : 2);
}
@@ -50486,6 +48066,46 @@ ix86_bnd_prefixed_insn_p (rtx insn)
return chkp_function_instrumented_p (current_function_decl);
}
+/* Return 1 if control tansfer instruction INSN
+ should be encoded with notrack prefix. */
+
+static bool
+ix86_notrack_prefixed_insn_p (rtx insn)
+{
+ if (!insn || !((flag_cf_protection & CF_BRANCH) && TARGET_IBT))
+ return false;
+
+ if (CALL_P (insn))
+ {
+ rtx call = get_call_rtx_from (insn);
+ gcc_assert (call != NULL_RTX);
+ rtx addr = XEXP (call, 0);
+
+ /* Do not emit 'notrack' if it's not an indirect call. */
+ if (MEM_P (addr)
+ && GET_CODE (XEXP (addr, 0)) == SYMBOL_REF)
+ return false;
+ else
+ return find_reg_note (insn, REG_CALL_NOCF_CHECK, 0);
+ }
+
+ if (JUMP_P (insn) && !flag_cet_switch)
+ {
+ rtx target = JUMP_LABEL (insn);
+ if (target == NULL_RTX || ANY_RETURN_P (target))
+ return false;
+
+ /* Check the jump is a switch table. */
+ rtx_insn *label = as_a<rtx_insn *> (target);
+ rtx_insn *table = next_insn (label);
+ if (table == NULL_RTX || !JUMP_TABLE_DATA_P (table))
+ return false;
+ else
+ return true;
+ }
+ return false;
+}
+
/* Calculate integer abs() using only SSE2 instructions. */
void
@@ -50830,837 +48450,64 @@ ix86_enum_va_list (int idx, const char **pname, tree *ptree)
}
#undef TARGET_SCHED_DISPATCH
-#define TARGET_SCHED_DISPATCH has_dispatch
+#define TARGET_SCHED_DISPATCH ix86_bd_has_dispatch
#undef TARGET_SCHED_DISPATCH_DO
-#define TARGET_SCHED_DISPATCH_DO do_dispatch
+#define TARGET_SCHED_DISPATCH_DO ix86_bd_do_dispatch
#undef TARGET_SCHED_REASSOCIATION_WIDTH
#define TARGET_SCHED_REASSOCIATION_WIDTH ix86_reassociation_width
#undef TARGET_SCHED_REORDER
-#define TARGET_SCHED_REORDER ix86_sched_reorder
+#define TARGET_SCHED_REORDER ix86_atom_sched_reorder
#undef TARGET_SCHED_ADJUST_PRIORITY
#define TARGET_SCHED_ADJUST_PRIORITY ix86_adjust_priority
#undef TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK
#define TARGET_SCHED_DEPENDENCIES_EVALUATION_HOOK \
ix86_dependencies_evaluation_hook
-/* The size of the dispatch window is the total number of bytes of
- object code allowed in a window. */
-#define DISPATCH_WINDOW_SIZE 16
-
-/* Number of dispatch windows considered for scheduling. */
-#define MAX_DISPATCH_WINDOWS 3
-
-/* Maximum number of instructions in a window. */
-#define MAX_INSN 4
-
-/* Maximum number of immediate operands in a window. */
-#define MAX_IMM 4
-
-/* Maximum number of immediate bits allowed in a window. */
-#define MAX_IMM_SIZE 128
-
-/* Maximum number of 32 bit immediates allowed in a window. */
-#define MAX_IMM_32 4
-
-/* Maximum number of 64 bit immediates allowed in a window. */
-#define MAX_IMM_64 2
-
-/* Maximum total of loads or prefetches allowed in a window. */
-#define MAX_LOAD 2
-
-/* Maximum total of stores allowed in a window. */
-#define MAX_STORE 1
-
-#undef BIG
-#define BIG 100
-
-
-/* Dispatch groups. Istructions that affect the mix in a dispatch window. */
-enum dispatch_group {
- disp_no_group = 0,
- disp_load,
- disp_store,
- disp_load_store,
- disp_prefetch,
- disp_imm,
- disp_imm_32,
- disp_imm_64,
- disp_branch,
- disp_cmp,
- disp_jcc,
- disp_last
-};
-
-/* Number of allowable groups in a dispatch window. It is an array
- indexed by dispatch_group enum. 100 is used as a big number,
- because the number of these kind of operations does not have any
- effect in dispatch window, but we need them for other reasons in
- the table. */
-static unsigned int num_allowable_groups[disp_last] = {
- 0, 2, 1, 1, 2, 4, 4, 2, 1, BIG, BIG
-};
-
-char group_name[disp_last + 1][16] = {
- "disp_no_group", "disp_load", "disp_store", "disp_load_store",
- "disp_prefetch", "disp_imm", "disp_imm_32", "disp_imm_64",
- "disp_branch", "disp_cmp", "disp_jcc", "disp_last"
-};
-
-/* Instruction path. */
-enum insn_path {
- no_path = 0,
- path_single, /* Single micro op. */
- path_double, /* Double micro op. */
- path_multi, /* Instructions with more than 2 micro op.. */
- last_path
-};
-
-/* sched_insn_info defines a window to the instructions scheduled in
- the basic block. It contains a pointer to the insn_info table and
- the instruction scheduled.
-
- Windows are allocated for each basic block and are linked
- together. */
-typedef struct sched_insn_info_s {
- rtx insn;
- enum dispatch_group group;
- enum insn_path path;
- int byte_len;
- int imm_bytes;
-} sched_insn_info;
-
-/* Linked list of dispatch windows. This is a two way list of
- dispatch windows of a basic block. It contains information about
- the number of uops in the window and the total number of
- instructions and of bytes in the object code for this dispatch
- window. */
-typedef struct dispatch_windows_s {
- int num_insn; /* Number of insn in the window. */
- int num_uops; /* Number of uops in the window. */
- int window_size; /* Number of bytes in the window. */
- int window_num; /* Window number between 0 or 1. */
- int num_imm; /* Number of immediates in an insn. */
- int num_imm_32; /* Number of 32 bit immediates in an insn. */
- int num_imm_64; /* Number of 64 bit immediates in an insn. */
- int imm_size; /* Total immediates in the window. */
- int num_loads; /* Total memory loads in the window. */
- int num_stores; /* Total memory stores in the window. */
- int violation; /* Violation exists in window. */
- sched_insn_info *window; /* Pointer to the window. */
- struct dispatch_windows_s *next;
- struct dispatch_windows_s *prev;
-} dispatch_windows;
-
-/* Immediate valuse used in an insn. */
-typedef struct imm_info_s
- {
- int imm;
- int imm32;
- int imm64;
- } imm_info;
-
-static dispatch_windows *dispatch_window_list;
-static dispatch_windows *dispatch_window_list1;
-
-/* Get dispatch group of insn. */
-
-static enum dispatch_group
-get_mem_group (rtx_insn *insn)
-{
- enum attr_memory memory;
-
- if (INSN_CODE (insn) < 0)
- return disp_no_group;
- memory = get_attr_memory (insn);
- if (memory == MEMORY_STORE)
- return disp_store;
-
- if (memory == MEMORY_LOAD)
- return disp_load;
-
- if (memory == MEMORY_BOTH)
- return disp_load_store;
-
- return disp_no_group;
-}
-
-/* Return true if insn is a compare instruction. */
-
-static bool
-is_cmp (rtx_insn *insn)
-{
- enum attr_type type;
-
- type = get_attr_type (insn);
- return (type == TYPE_TEST
- || type == TYPE_ICMP
- || type == TYPE_FCMP
- || GET_CODE (PATTERN (insn)) == COMPARE);
-}
-
-/* Return true if a dispatch violation encountered. */
-
-static bool
-dispatch_violation (void)
-{
- if (dispatch_window_list->next)
- return dispatch_window_list->next->violation;
- return dispatch_window_list->violation;
-}
-
-/* Return true if insn is a branch instruction. */
-
-static bool
-is_branch (rtx_insn *insn)
-{
- return (CALL_P (insn) || JUMP_P (insn));
-}
-
-/* Return true if insn is a prefetch instruction. */
-
-static bool
-is_prefetch (rtx_insn *insn)
-{
- return NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == PREFETCH;
-}
-
-/* This function initializes a dispatch window and the list container holding a
- pointer to the window. */
-
-static void
-init_window (int window_num)
-{
- int i;
- dispatch_windows *new_list;
-
- if (window_num == 0)
- new_list = dispatch_window_list;
- else
- new_list = dispatch_window_list1;
-
- new_list->num_insn = 0;
- new_list->num_uops = 0;
- new_list->window_size = 0;
- new_list->next = NULL;
- new_list->prev = NULL;
- new_list->window_num = window_num;
- new_list->num_imm = 0;
- new_list->num_imm_32 = 0;
- new_list->num_imm_64 = 0;
- new_list->imm_size = 0;
- new_list->num_loads = 0;
- new_list->num_stores = 0;
- new_list->violation = false;
-
- for (i = 0; i < MAX_INSN; i++)
- {
- new_list->window[i].insn = NULL;
- new_list->window[i].group = disp_no_group;
- new_list->window[i].path = no_path;
- new_list->window[i].byte_len = 0;
- new_list->window[i].imm_bytes = 0;
- }
- return;
-}
-
-/* This function allocates and initializes a dispatch window and the
- list container holding a pointer to the window. */
-
-static dispatch_windows *
-allocate_window (void)
-{
- dispatch_windows *new_list = XNEW (struct dispatch_windows_s);
- new_list->window = XNEWVEC (struct sched_insn_info_s, MAX_INSN + 1);
-
- return new_list;
-}
-
-/* This routine initializes the dispatch scheduling information. It
- initiates building dispatch scheduler tables and constructs the
- first dispatch window. */
-
-static void
-init_dispatch_sched (void)
-{
- /* Allocate a dispatch list and a window. */
- dispatch_window_list = allocate_window ();
- dispatch_window_list1 = allocate_window ();
- init_window (0);
- init_window (1);
-}
-
-/* This function returns true if a branch is detected. End of a basic block
- does not have to be a branch, but here we assume only branches end a
- window. */
-
-static bool
-is_end_basic_block (enum dispatch_group group)
-{
- return group == disp_branch;
-}
-
-/* This function is called when the end of a window processing is reached. */
-
-static void
-process_end_window (void)
-{
- gcc_assert (dispatch_window_list->num_insn <= MAX_INSN);
- if (dispatch_window_list->next)
- {
- gcc_assert (dispatch_window_list1->num_insn <= MAX_INSN);
- gcc_assert (dispatch_window_list->window_size
- + dispatch_window_list1->window_size <= 48);
- init_window (1);
- }
- init_window (0);
-}
-
-/* Allocates a new dispatch window and adds it to WINDOW_LIST.
- WINDOW_NUM is either 0 or 1. A maximum of two windows are generated
- for 48 bytes of instructions. Note that these windows are not dispatch
- windows that their sizes are DISPATCH_WINDOW_SIZE. */
-
-static dispatch_windows *
-allocate_next_window (int window_num)
-{
- if (window_num == 0)
- {
- if (dispatch_window_list->next)
- init_window (1);
- init_window (0);
- return dispatch_window_list;
- }
-
- dispatch_window_list->next = dispatch_window_list1;
- dispatch_window_list1->prev = dispatch_window_list;
-
- return dispatch_window_list1;
-}
-
-/* Compute number of immediate operands of an instruction. */
-
-static void
-find_constant (rtx in_rtx, imm_info *imm_values)
-{
- if (INSN_P (in_rtx))
- in_rtx = PATTERN (in_rtx);
- subrtx_iterator::array_type array;
- FOR_EACH_SUBRTX (iter, array, in_rtx, ALL)
- if (const_rtx x = *iter)
- switch (GET_CODE (x))
- {
- case CONST:
- case SYMBOL_REF:
- case CONST_INT:
- (imm_values->imm)++;
- if (x86_64_immediate_operand (CONST_CAST_RTX (x), SImode))
- (imm_values->imm32)++;
- else
- (imm_values->imm64)++;
- break;
-
- case CONST_DOUBLE:
- case CONST_WIDE_INT:
- (imm_values->imm)++;
- (imm_values->imm64)++;
- break;
-
- case CODE_LABEL:
- if (LABEL_KIND (x) == LABEL_NORMAL)
- {
- (imm_values->imm)++;
- (imm_values->imm32)++;
- }
- break;
-
- default:
- break;
- }
-}
-
-/* Return total size of immediate operands of an instruction along with number
- of corresponding immediate-operands. It initializes its parameters to zero
- befor calling FIND_CONSTANT.
- INSN is the input instruction. IMM is the total of immediates.
- IMM32 is the number of 32 bit immediates. IMM64 is the number of 64
- bit immediates. */
-
-static int
-get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
-{
- imm_info imm_values = {0, 0, 0};
-
- find_constant (insn, &imm_values);
- *imm = imm_values.imm;
- *imm32 = imm_values.imm32;
- *imm64 = imm_values.imm64;
- return imm_values.imm32 * 4 + imm_values.imm64 * 8;
-}
-
-/* This function indicates if an operand of an instruction is an
- immediate. */
-
-static bool
-has_immediate (rtx_insn *insn)
-{
- int num_imm_operand;
- int num_imm32_operand;
- int num_imm64_operand;
-
- if (insn)
- return get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
- &num_imm64_operand);
- return false;
-}
-
-/* Return single or double path for instructions. */
-
-static enum insn_path
-get_insn_path (rtx_insn *insn)
-{
- enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
-
- if ((int)path == 0)
- return path_single;
-
- if ((int)path == 1)
- return path_double;
-
- return path_multi;
-}
-
-/* Return insn dispatch group. */
-
-static enum dispatch_group
-get_insn_group (rtx_insn *insn)
-{
- enum dispatch_group group = get_mem_group (insn);
- if (group)
- return group;
-
- if (is_branch (insn))
- return disp_branch;
-
- if (is_cmp (insn))
- return disp_cmp;
-
- if (has_immediate (insn))
- return disp_imm;
-
- if (is_prefetch (insn))
- return disp_prefetch;
-
- return disp_no_group;
-}
-
-/* Count number of GROUP restricted instructions in a dispatch
- window WINDOW_LIST. */
-
-static int
-count_num_restricted (rtx_insn *insn, dispatch_windows *window_list)
-{
- enum dispatch_group group = get_insn_group (insn);
- int imm_size;
- int num_imm_operand;
- int num_imm32_operand;
- int num_imm64_operand;
-
- if (group == disp_no_group)
- return 0;
-
- if (group == disp_imm)
- {
- imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
- &num_imm64_operand);
- if (window_list->imm_size + imm_size > MAX_IMM_SIZE
- || num_imm_operand + window_list->num_imm > MAX_IMM
- || (num_imm32_operand > 0
- && (window_list->num_imm_32 + num_imm32_operand > MAX_IMM_32
- || window_list->num_imm_64 * 2 + num_imm32_operand > MAX_IMM_32))
- || (num_imm64_operand > 0
- && (window_list->num_imm_64 + num_imm64_operand > MAX_IMM_64
- || window_list->num_imm_32 + num_imm64_operand * 2 > MAX_IMM_32))
- || (window_list->imm_size + imm_size == MAX_IMM_SIZE
- && num_imm64_operand > 0
- && ((window_list->num_imm_64 > 0
- && window_list->num_insn >= 2)
- || window_list->num_insn >= 3)))
- return BIG;
-
- return 1;
- }
-
- if ((group == disp_load_store
- && (window_list->num_loads >= MAX_LOAD
- || window_list->num_stores >= MAX_STORE))
- || ((group == disp_load
- || group == disp_prefetch)
- && window_list->num_loads >= MAX_LOAD)
- || (group == disp_store
- && window_list->num_stores >= MAX_STORE))
- return BIG;
-
- return 1;
-}
-
-/* This function returns true if insn satisfies dispatch rules on the
- last window scheduled. */
-
-static bool
-fits_dispatch_window (rtx_insn *insn)
-{
- dispatch_windows *window_list = dispatch_window_list;
- dispatch_windows *window_list_next = dispatch_window_list->next;
- unsigned int num_restrict;
- enum dispatch_group group = get_insn_group (insn);
- enum insn_path path = get_insn_path (insn);
- int sum;
-
- /* Make disp_cmp and disp_jcc get scheduled at the latest. These
- instructions should be given the lowest priority in the
- scheduling process in Haifa scheduler to make sure they will be
- scheduled in the same dispatch window as the reference to them. */
- if (group == disp_jcc || group == disp_cmp)
- return false;
-
- /* Check nonrestricted. */
- if (group == disp_no_group || group == disp_branch)
- return true;
-
- /* Get last dispatch window. */
- if (window_list_next)
- window_list = window_list_next;
-
- if (window_list->window_num == 1)
- {
- sum = window_list->prev->window_size + window_list->window_size;
-
- if (sum == 32
- || (min_insn_size (insn) + sum) >= 48)
- /* Window 1 is full. Go for next window. */
- return true;
- }
-
- num_restrict = count_num_restricted (insn, window_list);
-
- if (num_restrict > num_allowable_groups[group])
- return false;
-
- /* See if it fits in the first window. */
- if (window_list->window_num == 0)
- {
- /* The first widow should have only single and double path
- uops. */
- if (path == path_double
- && (window_list->num_uops + 2) > MAX_INSN)
- return false;
- else if (path != path_single)
- return false;
- }
- return true;
-}
-
-/* Add an instruction INSN with NUM_UOPS micro-operations to the
- dispatch window WINDOW_LIST. */
-
-static void
-add_insn_window (rtx_insn *insn, dispatch_windows *window_list, int num_uops)
-{
- int byte_len = min_insn_size (insn);
- int num_insn = window_list->num_insn;
- int imm_size;
- sched_insn_info *window = window_list->window;
- enum dispatch_group group = get_insn_group (insn);
- enum insn_path path = get_insn_path (insn);
- int num_imm_operand;
- int num_imm32_operand;
- int num_imm64_operand;
-
- if (!window_list->violation && group != disp_cmp
- && !fits_dispatch_window (insn))
- window_list->violation = true;
-
- imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
- &num_imm64_operand);
-
- /* Initialize window with new instruction. */
- window[num_insn].insn = insn;
- window[num_insn].byte_len = byte_len;
- window[num_insn].group = group;
- window[num_insn].path = path;
- window[num_insn].imm_bytes = imm_size;
-
- window_list->window_size += byte_len;
- window_list->num_insn = num_insn + 1;
- window_list->num_uops = window_list->num_uops + num_uops;
- window_list->imm_size += imm_size;
- window_list->num_imm += num_imm_operand;
- window_list->num_imm_32 += num_imm32_operand;
- window_list->num_imm_64 += num_imm64_operand;
-
- if (group == disp_store)
- window_list->num_stores += 1;
- else if (group == disp_load
- || group == disp_prefetch)
- window_list->num_loads += 1;
- else if (group == disp_load_store)
- {
- window_list->num_stores += 1;
- window_list->num_loads += 1;
- }
-}
-
-/* Adds a scheduled instruction, INSN, to the current dispatch window.
- If the total bytes of instructions or the number of instructions in
- the window exceed allowable, it allocates a new window. */
-
-static void
-add_to_dispatch_window (rtx_insn *insn)
-{
- int byte_len;
- dispatch_windows *window_list;
- dispatch_windows *next_list;
- dispatch_windows *window0_list;
- enum insn_path path;
- enum dispatch_group insn_group;
- bool insn_fits;
- int num_insn;
- int num_uops;
- int window_num;
- int insn_num_uops;
- int sum;
-
- if (INSN_CODE (insn) < 0)
- return;
-
- byte_len = min_insn_size (insn);
- window_list = dispatch_window_list;
- next_list = window_list->next;
- path = get_insn_path (insn);
- insn_group = get_insn_group (insn);
-
- /* Get the last dispatch window. */
- if (next_list)
- window_list = dispatch_window_list->next;
-
- if (path == path_single)
- insn_num_uops = 1;
- else if (path == path_double)
- insn_num_uops = 2;
- else
- insn_num_uops = (int) path;
-
- /* If current window is full, get a new window.
- Window number zero is full, if MAX_INSN uops are scheduled in it.
- Window number one is full, if window zero's bytes plus window
- one's bytes is 32, or if the bytes of the new instruction added
- to the total makes it greater than 48, or it has already MAX_INSN
- instructions in it. */
- num_insn = window_list->num_insn;
- num_uops = window_list->num_uops;
- window_num = window_list->window_num;
- insn_fits = fits_dispatch_window (insn);
-
- if (num_insn >= MAX_INSN
- || num_uops + insn_num_uops > MAX_INSN
- || !(insn_fits))
- {
- window_num = ~window_num & 1;
- window_list = allocate_next_window (window_num);
- }
-
- if (window_num == 0)
- {
- add_insn_window (insn, window_list, insn_num_uops);
- if (window_list->num_insn >= MAX_INSN
- && insn_group == disp_branch)
- {
- process_end_window ();
- return;
- }
- }
- else if (window_num == 1)
- {
- window0_list = window_list->prev;
- sum = window0_list->window_size + window_list->window_size;
- if (sum == 32
- || (byte_len + sum) >= 48)
- {
- process_end_window ();
- window_list = dispatch_window_list;
- }
-
- add_insn_window (insn, window_list, insn_num_uops);
- }
- else
- gcc_unreachable ();
-
- if (is_end_basic_block (insn_group))
- {
- /* End of basic block is reached do end-basic-block process. */
- process_end_window ();
- return;
- }
-}
-
-/* Print the dispatch window, WINDOW_NUM, to FILE. */
-
-DEBUG_FUNCTION static void
-debug_dispatch_window_file (FILE *file, int window_num)
-{
- dispatch_windows *list;
- int i;
-
- if (window_num == 0)
- list = dispatch_window_list;
- else
- list = dispatch_window_list1;
-
- fprintf (file, "Window #%d:\n", list->window_num);
- fprintf (file, " num_insn = %d, num_uops = %d, window_size = %d\n",
- list->num_insn, list->num_uops, list->window_size);
- fprintf (file, " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
- list->num_imm, list->num_imm_32, list->num_imm_64, list->imm_size);
-
- fprintf (file, " num_loads = %d, num_stores = %d\n", list->num_loads,
- list->num_stores);
- fprintf (file, " insn info:\n");
-
- for (i = 0; i < MAX_INSN; i++)
- {
- if (!list->window[i].insn)
- break;
- fprintf (file, " group[%d] = %s, insn[%d] = %p, path[%d] = %d byte_len[%d] = %d, imm_bytes[%d] = %d\n",
- i, group_name[list->window[i].group],
- i, (void *)list->window[i].insn,
- i, list->window[i].path,
- i, list->window[i].byte_len,
- i, list->window[i].imm_bytes);
- }
-}
-
-/* Print to stdout a dispatch window. */
-
-DEBUG_FUNCTION void
-debug_dispatch_window (int window_num)
-{
- debug_dispatch_window_file (stdout, window_num);
-}
-
-/* Print INSN dispatch information to FILE. */
-
-DEBUG_FUNCTION static void
-debug_insn_dispatch_info_file (FILE *file, rtx_insn *insn)
-{
- int byte_len;
- enum insn_path path;
- enum dispatch_group group;
- int imm_size;
- int num_imm_operand;
- int num_imm32_operand;
- int num_imm64_operand;
-
- if (INSN_CODE (insn) < 0)
- return;
-
- byte_len = min_insn_size (insn);
- path = get_insn_path (insn);
- group = get_insn_group (insn);
- imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
- &num_imm64_operand);
-
- fprintf (file, " insn info:\n");
- fprintf (file, " group = %s, path = %d, byte_len = %d\n",
- group_name[group], path, byte_len);
- fprintf (file, " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
- num_imm_operand, num_imm32_operand, num_imm64_operand, imm_size);
-}
-
-/* Print to STDERR the status of the ready list with respect to
- dispatch windows. */
-
-DEBUG_FUNCTION void
-debug_ready_dispatch (void)
-{
- int i;
- int no_ready = number_in_ready ();
-
- fprintf (stdout, "Number of ready: %d\n", no_ready);
-
- for (i = 0; i < no_ready; i++)
- debug_insn_dispatch_info_file (stdout, get_ready_element (i));
-}
-
-/* This routine is the driver of the dispatch scheduler. */
-
-static void
-do_dispatch (rtx_insn *insn, int mode)
-{
- if (mode == DISPATCH_INIT)
- init_dispatch_sched ();
- else if (mode == ADD_TO_DISPATCH_WINDOW)
- add_to_dispatch_window (insn);
-}
-
-/* Return TRUE if Dispatch Scheduling is supported. */
-
-static bool
-has_dispatch (rtx_insn *insn, int action)
-{
- if ((TARGET_BDVER1 || TARGET_BDVER2 || TARGET_BDVER3
- || TARGET_BDVER4 || TARGET_ZNVER1) && flag_dispatch_scheduler)
- switch (action)
- {
- default:
- return false;
-
- case IS_DISPATCH_ON:
- return true;
-
- case IS_CMP:
- return is_cmp (insn);
-
- case DISPATCH_VIOLATION:
- return dispatch_violation ();
-
- case FITS_DISPATCH_WINDOW:
- return fits_dispatch_window (insn);
- }
-
- return false;
-}
/* Implementation of reassociation_width target hook used by
reassoc phase to identify parallelism level in reassociated
tree. Statements tree_code is passed in OPC. Arguments type
- is passed in MODE.
-
- Currently parallel reassociation is enabled for Atom
- processors only and we set reassociation width to be 2
- because Atom may issue up to 2 instructions per cycle.
-
- Return value should be fixed if parallel reassociation is
- enabled for other processors. */
+ is passed in MODE. */
static int
-ix86_reassociation_width (unsigned int, machine_mode mode)
+ix86_reassociation_width (unsigned int op, machine_mode mode)
{
+ int width = 1;
/* Vector part. */
if (VECTOR_MODE_P (mode))
{
- if (TARGET_VECTOR_PARALLEL_EXECUTION)
- return 2;
- else
+ int div = 1;
+ if (INTEGRAL_MODE_P (mode))
+ width = ix86_cost->reassoc_vec_int;
+ else if (FLOAT_MODE_P (mode))
+ width = ix86_cost->reassoc_vec_fp;
+
+ if (width == 1)
+ return 1;
+
+ /* Integer vector instructions execute in FP unit
+ and can execute 3 additions and one multiplication per cycle. */
+ if (ix86_tune == PROCESSOR_ZNVER1 && INTEGRAL_MODE_P (mode)
+ && op != PLUS && op != MINUS)
return 1;
- }
+ /* Account for targets that splits wide vectors into multiple parts. */
+ if (TARGET_AVX128_OPTIMAL && GET_MODE_BITSIZE (mode) > 128)
+ div = GET_MODE_BITSIZE (mode) / 128;
+ else if (TARGET_SSE_SPLIT_REGS && GET_MODE_BITSIZE (mode) > 64)
+ div = GET_MODE_BITSIZE (mode) / 64;
+ width = (width + div - 1) / div;
+ }
/* Scalar part. */
- if (INTEGRAL_MODE_P (mode) && TARGET_REASSOC_INT_TO_PARALLEL)
- return 2;
- else if (FLOAT_MODE_P (mode) && TARGET_REASSOC_FP_TO_PARALLEL)
- return ((TARGET_64BIT && ix86_tune == PROCESSOR_HASWELL)? 4 : 2);
- else
- return 1;
+ else if (INTEGRAL_MODE_P (mode))
+ width = ix86_cost->reassoc_int;
+ else if (FLOAT_MODE_P (mode))
+ width = ix86_cost->reassoc_fp;
+
+ /* Avoid using too many registers in 32bit mode. */
+ if (!TARGET_64BIT && width > 2)
+ width = 2;
+ return width;
}
/* ??? No autovectorization into MMX or 3DNOW until we can reliably
@@ -51675,20 +48522,39 @@ ix86_preferred_simd_mode (scalar_mode mode)
switch (mode)
{
case E_QImode:
- return TARGET_AVX512BW ? V64QImode :
- (TARGET_AVX && !TARGET_PREFER_AVX128) ? V32QImode : V16QImode;
+ if (TARGET_AVX512BW && !TARGET_PREFER_AVX256)
+ return V64QImode;
+ else if (TARGET_AVX && !TARGET_PREFER_AVX128)
+ return V32QImode;
+ else
+ return V16QImode;
+
case E_HImode:
- return TARGET_AVX512BW ? V32HImode :
- (TARGET_AVX && !TARGET_PREFER_AVX128) ? V16HImode : V8HImode;
+ if (TARGET_AVX512BW && !TARGET_PREFER_AVX256)
+ return V32HImode;
+ else if (TARGET_AVX && !TARGET_PREFER_AVX128)
+ return V16HImode;
+ else
+ return V8HImode;
+
case E_SImode:
- return TARGET_AVX512F ? V16SImode :
- (TARGET_AVX && !TARGET_PREFER_AVX128) ? V8SImode : V4SImode;
+ if (TARGET_AVX512F && !TARGET_PREFER_AVX256)
+ return V16SImode;
+ else if (TARGET_AVX && !TARGET_PREFER_AVX128)
+ return V8SImode;
+ else
+ return V4SImode;
+
case E_DImode:
- return TARGET_AVX512F ? V8DImode :
- (TARGET_AVX && !TARGET_PREFER_AVX128) ? V4DImode : V2DImode;
+ if (TARGET_AVX512F && !TARGET_PREFER_AVX256)
+ return V8DImode;
+ else if (TARGET_AVX && !TARGET_PREFER_AVX128)
+ return V4DImode;
+ else
+ return V2DImode;
case E_SFmode:
- if (TARGET_AVX512F)
+ if (TARGET_AVX512F && !TARGET_PREFER_AVX256)
return V16SFmode;
else if (TARGET_AVX && !TARGET_PREFER_AVX128)
return V8SFmode;
@@ -51696,7 +48562,7 @@ ix86_preferred_simd_mode (scalar_mode mode)
return V4SFmode;
case E_DFmode:
- if (TARGET_AVX512F)
+ if (TARGET_AVX512F && !TARGET_PREFER_AVX256)
return V8DFmode;
else if (TARGET_AVX && !TARGET_PREFER_AVX128)
return V4DFmode;
@@ -51716,8 +48582,14 @@ ix86_preferred_simd_mode (scalar_mode mode)
static unsigned int
ix86_autovectorize_vector_sizes (void)
{
- return TARGET_AVX512F ? 64 | 32 | 16 :
- (TARGET_AVX && !TARGET_PREFER_AVX128) ? 32 | 16 : 0;
+ unsigned int bytesizes = 0;
+
+ if (TARGET_AVX512F && !TARGET_PREFER_AVX256)
+ bytesizes |= (64 | 32 | 16);
+ else if (TARGET_AVX && !TARGET_PREFER_AVX128)
+ bytesizes |= (32 | 16);
+
+ return bytesizes;
}
/* Implemenation of targetm.vectorize.get_mask_mode. */
@@ -53006,6 +49878,9 @@ ix86_run_selftests (void)
#undef TARGET_DELEGITIMIZE_ADDRESS
#define TARGET_DELEGITIMIZE_ADDRESS ix86_delegitimize_address
+#undef TARGET_CONST_NOT_OK_FOR_DEBUG_P
+#define TARGET_CONST_NOT_OK_FOR_DEBUG_P ix86_const_not_ok_for_debug_p
+
#undef TARGET_MS_BITFIELD_LAYOUT_P
#define TARGET_MS_BITFIELD_LAYOUT_P ix86_ms_bitfield_layout_p
@@ -53280,6 +50155,9 @@ ix86_run_selftests (void)
#undef TARGET_CONDITIONAL_REGISTER_USAGE
#define TARGET_CONDITIONAL_REGISTER_USAGE ix86_conditional_register_usage
+#undef TARGET_CANONICALIZE_COMPARISON
+#define TARGET_CANONICALIZE_COMPARISON ix86_canonicalize_comparison
+
#undef TARGET_LOOP_UNROLL_ADJUST
#define TARGET_LOOP_UNROLL_ADJUST ix86_loop_unroll_adjust
@@ -53403,6 +50281,9 @@ ix86_run_selftests (void)
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS ix86_can_change_mode_class
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT ix86_constant_alignment
+
#if CHECKING_P
#undef TARGET_RUN_TARGET_SELFTESTS
#define TARGET_RUN_TARGET_SELFTESTS selftest::ix86_run_selftests
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 6c8ae97..27fc9f0 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -103,6 +103,8 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define TARGET_SGX_P(x) TARGET_ISA_SGX_P(x)
#define TARGET_RDPID TARGET_ISA_RDPID
#define TARGET_RDPID_P(x) TARGET_ISA_RDPID_P(x)
+#define TARGET_GFNI TARGET_ISA_GFNI
+#define TARGET_GFNI_P(x) TARGET_ISA_GFNI_P(x)
#define TARGET_BMI TARGET_ISA_BMI
#define TARGET_BMI_P(x) TARGET_ISA_BMI_P(x)
#define TARGET_BMI2 TARGET_ISA_BMI2
@@ -167,6 +169,10 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define TARGET_MWAITX_P(x) TARGET_ISA_MWAITX_P(x)
#define TARGET_PKU TARGET_ISA_PKU
#define TARGET_PKU_P(x) TARGET_ISA_PKU_P(x)
+#define TARGET_IBT TARGET_ISA_IBT
+#define TARGET_IBT_P(x) TARGET_ISA_IBT_P(x)
+#define TARGET_SHSTK TARGET_ISA_SHSTK
+#define TARGET_SHSTK_P(x) TARGET_ISA_SHSTK_P(x)
#define TARGET_LP64 TARGET_ABI_64
#define TARGET_LP64_P(x) TARGET_ABI_64_P(x)
@@ -236,13 +242,17 @@ struct processor_costs {
in SImode and DImode */
const int mmx_store[2]; /* cost of storing MMX register
in SImode and DImode */
- const int sse_move; /* cost of moving SSE register. */
- const int sse_load[3]; /* cost of loading SSE register
- in SImode, DImode and TImode*/
- const int sse_store[3]; /* cost of storing SSE register
- in SImode, DImode and TImode*/
+ const int xmm_move, ymm_move, /* cost of moving XMM and YMM register. */
+ zmm_move;
+ const int sse_load[5]; /* cost of loading SSE register
+ in 32bit, 64bit, 128bit, 256bit and 512bit */
+ const int sse_unaligned_load[5];/* cost of unaligned load. */
+ const int sse_store[5]; /* cost of storing SSE register
+ in SImode, DImode and TImode. */
+ const int sse_unaligned_store[5];/* cost of unaligned store. */
const int mmxsse_to_integer; /* cost of moving mmxsse register to
- integer and vice versa. */
+ integer. */
+ const int ssemmx_to_integer; /* cost of moving integer to mmxsse register. */
const int l1_cache_size; /* size of l1 cache, in kilobytes. */
const int l2_cache_size; /* size of l2 cache, in kilobytes. */
const int prefetch_block; /* bytes moved to cache for prefetch. */
@@ -257,19 +267,24 @@ struct processor_costs {
const int fsqrt; /* cost of FSQRT instruction. */
/* Specify what algorithm
to use for stringops on unknown size. */
+ const int sse_op; /* cost of cheap SSE instruction. */
+ const int addss; /* cost of ADDSS/SD SUBSS/SD instructions. */
+ const int mulss; /* cost of MULSS instructions. */
+ const int mulsd; /* cost of MULSD instructions. */
+ const int fmass; /* cost of FMASS instructions. */
+ const int fmasd; /* cost of FMASD instructions. */
+ const int divss; /* cost of DIVSS instructions. */
+ const int divsd; /* cost of DIVSD instructions. */
+ const int sqrtss; /* cost of SQRTSS instructions. */
+ const int sqrtsd; /* cost of SQRTSD instructions. */
+ const int reassoc_int, reassoc_fp, reassoc_vec_int, reassoc_vec_fp;
+ /* Specify reassociation width for integer,
+ fp, vector integer and vector fp
+ operations. Generally should correspond
+ to number of instructions executed in
+ parallel. See also
+ ix86_reassociation_width. */
struct stringop_algs *memcpy, *memset;
- const int scalar_stmt_cost; /* Cost of any scalar operation, excluding
- load and store. */
- const int scalar_load_cost; /* Cost of scalar load. */
- const int scalar_store_cost; /* Cost of scalar store. */
- const int vec_stmt_cost; /* Cost of any vector operation, excluding
- load, store, vector-to-scalar and
- scalar-to-vector operation. */
- const int vec_to_scalar_cost; /* Cost of vect-to-scalar operation. */
- const int scalar_to_vec_cost; /* Cost of scalar-to-vector operation. */
- const int vec_align_load_cost; /* Cost of aligned vector load. */
- const int vec_unalign_load_cost; /* Cost of unaligned vector load. */
- const int vec_store_cost; /* Cost of vector store. */
const int cond_taken_branch_cost; /* Cost of taken branch for vectorizer
cost model. */
const int cond_not_taken_branch_cost;/* Cost of not taken branch for
@@ -351,6 +366,7 @@ extern const struct processor_costs ix86_size_cost;
#define TARGET_BONNELL (ix86_tune == PROCESSOR_BONNELL)
#define TARGET_SILVERMONT (ix86_tune == PROCESSOR_SILVERMONT)
#define TARGET_KNL (ix86_tune == PROCESSOR_KNL)
+#define TARGET_KNM (ix86_tune == PROCESSOR_KNM)
#define TARGET_SKYLAKE_AVX512 (ix86_tune == PROCESSOR_SKYLAKE_AVX512)
#define TARGET_INTEL (ix86_tune == PROCESSOR_INTEL)
#define TARGET_GENERIC (ix86_tune == PROCESSOR_GENERIC)
@@ -465,8 +481,6 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST];
ix86_tune_features[X86_TUNE_USE_VECTOR_CONVERTS]
#define TARGET_SLOW_PSHUFB \
ix86_tune_features[X86_TUNE_SLOW_PSHUFB]
-#define TARGET_VECTOR_PARALLEL_EXECUTION \
- ix86_tune_features[X86_TUNE_VECTOR_PARALLEL_EXECUTION]
#define TARGET_AVOID_4BYTE_PREFIXES \
ix86_tune_features[X86_TUNE_AVOID_4BYTE_PREFIXES]
#define TARGET_FUSE_CMP_AND_BRANCH_32 \
@@ -487,10 +501,6 @@ extern unsigned char ix86_tune_features[X86_TUNE_LAST];
ix86_tune_features[X86_TUNE_SOFTWARE_PREFETCHING_BENEFICIAL]
#define TARGET_AVX128_OPTIMAL \
ix86_tune_features[X86_TUNE_AVX128_OPTIMAL]
-#define TARGET_REASSOC_INT_TO_PARALLEL \
- ix86_tune_features[X86_TUNE_REASSOC_INT_TO_PARALLEL]
-#define TARGET_REASSOC_FP_TO_PARALLEL \
- ix86_tune_features[X86_TUNE_REASSOC_FP_TO_PARALLEL]
#define TARGET_GENERAL_REGS_SSE_SPILL \
ix86_tune_features[X86_TUNE_GENERAL_REGS_SSE_SPILL]
#define TARGET_AVOID_MEM_OPND_FOR_CMOVE \
@@ -847,20 +857,6 @@ extern const char *host_detect_local_cpu (int argc, const char **argv);
x86_field_alignment ((TYPE), (COMPUTED))
#endif
-/* If defined, a C expression to compute the alignment given to a
- constant that is being placed in memory. EXP is the constant
- and ALIGN is the alignment that the object would ordinarily have.
- The value of this macro is used instead of that alignment to align
- the object.
-
- If this macro is not defined, then ALIGN is used.
-
- The typical use of this macro is to increase alignment for string
- constants to be word aligned so that `strcpy' calls that copy
- constants can be done inline. */
-
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) ix86_constant_alignment ((EXP), (ALIGN))
-
/* If defined, a C expression to compute the alignment for a static
variable. TYPE is the data type, and ALIGN is the alignment that
the object would ordinarily have. The value of this macro is used
@@ -1531,12 +1527,6 @@ enum reg_class
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* If we generate an insn to push BYTES bytes, this says how many the stack
pointer really advances by. On 386, we have pushw instruction that
decrements by exactly 2 no matter what the position was, there is no pushb.
@@ -2250,6 +2240,7 @@ enum processor_type
PROCESSOR_BONNELL,
PROCESSOR_SILVERMONT,
PROCESSOR_KNL,
+ PROCESSOR_KNM,
PROCESSOR_SKYLAKE_AVX512,
PROCESSOR_INTEL,
PROCESSOR_GEODE,
@@ -2614,6 +2605,7 @@ struct GTY(()) machine_function {
#define ix86_current_function_calls_tls_descriptor \
(ix86_tls_descriptor_calls_expanded_in_cfun && df_regs_ever_live_p (SP_REG))
#define ix86_static_chain_on_stack (cfun->machine->static_chain_on_stack)
+#define ix86_red_zone_size (cfun->machine->frame.red_zone_size)
/* Control behavior of x86_file_start. */
#define X86_FILE_START_VERSION_DIRECTIVE false
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index b1bde14..49ad039 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -62,7 +62,7 @@
;; ; -- print a semicolon (after prefixes due to bug in older gas).
;; ~ -- print "i" if TARGET_AVX2, "f" otherwise.
;; ^ -- print addr32 prefix if TARGET_64BIT and Pmode != word_mode
-;; ! -- print MPX prefix for jxx/call/ret instructions if required.
+;; ! -- print MPX or NOTRACK prefix for jxx/call/ret instructions if required.
(define_c_enum "unspec" [
;; Relocation specifiers
@@ -112,6 +112,7 @@
UNSPEC_STOS
UNSPEC_PEEPSIB
UNSPEC_INSN_FALSE_DEP
+ UNSPEC_SBB
;; For SSE/MMX support:
UNSPEC_FIX_NOTRUNC
@@ -274,6 +275,17 @@
;; For RDPID support
UNSPECV_RDPID
+
+ ;; For CET support
+ UNSPECV_NOP_ENDBR
+ UNSPECV_NOP_RDSSP
+ UNSPECV_INCSSP
+ UNSPECV_SAVEPREVSSP
+ UNSPECV_RSTORSSP
+ UNSPECV_WRSS
+ UNSPECV_WRUSS
+ UNSPECV_SETSSBSY
+ UNSPECV_CLRSSBSY
])
;; Constants to represent rounding modes in the ROUND instruction
@@ -798,7 +810,7 @@
(define_attr "isa" "base,x64,x64_sse4,x64_sse4_noavx,x64_avx,nox64,
sse2,sse2_noavx,sse3,sse4,sse4_noavx,avx,noavx,
avx2,noavx2,bmi,bmi2,fma4,fma,avx512f,noavx512f,
- fma_avx512f,avx512bw,noavx512bw,avx512dq,noavx512dq,
+ avx512bw,noavx512bw,avx512dq,noavx512dq,
avx512vl,noavx512vl,x64_avx512dq,x64_avx512bw"
(const_string "base"))
@@ -832,8 +844,6 @@
(eq_attr "isa" "fma") (symbol_ref "TARGET_FMA")
(eq_attr "isa" "avx512f") (symbol_ref "TARGET_AVX512F")
(eq_attr "isa" "noavx512f") (symbol_ref "!TARGET_AVX512F")
- (eq_attr "isa" "fma_avx512f")
- (symbol_ref "TARGET_FMA || TARGET_AVX512F")
(eq_attr "isa" "avx512bw") (symbol_ref "TARGET_AVX512BW")
(eq_attr "isa" "noavx512bw") (symbol_ref "!TARGET_AVX512BW")
(eq_attr "isa" "avx512dq") (symbol_ref "TARGET_AVX512DQ")
@@ -1612,8 +1622,8 @@
(unspec:HI
[(compare:CCFP
(match_operand:X87MODEF 1 "register_operand" "f")
- (match_operator:X87MODEF 3 "float_operator"
- [(match_operand:SWI24 2 "memory_operand" "m")]))]
+ (float:X87MODEF
+ (match_operand:SWI24 2 "memory_operand" "m")))]
UNSPEC_FNSTSW))]
"TARGET_80387
&& (TARGET_USE_<SWI24:MODE>MODE_FIOP
@@ -1628,8 +1638,8 @@
[(set (reg:CCFP FLAGS_REG)
(compare:CCFP
(match_operand:X87MODEF 1 "register_operand" "f")
- (match_operator:X87MODEF 3 "float_operator"
- [(match_operand:SWI24 2 "memory_operand" "m")])))
+ (float:X87MODEF
+ (match_operand:SWI24 2 "memory_operand" "m"))))
(clobber (match_operand:HI 0 "register_operand" "=a"))]
"TARGET_80387 && TARGET_SAHF && !TARGET_CMOVE
&& (TARGET_USE_<SWI24:MODE>MODE_FIOP
@@ -1640,7 +1650,7 @@
(unspec:HI
[(compare:CCFP
(match_dup 1)
- (match_op_dup 3 [(match_dup 2)]))]
+ (float:X87MODEF (match_dup 2)))]
UNSPEC_FNSTSW))
(set (reg:CC FLAGS_REG)
(unspec:CC [(match_dup 0)] UNSPEC_SAHF))]
@@ -1685,8 +1695,7 @@
(set_attr "mode" "SI")])
;; Pentium Pro can do steps 1 through 3 in one go.
-;; comi*, ucomi*, fcomi*, ficomi*, fucomi*
-;; (these i387 instructions set flags directly)
+;; (these instructions set flags directly)
(define_mode_iterator FPCMP [CCFP CCFPU])
(define_mode_attr unord [(CCFP "") (CCFPU "u")])
@@ -1698,8 +1707,10 @@
(match_operand:MODEF 1 "register_ssemem_operand" "f,vm")))]
"(SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH)
|| (TARGET_80387 && TARGET_CMOVE)"
- "* return output_fp_compare (insn, operands, true,
- <FPCMP:MODE>mode == CCFPUmode);"
+ "@
+ * return output_fp_compare (insn, operands, true, \
+ <FPCMP:MODE>mode == CCFPUmode);
+ %v<FPCMP:unord>comi<MODEF:ssemodesuffix>\t{%1, %0|%0, %1}"
[(set_attr "type" "fcmp,ssecomi")
(set_attr "prefix" "orig,maybe_vex")
(set_attr "mode" "<MODEF:MODE>")
@@ -2379,6 +2390,28 @@
gen_lowpart (SImode, operands[1]));
})
+;; movabsq $0x0012345678000000, %rax is longer
+;; than movl $0x12345678, %eax; shlq $24, %rax.
+(define_peephole2
+ [(set (match_operand:DI 0 "register_operand")
+ (match_operand:DI 1 "const_int_operand"))]
+ "TARGET_64BIT
+ && optimize_insn_for_size_p ()
+ && LEGACY_INT_REG_P (operands[0])
+ && !x86_64_immediate_operand (operands[1], DImode)
+ && !x86_64_zext_immediate_operand (operands[1], DImode)
+ && !((UINTVAL (operands[1]) >> ctz_hwi (UINTVAL (operands[1])))
+ & ~(HOST_WIDE_INT) 0xffffffff)
+ && peep2_regno_dead_p (0, FLAGS_REG)"
+ [(set (match_dup 0) (match_dup 1))
+ (parallel [(set (match_dup 0) (ashift:DI (match_dup 0) (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ int shift = ctz_hwi (UINTVAL (operands[1]));
+ operands[1] = gen_int_mode (UINTVAL (operands[1]) >> shift, DImode);
+ operands[2] = gen_int_mode (shift, QImode);
+})
+
(define_insn "*movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand"
"=r,m ,*y,*y,?*y,?m,?r ,?*Ym,*v,*v,*v,m ,?r ,?*Yi,*k,*k ,*rm")
@@ -2571,9 +2604,9 @@
(define_insn "*movqi_internal"
[(set (match_operand:QI 0 "nonimmediate_operand"
- "=q,q ,q ,r,r ,?r,m ,k,k,r,m,k")
+ "=Q,R,r,q,q,r,r ,?r,m ,k,k,r,m,k")
(match_operand:QI 1 "general_operand"
- "q ,qn,qm,q,rn,qm,qn,r,k,k,k,m"))]
+ "Q ,R,r,n,m,q,rn, m,qn,r,k,k,k,m"))]
"!(MEM_P (operands[0]) && MEM_P (operands[1]))"
{
static char buf[128];
@@ -2589,17 +2622,17 @@
case TYPE_MSKMOV:
switch (which_alternative)
{
- case 7:
+ case 9:
ops = "kmov%s\t{%%k1, %%0|%%0, %%k1}";
break;
- case 9:
+ case 11:
ops = "kmov%s\t{%%1, %%k0|%%k0, %%1}";
break;
- case 10:
- case 11:
+ case 12:
+ case 13:
gcc_assert (TARGET_AVX512DQ);
/* FALLTHRU */
- case 8:
+ case 10:
ops = "kmov%s\t{%%1, %%0|%%0, %%1}";
break;
default:
@@ -2619,51 +2652,67 @@
}
}
[(set (attr "isa")
- (if_then_else (eq_attr "alternative" "10,11")
- (const_string "avx512dq")
- (const_string "*")))
+ (cond [(eq_attr "alternative" "1,2")
+ (const_string "x64")
+ (eq_attr "alternative" "12,13")
+ (const_string "avx512dq")
+ ]
+ (const_string "*")))
(set (attr "type")
- (cond [(eq_attr "alternative" "7,8,9,10,11")
+ (cond [(eq_attr "alternative" "9,10,11,12,13")
(const_string "mskmov")
- (and (eq_attr "alternative" "5")
+ (and (eq_attr "alternative" "7")
(not (match_operand:QI 1 "aligned_operand")))
(const_string "imovx")
(match_test "optimize_function_for_size_p (cfun)")
(const_string "imov")
- (and (eq_attr "alternative" "3")
+ (and (eq_attr "alternative" "5")
(ior (not (match_test "TARGET_PARTIAL_REG_STALL"))
(not (match_test "TARGET_QIMODE_MATH"))))
(const_string "imov")
- (eq_attr "alternative" "3,5")
+ (eq_attr "alternative" "5,7")
(const_string "imovx")
(and (match_test "TARGET_MOVX")
- (eq_attr "alternative" "2"))
+ (eq_attr "alternative" "4"))
(const_string "imovx")
]
(const_string "imov")))
(set (attr "prefix")
- (if_then_else (eq_attr "alternative" "7,8,9")
+ (if_then_else (eq_attr "alternative" "9,10,11")
(const_string "vex")
(const_string "orig")))
(set (attr "mode")
- (cond [(eq_attr "alternative" "3,4,5")
+ (cond [(eq_attr "alternative" "5,6,7")
(const_string "SI")
- (eq_attr "alternative" "6")
+ (eq_attr "alternative" "8")
(const_string "QI")
- (and (eq_attr "alternative" "7,8,9")
+ (and (eq_attr "alternative" "9,10,11")
(not (match_test "TARGET_AVX512DQ")))
(const_string "HI")
(eq_attr "type" "imovx")
(const_string "SI")
+ ;; For -Os, 8-bit immediates are always shorter than 32-bit
+ ;; ones.
+ (and (eq_attr "type" "imov")
+ (and (eq_attr "alternative" "3")
+ (match_test "optimize_function_for_size_p (cfun)")))
+ (const_string "QI")
+ ;; For -Os, movl where one or both operands are NON_Q_REGS
+ ;; and both are LEGACY_REGS is shorter than movb.
+ ;; Otherwise movb and movl sizes are the same, so decide purely
+ ;; based on speed factors.
(and (eq_attr "type" "imov")
- (and (eq_attr "alternative" "0,1")
+ (and (eq_attr "alternative" "1")
+ (match_test "optimize_function_for_size_p (cfun)")))
+ (const_string "SI")
+ (and (eq_attr "type" "imov")
+ (and (eq_attr "alternative" "0,1,2,3")
(and (match_test "TARGET_PARTIAL_REG_DEPENDENCY")
- (and (not (match_test "optimize_function_for_size_p (cfun)"))
- (not (match_test "TARGET_PARTIAL_REG_STALL"))))))
+ (not (match_test "TARGET_PARTIAL_REG_STALL")))))
(const_string "SI")
;; Avoid partial register stalls when not using QImode arithmetic
(and (eq_attr "type" "imov")
- (and (eq_attr "alternative" "0,1")
+ (and (eq_attr "alternative" "0,1,2,3")
(and (match_test "TARGET_PARTIAL_REG_STALL")
(not (match_test "TARGET_QIMODE_MATH")))))
(const_string "SI")
@@ -3508,7 +3557,8 @@
(eq_attr "alternative" "12,16")
(cond [(not (match_test "TARGET_SSE2"))
(const_string "V4SF")
- (match_test "TARGET_AVX512F")
+ (and (match_test "TARGET_AVX512F")
+ (not (match_test "TARGET_PREFER_AVX256")))
(const_string "XI")
(match_test "TARGET_AVX")
(const_string "V2DF")
@@ -3525,8 +3575,10 @@
/* movaps is one byte shorter for non-AVX targets. */
(eq_attr "alternative" "13,17")
- (cond [(ior (match_operand 0 "ext_sse_reg_operand")
- (match_operand 1 "ext_sse_reg_operand"))
+ (cond [(and (ior (not (match_test "TARGET_PREFER_AVX256"))
+ (not (match_test "TARGET_AVX512VL")))
+ (ior (match_operand 0 "ext_sse_reg_operand")
+ (match_operand 1 "ext_sse_reg_operand")))
(const_string "V8DF")
(ior (not (match_test "TARGET_SSE2"))
(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
@@ -3677,7 +3729,8 @@
(eq_attr "alternative" "5")
(cond [(not (match_test "TARGET_SSE2"))
(const_string "V4SF")
- (match_test "TARGET_AVX512F")
+ (and (match_test "TARGET_AVX512F")
+ (not (match_test "TARGET_PREFER_AVX256")))
(const_string "V16SF")
(match_test "TARGET_AVX")
(const_string "V4SF")
@@ -3699,8 +3752,10 @@
better to maintain the whole registers in single format
to avoid problems on using packed logical operations. */
(eq_attr "alternative" "6")
- (cond [(ior (match_operand 0 "ext_sse_reg_operand")
- (match_operand 1 "ext_sse_reg_operand"))
+ (cond [(and (ior (not (match_test "TARGET_PREFER_AVX256"))
+ (not (match_test "TARGET_AVX512VL")))
+ (ior (match_operand 0 "ext_sse_reg_operand")
+ (match_operand 1 "ext_sse_reg_operand")))
(const_string "V16SF")
(ior (match_test "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
(match_test "TARGET_SSE_SPLIT_REGS"))
@@ -6224,7 +6279,7 @@
(set_attr "mode" "<MODE>")])
(define_insn "addqi_ext_1"
- [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
(const_int 8)
(const_int 8))
(subreg:SI
@@ -6235,7 +6290,8 @@
(const_int 8)) 0)
(match_operand:QI 2 "general_operand" "QnBc,m")) 0))
(clobber (reg:CC FLAGS_REG))]
- ""
+ "/* FIXME: without this LRA can't reload this pattern, see PR82524. */
+ rtx_equal_p (operands[0], operands[1])"
{
switch (get_attr_type (insn))
{
@@ -6260,7 +6316,7 @@
(set_attr "mode" "QI")])
(define_insn "*addqi_ext_2"
- [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q")
(const_int 8)
(const_int 8))
(subreg:SI
@@ -6274,7 +6330,9 @@
(const_int 8)
(const_int 8)) 0)) 0))
(clobber (reg:CC FLAGS_REG))]
- ""
+ "/* FIXME: without this LRA can't reload this pattern, see PR82524. */
+ rtx_equal_p (operands[0], operands[1])
+ || rtx_equal_p (operands[0], operands[2])"
"add{b}\t{%h2, %h0|%h0, %h2}"
[(set_attr "type" "alu")
(set_attr "mode" "QI")])
@@ -6722,6 +6780,17 @@
[(set_attr "type" "alu")
(set_attr "mode" "<MODE>")])
+(define_peephole2
+ [(parallel
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_operand:SWI 0 "general_reg_operand")
+ (match_operand:SWI 1 "general_gr_operand")))
+ (set (match_dup 0)
+ (minus:SWI (match_dup 0) (match_dup 1)))])]
+ "find_regno_note (peep2_next_insn (0), REG_UNUSED, REGNO (operands[0])) != 0"
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC (match_dup 0) (match_dup 1)))])
+
(define_insn "*subsi_3_zext"
[(set (reg FLAGS_REG)
(compare (match_operand:SI 1 "register_operand" "0")
@@ -6775,15 +6844,19 @@
(define_insn "addcarry<mode>"
[(set (reg:CCC FLAGS_REG)
(compare:CCC
- (plus:SWI48
+ (zero_extend:<DWI>
(plus:SWI48
- (match_operator:SWI48 4 "ix86_carry_flag_operator"
- [(match_operand 3 "flags_reg_operand") (const_int 0)])
- (match_operand:SWI48 1 "nonimmediate_operand" "%0"))
- (match_operand:SWI48 2 "nonimmediate_operand" "rm"))
- (match_dup 1)))
+ (plus:SWI48
+ (match_operator:SWI48 5 "ix86_carry_flag_operator"
+ [(match_operand 3 "flags_reg_operand") (const_int 0)])
+ (match_operand:SWI48 1 "nonimmediate_operand" "%0"))
+ (match_operand:SWI48 2 "nonimmediate_operand" "rm")))
+ (plus:<DWI>
+ (zero_extend:<DWI> (match_dup 2))
+ (match_operator:<DWI> 4 "ix86_carry_flag_operator"
+ [(match_dup 3) (const_int 0)]))))
(set (match_operand:SWI48 0 "register_operand" "=r")
- (plus:SWI48 (plus:SWI48 (match_op_dup 4
+ (plus:SWI48 (plus:SWI48 (match_op_dup 5
[(match_dup 3) (const_int 0)])
(match_dup 1))
(match_dup 2)))]
@@ -6794,6 +6867,18 @@
(set_attr "pent_pair" "pu")
(set_attr "mode" "<MODE>")])
+(define_expand "addcarry<mode>_0"
+ [(parallel
+ [(set (reg:CCC FLAGS_REG)
+ (compare:CCC
+ (plus:SWI48
+ (match_operand:SWI48 1 "nonimmediate_operand")
+ (match_operand:SWI48 2 "x86_64_general_operand"))
+ (match_dup 1)))
+ (set (match_operand:SWI48 0 "register_operand")
+ (plus:SWI48 (match_dup 1) (match_dup 2)))])]
+ "ix86_binary_operator_ok (PLUS, <MODE>mode, operands)")
+
(define_insn "sub<mode>3_carry"
[(set (match_operand:SWI 0 "nonimmediate_operand" "=<r>m,<r>")
(minus:SWI
@@ -6827,18 +6912,67 @@
(set_attr "pent_pair" "pu")
(set_attr "mode" "SI")])
+(define_insn "sub<mode>3_carry_ccc"
+ [(set (reg:CCC FLAGS_REG)
+ (compare:CCC
+ (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "0"))
+ (plus:<DWI>
+ (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))
+ (zero_extend:<DWI>
+ (match_operand:DWIH 2 "x86_64_sext_operand" "rmWe")))))
+ (clobber (match_scratch:DWIH 0 "=r"))]
+ ""
+ "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "mode" "<MODE>")])
+
+(define_insn "*sub<mode>3_carry_ccc_1"
+ [(set (reg:CCC FLAGS_REG)
+ (compare:CCC
+ (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "0"))
+ (plus:<DWI>
+ (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))
+ (match_operand:<DWI> 2 "x86_64_dwzext_immediate_operand" "Wf"))))
+ (clobber (match_scratch:DWIH 0 "=r"))]
+ ""
+{
+ operands[3] = simplify_subreg (<MODE>mode, operands[2], <DWI>mode, 0);
+ return "sbb{<imodesuffix>}\t{%3, %0|%0, %3}";
+}
+ [(set_attr "type" "alu")
+ (set_attr "mode" "<MODE>")])
+
+;; The sign flag is set from the
+;; (compare (match_dup 1) (plus:DWIH (ltu:DWIH ...) (match_dup 2)))
+;; result, the overflow flag likewise, but the overflow flag is also
+;; set if the (plus:DWIH (ltu:DWIH ...) (match_dup 2)) overflows.
+(define_insn "sub<mode>3_carry_ccgz"
+ [(set (reg:CCGZ FLAGS_REG)
+ (unspec:CCGZ [(match_operand:DWIH 1 "register_operand" "0")
+ (match_operand:DWIH 2 "x86_64_general_operand" "rme")
+ (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0))]
+ UNSPEC_SBB))
+ (clobber (match_scratch:DWIH 0 "=r"))]
+ ""
+ "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
+ [(set_attr "type" "alu")
+ (set_attr "mode" "<MODE>")])
+
(define_insn "subborrow<mode>"
[(set (reg:CCC FLAGS_REG)
(compare:CCC
- (match_operand:SWI48 1 "nonimmediate_operand" "0")
- (plus:SWI48
- (match_operator:SWI48 4 "ix86_carry_flag_operator"
- [(match_operand 3 "flags_reg_operand") (const_int 0)])
- (match_operand:SWI48 2 "nonimmediate_operand" "rm"))))
+ (zero_extend:<DWI>
+ (match_operand:SWI48 1 "nonimmediate_operand" "0"))
+ (plus:<DWI>
+ (match_operator:<DWI> 4 "ix86_carry_flag_operator"
+ [(match_operand 3 "flags_reg_operand") (const_int 0)])
+ (zero_extend:<DWI>
+ (match_operand:SWI48 2 "nonimmediate_operand" "rm")))))
(set (match_operand:SWI48 0 "register_operand" "=r")
- (minus:SWI48 (minus:SWI48 (match_dup 1)
- (match_op_dup 4
- [(match_dup 3) (const_int 0)]))
+ (minus:SWI48 (minus:SWI48
+ (match_dup 1)
+ (match_operator:SWI48 5 "ix86_carry_flag_operator"
+ [(match_dup 3) (const_int 0)]))
(match_dup 2)))]
"ix86_binary_operator_ok (MINUS, <MODE>mode, operands)"
"sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
@@ -6846,6 +6980,16 @@
(set_attr "use_carry" "1")
(set_attr "pent_pair" "pu")
(set_attr "mode" "<MODE>")])
+
+(define_expand "subborrow<mode>_0"
+ [(parallel
+ [(set (reg:CC FLAGS_REG)
+ (compare:CC
+ (match_operand:SWI48 1 "nonimmediate_operand")
+ (match_operand:SWI48 2 "<general_operand>")))
+ (set (match_operand:SWI48 0 "register_operand")
+ (minus:SWI48 (match_dup 1) (match_dup 2)))])]
+ "ix86_binary_operator_ok (MINUS, <MODE>mode, operands)")
;; Overflow setting add instructions
@@ -7595,6 +7739,36 @@
[(const_int 0)]
"ix86_split_idivmod (<MODE>mode, operands, true); DONE;")
+(define_split
+ [(set (match_operand:DI 0 "register_operand")
+ (zero_extend:DI
+ (div:SI (match_operand:SI 2 "register_operand")
+ (match_operand:SI 3 "nonimmediate_operand"))))
+ (set (match_operand:SI 1 "register_operand")
+ (mod:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_USE_8BIT_IDIV
+ && TARGET_QIMODE_MATH
+ && can_create_pseudo_p ()
+ && !optimize_insn_for_size_p ()"
+ [(const_int 0)]
+ "ix86_split_idivmod (SImode, operands, true); DONE;")
+
+(define_split
+ [(set (match_operand:DI 1 "register_operand")
+ (zero_extend:DI
+ (mod:SI (match_operand:SI 2 "register_operand")
+ (match_operand:SI 3 "nonimmediate_operand"))))
+ (set (match_operand:SI 0 "register_operand")
+ (div:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_USE_8BIT_IDIV
+ && TARGET_QIMODE_MATH
+ && can_create_pseudo_p ()
+ && !optimize_insn_for_size_p ()"
+ [(const_int 0)]
+ "ix86_split_idivmod (SImode, operands, true); DONE;")
+
(define_insn_and_split "divmod<mode>4_1"
[(set (match_operand:SWI48 0 "register_operand" "=a")
(div:SWI48 (match_operand:SWI48 2 "register_operand" "0")
@@ -7630,6 +7804,79 @@
[(set_attr "type" "multi")
(set_attr "mode" "<MODE>")])
+(define_insn_and_split "divmodsi4_zext_1"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (zero_extend:DI
+ (div:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 1 "register_operand" "=&d")
+ (mod:SI (match_dup 2) (match_dup 3)))
+ (unspec [(const_int 0)] UNSPEC_DIV_ALREADY_SPLIT)
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 1)
+ (ashiftrt:SI (match_dup 4) (match_dup 5)))
+ (clobber (reg:CC FLAGS_REG))])
+ (parallel [(set (match_dup 0)
+ (zero_extend:DI (div:SI (match_dup 2) (match_dup 3))))
+ (set (match_dup 1)
+ (mod:SI (match_dup 2) (match_dup 3)))
+ (use (match_dup 1))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ operands[5] = GEN_INT (GET_MODE_BITSIZE (SImode)-1);
+
+ if (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)
+ operands[4] = operands[2];
+ else
+ {
+ /* Avoid use of cltd in favor of a mov+shift. */
+ emit_move_insn (operands[1], operands[2]);
+ operands[4] = operands[1];
+ }
+}
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "divmodsi4_zext_2"
+ [(set (match_operand:DI 1 "register_operand" "=&d")
+ (zero_extend:DI
+ (mod:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 0 "register_operand" "=a")
+ (div:SI (match_dup 2) (match_dup 3)))
+ (unspec [(const_int 0)] UNSPEC_DIV_ALREADY_SPLIT)
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 6)
+ (ashiftrt:SI (match_dup 4) (match_dup 5)))
+ (clobber (reg:CC FLAGS_REG))])
+ (parallel [(set (match_dup 1)
+ (zero_extend:DI (mod:SI (match_dup 2) (match_dup 3))))
+ (set (match_dup 0)
+ (div:SI (match_dup 2) (match_dup 3)))
+ (use (match_dup 6))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ operands[5] = GEN_INT (GET_MODE_BITSIZE (SImode)-1);
+ operands[6] = gen_lowpart (SImode, operands[1]);
+
+ if (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)
+ operands[4] = operands[2];
+ else
+ {
+ /* Avoid use of cltd in favor of a mov+shift. */
+ emit_move_insn (operands[6], operands[2]);
+ operands[4] = operands[6];
+ }
+}
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
(define_insn_and_split "*divmod<mode>4"
[(set (match_operand:SWIM248 0 "register_operand" "=a")
(div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
@@ -7665,6 +7912,77 @@
[(set_attr "type" "multi")
(set_attr "mode" "<MODE>")])
+(define_insn_and_split "*divmodsi4_zext_1"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (zero_extend:DI
+ (div:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 1 "register_operand" "=&d")
+ (mod:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 1)
+ (ashiftrt:SI (match_dup 4) (match_dup 5)))
+ (clobber (reg:CC FLAGS_REG))])
+ (parallel [(set (match_dup 0)
+ (zero_extend:DI (div:SI (match_dup 2) (match_dup 3))))
+ (set (match_dup 1)
+ (mod:SI (match_dup 2) (match_dup 3)))
+ (use (match_dup 1))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ operands[5] = GEN_INT (GET_MODE_BITSIZE (SImode)-1);
+
+ if (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)
+ operands[4] = operands[2];
+ else
+ {
+ /* Avoid use of cltd in favor of a mov+shift. */
+ emit_move_insn (operands[1], operands[2]);
+ operands[4] = operands[1];
+ }
+}
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "*divmodsi4_zext_2"
+ [(set (match_operand:DI 1 "register_operand" "=&d")
+ (zero_extend:DI
+ (mod:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 0 "register_operand" "=a")
+ (div:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "#"
+ "reload_completed"
+ [(parallel [(set (match_dup 6)
+ (ashiftrt:SI (match_dup 4) (match_dup 5)))
+ (clobber (reg:CC FLAGS_REG))])
+ (parallel [(set (match_dup 1)
+ (zero_extend:DI (mod:SI (match_dup 2) (match_dup 3))))
+ (set (match_dup 0)
+ (div:SI (match_dup 2) (match_dup 3)))
+ (use (match_dup 6))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ operands[5] = GEN_INT (GET_MODE_BITSIZE (SImode)-1);
+ operands[6] = gen_lowpart (SImode, operands[1]);
+
+ if (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)
+ operands[4] = operands[2];
+ else
+ {
+ /* Avoid use of cltd in favor of a mov+shift. */
+ emit_move_insn (operands[6], operands[2]);
+ operands[4] = operands[6];
+ }
+}
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
(define_insn "*divmod<mode>4_noext"
[(set (match_operand:SWIM248 0 "register_operand" "=a")
(div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
@@ -7678,6 +7996,34 @@
[(set_attr "type" "idiv")
(set_attr "mode" "<MODE>")])
+(define_insn "*divmodsi4_noext_zext_1"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (zero_extend:DI
+ (div:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 1 "register_operand" "=d")
+ (mod:SI (match_dup 2) (match_dup 3)))
+ (use (match_operand:SI 4 "register_operand" "1"))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "idiv{l}\t%3"
+ [(set_attr "type" "idiv")
+ (set_attr "mode" "SI")])
+
+(define_insn "*divmodsi4_noext_zext_2"
+ [(set (match_operand:DI 1 "register_operand" "=d")
+ (zero_extend:DI
+ (mod:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 0 "register_operand" "=a")
+ (div:SI (match_dup 2) (match_dup 3)))
+ (use (match_operand:SI 4 "register_operand" "1"))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "idiv{l}\t%3"
+ [(set_attr "type" "idiv")
+ (set_attr "mode" "SI")])
+
(define_expand "divmodqi4"
[(parallel [(set (match_operand:QI 0 "register_operand")
(div:QI
@@ -7768,6 +8114,38 @@
[(const_int 0)]
"ix86_split_idivmod (<MODE>mode, operands, false); DONE;")
+(define_split
+ [(set (match_operand:DI 0 "register_operand")
+ (zero_extend:DI
+ (udiv:SI (match_operand:SI 2 "register_operand")
+ (match_operand:SI 3 "nonimmediate_operand"))))
+ (set (match_operand:SI 1 "register_operand")
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT
+ && TARGET_USE_8BIT_IDIV
+ && TARGET_QIMODE_MATH
+ && can_create_pseudo_p ()
+ && !optimize_insn_for_size_p ()"
+ [(const_int 0)]
+ "ix86_split_idivmod (SImode, operands, false); DONE;")
+
+(define_split
+ [(set (match_operand:DI 1 "register_operand")
+ (zero_extend:DI
+ (umod:SI (match_operand:SI 2 "register_operand")
+ (match_operand:SI 3 "nonimmediate_operand"))))
+ (set (match_operand:SI 0 "register_operand")
+ (udiv:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT
+ && TARGET_USE_8BIT_IDIV
+ && TARGET_QIMODE_MATH
+ && can_create_pseudo_p ()
+ && !optimize_insn_for_size_p ()"
+ [(const_int 0)]
+ "ix86_split_idivmod (SImode, operands, false); DONE;")
+
(define_insn_and_split "udivmod<mode>4_1"
[(set (match_operand:SWI48 0 "register_operand" "=a")
(udiv:SWI48 (match_operand:SWI48 2 "register_operand" "0")
@@ -7790,6 +8168,52 @@
[(set_attr "type" "multi")
(set_attr "mode" "<MODE>")])
+(define_insn_and_split "udivmodsi4_zext_1"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (zero_extend:DI
+ (udiv:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 1 "register_operand" "=&d")
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (unspec [(const_int 0)] UNSPEC_DIV_ALREADY_SPLIT)
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "#"
+ "reload_completed"
+ [(set (match_dup 1) (const_int 0))
+ (parallel [(set (match_dup 0)
+ (zero_extend:DI (udiv:SI (match_dup 2) (match_dup 3))))
+ (set (match_dup 1)
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (use (match_dup 1))
+ (clobber (reg:CC FLAGS_REG))])]
+ ""
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "udivmodsi4_zext_2"
+ [(set (match_operand:DI 1 "register_operand" "=&d")
+ (zero_extend:DI
+ (umod:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 0 "register_operand" "=a")
+ (udiv:SI (match_dup 2) (match_dup 3)))
+ (unspec [(const_int 0)] UNSPEC_DIV_ALREADY_SPLIT)
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "#"
+ "reload_completed"
+ [(set (match_dup 4) (const_int 0))
+ (parallel [(set (match_dup 1)
+ (zero_extend:DI (umod:SI (match_dup 2) (match_dup 3))))
+ (set (match_dup 0)
+ (udiv:SI (match_dup 2) (match_dup 3)))
+ (use (match_dup 4))
+ (clobber (reg:CC FLAGS_REG))])]
+ "operands[4] = gen_lowpart (SImode, operands[1]);"
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
(define_insn_and_split "*udivmod<mode>4"
[(set (match_operand:SWIM248 0 "register_operand" "=a")
(udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
@@ -7811,6 +8235,50 @@
[(set_attr "type" "multi")
(set_attr "mode" "<MODE>")])
+(define_insn_and_split "*udivmodsi4_zext_1"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (zero_extend:DI
+ (udiv:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 1 "register_operand" "=&d")
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "#"
+ "reload_completed"
+ [(set (match_dup 1) (const_int 0))
+ (parallel [(set (match_dup 0)
+ (zero_extend:DI (udiv:SI (match_dup 2) (match_dup 3))))
+ (set (match_dup 1)
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (use (match_dup 1))
+ (clobber (reg:CC FLAGS_REG))])]
+ ""
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "*udivmodsi4_zext_2"
+ [(set (match_operand:DI 1 "register_operand" "=&d")
+ (zero_extend:DI
+ (umod:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 0 "register_operand" "=a")
+ (udiv:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "#"
+ "reload_completed"
+ [(set (match_dup 4) (const_int 0))
+ (parallel [(set (match_dup 1)
+ (zero_extend:DI (umod:SI (match_dup 2) (match_dup 3))))
+ (set (match_dup 0)
+ (udiv:SI (match_dup 2) (match_dup 3)))
+ (use (match_dup 4))
+ (clobber (reg:CC FLAGS_REG))])]
+ "operands[4] = gen_lowpart (SImode, operands[1]);"
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
;; Optimize division or modulo by constant power of 2, if the constant
;; materializes only after expansion.
(define_insn_and_split "*udivmod<mode>4_pow2"
@@ -7837,6 +8305,60 @@
[(set_attr "type" "multi")
(set_attr "mode" "<MODE>")])
+(define_insn_and_split "*udivmodsi4_pow2_zext_1"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (zero_extend:DI
+ (udiv:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "const_int_operand" "n"))))
+ (set (match_operand:SI 1 "register_operand" "=r")
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT
+ && IN_RANGE (INTVAL (operands[3]), 2, HOST_WIDE_INT_UC (0x80000000))
+ && (UINTVAL (operands[3]) & (UINTVAL (operands[3]) - 1)) == 0"
+ "#"
+ "&& 1"
+ [(set (match_dup 1) (match_dup 2))
+ (parallel [(set (match_dup 0)
+ (zero_extend:DI (lshiftrt:SI (match_dup 2) (match_dup 4))))
+ (clobber (reg:CC FLAGS_REG))])
+ (parallel [(set (match_dup 1) (and:SI (match_dup 1) (match_dup 5)))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ int v = exact_log2 (UINTVAL (operands[3]));
+ operands[4] = GEN_INT (v);
+ operands[5] = GEN_INT ((HOST_WIDE_INT_1U << v) - 1);
+}
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
+(define_insn_and_split "*udivmodsi4_pow2_zext_2"
+ [(set (match_operand:DI 1 "register_operand" "=r")
+ (zero_extend:DI
+ (umod:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "const_int_operand" "n"))))
+ (set (match_operand:SI 0 "register_operand" "=r")
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT
+ && IN_RANGE (INTVAL (operands[3]), 2, HOST_WIDE_INT_UC (0x80000000))
+ && (UINTVAL (operands[3]) & (UINTVAL (operands[3]) - 1)) == 0"
+ "#"
+ "&& 1"
+ [(set (match_dup 1) (match_dup 2))
+ (parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 2) (match_dup 4)))
+ (clobber (reg:CC FLAGS_REG))])
+ (parallel [(set (match_dup 1)
+ (zero_extend:DI (and:SI (match_dup 1) (match_dup 5))))
+ (clobber (reg:CC FLAGS_REG))])]
+{
+ int v = exact_log2 (UINTVAL (operands[3]));
+ operands[4] = GEN_INT (v);
+ operands[5] = GEN_INT ((HOST_WIDE_INT_1U << v) - 1);
+}
+ [(set_attr "type" "multi")
+ (set_attr "mode" "SI")])
+
(define_insn "*udivmod<mode>4_noext"
[(set (match_operand:SWIM248 0 "register_operand" "=a")
(udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
@@ -7850,6 +8372,34 @@
[(set_attr "type" "idiv")
(set_attr "mode" "<MODE>")])
+(define_insn "*udivmodsi4_noext_zext_1"
+ [(set (match_operand:DI 0 "register_operand" "=a")
+ (zero_extend:DI
+ (udiv:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 1 "register_operand" "=d")
+ (umod:SI (match_dup 2) (match_dup 3)))
+ (use (match_operand:SI 4 "register_operand" "1"))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "div{l}\t%3"
+ [(set_attr "type" "idiv")
+ (set_attr "mode" "SI")])
+
+(define_insn "*udivmodsi4_noext_zext_2"
+ [(set (match_operand:DI 1 "register_operand" "=d")
+ (zero_extend:DI
+ (umod:SI (match_operand:SI 2 "register_operand" "0")
+ (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+ (set (match_operand:SI 0 "register_operand" "=a")
+ (udiv:SI (match_dup 2) (match_dup 3)))
+ (use (match_operand:SI 4 "register_operand" "1"))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_64BIT"
+ "div{l}\t%3"
+ [(set_attr "type" "idiv")
+ (set_attr "mode" "SI")])
+
(define_expand "udivmodqi4"
[(parallel [(set (match_operand:QI 0 "register_operand")
(udiv:QI
@@ -8552,7 +9102,7 @@
(set_attr "mode" "QI")])
(define_insn "andqi_ext_1"
- [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
(const_int 8)
(const_int 8))
(subreg:SI
@@ -8563,7 +9113,8 @@
(const_int 8)) 0)
(match_operand:QI 2 "general_operand" "QnBc,m")) 0))
(clobber (reg:CC FLAGS_REG))]
- ""
+ "/* FIXME: without this LRA can't reload this pattern, see PR82524. */
+ rtx_equal_p (operands[0], operands[1])"
"and{b}\t{%2, %h0|%h0, %2}"
[(set_attr "isa" "*,nox64")
(set_attr "type" "alu")
@@ -8581,7 +9132,7 @@
(const_int 8)) 0)
(match_operand:QI 2 "general_operand" "QnBc,m"))
(const_int 0)))
- (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
+ (set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
(const_int 8)
(const_int 8))
(subreg:SI
@@ -8591,14 +9142,16 @@
(const_int 8)
(const_int 8)) 0)
(match_dup 2)) 0))]
- "ix86_match_ccmode (insn, CCNOmode)"
+ "ix86_match_ccmode (insn, CCNOmode)
+ /* FIXME: without this LRA can't reload this pattern, see PR82524. */
+ && rtx_equal_p (operands[0], operands[1])"
"and{b}\t{%2, %h0|%h0, %2}"
[(set_attr "isa" "*,nox64")
(set_attr "type" "alu")
(set_attr "mode" "QI")])
(define_insn "*andqi_ext_2"
- [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q")
(const_int 8)
(const_int 8))
(subreg:SI
@@ -8612,7 +9165,9 @@
(const_int 8)
(const_int 8)) 0)) 0))
(clobber (reg:CC FLAGS_REG))]
- ""
+ "/* FIXME: without this LRA can't reload this pattern, see PR82524. */
+ rtx_equal_p (operands[0], operands[1])
+ || rtx_equal_p (operands[0], operands[2])"
"and{b}\t{%h2, %h0|%h0, %h2}"
[(set_attr "type" "alu")
(set_attr "mode" "QI")])
@@ -8985,7 +9540,7 @@
(set_attr "mode" "<MODE>")])
(define_insn "*<code>qi_ext_1"
- [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
(const_int 8)
(const_int 8))
(subreg:SI
@@ -8996,14 +9551,16 @@
(const_int 8)) 0)
(match_operand:QI 2 "general_operand" "QnBc,m")) 0))
(clobber (reg:CC FLAGS_REG))]
- "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)"
+ "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
+ /* FIXME: without this LRA can't reload this pattern, see PR82524. */
+ && rtx_equal_p (operands[0], operands[1])"
"<logic>{b}\t{%2, %h0|%h0, %2}"
[(set_attr "isa" "*,nox64")
(set_attr "type" "alu")
(set_attr "mode" "QI")])
(define_insn "*<code>qi_ext_2"
- [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q")
+ [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q")
(const_int 8)
(const_int 8))
(subreg:SI
@@ -9017,7 +9574,10 @@
(const_int 8)
(const_int 8)) 0)) 0))
(clobber (reg:CC FLAGS_REG))]
- "!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)"
+ "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun))
+ /* FIXME: without this LRA can't reload this pattern, see PR82524. */
+ && (rtx_equal_p (operands[0], operands[1])
+ || rtx_equal_p (operands[0], operands[2]))"
"<logic>{b}\t{%h2, %h0|%h0, %h2}"
[(set_attr "type" "alu")
(set_attr "mode" "QI")])
@@ -9106,7 +9666,7 @@
(const_int 8)) 0)
(match_operand:QI 2 "general_operand" "QnBc,m"))
(const_int 0)))
- (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=Q,Q")
+ (set (zero_extract:SI (match_operand 0 "ext_register_operand" "+Q,Q")
(const_int 8)
(const_int 8))
(subreg:SI
@@ -9116,7 +9676,9 @@
(const_int 8)
(const_int 8)) 0)
(match_dup 2)) 0))]
- "ix86_match_ccmode (insn, CCNOmode)"
+ "ix86_match_ccmode (insn, CCNOmode)
+ /* FIXME: without this LRA can't reload this pattern, see PR82524. */
+ && rtx_equal_p (operands[0], operands[1])"
"xor{b}\t{%2, %h0|%h0, %2}"
[(set_attr "isa" "*,nox64")
(set_attr "type" "alu")
@@ -9782,6 +10344,26 @@
(clobber (reg:CC FLAGS_REG))])]
"operands[2] = gen_lowpart (QImode, operands[2]);")
+(define_insn_and_split "*ashl<mode>3_mask_1"
+ [(set (match_operand:SWI48 0 "nonimmediate_operand")
+ (ashift:SWI48
+ (match_operand:SWI48 1 "nonimmediate_operand")
+ (and:QI
+ (match_operand:QI 2 "register_operand")
+ (match_operand:QI 3 "const_int_operand"))))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_binary_operator_ok (ASHIFT, <MODE>mode, operands)
+ && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
+ == GET_MODE_BITSIZE (<MODE>mode)-1
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(parallel
+ [(set (match_dup 0)
+ (ashift:SWI48 (match_dup 1)
+ (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])])
+
(define_insn "*bmi2_ashl<mode>3_1"
[(set (match_operand:SWI48 0 "register_operand" "=r")
(ashift:SWI48 (match_operand:SWI48 1 "nonimmediate_operand" "rm")
@@ -10282,6 +10864,26 @@
(clobber (reg:CC FLAGS_REG))])]
"operands[2] = gen_lowpart (QImode, operands[2]);")
+(define_insn_and_split "*<shift_insn><mode>3_mask_1"
+ [(set (match_operand:SWI48 0 "nonimmediate_operand")
+ (any_shiftrt:SWI48
+ (match_operand:SWI48 1 "nonimmediate_operand")
+ (and:QI
+ (match_operand:QI 2 "register_operand")
+ (match_operand:QI 3 "const_int_operand"))))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)
+ && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
+ == GET_MODE_BITSIZE (<MODE>mode)-1
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(parallel
+ [(set (match_dup 0)
+ (any_shiftrt:SWI48 (match_dup 1)
+ (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])])
+
(define_insn_and_split "*<shift_insn><mode>3_doubleword"
[(set (match_operand:DWI 0 "register_operand" "=&r")
(any_shiftrt:DWI (match_operand:DWI 1 "register_operand" "0")
@@ -10741,6 +11343,26 @@
(clobber (reg:CC FLAGS_REG))])]
"operands[2] = gen_lowpart (QImode, operands[2]);")
+(define_insn_and_split "*<rotate_insn><mode>3_mask_1"
+ [(set (match_operand:SWI48 0 "nonimmediate_operand")
+ (any_rotate:SWI48
+ (match_operand:SWI48 1 "nonimmediate_operand")
+ (and:QI
+ (match_operand:QI 2 "register_operand")
+ (match_operand:QI 3 "const_int_operand"))))
+ (clobber (reg:CC FLAGS_REG))]
+ "ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)
+ && (INTVAL (operands[3]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
+ == GET_MODE_BITSIZE (<MODE>mode)-1
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(parallel
+ [(set (match_dup 0)
+ (any_rotate:SWI48 (match_dup 1)
+ (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])])
+
;; Implement rotation using two double-precision
;; shift instructions and a scratch register.
@@ -11048,6 +11670,30 @@
(clobber (reg:CC FLAGS_REG))])]
"operands[1] = gen_lowpart (QImode, operands[1]);")
+(define_insn_and_split "*<btsc><mode>_mask_1"
+ [(set (match_operand:SWI48 0 "register_operand")
+ (any_or:SWI48
+ (ashift:SWI48
+ (const_int 1)
+ (and:QI
+ (match_operand:QI 1 "register_operand")
+ (match_operand:QI 2 "const_int_operand")))
+ (match_operand:SWI48 3 "register_operand")))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_USE_BT
+ && (INTVAL (operands[2]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
+ == GET_MODE_BITSIZE (<MODE>mode)-1
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(parallel
+ [(set (match_dup 0)
+ (any_or:SWI48
+ (ashift:SWI48 (const_int 1)
+ (match_dup 1))
+ (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))])])
+
(define_insn "*btr<mode>"
[(set (match_operand:SWI48 0 "register_operand" "=r")
(and:SWI48
@@ -11089,6 +11735,30 @@
(clobber (reg:CC FLAGS_REG))])]
"operands[1] = gen_lowpart (QImode, operands[1]);")
+(define_insn_and_split "*btr<mode>_mask_1"
+ [(set (match_operand:SWI48 0 "register_operand")
+ (and:SWI48
+ (rotate:SWI48
+ (const_int -2)
+ (and:QI
+ (match_operand:QI 1 "register_operand")
+ (match_operand:QI 2 "const_int_operand")))
+ (match_operand:SWI48 3 "register_operand")))
+ (clobber (reg:CC FLAGS_REG))]
+ "TARGET_USE_BT
+ && (INTVAL (operands[2]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
+ == GET_MODE_BITSIZE (<MODE>mode)-1
+ && can_create_pseudo_p ()"
+ "#"
+ "&& 1"
+ [(parallel
+ [(set (match_dup 0)
+ (and:SWI48
+ (rotate:SWI48 (const_int -2)
+ (match_dup 1))
+ (match_dup 3)))
+ (clobber (reg:CC FLAGS_REG))])])
+
;; These instructions are never faster than the corresponding
;; and/ior/xor operations when using immediate operand, so with
;; 32-bit there's no point. But in 64-bit, we can't hold the
@@ -11246,98 +11916,6 @@
(const_string "SI")
(const_string "<MODE>")))])
-(define_insn_and_split "*scc_bt<mode>"
- [(set (match_operand:QI 0 "nonimmediate_operand")
- (match_operator 1 "bt_comparison_operator"
- [(zero_extract:SWI48
- (match_operand:SWI48 2 "nonimmediate_operand")
- (const_int 1)
- (match_operand:SI 3 "nonmemory_operand"))
- (const_int 0)]))
- (clobber (reg:CC FLAGS_REG))]
- "(TARGET_USE_BT || optimize_function_for_size_p (cfun))
- && (CONST_INT_P (operands[3])
- ? (INTVAL (operands[3]) < GET_MODE_BITSIZE (<MODE>mode)
- && INTVAL (operands[3])
- >= (optimize_function_for_size_p (cfun) ? 8 : 32))
- : !memory_operand (operands[2], <MODE>mode))
- && can_create_pseudo_p ()"
- "#"
- "&& 1"
- [(set (reg:CCC FLAGS_REG)
- (compare:CCC
- (zero_extract:SWI48
- (match_dup 2)
- (const_int 1)
- (match_dup 3))
- (const_int 0)))
- (set (match_dup 0)
- (match_op_dup 1 [(reg:CCC FLAGS_REG) (const_int 0)]))]
-{
- operands[1] = shallow_copy_rtx (operands[1]);
- PUT_CODE (operands[1], reverse_condition (GET_CODE (operands[1])));
-})
-
-(define_insn_and_split "*scc_bt<mode>_1"
- [(set (match_operand:QI 0 "nonimmediate_operand")
- (match_operator 1 "bt_comparison_operator"
- [(zero_extract:SWI48
- (match_operand:SWI48 2 "register_operand")
- (const_int 1)
- (zero_extend:SI
- (match_operand:QI 3 "register_operand")))
- (const_int 0)]))
- (clobber (reg:CC FLAGS_REG))]
- "(TARGET_USE_BT || optimize_function_for_size_p (cfun))
- && can_create_pseudo_p ()"
- "#"
- "&& 1"
- [(set (reg:CCC FLAGS_REG)
- (compare:CCC
- (zero_extract:SWI48
- (match_dup 2)
- (const_int 1)
- (match_dup 3))
- (const_int 0)))
- (set (match_dup 0)
- (match_op_dup 1 [(reg:CCC FLAGS_REG) (const_int 0)]))]
-{
- operands[3] = lowpart_subreg (SImode, operands[3], QImode);
- operands[1] = shallow_copy_rtx (operands[1]);
- PUT_CODE (operands[1], reverse_condition (GET_CODE (operands[1])));
-})
-
-;; Avoid useless masking of bit offset operand.
-(define_insn_and_split "*scc_bt<mode>_mask"
- [(set (match_operand:QI 0 "nonimmediate_operand")
- (match_operator 1 "bt_comparison_operator"
- [(zero_extract:SWI48
- (match_operand:SWI48 2 "register_operand")
- (const_int 1)
- (and:SI
- (match_operand:SI 3 "register_operand")
- (match_operand 4 "const_int_operand")))]))
- (clobber (reg:CC FLAGS_REG))]
- "(TARGET_USE_BT || optimize_function_for_size_p (cfun))
- && (INTVAL (operands[4]) & (GET_MODE_BITSIZE (<MODE>mode)-1))
- == GET_MODE_BITSIZE (<MODE>mode)-1
- && can_create_pseudo_p ()"
- "#"
- "&& 1"
- [(set (reg:CCC FLAGS_REG)
- (compare:CCC
- (zero_extract:SWI48
- (match_dup 2)
- (const_int 1)
- (match_dup 3))
- (const_int 0)))
- (set (match_dup 0)
- (match_op_dup 1 [(reg:CCC FLAGS_REG) (const_int 0)]))]
-{
- operands[1] = shallow_copy_rtx (operands[1]);
- PUT_CODE (operands[1], reverse_condition (GET_CODE (operands[1])));
-})
-
(define_insn_and_split "*jcc_bt<mode>"
[(set (pc)
(if_then_else (match_operator 0 "bt_comparison_operator"
@@ -11609,7 +12187,7 @@
;; Basic conditional jump instructions.
;; We ignore the overflow flag for signed branch instructions.
-(define_insn "*jcc_1"
+(define_insn "*jcc"
[(set (pc)
(if_then_else (match_operator 1 "ix86_comparison_operator"
[(reg FLAGS_REG) (const_int 0)])
@@ -11629,26 +12207,6 @@
(const_int 6)))
(set_attr "maybe_prefix_bnd" "1")])
-(define_insn "*jcc_2"
- [(set (pc)
- (if_then_else (match_operator 1 "ix86_comparison_operator"
- [(reg FLAGS_REG) (const_int 0)])
- (pc)
- (label_ref (match_operand 0))))]
- ""
- "%!%+j%c1\t%l0"
- [(set_attr "type" "ibr")
- (set_attr "modrm" "0")
- (set (attr "length")
- (if_then_else
- (and (ge (minus (match_dup 0) (pc))
- (const_int -126))
- (lt (minus (match_dup 0) (pc))
- (const_int 128)))
- (const_int 2)
- (const_int 6)))
- (set_attr "maybe_prefix_bnd" "1")])
-
;; In general it is not safe to assume too much about CCmode registers,
;; so simplify-rtx stops when it sees a second one. Under certain
;; conditions this is safe on x86, so help combine not create
@@ -11698,211 +12256,6 @@
if (! ix86_comparison_operator (operands[0], VOIDmode))
FAIL;
})
-
-;; Define combination compare-and-branch fp compare instructions to help
-;; combine.
-
-(define_insn "*jcc<mode>_0_i387"
- [(set (pc)
- (if_then_else (match_operator:CCFP 0 "ix86_fp_comparison_operator"
- [(match_operand:X87MODEF 1 "register_operand" "f")
- (match_operand:X87MODEF 2 "const0_operand")])
- (label_ref (match_operand 3))
- (pc)))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 4 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE"
- "#")
-
-(define_insn "*jcc<mode>_0_r_i387"
- [(set (pc)
- (if_then_else (match_operator:CCFP 0 "ix86_fp_comparison_operator"
- [(match_operand:X87MODEF 1 "register_operand" "f")
- (match_operand:X87MODEF 2 "const0_operand")])
- (pc)
- (label_ref (match_operand 3))))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 4 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE"
- "#")
-
-(define_insn "*jccxf_i387"
- [(set (pc)
- (if_then_else (match_operator:CCFP 0 "ix86_fp_comparison_operator"
- [(match_operand:XF 1 "register_operand" "f")
- (match_operand:XF 2 "register_operand" "f")])
- (label_ref (match_operand 3))
- (pc)))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 4 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE"
- "#")
-
-(define_insn "*jccxf_r_i387"
- [(set (pc)
- (if_then_else (match_operator:CCFP 0 "ix86_fp_comparison_operator"
- [(match_operand:XF 1 "register_operand" "f")
- (match_operand:XF 2 "register_operand" "f")])
- (pc)
- (label_ref (match_operand 3))))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 4 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE"
- "#")
-
-(define_insn "*jcc<mode>_i387"
- [(set (pc)
- (if_then_else (match_operator:CCFP 0 "ix86_fp_comparison_operator"
- [(match_operand:MODEF 1 "register_operand" "f")
- (match_operand:MODEF 2 "nonimmediate_operand" "fm")])
- (label_ref (match_operand 3))
- (pc)))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 4 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE"
- "#")
-
-(define_insn "*jcc<mode>_r_i387"
- [(set (pc)
- (if_then_else (match_operator:CCFP 0 "ix86_fp_comparison_operator"
- [(match_operand:MODEF 1 "register_operand" "f")
- (match_operand:MODEF 2 "nonimmediate_operand" "fm")])
- (pc)
- (label_ref (match_operand 3))))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 4 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE"
- "#")
-
-(define_insn "*jccu<mode>_i387"
- [(set (pc)
- (if_then_else (match_operator:CCFPU 0 "ix86_fp_comparison_operator"
- [(match_operand:X87MODEF 1 "register_operand" "f")
- (match_operand:X87MODEF 2 "register_operand" "f")])
- (label_ref (match_operand 3))
- (pc)))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 4 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE"
- "#")
-
-(define_insn "*jccu<mode>_r_i387"
- [(set (pc)
- (if_then_else (match_operator:CCFPU 0 "ix86_fp_comparison_operator"
- [(match_operand:X87MODEF 1 "register_operand" "f")
- (match_operand:X87MODEF 2 "register_operand" "f")])
- (pc)
- (label_ref (match_operand 3))))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 4 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE"
- "#")
-
-(define_split
- [(set (pc)
- (if_then_else (match_operator 0 "ix86_fp_comparison_operator"
- [(match_operand:X87MODEF 1 "register_operand")
- (match_operand:X87MODEF 2 "nonimmediate_operand")])
- (match_operand 3)
- (match_operand 4)))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))]
- "TARGET_80387 && !TARGET_CMOVE
- && reload_completed"
- [(const_int 0)]
-{
- ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2],
- operands[3], operands[4], NULL_RTX);
- DONE;
-})
-
-(define_split
- [(set (pc)
- (if_then_else (match_operator 0 "ix86_fp_comparison_operator"
- [(match_operand:X87MODEF 1 "register_operand")
- (match_operand:X87MODEF 2 "general_operand")])
- (match_operand 3)
- (match_operand 4)))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 5))]
- "TARGET_80387 && !TARGET_CMOVE
- && reload_completed"
- [(const_int 0)]
-{
- ix86_split_fp_branch (GET_CODE (operands[0]), operands[1], operands[2],
- operands[3], operands[4], operands[5]);
- DONE;
-})
-
-;; The order of operands in *jcc<fp>_<int>_i387 is forced by combine in
-;; simplify_comparison () function. Float operator is treated as RTX_OBJ
-;; with a precedence over other operators and is always put in the first
-;; place. Swap condition and operands to match ficom instruction.
-
-(define_insn "*jcc<X87MODEF:mode>_<SWI24:mode>_i387"
- [(set (pc)
- (if_then_else
- (match_operator:CCFP 0 "ix86_swapped_fp_comparison_operator"
- [(match_operator:X87MODEF 1 "float_operator"
- [(match_operand:SWI24 2 "nonimmediate_operand" "m")])
- (match_operand:X87MODEF 3 "register_operand" "f")])
- (label_ref (match_operand 4))
- (pc)))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 5 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE
- && (TARGET_USE_<SWI24:MODE>MODE_FIOP
- || optimize_function_for_size_p (cfun))"
- "#")
-
-(define_insn "*jcc<X87MODEF:mode>_<SWI24:mode>_r_i387"
- [(set (pc)
- (if_then_else
- (match_operator:CCFP 0 "ix86_swapped_fp_comparison_operator"
- [(match_operator:X87MODEF 1 "float_operator"
- [(match_operand:SWI24 2 "nonimmediate_operand" "m")])
- (match_operand:X87MODEF 3 "register_operand" "f")])
- (pc)
- (label_ref (match_operand 4))))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 5 "=a"))]
- "TARGET_80387 && !TARGET_CMOVE
- && (TARGET_USE_<SWI24:MODE>MODE_FIOP
- || optimize_function_for_size_p (cfun))"
- "#")
-
-(define_split
- [(set (pc)
- (if_then_else
- (match_operator:CCFP 0 "ix86_swapped_fp_comparison_operator"
- [(match_operator:X87MODEF 1 "float_operator"
- [(match_operand:SWI24 2 "memory_operand")])
- (match_operand:X87MODEF 3 "register_operand")])
- (match_operand 4)
- (match_operand 5)))
- (clobber (reg:CCFP FPSR_REG))
- (clobber (reg:CCFP FLAGS_REG))
- (clobber (match_scratch:HI 6))]
- "TARGET_80387 && !TARGET_CMOVE
- && reload_completed"
- [(const_int 0)]
-{
- ix86_split_fp_branch (swap_condition (GET_CODE (operands[0])), operands[3],
- gen_rtx_FLOAT (GET_MODE (operands[1]), operands[2]),
- operands[4], operands[5], operands[6]);
- DONE;
-})
;; Unconditional and other jump instructions
@@ -12034,6 +12387,34 @@
ix86_expand_clear (operands[3]);
})
+(define_peephole2
+ [(set (reg FLAGS_REG) (match_operand 0))
+ (parallel [(set (reg FLAGS_REG) (match_operand 1))
+ (match_operand 5)])
+ (set (match_operand:QI 2 "register_operand")
+ (match_operator:QI 3 "ix86_comparison_operator"
+ [(reg FLAGS_REG) (const_int 0)]))
+ (set (match_operand 4 "any_QIreg_operand")
+ (zero_extend (match_dup 2)))]
+ "(peep2_reg_dead_p (4, operands[2])
+ || operands_match_p (operands[2], operands[4]))
+ && ! reg_overlap_mentioned_p (operands[4], operands[0])
+ && ! reg_overlap_mentioned_p (operands[4], operands[1])
+ && ! reg_set_p (operands[4], operands[5])
+ && refers_to_regno_p (FLAGS_REG, operands[1], (rtx *)NULL)
+ && peep2_regno_dead_p (0, FLAGS_REG)"
+ [(set (match_dup 6) (match_dup 0))
+ (parallel [(set (match_dup 7) (match_dup 1))
+ (match_dup 5)])
+ (set (strict_low_part (match_dup 8))
+ (match_dup 3))]
+{
+ operands[6] = gen_rtx_REG (GET_MODE (operands[0]), FLAGS_REG);
+ operands[7] = gen_rtx_REG (GET_MODE (operands[1]), FLAGS_REG);
+ operands[8] = gen_lowpart (QImode, operands[4]);
+ ix86_expand_clear (operands[4]);
+})
+
;; Similar, but match zero extend with andsi3.
(define_peephole2
@@ -12079,6 +12460,35 @@
operands[6] = gen_lowpart (QImode, operands[3]);
ix86_expand_clear (operands[3]);
})
+
+(define_peephole2
+ [(set (reg FLAGS_REG) (match_operand 0))
+ (parallel [(set (reg FLAGS_REG) (match_operand 1))
+ (match_operand 5)])
+ (set (match_operand:QI 2 "register_operand")
+ (match_operator:QI 3 "ix86_comparison_operator"
+ [(reg FLAGS_REG) (const_int 0)]))
+ (parallel [(set (match_operand 4 "any_QIreg_operand")
+ (zero_extend (match_dup 2)))
+ (clobber (reg:CC FLAGS_REG))])]
+ "(peep2_reg_dead_p (4, operands[2])
+ || operands_match_p (operands[2], operands[4]))
+ && ! reg_overlap_mentioned_p (operands[4], operands[0])
+ && ! reg_overlap_mentioned_p (operands[4], operands[1])
+ && ! reg_set_p (operands[4], operands[5])
+ && refers_to_regno_p (FLAGS_REG, operands[1], (rtx *)NULL)
+ && peep2_regno_dead_p (0, FLAGS_REG)"
+ [(set (match_dup 6) (match_dup 0))
+ (parallel [(set (match_dup 7) (match_dup 1))
+ (match_dup 5)])
+ (set (strict_low_part (match_dup 8))
+ (match_dup 3))]
+{
+ operands[6] = gen_rtx_REG (GET_MODE (operands[0]), FLAGS_REG);
+ operands[7] = gen_rtx_REG (GET_MODE (operands[1]), FLAGS_REG);
+ operands[8] = gen_lowpart (QImode, operands[4]);
+ ix86_expand_clear (operands[4]);
+})
;; Call instructions.
@@ -17883,6 +18293,28 @@
"* return output_probe_stack_range (operands[0], operands[2]);"
[(set_attr "type" "multi")])
+/* Additional processing for builtin_setjmp. Store the shadow stack pointer
+ as a forth element in jmpbuf. */
+(define_expand "builtin_setjmp_setup"
+ [(match_operand 0 "address_operand")]
+ "TARGET_SHSTK"
+{
+ if (flag_cf_protection & CF_RETURN)
+ {
+ rtx mem, reg_ssp;
+
+ mem = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0],
+ 3 * GET_MODE_SIZE (Pmode)));
+ reg_ssp = gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (reg_ssp, const0_rtx));
+ emit_insn ((Pmode == SImode)
+ ? gen_rdsspsi (reg_ssp, reg_ssp)
+ : gen_rdsspdi (reg_ssp, reg_ssp));
+ emit_move_insn (mem, reg_ssp);
+ }
+ DONE;
+})
+
(define_expand "builtin_setjmp_receiver"
[(label_ref (match_operand 0))]
"!TARGET_64BIT && flag_pic"
@@ -17903,6 +18335,83 @@
DONE;
})
+(define_expand "builtin_longjmp"
+ [(match_operand 0 "address_operand")]
+ "TARGET_SHSTK"
+{
+ rtx fp, lab, stack;
+ rtx jump, label, reg_adj, reg_ssp, reg_minus, mem_buf, tmp, clob;
+ machine_mode sa_mode = STACK_SAVEAREA_MODE (SAVE_NONLOCAL);
+
+ /* Adjust the shadow stack pointer (ssp) to the value saved in the
+ jmp_buf. The saving was done in the builtin_setjmp_setup. */
+ if (flag_cf_protection & CF_RETURN)
+ {
+ /* Get current shadow stack pointer. The code below will check if
+ SHSTK feature is enabled. If it's not enabled RDSSP instruction
+ is a NOP. */
+ reg_ssp = gen_reg_rtx (Pmode);
+ emit_insn (gen_rtx_SET (reg_ssp, const0_rtx));
+ emit_insn ((Pmode == SImode)
+ ? gen_rdsspsi (reg_ssp, reg_ssp)
+ : gen_rdsspdi (reg_ssp, reg_ssp));
+ mem_buf = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0],
+ 3 * GET_MODE_SIZE (Pmode))),
+
+ /* Compare through substraction the saved and the current ssp to decide
+ if ssp has to be adjusted. */
+ reg_minus = gen_reg_rtx (Pmode);
+ tmp = gen_rtx_SET (reg_minus, gen_rtx_MINUS (Pmode, reg_ssp, mem_buf));
+ clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+ tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
+ emit_insn (tmp);
+
+ /* Jump over adjustment code. */
+ label = gen_label_rtx ();
+ tmp = gen_rtx_REG (CCmode, FLAGS_REG);
+ tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
+ tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+ gen_rtx_LABEL_REF (VOIDmode, label),
+ pc_rtx);
+ jump = emit_jump_insn (gen_rtx_SET (pc_rtx, tmp));
+ JUMP_LABEL (jump) = label;
+
+ /* Adjust the ssp. */
+ reg_adj = gen_reg_rtx (Pmode);
+ tmp = gen_rtx_SET (reg_adj,
+ gen_rtx_LSHIFTRT (Pmode, negate_rtx (Pmode, reg_minus),
+ GEN_INT (3)));
+ clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (CCmode, FLAGS_REG));
+ tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
+ emit_insn (tmp);
+ emit_insn ((Pmode == SImode)
+ ? gen_incsspsi (reg_adj)
+ : gen_incsspdi (reg_adj));
+
+ emit_label (label);
+ LABEL_NUSES (label) = 1;
+ }
+
+ /* This code is the same as in expand_buildin_longjmp. */
+ fp = gen_rtx_MEM (Pmode, operands[0]);
+ lab = gen_rtx_MEM (Pmode, plus_constant (Pmode, operands[0],
+ GET_MODE_SIZE (Pmode)));
+ stack = gen_rtx_MEM (sa_mode, plus_constant (Pmode, operands[0],
+ 2 * GET_MODE_SIZE (Pmode)));
+ lab = copy_to_reg (lab);
+
+ emit_clobber (gen_rtx_MEM (BLKmode, gen_rtx_SCRATCH (VOIDmode)));
+ emit_clobber (gen_rtx_MEM (BLKmode, hard_frame_pointer_rtx));
+
+ emit_move_insn (hard_frame_pointer_rtx, fp);
+ emit_stack_restore (SAVE_NONLOCAL, stack);
+
+ emit_use (hard_frame_pointer_rtx);
+ emit_use (stack_pointer_rtx);
+ emit_indirect_jump (lab);
+})
+
+
;; Avoid redundant prefixes by splitting HImode arithmetic to SImode.
;; Do not split instructions with mask registers.
(define_split
@@ -18562,7 +19071,7 @@
(clobber (mem:BLK (scratch)))])]
"(TARGET_SINGLE_PUSH || optimize_insn_for_size_p ())
&& INTVAL (operands[0]) == -GET_MODE_SIZE (word_mode)
- && !ix86_using_red_zone ()"
+ && ix86_red_zone_size == 0"
[(clobber (match_dup 1))
(parallel [(set (mem:W (pre_dec:P (reg:P SP_REG))) (match_dup 1))
(clobber (mem:BLK (scratch)))])])
@@ -18576,7 +19085,7 @@
(clobber (mem:BLK (scratch)))])]
"(TARGET_DOUBLE_PUSH || optimize_insn_for_size_p ())
&& INTVAL (operands[0]) == -2*GET_MODE_SIZE (word_mode)
- && !ix86_using_red_zone ()"
+ && ix86_red_zone_size == 0"
[(clobber (match_dup 1))
(set (mem:W (pre_dec:P (reg:P SP_REG))) (match_dup 1))
(parallel [(set (mem:W (pre_dec:P (reg:P SP_REG))) (match_dup 1))
@@ -18591,7 +19100,7 @@
(clobber (reg:CC FLAGS_REG))])]
"(TARGET_SINGLE_PUSH || optimize_insn_for_size_p ())
&& INTVAL (operands[0]) == -GET_MODE_SIZE (word_mode)
- && !ix86_using_red_zone ()"
+ && ix86_red_zone_size == 0"
[(clobber (match_dup 1))
(set (mem:W (pre_dec:P (reg:P SP_REG))) (match_dup 1))])
@@ -18603,7 +19112,7 @@
(clobber (reg:CC FLAGS_REG))])]
"(TARGET_DOUBLE_PUSH || optimize_insn_for_size_p ())
&& INTVAL (operands[0]) == -2*GET_MODE_SIZE (word_mode)
- && !ix86_using_red_zone ()"
+ && ix86_red_zone_size == 0"
[(clobber (match_dup 1))
(set (mem:W (pre_dec:P (reg:P SP_REG))) (match_dup 1))
(set (mem:W (pre_dec:P (reg:P SP_REG))) (match_dup 1))])
@@ -19523,6 +20032,83 @@
[(set_attr "length" "2")
(set_attr "memory" "unknown")])
+;; CET instructions
+(define_insn "rdssp<mode>"
+ [(set (match_operand:SWI48x 0 "register_operand" "=r")
+ (unspec_volatile:SWI48x
+ [(match_operand:SWI48x 1 "register_operand" "0")]
+ UNSPECV_NOP_RDSSP))]
+ "TARGET_SHSTK"
+ "rdssp<mskmodesuffix>\t%0"
+ [(set_attr "length" "4")
+ (set_attr "type" "other")])
+
+(define_insn "incssp<mode>"
+ [(unspec_volatile [(match_operand:SWI48x 0 "register_operand" "r")]
+ UNSPECV_INCSSP)]
+ "TARGET_SHSTK"
+ "incssp<mskmodesuffix>\t%0"
+ [(set_attr "length" "4")
+ (set_attr "type" "other")])
+
+(define_insn "saveprevssp"
+ [(unspec_volatile [(const_int 0)] UNSPECV_SAVEPREVSSP)]
+ "TARGET_SHSTK"
+ "saveprevssp"
+ [(set_attr "length" "5")
+ (set_attr "type" "other")])
+
+(define_insn "rstorssp"
+ [(unspec_volatile [(match_operand 0 "memory_operand" "m")]
+ UNSPECV_RSTORSSP)]
+ "TARGET_SHSTK"
+ "rstorssp\t%0"
+ [(set_attr "length" "5")
+ (set_attr "type" "other")])
+
+(define_insn "wrss<mode>"
+ [(unspec_volatile [(match_operand:SWI48x 0 "register_operand" "r")
+ (match_operand:SWI48x 1 "memory_operand" "m")]
+ UNSPECV_WRSS)]
+ "TARGET_SHSTK"
+ "wrss<mskmodesuffix>\t%0, %1"
+ [(set_attr "length" "3")
+ (set_attr "type" "other")])
+
+(define_insn "wruss<mode>"
+ [(unspec_volatile [(match_operand:SWI48x 0 "register_operand" "r")
+ (match_operand:SWI48x 1 "memory_operand" "m")]
+ UNSPECV_WRUSS)]
+ "TARGET_SHSTK"
+ "wruss<mskmodesuffix>\t%0, %1"
+ [(set_attr "length" "4")
+ (set_attr "type" "other")])
+
+(define_insn "setssbsy"
+ [(unspec_volatile [(const_int 0)] UNSPECV_SETSSBSY)]
+ "TARGET_SHSTK"
+ "setssbsy"
+ [(set_attr "length" "4")
+ (set_attr "type" "other")])
+
+(define_insn "clrssbsy"
+ [(unspec_volatile [(match_operand 0 "memory_operand" "m")]
+ UNSPECV_CLRSSBSY)]
+ "TARGET_SHSTK"
+ "clrssbsy\t%0"
+ [(set_attr "length" "4")
+ (set_attr "type" "other")])
+
+(define_insn "nop_endbr"
+ [(unspec_volatile [(const_int 0)] UNSPECV_NOP_ENDBR)]
+ "TARGET_IBT"
+ "*
+{ return (TARGET_64BIT)? \"endbr64\" : \"endbr32\"; }"
+ [(set_attr "length" "4")
+ (set_attr "length_immediate" "0")
+ (set_attr "modrm" "0")])
+
+;; For RTM support
(define_expand "xbegin"
[(set (match_operand:SI 0 "register_operand")
(unspec_volatile:SI [(const_int 0)] UNSPECV_XBEGIN))]
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 81bbc1e..7c9dd47 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -588,9 +588,13 @@ Do dispatch scheduling if processor is bdver1, bdver2, bdver3, bdver4
or znver1 and Haifa scheduling is selected.
mprefer-avx128
-Target Report Mask(PREFER_AVX128) SAVE
+Target Report Mask(PREFER_AVX128) Save
Use 128-bit AVX instructions instead of 256-bit AVX instructions in the auto-vectorizer.
+mprefer-avx256
+Target Report Mask(PREFER_AVX256) Var(ix86_target_flags) Save
+Use 256-bit AVX instructions instead of 512-bit AVX instructions in the auto-vectorizer.
+
;; ISA support
m32
@@ -749,6 +753,10 @@ mrdpid
Target Report Mask(ISA_RDPID) Var(ix86_isa_flags2) Save
Support RDPID built-in functions and code generation.
+mgfni
+Target Report Mask(ISA_GFNI) Var(ix86_isa_flags2) Save
+Support GFNI built-in functions and code generation.
+
mbmi
Target Report Mask(ISA_BMI) Var(ix86_isa_flags) Save
Support BMI built-in functions and code generation.
@@ -949,3 +957,23 @@ Attempt to avoid generating instruction sequences containing ret bytes.
mgeneral-regs-only
Target Report RejectNegative Mask(GENERAL_REGS_ONLY) Var(ix86_target_flags) Save
Generate code which uses only the general registers.
+
+mcet
+Target Report Var(flag_cet) Init(0)
+Support Control-flow Enforcment Technology (CET) built-in functions
+and code generation.
+
+mibt
+Target Report Mask(ISA_IBT) Var(ix86_isa_flags2) Save
+Specifically enables an indirect branch tracking feature from Control-flow
+Enforcment Technology (CET).
+
+mshstk
+Target Report Mask(ISA_SHSTK) Var(ix86_isa_flags2) Save
+Specifically enables an shadow stack support feature from Control-flow
+Enforcment Technology (CET).
+
+mcet-switch
+Target Report Undocumented Var(flag_cet_switch) Init(0)
+Turn on CET instrumentation for switch statements, which use jump table and
+indirect jump.
diff --git a/gcc/config/i386/ia32intrin.h b/gcc/config/i386/ia32intrin.h
index 5f954fc..1f4e484 100644
--- a/gcc/config/i386/ia32intrin.h
+++ b/gcc/config/i386/ia32intrin.h
@@ -147,7 +147,8 @@ extern __inline unsigned int
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
__rold (unsigned int __X, int __C)
{
- return (__X << __C) | (__X >> (32 - __C));
+ __C &= 31;
+ return (__X << __C) | (__X >> (-__C & 31));
}
/* 8bit ror */
@@ -171,7 +172,8 @@ extern __inline unsigned int
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
__rord (unsigned int __X, int __C)
{
- return (__X >> __C) | (__X << (32 - __C));
+ __C &= 31;
+ return (__X >> __C) | (__X << (-__C & 31));
}
/* Pause */
@@ -239,7 +241,8 @@ extern __inline unsigned long long
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
__rolq (unsigned long long __X, int __C)
{
- return (__X << __C) | (__X >> (64 - __C));
+ __C &= 63;
+ return (__X << __C) | (__X >> (-__C & 63));
}
/* 64bit ror */
@@ -247,7 +250,8 @@ extern __inline unsigned long long
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
__rorq (unsigned long long __X, int __C)
{
- return (__X >> __C) | (__X << (64 - __C));
+ __C &= 63;
+ return (__X >> __C) | (__X << (-__C & 63));
}
/* Read flags register */
diff --git a/gcc/config/i386/immintrin.h b/gcc/config/i386/immintrin.h
index b52f58e..696cd20 100644
--- a/gcc/config/i386/immintrin.h
+++ b/gcc/config/i386/immintrin.h
@@ -90,6 +90,8 @@
#include <xtestintrin.h>
+#include <cetintrin.h>
+
#ifndef __RDRND__
#pragma GCC push_options
#pragma GCC target("rdrnd")
diff --git a/gcc/config/i386/linux-common.h b/gcc/config/i386/linux-common.h
index 6380639..6613807 100644
--- a/gcc/config/i386/linux-common.h
+++ b/gcc/config/i386/linux-common.h
@@ -121,3 +121,8 @@ along with GCC; see the file COPYING3. If not see
#define CHKP_SPEC "\
%{!nostdlib:%{!nodefaultlibs:" LIBMPX_SPEC LIBMPXWRAPPERS_SPEC "}}" MPX_SPEC
#endif
+
+extern void file_end_indicate_exec_stack_and_cet (void);
+
+#undef TARGET_ASM_FILE_END
+#define TARGET_ASM_FILE_END file_end_indicate_exec_stack_and_cet
diff --git a/gcc/config/i386/predicates.md b/gcc/config/i386/predicates.md
index f7854e9..c46dd5c 100644
--- a/gcc/config/i386/predicates.md
+++ b/gcc/config/i386/predicates.md
@@ -366,6 +366,31 @@
}
})
+;; Return true if VALUE is a constant integer whose value is
+;; x86_64_immediate_operand value zero extended from word mode to mode.
+(define_predicate "x86_64_dwzext_immediate_operand"
+ (match_code "const_int,const_wide_int")
+{
+ switch (GET_CODE (op))
+ {
+ case CONST_INT:
+ if (!TARGET_64BIT)
+ return UINTVAL (op) <= HOST_WIDE_INT_UC (0xffffffff);
+ return UINTVAL (op) <= HOST_WIDE_INT_UC (0x7fffffff);
+
+ case CONST_WIDE_INT:
+ if (!TARGET_64BIT)
+ return false;
+ return (CONST_WIDE_INT_NUNITS (op) == 2
+ && CONST_WIDE_INT_ELT (op, 1) == 0
+ && (trunc_int_for_mode (CONST_WIDE_INT_ELT (op, 0), SImode)
+ == (HOST_WIDE_INT) CONST_WIDE_INT_ELT (op, 0)));
+
+ default:
+ gcc_unreachable ();
+ }
+})
+
;; Return true if size of VALUE can be stored in a sign
;; extended immediate field.
(define_predicate "x86_64_immediate_size_operand"
@@ -1042,7 +1067,7 @@
(define_predicate "SImode_address_operand"
(match_code "subreg,zero_extend,and"))
-;; Return true if op if a valid address for LEA, and does not contain
+;; Return true if op is a valid address for LEA, and does not contain
;; a segment override. Defined as a special predicate to allow
;; mode-less const_int operands pass to address_operand.
(define_special_predicate "address_no_seg_operand"
@@ -1329,14 +1354,20 @@
switch (code)
{
case EQ: case NE:
+ if (inmode == CCGZmode)
+ return false;
return true;
- case LT: case GE:
+ case GE: case LT:
if (inmode == CCmode || inmode == CCGCmode
- || inmode == CCGOCmode || inmode == CCNOmode)
+ || inmode == CCGOCmode || inmode == CCNOmode || inmode == CCGZmode)
return true;
return false;
- case LTU: case GTU: case LEU: case GEU:
- if (inmode == CCmode || inmode == CCCmode)
+ case GEU: case LTU:
+ if (inmode == CCGZmode)
+ return true;
+ /* FALLTHRU */
+ case GTU: case LEU:
+ if (inmode == CCmode || inmode == CCCmode || inmode == CCGZmode)
return true;
return false;
case ORDERED: case UNORDERED:
@@ -1387,19 +1418,6 @@
(match_operand 0 "comparison_operator")
(match_operand 0 "ix86_trivial_fp_comparison_operator")))
-;; Same as above, but for swapped comparison used in *jcc<fp>_<int>_i387.
-(define_predicate "ix86_swapped_fp_comparison_operator"
- (match_operand 0 "comparison_operator")
-{
- enum rtx_code code = GET_CODE (op);
- bool ret;
-
- PUT_CODE (op, swap_condition (code));
- ret = ix86_fp_comparison_operator (op, mode);
- PUT_CODE (op, code);
- return ret;
-})
-
;; Nearly general operand, but accept any const_double, since we wish
;; to be able to drop them into memory rather than have them get pulled
;; into registers.
@@ -1423,10 +1441,6 @@
(define_predicate "plusminuslogic_operator"
(match_code "plus,minus,and,ior,xor"))
-;; Return true if this is a float extend operation.
-(define_predicate "float_operator"
- (match_code "float"))
-
;; Return true for ARITHMETIC_P.
(define_predicate "arith_or_logical_operator"
(match_code "plus,mult,and,ior,xor,smin,smax,umin,umax,compare,minus,div,
diff --git a/gcc/config/i386/sse.md b/gcc/config/i386/sse.md
index d61afcf..fe3cb17 100644
--- a/gcc/config/i386/sse.md
+++ b/gcc/config/i386/sse.md
@@ -83,9 +83,7 @@
UNSPEC_VSIBADDR
;; For AVX512F support
- UNSPEC_VPERMI2
UNSPEC_VPERMT2
- UNSPEC_VPERMI2_MASK
UNSPEC_UNSIGNED_FIX_NOTRUNC
UNSPEC_UNSIGNED_PCMP
UNSPEC_TESTM
@@ -371,10 +369,17 @@
[V16SF V16SI])
;; ??? We should probably use TImode instead.
-(define_mode_iterator VIMAX_AVX2
+(define_mode_iterator VIMAX_AVX2_AVX512BW
[(V4TI "TARGET_AVX512BW") (V2TI "TARGET_AVX2") V1TI])
-;; ??? This should probably be dropped in favor of VIMAX_AVX2.
+;; Suppose TARGET_AVX512BW as baseline
+(define_mode_iterator VIMAX_AVX512VL
+ [V4TI (V2TI "TARGET_AVX512VL") (V1TI "TARGET_AVX512VL")])
+
+(define_mode_iterator VIMAX_AVX2
+ [(V2TI "TARGET_AVX2") V1TI])
+
+;; ??? This should probably be dropped in favor of VIMAX_AVX2_AVX512BW.
(define_mode_iterator SSESCALARMODE
[(V4TI "TARGET_AVX512BW") (V2TI "TARGET_AVX2") TI])
@@ -403,11 +408,19 @@
[(V8SI "TARGET_AVX2") V4SI
(V4DI "TARGET_AVX2") V2DI])
+(define_mode_iterator VI248_AVX2
+ [(V16HI "TARGET_AVX2") V8HI
+ (V8SI "TARGET_AVX2") V4SI
+ (V4DI "TARGET_AVX2") V2DI])
+
(define_mode_iterator VI248_AVX2_8_AVX512F_24_AVX512BW
[(V32HI "TARGET_AVX512BW") (V16HI "TARGET_AVX2") V8HI
(V16SI "TARGET_AVX512BW") (V8SI "TARGET_AVX2") V4SI
(V8DI "TARGET_AVX512F") (V4DI "TARGET_AVX2") V2DI])
+(define_mode_iterator VI248_AVX512BW
+ [(V32HI "TARGET_AVX512BW") V16SI V8DI])
+
(define_mode_iterator VI248_AVX512BW_AVX512VL
[(V32HI "TARGET_AVX512BW")
(V4DI "TARGET_AVX512VL") V16SI V8DI])
@@ -418,6 +431,11 @@
V8SI V4SI
V2DI])
+(define_mode_iterator VI248_AVX512BW_2
+ [(V16HI "TARGET_AVX512BW") (V8HI "TARGET_AVX512BW")
+ V8SI V4SI
+ V4DI V2DI])
+
(define_mode_iterator VI48_AVX512F
[(V16SI "TARGET_AVX512F") V8SI V4SI
(V8DI "TARGET_AVX512F") V4DI V2DI])
@@ -978,7 +996,7 @@
(set (attr "mode")
(cond [(and (eq_attr "alternative" "1")
(match_test "TARGET_AVX512VL"))
- (const_string "XI")
+ (const_string "<sseinsnmode>")
(and (match_test "<MODE_SIZE> == 16")
(ior (match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL")
(and (eq_attr "alternative" "3")
@@ -2522,7 +2540,7 @@
(set_attr "prefix" "evex")
(set_attr "mode" "<MODE>")])
-(define_insn "reduces<mode>"
+(define_insn "reduces<mode><mask_scalar_name>"
[(set (match_operand:VF_128 0 "register_operand" "=v")
(vec_merge:VF_128
(unspec:VF_128
@@ -2533,7 +2551,7 @@
(match_dup 1)
(const_int 1)))]
"TARGET_AVX512DQ"
- "vreduce<ssescalarmodesuffix>\t{%3, %2, %1, %0|%0, %1, %2, %3}"
+ "vreduce<ssescalarmodesuffix>\t{%3, %2, %1, %0<mask_scalar_operand4>|%0<mask_scalar_operand4>, %1, %2, %3}"
[(set_attr "type" "sse")
(set_attr "prefix" "evex")
(set_attr "mode" "<MODE>")])
@@ -3700,8 +3718,7 @@
"@
vfmadd132<ssemodesuffix>\t{<round_op5>%2, %3, %0%{%4%}|%0%{%4%}, %3, %2<round_op5>}
vfmadd213<ssemodesuffix>\t{<round_op5>%3, %2, %0%{%4%}|%0%{%4%}, %2, %3<round_op5>}"
- [(set_attr "isa" "fma_avx512f,fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "<avx512>_fmadd_<mode>_mask3<round_name>"
@@ -3715,8 +3732,7 @@
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
"TARGET_AVX512F"
"vfmadd231<ssemodesuffix>\t{<round_op5>%2, %1, %0%{%4%}|%0%{%4%}, %1, %2<round_op5>}"
- [(set_attr "isa" "fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "*fma_fmsub_<mode>"
@@ -3766,8 +3782,7 @@
"@
vfmsub132<ssemodesuffix>\t{<round_op5>%2, %3, %0%{%4%}|%0%{%4%}, %3, %2<round_op5>}
vfmsub213<ssemodesuffix>\t{<round_op5>%3, %2, %0%{%4%}|%0%{%4%}, %2, %3<round_op5>}"
- [(set_attr "isa" "fma_avx512f,fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "<avx512>_fmsub_<mode>_mask3<round_name>"
@@ -3782,8 +3797,7 @@
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
"TARGET_AVX512F && <round_mode512bit_condition>"
"vfmsub231<ssemodesuffix>\t{<round_op5>%2, %1, %0%{%4%}|%0%{%4%}, %1, %2<round_op5>}"
- [(set_attr "isa" "fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "*fma_fnmadd_<mode>"
@@ -3833,8 +3847,7 @@
"@
vfnmadd132<ssemodesuffix>\t{<round_op5>%2, %3, %0%{%4%}|%0%{%4%}, %3, %2<round_op5>}
vfnmadd213<ssemodesuffix>\t{<round_op5>%3, %2, %0%{%4%}|%0%{%4%}, %2, %3<round_op5>}"
- [(set_attr "isa" "fma_avx512f,fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "<avx512>_fnmadd_<mode>_mask3<round_name>"
@@ -3849,8 +3862,7 @@
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
"TARGET_AVX512F && <round_mode512bit_condition>"
"vfnmadd231<ssemodesuffix>\t{<round_op5>%2, %1, %0%{%4%}|%0%{%4%}, %1, %2<round_op5>}"
- [(set_attr "isa" "fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "*fma_fnmsub_<mode>"
@@ -3903,8 +3915,7 @@
"@
vfnmsub132<ssemodesuffix>\t{<round_op5>%2, %3, %0%{%4%}|%0%{%4%}, %3, %2<round_op5>}
vfnmsub213<ssemodesuffix>\t{<round_op5>%3, %2, %0%{%4%}|%0%{%4%}, %2, %3<round_op5>}"
- [(set_attr "isa" "fma_avx512f,fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "<avx512>_fnmsub_<mode>_mask3<round_name>"
@@ -3920,8 +3931,7 @@
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
"TARGET_AVX512F"
"vfnmsub231<ssemodesuffix>\t{<round_op5>%2, %1, %0%{%4%}|%0%{%4%}, %1, %2<round_op5>}"
- [(set_attr "isa" "fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
;; FMA parallel floating point multiply addsub and subadd operations.
@@ -4005,8 +4015,7 @@
"@
vfmaddsub132<ssemodesuffix>\t{<round_op5>%2, %3, %0%{%4%}|%0%{%4%}, %3, %2<round_op5>}
vfmaddsub213<ssemodesuffix>\t{<round_op5>%3, %2, %0%{%4%}|%0%{%4%}, %2, %3<round_op5>}"
- [(set_attr "isa" "fma_avx512f,fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "<avx512>_fmaddsub_<mode>_mask3<round_name>"
@@ -4021,8 +4030,7 @@
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
"TARGET_AVX512F"
"vfmaddsub231<ssemodesuffix>\t{<round_op5>%2, %1, %0%{%4%}|%0%{%4%}, %1, %2<round_op5>}"
- [(set_attr "isa" "fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "*fma_fmsubadd_<mode>"
@@ -4075,8 +4083,7 @@
"@
vfmsubadd132<ssemodesuffix>\t{<round_op5>%2, %3, %0%{%4%}|%0%{%4%}, %3, %2<round_op5>}
vfmsubadd213<ssemodesuffix>\t{<round_op5>%3, %2, %0%{%4%}|%0%{%4%}, %2, %3<round_op5>}"
- [(set_attr "isa" "fma_avx512f,fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
(define_insn "<avx512>_fmsubadd_<mode>_mask3<round_name>"
@@ -4092,8 +4099,7 @@
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
"TARGET_AVX512F"
"vfmsubadd231<ssemodesuffix>\t{<round_op5>%2, %1, %0%{%4%}|%0%{%4%}, %1, %2<round_op5>}"
- [(set_attr "isa" "fma_avx512f")
- (set_attr "type" "ssemuladd")
+ [(set_attr "type" "ssemuladd")
(set_attr "mode" "<MODE>")])
;; FMA3 floating point scalar intrinsics. These merge result with
@@ -10168,8 +10174,7 @@
(const_int 12) (const_int 14)])))))]
"TARGET_AVX512F && ix86_binary_operator_ok (MULT, V16SImode, operands)"
"vpmuludq\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}"
- [(set_attr "isa" "avx512f")
- (set_attr "type" "sseimul")
+ [(set_attr "type" "sseimul")
(set_attr "prefix_extra" "1")
(set_attr "prefix" "evex")
(set_attr "mode" "XI")])
@@ -10285,8 +10290,7 @@
(const_int 12) (const_int 14)])))))]
"TARGET_AVX512F && ix86_binary_operator_ok (MULT, V16SImode, operands)"
"vpmuldq\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}"
- [(set_attr "isa" "avx512f")
- (set_attr "type" "sseimul")
+ [(set_attr "type" "sseimul")
(set_attr "prefix_extra" "1")
(set_attr "prefix" "evex")
(set_attr "mode" "XI")])
@@ -10731,65 +10735,57 @@
(const_string "0")))
(set_attr "mode" "<sseinsnmode>")])
-(define_insn "<shift_insn><mode>3<mask_name>"
- [(set (match_operand:VI2_AVX2_AVX512BW 0 "register_operand" "=x,v")
- (any_lshift:VI2_AVX2_AVX512BW
- (match_operand:VI2_AVX2_AVX512BW 1 "register_operand" "0,v")
- (match_operand:DI 2 "nonmemory_operand" "xN,vN")))]
- "TARGET_SSE2 && <mask_mode512bit_condition> && <mask_avx512bw_condition>"
- "@
- p<vshift><ssemodesuffix>\t{%2, %0|%0, %2}
- vp<vshift><ssemodesuffix>\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}"
- [(set_attr "isa" "noavx,avx")
- (set_attr "type" "sseishft")
+(define_insn "<mask_codefor><shift_insn><mode>3<mask_name>"
+ [(set (match_operand:VI248_AVX512BW_2 0 "register_operand" "=v,v")
+ (any_lshift:VI248_AVX512BW_2
+ (match_operand:VI248_AVX512BW_2 1 "nonimmediate_operand" "v,vm")
+ (match_operand:DI 2 "nonmemory_operand" "v,N")))]
+ "TARGET_AVX512VL"
+ "vp<vshift><ssemodesuffix>\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}"
+ [(set_attr "type" "sseishft")
(set (attr "length_immediate")
(if_then_else (match_operand 2 "const_int_operand")
(const_string "1")
(const_string "0")))
- (set_attr "prefix_data16" "1,*")
- (set_attr "prefix" "orig,vex")
(set_attr "mode" "<sseinsnmode>")])
-(define_insn "<shift_insn><mode>3<mask_name>"
- [(set (match_operand:VI48_AVX2 0 "register_operand" "=x,x,v")
- (any_lshift:VI48_AVX2
- (match_operand:VI48_AVX2 1 "register_operand" "0,x,v")
- (match_operand:DI 2 "nonmemory_operand" "xN,xN,vN")))]
- "TARGET_SSE2 && <mask_mode512bit_condition>"
+(define_insn "<shift_insn><mode>3"
+ [(set (match_operand:VI248_AVX2 0 "register_operand" "=x,x")
+ (any_lshift:VI248_AVX2
+ (match_operand:VI248_AVX2 1 "register_operand" "0,x")
+ (match_operand:DI 2 "nonmemory_operand" "xN,xN")))]
+ "TARGET_SSE2"
"@
p<vshift><ssemodesuffix>\t{%2, %0|%0, %2}
- vp<vshift><ssemodesuffix>\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}
- vp<vshift><ssemodesuffix>\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}"
- [(set_attr "isa" "noavx,avx,avx512bw")
+ vp<vshift><ssemodesuffix>\t{%2, %1, %0|%0, %1, %2}"
+ [(set_attr "isa" "noavx,avx")
(set_attr "type" "sseishft")
(set (attr "length_immediate")
(if_then_else (match_operand 2 "const_int_operand")
(const_string "1")
(const_string "0")))
- (set_attr "prefix_data16" "1,*,*")
- (set_attr "prefix" "orig,vex,evex")
+ (set_attr "prefix_data16" "1,*")
+ (set_attr "prefix" "orig,vex")
(set_attr "mode" "<sseinsnmode>")])
(define_insn "<shift_insn><mode>3<mask_name>"
- [(set (match_operand:VI48_512 0 "register_operand" "=v,v")
- (any_lshift:VI48_512
- (match_operand:VI48_512 1 "nonimmediate_operand" "v,m")
+ [(set (match_operand:VI248_AVX512BW 0 "register_operand" "=v,v")
+ (any_lshift:VI248_AVX512BW
+ (match_operand:VI248_AVX512BW 1 "nonimmediate_operand" "v,m")
(match_operand:DI 2 "nonmemory_operand" "vN,N")))]
- "TARGET_AVX512F && <mask_mode512bit_condition>"
+ "TARGET_AVX512F"
"vp<vshift><ssemodesuffix>\t{%2, %1, %0<mask_operand3>|%0<mask_operand3>, %1, %2}"
- [(set_attr "isa" "avx512f")
- (set_attr "type" "sseishft")
+ [(set_attr "type" "sseishft")
(set (attr "length_immediate")
(if_then_else (match_operand 2 "const_int_operand")
(const_string "1")
(const_string "0")))
- (set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
-(define_expand "vec_shl_<mode>"
+(define_expand "vec_shr_<mode>"
[(set (match_dup 3)
- (ashift:V1TI
+ (lshiftrt:V1TI
(match_operand:VI_128 1 "register_operand")
(match_operand:SI 2 "const_0_to_255_mul_8_operand")))
(set (match_operand:VI_128 0 "register_operand") (match_dup 4))]
@@ -10800,48 +10796,24 @@
operands[4] = gen_lowpart (<MODE>mode, operands[3]);
})
-(define_insn "<sse2_avx2>_ashl<mode>3"
- [(set (match_operand:VIMAX_AVX2 0 "register_operand" "=x,v")
- (ashift:VIMAX_AVX2
- (match_operand:VIMAX_AVX2 1 "register_operand" "0,v")
- (match_operand:SI 2 "const_0_to_255_mul_8_operand" "n,n")))]
- "TARGET_SSE2"
+(define_insn "avx512bw_<shift_insn><mode>3"
+ [(set (match_operand:VIMAX_AVX512VL 0 "register_operand" "=v")
+ (any_lshift:VIMAX_AVX512VL
+ (match_operand:VIMAX_AVX512VL 1 "nonimmediate_operand" "vm")
+ (match_operand:SI 2 "const_0_to_255_mul_8_operand" "n")))]
+ "TARGET_AVX512BW"
{
operands[2] = GEN_INT (INTVAL (operands[2]) / 8);
-
- switch (which_alternative)
- {
- case 0:
- return "pslldq\t{%2, %0|%0, %2}";
- case 1:
- return "vpslldq\t{%2, %1, %0|%0, %1, %2}";
- default:
- gcc_unreachable ();
- }
+ return "vp<vshift>dq\t{%2, %1, %0|%0, %1, %2}";
}
- [(set_attr "isa" "noavx,avx")
- (set_attr "type" "sseishft")
+ [(set_attr "type" "sseishft")
(set_attr "length_immediate" "1")
- (set_attr "prefix_data16" "1,*")
- (set_attr "prefix" "orig,vex")
+ (set_attr "prefix" "maybe_evex")
(set_attr "mode" "<sseinsnmode>")])
-(define_expand "vec_shr_<mode>"
- [(set (match_dup 3)
- (lshiftrt:V1TI
- (match_operand:VI_128 1 "register_operand")
- (match_operand:SI 2 "const_0_to_255_mul_8_operand")))
- (set (match_operand:VI_128 0 "register_operand") (match_dup 4))]
- "TARGET_SSE2"
-{
- operands[1] = gen_lowpart (V1TImode, operands[1]);
- operands[3] = gen_reg_rtx (V1TImode);
- operands[4] = gen_lowpart (<MODE>mode, operands[3]);
-})
-
-(define_insn "<sse2_avx2>_lshr<mode>3"
+(define_insn "<sse2_avx2>_<shift_insn><mode>3"
[(set (match_operand:VIMAX_AVX2 0 "register_operand" "=x,v")
- (lshiftrt:VIMAX_AVX2
+ (any_lshift:VIMAX_AVX2
(match_operand:VIMAX_AVX2 1 "register_operand" "0,v")
(match_operand:SI 2 "const_0_to_255_mul_8_operand" "n,n")))]
"TARGET_SSE2"
@@ -10851,9 +10823,9 @@
switch (which_alternative)
{
case 0:
- return "psrldq\t{%2, %0|%0, %2}";
+ return "p<vshift>dq\t{%2, %0|%0, %2}";
case 1:
- return "vpsrldq\t{%2, %1, %0|%0, %1, %2}";
+ return "vp<vshift>dq\t{%2, %1, %0|%0, %1, %2}";
default:
gcc_unreachable ();
}
@@ -11568,10 +11540,10 @@
"TARGET_AVX512BW")
(define_insn "*andnot<mode>3"
- [(set (match_operand:VI 0 "register_operand" "=x,v")
+ [(set (match_operand:VI 0 "register_operand" "=x,x,v")
(and:VI
- (not:VI (match_operand:VI 1 "register_operand" "0,v"))
- (match_operand:VI 2 "vector_operand" "xBm,vm")))]
+ (not:VI (match_operand:VI 1 "register_operand" "0,x,v"))
+ (match_operand:VI 2 "vector_operand" "xBm,xm,vm")))]
"TARGET_SSE"
{
static char buf[64];
@@ -11606,10 +11578,11 @@
case E_V4DImode:
case E_V4SImode:
case E_V2DImode:
- ssesuffix = TARGET_AVX512VL ? "<ssemodesuffix>" : "";
+ ssesuffix = (TARGET_AVX512VL && which_alternative == 2
+ ? "<ssemodesuffix>" : "");
break;
default:
- ssesuffix = TARGET_AVX512VL ? "q" : "";
+ ssesuffix = TARGET_AVX512VL && which_alternative == 2 ? "q" : "";
}
break;
@@ -11635,6 +11608,7 @@
ops = "%s%s\t{%%2, %%0|%%0, %%2}";
break;
case 1:
+ case 2:
ops = "v%s%s\t{%%2, %%1, %%0|%%0, %%1, %%2}";
break;
default:
@@ -11644,7 +11618,7 @@
snprintf (buf, sizeof (buf), ops, tmp, ssesuffix);
return buf;
}
- [(set_attr "isa" "noavx,avx")
+ [(set_attr "isa" "noavx,avx,avx")
(set_attr "type" "sselog")
(set (attr "prefix_data16")
(if_then_else
@@ -11652,7 +11626,7 @@
(eq_attr "mode" "TI"))
(const_string "1")
(const_string "*")))
- (set_attr "prefix" "orig,vex")
+ (set_attr "prefix" "orig,vex,evex")
(set (attr "mode")
(cond [(and (match_test "<MODE_SIZE> == 16")
(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
@@ -11697,10 +11671,10 @@
})
(define_insn "<mask_codefor><code><mode>3<mask_name>"
- [(set (match_operand:VI48_AVX_AVX512F 0 "register_operand" "=x,v")
+ [(set (match_operand:VI48_AVX_AVX512F 0 "register_operand" "=x,x,v")
(any_logic:VI48_AVX_AVX512F
- (match_operand:VI48_AVX_AVX512F 1 "vector_operand" "%0,v")
- (match_operand:VI48_AVX_AVX512F 2 "vector_operand" "xBm,vm")))]
+ (match_operand:VI48_AVX_AVX512F 1 "vector_operand" "%0,x,v")
+ (match_operand:VI48_AVX_AVX512F 2 "vector_operand" "xBm,xm,vm")))]
"TARGET_SSE && <mask_mode512bit_condition>
&& ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)"
{
@@ -11730,7 +11704,9 @@
case E_V4DImode:
case E_V4SImode:
case E_V2DImode:
- ssesuffix = TARGET_AVX512VL ? "<ssemodesuffix>" : "";
+ ssesuffix = (TARGET_AVX512VL
+ && (<mask_applied> || which_alternative == 2)
+ ? "<ssemodesuffix>" : "");
break;
default:
gcc_unreachable ();
@@ -11759,6 +11735,7 @@
ops = "%s%s\t{%%2, %%0|%%0, %%2}";
break;
case 1:
+ case 2:
ops = "v%s%s\t{%%2, %%1, %%0<mask_operand3_1>|%%0<mask_operand3_1>, %%1, %%2}";
break;
default:
@@ -11768,7 +11745,7 @@
snprintf (buf, sizeof (buf), ops, tmp, ssesuffix);
return buf;
}
- [(set_attr "isa" "noavx,avx")
+ [(set_attr "isa" "noavx,avx,avx")
(set_attr "type" "sselog")
(set (attr "prefix_data16")
(if_then_else
@@ -11776,7 +11753,7 @@
(eq_attr "mode" "TI"))
(const_string "1")
(const_string "*")))
- (set_attr "prefix" "<mask_prefix3>")
+ (set_attr "prefix" "<mask_prefix3>,evex")
(set (attr "mode")
(cond [(and (match_test "<MODE_SIZE> == 16")
(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
@@ -11795,10 +11772,10 @@
(const_string "<sseinsnmode>")))])
(define_insn "*<code><mode>3"
- [(set (match_operand:VI12_AVX_AVX512F 0 "register_operand" "=x,v")
+ [(set (match_operand:VI12_AVX_AVX512F 0 "register_operand" "=x,x,v")
(any_logic: VI12_AVX_AVX512F
- (match_operand:VI12_AVX_AVX512F 1 "vector_operand" "%0,v")
- (match_operand:VI12_AVX_AVX512F 2 "vector_operand" "xBm,vm")))]
+ (match_operand:VI12_AVX_AVX512F 1 "vector_operand" "%0,x,v")
+ (match_operand:VI12_AVX_AVX512F 2 "vector_operand" "xBm,xm,vm")))]
"TARGET_SSE && ix86_binary_operator_ok (<CODE>, <MODE>mode, operands)"
{
static char buf[64];
@@ -11827,7 +11804,7 @@
case E_V16HImode:
case E_V16QImode:
case E_V8HImode:
- ssesuffix = TARGET_AVX512VL ? "q" : "";
+ ssesuffix = TARGET_AVX512VL && which_alternative == 2 ? "q" : "";
break;
default:
gcc_unreachable ();
@@ -11853,6 +11830,7 @@
ops = "%s%s\t{%%2, %%0|%%0, %%2}";
break;
case 1:
+ case 2:
ops = "v%s%s\t{%%2, %%1, %%0|%%0, %%1, %%2}";
break;
default:
@@ -11862,7 +11840,7 @@
snprintf (buf, sizeof (buf), ops, tmp, ssesuffix);
return buf;
}
- [(set_attr "isa" "noavx,avx")
+ [(set_attr "isa" "noavx,avx,avx")
(set_attr "type" "sselog")
(set (attr "prefix_data16")
(if_then_else
@@ -11870,7 +11848,7 @@
(eq_attr "mode" "TI"))
(const_string "1")
(const_string "*")))
- (set_attr "prefix" "<mask_prefix3>")
+ (set_attr "prefix" "<mask_prefix3>,evex")
(set (attr "mode")
(cond [(and (match_test "<MODE_SIZE> == 16")
(match_test "TARGET_SSE_PACKED_SINGLE_INSN_OPTIMAL"))
@@ -18105,96 +18083,48 @@
(set_attr "prefix" "<mask_prefix>")
(set_attr "mode" "<sseinsnmode>")])
-(define_expand "<avx512>_vpermi2var<mode>3_maskz"
- [(match_operand:VI48F 0 "register_operand")
- (match_operand:VI48F 1 "register_operand")
- (match_operand:<sseintvecmode> 2 "register_operand")
- (match_operand:VI48F 3 "nonimmediate_operand")
- (match_operand:<avx512fmaskmode> 4 "register_operand")]
- "TARGET_AVX512F"
-{
- emit_insn (gen_<avx512>_vpermi2var<mode>3_maskz_1 (
- operands[0], operands[1], operands[2], operands[3],
- CONST0_RTX (<MODE>mode), operands[4]));
- DONE;
-})
-
-(define_expand "<avx512>_vpermi2var<mode>3_maskz"
- [(match_operand:VI1_AVX512VL 0 "register_operand")
- (match_operand:VI1_AVX512VL 1 "register_operand")
- (match_operand:<sseintvecmode> 2 "register_operand")
- (match_operand:VI1_AVX512VL 3 "nonimmediate_operand")
- (match_operand:<avx512fmaskmode> 4 "register_operand")]
- "TARGET_AVX512VBMI"
-{
- emit_insn (gen_<avx512>_vpermi2var<mode>3_maskz_1 (
- operands[0], operands[1], operands[2], operands[3],
- CONST0_RTX (<MODE>mode), operands[4]));
- DONE;
-})
-
-(define_expand "<avx512>_vpermi2var<mode>3_maskz"
- [(match_operand:VI2_AVX512VL 0 "register_operand")
- (match_operand:VI2_AVX512VL 1 "register_operand")
- (match_operand:<sseintvecmode> 2 "register_operand")
- (match_operand:VI2_AVX512VL 3 "nonimmediate_operand")
- (match_operand:<avx512fmaskmode> 4 "register_operand")]
- "TARGET_AVX512BW"
-{
- emit_insn (gen_<avx512>_vpermi2var<mode>3_maskz_1 (
- operands[0], operands[1], operands[2], operands[3],
- CONST0_RTX (<MODE>mode), operands[4]));
- DONE;
-})
-
-(define_insn "<avx512>_vpermi2var<mode>3<sd_maskz_name>"
- [(set (match_operand:VI48F 0 "register_operand" "=v")
- (unspec:VI48F
- [(match_operand:VI48F 1 "register_operand" "v")
- (match_operand:<sseintvecmode> 2 "register_operand" "0")
- (match_operand:VI48F 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMI2))]
+(define_mode_iterator VPERMI2
+ [V16SI V16SF V8DI V8DF
+ (V8SI "TARGET_AVX512VL") (V8SF "TARGET_AVX512VL")
+ (V4DI "TARGET_AVX512VL") (V4DF "TARGET_AVX512VL")
+ (V4SI "TARGET_AVX512VL") (V4SF "TARGET_AVX512VL")
+ (V2DI "TARGET_AVX512VL") (V2DF "TARGET_AVX512VL")
+ (V32HI "TARGET_AVX512BW") (V16HI "TARGET_AVX512BW && TARGET_AVX512VL")
+ (V8HI "TARGET_AVX512BW && TARGET_AVX512VL")
+ (V64QI "TARGET_AVX512VBMI") (V32QI "TARGET_AVX512VBMI && TARGET_AVX512VL")
+ (V16QI "TARGET_AVX512VBMI && TARGET_AVX512VL")])
+
+(define_mode_iterator VPERMI2I
+ [V16SI V8DI
+ (V8SI "TARGET_AVX512VL") (V4SI "TARGET_AVX512VL")
+ (V4DI "TARGET_AVX512VL") (V2DI "TARGET_AVX512VL")
+ (V32HI "TARGET_AVX512BW") (V16HI "TARGET_AVX512BW && TARGET_AVX512VL")
+ (V8HI "TARGET_AVX512BW && TARGET_AVX512VL")
+ (V64QI "TARGET_AVX512VBMI") (V32QI "TARGET_AVX512VBMI && TARGET_AVX512VL")
+ (V16QI "TARGET_AVX512VBMI && TARGET_AVX512VL")])
+
+(define_expand "<avx512>_vpermi2var<mode>3_mask"
+ [(set (match_operand:VPERMI2 0 "register_operand")
+ (vec_merge:VPERMI2
+ (unspec:VPERMI2
+ [(match_operand:<sseintvecmode> 2 "register_operand")
+ (match_operand:VPERMI2 1 "register_operand")
+ (match_operand:VPERMI2 3 "nonimmediate_operand")]
+ UNSPEC_VPERMT2)
+ (match_dup 5)
+ (match_operand:<avx512fmaskmode> 4 "register_operand")))]
"TARGET_AVX512F"
- "vpermi2<ssemodesuffix>\t{%3, %1, %0<sd_mask_op4>|%0<sd_mask_op4>, %1, %3}"
- [(set_attr "type" "sselog")
- (set_attr "prefix" "evex")
- (set_attr "mode" "<sseinsnmode>")])
-
-(define_insn "<avx512>_vpermi2var<mode>3<sd_maskz_name>"
- [(set (match_operand:VI1_AVX512VL 0 "register_operand" "=v")
- (unspec:VI1_AVX512VL
- [(match_operand:VI1_AVX512VL 1 "register_operand" "v")
- (match_operand:<sseintvecmode> 2 "register_operand" "0")
- (match_operand:VI1_AVX512VL 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMI2))]
- "TARGET_AVX512VBMI"
- "vpermi2<ssemodesuffix>\t{%3, %1, %0<sd_mask_op4>|%0<sd_mask_op4>, %1, %3}"
- [(set_attr "type" "sselog")
- (set_attr "prefix" "evex")
- (set_attr "mode" "<sseinsnmode>")])
-
-(define_insn "<avx512>_vpermi2var<mode>3<sd_maskz_name>"
- [(set (match_operand:VI2_AVX512VL 0 "register_operand" "=v")
- (unspec:VI2_AVX512VL
- [(match_operand:VI2_AVX512VL 1 "register_operand" "v")
- (match_operand:<sseintvecmode> 2 "register_operand" "0")
- (match_operand:VI2_AVX512VL 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMI2))]
- "TARGET_AVX512BW"
- "vpermi2<ssemodesuffix>\t{%3, %1, %0<sd_mask_op4>|%0<sd_mask_op4>, %1, %3}"
- [(set_attr "type" "sselog")
- (set_attr "prefix" "evex")
- (set_attr "mode" "<sseinsnmode>")])
-
-(define_insn "<avx512>_vpermi2var<mode>3_mask"
- [(set (match_operand:VI48F 0 "register_operand" "=v")
- (vec_merge:VI48F
- (unspec:VI48F
- [(match_operand:VI48F 1 "register_operand" "v")
- (match_operand:<sseintvecmode> 2 "register_operand" "0")
- (match_operand:VI48F 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMI2_MASK)
- (match_dup 0)
+ "operands[5] = gen_lowpart (<MODE>mode, operands[2]);")
+
+(define_insn "*<avx512>_vpermi2var<mode>3_mask"
+ [(set (match_operand:VPERMI2I 0 "register_operand" "=v")
+ (vec_merge:VPERMI2I
+ (unspec:VPERMI2I
+ [(match_operand:<sseintvecmode> 2 "register_operand" "0")
+ (match_operand:VPERMI2I 1 "register_operand" "v")
+ (match_operand:VPERMI2I 3 "nonimmediate_operand" "vm")]
+ UNSPEC_VPERMT2)
+ (match_dup 2)
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
"TARGET_AVX512F"
"vpermi2<ssemodesuffix>\t{%3, %1, %0%{%4%}|%0%{%4%}, %1, %3}"
@@ -18202,43 +18132,27 @@
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
-(define_insn "<avx512>_vpermi2var<mode>3_mask"
- [(set (match_operand:VI1_AVX512VL 0 "register_operand" "=v")
- (vec_merge:VI1_AVX512VL
- (unspec:VI1_AVX512VL
- [(match_operand:VI1_AVX512VL 1 "register_operand" "v")
- (match_operand:<sseintvecmode> 2 "register_operand" "0")
- (match_operand:VI1_AVX512VL 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMI2_MASK)
- (match_dup 0)
- (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
- "TARGET_AVX512VBMI"
- "vpermi2<ssemodesuffix>\t{%3, %1, %0%{%4%}|%0%{%4%}, %1, %3}"
- [(set_attr "type" "sselog")
- (set_attr "prefix" "evex")
- (set_attr "mode" "<sseinsnmode>")])
-
-(define_insn "<avx512>_vpermi2var<mode>3_mask"
- [(set (match_operand:VI2_AVX512VL 0 "register_operand" "=v")
- (vec_merge:VI2_AVX512VL
- (unspec:VI2_AVX512VL
- [(match_operand:VI2_AVX512VL 1 "register_operand" "v")
- (match_operand:<sseintvecmode> 2 "register_operand" "0")
- (match_operand:VI2_AVX512VL 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMI2_MASK)
- (match_dup 0)
+(define_insn "*<avx512>_vpermi2var<mode>3_mask"
+ [(set (match_operand:VF_AVX512VL 0 "register_operand" "=v")
+ (vec_merge:VF_AVX512VL
+ (unspec:VF_AVX512VL
+ [(match_operand:<sseintvecmode> 2 "register_operand" "0")
+ (match_operand:VF_AVX512VL 1 "register_operand" "v")
+ (match_operand:VF_AVX512VL 3 "nonimmediate_operand" "vm")]
+ UNSPEC_VPERMT2)
+ (subreg:VF_AVX512VL (match_dup 2) 0)
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
- "TARGET_AVX512BW"
+ "TARGET_AVX512F"
"vpermi2<ssemodesuffix>\t{%3, %1, %0%{%4%}|%0%{%4%}, %1, %3}"
[(set_attr "type" "sselog")
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
(define_expand "<avx512>_vpermt2var<mode>3_maskz"
- [(match_operand:VI48F 0 "register_operand")
+ [(match_operand:VPERMI2 0 "register_operand")
(match_operand:<sseintvecmode> 1 "register_operand")
- (match_operand:VI48F 2 "register_operand")
- (match_operand:VI48F 3 "nonimmediate_operand")
+ (match_operand:VPERMI2 2 "register_operand")
+ (match_operand:VPERMI2 3 "nonimmediate_operand")
(match_operand:<avx512fmaskmode> 4 "register_operand")]
"TARGET_AVX512F"
{
@@ -18248,80 +18162,28 @@
DONE;
})
-(define_expand "<avx512>_vpermt2var<mode>3_maskz"
- [(match_operand:VI1_AVX512VL 0 "register_operand")
- (match_operand:<sseintvecmode> 1 "register_operand")
- (match_operand:VI1_AVX512VL 2 "register_operand")
- (match_operand:VI1_AVX512VL 3 "nonimmediate_operand")
- (match_operand:<avx512fmaskmode> 4 "register_operand")]
- "TARGET_AVX512VBMI"
-{
- emit_insn (gen_<avx512>_vpermt2var<mode>3_maskz_1 (
- operands[0], operands[1], operands[2], operands[3],
- CONST0_RTX (<MODE>mode), operands[4]));
- DONE;
-})
-
-(define_expand "<avx512>_vpermt2var<mode>3_maskz"
- [(match_operand:VI2_AVX512VL 0 "register_operand")
- (match_operand:<sseintvecmode> 1 "register_operand")
- (match_operand:VI2_AVX512VL 2 "register_operand")
- (match_operand:VI2_AVX512VL 3 "nonimmediate_operand")
- (match_operand:<avx512fmaskmode> 4 "register_operand")]
- "TARGET_AVX512BW"
-{
- emit_insn (gen_<avx512>_vpermt2var<mode>3_maskz_1 (
- operands[0], operands[1], operands[2], operands[3],
- CONST0_RTX (<MODE>mode), operands[4]));
- DONE;
-})
-
(define_insn "<avx512>_vpermt2var<mode>3<sd_maskz_name>"
- [(set (match_operand:VI48F 0 "register_operand" "=v")
- (unspec:VI48F
- [(match_operand:<sseintvecmode> 1 "register_operand" "v")
- (match_operand:VI48F 2 "register_operand" "0")
- (match_operand:VI48F 3 "nonimmediate_operand" "vm")]
+ [(set (match_operand:VPERMI2 0 "register_operand" "=v,v")
+ (unspec:VPERMI2
+ [(match_operand:<sseintvecmode> 1 "register_operand" "v,0")
+ (match_operand:VPERMI2 2 "register_operand" "0,v")
+ (match_operand:VPERMI2 3 "nonimmediate_operand" "vm,vm")]
UNSPEC_VPERMT2))]
"TARGET_AVX512F"
- "vpermt2<ssemodesuffix>\t{%3, %1, %0<sd_mask_op4>|%0<sd_mask_op4>, %1, %3}"
- [(set_attr "type" "sselog")
- (set_attr "prefix" "evex")
- (set_attr "mode" "<sseinsnmode>")])
-
-(define_insn "<avx512>_vpermt2var<mode>3<sd_maskz_name>"
- [(set (match_operand:VI1_AVX512VL 0 "register_operand" "=v")
- (unspec:VI1_AVX512VL
- [(match_operand:<sseintvecmode> 1 "register_operand" "v")
- (match_operand:VI1_AVX512VL 2 "register_operand" "0")
- (match_operand:VI1_AVX512VL 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMT2))]
- "TARGET_AVX512VBMI"
- "vpermt2<ssemodesuffix>\t{%3, %1, %0<sd_mask_op4>|%0<sd_mask_op4>, %1, %3}"
- [(set_attr "type" "sselog")
- (set_attr "prefix" "evex")
- (set_attr "mode" "<sseinsnmode>")])
-
-(define_insn "<avx512>_vpermt2var<mode>3<sd_maskz_name>"
- [(set (match_operand:VI2_AVX512VL 0 "register_operand" "=v")
- (unspec:VI2_AVX512VL
- [(match_operand:<sseintvecmode> 1 "register_operand" "v")
- (match_operand:VI2_AVX512VL 2 "register_operand" "0")
- (match_operand:VI2_AVX512VL 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMT2))]
- "TARGET_AVX512BW"
- "vpermt2<ssemodesuffix>\t{%3, %1, %0<sd_mask_op4>|%0<sd_mask_op4>, %1, %3}"
+ "@
+ vpermt2<ssemodesuffix>\t{%3, %1, %0<sd_mask_op4>|%0<sd_mask_op4>, %1, %3}
+ vpermi2<ssemodesuffix>\t{%3, %2, %0<sd_mask_op4>|%0<sd_mask_op4>, %2, %3}"
[(set_attr "type" "sselog")
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
(define_insn "<avx512>_vpermt2var<mode>3_mask"
- [(set (match_operand:VI48F 0 "register_operand" "=v")
- (vec_merge:VI48F
- (unspec:VI48F
+ [(set (match_operand:VPERMI2 0 "register_operand" "=v")
+ (vec_merge:VPERMI2
+ (unspec:VPERMI2
[(match_operand:<sseintvecmode> 1 "register_operand" "v")
- (match_operand:VI48F 2 "register_operand" "0")
- (match_operand:VI48F 3 "nonimmediate_operand" "vm")]
+ (match_operand:VPERMI2 2 "register_operand" "0")
+ (match_operand:VPERMI2 3 "nonimmediate_operand" "vm")]
UNSPEC_VPERMT2)
(match_dup 2)
(match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
@@ -18331,38 +18193,6 @@
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
-(define_insn "<avx512>_vpermt2var<mode>3_mask"
- [(set (match_operand:VI1_AVX512VL 0 "register_operand" "=v")
- (vec_merge:VI1_AVX512VL
- (unspec:VI1_AVX512VL
- [(match_operand:<sseintvecmode> 1 "register_operand" "v")
- (match_operand:VI1_AVX512VL 2 "register_operand" "0")
- (match_operand:VI1_AVX512VL 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMT2)
- (match_dup 2)
- (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
- "TARGET_AVX512VBMI"
- "vpermt2<ssemodesuffix>\t{%3, %1, %0%{%4%}|%0%{%4%}, %1, %3}"
- [(set_attr "type" "sselog")
- (set_attr "prefix" "evex")
- (set_attr "mode" "<sseinsnmode>")])
-
-(define_insn "<avx512>_vpermt2var<mode>3_mask"
- [(set (match_operand:VI2_AVX512VL 0 "register_operand" "=v")
- (vec_merge:VI2_AVX512VL
- (unspec:VI2_AVX512VL
- [(match_operand:<sseintvecmode> 1 "register_operand" "v")
- (match_operand:VI2_AVX512VL 2 "register_operand" "0")
- (match_operand:VI2_AVX512VL 3 "nonimmediate_operand" "vm")]
- UNSPEC_VPERMT2)
- (match_dup 2)
- (match_operand:<avx512fmaskmode> 4 "register_operand" "Yk")))]
- "TARGET_AVX512BW"
- "vpermt2<ssemodesuffix>\t{%3, %1, %0%{%4%}|%0%{%4%}, %1, %3}"
- [(set_attr "type" "sselog")
- (set_attr "prefix" "evex")
- (set_attr "mode" "<sseinsnmode>")])
-
(define_expand "avx_vperm2f128<mode>3"
[(set (match_operand:AVX256MODE2P 0 "register_operand")
(unspec:AVX256MODE2P
@@ -19619,8 +19449,7 @@
UNSPEC_DBPSADBW))]
"TARGET_AVX512BW"
"vdbpsadbw\t{%3, %2, %1, %0<mask_operand4>|%0<mask_operand4>, %1, %2, %3}"
- [(set_attr "isa" "avx")
- (set_attr "type" "sselog1")
+ [(set_attr "type" "sselog1")
(set_attr "length_immediate" "1")
(set_attr "prefix" "evex")
(set_attr "mode" "<sseinsnmode>")])
diff --git a/gcc/config/i386/subst.md b/gcc/config/i386/subst.md
index a318a8d..c93a526 100644
--- a/gcc/config/i386/subst.md
+++ b/gcc/config/i386/subst.md
@@ -62,8 +62,8 @@
(define_subst_attr "store_mask_predicate" "mask" "nonimmediate_operand" "register_operand")
(define_subst_attr "mask_prefix" "mask" "vex" "evex")
(define_subst_attr "mask_prefix2" "mask" "maybe_vex" "evex")
-(define_subst_attr "mask_prefix3" "mask" "orig,vex" "evex")
-(define_subst_attr "mask_prefix4" "mask" "orig,orig,vex" "evex")
+(define_subst_attr "mask_prefix3" "mask" "orig,vex" "evex,evex")
+(define_subst_attr "mask_prefix4" "mask" "orig,orig,vex" "evex,evex,evex")
(define_subst_attr "mask_expand_op3" "mask" "3" "5")
(define_subst "mask"
diff --git a/gcc/config/i386/sync.md b/gcc/config/i386/sync.md
index 29b82f8..eceaa73 100644
--- a/gcc/config/i386/sync.md
+++ b/gcc/config/i386/sync.md
@@ -219,29 +219,71 @@
(set (match_operand:DI 2 "memory_operand")
(unspec:DI [(match_dup 0)]
UNSPEC_FIST_ATOMIC))
- (set (match_operand:DF 3 "fp_register_operand")
+ (set (match_operand:DF 3 "any_fp_register_operand")
(match_operand:DF 4 "memory_operand"))]
"!TARGET_64BIT
&& peep2_reg_dead_p (2, operands[0])
- && rtx_equal_p (operands[4], adjust_address_nv (operands[2], DFmode, 0))"
+ && rtx_equal_p (XEXP (operands[4], 0), XEXP (operands[2], 0))"
[(set (match_dup 3) (match_dup 5))]
"operands[5] = gen_lowpart (DFmode, operands[1]);")
(define_peephole2
+ [(set (match_operand:DF 0 "fp_register_operand")
+ (unspec:DF [(match_operand:DI 1 "memory_operand")]
+ UNSPEC_FILD_ATOMIC))
+ (set (match_operand:DI 2 "memory_operand")
+ (unspec:DI [(match_dup 0)]
+ UNSPEC_FIST_ATOMIC))
+ (set (mem:BLK (scratch:SI))
+ (unspec:BLK [(mem:BLK (scratch:SI))] UNSPEC_MEMORY_BLOCKAGE))
+ (set (match_operand:DF 3 "any_fp_register_operand")
+ (match_operand:DF 4 "memory_operand"))]
+ "!TARGET_64BIT
+ && peep2_reg_dead_p (2, operands[0])
+ && rtx_equal_p (XEXP (operands[4], 0), XEXP (operands[2], 0))"
+ [(const_int 0)]
+{
+ emit_move_insn (operands[3], gen_lowpart (DFmode, operands[1]));
+ emit_insn (gen_memory_blockage ());
+ DONE;
+})
+
+(define_peephole2
[(set (match_operand:DF 0 "sse_reg_operand")
(unspec:DF [(match_operand:DI 1 "memory_operand")]
UNSPEC_LDX_ATOMIC))
(set (match_operand:DI 2 "memory_operand")
(unspec:DI [(match_dup 0)]
UNSPEC_STX_ATOMIC))
- (set (match_operand:DF 3 "fp_register_operand")
+ (set (match_operand:DF 3 "any_fp_register_operand")
(match_operand:DF 4 "memory_operand"))]
"!TARGET_64BIT
&& peep2_reg_dead_p (2, operands[0])
- && rtx_equal_p (operands[4], adjust_address_nv (operands[2], DFmode, 0))"
+ && rtx_equal_p (XEXP (operands[4], 0), XEXP (operands[2], 0))"
[(set (match_dup 3) (match_dup 5))]
"operands[5] = gen_lowpart (DFmode, operands[1]);")
+(define_peephole2
+ [(set (match_operand:DF 0 "sse_reg_operand")
+ (unspec:DF [(match_operand:DI 1 "memory_operand")]
+ UNSPEC_LDX_ATOMIC))
+ (set (match_operand:DI 2 "memory_operand")
+ (unspec:DI [(match_dup 0)]
+ UNSPEC_STX_ATOMIC))
+ (set (mem:BLK (scratch:SI))
+ (unspec:BLK [(mem:BLK (scratch:SI))] UNSPEC_MEMORY_BLOCKAGE))
+ (set (match_operand:DF 3 "any_fp_register_operand")
+ (match_operand:DF 4 "memory_operand"))]
+ "!TARGET_64BIT
+ && peep2_reg_dead_p (2, operands[0])
+ && rtx_equal_p (XEXP (operands[4], 0), XEXP (operands[2], 0))"
+ [(const_int 0)]
+{
+ emit_move_insn (operands[3], gen_lowpart (DFmode, operands[1]));
+ emit_insn (gen_memory_blockage ());
+ DONE;
+})
+
(define_expand "atomic_store<mode>"
[(set (match_operand:ATOMIC 0 "memory_operand")
(unspec:ATOMIC [(match_operand:ATOMIC 1 "nonimmediate_operand")
@@ -331,7 +373,7 @@
(define_peephole2
[(set (match_operand:DF 0 "memory_operand")
- (match_operand:DF 1 "fp_register_operand"))
+ (match_operand:DF 1 "any_fp_register_operand"))
(set (match_operand:DF 2 "fp_register_operand")
(unspec:DF [(match_operand:DI 3 "memory_operand")]
UNSPEC_FILD_ATOMIC))
@@ -340,13 +382,34 @@
UNSPEC_FIST_ATOMIC))]
"!TARGET_64BIT
&& peep2_reg_dead_p (3, operands[2])
- && rtx_equal_p (operands[0], adjust_address_nv (operands[3], DFmode, 0))"
+ && rtx_equal_p (XEXP (operands[0], 0), XEXP (operands[3], 0))"
[(set (match_dup 5) (match_dup 1))]
"operands[5] = gen_lowpart (DFmode, operands[4]);")
(define_peephole2
[(set (match_operand:DF 0 "memory_operand")
- (match_operand:DF 1 "fp_register_operand"))
+ (match_operand:DF 1 "any_fp_register_operand"))
+ (set (mem:BLK (scratch:SI))
+ (unspec:BLK [(mem:BLK (scratch:SI))] UNSPEC_MEMORY_BLOCKAGE))
+ (set (match_operand:DF 2 "fp_register_operand")
+ (unspec:DF [(match_operand:DI 3 "memory_operand")]
+ UNSPEC_FILD_ATOMIC))
+ (set (match_operand:DI 4 "memory_operand")
+ (unspec:DI [(match_dup 2)]
+ UNSPEC_FIST_ATOMIC))]
+ "!TARGET_64BIT
+ && peep2_reg_dead_p (4, operands[2])
+ && rtx_equal_p (XEXP (operands[0], 0), XEXP (operands[3], 0))"
+ [(const_int 0)]
+{
+ emit_insn (gen_memory_blockage ());
+ emit_move_insn (gen_lowpart (DFmode, operands[4]), operands[1]);
+ DONE;
+})
+
+(define_peephole2
+ [(set (match_operand:DF 0 "memory_operand")
+ (match_operand:DF 1 "any_fp_register_operand"))
(set (match_operand:DF 2 "sse_reg_operand")
(unspec:DF [(match_operand:DI 3 "memory_operand")]
UNSPEC_LDX_ATOMIC))
@@ -355,10 +418,31 @@
UNSPEC_STX_ATOMIC))]
"!TARGET_64BIT
&& peep2_reg_dead_p (3, operands[2])
- && rtx_equal_p (operands[0], adjust_address_nv (operands[3], DFmode, 0))"
+ && rtx_equal_p (XEXP (operands[0], 0), XEXP (operands[3], 0))"
[(set (match_dup 5) (match_dup 1))]
"operands[5] = gen_lowpart (DFmode, operands[4]);")
+(define_peephole2
+ [(set (match_operand:DF 0 "memory_operand")
+ (match_operand:DF 1 "any_fp_register_operand"))
+ (set (mem:BLK (scratch:SI))
+ (unspec:BLK [(mem:BLK (scratch:SI))] UNSPEC_MEMORY_BLOCKAGE))
+ (set (match_operand:DF 2 "sse_reg_operand")
+ (unspec:DF [(match_operand:DI 3 "memory_operand")]
+ UNSPEC_LDX_ATOMIC))
+ (set (match_operand:DI 4 "memory_operand")
+ (unspec:DI [(match_dup 2)]
+ UNSPEC_STX_ATOMIC))]
+ "!TARGET_64BIT
+ && peep2_reg_dead_p (4, operands[2])
+ && rtx_equal_p (XEXP (operands[0], 0), XEXP (operands[3], 0))"
+ [(const_int 0)]
+{
+ emit_insn (gen_memory_blockage ());
+ emit_move_insn (gen_lowpart (DFmode, operands[4]), operands[1]);
+ DONE;
+})
+
;; ??? You'd think that we'd be able to perform this via FLOAT + FIX_TRUNC
;; operations. But the fix_trunc patterns want way more setup than we want
;; to provide. Note that the scratch is DFmode instead of XFmode in order
diff --git a/gcc/config/i386/t-cet b/gcc/config/i386/t-cet
new file mode 100644
index 0000000..317f30d
--- /dev/null
+++ b/gcc/config/i386/t-cet
@@ -0,0 +1,21 @@
+# Copyright (C) 2017 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
+# <http://www.gnu.org/licenses/>.
+
+cet.o: $(srcdir)/config/i386/cet.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
diff --git a/gcc/config/i386/t-i386 b/gcc/config/i386/t-i386
index 0a8524b..8411a96 100644
--- a/gcc/config/i386/t-i386
+++ b/gcc/config/i386/t-i386
@@ -24,6 +24,22 @@ i386-c.o: $(srcdir)/config/i386/i386-c.c
$(COMPILE) $<
$(POSTCOMPILE)
+x86-tune-sched.o: $(srcdir)/config/i386/x86-tune-sched.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+x86-tune-sched-bd.o: $(srcdir)/config/i386/x86-tune-sched-bd.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+x86-tune-sched-atom.o: $(srcdir)/config/i386/x86-tune-sched-atom.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
+x86-tune-sched-core.o: $(srcdir)/config/i386/x86-tune-sched-core.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
+
i386.o: i386-builtin-types.inc
i386-builtin-types.inc: s-i386-bt ; @true
diff --git a/gcc/config/i386/x86-tune-costs.h b/gcc/config/i386/x86-tune-costs.h
new file mode 100644
index 0000000..e31d7ce
--- /dev/null
+++ b/gcc/config/i386/x86-tune-costs.h
@@ -0,0 +1,2272 @@
+/* Costs of operations of individual x86 CPUs.
+ Copyright (C) 1988-2017 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
+<http://www.gnu.org/licenses/>. */
+/* Processor costs (relative to an add) */
+/* We assume COSTS_N_INSNS is defined as (N)*4 and an addition is 2 bytes. */
+#define COSTS_N_BYTES(N) ((N) * 2)
+
+#define DUMMY_STRINGOP_ALGS {libcall, {{-1, libcall, false}}}
+
+static stringop_algs ix86_size_memcpy[2] = {
+ {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}},
+ {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}}};
+static stringop_algs ix86_size_memset[2] = {
+ {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}},
+ {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}}};
+
+const
+struct processor_costs ix86_size_cost = {/* costs for tuning for size */
+ COSTS_N_BYTES (2), /* cost of an add instruction */
+ COSTS_N_BYTES (3), /* cost of a lea instruction */
+ COSTS_N_BYTES (2), /* variable shift costs */
+ COSTS_N_BYTES (3), /* constant shift costs */
+ {COSTS_N_BYTES (3), /* cost of starting multiply for QI */
+ COSTS_N_BYTES (3), /* HI */
+ COSTS_N_BYTES (3), /* SI */
+ COSTS_N_BYTES (3), /* DI */
+ COSTS_N_BYTES (5)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_BYTES (3), /* cost of a divide/mod for QI */
+ COSTS_N_BYTES (3), /* HI */
+ COSTS_N_BYTES (3), /* SI */
+ COSTS_N_BYTES (3), /* DI */
+ COSTS_N_BYTES (5)}, /* other */
+ COSTS_N_BYTES (3), /* cost of movsx */
+ COSTS_N_BYTES (3), /* cost of movzx */
+ 0, /* "large" insn */
+ 2, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2. */
+ 2, /* cost for loading QImode using movzbl */
+ {2, 2, 2}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 2, 2}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {2, 2, 2}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {2, 2, 2}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 3, /* cost of moving MMX register */
+ {3, 3}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {3, 3}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 3, 3, 3, /* cost of moving XMM,YMM,ZMM register */
+ {3, 3, 3, 3, 3}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {3, 3, 3, 3, 3}, /* cost of unaligned SSE load
+ in 128bit, 256bit and 512bit */
+ {3, 3, 3, 3, 3}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {3, 3, 3, 3, 3}, /* cost of unaligned SSE store
+ in 128bit, 256bit and 512bit */
+ 3, 3, /* SSE->integer and integer->SSE moves */
+ 0, /* size of l1 cache */
+ 0, /* size of l2 cache */
+ 0, /* size of prefetch block */
+ 0, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_BYTES (2), /* cost of FADD and FSUB insns. */
+ COSTS_N_BYTES (2), /* cost of FMUL instruction. */
+ COSTS_N_BYTES (2), /* cost of FDIV instruction. */
+ COSTS_N_BYTES (2), /* cost of FABS instruction. */
+ COSTS_N_BYTES (2), /* cost of FCHS instruction. */
+ COSTS_N_BYTES (2), /* cost of FSQRT instruction. */
+
+ COSTS_N_BYTES (2), /* cost of cheap SSE instruction. */
+ COSTS_N_BYTES (2), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_BYTES (2), /* cost of MULSS instruction. */
+ COSTS_N_BYTES (2), /* cost of MULSD instruction. */
+ COSTS_N_BYTES (2), /* cost of FMA SS instruction. */
+ COSTS_N_BYTES (2), /* cost of FMA SD instruction. */
+ COSTS_N_BYTES (2), /* cost of DIVSS instruction. */
+ COSTS_N_BYTES (2), /* cost of DIVSD instruction. */
+ COSTS_N_BYTES (2), /* cost of SQRTSS instruction. */
+ COSTS_N_BYTES (2), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ ix86_size_memcpy,
+ ix86_size_memset,
+ COSTS_N_BYTES (1), /* cond_taken_branch_cost. */
+ COSTS_N_BYTES (1), /* cond_not_taken_branch_cost. */
+};
+
+/* Processor costs (relative to an add) */
+static stringop_algs i386_memcpy[2] = {
+ {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}},
+ DUMMY_STRINGOP_ALGS};
+static stringop_algs i386_memset[2] = {
+ {rep_prefix_1_byte, {{-1, rep_prefix_1_byte, false}}},
+ DUMMY_STRINGOP_ALGS};
+
+static const
+struct processor_costs i386_cost = { /* 386 specific costs */
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (3), /* variable shift costs */
+ COSTS_N_INSNS (2), /* constant shift costs */
+ {COSTS_N_INSNS (6), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (6), /* HI */
+ COSTS_N_INSNS (6), /* SI */
+ COSTS_N_INSNS (6), /* DI */
+ COSTS_N_INSNS (6)}, /* other */
+ COSTS_N_INSNS (1), /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (23), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (23), /* HI */
+ COSTS_N_INSNS (23), /* SI */
+ COSTS_N_INSNS (23), /* DI */
+ COSTS_N_INSNS (23)}, /* other */
+ COSTS_N_INSNS (3), /* cost of movsx */
+ COSTS_N_INSNS (2), /* cost of movzx */
+ 15, /* "large" insn */
+ 3, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 4, /* cost for loading QImode using movzbl */
+ {2, 4, 2}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 4, 2}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {8, 8, 8}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {8, 8, 8}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {4, 8}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {4, 8}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {4, 8, 16, 32, 64}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned loads. */
+ {4, 8, 16, 32, 64}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned stores. */
+ 3, 3, /* SSE->integer and integer->SSE moves */
+ 0, /* size of l1 cache */
+ 0, /* size of l2 cache */
+ 0, /* size of prefetch block */
+ 0, /* number of parallel prefetches */
+ 1, /* Branch cost */
+ COSTS_N_INSNS (23), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (27), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (88), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (22), /* cost of FABS instruction. */
+ COSTS_N_INSNS (24), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (122), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (23), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (27), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (27), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (27), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (27), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (88), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (88), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (122), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (122), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ i386_memcpy,
+ i386_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs i486_memcpy[2] = {
+ {rep_prefix_4_byte, {{-1, rep_prefix_4_byte, false}}},
+ DUMMY_STRINGOP_ALGS};
+static stringop_algs i486_memset[2] = {
+ {rep_prefix_4_byte, {{-1, rep_prefix_4_byte, false}}},
+ DUMMY_STRINGOP_ALGS};
+
+static const
+struct processor_costs i486_cost = { /* 486 specific costs */
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (3), /* variable shift costs */
+ COSTS_N_INSNS (2), /* constant shift costs */
+ {COSTS_N_INSNS (12), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (12), /* HI */
+ COSTS_N_INSNS (12), /* SI */
+ COSTS_N_INSNS (12), /* DI */
+ COSTS_N_INSNS (12)}, /* other */
+ 1, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (40), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (40), /* HI */
+ COSTS_N_INSNS (40), /* SI */
+ COSTS_N_INSNS (40), /* DI */
+ COSTS_N_INSNS (40)}, /* other */
+ COSTS_N_INSNS (3), /* cost of movsx */
+ COSTS_N_INSNS (2), /* cost of movzx */
+ 15, /* "large" insn */
+ 3, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 4, /* cost for loading QImode using movzbl */
+ {2, 4, 2}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 4, 2}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {8, 8, 8}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {8, 8, 8}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {4, 8}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {4, 8}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {4, 8, 16, 32, 64}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned loads. */
+ {4, 8, 16, 32, 64}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned stores. */
+ 3, 3, /* SSE->integer and integer->SSE moves */
+ 4, /* size of l1 cache. 486 has 8kB cache
+ shared for code and data, so 4kB is
+ not really precise. */
+ 4, /* size of l2 cache */
+ 0, /* size of prefetch block */
+ 0, /* number of parallel prefetches */
+ 1, /* Branch cost */
+ COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (16), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (73), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (3), /* cost of FABS instruction. */
+ COSTS_N_INSNS (3), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (83), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (8), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (16), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (16), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (16), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (16), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (73), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (74), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (83), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (83), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ i486_memcpy,
+ i486_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs pentium_memcpy[2] = {
+ {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+static stringop_algs pentium_memset[2] = {
+ {libcall, {{-1, rep_prefix_4_byte, false}}},
+ DUMMY_STRINGOP_ALGS};
+
+static const
+struct processor_costs pentium_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (4), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (11), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (11), /* HI */
+ COSTS_N_INSNS (11), /* SI */
+ COSTS_N_INSNS (11), /* DI */
+ COSTS_N_INSNS (11)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (25), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (25), /* HI */
+ COSTS_N_INSNS (25), /* SI */
+ COSTS_N_INSNS (25), /* DI */
+ COSTS_N_INSNS (25)}, /* other */
+ COSTS_N_INSNS (3), /* cost of movsx */
+ COSTS_N_INSNS (2), /* cost of movzx */
+ 8, /* "large" insn */
+ 6, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 6, /* cost for loading QImode using movzbl */
+ {2, 4, 2}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 4, 2}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {2, 2, 6}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {4, 4, 6}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 8, /* cost of moving MMX register */
+ {8, 8}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {8, 8}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {4, 8, 16, 32, 64}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned loads. */
+ {4, 8, 16, 32, 64}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned stores. */
+ 3, 3, /* SSE->integer and integer->SSE moves */
+ 8, /* size of l1 cache. */
+ 8, /* size of l2 cache */
+ 0, /* size of prefetch block */
+ 0, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (3), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (39), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (1), /* cost of FABS instruction. */
+ COSTS_N_INSNS (1), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (70), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (3), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (3), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (39), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (39), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (70), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (70), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ pentium_memcpy,
+ pentium_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static const
+struct processor_costs lakemont_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (11), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (11), /* HI */
+ COSTS_N_INSNS (11), /* SI */
+ COSTS_N_INSNS (11), /* DI */
+ COSTS_N_INSNS (11)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (25), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (25), /* HI */
+ COSTS_N_INSNS (25), /* SI */
+ COSTS_N_INSNS (25), /* DI */
+ COSTS_N_INSNS (25)}, /* other */
+ COSTS_N_INSNS (3), /* cost of movsx */
+ COSTS_N_INSNS (2), /* cost of movzx */
+ 8, /* "large" insn */
+ 17, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 6, /* cost for loading QImode using movzbl */
+ {2, 4, 2}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 4, 2}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {2, 2, 6}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {4, 4, 6}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 8, /* cost of moving MMX register */
+ {8, 8}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {8, 8}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {4, 8, 16, 32, 64}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned loads. */
+ {4, 8, 16, 32, 64}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned stores. */
+ 3, 3, /* SSE->integer and integer->SSE moves */
+ 8, /* size of l1 cache. */
+ 8, /* size of l2 cache */
+ 0, /* size of prefetch block */
+ 0, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (3), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (39), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (1), /* cost of FABS instruction. */
+ COSTS_N_INSNS (1), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (70), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (5), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (5), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (5), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (10), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (10), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (31), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (60), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (31), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (63), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ pentium_memcpy,
+ pentium_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+/* PentiumPro has optimized rep instructions for blocks aligned by 8 bytes
+ (we ensure the alignment). For small blocks inline loop is still a
+ noticeable win, for bigger blocks either rep movsl or rep movsb is
+ way to go. Rep movsb has apparently more expensive startup time in CPU,
+ but after 4K the difference is down in the noise. */
+static stringop_algs pentiumpro_memcpy[2] = {
+ {rep_prefix_4_byte, {{128, loop, false}, {1024, unrolled_loop, false},
+ {8192, rep_prefix_4_byte, false},
+ {-1, rep_prefix_1_byte, false}}},
+ DUMMY_STRINGOP_ALGS};
+static stringop_algs pentiumpro_memset[2] = {
+ {rep_prefix_4_byte, {{1024, unrolled_loop, false},
+ {8192, rep_prefix_4_byte, false},
+ {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+static const
+struct processor_costs pentiumpro_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (4), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (4)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (17), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (17), /* HI */
+ COSTS_N_INSNS (17), /* SI */
+ COSTS_N_INSNS (17), /* DI */
+ COSTS_N_INSNS (17)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 6, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 2, /* cost for loading QImode using movzbl */
+ {4, 4, 4}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 2, 2}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {2, 2, 6}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {4, 4, 6}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {2, 2}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {2, 2}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {4, 8, 16, 32, 64}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned loads. */
+ {4, 8, 16, 32, 64}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 8, 16, 32, 64}, /* cost of unaligned stores. */
+ 3, 3, /* SSE->integer and integer->SSE moves */
+ 8, /* size of l1 cache. */
+ 256, /* size of l2 cache */
+ 32, /* size of prefetch block */
+ 6, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (5), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (56), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (56), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (4), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (4), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (7), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (7), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (18), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (18), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (31), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (31), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ pentiumpro_memcpy,
+ pentiumpro_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs geode_memcpy[2] = {
+ {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+static stringop_algs geode_memset[2] = {
+ {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+static const
+struct processor_costs geode_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (2), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (7), /* SI */
+ COSTS_N_INSNS (7), /* DI */
+ COSTS_N_INSNS (7)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (15), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (23), /* HI */
+ COSTS_N_INSNS (39), /* SI */
+ COSTS_N_INSNS (39), /* DI */
+ COSTS_N_INSNS (39)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 4, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 2, /* cost for loading QImode using movzbl */
+ {2, 2, 2}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 2, 2}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {2, 2, 2}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {4, 6, 6}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+
+ 2, /* cost of moving MMX register */
+ {2, 2}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {2, 2}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {2, 2, 8, 16, 32}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {2, 2, 8, 16, 32}, /* cost of unaligned loads. */
+ {2, 2, 8, 16, 32}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {2, 2, 8, 16, 32}, /* cost of unaligned stores. */
+ 6, 6, /* SSE->integer and integer->SSE moves */
+ 64, /* size of l1 cache. */
+ 128, /* size of l2 cache. */
+ 32, /* size of prefetch block */
+ 1, /* number of parallel prefetches */
+ 1, /* Branch cost */
+ COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (11), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (47), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (1), /* cost of FABS instruction. */
+ COSTS_N_INSNS (1), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (54), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (6), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (11), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (11), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (17), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (17), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (47), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (47), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (54), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (54), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ geode_memcpy,
+ geode_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs k6_memcpy[2] = {
+ {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+static stringop_algs k6_memset[2] = {
+ {libcall, {{256, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+static const
+struct processor_costs k6_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (2), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (3), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (3), /* DI */
+ COSTS_N_INSNS (3)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (18), /* HI */
+ COSTS_N_INSNS (18), /* SI */
+ COSTS_N_INSNS (18), /* DI */
+ COSTS_N_INSNS (18)}, /* other */
+ COSTS_N_INSNS (2), /* cost of movsx */
+ COSTS_N_INSNS (2), /* cost of movzx */
+ 8, /* "large" insn */
+ 4, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 3, /* cost for loading QImode using movzbl */
+ {4, 5, 4}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 3, 2}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {6, 6, 6}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {4, 4, 4}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {2, 2}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {2, 2}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {2, 2, 8, 16, 32}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {2, 2, 8, 16, 32}, /* cost of unaligned loads. */
+ {2, 2, 8, 16, 32}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {2, 2, 8, 16, 32}, /* cost of unaligned stores. */
+ 6, 6, /* SSE->integer and integer->SSE moves */
+ 32, /* size of l1 cache. */
+ 32, /* size of l2 cache. Some models
+ have integrated l2 cache, but
+ optimizing for k6 is not important
+ enough to worry about that. */
+ 32, /* size of prefetch block */
+ 1, /* number of parallel prefetches */
+ 1, /* Branch cost */
+ COSTS_N_INSNS (2), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (2), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (56), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (56), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (2), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (2), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (2), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (4), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (4), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (56), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (56), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (56), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (56), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ k6_memcpy,
+ k6_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+/* For some reason, Athlon deals better with REP prefix (relative to loops)
+ compared to K8. Alignment becomes important after 8 bytes for memcpy and
+ 128 bytes for memset. */
+static stringop_algs athlon_memcpy[2] = {
+ {libcall, {{2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+static stringop_algs athlon_memset[2] = {
+ {libcall, {{2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+static const
+struct processor_costs athlon_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (2), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (5), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (5), /* HI */
+ COSTS_N_INSNS (5), /* SI */
+ COSTS_N_INSNS (5), /* DI */
+ COSTS_N_INSNS (5)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (26), /* HI */
+ COSTS_N_INSNS (42), /* SI */
+ COSTS_N_INSNS (74), /* DI */
+ COSTS_N_INSNS (74)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 4, /* cost for loading QImode using movzbl */
+ {3, 4, 3}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {3, 4, 3}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {4, 4, 12}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {6, 6, 8}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {4, 4}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {4, 4}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {4, 4, 6, 12, 24}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 4, 6, 12, 24}, /* cost of unaligned loads. */
+ {4, 4, 5, 10, 20}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 4, 5, 10, 20}, /* cost of unaligned stores. */
+ 5, 5, /* SSE->integer and integer->SSE moves */
+ 64, /* size of l1 cache. */
+ 256, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 6, /* number of parallel prefetches */
+ 5, /* Branch cost */
+ COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (4), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (24), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (4), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (4), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (4), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (8), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (8), /* cost of FMA SD instruction. */
+ /* 11-16 */
+ COSTS_N_INSNS (16), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (24), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (19), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (19), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ athlon_memcpy,
+ athlon_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+/* K8 has optimized REP instruction for medium sized blocks, but for very
+ small blocks it is better to use loop. For large blocks, libcall can
+ do nontemporary accesses and beat inline considerably. */
+static stringop_algs k8_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs k8_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false},
+ {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
+static const
+struct processor_costs k8_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (2), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (5)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (26), /* HI */
+ COSTS_N_INSNS (42), /* SI */
+ COSTS_N_INSNS (74), /* DI */
+ COSTS_N_INSNS (74)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 4, /* cost for loading QImode using movzbl */
+ {3, 4, 3}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {3, 4, 3}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {4, 4, 12}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {6, 6, 8}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {3, 3}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {4, 4}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {4, 3, 6, 12, 24}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 3, 6, 12, 24}, /* cost of unaligned loads. */
+ {4, 4, 5, 10, 20}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 4, 5, 10, 20}, /* cost of unaligned stores. */
+ 5, 5, /* SSE->integer and integer->SSE moves */
+ 64, /* size of l1 cache. */
+ 512, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ /* New AMD processors never drop prefetches; if they cannot be performed
+ immediately, they are queued. We set number of simultaneous prefetches
+ to a large constant to reflect this (it probably is not a good idea not
+ to limit number of prefetches at all, as their execution also takes some
+ time). */
+ 100, /* number of parallel prefetches */
+ 3, /* Branch cost */
+ COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (4), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (19), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (4), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (4), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (4), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (8), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (8), /* cost of FMA SD instruction. */
+ /* 11-16 */
+ COSTS_N_INSNS (16), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (20), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (19), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (27), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ k8_memcpy,
+ k8_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (2), /* cond_not_taken_branch_cost. */
+};
+
+/* AMDFAM10 has optimized REP instruction for medium sized blocks, but for
+ very small blocks it is better to use loop. For large blocks, libcall can
+ do nontemporary accesses and beat inline considerably. */
+static stringop_algs amdfam10_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs amdfam10_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+struct processor_costs amdfam10_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (2), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (5)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (35), /* HI */
+ COSTS_N_INSNS (51), /* SI */
+ COSTS_N_INSNS (83), /* DI */
+ COSTS_N_INSNS (83)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 4, /* cost for loading QImode using movzbl */
+ {3, 4, 3}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {3, 4, 3}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {4, 4, 12}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {6, 6, 8}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {3, 3}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {4, 4}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {4, 4, 3, 6, 12}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 4, 3, 7, 12}, /* cost of unaligned loads. */
+ {4, 4, 5, 10, 20}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {4, 4, 5, 10, 20}, /* cost of unaligned stores. */
+ 3, 3, /* SSE->integer and integer->SSE moves */
+ /* On K8:
+ MOVD reg64, xmmreg Double FSTORE 4
+ MOVD reg32, xmmreg Double FSTORE 4
+ On AMDFAM10:
+ MOVD reg64, xmmreg Double FADD 3
+ 1/1 1/1
+ MOVD reg32, xmmreg Double FADD 3
+ 1/1 1/1 */
+ 64, /* size of l1 cache. */
+ 512, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ /* New AMD processors never drop prefetches; if they cannot be performed
+ immediately, they are queued. We set number of simultaneous prefetches
+ to a large constant to reflect this (it probably is not a good idea not
+ to limit number of prefetches at all, as their execution also takes some
+ time). */
+ 100, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (4), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (19), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (4), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (4), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (4), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (8), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (8), /* cost of FMA SD instruction. */
+ /* 11-16 */
+ COSTS_N_INSNS (16), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (20), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (19), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (27), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ amdfam10_memcpy,
+ amdfam10_memset,
+ COSTS_N_INSNS (2), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+/* BDVER1 has optimized REP instruction for medium sized blocks, but for
+ very small blocks it is better to use loop. For large blocks, libcall
+ can do nontemporary accesses and beat inline considerably. */
+static stringop_algs bdver1_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs bdver1_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+
+const struct processor_costs bdver1_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (4), /* SI */
+ COSTS_N_INSNS (6), /* DI */
+ COSTS_N_INSNS (6)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (35), /* HI */
+ COSTS_N_INSNS (51), /* SI */
+ COSTS_N_INSNS (83), /* DI */
+ COSTS_N_INSNS (83)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 8, /* cost for loading QImode using movzbl */
+ {8, 8, 8}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {8, 8, 8}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {12, 12, 28}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {10, 10, 18}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 4, /* cost of moving MMX register */
+ {12, 12}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {10, 10}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {12, 12, 10, 20, 30}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {12, 12, 10, 20, 30}, /* cost of unaligned loads. */
+ {10, 10, 10, 20, 30}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 10, 20, 30}, /* cost of unaligned stores. */
+ 16, 20, /* SSE->integer and integer->SSE moves */
+ 16, /* size of l1 cache. */
+ 2048, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ /* New AMD processors never drop prefetches; if they cannot be performed
+ immediately, they are queued. We set number of simultaneous prefetches
+ to a large constant to reflect this (it probably is not a good idea not
+ to limit number of prefetches at all, as their execution also takes some
+ time). */
+ 100, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (6), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (42), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (6), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (6), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (6), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ /* 9-24 */
+ COSTS_N_INSNS (24), /* cost of DIVSS instruction. */
+ /* 9-27 */
+ COSTS_N_INSNS (27), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (15), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (26), /* cost of SQRTSD instruction. */
+ 1, 2, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ bdver1_memcpy,
+ bdver1_memset,
+ COSTS_N_INSNS (4), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (2), /* cond_not_taken_branch_cost. */
+};
+
+/* BDVER2 has optimized REP instruction for medium sized blocks, but for
+ very small blocks it is better to use loop. For large blocks, libcall
+ can do nontemporary accesses and beat inline considerably. */
+
+static stringop_algs bdver2_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs bdver2_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+
+const struct processor_costs bdver2_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (4), /* SI */
+ COSTS_N_INSNS (6), /* DI */
+ COSTS_N_INSNS (6)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (35), /* HI */
+ COSTS_N_INSNS (51), /* SI */
+ COSTS_N_INSNS (83), /* DI */
+ COSTS_N_INSNS (83)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 8, /* cost for loading QImode using movzbl */
+ {8, 8, 8}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {8, 8, 8}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {12, 12, 28}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {10, 10, 18}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 4, /* cost of moving MMX register */
+ {12, 12}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {10, 10}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {12, 12, 10, 20, 30}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {12, 12, 10, 20, 30}, /* cost of unaligned loads. */
+ {10, 10, 10, 20, 30}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 10, 20, 30}, /* cost of unaligned stores. */
+ 16, 20, /* SSE->integer and integer->SSE moves */
+ 16, /* size of l1 cache. */
+ 2048, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ /* New AMD processors never drop prefetches; if they cannot be performed
+ immediately, they are queued. We set number of simultaneous prefetches
+ to a large constant to reflect this (it probably is not a good idea not
+ to limit number of prefetches at all, as their execution also takes some
+ time). */
+ 100, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (6), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (42), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (6), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (6), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (6), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ /* 9-24 */
+ COSTS_N_INSNS (24), /* cost of DIVSS instruction. */
+ /* 9-27 */
+ COSTS_N_INSNS (27), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (15), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (26), /* cost of SQRTSD instruction. */
+ 1, 2, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ bdver2_memcpy,
+ bdver2_memset,
+ COSTS_N_INSNS (4), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (2), /* cond_not_taken_branch_cost. */
+};
+
+
+ /* BDVER3 has optimized REP instruction for medium sized blocks, but for
+ very small blocks it is better to use loop. For large blocks, libcall
+ can do nontemporary accesses and beat inline considerably. */
+static stringop_algs bdver3_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs bdver3_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+struct processor_costs bdver3_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (4), /* SI */
+ COSTS_N_INSNS (6), /* DI */
+ COSTS_N_INSNS (6)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (35), /* HI */
+ COSTS_N_INSNS (51), /* SI */
+ COSTS_N_INSNS (83), /* DI */
+ COSTS_N_INSNS (83)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 8, /* cost for loading QImode using movzbl */
+ {8, 8, 8}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {8, 8, 8}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {12, 12, 28}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {10, 10, 18}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 4, /* cost of moving MMX register */
+ {12, 12}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {10, 10}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {12, 12, 10, 20, 30}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {12, 12, 10, 20, 30}, /* cost of unaligned loads. */
+ {10, 10, 10, 20, 30}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 10, 20, 30}, /* cost of unaligned stores. */
+ 16, 20, /* SSE->integer and integer->SSE moves */
+ 16, /* size of l1 cache. */
+ 2048, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ /* New AMD processors never drop prefetches; if they cannot be performed
+ immediately, they are queued. We set number of simultaneous prefetches
+ to a large constant to reflect this (it probably is not a good idea not
+ to limit number of prefetches at all, as their execution also takes some
+ time). */
+ 100, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (6), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (42), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (6), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (6), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (6), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ /* 9-24 */
+ COSTS_N_INSNS (24), /* cost of DIVSS instruction. */
+ /* 9-27 */
+ COSTS_N_INSNS (27), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (15), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (26), /* cost of SQRTSD instruction. */
+ 1, 2, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ bdver3_memcpy,
+ bdver3_memset,
+ COSTS_N_INSNS (4), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (2), /* cond_not_taken_branch_cost. */
+};
+
+/* BDVER4 has optimized REP instruction for medium sized blocks, but for
+ very small blocks it is better to use loop. For large blocks, libcall
+ can do nontemporary accesses and beat inline considerably. */
+static stringop_algs bdver4_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs bdver4_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+struct processor_costs bdver4_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (4), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (4), /* SI */
+ COSTS_N_INSNS (6), /* DI */
+ COSTS_N_INSNS (6)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (35), /* HI */
+ COSTS_N_INSNS (51), /* SI */
+ COSTS_N_INSNS (83), /* DI */
+ COSTS_N_INSNS (83)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 8, /* cost for loading QImode using movzbl */
+ {8, 8, 8}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {8, 8, 8}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {12, 12, 28}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {10, 10, 18}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 4, /* cost of moving MMX register */
+ {12, 12}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {10, 10}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {12, 12, 10, 20, 30}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {12, 12, 10, 20, 30}, /* cost of unaligned loads. */
+ {10, 10, 10, 20, 30}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 10, 20, 30}, /* cost of unaligned stores. */
+ 16, 20, /* SSE->integer and integer->SSE moves */
+ 16, /* size of l1 cache. */
+ 2048, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ /* New AMD processors never drop prefetches; if they cannot be performed
+ immediately, they are queued. We set number of simultaneous prefetches
+ to a large constant to reflect this (it probably is not a good idea not
+ to limit number of prefetches at all, as their execution also takes some
+ time). */
+ 100, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (6), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (42), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (52), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (6), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (6), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (6), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ /* 9-24 */
+ COSTS_N_INSNS (24), /* cost of DIVSS instruction. */
+ /* 9-27 */
+ COSTS_N_INSNS (27), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (15), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (26), /* cost of SQRTSD instruction. */
+ 1, 2, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ bdver4_memcpy,
+ bdver4_memset,
+ COSTS_N_INSNS (4), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (2), /* cond_not_taken_branch_cost. */
+};
+
+
+/* ZNVER1 has optimized REP instruction for medium sized blocks, but for
+ very small blocks it is better to use loop. For large blocks, libcall
+ can do nontemporary accesses and beat inline considerably. */
+static stringop_algs znver1_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs znver1_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+struct processor_costs znver1_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction. */
+ COSTS_N_INSNS (1), /* cost of a lea instruction. */
+ COSTS_N_INSNS (1), /* variable shift costs. */
+ COSTS_N_INSNS (1), /* constant shift costs. */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI. */
+ COSTS_N_INSNS (3), /* HI. */
+ COSTS_N_INSNS (3), /* SI. */
+ COSTS_N_INSNS (3), /* DI. */
+ COSTS_N_INSNS (3)}, /* other. */
+ 0, /* cost of multiply per each bit
+ set. */
+ /* Depending on parameters, idiv can get faster on ryzen. This is upper
+ bound. */
+ {COSTS_N_INSNS (16), /* cost of a divide/mod for QI. */
+ COSTS_N_INSNS (22), /* HI. */
+ COSTS_N_INSNS (30), /* SI. */
+ COSTS_N_INSNS (45), /* DI. */
+ COSTS_N_INSNS (45)}, /* other. */
+ COSTS_N_INSNS (1), /* cost of movsx. */
+ COSTS_N_INSNS (1), /* cost of movzx. */
+ 8, /* "large" insn. */
+ 9, /* MOVE_RATIO. */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+
+ /* reg-reg moves are done by renaming and thus they are even cheaper than
+ 1 cycle. Becuase reg-reg move cost is 2 and the following tables correspond
+ to doubles of latencies, we do not model this correctly. It does not
+ seem to make practical difference to bump prices up even more. */
+ 6, /* cost for loading QImode using
+ movzbl. */
+ {6, 6, 6}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {8, 8, 8}, /* cost of storing integer
+ registers. */
+ 2, /* cost of reg,reg fld/fst. */
+ {6, 6, 16}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode. */
+ {8, 8, 16}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode. */
+ 2, /* cost of moving MMX register. */
+ {6, 6}, /* cost of loading MMX registers
+ in SImode and DImode. */
+ {8, 8}, /* cost of storing MMX registers
+ in SImode and DImode. */
+ 2, 3, 6, /* cost of moving XMM,YMM,ZMM register. */
+ {6, 6, 6, 10, 20}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit. */
+ {6, 6, 6, 10, 20}, /* cost of unaligned loads. */
+ {8, 8, 8, 8, 16}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit. */
+ {8, 8, 8, 8, 16}, /* cost of unaligned stores. */
+ 6, 6, /* SSE->integer and integer->SSE moves. */
+ 32, /* size of l1 cache. */
+ 512, /* size of l2 cache. */
+ 64, /* size of prefetch block. */
+ /* New AMD processors never drop prefetches; if they cannot be performed
+ immediately, they are queued. We set number of simultaneous prefetches
+ to a large constant to reflect this (it probably is not a good idea not
+ to limit number of prefetches at all, as their execution also takes some
+ time). */
+ 100, /* number of parallel prefetches. */
+ 3, /* Branch cost. */
+ COSTS_N_INSNS (5), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (5), /* cost of FMUL instruction. */
+ /* Latency of fdiv is 8-15. */
+ COSTS_N_INSNS (15), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (1), /* cost of FABS instruction. */
+ COSTS_N_INSNS (1), /* cost of FCHS instruction. */
+ /* Latency of fsqrt is 4-10. */
+ COSTS_N_INSNS (10), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (3), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (4), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (10), /* cost of DIVSS instruction. */
+ /* 9-13 */
+ COSTS_N_INSNS (13), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (10), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (15), /* cost of SQRTSD instruction. */
+ /* Zen can execute 4 integer operations per cycle. FP operations take 3 cycles
+ and it can execute 2 integer additions and 2 multiplications thus
+ reassociation may make sense up to with of 6. SPEC2k6 bencharks suggests
+ that 4 works better than 6 probably due to register pressure.
+
+ Integer vector operations are taken by FP unit and execute 3 vector
+ plus/minus operations per cycle but only one multiply. This is adjusted
+ in ix86_reassociation_width. */
+ 4, 4, 3, 6, /* reassoc int, fp, vec_int, vec_fp. */
+ znver1_memcpy,
+ znver1_memset,
+ COSTS_N_INSNS (4), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (2), /* cond_not_taken_branch_cost. */
+};
+
+ /* BTVER1 has optimized REP instruction for medium sized blocks, but for
+ very small blocks it is better to use loop. For large blocks, libcall can
+ do nontemporary accesses and beat inline considerably. */
+static stringop_algs btver1_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs btver1_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+const struct processor_costs btver1_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (2), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (5)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (35), /* HI */
+ COSTS_N_INSNS (51), /* SI */
+ COSTS_N_INSNS (83), /* DI */
+ COSTS_N_INSNS (83)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 8, /* cost for loading QImode using movzbl */
+ {6, 8, 6}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {6, 8, 6}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {12, 12, 28}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {12, 12, 38}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 4, /* cost of moving MMX register */
+ {10, 10}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {12, 12}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {10, 10, 12, 24, 48}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 12, 24, 48}, /* cost of unaligned loads. */
+ {10, 10, 12, 24, 48}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 12, 24, 48}, /* cost of unaligned stores. */
+ 14, 14, /* SSE->integer and integer->SSE moves */
+ 32, /* size of l1 cache. */
+ 512, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 100, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (4), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (19), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (2), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (4), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (13), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (17), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (14), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (48), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ btver1_memcpy,
+ btver1_memset,
+ COSTS_N_INSNS (2), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs btver2_memcpy[2] = {
+ {libcall, {{6, loop, false}, {14, unrolled_loop, false},
+ {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{16, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs btver2_memset[2] = {
+ {libcall, {{8, loop, false}, {24, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{48, unrolled_loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+const struct processor_costs btver2_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (2), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (5)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (19), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (35), /* HI */
+ COSTS_N_INSNS (51), /* SI */
+ COSTS_N_INSNS (83), /* DI */
+ COSTS_N_INSNS (83)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 9, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 8, /* cost for loading QImode using movzbl */
+ {8, 8, 6}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {8, 8, 6}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {12, 12, 28}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {12, 12, 38}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 4, /* cost of moving MMX register */
+ {10, 10}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {12, 12}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {10, 10, 12, 24, 48}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 12, 24, 48}, /* cost of unaligned loads. */
+ {10, 10, 12, 24, 48}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 12, 24, 48}, /* cost of unaligned stores. */
+ 14, 14, /* SSE->integer and integer->SSE moves */
+ 32, /* size of l1 cache. */
+ 2048, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 100, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (4), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (4), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (19), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (35), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (2), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (4), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (13), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (19), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (16), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (21), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ btver2_memcpy,
+ btver2_memset,
+ COSTS_N_INSNS (2), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs pentium4_memcpy[2] = {
+ {libcall, {{12, loop_1_byte, false}, {-1, rep_prefix_4_byte, false}}},
+ DUMMY_STRINGOP_ALGS};
+static stringop_algs pentium4_memset[2] = {
+ {libcall, {{6, loop_1_byte, false}, {48, loop, false},
+ {20480, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ DUMMY_STRINGOP_ALGS};
+
+static const
+struct processor_costs pentium4_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (3), /* cost of a lea instruction */
+ COSTS_N_INSNS (4), /* variable shift costs */
+ COSTS_N_INSNS (4), /* constant shift costs */
+ {COSTS_N_INSNS (15), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (15), /* HI */
+ COSTS_N_INSNS (15), /* SI */
+ COSTS_N_INSNS (15), /* DI */
+ COSTS_N_INSNS (15)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (56), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (56), /* HI */
+ COSTS_N_INSNS (56), /* SI */
+ COSTS_N_INSNS (56), /* DI */
+ COSTS_N_INSNS (56)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 16, /* "large" insn */
+ 6, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 5, /* cost for loading QImode using movzbl */
+ {4, 5, 4}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {2, 3, 2}, /* cost of storing integer registers */
+ 12, /* cost of reg,reg fld/fst */
+ {14, 14, 14}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {14, 14, 14}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 12, /* cost of moving MMX register */
+ {16, 16}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {16, 16}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 12, 24, 48, /* cost of moving XMM,YMM,ZMM register */
+ {16, 16, 16, 32, 64}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {32, 32, 32, 64, 128}, /* cost of unaligned loads. */
+ {16, 16, 16, 32, 64}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {32, 32, 32, 64, 128}, /* cost of unaligned stores. */
+ 20, 12, /* SSE->integer and integer->SSE moves */
+ 8, /* size of l1 cache. */
+ 256, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 6, /* number of parallel prefetches */
+ 2, /* Branch cost */
+ COSTS_N_INSNS (5), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (7), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (43), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (2), /* cost of FABS instruction. */
+ COSTS_N_INSNS (2), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (43), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (4), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (6), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (6), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (23), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (38), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (23), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (38), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ pentium4_memcpy,
+ pentium4_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs nocona_memcpy[2] = {
+ {libcall, {{12, loop_1_byte, false}, {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{32, loop, false}, {20000, rep_prefix_8_byte, false},
+ {100000, unrolled_loop, false}, {-1, libcall, false}}}};
+
+static stringop_algs nocona_memset[2] = {
+ {libcall, {{6, loop_1_byte, false}, {48, loop, false},
+ {20480, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{24, loop, false}, {64, unrolled_loop, false},
+ {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
+
+static const
+struct processor_costs nocona_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1), /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (10), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (10), /* HI */
+ COSTS_N_INSNS (10), /* SI */
+ COSTS_N_INSNS (10), /* DI */
+ COSTS_N_INSNS (10)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (66), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (66), /* HI */
+ COSTS_N_INSNS (66), /* SI */
+ COSTS_N_INSNS (66), /* DI */
+ COSTS_N_INSNS (66)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 16, /* "large" insn */
+ 17, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 4, /* cost for loading QImode using movzbl */
+ {4, 4, 4}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {4, 4, 4}, /* cost of storing integer registers */
+ 12, /* cost of reg,reg fld/fst */
+ {14, 14, 14}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {14, 14, 14}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 14, /* cost of moving MMX register */
+ {12, 12}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {12, 12}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 6, 12, 24, /* cost of moving XMM,YMM,ZMM register */
+ {12, 12, 12, 24, 48}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {24, 24, 24, 48, 96}, /* cost of unaligned loads. */
+ {12, 12, 12, 24, 48}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {24, 24, 24, 48, 96}, /* cost of unaligned stores. */
+ 20, 12, /* SSE->integer and integer->SSE moves */
+ 8, /* size of l1 cache. */
+ 1024, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 8, /* number of parallel prefetches */
+ 1, /* Branch cost */
+ COSTS_N_INSNS (6), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (8), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (40), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (3), /* cost of FABS instruction. */
+ COSTS_N_INSNS (3), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (44), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (2), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (5), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (7), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (7), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (7), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (7), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (32), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (40), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (32), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (41), /* cost of SQRTSD instruction. */
+ 1, 1, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ nocona_memcpy,
+ nocona_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs atom_memcpy[2] = {
+ {libcall, {{11, loop, false}, {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{32, loop, false}, {64, rep_prefix_4_byte, false},
+ {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
+static stringop_algs atom_memset[2] = {
+ {libcall, {{8, loop, false}, {15, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{24, loop, false}, {32, unrolled_loop, false},
+ {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
+static const
+struct processor_costs atom_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (2)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (26), /* HI */
+ COSTS_N_INSNS (42), /* SI */
+ COSTS_N_INSNS (74), /* DI */
+ COSTS_N_INSNS (74)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 17, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 6, /* cost for loading QImode using movzbl */
+ {6, 6, 6}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {6, 6, 6}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {6, 6, 18}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {14, 14, 24}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {8, 8}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {10, 10}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {8, 8, 8, 16, 32}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {16, 16, 16, 32, 64}, /* cost of unaligned loads. */
+ {8, 8, 8, 16, 32}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {16, 16, 16, 32, 64}, /* cost of unaligned stores. */
+ 8, 6, /* SSE->integer and integer->SSE moves */
+ 32, /* size of l1 cache. */
+ 256, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 6, /* number of parallel prefetches */
+ 3, /* Branch cost */
+ COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (8), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (20), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (8), /* cost of FABS instruction. */
+ COSTS_N_INSNS (8), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (5), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (4), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (5), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (31), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (60), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (31), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (63), /* cost of SQRTSD instruction. */
+ 2, 2, 2, 2, /* reassoc int, fp, vec_int, vec_fp. */
+ atom_memcpy,
+ atom_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs slm_memcpy[2] = {
+ {libcall, {{11, loop, false}, {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{32, loop, false}, {64, rep_prefix_4_byte, false},
+ {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
+static stringop_algs slm_memset[2] = {
+ {libcall, {{8, loop, false}, {15, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{24, loop, false}, {32, unrolled_loop, false},
+ {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
+static const
+struct processor_costs slm_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (3), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (2)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (26), /* HI */
+ COSTS_N_INSNS (42), /* SI */
+ COSTS_N_INSNS (74), /* DI */
+ COSTS_N_INSNS (74)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 17, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 8, /* cost for loading QImode using movzbl */
+ {8, 8, 8}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {6, 6, 6}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {8, 8, 18}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {6, 6, 18}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {8, 8}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {6, 6}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 4, 8, /* cost of moving XMM,YMM,ZMM register */
+ {8, 8, 8, 16, 32}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {16, 16, 16, 32, 64}, /* cost of unaligned loads. */
+ {8, 8, 8, 16, 32}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {16, 16, 16, 32, 64}, /* cost of unaligned stores. */
+ 8, 6, /* SSE->integer and integer->SSE moves */
+ 32, /* size of l1 cache. */
+ 256, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 6, /* number of parallel prefetches */
+ 3, /* Branch cost */
+ COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (8), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (20), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (8), /* cost of FABS instruction. */
+ COSTS_N_INSNS (8), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (4), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (5), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (39), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (69), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (20), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (35), /* cost of SQRTSD instruction. */
+ 1, 2, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ slm_memcpy,
+ slm_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+static stringop_algs intel_memcpy[2] = {
+ {libcall, {{11, loop, false}, {-1, rep_prefix_4_byte, false}}},
+ {libcall, {{32, loop, false}, {64, rep_prefix_4_byte, false},
+ {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
+static stringop_algs intel_memset[2] = {
+ {libcall, {{8, loop, false}, {15, unrolled_loop, false},
+ {2048, rep_prefix_4_byte, false}, {-1, libcall, false}}},
+ {libcall, {{24, loop, false}, {32, unrolled_loop, false},
+ {8192, rep_prefix_8_byte, false}, {-1, libcall, false}}}};
+static const
+struct processor_costs intel_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (3), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (2)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (26), /* HI */
+ COSTS_N_INSNS (42), /* SI */
+ COSTS_N_INSNS (74), /* DI */
+ COSTS_N_INSNS (74)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 17, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 6, /* cost for loading QImode using movzbl */
+ {4, 4, 4}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {6, 6, 6}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {6, 6, 8}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {6, 6, 10}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {6, 6}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {6, 6}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 2, 2, /* cost of moving XMM,YMM,ZMM register */
+ {6, 6, 6, 6, 6}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 10, 10, 10}, /* cost of unaligned loads. */
+ {6, 6, 6, 6, 6}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 10, 10, 10}, /* cost of unaligned loads. */
+ 4, 4, /* SSE->integer and integer->SSE moves */
+ 32, /* size of l1 cache. */
+ 256, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 6, /* number of parallel prefetches */
+ 3, /* Branch cost */
+ COSTS_N_INSNS (8), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (8), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (20), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (8), /* cost of FABS instruction. */
+ COSTS_N_INSNS (8), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (8), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (8), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (8), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (8), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (6), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (20), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (20), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (40), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (40), /* cost of SQRTSD instruction. */
+ 1, 4, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ intel_memcpy,
+ intel_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+/* Generic should produce code tuned for Core-i7 (and newer chips)
+ and btver1 (and newer chips). */
+
+static stringop_algs generic_memcpy[2] = {
+ {libcall, {{32, loop, false}, {8192, rep_prefix_4_byte, false},
+ {-1, libcall, false}}},
+ {libcall, {{32, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static stringop_algs generic_memset[2] = {
+ {libcall, {{32, loop, false}, {8192, rep_prefix_4_byte, false},
+ {-1, libcall, false}}},
+ {libcall, {{32, loop, false}, {8192, rep_prefix_8_byte, false},
+ {-1, libcall, false}}}};
+static const
+struct processor_costs generic_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ /* Setting cost to 2 makes our current implementation of synth_mult result in
+ use of unnecessary temporary registers causing regression on several
+ SPECfp benchmarks. */
+ COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (2)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (18), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (26), /* HI */
+ COSTS_N_INSNS (42), /* SI */
+ COSTS_N_INSNS (74), /* DI */
+ COSTS_N_INSNS (74)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 17, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 4, /* cost for loading QImode using movzbl */
+ {4, 4, 4}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {6, 6, 6}, /* cost of storing integer registers */
+ 4, /* cost of reg,reg fld/fst */
+ {6, 6, 12}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {6, 6, 12}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {6, 6}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {6, 6}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 3, 4, /* cost of moving XMM,YMM,ZMM register */
+ {6, 6, 6, 10, 15}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 10, 15, 20}, /* cost of unaligned loads. */
+ {6, 6, 6, 10, 15}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {10, 10, 10, 15, 20}, /* cost of unaligned storess. */
+ 20, 20, /* SSE->integer and integer->SSE moves */
+ 32, /* size of l1 cache. */
+ 512, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 6, /* number of parallel prefetches */
+ /* Benchmarks shows large regressions on K8 sixtrack benchmark when this
+ value is increased to perhaps more appropriate value of 5. */
+ 3, /* Branch cost */
+ COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (3), /* cost of FMUL instruction. */
+ COSTS_N_INSNS (20), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (1), /* cost of FABS instruction. */
+ COSTS_N_INSNS (1), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (40), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (4), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (5), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (18), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (32), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (30), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (58), /* cost of SQRTSD instruction. */
+ 1, 2, 1, 1, /* reassoc int, fp, vec_int, vec_fp. */
+ generic_memcpy,
+ generic_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
+/* core_cost should produce code tuned for Core familly of CPUs. */
+static stringop_algs core_memcpy[2] = {
+ {libcall, {{1024, rep_prefix_4_byte, true}, {-1, libcall, false}}},
+ {libcall, {{24, loop, true}, {128, rep_prefix_8_byte, true},
+ {-1, libcall, false}}}};
+static stringop_algs core_memset[2] = {
+ {libcall, {{6, loop_1_byte, true},
+ {24, loop, true},
+ {8192, rep_prefix_4_byte, true},
+ {-1, libcall, false}}},
+ {libcall, {{24, loop, true}, {512, rep_prefix_8_byte, true},
+ {-1, libcall, false}}}};
+
+static const
+struct processor_costs core_cost = {
+ COSTS_N_INSNS (1), /* cost of an add instruction */
+ /* On all chips taken into consideration lea is 2 cycles and more. With
+ this cost however our current implementation of synth_mult results in
+ use of unnecessary temporary registers causing regression on several
+ SPECfp benchmarks. */
+ COSTS_N_INSNS (1) + 1, /* cost of a lea instruction */
+ COSTS_N_INSNS (1), /* variable shift costs */
+ COSTS_N_INSNS (1), /* constant shift costs */
+ {COSTS_N_INSNS (3), /* cost of starting multiply for QI */
+ COSTS_N_INSNS (4), /* HI */
+ COSTS_N_INSNS (3), /* SI */
+ COSTS_N_INSNS (4), /* DI */
+ COSTS_N_INSNS (4)}, /* other */
+ 0, /* cost of multiply per each bit set */
+ {COSTS_N_INSNS (8), /* cost of a divide/mod for QI */
+ COSTS_N_INSNS (8), /* HI */
+ /* 8-11 */
+ COSTS_N_INSNS (11), /* SI */
+ /* 24-81 */
+ COSTS_N_INSNS (81), /* DI */
+ COSTS_N_INSNS (81)}, /* other */
+ COSTS_N_INSNS (1), /* cost of movsx */
+ COSTS_N_INSNS (1), /* cost of movzx */
+ 8, /* "large" insn */
+ 17, /* MOVE_RATIO */
+
+ /* All move costs are relative to integer->integer move times 2 and thus
+ they are latency*2. */
+ 6, /* cost for loading QImode using movzbl */
+ {4, 4, 4}, /* cost of loading integer registers
+ in QImode, HImode and SImode.
+ Relative to reg-reg move (2). */
+ {6, 6, 6}, /* cost of storing integer registers */
+ 2, /* cost of reg,reg fld/fst */
+ {6, 6, 8}, /* cost of loading fp registers
+ in SFmode, DFmode and XFmode */
+ {6, 6, 10}, /* cost of storing fp registers
+ in SFmode, DFmode and XFmode */
+ 2, /* cost of moving MMX register */
+ {6, 6}, /* cost of loading MMX registers
+ in SImode and DImode */
+ {6, 6}, /* cost of storing MMX registers
+ in SImode and DImode */
+ 2, 2, 4, /* cost of moving XMM,YMM,ZMM register */
+ {6, 6, 6, 6, 12}, /* cost of loading SSE registers
+ in 32,64,128,256 and 512-bit */
+ {6, 6, 6, 6, 12}, /* cost of unaligned loads. */
+ {6, 6, 6, 6, 12}, /* cost of storing SSE registers
+ in 32,64,128,256 and 512-bit */
+ {6, 6, 6, 6, 12}, /* cost of unaligned stores. */
+ 2, 2, /* SSE->integer and integer->SSE moves */
+ 64, /* size of l1 cache. */
+ 512, /* size of l2 cache. */
+ 64, /* size of prefetch block */
+ 6, /* number of parallel prefetches */
+ /* FIXME perhaps more appropriate value is 5. */
+ 3, /* Branch cost */
+ COSTS_N_INSNS (3), /* cost of FADD and FSUB insns. */
+ COSTS_N_INSNS (5), /* cost of FMUL instruction. */
+ /* 10-24 */
+ COSTS_N_INSNS (24), /* cost of FDIV instruction. */
+ COSTS_N_INSNS (1), /* cost of FABS instruction. */
+ COSTS_N_INSNS (1), /* cost of FCHS instruction. */
+ COSTS_N_INSNS (23), /* cost of FSQRT instruction. */
+
+ COSTS_N_INSNS (1), /* cost of cheap SSE instruction. */
+ COSTS_N_INSNS (3), /* cost of ADDSS/SD SUBSS/SD insns. */
+ COSTS_N_INSNS (4), /* cost of MULSS instruction. */
+ COSTS_N_INSNS (5), /* cost of MULSD instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SS instruction. */
+ COSTS_N_INSNS (5), /* cost of FMA SD instruction. */
+ COSTS_N_INSNS (18), /* cost of DIVSS instruction. */
+ COSTS_N_INSNS (32), /* cost of DIVSD instruction. */
+ COSTS_N_INSNS (30), /* cost of SQRTSS instruction. */
+ COSTS_N_INSNS (58), /* cost of SQRTSD instruction. */
+ 1, 4, 2, 2, /* reassoc int, fp, vec_int, vec_fp. */
+ core_memcpy,
+ core_memset,
+ COSTS_N_INSNS (3), /* cond_taken_branch_cost. */
+ COSTS_N_INSNS (1), /* cond_not_taken_branch_cost. */
+};
+
diff --git a/gcc/config/i386/x86-tune-sched-atom.c b/gcc/config/i386/x86-tune-sched-atom.c
new file mode 100644
index 0000000..86942c0
--- /dev/null
+++ b/gcc/config/i386/x86-tune-sched-atom.c
@@ -0,0 +1,244 @@
+/* Scheduler hooks for IA-32 which implement atom+ specific logic.
+ Copyright (C) 1988-2017 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "insn-attr.h"
+#include "recog.h"
+#include "target.h"
+#include "rtl-iter.h"
+#include "regset.h"
+#include "sched-int.h"
+
+/* Try to reorder ready list to take advantage of Atom pipelined IMUL
+ execution. It is applied if
+ (1) IMUL instruction is on the top of list;
+ (2) There exists the only producer of independent IMUL instruction in
+ ready list.
+ Return index of IMUL producer if it was found and -1 otherwise. */
+static int
+do_reorder_for_imul (rtx_insn **ready, int n_ready)
+{
+ rtx_insn *insn;
+ rtx set, insn1, insn2;
+ sd_iterator_def sd_it;
+ dep_t dep;
+ int index = -1;
+ int i;
+
+ if (!TARGET_BONNELL)
+ return index;
+
+ /* Check that IMUL instruction is on the top of ready list. */
+ insn = ready[n_ready - 1];
+ set = single_set (insn);
+ if (!set)
+ return index;
+ if (!(GET_CODE (SET_SRC (set)) == MULT
+ && GET_MODE (SET_SRC (set)) == SImode))
+ return index;
+
+ /* Search for producer of independent IMUL instruction. */
+ for (i = n_ready - 2; i >= 0; i--)
+ {
+ insn = ready[i];
+ if (!NONDEBUG_INSN_P (insn))
+ continue;
+ /* Skip IMUL instruction. */
+ insn2 = PATTERN (insn);
+ if (GET_CODE (insn2) == PARALLEL)
+ insn2 = XVECEXP (insn2, 0, 0);
+ if (GET_CODE (insn2) == SET
+ && GET_CODE (SET_SRC (insn2)) == MULT
+ && GET_MODE (SET_SRC (insn2)) == SImode)
+ continue;
+
+ FOR_EACH_DEP (insn, SD_LIST_FORW, sd_it, dep)
+ {
+ rtx con;
+ con = DEP_CON (dep);
+ if (!NONDEBUG_INSN_P (con))
+ continue;
+ insn1 = PATTERN (con);
+ if (GET_CODE (insn1) == PARALLEL)
+ insn1 = XVECEXP (insn1, 0, 0);
+
+ if (GET_CODE (insn1) == SET
+ && GET_CODE (SET_SRC (insn1)) == MULT
+ && GET_MODE (SET_SRC (insn1)) == SImode)
+ {
+ sd_iterator_def sd_it1;
+ dep_t dep1;
+ /* Check if there is no other dependee for IMUL. */
+ index = i;
+ FOR_EACH_DEP (con, SD_LIST_BACK, sd_it1, dep1)
+ {
+ rtx pro;
+ pro = DEP_PRO (dep1);
+ if (!NONDEBUG_INSN_P (pro))
+ continue;
+ if (pro != insn)
+ index = -1;
+ }
+ if (index >= 0)
+ break;
+ }
+ }
+ if (index >= 0)
+ break;
+ }
+ return index;
+}
+
+/* Try to find the best candidate on the top of ready list if two insns
+ have the same priority - candidate is best if its dependees were
+ scheduled earlier. Applied for Silvermont only.
+ Return true if top 2 insns must be interchanged. */
+static bool
+swap_top_of_ready_list (rtx_insn **ready, int n_ready)
+{
+ rtx_insn *top = ready[n_ready - 1];
+ rtx_insn *next = ready[n_ready - 2];
+ rtx set;
+ sd_iterator_def sd_it;
+ dep_t dep;
+ int clock1 = -1;
+ int clock2 = -1;
+ #define INSN_TICK(INSN) (HID (INSN)->tick)
+
+ if (!TARGET_SILVERMONT && !TARGET_INTEL)
+ return false;
+
+ if (!NONDEBUG_INSN_P (top))
+ return false;
+ if (!NONJUMP_INSN_P (top))
+ return false;
+ if (!NONDEBUG_INSN_P (next))
+ return false;
+ if (!NONJUMP_INSN_P (next))
+ return false;
+ set = single_set (top);
+ if (!set)
+ return false;
+ set = single_set (next);
+ if (!set)
+ return false;
+
+ if (INSN_PRIORITY_KNOWN (top) && INSN_PRIORITY_KNOWN (next))
+ {
+ if (INSN_PRIORITY (top) != INSN_PRIORITY (next))
+ return false;
+ /* Determine winner more precise. */
+ FOR_EACH_DEP (top, SD_LIST_RES_BACK, sd_it, dep)
+ {
+ rtx pro;
+ pro = DEP_PRO (dep);
+ if (!NONDEBUG_INSN_P (pro))
+ continue;
+ if (INSN_TICK (pro) > clock1)
+ clock1 = INSN_TICK (pro);
+ }
+ FOR_EACH_DEP (next, SD_LIST_RES_BACK, sd_it, dep)
+ {
+ rtx pro;
+ pro = DEP_PRO (dep);
+ if (!NONDEBUG_INSN_P (pro))
+ continue;
+ if (INSN_TICK (pro) > clock2)
+ clock2 = INSN_TICK (pro);
+ }
+
+ if (clock1 == clock2)
+ {
+ /* Determine winner - load must win. */
+ enum attr_memory memory1, memory2;
+ memory1 = get_attr_memory (top);
+ memory2 = get_attr_memory (next);
+ if (memory2 == MEMORY_LOAD && memory1 != MEMORY_LOAD)
+ return true;
+ }
+ return (bool) (clock2 < clock1);
+ }
+ return false;
+ #undef INSN_TICK
+}
+
+/* Perform possible reodering of ready list for Atom/Silvermont only.
+ Return issue rate. */
+int
+ix86_atom_sched_reorder (FILE *dump, int sched_verbose, rtx_insn **ready,
+ int *pn_ready, int clock_var)
+{
+ int issue_rate = -1;
+ int n_ready = *pn_ready;
+ int i;
+ rtx_insn *insn;
+ int index = -1;
+
+ /* Set up issue rate. */
+ issue_rate = ix86_issue_rate ();
+
+ /* Do reodering for BONNELL/SILVERMONT only. */
+ if (!TARGET_BONNELL && !TARGET_SILVERMONT && !TARGET_INTEL)
+ return issue_rate;
+
+ /* Nothing to do if ready list contains only 1 instruction. */
+ if (n_ready <= 1)
+ return issue_rate;
+
+ /* Do reodering for post-reload scheduler only. */
+ if (!reload_completed)
+ return issue_rate;
+
+ if ((index = do_reorder_for_imul (ready, n_ready)) >= 0)
+ {
+ if (sched_verbose > 1)
+ fprintf (dump, ";;\tatom sched_reorder: put %d insn on top\n",
+ INSN_UID (ready[index]));
+
+ /* Put IMUL producer (ready[index]) at the top of ready list. */
+ insn = ready[index];
+ for (i = index; i < n_ready - 1; i++)
+ ready[i] = ready[i + 1];
+ ready[n_ready - 1] = insn;
+ return issue_rate;
+ }
+
+ /* Skip selective scheduling since HID is not populated in it. */
+ if (clock_var != 0
+ && !sel_sched_p ()
+ && swap_top_of_ready_list (ready, n_ready))
+ {
+ if (sched_verbose > 1)
+ fprintf (dump, ";;\tslm sched_reorder: swap %d and %d insns\n",
+ INSN_UID (ready[n_ready - 1]), INSN_UID (ready[n_ready - 2]));
+ /* Swap 2 top elements of ready list. */
+ insn = ready[n_ready - 1];
+ ready[n_ready - 1] = ready[n_ready - 2];
+ ready[n_ready - 2] = insn;
+ }
+ return issue_rate;
+}
diff --git a/gcc/config/i386/x86-tune-sched-bd.c b/gcc/config/i386/x86-tune-sched-bd.c
new file mode 100644
index 0000000..c862fc1
--- /dev/null
+++ b/gcc/config/i386/x86-tune-sched-bd.c
@@ -0,0 +1,822 @@
+/* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
+ Copyright (C) 1988-2017 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "insn-attr.h"
+#include "recog.h"
+#include "target.h"
+#include "rtl-iter.h"
+#include "regset.h"
+#include "sched-int.h"
+
+/* The size of the dispatch window is the total number of bytes of
+ object code allowed in a window. */
+#define DISPATCH_WINDOW_SIZE 16
+
+/* Number of dispatch windows considered for scheduling. */
+#define MAX_DISPATCH_WINDOWS 3
+
+/* Maximum number of instructions in a window. */
+#define MAX_INSN 4
+
+/* Maximum number of immediate operands in a window. */
+#define MAX_IMM 4
+
+/* Maximum number of immediate bits allowed in a window. */
+#define MAX_IMM_SIZE 128
+
+/* Maximum number of 32 bit immediates allowed in a window. */
+#define MAX_IMM_32 4
+
+/* Maximum number of 64 bit immediates allowed in a window. */
+#define MAX_IMM_64 2
+
+/* Maximum total of loads or prefetches allowed in a window. */
+#define MAX_LOAD 2
+
+/* Maximum total of stores allowed in a window. */
+#define MAX_STORE 1
+
+#undef BIG
+#define BIG 100
+
+
+/* Dispatch groups. Istructions that affect the mix in a dispatch window. */
+enum dispatch_group {
+ disp_no_group = 0,
+ disp_load,
+ disp_store,
+ disp_load_store,
+ disp_prefetch,
+ disp_imm,
+ disp_imm_32,
+ disp_imm_64,
+ disp_branch,
+ disp_cmp,
+ disp_jcc,
+ disp_last
+};
+
+/* Number of allowable groups in a dispatch window. It is an array
+ indexed by dispatch_group enum. 100 is used as a big number,
+ because the number of these kind of operations does not have any
+ effect in dispatch window, but we need them for other reasons in
+ the table. */
+static unsigned int num_allowable_groups[disp_last] = {
+ 0, 2, 1, 1, 2, 4, 4, 2, 1, BIG, BIG
+};
+
+char group_name[disp_last + 1][16] = {
+ "disp_no_group", "disp_load", "disp_store", "disp_load_store",
+ "disp_prefetch", "disp_imm", "disp_imm_32", "disp_imm_64",
+ "disp_branch", "disp_cmp", "disp_jcc", "disp_last"
+};
+
+/* Instruction path. */
+enum insn_path {
+ no_path = 0,
+ path_single, /* Single micro op. */
+ path_double, /* Double micro op. */
+ path_multi, /* Instructions with more than 2 micro op.. */
+ last_path
+};
+
+/* sched_insn_info defines a window to the instructions scheduled in
+ the basic block. It contains a pointer to the insn_info table and
+ the instruction scheduled.
+
+ Windows are allocated for each basic block and are linked
+ together. */
+typedef struct sched_insn_info_s {
+ rtx insn;
+ enum dispatch_group group;
+ enum insn_path path;
+ int byte_len;
+ int imm_bytes;
+} sched_insn_info;
+
+/* Linked list of dispatch windows. This is a two way list of
+ dispatch windows of a basic block. It contains information about
+ the number of uops in the window and the total number of
+ instructions and of bytes in the object code for this dispatch
+ window. */
+typedef struct dispatch_windows_s {
+ int num_insn; /* Number of insn in the window. */
+ int num_uops; /* Number of uops in the window. */
+ int window_size; /* Number of bytes in the window. */
+ int window_num; /* Window number between 0 or 1. */
+ int num_imm; /* Number of immediates in an insn. */
+ int num_imm_32; /* Number of 32 bit immediates in an insn. */
+ int num_imm_64; /* Number of 64 bit immediates in an insn. */
+ int imm_size; /* Total immediates in the window. */
+ int num_loads; /* Total memory loads in the window. */
+ int num_stores; /* Total memory stores in the window. */
+ int violation; /* Violation exists in window. */
+ sched_insn_info *window; /* Pointer to the window. */
+ struct dispatch_windows_s *next;
+ struct dispatch_windows_s *prev;
+} dispatch_windows;
+
+/* Immediate valuse used in an insn. */
+typedef struct imm_info_s
+ {
+ int imm;
+ int imm32;
+ int imm64;
+ } imm_info;
+
+static dispatch_windows *dispatch_window_list;
+static dispatch_windows *dispatch_window_list1;
+
+/* Get dispatch group of insn. */
+
+static enum dispatch_group
+get_mem_group (rtx_insn *insn)
+{
+ enum attr_memory memory;
+
+ if (INSN_CODE (insn) < 0)
+ return disp_no_group;
+ memory = get_attr_memory (insn);
+ if (memory == MEMORY_STORE)
+ return disp_store;
+
+ if (memory == MEMORY_LOAD)
+ return disp_load;
+
+ if (memory == MEMORY_BOTH)
+ return disp_load_store;
+
+ return disp_no_group;
+}
+
+/* Return true if insn is a compare instruction. */
+
+static bool
+is_cmp (rtx_insn *insn)
+{
+ enum attr_type type;
+
+ type = get_attr_type (insn);
+ return (type == TYPE_TEST
+ || type == TYPE_ICMP
+ || type == TYPE_FCMP
+ || GET_CODE (PATTERN (insn)) == COMPARE);
+}
+
+/* Return true if a dispatch violation encountered. */
+
+static bool
+dispatch_violation (void)
+{
+ if (dispatch_window_list->next)
+ return dispatch_window_list->next->violation;
+ return dispatch_window_list->violation;
+}
+
+/* Return true if insn is a branch instruction. */
+
+static bool
+is_branch (rtx_insn *insn)
+{
+ return (CALL_P (insn) || JUMP_P (insn));
+}
+
+/* Return true if insn is a prefetch instruction. */
+
+static bool
+is_prefetch (rtx_insn *insn)
+{
+ return NONJUMP_INSN_P (insn) && GET_CODE (PATTERN (insn)) == PREFETCH;
+}
+
+/* This function initializes a dispatch window and the list container holding a
+ pointer to the window. */
+
+static void
+init_window (int window_num)
+{
+ int i;
+ dispatch_windows *new_list;
+
+ if (window_num == 0)
+ new_list = dispatch_window_list;
+ else
+ new_list = dispatch_window_list1;
+
+ new_list->num_insn = 0;
+ new_list->num_uops = 0;
+ new_list->window_size = 0;
+ new_list->next = NULL;
+ new_list->prev = NULL;
+ new_list->window_num = window_num;
+ new_list->num_imm = 0;
+ new_list->num_imm_32 = 0;
+ new_list->num_imm_64 = 0;
+ new_list->imm_size = 0;
+ new_list->num_loads = 0;
+ new_list->num_stores = 0;
+ new_list->violation = false;
+
+ for (i = 0; i < MAX_INSN; i++)
+ {
+ new_list->window[i].insn = NULL;
+ new_list->window[i].group = disp_no_group;
+ new_list->window[i].path = no_path;
+ new_list->window[i].byte_len = 0;
+ new_list->window[i].imm_bytes = 0;
+ }
+ return;
+}
+
+/* This function allocates and initializes a dispatch window and the
+ list container holding a pointer to the window. */
+
+static dispatch_windows *
+allocate_window (void)
+{
+ dispatch_windows *new_list = XNEW (struct dispatch_windows_s);
+ new_list->window = XNEWVEC (struct sched_insn_info_s, MAX_INSN + 1);
+
+ return new_list;
+}
+
+/* This routine initializes the dispatch scheduling information. It
+ initiates building dispatch scheduler tables and constructs the
+ first dispatch window. */
+
+static void
+init_dispatch_sched (void)
+{
+ /* Allocate a dispatch list and a window. */
+ dispatch_window_list = allocate_window ();
+ dispatch_window_list1 = allocate_window ();
+ init_window (0);
+ init_window (1);
+}
+
+/* This function returns true if a branch is detected. End of a basic block
+ does not have to be a branch, but here we assume only branches end a
+ window. */
+
+static bool
+is_end_basic_block (enum dispatch_group group)
+{
+ return group == disp_branch;
+}
+
+/* This function is called when the end of a window processing is reached. */
+
+static void
+process_end_window (void)
+{
+ gcc_assert (dispatch_window_list->num_insn <= MAX_INSN);
+ if (dispatch_window_list->next)
+ {
+ gcc_assert (dispatch_window_list1->num_insn <= MAX_INSN);
+ gcc_assert (dispatch_window_list->window_size
+ + dispatch_window_list1->window_size <= 48);
+ init_window (1);
+ }
+ init_window (0);
+}
+
+/* Allocates a new dispatch window and adds it to WINDOW_LIST.
+ WINDOW_NUM is either 0 or 1. A maximum of two windows are generated
+ for 48 bytes of instructions. Note that these windows are not dispatch
+ windows that their sizes are DISPATCH_WINDOW_SIZE. */
+
+static dispatch_windows *
+allocate_next_window (int window_num)
+{
+ if (window_num == 0)
+ {
+ if (dispatch_window_list->next)
+ init_window (1);
+ init_window (0);
+ return dispatch_window_list;
+ }
+
+ dispatch_window_list->next = dispatch_window_list1;
+ dispatch_window_list1->prev = dispatch_window_list;
+
+ return dispatch_window_list1;
+}
+
+/* Compute number of immediate operands of an instruction. */
+
+static void
+find_constant (rtx in_rtx, imm_info *imm_values)
+{
+ if (INSN_P (in_rtx))
+ in_rtx = PATTERN (in_rtx);
+ subrtx_iterator::array_type array;
+ FOR_EACH_SUBRTX (iter, array, in_rtx, ALL)
+ if (const_rtx x = *iter)
+ switch (GET_CODE (x))
+ {
+ case CONST:
+ case SYMBOL_REF:
+ case CONST_INT:
+ (imm_values->imm)++;
+ if (x86_64_immediate_operand (CONST_CAST_RTX (x), SImode))
+ (imm_values->imm32)++;
+ else
+ (imm_values->imm64)++;
+ break;
+
+ case CONST_DOUBLE:
+ case CONST_WIDE_INT:
+ (imm_values->imm)++;
+ (imm_values->imm64)++;
+ break;
+
+ case CODE_LABEL:
+ if (LABEL_KIND (x) == LABEL_NORMAL)
+ {
+ (imm_values->imm)++;
+ (imm_values->imm32)++;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+/* Return total size of immediate operands of an instruction along with number
+ of corresponding immediate-operands. It initializes its parameters to zero
+ befor calling FIND_CONSTANT.
+ INSN is the input instruction. IMM is the total of immediates.
+ IMM32 is the number of 32 bit immediates. IMM64 is the number of 64
+ bit immediates. */
+
+static int
+get_num_immediates (rtx_insn *insn, int *imm, int *imm32, int *imm64)
+{
+ imm_info imm_values = {0, 0, 0};
+
+ find_constant (insn, &imm_values);
+ *imm = imm_values.imm;
+ *imm32 = imm_values.imm32;
+ *imm64 = imm_values.imm64;
+ return imm_values.imm32 * 4 + imm_values.imm64 * 8;
+}
+
+/* This function indicates if an operand of an instruction is an
+ immediate. */
+
+static bool
+has_immediate (rtx_insn *insn)
+{
+ int num_imm_operand;
+ int num_imm32_operand;
+ int num_imm64_operand;
+
+ if (insn)
+ return get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
+ &num_imm64_operand);
+ return false;
+}
+
+/* Return single or double path for instructions. */
+
+static enum insn_path
+get_insn_path (rtx_insn *insn)
+{
+ enum attr_amdfam10_decode path = get_attr_amdfam10_decode (insn);
+
+ if ((int)path == 0)
+ return path_single;
+
+ if ((int)path == 1)
+ return path_double;
+
+ return path_multi;
+}
+
+/* Return insn dispatch group. */
+
+static enum dispatch_group
+get_insn_group (rtx_insn *insn)
+{
+ enum dispatch_group group = get_mem_group (insn);
+ if (group)
+ return group;
+
+ if (is_branch (insn))
+ return disp_branch;
+
+ if (is_cmp (insn))
+ return disp_cmp;
+
+ if (has_immediate (insn))
+ return disp_imm;
+
+ if (is_prefetch (insn))
+ return disp_prefetch;
+
+ return disp_no_group;
+}
+
+/* Count number of GROUP restricted instructions in a dispatch
+ window WINDOW_LIST. */
+
+static int
+count_num_restricted (rtx_insn *insn, dispatch_windows *window_list)
+{
+ enum dispatch_group group = get_insn_group (insn);
+ int imm_size;
+ int num_imm_operand;
+ int num_imm32_operand;
+ int num_imm64_operand;
+
+ if (group == disp_no_group)
+ return 0;
+
+ if (group == disp_imm)
+ {
+ imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
+ &num_imm64_operand);
+ if (window_list->imm_size + imm_size > MAX_IMM_SIZE
+ || num_imm_operand + window_list->num_imm > MAX_IMM
+ || (num_imm32_operand > 0
+ && (window_list->num_imm_32 + num_imm32_operand > MAX_IMM_32
+ || window_list->num_imm_64 * 2 + num_imm32_operand > MAX_IMM_32))
+ || (num_imm64_operand > 0
+ && (window_list->num_imm_64 + num_imm64_operand > MAX_IMM_64
+ || window_list->num_imm_32 + num_imm64_operand * 2 > MAX_IMM_32))
+ || (window_list->imm_size + imm_size == MAX_IMM_SIZE
+ && num_imm64_operand > 0
+ && ((window_list->num_imm_64 > 0
+ && window_list->num_insn >= 2)
+ || window_list->num_insn >= 3)))
+ return BIG;
+
+ return 1;
+ }
+
+ if ((group == disp_load_store
+ && (window_list->num_loads >= MAX_LOAD
+ || window_list->num_stores >= MAX_STORE))
+ || ((group == disp_load
+ || group == disp_prefetch)
+ && window_list->num_loads >= MAX_LOAD)
+ || (group == disp_store
+ && window_list->num_stores >= MAX_STORE))
+ return BIG;
+
+ return 1;
+}
+
+/* This function returns true if insn satisfies dispatch rules on the
+ last window scheduled. */
+
+static bool
+fits_dispatch_window (rtx_insn *insn)
+{
+ dispatch_windows *window_list = dispatch_window_list;
+ dispatch_windows *window_list_next = dispatch_window_list->next;
+ unsigned int num_restrict;
+ enum dispatch_group group = get_insn_group (insn);
+ enum insn_path path = get_insn_path (insn);
+ int sum;
+
+ /* Make disp_cmp and disp_jcc get scheduled at the latest. These
+ instructions should be given the lowest priority in the
+ scheduling process in Haifa scheduler to make sure they will be
+ scheduled in the same dispatch window as the reference to them. */
+ if (group == disp_jcc || group == disp_cmp)
+ return false;
+
+ /* Check nonrestricted. */
+ if (group == disp_no_group || group == disp_branch)
+ return true;
+
+ /* Get last dispatch window. */
+ if (window_list_next)
+ window_list = window_list_next;
+
+ if (window_list->window_num == 1)
+ {
+ sum = window_list->prev->window_size + window_list->window_size;
+
+ if (sum == 32
+ || (ix86_min_insn_size (insn) + sum) >= 48)
+ /* Window 1 is full. Go for next window. */
+ return true;
+ }
+
+ num_restrict = count_num_restricted (insn, window_list);
+
+ if (num_restrict > num_allowable_groups[group])
+ return false;
+
+ /* See if it fits in the first window. */
+ if (window_list->window_num == 0)
+ {
+ /* The first widow should have only single and double path
+ uops. */
+ if (path == path_double
+ && (window_list->num_uops + 2) > MAX_INSN)
+ return false;
+ else if (path != path_single)
+ return false;
+ }
+ return true;
+}
+
+/* Add an instruction INSN with NUM_UOPS micro-operations to the
+ dispatch window WINDOW_LIST. */
+
+static void
+add_insn_window (rtx_insn *insn, dispatch_windows *window_list, int num_uops)
+{
+ int byte_len = ix86_min_insn_size (insn);
+ int num_insn = window_list->num_insn;
+ int imm_size;
+ sched_insn_info *window = window_list->window;
+ enum dispatch_group group = get_insn_group (insn);
+ enum insn_path path = get_insn_path (insn);
+ int num_imm_operand;
+ int num_imm32_operand;
+ int num_imm64_operand;
+
+ if (!window_list->violation && group != disp_cmp
+ && !fits_dispatch_window (insn))
+ window_list->violation = true;
+
+ imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
+ &num_imm64_operand);
+
+ /* Initialize window with new instruction. */
+ window[num_insn].insn = insn;
+ window[num_insn].byte_len = byte_len;
+ window[num_insn].group = group;
+ window[num_insn].path = path;
+ window[num_insn].imm_bytes = imm_size;
+
+ window_list->window_size += byte_len;
+ window_list->num_insn = num_insn + 1;
+ window_list->num_uops = window_list->num_uops + num_uops;
+ window_list->imm_size += imm_size;
+ window_list->num_imm += num_imm_operand;
+ window_list->num_imm_32 += num_imm32_operand;
+ window_list->num_imm_64 += num_imm64_operand;
+
+ if (group == disp_store)
+ window_list->num_stores += 1;
+ else if (group == disp_load
+ || group == disp_prefetch)
+ window_list->num_loads += 1;
+ else if (group == disp_load_store)
+ {
+ window_list->num_stores += 1;
+ window_list->num_loads += 1;
+ }
+}
+
+/* Adds a scheduled instruction, INSN, to the current dispatch window.
+ If the total bytes of instructions or the number of instructions in
+ the window exceed allowable, it allocates a new window. */
+
+static void
+add_to_dispatch_window (rtx_insn *insn)
+{
+ int byte_len;
+ dispatch_windows *window_list;
+ dispatch_windows *next_list;
+ dispatch_windows *window0_list;
+ enum insn_path path;
+ enum dispatch_group insn_group;
+ bool insn_fits;
+ int num_insn;
+ int num_uops;
+ int window_num;
+ int insn_num_uops;
+ int sum;
+
+ if (INSN_CODE (insn) < 0)
+ return;
+
+ byte_len = ix86_min_insn_size (insn);
+ window_list = dispatch_window_list;
+ next_list = window_list->next;
+ path = get_insn_path (insn);
+ insn_group = get_insn_group (insn);
+
+ /* Get the last dispatch window. */
+ if (next_list)
+ window_list = dispatch_window_list->next;
+
+ if (path == path_single)
+ insn_num_uops = 1;
+ else if (path == path_double)
+ insn_num_uops = 2;
+ else
+ insn_num_uops = (int) path;
+
+ /* If current window is full, get a new window.
+ Window number zero is full, if MAX_INSN uops are scheduled in it.
+ Window number one is full, if window zero's bytes plus window
+ one's bytes is 32, or if the bytes of the new instruction added
+ to the total makes it greater than 48, or it has already MAX_INSN
+ instructions in it. */
+ num_insn = window_list->num_insn;
+ num_uops = window_list->num_uops;
+ window_num = window_list->window_num;
+ insn_fits = fits_dispatch_window (insn);
+
+ if (num_insn >= MAX_INSN
+ || num_uops + insn_num_uops > MAX_INSN
+ || !(insn_fits))
+ {
+ window_num = ~window_num & 1;
+ window_list = allocate_next_window (window_num);
+ }
+
+ if (window_num == 0)
+ {
+ add_insn_window (insn, window_list, insn_num_uops);
+ if (window_list->num_insn >= MAX_INSN
+ && insn_group == disp_branch)
+ {
+ process_end_window ();
+ return;
+ }
+ }
+ else if (window_num == 1)
+ {
+ window0_list = window_list->prev;
+ sum = window0_list->window_size + window_list->window_size;
+ if (sum == 32
+ || (byte_len + sum) >= 48)
+ {
+ process_end_window ();
+ window_list = dispatch_window_list;
+ }
+
+ add_insn_window (insn, window_list, insn_num_uops);
+ }
+ else
+ gcc_unreachable ();
+
+ if (is_end_basic_block (insn_group))
+ {
+ /* End of basic block is reached do end-basic-block process. */
+ process_end_window ();
+ return;
+ }
+}
+
+/* Print the dispatch window, WINDOW_NUM, to FILE. */
+
+DEBUG_FUNCTION static void
+debug_dispatch_window_file (FILE *file, int window_num)
+{
+ dispatch_windows *list;
+ int i;
+
+ if (window_num == 0)
+ list = dispatch_window_list;
+ else
+ list = dispatch_window_list1;
+
+ fprintf (file, "Window #%d:\n", list->window_num);
+ fprintf (file, " num_insn = %d, num_uops = %d, window_size = %d\n",
+ list->num_insn, list->num_uops, list->window_size);
+ fprintf (file, " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
+ list->num_imm, list->num_imm_32, list->num_imm_64, list->imm_size);
+
+ fprintf (file, " num_loads = %d, num_stores = %d\n", list->num_loads,
+ list->num_stores);
+ fprintf (file, " insn info:\n");
+
+ for (i = 0; i < MAX_INSN; i++)
+ {
+ if (!list->window[i].insn)
+ break;
+ fprintf (file, " group[%d] = %s, insn[%d] = %p, path[%d] = %d byte_len[%d] = %d, imm_bytes[%d] = %d\n",
+ i, group_name[list->window[i].group],
+ i, (void *)list->window[i].insn,
+ i, list->window[i].path,
+ i, list->window[i].byte_len,
+ i, list->window[i].imm_bytes);
+ }
+}
+
+/* Print to stdout a dispatch window. */
+
+DEBUG_FUNCTION void
+debug_dispatch_window (int window_num)
+{
+ debug_dispatch_window_file (stdout, window_num);
+}
+
+/* Print INSN dispatch information to FILE. */
+
+DEBUG_FUNCTION static void
+debug_insn_dispatch_info_file (FILE *file, rtx_insn *insn)
+{
+ int byte_len;
+ enum insn_path path;
+ enum dispatch_group group;
+ int imm_size;
+ int num_imm_operand;
+ int num_imm32_operand;
+ int num_imm64_operand;
+
+ if (INSN_CODE (insn) < 0)
+ return;
+
+ byte_len = ix86_min_insn_size (insn);
+ path = get_insn_path (insn);
+ group = get_insn_group (insn);
+ imm_size = get_num_immediates (insn, &num_imm_operand, &num_imm32_operand,
+ &num_imm64_operand);
+
+ fprintf (file, " insn info:\n");
+ fprintf (file, " group = %s, path = %d, byte_len = %d\n",
+ group_name[group], path, byte_len);
+ fprintf (file, " num_imm = %d, num_imm_32 = %d, num_imm_64 = %d, imm_size = %d\n",
+ num_imm_operand, num_imm32_operand, num_imm64_operand, imm_size);
+}
+
+/* Print to STDERR the status of the ready list with respect to
+ dispatch windows. */
+
+DEBUG_FUNCTION void
+debug_ready_dispatch (void)
+{
+ int i;
+ int no_ready = number_in_ready ();
+
+ fprintf (stdout, "Number of ready: %d\n", no_ready);
+
+ for (i = 0; i < no_ready; i++)
+ debug_insn_dispatch_info_file (stdout, get_ready_element (i));
+}
+
+/* This routine is the driver of the dispatch scheduler. */
+
+void
+ix86_bd_do_dispatch (rtx_insn *insn, int mode)
+{
+ if (mode == DISPATCH_INIT)
+ init_dispatch_sched ();
+ else if (mode == ADD_TO_DISPATCH_WINDOW)
+ add_to_dispatch_window (insn);
+}
+
+/* Return TRUE if Dispatch Scheduling is supported. */
+
+bool
+ix86_bd_has_dispatch (rtx_insn *insn, int action)
+{
+ /* Current implementation of dispatch scheduler models buldozer only. */
+ if ((TARGET_BDVER1 || TARGET_BDVER2 || TARGET_BDVER3
+ || TARGET_BDVER4) && flag_dispatch_scheduler)
+ switch (action)
+ {
+ default:
+ return false;
+
+ case IS_DISPATCH_ON:
+ return true;
+
+ case IS_CMP:
+ return is_cmp (insn);
+
+ case DISPATCH_VIOLATION:
+ return dispatch_violation ();
+
+ case FITS_DISPATCH_WINDOW:
+ return fits_dispatch_window (insn);
+ }
+
+ return false;
+}
diff --git a/gcc/config/i386/x86-tune-sched-core.c b/gcc/config/i386/x86-tune-sched-core.c
new file mode 100644
index 0000000..67b14a7
--- /dev/null
+++ b/gcc/config/i386/x86-tune-sched-core.c
@@ -0,0 +1,255 @@
+/* Scheduler hooks for IA-32 which implement bdver1-4 specific logic.
+ Copyright (C) 1988-2017 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "insn-attr.h"
+#include "recog.h"
+#include "target.h"
+#include "rtl-iter.h"
+#include "regset.h"
+#include "sched-int.h"
+
+
+/* Model decoder of Core 2/i7.
+ Below hooks for multipass scheduling (see haifa-sched.c:max_issue)
+ track the instruction fetch block boundaries and make sure that long
+ (9+ bytes) instructions are assigned to D0. */
+
+/* Maximum length of an insn that can be handled by
+ a secondary decoder unit. '8' for Core 2/i7. */
+static int core2i7_secondary_decoder_max_insn_size;
+
+/* Ifetch block size, i.e., number of bytes decoder reads per cycle.
+ '16' for Core 2/i7. */
+static int core2i7_ifetch_block_size;
+
+/* Maximum number of instructions decoder can handle per cycle.
+ '6' for Core 2/i7. */
+static int core2i7_ifetch_block_max_insns;
+
+typedef struct ix86_first_cycle_multipass_data_ *
+ ix86_first_cycle_multipass_data_t;
+typedef const struct ix86_first_cycle_multipass_data_ *
+ const_ix86_first_cycle_multipass_data_t;
+
+/* A variable to store target state across calls to max_issue within
+ one cycle. */
+static struct ix86_first_cycle_multipass_data_ _ix86_first_cycle_multipass_data,
+ *ix86_first_cycle_multipass_data = &_ix86_first_cycle_multipass_data;
+
+/* Initialize DATA. */
+static void
+core2i7_first_cycle_multipass_init (void *_data)
+{
+ ix86_first_cycle_multipass_data_t data
+ = (ix86_first_cycle_multipass_data_t) _data;
+
+ data->ifetch_block_len = 0;
+ data->ifetch_block_n_insns = 0;
+ data->ready_try_change = NULL;
+ data->ready_try_change_size = 0;
+}
+
+/* Advancing the cycle; reset ifetch block counts. */
+static void
+core2i7_dfa_post_advance_cycle (void)
+{
+ ix86_first_cycle_multipass_data_t data = ix86_first_cycle_multipass_data;
+
+ gcc_assert (data->ifetch_block_n_insns <= core2i7_ifetch_block_max_insns);
+
+ data->ifetch_block_len = 0;
+ data->ifetch_block_n_insns = 0;
+}
+
+/* Filter out insns from ready_try that the core will not be able to issue
+ on current cycle due to decoder. */
+static void
+core2i7_first_cycle_multipass_filter_ready_try
+(const_ix86_first_cycle_multipass_data_t data,
+ signed char *ready_try, int n_ready, bool first_cycle_insn_p)
+{
+ while (n_ready--)
+ {
+ rtx_insn *insn;
+ int insn_size;
+
+ if (ready_try[n_ready])
+ continue;
+
+ insn = get_ready_element (n_ready);
+ insn_size = ix86_min_insn_size (insn);
+
+ if (/* If this is a too long an insn for a secondary decoder ... */
+ (!first_cycle_insn_p
+ && insn_size > core2i7_secondary_decoder_max_insn_size)
+ /* ... or it would not fit into the ifetch block ... */
+ || data->ifetch_block_len + insn_size > core2i7_ifetch_block_size
+ /* ... or the decoder is full already ... */
+ || data->ifetch_block_n_insns + 1 > core2i7_ifetch_block_max_insns)
+ /* ... mask the insn out. */
+ {
+ ready_try[n_ready] = 1;
+
+ if (data->ready_try_change)
+ bitmap_set_bit (data->ready_try_change, n_ready);
+ }
+ }
+}
+
+/* Prepare for a new round of multipass lookahead scheduling. */
+static void
+core2i7_first_cycle_multipass_begin (void *_data,
+ signed char *ready_try, int n_ready,
+ bool first_cycle_insn_p)
+{
+ ix86_first_cycle_multipass_data_t data
+ = (ix86_first_cycle_multipass_data_t) _data;
+ const_ix86_first_cycle_multipass_data_t prev_data
+ = ix86_first_cycle_multipass_data;
+
+ /* Restore the state from the end of the previous round. */
+ data->ifetch_block_len = prev_data->ifetch_block_len;
+ data->ifetch_block_n_insns = prev_data->ifetch_block_n_insns;
+
+ /* Filter instructions that cannot be issued on current cycle due to
+ decoder restrictions. */
+ core2i7_first_cycle_multipass_filter_ready_try (data, ready_try, n_ready,
+ first_cycle_insn_p);
+}
+
+/* INSN is being issued in current solution. Account for its impact on
+ the decoder model. */
+static void
+core2i7_first_cycle_multipass_issue (void *_data,
+ signed char *ready_try, int n_ready,
+ rtx_insn *insn, const void *_prev_data)
+{
+ ix86_first_cycle_multipass_data_t data
+ = (ix86_first_cycle_multipass_data_t) _data;
+ const_ix86_first_cycle_multipass_data_t prev_data
+ = (const_ix86_first_cycle_multipass_data_t) _prev_data;
+
+ int insn_size = ix86_min_insn_size (insn);
+
+ data->ifetch_block_len = prev_data->ifetch_block_len + insn_size;
+ data->ifetch_block_n_insns = prev_data->ifetch_block_n_insns + 1;
+ gcc_assert (data->ifetch_block_len <= core2i7_ifetch_block_size
+ && data->ifetch_block_n_insns <= core2i7_ifetch_block_max_insns);
+
+ /* Allocate or resize the bitmap for storing INSN's effect on ready_try. */
+ if (!data->ready_try_change)
+ {
+ data->ready_try_change = sbitmap_alloc (n_ready);
+ data->ready_try_change_size = n_ready;
+ }
+ else if (data->ready_try_change_size < n_ready)
+ {
+ data->ready_try_change = sbitmap_resize (data->ready_try_change,
+ n_ready, 0);
+ data->ready_try_change_size = n_ready;
+ }
+ bitmap_clear (data->ready_try_change);
+
+ /* Filter out insns from ready_try that the core will not be able to issue
+ on current cycle due to decoder. */
+ core2i7_first_cycle_multipass_filter_ready_try (data, ready_try, n_ready,
+ false);
+}
+
+/* Revert the effect on ready_try. */
+static void
+core2i7_first_cycle_multipass_backtrack (const void *_data,
+ signed char *ready_try,
+ int n_ready ATTRIBUTE_UNUSED)
+{
+ const_ix86_first_cycle_multipass_data_t data
+ = (const_ix86_first_cycle_multipass_data_t) _data;
+ unsigned int i = 0;
+ sbitmap_iterator sbi;
+
+ gcc_assert (bitmap_last_set_bit (data->ready_try_change) < n_ready);
+ EXECUTE_IF_SET_IN_BITMAP (data->ready_try_change, 0, i, sbi)
+ {
+ ready_try[i] = 0;
+ }
+}
+
+/* Save the result of multipass lookahead scheduling for the next round. */
+static void
+core2i7_first_cycle_multipass_end (const void *_data)
+{
+ const_ix86_first_cycle_multipass_data_t data
+ = (const_ix86_first_cycle_multipass_data_t) _data;
+ ix86_first_cycle_multipass_data_t next_data
+ = ix86_first_cycle_multipass_data;
+
+ if (data != NULL)
+ {
+ next_data->ifetch_block_len = data->ifetch_block_len;
+ next_data->ifetch_block_n_insns = data->ifetch_block_n_insns;
+ }
+}
+
+/* Deallocate target data. */
+static void
+core2i7_first_cycle_multipass_fini (void *_data)
+{
+ ix86_first_cycle_multipass_data_t data
+ = (ix86_first_cycle_multipass_data_t) _data;
+
+ if (data->ready_try_change)
+ {
+ sbitmap_free (data->ready_try_change);
+ data->ready_try_change = NULL;
+ data->ready_try_change_size = 0;
+ }
+}
+
+void
+ix86_core2i7_init_hooks (void)
+{
+ targetm.sched.dfa_post_advance_cycle
+ = core2i7_dfa_post_advance_cycle;
+ targetm.sched.first_cycle_multipass_init
+ = core2i7_first_cycle_multipass_init;
+ targetm.sched.first_cycle_multipass_begin
+ = core2i7_first_cycle_multipass_begin;
+ targetm.sched.first_cycle_multipass_issue
+ = core2i7_first_cycle_multipass_issue;
+ targetm.sched.first_cycle_multipass_backtrack
+ = core2i7_first_cycle_multipass_backtrack;
+ targetm.sched.first_cycle_multipass_end
+ = core2i7_first_cycle_multipass_end;
+ targetm.sched.first_cycle_multipass_fini
+ = core2i7_first_cycle_multipass_fini;
+
+ /* Set decoder parameters. */
+ core2i7_secondary_decoder_max_insn_size = 8;
+ core2i7_ifetch_block_size = 16;
+ core2i7_ifetch_block_max_insns = 6;
+}
diff --git a/gcc/config/i386/x86-tune-sched.c b/gcc/config/i386/x86-tune-sched.c
new file mode 100644
index 0000000..aac2bae
--- /dev/null
+++ b/gcc/config/i386/x86-tune-sched.c
@@ -0,0 +1,627 @@
+/* Scheduler hooks for IA-32 which implement CPU specific logic.
+ Copyright (C) 1988-2017 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "backend.h"
+#include "rtl.h"
+#include "tree.h"
+#include "cfghooks.h"
+#include "tm_p.h"
+#include "insn-config.h"
+#include "insn-attr.h"
+#include "recog.h"
+#include "target.h"
+
+/* Return the maximum number of instructions a cpu can issue. */
+
+int
+ix86_issue_rate (void)
+{
+ switch (ix86_tune)
+ {
+ case PROCESSOR_PENTIUM:
+ case PROCESSOR_LAKEMONT:
+ case PROCESSOR_BONNELL:
+ case PROCESSOR_SILVERMONT:
+ case PROCESSOR_KNL:
+ case PROCESSOR_KNM:
+ case PROCESSOR_INTEL:
+ case PROCESSOR_K6:
+ case PROCESSOR_BTVER2:
+ case PROCESSOR_PENTIUM4:
+ case PROCESSOR_NOCONA:
+ return 2;
+
+ case PROCESSOR_PENTIUMPRO:
+ case PROCESSOR_ATHLON:
+ case PROCESSOR_K8:
+ case PROCESSOR_AMDFAM10:
+ case PROCESSOR_GENERIC:
+ case PROCESSOR_BTVER1:
+ return 3;
+
+ case PROCESSOR_BDVER1:
+ case PROCESSOR_BDVER2:
+ case PROCESSOR_BDVER3:
+ case PROCESSOR_BDVER4:
+ case PROCESSOR_ZNVER1:
+ case PROCESSOR_CORE2:
+ case PROCESSOR_NEHALEM:
+ case PROCESSOR_SANDYBRIDGE:
+ case PROCESSOR_HASWELL:
+ return 4;
+
+ default:
+ return 1;
+ }
+}
+
+/* Return true iff USE_INSN has a memory address with operands set by
+ SET_INSN. */
+
+bool
+ix86_agi_dependent (rtx_insn *set_insn, rtx_insn *use_insn)
+{
+ int i;
+ extract_insn_cached (use_insn);
+ for (i = recog_data.n_operands - 1; i >= 0; --i)
+ if (MEM_P (recog_data.operand[i]))
+ {
+ rtx addr = XEXP (recog_data.operand[i], 0);
+ if (modified_in_p (addr, set_insn) != 0)
+ {
+ /* No AGI stall if SET_INSN is a push or pop and USE_INSN
+ has SP based memory (unless index reg is modified in a pop). */
+ rtx set = single_set (set_insn);
+ if (set
+ && (push_operand (SET_DEST (set), GET_MODE (SET_DEST (set)))
+ || pop_operand (SET_SRC (set), GET_MODE (SET_SRC (set)))))
+ {
+ struct ix86_address parts;
+ if (ix86_decompose_address (addr, &parts)
+ && parts.base == stack_pointer_rtx
+ && (parts.index == NULL_RTX
+ || MEM_P (SET_DEST (set))
+ || !modified_in_p (parts.index, set_insn)))
+ return false;
+ }
+ return true;
+ }
+ return false;
+ }
+ return false;
+}
+
+/* A subroutine of ix86_adjust_cost -- return TRUE iff INSN reads flags set
+ by DEP_INSN and nothing set by DEP_INSN. */
+
+static bool
+ix86_flags_dependent (rtx_insn *insn, rtx_insn *dep_insn, enum attr_type insn_type)
+{
+ rtx set, set2;
+
+ /* Simplify the test for uninteresting insns. */
+ if (insn_type != TYPE_SETCC
+ && insn_type != TYPE_ICMOV
+ && insn_type != TYPE_FCMOV
+ && insn_type != TYPE_IBR)
+ return false;
+
+ if ((set = single_set (dep_insn)) != 0)
+ {
+ set = SET_DEST (set);
+ set2 = NULL_RTX;
+ }
+ else if (GET_CODE (PATTERN (dep_insn)) == PARALLEL
+ && XVECLEN (PATTERN (dep_insn), 0) == 2
+ && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 0)) == SET
+ && GET_CODE (XVECEXP (PATTERN (dep_insn), 0, 1)) == SET)
+ {
+ set = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
+ set2 = SET_DEST (XVECEXP (PATTERN (dep_insn), 0, 0));
+ }
+ else
+ return false;
+
+ if (!REG_P (set) || REGNO (set) != FLAGS_REG)
+ return false;
+
+ /* This test is true if the dependent insn reads the flags but
+ not any other potentially set register. */
+ if (!reg_overlap_mentioned_p (set, PATTERN (insn)))
+ return false;
+
+ if (set2 && reg_overlap_mentioned_p (set2, PATTERN (insn)))
+ return false;
+
+ return true;
+}
+
+/* Helper function for exact_store_load_dependency.
+ Return true if addr is found in insn. */
+static bool
+exact_dependency_1 (rtx addr, rtx insn)
+{
+ enum rtx_code code;
+ const char *format_ptr;
+ int i, j;
+
+ code = GET_CODE (insn);
+ switch (code)
+ {
+ case MEM:
+ if (rtx_equal_p (addr, insn))
+ return true;
+ break;
+ case REG:
+ CASE_CONST_ANY:
+ case SYMBOL_REF:
+ case CODE_LABEL:
+ case PC:
+ case CC0:
+ case EXPR_LIST:
+ return false;
+ default:
+ break;
+ }
+
+ format_ptr = GET_RTX_FORMAT (code);
+ for (i = 0; i < GET_RTX_LENGTH (code); i++)
+ {
+ switch (*format_ptr++)
+ {
+ case 'e':
+ if (exact_dependency_1 (addr, XEXP (insn, i)))
+ return true;
+ break;
+ case 'E':
+ for (j = 0; j < XVECLEN (insn, i); j++)
+ if (exact_dependency_1 (addr, XVECEXP (insn, i, j)))
+ return true;
+ break;
+ }
+ }
+ return false;
+}
+
+/* Return true if there exists exact dependency for store & load, i.e.
+ the same memory address is used in them. */
+static bool
+exact_store_load_dependency (rtx_insn *store, rtx_insn *load)
+{
+ rtx set1, set2;
+
+ set1 = single_set (store);
+ if (!set1)
+ return false;
+ if (!MEM_P (SET_DEST (set1)))
+ return false;
+ set2 = single_set (load);
+ if (!set2)
+ return false;
+ if (exact_dependency_1 (SET_DEST (set1), SET_SRC (set2)))
+ return true;
+ return false;
+}
+
+
+/* This function corrects the value of COST (latency) based on the relationship
+ between INSN and DEP_INSN through a dependence of type DEP_TYPE, and strength
+ DW. It should return the new value.
+
+ On x86 CPUs this is most commonly used to model the fact that valus of
+ registers used to compute address of memory operand needs to be ready
+ earlier than values of registers used in the actual operation. */
+
+int
+ix86_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn, int cost,
+ unsigned int)
+{
+ enum attr_type insn_type, dep_insn_type;
+ enum attr_memory memory;
+ rtx set, set2;
+ int dep_insn_code_number;
+
+ /* Anti and output dependencies have zero cost on all CPUs. */
+ if (dep_type != 0)
+ return 0;
+
+ dep_insn_code_number = recog_memoized (dep_insn);
+
+ /* If we can't recognize the insns, we can't really do anything. */
+ if (dep_insn_code_number < 0 || recog_memoized (insn) < 0)
+ return cost;
+
+ insn_type = get_attr_type (insn);
+ dep_insn_type = get_attr_type (dep_insn);
+
+ switch (ix86_tune)
+ {
+ case PROCESSOR_PENTIUM:
+ case PROCESSOR_LAKEMONT:
+ /* Address Generation Interlock adds a cycle of latency. */
+ if (insn_type == TYPE_LEA)
+ {
+ rtx addr = PATTERN (insn);
+
+ if (GET_CODE (addr) == PARALLEL)
+ addr = XVECEXP (addr, 0, 0);
+
+ gcc_assert (GET_CODE (addr) == SET);
+
+ addr = SET_SRC (addr);
+ if (modified_in_p (addr, dep_insn))
+ cost += 1;
+ }
+ else if (ix86_agi_dependent (dep_insn, insn))
+ cost += 1;
+
+ /* ??? Compares pair with jump/setcc. */
+ if (ix86_flags_dependent (insn, dep_insn, insn_type))
+ cost = 0;
+
+ /* Floating point stores require value to be ready one cycle earlier. */
+ if (insn_type == TYPE_FMOV
+ && get_attr_memory (insn) == MEMORY_STORE
+ && !ix86_agi_dependent (dep_insn, insn))
+ cost += 1;
+ break;
+
+ case PROCESSOR_PENTIUMPRO:
+ /* INT->FP conversion is expensive. */
+ if (get_attr_fp_int_src (dep_insn))
+ cost += 5;
+
+ /* There is one cycle extra latency between an FP op and a store. */
+ if (insn_type == TYPE_FMOV
+ && (set = single_set (dep_insn)) != NULL_RTX
+ && (set2 = single_set (insn)) != NULL_RTX
+ && rtx_equal_p (SET_DEST (set), SET_SRC (set2))
+ && MEM_P (SET_DEST (set2)))
+ cost += 1;
+
+ memory = get_attr_memory (insn);
+
+ /* Show ability of reorder buffer to hide latency of load by executing
+ in parallel with previous instruction in case
+ previous instruction is not needed to compute the address. */
+ if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
+ && !ix86_agi_dependent (dep_insn, insn))
+ {
+ /* Claim moves to take one cycle, as core can issue one load
+ at time and the next load can start cycle later. */
+ if (dep_insn_type == TYPE_IMOV
+ || dep_insn_type == TYPE_FMOV)
+ cost = 1;
+ else if (cost > 1)
+ cost--;
+ }
+ break;
+
+ case PROCESSOR_K6:
+ /* The esp dependency is resolved before
+ the instruction is really finished. */
+ if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
+ && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
+ return 1;
+
+ /* INT->FP conversion is expensive. */
+ if (get_attr_fp_int_src (dep_insn))
+ cost += 5;
+
+ memory = get_attr_memory (insn);
+
+ /* Show ability of reorder buffer to hide latency of load by executing
+ in parallel with previous instruction in case
+ previous instruction is not needed to compute the address. */
+ if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
+ && !ix86_agi_dependent (dep_insn, insn))
+ {
+ /* Claim moves to take one cycle, as core can issue one load
+ at time and the next load can start cycle later. */
+ if (dep_insn_type == TYPE_IMOV
+ || dep_insn_type == TYPE_FMOV)
+ cost = 1;
+ else if (cost > 2)
+ cost -= 2;
+ else
+ cost = 1;
+ }
+ break;
+
+ case PROCESSOR_AMDFAM10:
+ case PROCESSOR_BDVER1:
+ case PROCESSOR_BDVER2:
+ case PROCESSOR_BDVER3:
+ case PROCESSOR_BDVER4:
+ case PROCESSOR_BTVER1:
+ case PROCESSOR_BTVER2:
+ case PROCESSOR_GENERIC:
+ /* Stack engine allows to execute push&pop instructions in parall. */
+ if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
+ && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
+ return 0;
+ /* FALLTHRU */
+
+ case PROCESSOR_ATHLON:
+ case PROCESSOR_K8:
+ memory = get_attr_memory (insn);
+
+ /* Show ability of reorder buffer to hide latency of load by executing
+ in parallel with previous instruction in case
+ previous instruction is not needed to compute the address. */
+ if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
+ && !ix86_agi_dependent (dep_insn, insn))
+ {
+ enum attr_unit unit = get_attr_unit (insn);
+ int loadcost = 3;
+
+ /* Because of the difference between the length of integer and
+ floating unit pipeline preparation stages, the memory operands
+ for floating point are cheaper.
+
+ ??? For Athlon it the difference is most probably 2. */
+ if (unit == UNIT_INTEGER || unit == UNIT_UNKNOWN)
+ loadcost = 3;
+ else
+ loadcost = TARGET_ATHLON ? 2 : 0;
+
+ if (cost >= loadcost)
+ cost -= loadcost;
+ else
+ cost = 0;
+ }
+ break;
+
+ case PROCESSOR_ZNVER1:
+ /* Stack engine allows to execute push&pop instructions in parall. */
+ if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
+ && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
+ return 0;
+
+ memory = get_attr_memory (insn);
+
+ /* Show ability of reorder buffer to hide latency of load by executing
+ in parallel with previous instruction in case
+ previous instruction is not needed to compute the address. */
+ if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
+ && !ix86_agi_dependent (dep_insn, insn))
+ {
+ enum attr_unit unit = get_attr_unit (insn);
+ int loadcost;
+
+ if (unit == UNIT_INTEGER || unit == UNIT_UNKNOWN)
+ loadcost = 4;
+ else
+ loadcost = 7;
+
+ if (cost >= loadcost)
+ cost -= loadcost;
+ else
+ cost = 0;
+ }
+ break;
+
+ case PROCESSOR_CORE2:
+ case PROCESSOR_NEHALEM:
+ case PROCESSOR_SANDYBRIDGE:
+ case PROCESSOR_HASWELL:
+ /* Stack engine allows to execute push&pop instructions in parall. */
+ if ((insn_type == TYPE_PUSH || insn_type == TYPE_POP)
+ && (dep_insn_type == TYPE_PUSH || dep_insn_type == TYPE_POP))
+ return 0;
+
+ memory = get_attr_memory (insn);
+
+ /* Show ability of reorder buffer to hide latency of load by executing
+ in parallel with previous instruction in case
+ previous instruction is not needed to compute the address. */
+ if ((memory == MEMORY_LOAD || memory == MEMORY_BOTH)
+ && !ix86_agi_dependent (dep_insn, insn))
+ {
+ if (cost >= 4)
+ cost -= 4;
+ else
+ cost = 0;
+ }
+ break;
+
+ case PROCESSOR_SILVERMONT:
+ case PROCESSOR_KNL:
+ case PROCESSOR_KNM:
+ case PROCESSOR_INTEL:
+ if (!reload_completed)
+ return cost;
+
+ /* Increase cost of integer loads. */
+ memory = get_attr_memory (dep_insn);
+ if (memory == MEMORY_LOAD || memory == MEMORY_BOTH)
+ {
+ enum attr_unit unit = get_attr_unit (dep_insn);
+ if (unit == UNIT_INTEGER && cost == 1)
+ {
+ if (memory == MEMORY_LOAD)
+ cost = 3;
+ else
+ {
+ /* Increase cost of ld/st for short int types only
+ because of store forwarding issue. */
+ rtx set = single_set (dep_insn);
+ if (set && (GET_MODE (SET_DEST (set)) == QImode
+ || GET_MODE (SET_DEST (set)) == HImode))
+ {
+ /* Increase cost of store/load insn if exact
+ dependence exists and it is load insn. */
+ enum attr_memory insn_memory = get_attr_memory (insn);
+ if (insn_memory == MEMORY_LOAD
+ && exact_store_load_dependency (dep_insn, insn))
+ cost = 3;
+ }
+ }
+ }
+ }
+
+ default:
+ break;
+ }
+
+ return cost;
+}
+
+/* How many alternative schedules to try. This should be as wide as the
+ scheduling freedom in the DFA, but no wider. Making this value too
+ large results extra work for the scheduler. */
+
+int
+ia32_multipass_dfa_lookahead (void)
+{
+ /* Generally, we want haifa-sched:max_issue() to look ahead as far
+ as many instructions can be executed on a cycle, i.e.,
+ issue_rate. */
+ if (reload_completed)
+ return ix86_issue_rate ();
+ /* Don't use lookahead for pre-reload schedule to save compile time. */
+ return 0;
+}
+
+/* Return true if target platform supports macro-fusion. */
+
+bool
+ix86_macro_fusion_p ()
+{
+ return TARGET_FUSE_CMP_AND_BRANCH;
+}
+
+/* Check whether current microarchitecture support macro fusion
+ for insn pair "CONDGEN + CONDJMP". Refer to
+ "Intel Architectures Optimization Reference Manual". */
+
+bool
+ix86_macro_fusion_pair_p (rtx_insn *condgen, rtx_insn *condjmp)
+{
+ rtx src, dest;
+ enum rtx_code ccode;
+ rtx compare_set = NULL_RTX, test_if, cond;
+ rtx alu_set = NULL_RTX, addr = NULL_RTX;
+
+ if (!any_condjump_p (condjmp))
+ return false;
+
+ unsigned int condreg1, condreg2;
+ rtx cc_reg_1;
+ targetm.fixed_condition_code_regs (&condreg1, &condreg2);
+ cc_reg_1 = gen_rtx_REG (CCmode, condreg1);
+ if (!reg_referenced_p (cc_reg_1, PATTERN (condjmp))
+ || !condgen
+ || !modified_in_p (cc_reg_1, condgen))
+ return false;
+
+ if (get_attr_type (condgen) != TYPE_TEST
+ && get_attr_type (condgen) != TYPE_ICMP
+ && get_attr_type (condgen) != TYPE_INCDEC
+ && get_attr_type (condgen) != TYPE_ALU)
+ return false;
+
+ compare_set = single_set (condgen);
+ if (compare_set == NULL_RTX
+ && !TARGET_FUSE_ALU_AND_BRANCH)
+ return false;
+
+ if (compare_set == NULL_RTX)
+ {
+ int i;
+ rtx pat = PATTERN (condgen);
+ for (i = 0; i < XVECLEN (pat, 0); i++)
+ if (GET_CODE (XVECEXP (pat, 0, i)) == SET)
+ {
+ rtx set_src = SET_SRC (XVECEXP (pat, 0, i));
+ if (GET_CODE (set_src) == COMPARE)
+ compare_set = XVECEXP (pat, 0, i);
+ else
+ alu_set = XVECEXP (pat, 0, i);
+ }
+ }
+ if (compare_set == NULL_RTX)
+ return false;
+ src = SET_SRC (compare_set);
+ if (GET_CODE (src) != COMPARE)
+ return false;
+
+ /* Macro-fusion for cmp/test MEM-IMM + conditional jmp is not
+ supported. */
+ if ((MEM_P (XEXP (src, 0))
+ && CONST_INT_P (XEXP (src, 1)))
+ || (MEM_P (XEXP (src, 1))
+ && CONST_INT_P (XEXP (src, 0))))
+ return false;
+
+ /* No fusion for RIP-relative address. */
+ if (MEM_P (XEXP (src, 0)))
+ addr = XEXP (XEXP (src, 0), 0);
+ else if (MEM_P (XEXP (src, 1)))
+ addr = XEXP (XEXP (src, 1), 0);
+
+ if (addr) {
+ ix86_address parts;
+ int ok = ix86_decompose_address (addr, &parts);
+ gcc_assert (ok);
+
+ if (ix86_rip_relative_addr_p (&parts))
+ return false;
+ }
+
+ test_if = SET_SRC (pc_set (condjmp));
+ cond = XEXP (test_if, 0);
+ ccode = GET_CODE (cond);
+ /* Check whether conditional jump use Sign or Overflow Flags. */
+ if (!TARGET_FUSE_CMP_AND_BRANCH_SOFLAGS
+ && (ccode == GE
+ || ccode == GT
+ || ccode == LE
+ || ccode == LT))
+ return false;
+
+ /* Return true for TYPE_TEST and TYPE_ICMP. */
+ if (get_attr_type (condgen) == TYPE_TEST
+ || get_attr_type (condgen) == TYPE_ICMP)
+ return true;
+
+ /* The following is the case that macro-fusion for alu + jmp. */
+ if (!TARGET_FUSE_ALU_AND_BRANCH || !alu_set)
+ return false;
+
+ /* No fusion for alu op with memory destination operand. */
+ dest = SET_DEST (alu_set);
+ if (MEM_P (dest))
+ return false;
+
+ /* Macro-fusion for inc/dec + unsigned conditional jump is not
+ supported. */
+ if (get_attr_type (condgen) == TYPE_INCDEC
+ && (ccode == GEU
+ || ccode == GTU
+ || ccode == LEU
+ || ccode == LTU))
+ return false;
+
+ return true;
+}
+
diff --git a/gcc/config/i386/x86-tune.def b/gcc/config/i386/x86-tune.def
index c642f45..9d01761 100644
--- a/gcc/config/i386/x86-tune.def
+++ b/gcc/config/i386/x86-tune.def
@@ -41,7 +41,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
/* X86_TUNE_SCHEDULE: Enable scheduling. */
DEF_TUNE (X86_TUNE_SCHEDULE, "schedule",
m_PENT | m_LAKEMONT | m_PPRO | m_CORE_ALL | m_BONNELL | m_SILVERMONT
- | m_INTEL | m_KNL | m_K6_GEODE | m_AMD_MULTIPLE | m_GENERIC)
+ | m_INTEL | m_KNL | m_KNM | m_K6_GEODE | m_AMD_MULTIPLE | m_GENERIC)
/* X86_TUNE_PARTIAL_REG_DEPENDENCY: Enable more register renaming
on modern chips. Preffer stores affecting whole integer register
@@ -49,7 +49,7 @@ DEF_TUNE (X86_TUNE_SCHEDULE, "schedule",
value over movb. */
DEF_TUNE (X86_TUNE_PARTIAL_REG_DEPENDENCY, "partial_reg_dependency",
m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_INTEL
- | m_KNL | m_AMD_MULTIPLE | m_GENERIC)
+ | m_KNL | m_KNM | m_AMD_MULTIPLE | m_GENERIC)
/* X86_TUNE_SSE_PARTIAL_REG_DEPENDENCY: This knob promotes all store
destinations to be 128bit to allow register renaming on 128bit SSE units,
@@ -85,13 +85,13 @@ DEF_TUNE (X86_TUNE_PARTIAL_FLAG_REG_STALL, "partial_flag_reg_stall",
partial dependencies. */
DEF_TUNE (X86_TUNE_MOVX, "movx",
m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT
- | m_KNL | m_INTEL | m_GEODE | m_AMD_MULTIPLE | m_GENERIC)
+ | m_KNL | m_KNM | m_INTEL | m_GEODE | m_AMD_MULTIPLE | m_GENERIC)
/* X86_TUNE_MEMORY_MISMATCH_STALL: Avoid partial stores that are followed by
full sized loads. */
DEF_TUNE (X86_TUNE_MEMORY_MISMATCH_STALL, "memory_mismatch_stall",
m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_INTEL
- | m_KNL | m_AMD_MULTIPLE | m_GENERIC)
+ | m_KNL | m_KNM | m_AMD_MULTIPLE | m_GENERIC)
/* X86_TUNE_FUSE_CMP_AND_BRANCH_32: Fuse compare with a subsequent
conditional jump instruction for 32 bit TARGET.
@@ -117,16 +117,6 @@ DEF_TUNE (X86_TUNE_FUSE_CMP_AND_BRANCH_SOFLAGS, "fuse_cmp_and_branch_soflags",
DEF_TUNE (X86_TUNE_FUSE_ALU_AND_BRANCH, "fuse_alu_and_branch",
m_SANDYBRIDGE | m_HASWELL)
-/* X86_TUNE_REASSOC_INT_TO_PARALLEL: Try to produce parallel computations
- during reassociation of integer computation. */
-DEF_TUNE (X86_TUNE_REASSOC_INT_TO_PARALLEL, "reassoc_int_to_parallel",
- m_BONNELL)
-
-/* X86_TUNE_REASSOC_FP_TO_PARALLEL: Try to produce parallel computations
- during reassociation of fp computation. */
-DEF_TUNE (X86_TUNE_REASSOC_FP_TO_PARALLEL, "reassoc_fp_to_parallel",
- m_BONNELL | m_SILVERMONT | m_HASWELL | m_KNL |m_INTEL | m_BDVER1
- | m_BDVER2 | m_ZNVER1 | m_GENERIC)
/*****************************************************************************/
/* Function prologue, epilogue and function calling sequences. */
@@ -145,7 +135,7 @@ DEF_TUNE (X86_TUNE_REASSOC_FP_TO_PARALLEL, "reassoc_fp_to_parallel",
regression on mgrid due to IRA limitation leading to unecessary
use of the frame pointer in 32bit mode. */
DEF_TUNE (X86_TUNE_ACCUMULATE_OUTGOING_ARGS, "accumulate_outgoing_args",
- m_PPRO | m_P4_NOCONA | m_BONNELL | m_SILVERMONT | m_KNL | m_INTEL
+ m_PPRO | m_P4_NOCONA | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL
| m_ATHLON_K8)
/* X86_TUNE_PROLOGUE_USING_MOVE: Do not use push/pop in prologues that are
@@ -207,8 +197,8 @@ DEF_TUNE (X86_TUNE_PAD_RETURNS, "pad_returns",
/* X86_TUNE_FOUR_JUMP_LIMIT: Some CPU cores are not able to predict more
than 4 branch instructions in the 16 byte window. */
DEF_TUNE (X86_TUNE_FOUR_JUMP_LIMIT, "four_jump_limit",
- m_PPRO | m_P4_NOCONA | m_BONNELL | m_SILVERMONT | m_KNL |m_INTEL |
- m_ATHLON_K8 | m_AMDFAM10)
+ m_PPRO | m_P4_NOCONA | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM
+ |m_INTEL | m_ATHLON_K8 | m_AMDFAM10)
/*****************************************************************************/
/* Integer instruction selection tuning */
@@ -231,22 +221,22 @@ DEF_TUNE (X86_TUNE_READ_MODIFY, "read_modify", ~(m_PENT | m_LAKEMONT | m_PPRO))
/* X86_TUNE_USE_INCDEC: Enable use of inc/dec instructions. */
DEF_TUNE (X86_TUNE_USE_INCDEC, "use_incdec",
~(m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_INTEL
- | m_KNL | m_GENERIC))
+ | m_KNL | m_KNM | m_GENERIC))
/* X86_TUNE_INTEGER_DFMODE_MOVES: Enable if integer moves are preferred
for DFmode copies */
DEF_TUNE (X86_TUNE_INTEGER_DFMODE_MOVES, "integer_dfmode_moves",
~(m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT
- | m_KNL | m_INTEL | m_GEODE | m_AMD_MULTIPLE | m_GENERIC))
+ | m_KNL | m_KNM | m_INTEL | m_GEODE | m_AMD_MULTIPLE | m_GENERIC))
/* X86_TUNE_OPT_AGU: Optimize for Address Generation Unit. This flag
will impact LEA instruction selection. */
DEF_TUNE (X86_TUNE_OPT_AGU, "opt_agu", m_BONNELL | m_SILVERMONT | m_KNL
- | m_INTEL)
+ | m_KNM | m_INTEL)
/* X86_TUNE_AVOID_LEA_FOR_ADDR: Avoid lea for address computation. */
DEF_TUNE (X86_TUNE_AVOID_LEA_FOR_ADDR, "avoid_lea_for_addr",
- m_BONNELL | m_SILVERMONT | m_KNL)
+ m_BONNELL | m_SILVERMONT | m_KNL | m_KNM)
/* X86_TUNE_SLOW_IMUL_IMM32_MEM: Imul of 32-bit constant and memory is
vector path on AMD machines.
@@ -263,7 +253,7 @@ DEF_TUNE (X86_TUNE_SLOW_IMUL_IMM8, "slow_imul_imm8",
/* X86_TUNE_AVOID_MEM_OPND_FOR_CMOVE: Try to avoid memory operands for
a conditional move. */
DEF_TUNE (X86_TUNE_AVOID_MEM_OPND_FOR_CMOVE, "avoid_mem_opnd_for_cmove",
- m_BONNELL | m_SILVERMONT | m_KNL | m_INTEL)
+ m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL)
/* X86_TUNE_SINGLE_STRINGOP: Enable use of single string operations, such
as MOVS and STOS (without a REP prefix) to move/set sequences of bytes. */
@@ -281,19 +271,35 @@ DEF_TUNE (X86_TUNE_MISALIGNED_MOVE_STRING_PRO_EPILOGUES,
/* X86_TUNE_USE_SAHF: Controls use of SAHF. */
DEF_TUNE (X86_TUNE_USE_SAHF, "use_sahf",
m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT
- | m_KNL | m_INTEL | m_K6_GEODE | m_K8 | m_AMDFAM10 | m_BDVER
+ | m_KNL | m_KNM | m_INTEL | m_K6_GEODE | m_K8 | m_AMDFAM10 | m_BDVER
| m_BTVER | m_ZNVER1 | m_GENERIC)
/* X86_TUNE_USE_CLTD: Controls use of CLTD and CTQO instructions. */
DEF_TUNE (X86_TUNE_USE_CLTD, "use_cltd",
- ~(m_PENT | m_LAKEMONT | m_BONNELL | m_SILVERMONT | m_KNL | m_INTEL
+ ~(m_PENT | m_LAKEMONT | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL
| m_K6))
/* X86_TUNE_USE_BT: Enable use of BT (bit test) instructions. */
DEF_TUNE (X86_TUNE_USE_BT, "use_bt",
- m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_KNL | m_INTEL
+ m_CORE_ALL | m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL
| m_LAKEMONT | m_AMD_MULTIPLE | m_GENERIC)
+/* X86_TUNE_AVOID_FALSE_DEP_FOR_BMI: Avoid false dependency
+ for bit-manipulation instructions. */
+DEF_TUNE (X86_TUNE_AVOID_FALSE_DEP_FOR_BMI, "avoid_false_dep_for_bmi",
+ m_SANDYBRIDGE | m_HASWELL | m_GENERIC)
+
+/* X86_TUNE_ADJUST_UNROLL: This enables adjusting the unroll factor based
+ on hardware capabilities. Bdver3 hardware has a loop buffer which makes
+ unrolling small loop less important. For, such architectures we adjust
+ the unroll factor so that the unrolled loop fits the loop buffer. */
+DEF_TUNE (X86_TUNE_ADJUST_UNROLL, "adjust_unroll_factor", m_BDVER3 | m_BDVER4)
+
+/* X86_TUNE_ONE_IF_CONV_INSNS: Restrict a number of cmov insns in
+ if-converted sequence to one. */
+DEF_TUNE (X86_TUNE_ONE_IF_CONV_INSN, "one_if_conv_insn",
+ m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_CORE_ALL | m_GENERIC)
+
/*****************************************************************************/
/* 387 instruction selection tuning */
/*****************************************************************************/
@@ -308,7 +314,7 @@ DEF_TUNE (X86_TUNE_USE_HIMODE_FIOP, "use_himode_fiop",
integer operand. */
DEF_TUNE (X86_TUNE_USE_SIMODE_FIOP, "use_simode_fiop",
~(m_PENT | m_LAKEMONT | m_PPRO | m_CORE_ALL | m_BONNELL
- | m_SILVERMONT | m_KNL | m_INTEL | m_AMD_MULTIPLE | m_GENERIC))
+ | m_SILVERMONT | m_KNL | m_KNM | m_INTEL | m_AMD_MULTIPLE | m_GENERIC))
/* X86_TUNE_USE_FFREEP: Use freep instruction instead of fstp. */
DEF_TUNE (X86_TUNE_USE_FFREEP, "use_ffreep", m_AMD_MULTIPLE)
@@ -316,7 +322,7 @@ DEF_TUNE (X86_TUNE_USE_FFREEP, "use_ffreep", m_AMD_MULTIPLE)
/* X86_TUNE_EXT_80387_CONSTANTS: Use fancy 80387 constants, such as PI. */
DEF_TUNE (X86_TUNE_EXT_80387_CONSTANTS, "ext_80387_constants",
m_PPRO | m_P4_NOCONA | m_CORE_ALL | m_BONNELL | m_SILVERMONT
- | m_KNL | m_INTEL | m_K6_GEODE | m_ATHLON_K8 | m_GENERIC)
+ | m_KNL | m_KNM | m_INTEL | m_K6_GEODE | m_ATHLON_K8 | m_GENERIC)
/*****************************************************************************/
/* SSE instruction selection tuning */
@@ -330,13 +336,13 @@ DEF_TUNE (X86_TUNE_GENERAL_REGS_SSE_SPILL, "general_regs_sse_spill",
/* X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL: Use movups for misaligned loads instead
of a sequence loading registers by parts. */
DEF_TUNE (X86_TUNE_SSE_UNALIGNED_LOAD_OPTIMAL, "sse_unaligned_load_optimal",
- m_NEHALEM | m_SANDYBRIDGE | m_HASWELL | m_SILVERMONT | m_KNL
+ m_NEHALEM | m_SANDYBRIDGE | m_HASWELL | m_SILVERMONT | m_KNL | m_KNM
| m_INTEL | m_AMDFAM10 | m_BDVER | m_BTVER | m_ZNVER1 | m_GENERIC)
/* X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL: Use movups for misaligned stores instead
of a sequence loading registers by parts. */
DEF_TUNE (X86_TUNE_SSE_UNALIGNED_STORE_OPTIMAL, "sse_unaligned_store_optimal",
- m_NEHALEM | m_SANDYBRIDGE | m_HASWELL | m_SILVERMONT | m_KNL
+ m_NEHALEM | m_SANDYBRIDGE | m_HASWELL | m_SILVERMONT | m_KNL | m_KNM
| m_INTEL | m_BDVER | m_ZNVER1 | m_GENERIC)
/* Use packed single precision instructions where posisble. I.e. movups instead
@@ -375,7 +381,7 @@ DEF_TUNE (X86_TUNE_INTER_UNIT_CONVERSIONS, "inter_unit_conversions",
/* X86_TUNE_SPLIT_MEM_OPND_FOR_FP_CONVERTS: Try to split memory operand for
fp converts to destination register. */
DEF_TUNE (X86_TUNE_SPLIT_MEM_OPND_FOR_FP_CONVERTS, "split_mem_opnd_for_fp_converts",
- m_SILVERMONT | m_KNL | m_INTEL)
+ m_SILVERMONT | m_KNL | m_KNM | m_INTEL)
/* X86_TUNE_USE_VECTOR_FP_CONVERTS: Prefer vector packed SSE conversion
from FP to FP. This form of instructions avoids partial write to the
@@ -389,12 +395,7 @@ DEF_TUNE (X86_TUNE_USE_VECTOR_CONVERTS, "use_vector_converts", m_AMDFAM10)
/* X86_TUNE_SLOW_SHUFB: Indicates tunings with slow pshufb instruction. */
DEF_TUNE (X86_TUNE_SLOW_PSHUFB, "slow_pshufb",
- m_BONNELL | m_SILVERMONT | m_KNL | m_INTEL)
-
-/* X86_TUNE_VECTOR_PARALLEL_EXECUTION: Indicates tunings with ability to
- execute 2 or more vector instructions in parallel. */
-DEF_TUNE (X86_TUNE_VECTOR_PARALLEL_EXECUTION, "vec_parallel",
- m_NEHALEM | m_SANDYBRIDGE | m_HASWELL)
+ m_BONNELL | m_SILVERMONT | m_KNL | m_KNM | m_INTEL)
/* X86_TUNE_AVOID_4BYTE_PREFIXES: Avoid instructions requiring 4+ bytes of prefixes. */
DEF_TUNE (X86_TUNE_AVOID_4BYTE_PREFIXES, "avoid_4byte_prefixes",
@@ -518,11 +519,6 @@ DEF_TUNE (X86_TUNE_NOT_VECTORMODE, "not_vectormode", m_K6)
DEF_TUNE (X86_TUNE_AVOID_VECTOR_DECODE, "avoid_vector_decode",
m_K8)
-/* X86_TUNE_AVOID_FALSE_DEP_FOR_BMI: Avoid false dependency
- for bit-manipulation instructions. */
-DEF_TUNE (X86_TUNE_AVOID_FALSE_DEP_FOR_BMI, "avoid_false_dep_for_bmi",
- m_SANDYBRIDGE | m_HASWELL | m_GENERIC)
-
/*****************************************************************************/
/* This never worked well before. */
/*****************************************************************************/
@@ -540,14 +536,3 @@ DEF_TUNE (X86_TUNE_QIMODE_MATH, "qimode_math", ~0U)
arithmetic to 32bit via PROMOTE_MODE macro. This code generation scheme
is usually used for RISC targets. */
DEF_TUNE (X86_TUNE_PROMOTE_QI_REGS, "promote_qi_regs", 0U)
-
-/* X86_TUNE_ADJUST_UNROLL: This enables adjusting the unroll factor based
- on hardware capabilities. Bdver3 hardware has a loop buffer which makes
- unrolling small loop less important. For, such architectures we adjust
- the unroll factor so that the unrolled loop fits the loop buffer. */
-DEF_TUNE (X86_TUNE_ADJUST_UNROLL, "adjust_unroll_factor", m_BDVER3 | m_BDVER4)
-
-/* X86_TUNE_ONE_IF_CONV_INSNS: Restrict a number of cmov insns in
- if-converted sequence to one. */
-DEF_TUNE (X86_TUNE_ONE_IF_CONV_INSN, "one_if_conv_insn",
- m_SILVERMONT | m_KNL | m_INTEL | m_CORE_ALL | m_GENERIC)
diff --git a/gcc/config/ia64/ia64.c b/gcc/config/ia64/ia64.c
index b4d6359..fce3006 100644
--- a/gcc/config/ia64/ia64.c
+++ b/gcc/config/ia64/ia64.c
@@ -333,8 +333,7 @@ static machine_mode ia64_get_reg_raw_mode (int regno);
static section * ia64_hpux_function_section (tree, enum node_frequency,
bool, bool);
-static bool ia64_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel);
+static bool ia64_vectorize_vec_perm_const_ok (machine_mode, vec_perm_indices);
static unsigned int ia64_hard_regno_nregs (unsigned int, machine_mode);
static bool ia64_hard_regno_mode_ok (unsigned int, machine_mode);
@@ -673,6 +672,9 @@ static const struct attribute_spec ia64_attribute_table[] =
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS ia64_can_change_mode_class
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Returns TRUE iff the target attribute indicated by ATTR_ID takes a plain
@@ -2704,7 +2706,8 @@ ia64_compute_frame_size (HOST_WIDE_INT size)
mark_reg_gr_used_mask (cfun->machine->ia64_eh_epilogue_bsp, NULL);
/* Static stack checking uses r2 and r3. */
- if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
current_frame_info.gr_used_mask |= 0xc;
/* Find the size of the register stack frame. We have only 80 local
@@ -3494,7 +3497,8 @@ ia64_expand_prologue (void)
if (flag_stack_usage_info)
current_function_static_stack_size = current_frame_info.total_size;
- if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
{
HOST_WIDE_INT size = current_frame_info.total_size;
int bs_size = BACKING_STORE_SIZE (current_frame_info.n_input_regs
@@ -3502,15 +3506,16 @@ ia64_expand_prologue (void)
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT,
- size - STACK_CHECK_PROTECT,
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+ ia64_emit_probe_stack_range (get_stack_check_protect (),
+ size - get_stack_check_protect (),
bs_size);
- else if (size + bs_size > STACK_CHECK_PROTECT)
- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT, 0, bs_size);
+ else if (size + bs_size > get_stack_check_protect ())
+ ia64_emit_probe_stack_range (get_stack_check_protect (),
+ 0, bs_size);
}
else if (size + bs_size > 0)
- ia64_emit_probe_stack_range (STACK_CHECK_PROTECT, size, bs_size);
+ ia64_emit_probe_stack_range (get_stack_check_protect (), size, bs_size);
}
if (dump_file)
@@ -11821,8 +11826,7 @@ ia64_expand_vec_perm_const (rtx operands[4])
/* Implement targetm.vectorize.vec_perm_const_ok. */
static bool
-ia64_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel)
+ia64_vectorize_vec_perm_const_ok (machine_mode vmode, vec_perm_indices sel)
{
struct expand_vec_perm_d d;
unsigned int i, nelt, which;
@@ -11834,10 +11838,10 @@ ia64_vectorize_vec_perm_const_ok (machine_mode vmode,
/* Extract the values from the vector CST into the permutation
array in D. */
- memcpy (d.perm, sel, nelt);
for (i = which = 0; i < nelt; ++i)
{
- unsigned char e = d.perm[i];
+ unsigned char e = sel[i];
+ d.perm[i] = e;
gcc_assert (e < 2 * nelt);
which |= (e < nelt ? 1 : 2);
}
diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h
index 9cfb009..e7073d1 100644
--- a/gcc/config/ia64/ia64.h
+++ b/gcc/config/ia64/ia64.h
@@ -185,15 +185,6 @@ while (0)
&& TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-/* If defined, a C expression to compute the alignment given to a constant that
- is being placed in memory. CONSTANT is the constant and ALIGN is the
- alignment that the object would ordinarily have. The value of this macro is
- used instead of that alignment to align the object. */
-
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
#define STRICT_ALIGNMENT 1
/* Define this if you wish to imitate the way many other C compilers handle
@@ -788,10 +779,6 @@ enum reg_class
are at negative offsets from the frame pointer. */
#define FRAME_GROWS_DOWNWARD 0
-/* Offset from the frame pointer to the first local variable slot to
- be allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* Offset from the stack pointer register to the first location at which
outgoing arguments are placed. If not specified, the default value of zero
is used. This is the proper value for most machines. */
diff --git a/gcc/config/iq2000/iq2000.c b/gcc/config/iq2000/iq2000.c
index 460e38d..2e0c6f6 100644
--- a/gcc/config/iq2000/iq2000.c
+++ b/gcc/config/iq2000/iq2000.c
@@ -180,6 +180,8 @@ static void iq2000_print_operand_address (FILE *, machine_mode, rtx);
static bool iq2000_print_operand_punct_valid_p (unsigned char code);
static bool iq2000_hard_regno_mode_ok (unsigned int, machine_mode);
static bool iq2000_modes_tieable_p (machine_mode, machine_mode);
+static HOST_WIDE_INT iq2000_constant_alignment (const_tree, HOST_WIDE_INT);
+static HOST_WIDE_INT iq2000_starting_frame_offset (void);
#undef TARGET_INIT_BUILTINS
#define TARGET_INIT_BUILTINS iq2000_init_builtins
@@ -264,6 +266,12 @@ static bool iq2000_modes_tieable_p (machine_mode, machine_mode);
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P iq2000_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT iq2000_constant_alignment
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET iq2000_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Return nonzero if we split the address into high and low parts. */
@@ -3532,4 +3540,22 @@ iq2000_modes_tieable_p (machine_mode mode1, machine_mode mode2)
|| GET_MODE_CLASS (mode2) == MODE_COMPLEX_FLOAT));
}
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+iq2000_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
+
+static HOST_WIDE_INT
+iq2000_starting_frame_offset (void)
+{
+ return crtl->outgoing_args_size;
+}
+
#include "gt-iq2000.h"
diff --git a/gcc/config/iq2000/iq2000.h b/gcc/config/iq2000/iq2000.h
index ef4cd270..72122e2 100644
--- a/gcc/config/iq2000/iq2000.h
+++ b/gcc/config/iq2000/iq2000.h
@@ -96,10 +96,6 @@
|| TREE_CODE (TYPE) == UNION_TYPE \
|| TREE_CODE (TYPE) == RECORD_TYPE)) ? BITS_PER_WORD : (ALIGN))
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST || TREE_CODE (EXP) == CONSTRUCTOR) \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
#define EMPTY_FIELD_BOUNDARY 32
#define STRUCTURE_SIZE_BOUNDARY 8
@@ -219,9 +215,6 @@ enum reg_class
#define FRAME_GROWS_DOWNWARD 0
-#define STARTING_FRAME_OFFSET \
- (crtl->outgoing_args_size)
-
/* Use the default value zero. */
/* #define STACK_POINTER_OFFSET 0 */
diff --git a/gcc/config/lm32/lm32.c b/gcc/config/lm32/lm32.c
index f088069..1d6cfa0 100644
--- a/gcc/config/lm32/lm32.c
+++ b/gcc/config/lm32/lm32.c
@@ -79,6 +79,7 @@ static void lm32_function_arg_advance (cumulative_args_t cum,
const_tree type, bool named);
static bool lm32_hard_regno_mode_ok (unsigned int, machine_mode);
static bool lm32_modes_tieable_p (machine_mode, machine_mode);
+static HOST_WIDE_INT lm32_starting_frame_offset (void);
#undef TARGET_OPTION_OVERRIDE
#define TARGET_OPTION_OVERRIDE lm32_option_override
@@ -113,6 +114,12 @@ static bool lm32_modes_tieable_p (machine_mode, machine_mode);
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P lm32_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET lm32_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Current frame information calculated by lm32_compute_frame_size. */
@@ -1246,3 +1253,11 @@ lm32_modes_tieable_p (machine_mode mode1, machine_mode mode2)
&& GET_MODE_SIZE (mode1) <= UNITS_PER_WORD
&& GET_MODE_SIZE (mode2) <= UNITS_PER_WORD);
}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
+
+static HOST_WIDE_INT
+lm32_starting_frame_offset (void)
+{
+ return UNITS_PER_WORD;
+}
diff --git a/gcc/config/lm32/lm32.h b/gcc/config/lm32/lm32.h
index 9169834..8f20354 100644
--- a/gcc/config/lm32/lm32.h
+++ b/gcc/config/lm32/lm32.h
@@ -99,11 +99,6 @@ do { \
#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
/* Make arrays and structures word-aligned to allow faster copying etc. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
((((ALIGN) < BITS_PER_WORD) \
@@ -209,8 +204,6 @@ enum reg_class
#define STACK_POINTER_OFFSET (UNITS_PER_WORD)
-#define STARTING_FRAME_OFFSET (UNITS_PER_WORD)
-
#define FIRST_PARM_OFFSET(FNDECL) (UNITS_PER_WORD)
#define STACK_POINTER_REGNUM SP_REGNUM
diff --git a/gcc/config/m32c/m32c.h b/gcc/config/m32c/m32c.h
index 594288b..4bf67fb 100644
--- a/gcc/config/m32c/m32c.h
+++ b/gcc/config/m32c/m32c.h
@@ -421,7 +421,6 @@ enum reg_class
#define STACK_PUSH_CODE PRE_DEC
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
#define FIRST_PARM_OFFSET(F) 0
#define RETURN_ADDR_RTX(COUNT,FA) m32c_return_addr_rtx (COUNT)
diff --git a/gcc/config/m32r/m32r.c b/gcc/config/m32r/m32r.c
index 9b7cb5f..f104457 100644
--- a/gcc/config/m32r/m32r.c
+++ b/gcc/config/m32r/m32r.c
@@ -104,6 +104,7 @@ static bool m32r_legitimate_constant_p (machine_mode, rtx);
static bool m32r_attribute_identifier (const_tree);
static bool m32r_hard_regno_mode_ok (unsigned int, machine_mode);
static bool m32r_modes_tieable_p (machine_mode, machine_mode);
+static HOST_WIDE_INT m32r_starting_frame_offset (void);
/* M32R specific attributes. */
@@ -217,6 +218,12 @@ static const struct attribute_spec m32r_attribute_table[] =
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P m32r_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET m32r_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Called by m32r_option_override to initialize various things. */
@@ -2956,3 +2963,12 @@ m32r_legitimate_constant_p (machine_mode mode ATTRIBUTE_UNUSED, rtx x)
&& CONST_INT_P (XEXP (XEXP (x, 0), 1))
&& UINTVAL (XEXP (XEXP (x, 0), 1)) > 32767);
}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. The frame pointer points at
+ the same place as the stack pointer, except if alloca has been called. */
+
+static HOST_WIDE_INT
+m32r_starting_frame_offset (void)
+{
+ return M32R_STACK_ALIGN (crtl->outgoing_args_size);
+}
diff --git a/gcc/config/m32r/m32r.h b/gcc/config/m32r/m32r.h
index 09d73bc..0fa4c5f 100644
--- a/gcc/config/m32r/m32r.h
+++ b/gcc/config/m32r/m32r.h
@@ -260,12 +260,6 @@
/* The best alignment to use in cases where we have a choice. */
#define FASTEST_ALIGNMENT 32
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
@@ -498,15 +492,6 @@ extern enum reg_class m32r_regno_reg_class[FIRST_PSEUDO_REGISTER];
pointer to a smaller address. */
#define STACK_GROWS_DOWNWARD 1
-/* Offset from frame pointer to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-/* The frame pointer points at the same place as the stack pointer, except if
- alloca has been called. */
-#define STARTING_FRAME_OFFSET \
- M32R_STACK_ALIGN (crtl->outgoing_args_size)
-
/* Offset from the stack pointer register to the first location at which
outgoing arguments are placed. */
#define STACK_POINTER_OFFSET 0
diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h
index 2fefc72..97693cb 100644
--- a/gcc/config/m68k/m68k.h
+++ b/gcc/config/m68k/m68k.h
@@ -467,7 +467,6 @@ extern enum reg_class regno_reg_class[];
#define STACK_GROWS_DOWNWARD 1
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
/* On the 680x0, sp@- in a byte insn really pushes a word.
On the ColdFire, sp@- in a byte insn pushes just a byte. */
diff --git a/gcc/config/mcore/mcore.c b/gcc/config/mcore/mcore.c
index 81a5820..04dfb9d 100644
--- a/gcc/config/mcore/mcore.c
+++ b/gcc/config/mcore/mcore.c
@@ -248,6 +248,9 @@ static const struct attribute_spec mcore_attribute_table[] =
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P mcore_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Adjust the stack and return the number of bytes taken to do it. */
diff --git a/gcc/config/mcore/mcore.h b/gcc/config/mcore/mcore.h
index 4e93343..50d087c 100644
--- a/gcc/config/mcore/mcore.h
+++ b/gcc/config/mcore/mcore.h
@@ -148,12 +148,6 @@ extern char * mcore_current_function_name;
is GET_MODE_SIZE(DImode). */
#define MAX_FIXED_MODE_SIZE 32
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
@@ -396,12 +390,6 @@ extern const enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
makes the stack pointer a smaller address. */
#define STACK_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* If defined, the maximum amount of space required for outgoing arguments
will be computed and placed into the variable
`crtl->outgoing_args_size'. No space will be pushed
diff --git a/gcc/config/microblaze/linux.h b/gcc/config/microblaze/linux.h
index 41aa898..d715f45 100644
--- a/gcc/config/microblaze/linux.h
+++ b/gcc/config/microblaze/linux.h
@@ -57,3 +57,5 @@
/* For the microblaze-*-linux* subtarget. */
#undef TARGET_OS_CPP_BUILTINS
#define TARGET_OS_CPP_BUILTINS() GNU_USER_TARGET_OS_CPP_BUILTINS()
+
+#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
diff --git a/gcc/config/microblaze/microblaze.c b/gcc/config/microblaze/microblaze.c
index d935c3e..7487523 100644
--- a/gcc/config/microblaze/microblaze.c
+++ b/gcc/config/microblaze/microblaze.c
@@ -3800,6 +3800,24 @@ microblaze_machine_dependent_reorg (void)
return;
}
}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+microblaze_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
+
+static HOST_WIDE_INT
+microblaze_starting_frame_offset (void)
+{
+ return (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL));
+}
#undef TARGET_ENCODE_SECTION_INFO
#define TARGET_ENCODE_SECTION_INFO microblaze_encode_section_info
@@ -3904,6 +3922,12 @@ microblaze_machine_dependent_reorg (void)
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P microblaze_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT microblaze_constant_alignment
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET microblaze_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-microblaze.h"
diff --git a/gcc/config/microblaze/microblaze.h b/gcc/config/microblaze/microblaze.h
index 1726e26..59cc1cc 100644
--- a/gcc/config/microblaze/microblaze.h
+++ b/gcc/config/microblaze/microblaze.h
@@ -234,12 +234,6 @@ extern enum pipeline_type microblaze_pipe;
#undef PTRDIFF_TYPE
#define PTRDIFF_TYPE "int"
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST || TREE_CODE (EXP) == CONSTRUCTOR) \
- && (ALIGN) < BITS_PER_WORD \
- ? BITS_PER_WORD \
- : (ALIGN))
-
#define DATA_ALIGNMENT(TYPE, ALIGN) \
((((ALIGN) < BITS_PER_WORD) \
&& (TREE_CODE (TYPE) == ARRAY_TYPE \
@@ -408,10 +402,6 @@ extern enum reg_class microblaze_regno_to_class[];
#define STACK_GROWS_DOWNWARD 1
-/* Changed the starting frame offset to including the new link stuff */
-#define STARTING_FRAME_OFFSET \
- (crtl->outgoing_args_size + FIRST_PARM_OFFSET(FNDECL))
-
/* The return address for the current frame is in r31 if this is a leaf
function. Otherwise, it is on the stack. It is at a variable offset
from sp/fp/ap, so we define a fake hard register rap which is a
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index 7eaff14..149ad8e 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -10956,7 +10956,7 @@ mips_compute_frame_info (void)
if we know that none of the called functions will use this space.
But if the target-independent frame size is nonzero, we have already
- committed to allocating these in STARTING_FRAME_OFFSET for
+ committed to allocating these in TARGET_STARTING_FRAME_OFFSET for
!FRAME_GROWS_DOWNWARD. */
if ((size == 0 || FRAME_GROWS_DOWNWARD)
@@ -12080,16 +12080,17 @@ mips_expand_prologue (void)
if (flag_stack_usage_info)
current_function_static_stack_size = size;
- if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
{
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
- mips_emit_probe_stack_range (STACK_CHECK_PROTECT,
- size - STACK_CHECK_PROTECT);
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+ mips_emit_probe_stack_range (get_stack_check_protect (),
+ size - get_stack_check_protect ());
}
else if (size > 0)
- mips_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
+ mips_emit_probe_stack_range (get_stack_check_protect (), size);
}
/* Save the registers. Allocate up to MIPS_MAX_FIRST_STACK_STEP
@@ -21469,8 +21470,7 @@ mips_sched_reassociation_width (unsigned int opc ATTRIBUTE_UNUSED,
/* Implement TARGET_VECTORIZE_VEC_PERM_CONST_OK. */
static bool
-mips_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel)
+mips_vectorize_vec_perm_const_ok (machine_mode vmode, vec_perm_indices sel)
{
struct expand_vec_perm_d d;
unsigned int i, nelt, which;
@@ -21479,12 +21479,12 @@ mips_vectorize_vec_perm_const_ok (machine_mode vmode,
d.vmode = vmode;
d.nelt = nelt = GET_MODE_NUNITS (d.vmode);
d.testing_p = true;
- memcpy (d.perm, sel, nelt);
/* Categorize the set of elements in the selector. */
for (i = which = 0; i < nelt; ++i)
{
- unsigned char e = d.perm[i];
+ unsigned char e = sel[i];
+ d.perm[i] = e;
gcc_assert (e < 2 * nelt);
which |= (e < nelt ? 1 : 2);
}
@@ -22336,6 +22336,27 @@ mips_truly_noop_truncation (unsigned int outprec, unsigned int inprec)
{
return !TARGET_64BIT || inprec <= 32 || outprec > 32;
}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+mips_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. See mips_compute_frame_info
+ for details about the frame layout. */
+
+static HOST_WIDE_INT
+mips_starting_frame_offset (void)
+{
+ if (FRAME_GROWS_DOWNWARD)
+ return 0;
+ return crtl->outgoing_args_size + MIPS_GP_SAVE_AREA_SIZE;
+}
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
@@ -22634,6 +22655,12 @@ mips_truly_noop_truncation (unsigned int outprec, unsigned int inprec)
#undef TARGET_TRULY_NOOP_TRUNCATION
#define TARGET_TRULY_NOOP_TRUNCATION mips_truly_noop_truncation
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT mips_constant_alignment
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET mips_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-mips.h"
diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h
index 1f4cad8..550d283 100644
--- a/gcc/config/mips/mips.h
+++ b/gcc/config/mips/mips.h
@@ -1636,22 +1636,6 @@ FP_ASM_SPEC "\
#define PCC_BITFIELD_TYPE_MATTERS 1
-/* If defined, a C expression to compute the alignment given to a
- constant that is being placed in memory. CONSTANT is the constant
- and ALIGN is the alignment that the object would ordinarily have.
- The value of this macro is used instead of that alignment to align
- the object.
-
- If this macro is not defined, then ALIGN is used.
-
- The typical use of this macro is to increase alignment for string
- constants to be word aligned so that `strcpy' calls that copy
- constants can be done inline. */
-
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST || TREE_CODE (EXP) == CONSTRUCTOR) \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
/* If defined, a C expression to compute the alignment for a static
variable. TYPE is the data type, and ALIGN is the alignment that
the object would ordinarily have. The value of this macro is used
@@ -2314,14 +2298,6 @@ enum reg_class
#define MIPS_GP_SAVE_AREA_SIZE \
(TARGET_CALL_CLOBBERED_GP ? MIPS_STACK_ALIGN (UNITS_PER_WORD) : 0)
-/* The offset of the first local variable from the frame pointer. See
- mips_compute_frame_info for details about the frame layout. */
-
-#define STARTING_FRAME_OFFSET \
- (FRAME_GROWS_DOWNWARD \
- ? 0 \
- : crtl->outgoing_args_size + MIPS_GP_SAVE_AREA_SIZE)
-
#define RETURN_ADDR_RTX mips_return_addr
/* Mask off the MIPS16 ISA bit in unwind addresses.
diff --git a/gcc/config/mmix/mmix-protos.h b/gcc/config/mmix/mmix-protos.h
index 7cb4670..4e3a752 100644
--- a/gcc/config/mmix/mmix-protos.h
+++ b/gcc/config/mmix/mmix-protos.h
@@ -21,7 +21,6 @@ along with GCC; see the file COPYING3. If not see
extern void mmix_init_expanders (void);
extern int mmix_eh_return_data_regno (int);
extern int mmix_initial_elimination_offset (int, int);
-extern int mmix_starting_frame_offset (void);
extern int mmix_function_arg_regno_p (int, int);
extern void mmix_function_profiler (FILE *, int);
extern int mmix_reversible_cc_mode (machine_mode);
@@ -47,7 +46,6 @@ extern unsigned mmix_dbx_register_number (unsigned);
extern int mmix_use_simple_return (void);
extern void mmix_make_decl_one_only (tree);
extern int mmix_data_alignment (tree, int);
-extern int mmix_constant_alignment (tree, int);
extern unsigned mmix_local_alignment (tree, unsigned);
extern void mmix_asm_output_pool_prologue (FILE *, const char *, tree, int);
extern void mmix_asm_output_aligned_common (FILE *, const char *, int, int);
diff --git a/gcc/config/mmix/mmix.c b/gcc/config/mmix/mmix.c
index 90a4651..e911594 100644
--- a/gcc/config/mmix/mmix.c
+++ b/gcc/config/mmix/mmix.c
@@ -168,6 +168,8 @@ static void mmix_print_operand (FILE *, rtx, int);
static void mmix_print_operand_address (FILE *, machine_mode, rtx);
static bool mmix_print_operand_punct_valid_p (unsigned char);
static void mmix_conditional_register_usage (void);
+static HOST_WIDE_INT mmix_constant_alignment (const_tree, HOST_WIDE_INT);
+static HOST_WIDE_INT mmix_starting_frame_offset (void);
/* Target structure macros. Listed by node. See `Using and Porting GCC'
for a general description. */
@@ -282,6 +284,12 @@ static void mmix_conditional_register_usage (void);
#undef TARGET_OPTION_OVERRIDE
#define TARGET_OPTION_OVERRIDE mmix_option_override
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT mmix_constant_alignment
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET mmix_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Functions that are expansions for target macros.
@@ -334,10 +342,10 @@ mmix_data_alignment (tree type ATTRIBUTE_UNUSED, int basic_align)
return basic_align;
}
-/* CONSTANT_ALIGNMENT. */
+/* Implement tARGET_CONSTANT_ALIGNMENT. */
-int
-mmix_constant_alignment (tree constant ATTRIBUTE_UNUSED, int basic_align)
+static HOST_WIDE_INT
+mmix_constant_alignment (const_tree, HOST_WIDE_INT basic_align)
{
if (basic_align < 32)
return 32;
@@ -494,9 +502,9 @@ mmix_dynamic_chain_address (rtx frame)
return plus_constant (Pmode, frame, -8);
}
-/* STARTING_FRAME_OFFSET. */
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
-int
+static HOST_WIDE_INT
mmix_starting_frame_offset (void)
{
/* The old frame pointer is in the slot below the new one, so
@@ -562,7 +570,7 @@ mmix_initial_elimination_offset (int fromreg, int toreg)
counted; the others go on the register stack.
The frame-pointer is counted too if it is what is eliminated, as we
- need to balance the offset for it from STARTING_FRAME_OFFSET.
+ need to balance the offset for it from TARGET_STARTING_FRAME_OFFSET.
Also add in the slot for the register stack pointer we save if we
have a landing pad.
diff --git a/gcc/config/mmix/mmix.h b/gcc/config/mmix/mmix.h
index 7161656..5dafe2d 100644
--- a/gcc/config/mmix/mmix.h
+++ b/gcc/config/mmix/mmix.h
@@ -167,9 +167,6 @@ struct GTY(()) machine_function
#define DATA_ABI_ALIGNMENT(TYPE, BASIC_ALIGN) \
mmix_data_alignment (TYPE, BASIC_ALIGN)
-#define CONSTANT_ALIGNMENT(CONSTANT, BASIC_ALIGN) \
- mmix_constant_alignment (CONSTANT, BASIC_ALIGN)
-
#define LOCAL_ALIGNMENT(TYPE, BASIC_ALIGN) \
mmix_local_alignment (TYPE, BASIC_ALIGN)
@@ -440,9 +437,6 @@ enum reg_class
#define STACK_GROWS_DOWNWARD 1
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET \
- mmix_starting_frame_offset ()
-
#define FIRST_PARM_OFFSET(FUNDECL) 0
#define DYNAMIC_CHAIN_ADDRESS(FRAMEADDR) \
diff --git a/gcc/config/mn10300/mn10300.h b/gcc/config/mn10300/mn10300.h
index 1078b45..b074540 100644
--- a/gcc/config/mn10300/mn10300.h
+++ b/gcc/config/mn10300/mn10300.h
@@ -392,13 +392,6 @@ enum reg_class
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-
-#define STARTING_FRAME_OFFSET 0
-
/* Offset of first parameter from the argument pointer register value. */
/* Is equal to the size of the saved fp + pc, even if an fp isn't
saved since the value is used before we know. */
diff --git a/gcc/config/moxie/moxie.c b/gcc/config/moxie/moxie.c
index 19cd83f..4901237 100644
--- a/gcc/config/moxie/moxie.c
+++ b/gcc/config/moxie/moxie.c
@@ -667,6 +667,9 @@ moxie_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
#undef TARGET_PRINT_OPERAND_ADDRESS
#define TARGET_PRINT_OPERAND_ADDRESS moxie_print_operand_address
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-moxie.h"
diff --git a/gcc/config/moxie/moxie.h b/gcc/config/moxie/moxie.h
index 9ae5f82..3742967 100644
--- a/gcc/config/moxie/moxie.h
+++ b/gcc/config/moxie/moxie.h
@@ -226,10 +226,6 @@ enum reg_class
pointer to a smaller address. */
#define STACK_GROWS_DOWNWARD 1
-/* Offset from the frame pointer to the first local variable slot to
- be allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* Define this if the above stack space is to be considered part of the
space allocated by the caller. */
#define OUTGOING_REG_PARM_STACK_SPACE(FNTYPE) 1
@@ -317,12 +313,6 @@ enum reg_class
is GET_MODE_SIZE(DImode). */
#define MAX_FIXED_MODE_SIZE 32
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
diff --git a/gcc/config/msp430/msp430.c b/gcc/config/msp430/msp430.c
index 80ea119..9466d09 100644
--- a/gcc/config/msp430/msp430.c
+++ b/gcc/config/msp430/msp430.c
@@ -751,6 +751,10 @@ hwmult_name (unsigned int val)
static void
msp430_option_override (void)
{
+ /* The MSP430 architecture can safely dereference a NULL pointer. In fact,
+ there are memory mapped registers there. */
+ flag_delete_null_pointer_checks = 0;
+
init_machine_status = msp430_init_machine_status;
if (target_cpu)
@@ -1877,7 +1881,7 @@ msp430_attr (tree * node,
break;
case INTEGER_CST:
- if (wi::gtu_p (value, 63))
+ if (wi::gtu_p (wi::to_wide (value), 63))
/* Allow the attribute to be added - the linker script
being used may still recognise this value. */
warning (OPT_Wattributes,
diff --git a/gcc/config/msp430/msp430.h b/gcc/config/msp430/msp430.h
index 5a997670..d422725 100644
--- a/gcc/config/msp430/msp430.h
+++ b/gcc/config/msp430/msp430.h
@@ -196,7 +196,6 @@ extern const char * msp430_select_hwmult_lib (int, const char **);
#define WORD_REGISTER_OPERATIONS 1
#define MOVE_MAX 8
-#define STARTING_FRAME_OFFSET 0
#define INCOMING_RETURN_ADDR_RTX \
msp430_incoming_return_addr_rtx ()
diff --git a/gcc/config/nds32/nds32.c b/gcc/config/nds32/nds32.c
index 65095ff..c1eb66a 100644
--- a/gcc/config/nds32/nds32.c
+++ b/gcc/config/nds32/nds32.c
@@ -2576,8 +2576,8 @@ nds32_insert_attributes (tree decl, tree *attributes)
id = TREE_VALUE (id_list);
/* Issue error if it is not a valid integer value. */
if (TREE_CODE (id) != INTEGER_CST
- || wi::ltu_p (id, lower_bound)
- || wi::gtu_p (id, upper_bound))
+ || wi::ltu_p (wi::to_wide (id), lower_bound)
+ || wi::gtu_p (wi::to_wide (id), upper_bound))
error ("invalid id value for interrupt/exception attribute");
/* Advance to next id. */
@@ -2604,8 +2604,8 @@ nds32_insert_attributes (tree decl, tree *attributes)
/* 3. Check valid integer value for reset. */
if (TREE_CODE (id) != INTEGER_CST
- || wi::ltu_p (id, lower_bound)
- || wi::gtu_p (id, upper_bound))
+ || wi::ltu_p (wi::to_wide (id), lower_bound)
+ || wi::gtu_p (wi::to_wide (id), upper_bound))
error ("invalid id value for reset attribute");
/* 4. Check valid function for nmi/warm. */
diff --git a/gcc/config/nds32/nds32.h b/gcc/config/nds32/nds32.h
index d33237c..81522b8 100644
--- a/gcc/config/nds32/nds32.h
+++ b/gcc/config/nds32/nds32.h
@@ -681,8 +681,6 @@ enum reg_class
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
-
#define STACK_POINTER_OFFSET 0
#define FIRST_PARM_OFFSET(fundecl) \
diff --git a/gcc/config/netbsd-protos.h b/gcc/config/netbsd-protos.h
new file mode 100644
index 0000000..59007c4
--- /dev/null
+++ b/gcc/config/netbsd-protos.h
@@ -0,0 +1,20 @@
+/* Prototypes.
+ Copyright (C) 2017 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
+<http://www.gnu.org/licenses/>. */
+
+extern void netbsd_patch_builtins (void);
diff --git a/gcc/config/netbsd-stdint.h b/gcc/config/netbsd-stdint.h
index 7a127c5..3d54669 100644
--- a/gcc/config/netbsd-stdint.h
+++ b/gcc/config/netbsd-stdint.h
@@ -42,12 +42,28 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define UINT_LEAST32_TYPE UINT32_TYPE
#define UINT_LEAST64_TYPE UINT64_TYPE
+#ifdef CHAR_FAST8
+#define INT_FAST8_TYPE (LONG_TYPE_SIZE == 64 ? "int" : "signed char")
+#else
#define INT_FAST8_TYPE INT32_TYPE
+#endif
+#ifdef SHORT_FAST16
+#define INT_FAST16_TYPE (LONG_TYPE_SIZE == 64 ? "int" : "short int")
+#else
#define INT_FAST16_TYPE INT32_TYPE
+#endif
#define INT_FAST32_TYPE INT32_TYPE
#define INT_FAST64_TYPE INT64_TYPE
+#ifdef CHAR_FAST8
+#define UINT_FAST8_TYPE "unsigned char"
+#else
#define UINT_FAST8_TYPE UINT32_TYPE
+#endif
+#ifdef SHORT_FAST16
+#define UINT_FAST16_TYPE "short unsigned int"
+#else
#define UINT_FAST16_TYPE UINT32_TYPE
+#endif
#define UINT_FAST32_TYPE UINT32_TYPE
#define UINT_FAST64_TYPE UINT64_TYPE
diff --git a/gcc/config/netbsd.c b/gcc/config/netbsd.c
new file mode 100644
index 0000000..ed39f27
--- /dev/null
+++ b/gcc/config/netbsd.c
@@ -0,0 +1,54 @@
+/* Functions for generic NetBSD as target machine for GNU C compiler.
+ Copyright (C) 2017 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "varasm.h"
+#include "netbsd-protos.h"
+
+static void
+netbsd_patch_builtin (enum built_in_function fncode)
+{
+ tree fn = builtin_decl_explicit (fncode);
+ tree sym;
+ char *newname;
+
+ if (!fn)
+ return;
+
+ sym = DECL_ASSEMBLER_NAME (fn);
+ newname = ACONCAT (("__c99_", IDENTIFIER_POINTER (sym), NULL));
+
+ set_user_assembler_name (fn, newname);
+
+ fn = builtin_decl_implicit (fncode);
+ if (fn)
+ set_user_assembler_name (fn, newname);
+}
+
+void
+netbsd_patch_builtins (void)
+{
+ netbsd_patch_builtin (BUILT_IN_CABSF);
+ netbsd_patch_builtin (BUILT_IN_CABS);
+ netbsd_patch_builtin (BUILT_IN_CABSL);
+}
diff --git a/gcc/config/netbsd.h b/gcc/config/netbsd.h
index aafce9f..e84f193 100644
--- a/gcc/config/netbsd.h
+++ b/gcc/config/netbsd.h
@@ -164,3 +164,9 @@ along with GCC; see the file COPYING3. If not see
#undef WINT_TYPE
#define WINT_TYPE "int"
+
+#undef SUBTARGET_INIT_BUILTINS
+#define SUBTARGET_INIT_BUILTINS \
+ do { \
+ netbsd_patch_builtins (); \
+ } while(0)
diff --git a/gcc/config/nios2/nios2-protos.h b/gcc/config/nios2/nios2-protos.h
index 4478334..6df65bb 100644
--- a/gcc/config/nios2/nios2-protos.h
+++ b/gcc/config/nios2/nios2-protos.h
@@ -30,6 +30,11 @@ extern bool nios2_expand_return (void);
extern void nios2_function_profiler (FILE *, int);
#ifdef RTX_CODE
+extern bool nios2_large_constant_p (rtx);
+extern bool nios2_symbolic_memory_operand_p (rtx);
+
+extern rtx nios2_split_large_constant (rtx, rtx);
+extern rtx nios2_split_symbolic_memory_operand (rtx);
extern bool nios2_emit_move_sequence (rtx *, machine_mode);
extern void nios2_emit_expensive_div (rtx *, machine_mode);
extern void nios2_adjust_call_address (rtx *, rtx);
diff --git a/gcc/config/nios2/nios2.c b/gcc/config/nios2/nios2.c
index 893ddd1..f5963d4 100644
--- a/gcc/config/nios2/nios2.c
+++ b/gcc/config/nios2/nios2.c
@@ -48,11 +48,13 @@
#include "langhooks.h"
#include "stor-layout.h"
#include "builtins.h"
+#include "tree-pass.h"
/* This file should be included last. */
#include "target-def.h"
/* Forward function declarations. */
+static bool nios2_symbolic_constant_p (rtx);
static bool prologue_saved_reg_p (unsigned);
static void nios2_load_pic_register (void);
static void nios2_register_custom_code (unsigned int, enum nios2_ccs_code, int);
@@ -60,6 +62,7 @@ static const char *nios2_unspec_reloc_name (int);
static void nios2_register_builtin_fndecl (unsigned, tree);
static rtx nios2_ldst_parallel (bool, bool, bool, rtx, int,
unsigned HOST_WIDE_INT, bool);
+static int nios2_address_cost (rtx, machine_mode, addr_space_t, bool);
/* Threshold for data being put into the small data/bss area, instead
of the normal data area (references to the small data/bss area take
@@ -1428,29 +1431,25 @@ nios2_simple_const_p (const_rtx cst)
cost has been computed, and false if subexpressions should be
scanned. In either case, *TOTAL contains the cost result. */
static bool
-nios2_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
- int outer_code ATTRIBUTE_UNUSED,
- int opno ATTRIBUTE_UNUSED,
- int *total, bool speed ATTRIBUTE_UNUSED)
+nios2_rtx_costs (rtx x, machine_mode mode,
+ int outer_code,
+ int opno,
+ int *total, bool speed)
{
int code = GET_CODE (x);
switch (code)
{
case CONST_INT:
- if (INTVAL (x) == 0)
+ if (INTVAL (x) == 0 || nios2_simple_const_p (x))
{
*total = COSTS_N_INSNS (0);
return true;
}
- else if (nios2_simple_const_p (x))
- {
- *total = COSTS_N_INSNS (2);
- return true;
- }
else
{
- *total = COSTS_N_INSNS (4);
+ /* High + lo_sum. */
+ *total = COSTS_N_INSNS (1);
return true;
}
@@ -1458,10 +1457,30 @@ nios2_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
case SYMBOL_REF:
case CONST:
case CONST_DOUBLE:
- {
- *total = COSTS_N_INSNS (4);
- return true;
- }
+ if (gprel_constant_p (x))
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ else
+ {
+ /* High + lo_sum. */
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+
+ case HIGH:
+ {
+ /* This is essentially a constant. */
+ *total = COSTS_N_INSNS (0);
+ return true;
+ }
+
+ case LO_SUM:
+ {
+ *total = COSTS_N_INSNS (0);
+ return true;
+ }
case AND:
{
@@ -1475,29 +1494,83 @@ nios2_rtx_costs (rtx x, machine_mode mode ATTRIBUTE_UNUSED,
return false;
}
+ /* For insns that have an execution latency (3 cycles), don't
+ penalize by the full amount since we can often schedule
+ to avoid it. */
case MULT:
{
- *total = COSTS_N_INSNS (1);
+ if (!TARGET_HAS_MUL)
+ *total = COSTS_N_INSNS (5); /* Guess? */
+ else if (speed)
+ *total = COSTS_N_INSNS (2); /* Latency adjustment. */
+ else
+ *total = COSTS_N_INSNS (1);
return false;
}
- case SIGN_EXTEND:
+
+ case DIV:
{
- *total = COSTS_N_INSNS (3);
+ if (!TARGET_HAS_DIV)
+ *total = COSTS_N_INSNS (5); /* Guess? */
+ else if (speed)
+ *total = COSTS_N_INSNS (2); /* Latency adjustment. */
+ else
+ *total = COSTS_N_INSNS (1);
return false;
}
- case ZERO_EXTEND:
+
+ case ASHIFT:
+ case ASHIFTRT:
+ case LSHIFTRT:
+ case ROTATE:
{
- *total = COSTS_N_INSNS (1);
+ if (!speed)
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (2); /* Latency adjustment. */
return false;
}
+
+ case ZERO_EXTRACT:
+ if (TARGET_HAS_BMX)
+ {
+ *total = COSTS_N_INSNS (1);
+ return true;
+ }
+ return false;
- case ZERO_EXTRACT:
- if (TARGET_HAS_BMX)
+ case SIGN_EXTEND:
+ {
+ if (MEM_P (XEXP (x, 0)))
+ *total = COSTS_N_INSNS (1);
+ else
+ *total = COSTS_N_INSNS (3);
+ return false;
+ }
+
+ case MEM:
{
- *total = COSTS_N_INSNS (1);
- return true;
+ rtx addr = XEXP (x, 0);
+
+ /* Account for cost of different addressing modes. */
+ *total = nios2_address_cost (addr, mode, ADDR_SPACE_GENERIC, speed);
+
+ if (outer_code == SET && opno == 0)
+ /* Stores execute in 1 cycle accounted for by
+ the outer SET. */
+ ;
+ else if (outer_code == SET || outer_code == SIGN_EXTEND
+ || outer_code == ZERO_EXTEND)
+ /* Latency adjustment. */
+ {
+ if (speed)
+ *total += COSTS_N_INSNS (1);
+ }
+ else
+ /* This is going to have to be split into a load. */
+ *total += COSTS_N_INSNS (speed ? 2 : 1);
+ return true;
}
- return false;
default:
return false;
@@ -1902,7 +1975,52 @@ nios2_validate_compare (machine_mode mode, rtx *cmp, rtx *op1, rtx *op2)
}
-/* Addressing Modes. */
+/* Addressing modes and constants. */
+
+/* Symbolic constants are split into high/lo_sum pairs during the
+ split1 pass. After that, they are not considered legitimate addresses.
+ This function returns true if in a pre-split context where these
+ constants are allowed. */
+static bool
+nios2_symbolic_constant_allowed (void)
+{
+ /* The reload_completed check is for the benefit of
+ nios2_asm_output_mi_thunk and perhaps other places that try to
+ emulate a post-reload pass. */
+ return !(cfun->curr_properties & PROP_rtl_split_insns) && !reload_completed;
+}
+
+/* Return true if X is constant expression with a reference to an
+ "ordinary" symbol; not GOT-relative, not GP-relative, not TLS. */
+static bool
+nios2_symbolic_constant_p (rtx x)
+{
+ rtx base, offset;
+
+ if (flag_pic)
+ return false;
+ if (GET_CODE (x) == LABEL_REF)
+ return true;
+ else if (CONSTANT_P (x))
+ {
+ split_const (x, &base, &offset);
+ return (SYMBOL_REF_P (base)
+ && !SYMBOL_REF_TLS_MODEL (base)
+ && !gprel_constant_p (base)
+ && SMALL_INT (INTVAL (offset)));
+ }
+ return false;
+}
+
+/* Return true if X is an expression of the form
+ (PLUS reg symbolic_constant). */
+static bool
+nios2_plus_symbolic_constant_p (rtx x)
+{
+ return (GET_CODE (x) == PLUS
+ && REG_P (XEXP (x, 0))
+ && nios2_symbolic_constant_p (XEXP (x, 1)));
+}
/* Implement TARGET_LEGITIMATE_CONSTANT_P. */
static bool
@@ -1971,6 +2089,8 @@ nios2_valid_addr_expr_p (rtx base, rtx offset, bool strict_p)
&& nios2_regno_ok_for_base_p (REGNO (base), strict_p)
&& (offset == NULL_RTX
|| nios2_valid_addr_offset_p (offset)
+ || (nios2_symbolic_constant_allowed ()
+ && nios2_symbolic_constant_p (offset))
|| nios2_unspec_reloc_p (offset)));
}
@@ -1993,6 +2113,11 @@ nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
/* Else, fall through. */
case LABEL_REF:
+ if (nios2_symbolic_constant_allowed ()
+ && nios2_symbolic_constant_p (operand))
+ return true;
+
+ /* Else, fall through. */
case CONST_INT:
case CONST_DOUBLE:
return false;
@@ -2007,9 +2132,28 @@ nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
rtx op0 = XEXP (operand, 0);
rtx op1 = XEXP (operand, 1);
- return (nios2_valid_addr_expr_p (op0, op1, strict_p)
- || nios2_valid_addr_expr_p (op1, op0, strict_p));
+ if (nios2_valid_addr_expr_p (op0, op1, strict_p)
+ || nios2_valid_addr_expr_p (op1, op0, strict_p))
+ return true;
}
+ break;
+
+ /* %lo(constant)(reg)
+ This requires a 16-bit relocation and isn't valid with R2
+ io-variant load/stores. */
+ case LO_SUM:
+ if (TARGET_ARCH_R2
+ && (TARGET_BYPASS_CACHE || TARGET_BYPASS_CACHE_VOLATILE))
+ return false;
+ else
+ {
+ rtx op0 = XEXP (operand, 0);
+ rtx op1 = XEXP (operand, 1);
+
+ return (REG_P (op0)
+ && nios2_regno_ok_for_base_p (REGNO (op0), strict_p)
+ && nios2_large_constant_p (op1));
+ }
default:
break;
@@ -2017,6 +2161,106 @@ nios2_legitimate_address_p (machine_mode mode ATTRIBUTE_UNUSED,
return false;
}
+/* Implement TARGET_ADDRESS_COST.
+ Experimentation has shown that we get better code by penalizing the
+ the (plus reg symbolic_constant) and (plus reg (const ...)) forms
+ but giving (plus reg symbol_ref) address modes the same cost as those
+ that don't require splitting. Also, from a theoretical point of view:
+ - This is in line with the recommendation in the GCC internals
+ documentation to make address forms involving multiple
+ registers more expensive than single-register forms.
+ - OTOH it still encourages fwprop1 to propagate constants into
+ address expressions more aggressively.
+ - We should discourage splitting (symbol + offset) into hi/lo pairs
+ to allow CSE'ing the symbol when it's used with more than one offset,
+ but not so heavily as to avoid this addressing mode at all. */
+static int
+nios2_address_cost (rtx address,
+ machine_mode mode ATTRIBUTE_UNUSED,
+ addr_space_t as ATTRIBUTE_UNUSED,
+ bool speed ATTRIBUTE_UNUSED)
+{
+ if (nios2_plus_symbolic_constant_p (address))
+ return COSTS_N_INSNS (1);
+ if (nios2_symbolic_constant_p (address))
+ {
+ if (GET_CODE (address) == CONST)
+ return COSTS_N_INSNS (1);
+ else
+ return COSTS_N_INSNS (0);
+ }
+ return COSTS_N_INSNS (0);
+}
+
+/* Return true if X is a MEM whose address expression involves a symbolic
+ constant. */
+bool
+nios2_symbolic_memory_operand_p (rtx x)
+{
+ rtx addr;
+
+ if (GET_CODE (x) != MEM)
+ return false;
+ addr = XEXP (x, 0);
+
+ return (nios2_symbolic_constant_p (addr)
+ || nios2_plus_symbolic_constant_p (addr));
+}
+
+
+/* Return true if X is something that needs to be split into a
+ high/lo_sum pair. */
+bool
+nios2_large_constant_p (rtx x)
+{
+ return (nios2_symbolic_constant_p (x)
+ || nios2_large_unspec_reloc_p (x));
+}
+
+/* Given an RTX X that satisfies nios2_large_constant_p, split it into
+ high and lo_sum parts using TEMP as a scratch register. Emit the high
+ instruction and return the lo_sum expression. */
+rtx
+nios2_split_large_constant (rtx x, rtx temp)
+{
+ emit_insn (gen_rtx_SET (temp, gen_rtx_HIGH (Pmode, copy_rtx (x))));
+ return gen_rtx_LO_SUM (Pmode, temp, copy_rtx (x));
+}
+
+/* Split an RTX of the form
+ (plus op0 op1)
+ where op1 is a large constant into
+ (set temp (high op1))
+ (set temp (plus op0 temp))
+ (lo_sum temp op1)
+ returning the lo_sum expression as the value. */
+static rtx
+nios2_split_plus_large_constant (rtx op0, rtx op1)
+{
+ rtx temp = gen_reg_rtx (Pmode);
+ op0 = force_reg (Pmode, op0);
+
+ emit_insn (gen_rtx_SET (temp, gen_rtx_HIGH (Pmode, copy_rtx (op1))));
+ emit_insn (gen_rtx_SET (temp, gen_rtx_PLUS (Pmode, op0, temp)));
+ return gen_rtx_LO_SUM (Pmode, temp, copy_rtx (op1));
+}
+
+/* Given a MEM OP with an address that includes a splittable symbol,
+ emit some instructions to do the split and return a new MEM. */
+rtx
+nios2_split_symbolic_memory_operand (rtx op)
+{
+ rtx addr = XEXP (op, 0);
+
+ if (nios2_symbolic_constant_p (addr))
+ addr = nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
+ else if (nios2_plus_symbolic_constant_p (addr))
+ addr = nios2_split_plus_large_constant (XEXP (addr, 0), XEXP (addr, 1));
+ else
+ gcc_unreachable ();
+ return replace_equiv_address (op, addr, false);
+}
+
/* Return true if SECTION is a small section name. */
static bool
nios2_small_section_name_p (const char *section)
@@ -2219,6 +2463,9 @@ nios2_legitimize_constant_address (rtx addr)
base = nios2_legitimize_tls_address (base);
else if (flag_pic)
base = nios2_load_pic_address (base, UNSPEC_PIC_SYM, NULL_RTX);
+ else if (!nios2_symbolic_constant_allowed ()
+ && nios2_symbolic_constant_p (addr))
+ return nios2_split_large_constant (addr, gen_reg_rtx (Pmode));
else
return addr;
@@ -2239,9 +2486,35 @@ static rtx
nios2_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
machine_mode mode ATTRIBUTE_UNUSED)
{
+ rtx op0, op1;
+
if (CONSTANT_P (x))
return nios2_legitimize_constant_address (x);
+ /* Remaining cases all involve something + a constant. */
+ if (GET_CODE (x) != PLUS)
+ return x;
+
+ op0 = XEXP (x, 0);
+ op1 = XEXP (x, 1);
+
+ /* Target-independent code turns (exp + constant) into plain
+ register indirect. Although subsequent optimization passes will
+ eventually sort that out, ivopts uses the unoptimized form for
+ computing its cost model, so we get better results by generating
+ the correct form from the start. */
+ if (nios2_valid_addr_offset_p (op1))
+ return gen_rtx_PLUS (Pmode, force_reg (Pmode, op0), copy_rtx (op1));
+
+ /* We may need to split symbolic constants now. */
+ else if (nios2_symbolic_constant_p (op1))
+ {
+ if (nios2_symbolic_constant_allowed ())
+ return gen_rtx_PLUS (Pmode, force_reg (Pmode, op0), copy_rtx (op1));
+ else
+ return nios2_split_plus_large_constant (op0, op1);
+ }
+
/* For the TLS LE (Local Exec) model, the compiler may try to
combine constant offsets with unspec relocs, creating address RTXs
looking like this:
@@ -2264,20 +2537,19 @@ nios2_legitimize_address (rtx x, rtx oldx ATTRIBUTE_UNUSED,
(const_int 48 [0x30])))] UNSPEC_ADD_TLS_LE)))
Which will be output as '%tls_le(var+48)(r23)' in assembly. */
- if (GET_CODE (x) == PLUS
- && GET_CODE (XEXP (x, 1)) == CONST)
+ else if (GET_CODE (op1) == CONST)
{
rtx unspec, offset;
- split_const (XEXP (x, 1), &unspec, &offset);
+ split_const (op1, &unspec, &offset);
if (GET_CODE (unspec) == UNSPEC
&& !nios2_large_offset_p (XINT (unspec, 1))
&& offset != const0_rtx)
{
- rtx reg = force_reg (Pmode, XEXP (x, 0));
+ rtx reg = force_reg (Pmode, op0);
unspec = copy_rtx (unspec);
XVECEXP (unspec, 0, 0)
= plus_constant (Pmode, XVECEXP (unspec, 0, 0), INTVAL (offset));
- x = gen_rtx_PLUS (Pmode, reg, gen_rtx_CONST (Pmode, unspec));
+ return gen_rtx_PLUS (Pmode, reg, gen_rtx_CONST (Pmode, unspec));
}
}
@@ -2338,10 +2610,28 @@ nios2_emit_move_sequence (rtx *operands, machine_mode mode)
return true;
}
}
- else if (!gprel_constant_p (from))
+ else if (gprel_constant_p (from))
+ /* Handled directly by movsi_internal as gp + offset. */
+ ;
+ else if (nios2_large_constant_p (from))
+ /* This case covers either a regular symbol reference or an UNSPEC
+ representing a 32-bit offset. We split the former
+ only conditionally and the latter always. */
+ {
+ if (!nios2_symbolic_constant_allowed ()
+ || nios2_large_unspec_reloc_p (from))
+ {
+ rtx lo = nios2_split_large_constant (from, to);
+ emit_insn (gen_rtx_SET (to, lo));
+ set_unique_reg_note (get_last_insn (), REG_EQUAL,
+ copy_rtx (operands[1]));
+ return true;
+ }
+ }
+ else
+ /* This is a TLS or PIC symbol. */
{
- if (!nios2_large_unspec_reloc_p (from))
- from = nios2_legitimize_constant_address (from);
+ from = nios2_legitimize_constant_address (from);
if (CONSTANT_P (from))
{
emit_insn (gen_rtx_SET (to,
@@ -2652,6 +2942,7 @@ nios2_print_operand (FILE *file, rtx op, int letter)
break;
}
+ debug_rtx (op);
output_operand_lossage ("Unsupported operand for code '%c'", letter);
gcc_unreachable ();
}
@@ -2757,6 +3048,20 @@ nios2_print_operand_address (FILE *file, machine_mode mode, rtx op)
}
break;
+ case LO_SUM:
+ {
+ rtx op0 = XEXP (op, 0);
+ rtx op1 = XEXP (op, 1);
+
+ if (REG_P (op0) && CONSTANT_P (op1))
+ {
+ nios2_print_operand (file, op1, 'L');
+ fprintf (file, "(%s)", reg_names[REGNO (op0)]);
+ return;
+ }
+ }
+ break;
+
case REG:
fprintf (file, "0(%s)", reg_names[REGNO (op)]);
return;
@@ -4329,6 +4634,9 @@ nios2_cdx_narrow_form_p (rtx_insn *insn)
/* GP-based references are never narrow. */
if (gprel_constant_p (addr))
return false;
+ /* %lo requires a 16-bit relocation and is never narrow. */
+ if (GET_CODE (addr) == LO_SUM)
+ return false;
ret = split_mem_address (addr, &rhs1, &rhs2);
gcc_assert (ret);
}
@@ -4373,6 +4681,9 @@ nios2_cdx_narrow_form_p (rtx_insn *insn)
/* GP-based references are never narrow. */
if (gprel_constant_p (addr))
return false;
+ /* %lo requires a 16-bit relocation and is never narrow. */
+ if (GET_CODE (addr) == LO_SUM)
+ return false;
ret = split_mem_address (addr, &rhs1, &rhs2);
gcc_assert (ret);
offset = INTVAL (rhs2);
@@ -5052,15 +5363,15 @@ nios2_adjust_reg_alloc_order (void)
#undef TARGET_LEGITIMATE_ADDRESS_P
#define TARGET_LEGITIMATE_ADDRESS_P nios2_legitimate_address_p
-#undef TARGET_LRA_P
-#define TARGET_LRA_P hook_bool_void_false
-
#undef TARGET_PREFERRED_RELOAD_CLASS
#define TARGET_PREFERRED_RELOAD_CLASS nios2_preferred_reload_class
#undef TARGET_RTX_COSTS
#define TARGET_RTX_COSTS nios2_rtx_costs
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST nios2_address_cost
+
#undef TARGET_HAVE_TLS
#define TARGET_HAVE_TLS TARGET_LINUX_ABI
@@ -5116,6 +5427,9 @@ nios2_adjust_reg_alloc_order (void)
#undef TARGET_MACHINE_DEPENDENT_REORG
#define TARGET_MACHINE_DEPENDENT_REORG nios2_reorg
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-nios2.h"
diff --git a/gcc/config/nios2/nios2.h b/gcc/config/nios2/nios2.h
index d911b54..420543e 100644
--- a/gcc/config/nios2/nios2.h
+++ b/gcc/config/nios2/nios2.h
@@ -92,10 +92,6 @@
#define PREFERRED_STACK_BOUNDARY 32
#define MAX_FIXED_MODE_SIZE 64
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST) \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
#define LABEL_ALIGN(LABEL) nios2_label_align (LABEL)
/* Layout of source language data types. */
@@ -256,7 +252,6 @@ enum reg_class
/* Stack layout. */
#define STACK_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
#define FIRST_PARM_OFFSET(FUNDECL) 0
/* Before the prologue, RA lives in r31. */
diff --git a/gcc/config/nios2/nios2.md b/gcc/config/nios2/nios2.md
index 206ebce..ef2883f 100644
--- a/gcc/config/nios2/nios2.md
+++ b/gcc/config/nios2/nios2.md
@@ -201,7 +201,7 @@
"addi\\t%0, %1, %L2"
[(set_attr "type" "alu")])
-(define_insn "movqi_internal"
+(define_insn_and_split "movqi_internal"
[(set (match_operand:QI 0 "nonimmediate_operand" "=m, r,r")
(match_operand:QI 1 "general_operand" "rM,m,rI"))]
"(register_operand (operands[0], QImode)
@@ -224,20 +224,47 @@
gcc_unreachable ();
}
}
+ "(nios2_symbolic_memory_operand_p (operands[0])
+ || nios2_symbolic_memory_operand_p (operands[1]))"
+ [(set (match_dup 0) (match_dup 1))]
+ {
+ if (nios2_symbolic_memory_operand_p (operands[0]))
+ operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
+ else
+ operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ }
[(set_attr "type" "st,ld,mov")])
-(define_insn "movhi_internal"
+(define_insn_and_split "movhi_internal"
[(set (match_operand:HI 0 "nonimmediate_operand" "=m, r,r")
(match_operand:HI 1 "general_operand" "rM,m,rI"))]
"(register_operand (operands[0], HImode)
|| reg_or_0_operand (operands[1], HImode))"
- "@
- sth%o0%.\\t%z1, %0
- ldhu%o1%.\\t%0, %1
- mov%i1%.\\t%0, %z1"
+ {
+ switch (which_alternative)
+ {
+ case 0:
+ return "sth%o0%.\\t%z1, %0";
+ case 1:
+ return "ldhu%o1%.\\t%0, %1";
+ case 2:
+ return "mov%i1%.\\t%0, %z1";
+ default:
+ gcc_unreachable ();
+ }
+ }
+ "(nios2_symbolic_memory_operand_p (operands[0])
+ || nios2_symbolic_memory_operand_p (operands[1]))"
+ [(set (match_dup 0) (match_dup 1))]
+ {
+ if (nios2_symbolic_memory_operand_p (operands[0]))
+ operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
+ else
+ operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ }
[(set_attr "type" "st,ld,mov")])
-(define_insn "movsi_internal"
+(define_insn_and_split "movsi_internal"
[(set (match_operand:SI 0 "nonimmediate_operand" "=m, r,r, r")
(match_operand:SI 1 "general_operand" "rM,m,rIJK,S"))]
"(register_operand (operands[0], SImode)
@@ -269,6 +296,18 @@
gcc_unreachable ();
}
}
+ "(nios2_symbolic_memory_operand_p (operands[0])
+ || nios2_symbolic_memory_operand_p (operands[1])
+ || nios2_large_constant_p (operands[1]))"
+ [(set (match_dup 0) (match_dup 1))]
+ {
+ if (nios2_symbolic_memory_operand_p (operands[0]))
+ operands[0] = nios2_split_symbolic_memory_operand (operands[0]);
+ else if (nios2_symbolic_memory_operand_p (operands[1]))
+ operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ else
+ operands[1] = nios2_split_large_constant (operands[1], operands[0]);
+ }
[(set_attr "type" "st,ld,mov,alu")])
(define_mode_iterator BH [QI HI])
@@ -318,42 +357,62 @@
(define_mode_iterator QX [HI SI])
;; Zero extension patterns
-(define_insn "zero_extendhisi2"
+(define_insn_and_split "zero_extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
""
"@
andi%.\\t%0, %1, 0xffff
ldhu%o1%.\\t%0, %1"
+ "nios2_symbolic_memory_operand_p (operands[1])"
+ [(set (match_dup 0) (zero_extend:SI (match_dup 1)))]
+ {
+ operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ }
[(set_attr "type" "and,ld")])
-(define_insn "zero_extendqi<mode>2"
+(define_insn_and_split "zero_extendqi<mode>2"
[(set (match_operand:QX 0 "register_operand" "=r,r")
(zero_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
""
"@
andi%.\\t%0, %1, 0xff
ldbu%o1%.\\t%0, %1"
+ "nios2_symbolic_memory_operand_p (operands[1])"
+ [(set (match_dup 0) (zero_extend:QX (match_dup 1)))]
+ {
+ operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ }
[(set_attr "type" "and,ld")])
;; Sign extension patterns
-(define_insn "extendhisi2"
+(define_insn_and_split "extendhisi2"
[(set (match_operand:SI 0 "register_operand" "=r,r")
(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "r,m")))]
""
"@
#
ldh%o1%.\\t%0, %1"
+ "nios2_symbolic_memory_operand_p (operands[1])"
+ [(set (match_dup 0) (sign_extend:SI (match_dup 1)))]
+ {
+ operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ }
[(set_attr "type" "alu,ld")])
-(define_insn "extendqi<mode>2"
+(define_insn_and_split "extendqi<mode>2"
[(set (match_operand:QX 0 "register_operand" "=r,r")
(sign_extend:QX (match_operand:QI 1 "nonimmediate_operand" "r,m")))]
""
"@
#
ldb%o1%.\\t%0, %1"
+ "nios2_symbolic_memory_operand_p (operands[1])"
+ [(set (match_dup 0) (sign_extend:QX (match_dup 1)))]
+ {
+ operands[1] = nios2_split_symbolic_memory_operand (operands[1]);
+ }
[(set_attr "type" "alu,ld")])
;; Split patterns for register alternative cases.
diff --git a/gcc/config/nvptx/nvptx.c b/gcc/config/nvptx/nvptx.c
index 6cf9a66..634f660 100644
--- a/gcc/config/nvptx/nvptx.c
+++ b/gcc/config/nvptx/nvptx.c
@@ -2304,11 +2304,14 @@ nvptx_output_call_insn (rtx_insn *insn, rtx result, rtx callee)
fprintf (asm_out_file, ";\n");
if (find_reg_note (insn, REG_NORETURN, NULL))
- /* No return functions confuse the PTX JIT, as it doesn't realize
- the flow control barrier they imply. It can seg fault if it
- encounters what looks like an unexitable loop. Emit a trailing
- trap, which it does grok. */
- fprintf (asm_out_file, "\t\ttrap; // (noreturn)\n");
+ {
+ /* No return functions confuse the PTX JIT, as it doesn't realize
+ the flow control barrier they imply. It can seg fault if it
+ encounters what looks like an unexitable loop. Emit a trailing
+ trap and exit, which it does grok. */
+ fprintf (asm_out_file, "\t\ttrap; // (noreturn)\n");
+ fprintf (asm_out_file, "\t\texit; // (noreturn)\n");
+ }
if (result)
{
diff --git a/gcc/config/nvptx/nvptx.h b/gcc/config/nvptx/nvptx.h
index d02e854..f81b9e2 100644
--- a/gcc/config/nvptx/nvptx.h
+++ b/gcc/config/nvptx/nvptx.h
@@ -122,7 +122,6 @@ enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES };
/* Stack and Calling. */
-#define STARTING_FRAME_OFFSET 0
#define FRAME_GROWS_DOWNWARD 0
#define STACK_GROWS_DOWNWARD 1
diff --git a/gcc/config/pa/pa-linux.h b/gcc/config/pa/pa-linux.h
index a304c72..811e697 100644
--- a/gcc/config/pa/pa-linux.h
+++ b/gcc/config/pa/pa-linux.h
@@ -141,3 +141,6 @@ along with GCC; see the file COPYING3. If not see
#define HAVE_sync_compare_and_swaphi 1
#define HAVE_sync_compare_and_swapsi 1
#define HAVE_sync_compare_and_swapdi 1
+
+#undef NEED_INDICATE_EXEC_STACK
+#define NEED_INDICATE_EXEC_STACK 1
diff --git a/gcc/config/pa/pa.c b/gcc/config/pa/pa.c
index 651ae59..3e2ef9d 100644
--- a/gcc/config/pa/pa.c
+++ b/gcc/config/pa/pa.c
@@ -159,9 +159,7 @@ static void pa_hpux64_gas_file_start (void) ATTRIBUTE_UNUSED;
static void pa_hpux64_hpas_file_start (void) ATTRIBUTE_UNUSED;
static void output_deferred_plabels (void);
static void output_deferred_profile_counters (void) ATTRIBUTE_UNUSED;
-#ifdef ASM_OUTPUT_EXTERNAL_REAL
-static void pa_hpux_file_end (void);
-#endif
+static void pa_file_end (void);
static void pa_init_libfuncs (void);
static rtx pa_struct_value_rtx (tree, int);
static bool pa_pass_by_reference (cumulative_args_t, machine_mode,
@@ -205,6 +203,7 @@ static unsigned int pa_hard_regno_nregs (unsigned int, machine_mode);
static bool pa_hard_regno_mode_ok (unsigned int, machine_mode);
static bool pa_modes_tieable_p (machine_mode, machine_mode);
static bool pa_can_change_mode_class (machine_mode, machine_mode, reg_class_t);
+static HOST_WIDE_INT pa_starting_frame_offset (void);
/* The following extra sections are only used for SOM. */
static GTY(()) section *som_readonly_data_section;
@@ -301,11 +300,7 @@ static size_t n_deferred_plabels = 0;
#define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
#undef TARGET_ASM_FILE_END
-#ifdef ASM_OUTPUT_EXTERNAL_REAL
-#define TARGET_ASM_FILE_END pa_hpux_file_end
-#else
-#define TARGET_ASM_FILE_END output_deferred_plabels
-#endif
+#define TARGET_ASM_FILE_END pa_file_end
#undef TARGET_ASM_RELOC_RW_MASK
#define TARGET_ASM_RELOC_RW_MASK pa_reloc_rw_mask
@@ -425,6 +420,12 @@ static size_t n_deferred_plabels = 0;
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS pa_can_change_mode_class
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET pa_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Parse the -mfixed-range= option string. */
@@ -3782,11 +3783,11 @@ pa_compute_frame_size (HOST_WIDE_INT size, int *fregs_live)
size = (size + UNITS_PER_WORD - 1) & ~(UNITS_PER_WORD - 1);
/* Space for previous frame pointer + filler. If any frame is
- allocated, we need to add in the STARTING_FRAME_OFFSET. We
+ allocated, we need to add in the TARGET_STARTING_FRAME_OFFSET. We
waste some space here for the sake of HP compatibility. The
first slot is only used when the frame pointer is needed. */
if (size || frame_pointer_needed)
- size += STARTING_FRAME_OFFSET;
+ size += pa_starting_frame_offset ();
/* If the current function calls __builtin_eh_return, then we need
to allocate stack space for registers that will hold data for
@@ -3921,7 +3922,7 @@ pa_expand_prologue (void)
and must be changed in tandem with this code. */
local_fsize = (size + UNITS_PER_WORD - 1) & ~(UNITS_PER_WORD - 1);
if (local_fsize || frame_pointer_needed)
- local_fsize += STARTING_FRAME_OFFSET;
+ local_fsize += pa_starting_frame_offset ();
actual_fsize = pa_compute_frame_size (size, &save_fregs);
if (flag_stack_usage_info)
@@ -9976,22 +9977,26 @@ pa_hpux_asm_output_external (FILE *file, tree decl, const char *name)
extern_symbol p = {decl, name};
vec_safe_push (extern_symbols, p);
}
+#endif
/* Output text required at the end of an assembler file.
This includes deferred plabels and .import directives for
all external symbols that were actually referenced. */
static void
-pa_hpux_file_end (void)
+pa_file_end (void)
{
+#ifdef ASM_OUTPUT_EXTERNAL_REAL
unsigned int i;
extern_symbol *p;
if (!NO_DEFERRED_PROFILE_COUNTERS)
output_deferred_profile_counters ();
+#endif
output_deferred_plabels ();
+#ifdef ASM_OUTPUT_EXTERNAL_REAL
for (i = 0; vec_safe_iterate (extern_symbols, i, &p); i++)
{
tree decl = p->decl;
@@ -10002,9 +10007,12 @@ pa_hpux_file_end (void)
}
vec_free (extern_symbols);
-}
#endif
+ if (NEED_INDICATE_EXEC_STACK)
+ file_end_indicate_exec_stack ();
+}
+
/* Implement TARGET_CAN_CHANGE_MODE_CLASS. */
static bool
@@ -10805,4 +10813,17 @@ pa_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
return PA_HARD_REGNO_MODE_OK (regno, mode);
}
+/* Implement TARGET_STARTING_FRAME_OFFSET.
+
+ On the 32-bit ports, we reserve one slot for the previous frame
+ pointer and one fill slot. The fill slot is for compatibility
+ with HP compiled programs. On the 64-bit ports, we reserve one
+ slot for the previous frame pointer. */
+
+static HOST_WIDE_INT
+pa_starting_frame_offset (void)
+{
+ return 8;
+}
+
#include "gt-pa.h"
diff --git a/gcc/config/pa/pa.h b/gcc/config/pa/pa.h
index 2edf0db..7bd1f11 100644
--- a/gcc/config/pa/pa.h
+++ b/gcc/config/pa/pa.h
@@ -309,11 +309,6 @@ typedef struct GTY(()) machine_function
atomic operations. */
#define MALLOC_ABI_ALIGNMENT (TARGET_SOM ? 64 : 128)
-/* Get around hp-ux assembler bug, and make strcpy of constants fast. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
@@ -499,17 +494,6 @@ extern rtx hppa_pic_save_rtx (void);
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD 0
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated.
-
- On the 32-bit ports, we reserve one slot for the previous frame
- pointer and one fill slot. The fill slot is for compatibility
- with HP compiled programs. On the 64-bit ports, we reserve one
- slot for the previous frame pointer. */
-#define STARTING_FRAME_OFFSET 8
-
/* Define STACK_ALIGNMENT_NEEDED to zero to disable final alignment
of the stack. The default is to align it to STACK_BOUNDARY. */
#define STACK_ALIGNMENT_NEEDED 0
@@ -1311,3 +1295,5 @@ do { \
seven and four instructions, respectively. */
#define MAX_PCREL17F_OFFSET \
(flag_pic ? (TARGET_HPUX ? 198164 : 221312) : 240000)
+
+#define NEED_INDICATE_EXEC_STACK 0
diff --git a/gcc/config/pdp11/pdp11.h b/gcc/config/pdp11/pdp11.h
index 3c89327..115bb5b 100644
--- a/gcc/config/pdp11/pdp11.h
+++ b/gcc/config/pdp11/pdp11.h
@@ -257,12 +257,6 @@ enum reg_class { NO_REGS, MUL_REGS, GENERAL_REGS, LOAD_FPU_REGS, NO_LOAD_FPU_REG
*/
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by.
On the pdp11, the stack is on an even boundary */
diff --git a/gcc/config/powerpcspe/aix.h b/gcc/config/powerpcspe/aix.h
index 6c91a90..607b42c 100644
--- a/gcc/config/powerpcspe/aix.h
+++ b/gcc/config/powerpcspe/aix.h
@@ -54,13 +54,11 @@
sizes of the fixed area and the parameter area must be a multiple of
STACK_BOUNDARY. */
-#undef STARTING_FRAME_OFFSET
-#define STARTING_FRAME_OFFSET \
- (FRAME_GROWS_DOWNWARD \
- ? 0 \
- : (cfun->calls_alloca \
- ? RS6000_ALIGN (crtl->outgoing_args_size + RS6000_SAVE_AREA, 16) \
- : (RS6000_ALIGN (crtl->outgoing_args_size, 16) + RS6000_SAVE_AREA)))
+#undef RS6000_STARTING_FRAME_OFFSET
+#define RS6000_STARTING_FRAME_OFFSET \
+ (cfun->calls_alloca \
+ ? RS6000_ALIGN (crtl->outgoing_args_size + RS6000_SAVE_AREA, 16) \
+ : (RS6000_ALIGN (crtl->outgoing_args_size, 16) + RS6000_SAVE_AREA))
/* Offset from the stack pointer register to an item dynamically
allocated on the stack, e.g., by `alloca'.
diff --git a/gcc/config/powerpcspe/darwin.h b/gcc/config/powerpcspe/darwin.h
index 51474ae..ac268dc 100644
--- a/gcc/config/powerpcspe/darwin.h
+++ b/gcc/config/powerpcspe/darwin.h
@@ -148,12 +148,10 @@ extern int darwin_emit_branch_islands;
/* Pad the outgoing args area to 16 bytes instead of the usual 8. */
-#undef STARTING_FRAME_OFFSET
-#define STARTING_FRAME_OFFSET \
- (FRAME_GROWS_DOWNWARD \
- ? 0 \
- : (RS6000_ALIGN (crtl->outgoing_args_size, 16) \
- + RS6000_SAVE_AREA))
+#undef RS6000_STARTING_FRAME_OFFSET
+#define RS6000_STARTING_FRAME_OFFSET \
+ (RS6000_ALIGN (crtl->outgoing_args_size, 16) \
+ + RS6000_SAVE_AREA)
#undef STACK_DYNAMIC_OFFSET
#define STACK_DYNAMIC_OFFSET(FUNDECL) \
diff --git a/gcc/config/powerpcspe/powerpcspe-c.c b/gcc/config/powerpcspe/powerpcspe-c.c
index db04153..661480f 100644
--- a/gcc/config/powerpcspe/powerpcspe-c.c
+++ b/gcc/config/powerpcspe/powerpcspe-c.c
@@ -6055,7 +6055,8 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
/* If the second argument is an integer constant, if the value is in
the expected range, generate the built-in code if we can. We need
64-bit and direct move to extract the small integer vectors. */
- if (TREE_CODE (arg2) == INTEGER_CST && wi::ltu_p (arg2, nunits))
+ if (TREE_CODE (arg2) == INTEGER_CST
+ && wi::ltu_p (wi::to_wide (arg2), nunits))
{
switch (mode)
{
@@ -6217,7 +6218,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
mode = TYPE_MODE (arg1_type);
if ((mode == V2DFmode || mode == V2DImode) && VECTOR_UNIT_VSX_P (mode)
&& TREE_CODE (arg2) == INTEGER_CST
- && wi::ltu_p (arg2, 2))
+ && wi::ltu_p (wi::to_wide (arg2), 2))
{
tree call = NULL_TREE;
@@ -6233,7 +6234,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
}
else if (mode == V1TImode && VECTOR_UNIT_VSX_P (mode)
&& TREE_CODE (arg2) == INTEGER_CST
- && wi::eq_p (arg2, 0))
+ && wi::eq_p (wi::to_wide (arg2), 0))
{
tree call = rs6000_builtin_decls[VSX_BUILTIN_VEC_SET_V1TI];
diff --git a/gcc/config/powerpcspe/powerpcspe.c b/gcc/config/powerpcspe/powerpcspe.c
index 11664ee..b5fc656 100644
--- a/gcc/config/powerpcspe/powerpcspe.c
+++ b/gcc/config/powerpcspe/powerpcspe.c
@@ -1984,6 +1984,12 @@ static const struct attribute_spec rs6000_attribute_table[] =
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS rs6000_can_change_mode_class
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT rs6000_constant_alignment
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET rs6000_starting_frame_offset
/* Processor table. */
@@ -5852,6 +5858,7 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return 3;
case unaligned_load:
+ case vector_gather_load:
if (TARGET_P9_VECTOR)
return 3;
@@ -5893,6 +5900,7 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return 2;
case unaligned_store:
+ case vector_scatter_store:
if (TARGET_EFFICIENT_UNALIGNED_VSX)
return 1;
@@ -9531,6 +9539,8 @@ rs6000_delegitimize_address (rtx orig_x)
static bool
rs6000_const_not_ok_for_debug_p (rtx x)
{
+ if (GET_CODE (x) == UNSPEC)
+ return true;
if (GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x))
{
@@ -11614,7 +11624,8 @@ rs6000_aggregate_candidate (const_tree type, machine_mode *modep)
- tree_to_uhwi (TYPE_MIN_VALUE (index)));
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -11644,7 +11655,8 @@ rs6000_aggregate_candidate (const_tree type, machine_mode *modep)
}
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -11676,7 +11688,8 @@ rs6000_aggregate_candidate (const_tree type, machine_mode *modep)
}
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -15933,14 +15946,15 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
/* Check whether the 2nd and 3rd arguments are integer constants and in
range and prepare arguments. */
STRIP_NOPS (arg1);
- if (TREE_CODE (arg1) != INTEGER_CST || wi::geu_p (arg1, 2))
+ if (TREE_CODE (arg1) != INTEGER_CST || wi::geu_p (wi::to_wide (arg1), 2))
{
error ("argument 2 must be 0 or 1");
return CONST0_RTX (tmode);
}
STRIP_NOPS (arg2);
- if (TREE_CODE (arg2) != INTEGER_CST || wi::geu_p (arg2, 16))
+ if (TREE_CODE (arg2) != INTEGER_CST
+ || wi::geu_p (wi::to_wide (arg2), 16))
{
error ("argument 3 must be in the range 0..15");
return CONST0_RTX (tmode);
@@ -29687,18 +29701,19 @@ rs6000_emit_prologue (void)
if (flag_stack_usage_info)
current_function_static_stack_size = info->total_size;
- if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
{
HOST_WIDE_INT size = info->total_size;
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
- rs6000_emit_probe_stack_range (STACK_CHECK_PROTECT,
- size - STACK_CHECK_PROTECT);
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+ rs6000_emit_probe_stack_range (get_stack_check_protect (),
+ size - get_stack_check_protect ());
}
else if (size > 0)
- rs6000_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
+ rs6000_emit_probe_stack_range (get_stack_check_protect (), size);
}
if (TARGET_FIX_AND_CONTINUE)
@@ -38730,8 +38745,7 @@ rs6000_expand_vec_perm_const (rtx operands[4])
/* Test whether a constant permutation is supported. */
static bool
-rs6000_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel)
+rs6000_vectorize_vec_perm_const_ok (machine_mode vmode, vec_perm_indices sel)
{
/* AltiVec (and thus VSX) can handle arbitrary permutations. */
if (TARGET_ALTIVEC)
@@ -43752,6 +43766,27 @@ rs6000_optab_supported_p (int op, machine_mode mode1, machine_mode,
return true;
}
}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+rs6000_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST
+ && (STRICT_ALIGNMENT || !optimize_size))
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
+
+static HOST_WIDE_INT
+rs6000_starting_frame_offset (void)
+{
+ if (FRAME_GROWS_DOWNWARD)
+ return 0;
+ return RS6000_STARTING_FRAME_OFFSET;
+}
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/powerpcspe/powerpcspe.h b/gcc/config/powerpcspe/powerpcspe.h
index 52c0376..bc37c6f 100644
--- a/gcc/config/powerpcspe/powerpcspe.h
+++ b/gcc/config/powerpcspe/powerpcspe.h
@@ -978,14 +978,6 @@ enum data_align { align_abi, align_opt, align_both };
#define LOCAL_ALIGNMENT(TYPE, ALIGN) \
rs6000_data_alignment (TYPE, ALIGN, align_both)
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (STRICT_ALIGNMENT || !optimize_size) \
- && (ALIGN) < BITS_PER_WORD \
- ? BITS_PER_WORD \
- : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
rs6000_data_alignment (TYPE, ALIGN, align_opt)
@@ -1656,15 +1648,13 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
sizes of the fixed area and the parameter area must be a multiple of
STACK_BOUNDARY. */
-#define STARTING_FRAME_OFFSET \
- (FRAME_GROWS_DOWNWARD \
- ? 0 \
- : (cfun->calls_alloca \
- ? (RS6000_ALIGN (crtl->outgoing_args_size + RS6000_SAVE_AREA, \
- (TARGET_ALTIVEC || TARGET_VSX) ? 16 : 8 )) \
- : (RS6000_ALIGN (crtl->outgoing_args_size, \
- (TARGET_ALTIVEC || TARGET_VSX) ? 16 : 8) \
- + RS6000_SAVE_AREA)))
+#define RS6000_STARTING_FRAME_OFFSET \
+ (cfun->calls_alloca \
+ ? (RS6000_ALIGN (crtl->outgoing_args_size + RS6000_SAVE_AREA, \
+ (TARGET_ALTIVEC || TARGET_VSX) ? 16 : 8 )) \
+ : (RS6000_ALIGN (crtl->outgoing_args_size, \
+ (TARGET_ALTIVEC || TARGET_VSX) ? 16 : 8) \
+ + RS6000_SAVE_AREA))
/* Offset from the stack pointer register to an item dynamically
allocated on the stack, e.g., by `alloca'.
diff --git a/gcc/config/riscv/riscv.c b/gcc/config/riscv/riscv.c
index 42ddac9..c34468e 100644
--- a/gcc/config/riscv/riscv.c
+++ b/gcc/config/riscv/riscv.c
@@ -3995,6 +3995,17 @@ riscv_can_change_mode_class (machine_mode, machine_mode, reg_class_t rclass)
return !reg_classes_intersect_p (FP_REGS, rclass);
}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+riscv_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
#define TARGET_ASM_ALIGNED_HI_OP "\t.half\t"
@@ -4142,6 +4153,9 @@ riscv_can_change_mode_class (machine_mode, machine_mode, reg_class_t rclass)
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS riscv_can_change_mode_class
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT riscv_constant_alignment
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-riscv.h"
diff --git a/gcc/config/riscv/riscv.h b/gcc/config/riscv/riscv.h
index a04da2c..e53555e 100644
--- a/gcc/config/riscv/riscv.h
+++ b/gcc/config/riscv/riscv.h
@@ -152,22 +152,6 @@ along with GCC; see the file COPYING3. If not see
#define PCC_BITFIELD_TYPE_MATTERS 1
-/* If defined, a C expression to compute the alignment given to a
- constant that is being placed in memory. CONSTANT is the constant
- and ALIGN is the alignment that the object would ordinarily have.
- The value of this macro is used instead of that alignment to align
- the object.
-
- If this macro is not defined, then ALIGN is used.
-
- The typical use of this macro is to increase alignment for string
- constants to be word aligned so that `strcpy' calls that copy
- constants can be done inline. */
-
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST || TREE_CODE (EXP) == CONSTRUCTOR) \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
/* If defined, a C expression to compute the alignment for a static
variable. TYPE is the data type, and ALIGN is the alignment that
the object would ordinarily have. The value of this macro is used
@@ -462,8 +446,6 @@ enum reg_class
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
-
#define RETURN_ADDR_RTX riscv_return_addr
#define ELIMINABLE_REGS \
diff --git a/gcc/config/rl78/rl78-protos.h b/gcc/config/rl78/rl78-protos.h
index a155df6..976bffa 100644
--- a/gcc/config/rl78/rl78-protos.h
+++ b/gcc/config/rl78/rl78-protos.h
@@ -54,3 +54,13 @@ void rl78_output_aligned_common (FILE *, tree, const char *,
int, int, int);
int rl78_one_far_p (rtx *operands, int num_operands);
+
+#ifdef RTX_CODE
+#ifdef HAVE_MACHINE_MODES
+
+rtx rl78_emit_libcall (const char*, enum rtx_code,
+ enum machine_mode, enum machine_mode,
+ int, rtx*);
+
+#endif
+#endif
diff --git a/gcc/config/rl78/rl78.c b/gcc/config/rl78/rl78.c
index 6b13a80a..c835dc0 100644
--- a/gcc/config/rl78/rl78.c
+++ b/gcc/config/rl78/rl78.c
@@ -4791,6 +4791,45 @@ rl78_addsi3_internal (rtx * operands, unsigned int alternative)
}
}
+rtx
+rl78_emit_libcall (const char *name, enum rtx_code code,
+ enum machine_mode dmode, enum machine_mode smode,
+ int noperands, rtx *operands)
+{
+ rtx ret;
+ rtx_insn *insns;
+ rtx libcall;
+ rtx equiv;
+
+ start_sequence ();
+ libcall = gen_rtx_SYMBOL_REF (Pmode, name);
+
+ switch (noperands)
+ {
+ case 2:
+ ret = emit_library_call_value (libcall, NULL_RTX, LCT_CONST,
+ dmode, operands[1], smode);
+ equiv = gen_rtx_fmt_e (code, dmode, operands[1]);
+ break;
+
+ case 3:
+ ret = emit_library_call_value (libcall, NULL_RTX,
+ LCT_CONST, dmode,
+ operands[1], smode, operands[2],
+ smode);
+ equiv = gen_rtx_fmt_ee (code, dmode, operands[1], operands[2]);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ insns = get_insns ();
+ end_sequence ();
+ emit_libcall_block (insns, operands[0], ret, equiv);
+ return ret;
+}
+
#undef TARGET_PREFERRED_RELOAD_CLASS
#define TARGET_PREFERRED_RELOAD_CLASS rl78_preferred_reload_class
diff --git a/gcc/config/rl78/rl78.h b/gcc/config/rl78/rl78.h
index 30dfee8..e6b6409 100644
--- a/gcc/config/rl78/rl78.h
+++ b/gcc/config/rl78/rl78.h
@@ -149,7 +149,6 @@
#define HAS_LONG_UNCOND_BRANCH 0
#define MOVE_MAX 2
-#define STARTING_FRAME_OFFSET 0
#define ADDR_SPACE_NEAR 1
#define ADDR_SPACE_FAR 2
diff --git a/gcc/config/rl78/rl78.md b/gcc/config/rl78/rl78.md
index 722d984..c53ca0f 100644
--- a/gcc/config/rl78/rl78.md
+++ b/gcc/config/rl78/rl78.md
@@ -224,6 +224,16 @@
DONE;"
)
+(define_expand "adddi3"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (plus:DI (match_operand:DI 1 "general_operand" "")
+ (match_operand:DI 2 "general_operand" "")))
+ ]
+ ""
+ "rl78_emit_libcall (\"__adddi3\", PLUS, DImode, DImode, 3, operands);
+ DONE;"
+)
+
(define_insn "addsi3_internal_virt"
[(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vm, vm")
(plus:SI (match_operand:SI 1 "general_operand" "0, vim, vim")
@@ -258,6 +268,16 @@
DONE;"
)
+(define_expand "subdi3"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (minus:DI (match_operand:DI 1 "general_operand" "")
+ (match_operand:DI 2 "general_operand" "")))
+ ]
+ ""
+ "rl78_emit_libcall (\"__subdi3\", MINUS, DImode, DImode, 3, operands);
+ DONE;"
+)
+
(define_insn "subsi3_internal_virt"
[(set (match_operand:SI 0 "nonimmediate_operand" "=v,&vm, vm")
(minus:SI (match_operand:SI 1 "general_operand" "0, vim, vim")
diff --git a/gcc/config/rs6000/aix.h b/gcc/config/rs6000/aix.h
index 6c91a90..607b42c 100644
--- a/gcc/config/rs6000/aix.h
+++ b/gcc/config/rs6000/aix.h
@@ -54,13 +54,11 @@
sizes of the fixed area and the parameter area must be a multiple of
STACK_BOUNDARY. */
-#undef STARTING_FRAME_OFFSET
-#define STARTING_FRAME_OFFSET \
- (FRAME_GROWS_DOWNWARD \
- ? 0 \
- : (cfun->calls_alloca \
- ? RS6000_ALIGN (crtl->outgoing_args_size + RS6000_SAVE_AREA, 16) \
- : (RS6000_ALIGN (crtl->outgoing_args_size, 16) + RS6000_SAVE_AREA)))
+#undef RS6000_STARTING_FRAME_OFFSET
+#define RS6000_STARTING_FRAME_OFFSET \
+ (cfun->calls_alloca \
+ ? RS6000_ALIGN (crtl->outgoing_args_size + RS6000_SAVE_AREA, 16) \
+ : (RS6000_ALIGN (crtl->outgoing_args_size, 16) + RS6000_SAVE_AREA))
/* Offset from the stack pointer register to an item dynamically
allocated on the stack, e.g., by `alloca'.
diff --git a/gcc/config/rs6000/altivec.h b/gcc/config/rs6000/altivec.h
index c8e508c..94a4db2 100644
--- a/gcc/config/rs6000/altivec.h
+++ b/gcc/config/rs6000/altivec.h
@@ -467,6 +467,8 @@
#ifdef _ARCH_PPC64
#define vec_xl_len __builtin_vec_lxvl
#define vec_xst_len __builtin_vec_stxvl
+#define vec_xl_len_r __builtin_vec_xl_len_r
+#define vec_xst_len_r __builtin_vec_xst_len_r
#endif
#define vec_cmpnez __builtin_vec_vcmpnez
diff --git a/gcc/config/rs6000/altivec.md b/gcc/config/rs6000/altivec.md
index 8631604..6ea529b 100644
--- a/gcc/config/rs6000/altivec.md
+++ b/gcc/config/rs6000/altivec.md
@@ -2594,6 +2594,15 @@
DONE;
})
+(define_insn "altivec_lvsl_reg"
+ [(set (match_operand:V16QI 0 "altivec_register_operand" "=v")
+ (unspec:V16QI
+ [(match_operand:DI 1 "gpc_reg_operand" "b")]
+ UNSPEC_LVSL_REG))]
+ "TARGET_ALTIVEC"
+ "lvsl %0,0,%1"
+ [(set_attr "type" "vecload")])
+
(define_insn "altivec_lvsl_direct"
[(set (match_operand:V16QI 0 "register_operand" "=v")
(unspec:V16QI [(match_operand:V16QI 1 "memory_operand" "Z")]
@@ -2603,8 +2612,8 @@
[(set_attr "type" "vecload")])
(define_expand "altivec_lvsr"
- [(use (match_operand:V16QI 0 "register_operand" ""))
- (use (match_operand:V16QI 1 "memory_operand" ""))]
+ [(use (match_operand:V16QI 0 "altivec_register_operand"))
+ (use (match_operand:V16QI 1 "memory_operand"))]
"TARGET_ALTIVEC"
{
if (VECTOR_ELT_ORDER_BIG)
@@ -2626,6 +2635,15 @@
DONE;
})
+(define_insn "altivec_lvsr_reg"
+ [(set (match_operand:V16QI 0 "altivec_register_operand" "=v")
+ (unspec:V16QI
+ [(match_operand:DI 1 "gpc_reg_operand" "b")]
+ UNSPEC_LVSR_REG))]
+ "TARGET_ALTIVEC"
+ "lvsr %0,0,%1"
+ [(set_attr "type" "vecload")])
+
(define_insn "altivec_lvsr_direct"
[(set (match_operand:V16QI 0 "register_operand" "=v")
(unspec:V16QI [(match_operand:V16QI 1 "memory_operand" "Z")]
diff --git a/gcc/config/rs6000/amo.h b/gcc/config/rs6000/amo.h
new file mode 100644
index 0000000..d83e035
--- /dev/null
+++ b/gcc/config/rs6000/amo.h
@@ -0,0 +1,152 @@
+/* Power ISA 3.0 atomic memory operation include file.
+ Copyright (C) 2017 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
+ <http://www.gnu.org/licenses/>. */
+
+#ifndef _AMO_H
+#define _AMO_H
+
+#if !defined(_ARCH_PWR9) || !defined(_ARCH_PPC64)
+#error "The atomic memory operations require Power 64-bit ISA 3.0"
+
+#else
+#include <stdint.h>
+
+/* Enumeration of the LWAT/LDAT sub-opcodes. */
+enum _AMO_LD {
+ _AMO_LD_ADD = 0x00, /* Fetch and Add. */
+ _AMO_LD_XOR = 0x01, /* Fetch and Xor. */
+ _AMO_LD_IOR = 0x02, /* Fetch and Ior. */
+ _AMO_LD_AND = 0x03, /* Fetch and And. */
+ _AMO_LD_UMAX = 0x04, /* Fetch and Unsigned Maximum. */
+ _AMO_LD_SMAX = 0x05, /* Fetch and Signed Maximum. */
+ _AMO_LD_UMIN = 0x06, /* Fetch and Unsigned Minimum. */
+ _AMO_LD_SMIN = 0x07, /* Fetch and Signed Minimum. */
+ _AMO_LD_SWAP = 0x08, /* Swap. */
+ _AMO_LD_CS_NE = 0x10, /* Compare and Swap Not Equal. */
+ _AMO_LD_INC_BOUNDED = 0x18, /* Fetch and Increment Bounded. */
+ _AMO_LD_INC_EQUAL = 0x19, /* Fetch and Increment Equal. */
+ _AMO_LD_DEC_BOUNDED = 0x1A /* Fetch and Decrement Bounded. */
+};
+
+/* Implementation of the simple LWAT/LDAT operations that take one register and
+ modify one word or double-word of memory and return the value that was
+ previously in the memory location.
+
+ The LWAT/LDAT opcode requires the address to be a single register, and that
+ points to a suitably aligned memory location. Asm volatile is used to
+ prevent the optimizer from moving the operation. */
+
+#define _AMO_LD_SIMPLE(NAME, TYPE, OPCODE, FC) \
+static __inline__ TYPE \
+NAME (TYPE *_PTR, TYPE _VALUE) \
+{ \
+ unsigned __int128 _TMP; \
+ TYPE _RET; \
+ __asm__ volatile ("mr %L1,%3\n" \
+ "\t" OPCODE " %1,%P0,%4\n" \
+ "\tmr %2,%1\n" \
+ : "+Q" (_PTR[0]), "=&r" (_TMP), "=r" (_RET) \
+ : "r" (_VALUE), "n" (FC)); \
+ return _RET; \
+}
+
+_AMO_LD_SIMPLE (amo_lwat_add, uint32_t, "lwat", _AMO_LD_ADD)
+_AMO_LD_SIMPLE (amo_lwat_xor, uint32_t, "lwat", _AMO_LD_XOR)
+_AMO_LD_SIMPLE (amo_lwat_ior, uint32_t, "lwat", _AMO_LD_IOR)
+_AMO_LD_SIMPLE (amo_lwat_and, uint32_t, "lwat", _AMO_LD_AND)
+_AMO_LD_SIMPLE (amo_lwat_umax, uint32_t, "lwat", _AMO_LD_UMAX)
+_AMO_LD_SIMPLE (amo_lwat_umin, uint32_t, "lwat", _AMO_LD_UMIN)
+_AMO_LD_SIMPLE (amo_lwat_swap, uint32_t, "lwat", _AMO_LD_SWAP)
+
+_AMO_LD_SIMPLE (amo_lwat_sadd, int32_t, "lwat", _AMO_LD_ADD)
+_AMO_LD_SIMPLE (amo_lwat_smax, int32_t, "lwat", _AMO_LD_SMAX)
+_AMO_LD_SIMPLE (amo_lwat_smin, int32_t, "lwat", _AMO_LD_SMIN)
+_AMO_LD_SIMPLE (amo_lwat_sswap, int32_t, "lwat", _AMO_LD_SWAP)
+
+_AMO_LD_SIMPLE (amo_ldat_add, uint64_t, "ldat", _AMO_LD_ADD)
+_AMO_LD_SIMPLE (amo_ldat_xor, uint64_t, "ldat", _AMO_LD_XOR)
+_AMO_LD_SIMPLE (amo_ldat_ior, uint64_t, "ldat", _AMO_LD_IOR)
+_AMO_LD_SIMPLE (amo_ldat_and, uint64_t, "ldat", _AMO_LD_AND)
+_AMO_LD_SIMPLE (amo_ldat_umax, uint64_t, "ldat", _AMO_LD_UMAX)
+_AMO_LD_SIMPLE (amo_ldat_umin, uint64_t, "ldat", _AMO_LD_UMIN)
+_AMO_LD_SIMPLE (amo_ldat_swap, uint64_t, "ldat", _AMO_LD_SWAP)
+
+_AMO_LD_SIMPLE (amo_ldat_sadd, int64_t, "ldat", _AMO_LD_ADD)
+_AMO_LD_SIMPLE (amo_ldat_smax, int64_t, "ldat", _AMO_LD_SMAX)
+_AMO_LD_SIMPLE (amo_ldat_smin, int64_t, "ldat", _AMO_LD_SMIN)
+_AMO_LD_SIMPLE (amo_ldat_sswap, int64_t, "ldat", _AMO_LD_SWAP)
+
+/* Enumeration of the STWAT/STDAT sub-opcodes. */
+enum _AMO_ST {
+ _AMO_ST_ADD = 0x00, /* Store Add. */
+ _AMO_ST_XOR = 0x01, /* Store Xor. */
+ _AMO_ST_IOR = 0x02, /* Store Ior. */
+ _AMO_ST_AND = 0x03, /* Store And. */
+ _AMO_ST_UMAX = 0x04, /* Store Unsigned Maximum. */
+ _AMO_ST_SMAX = 0x05, /* Store Signed Maximum. */
+ _AMO_ST_UMIN = 0x06, /* Store Unsigned Minimum. */
+ _AMO_ST_SMIN = 0x07, /* Store Signed Minimum. */
+ _AMO_ST_TWIN = 0x18 /* Store Twin. */
+};
+
+/* Implementation of the simple STWAT/STDAT operations that take one register
+ and modify one word or double-word of memory. No value is returned.
+
+ The STWAT/STDAT opcode requires the address to be a single register, and
+ that points to a suitably aligned memory location. Asm volatile is used to
+ prevent the optimizer from moving the operation. */
+
+#define _AMO_ST_SIMPLE(NAME, TYPE, OPCODE, FC) \
+static __inline__ void \
+NAME (TYPE *_PTR, TYPE _VALUE) \
+{ \
+ __asm__ volatile (OPCODE " %1,%P0,%2" \
+ : "+Q" (_PTR[0]) \
+ : "r" (_VALUE), "n" (FC)); \
+ return; \
+}
+
+_AMO_ST_SIMPLE (amo_stwat_add, uint32_t, "stwat", _AMO_ST_ADD)
+_AMO_ST_SIMPLE (amo_stwat_xor, uint32_t, "stwat", _AMO_ST_XOR)
+_AMO_ST_SIMPLE (amo_stwat_ior, uint32_t, "stwat", _AMO_ST_IOR)
+_AMO_ST_SIMPLE (amo_stwat_and, uint32_t, "stwat", _AMO_ST_AND)
+_AMO_ST_SIMPLE (amo_stwat_umax, uint32_t, "stwat", _AMO_ST_UMAX)
+_AMO_ST_SIMPLE (amo_stwat_umin, uint32_t, "stwat", _AMO_ST_UMIN)
+
+_AMO_ST_SIMPLE (amo_stwat_sadd, int32_t, "stwat", _AMO_ST_ADD)
+_AMO_ST_SIMPLE (amo_stwat_smax, int32_t, "stwat", _AMO_ST_SMAX)
+_AMO_ST_SIMPLE (amo_stwat_smin, int32_t, "stwat", _AMO_ST_SMIN)
+
+_AMO_ST_SIMPLE (amo_stdat_add, uint64_t, "stdat", _AMO_ST_ADD)
+_AMO_ST_SIMPLE (amo_stdat_xor, uint64_t, "stdat", _AMO_ST_XOR)
+_AMO_ST_SIMPLE (amo_stdat_ior, uint64_t, "stdat", _AMO_ST_IOR)
+_AMO_ST_SIMPLE (amo_stdat_and, uint64_t, "stdat", _AMO_ST_AND)
+_AMO_ST_SIMPLE (amo_stdat_umax, uint64_t, "stdat", _AMO_ST_UMAX)
+_AMO_ST_SIMPLE (amo_stdat_umin, uint64_t, "stdat", _AMO_ST_UMIN)
+
+_AMO_ST_SIMPLE (amo_stdat_sadd, int64_t, "stdat", _AMO_ST_ADD)
+_AMO_ST_SIMPLE (amo_stdat_smax, int64_t, "stdat", _AMO_ST_SMAX)
+_AMO_ST_SIMPLE (amo_stdat_smin, int64_t, "stdat", _AMO_ST_SMIN)
+#endif /* _ARCH_PWR9 && _ARCH_PPC64. */
+#endif /* _POWERPC_AMO_H. */
diff --git a/gcc/config/rs6000/darwin.h b/gcc/config/rs6000/darwin.h
index aeb4762..9a88a8d 100644
--- a/gcc/config/rs6000/darwin.h
+++ b/gcc/config/rs6000/darwin.h
@@ -148,12 +148,10 @@ extern int darwin_emit_branch_islands;
/* Pad the outgoing args area to 16 bytes instead of the usual 8. */
-#undef STARTING_FRAME_OFFSET
-#define STARTING_FRAME_OFFSET \
- (FRAME_GROWS_DOWNWARD \
- ? 0 \
- : (RS6000_ALIGN (crtl->outgoing_args_size, 16) \
- + RS6000_SAVE_AREA))
+#undef RS6000_STARTING_FRAME_OFFSET
+#define RS6000_STARTING_FRAME_OFFSET \
+ (RS6000_ALIGN (crtl->outgoing_args_size, 16) \
+ + RS6000_SAVE_AREA)
#undef STACK_DYNAMIC_OFFSET
#define STACK_DYNAMIC_OFFSET(FUNDECL) \
diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 237b432..569158f 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -199,6 +199,16 @@
return CA_REGNO_P (REGNO (op));
})
+;; Return 1 if operand is constant zero (scalars and vectors).
+(define_predicate "zero_constant"
+ (and (match_code "const_int,const_double,const_wide_int,const_vector")
+ (match_test "op == CONST0_RTX (mode)")))
+
+;; Return 1 if operand is constant -1 (scalars and vectors).
+(define_predicate "all_ones_constant"
+ (and (match_code "const_int,const_double,const_wide_int,const_vector")
+ (match_test "op == CONSTM1_RTX (mode) && !FLOAT_MODE_P (mode)")))
+
;; Return 1 if op is a signed 5-bit constant integer.
(define_predicate "s5bit_cint_operand"
(and (match_code "const_int")
@@ -543,12 +553,16 @@
(match_operand 0 "u_short_cint_operand")
(match_operand 0 "gpc_reg_operand")))
-;; Return 1 if op is any constant integer
-;; or non-special register.
+;; Return 1 if op is any constant integer or a non-special register.
(define_predicate "reg_or_cint_operand"
(ior (match_code "const_int")
(match_operand 0 "gpc_reg_operand")))
+;; Return 1 if op is constant zero or a non-special register.
+(define_predicate "reg_or_zero_operand"
+ (ior (match_operand 0 "zero_constant")
+ (match_operand 0 "gpc_reg_operand")))
+
;; Return 1 if op is a constant integer valid for addition with addis, addi.
(define_predicate "add_cint_operand"
(and (match_code "const_int")
@@ -744,16 +758,6 @@
(and (match_test "easy_altivec_constant (op, mode)")
(match_test "vspltis_shifted (op) != 0")))))
-;; Return 1 if operand is constant zero (scalars and vectors).
-(define_predicate "zero_constant"
- (and (match_code "const_int,const_double,const_wide_int,const_vector")
- (match_test "op == CONST0_RTX (mode)")))
-
-;; Return 1 if operand is constant -1 (scalars and vectors).
-(define_predicate "all_ones_constant"
- (and (match_code "const_int,const_double,const_wide_int,const_vector")
- (match_test "op == CONSTM1_RTX (mode) && !FLOAT_MODE_P (mode)")))
-
;; Return 1 if operand is a vector int register or is either a vector constant
;; of all 0 bits of a vector constant of all 1 bits.
(define_predicate "vector_int_reg_or_same_bit"
diff --git a/gcc/config/rs6000/rs6000-builtin.def b/gcc/config/rs6000/rs6000-builtin.def
index 07925b3..ac9ddae 100644
--- a/gcc/config/rs6000/rs6000-builtin.def
+++ b/gcc/config/rs6000/rs6000-builtin.def
@@ -608,6 +608,16 @@
CODE_FOR_ ## ICODE) /* ICODE */
+/* Miscellaneous builtins for instructions added prior to ISA 2.04. These
+ operate on floating point registers. */
+#define BU_FP_MISC_1(ENUM, NAME, ATTR, ICODE) \
+ RS6000_BUILTIN_1 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \
+ "__builtin_" NAME, /* NAME */ \
+ RS6000_BTM_HARD_FLOAT, /* MASK */ \
+ (RS6000_BTC_ ## ATTR /* ATTR */ \
+ | RS6000_BTC_UNARY), \
+ CODE_FOR_ ## ICODE) /* ICODE */
+
/* Miscellaneous builtins for instructions added in ISA 2.06. These
instructions don't require either the DFP or VSX options, just the basic ISA
2.06 (popcntd) enablement since they operate on general purpose
@@ -676,6 +686,14 @@
| RS6000_BTC_UNARY), \
CODE_FOR_ ## ICODE) /* ICODE */
+#define BU_FLOAT128_2_HW(ENUM, NAME, ATTR, ICODE) \
+ RS6000_BUILTIN_2 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \
+ "__builtin_" NAME, /* NAME */ \
+ RS6000_BTM_FLOAT128_HW, /* MASK */ \
+ (RS6000_BTC_ ## ATTR /* ATTR */ \
+ | RS6000_BTC_BINARY), \
+ CODE_FOR_ ## ICODE) /* ICODE */
+
#define BU_FLOAT128_3_HW(ENUM, NAME, ATTR, ICODE) \
RS6000_BUILTIN_3 (MISC_BUILTIN_ ## ENUM, /* ENUM */ \
"__builtin_" NAME, /* NAME */ \
@@ -1863,6 +1881,10 @@ BU_VSX_OVERLOAD_X (XL, "xl")
BU_VSX_OVERLOAD_X (XL_BE, "xl_be")
BU_VSX_OVERLOAD_X (XST, "xst")
+/* 1 argument builtins pre ISA 2.04. */
+BU_FP_MISC_1 (FCTID, "fctid", CONST, lrintdfdi2)
+BU_FP_MISC_1 (FCTIW, "fctiw", CONST, lrintsfsi2)
+
/* 2 argument CMPB instructions added in ISA 2.05. */
BU_P6_2 (CMPB_32, "cmpb_32", CONST, cmpbsi3)
BU_P6_64BIT_2 (CMPB, "cmpb", CONST, cmpbdi3)
@@ -2142,6 +2164,7 @@ BU_P9V_OVERLOAD_2 (VIESP, "insert_exp_sp")
/* 2 argument vector functions added in ISA 3.0 (power9). */
BU_P9V_64BIT_VSX_2 (LXVL, "lxvl", CONST, lxvl)
+BU_P9V_64BIT_VSX_2 (XL_LEN_R, "xl_len_r", CONST, xl_len_r)
BU_P9V_AV_2 (VEXTUBLX, "vextublx", CONST, vextublx)
BU_P9V_AV_2 (VEXTUBRX, "vextubrx", CONST, vextubrx)
@@ -2158,6 +2181,7 @@ BU_P9V_VSX_3 (VINSERT4B_DI, "vinsert4b_di", CONST, vinsert4b_di)
/* 3 argument vector functions returning void, treated as SPECIAL,
added in ISA 3.0 (power9). */
BU_P9V_64BIT_AV_X (STXVL, "stxvl", MISC)
+BU_P9V_64BIT_AV_X (XST_LEN_R, "xst_len_r", MISC)
/* 1 argument vector functions added in ISA 3.0 (power9). */
BU_P9V_AV_1 (VCLZLSBB, "vclzlsbb", CONST, vclzlsbb)
@@ -2199,12 +2223,14 @@ BU_P9V_AV_P (VCMPNEZW_P, "vcmpnezw_p", CONST, vector_nez_v4si_p)
/* ISA 3.0 Vector scalar overloaded 2 argument functions */
BU_P9V_OVERLOAD_2 (LXVL, "lxvl")
+BU_P9V_OVERLOAD_2 (XL_LEN_R, "xl_len_r")
BU_P9V_OVERLOAD_2 (VEXTULX, "vextulx")
BU_P9V_OVERLOAD_2 (VEXTURX, "vexturx")
BU_P9V_OVERLOAD_2 (VEXTRACT4B, "vextract4b")
/* ISA 3.0 Vector scalar overloaded 3 argument functions */
BU_P9V_OVERLOAD_3 (STXVL, "stxvl")
+BU_P9V_OVERLOAD_3 (XST_LEN_R, "xst_len_r")
BU_P9V_OVERLOAD_3 (VINSERT4B, "vinsert4b")
/* Overloaded CMPNE support was implemented prior to Power 9,
@@ -2347,11 +2373,19 @@ BU_P9_OVERLOAD_2 (CMPEQB, "byte_in_set")
BU_FLOAT128_1 (FABSQ, "fabsq", CONST, abskf2)
BU_FLOAT128_2 (COPYSIGNQ, "copysignq", CONST, copysignkf3)
-/* 1 and 3 argument IEEE 128-bit floating point functions that require ISA 3.0
- hardware. These functions use the new 'f128' suffix. Eventually these
- should be folded into the common built-in function handling. */
-BU_FLOAT128_1_HW (SQRTF128, "sqrtf128", CONST, sqrtkf2)
-BU_FLOAT128_3_HW (FMAF128, "fmaf128", CONST, fmakf4_hw)
+/* 1, 2, and 3 argument IEEE 128-bit floating point functions that require ISA
+ 3.0 hardware. These functions use the new 'f128' suffix. Eventually the
+ standard functions should be folded into the common built-in function
+ handling. */
+BU_FLOAT128_1_HW (SQRTF128, "sqrtf128", CONST, sqrtkf2)
+BU_FLOAT128_1_HW (SQRTF128_ODD, "sqrtf128_round_to_odd", CONST, sqrtkf2_odd)
+BU_FLOAT128_1_HW (TRUNCF128_ODD, "truncf128_round_to_odd", CONST, trunckfdf2_odd)
+BU_FLOAT128_2_HW (ADDF128_ODD, "addf128_round_to_odd", CONST, addkf3_odd)
+BU_FLOAT128_2_HW (SUBF128_ODD, "subf128_round_to_odd", CONST, subkf3_odd)
+BU_FLOAT128_2_HW (MULF128_ODD, "mulf128_round_to_odd", CONST, mulkf3_odd)
+BU_FLOAT128_2_HW (DIVF128_ODD, "divf128_round_to_odd", CONST, divkf3_odd)
+BU_FLOAT128_3_HW (FMAF128, "fmaf128", CONST, fmakf4_hw)
+BU_FLOAT128_3_HW (FMAF128_ODD, "fmaf128_round_to_odd", CONST, fmakf4_odd)
/* 1 argument crypto functions. */
BU_CRYPTO_1 (VSBOX, "vsbox", CONST, crypto_vsbox)
diff --git a/gcc/config/rs6000/rs6000-c.c b/gcc/config/rs6000/rs6000-c.c
index a49db97..8e58124 100644
--- a/gcc/config/rs6000/rs6000-c.c
+++ b/gcc/config/rs6000/rs6000-c.c
@@ -4798,6 +4798,10 @@ const struct altivec_builtin_types altivec_overloaded_builtins[] = {
{ P9V_BUILTIN_VEC_VSCEDPUO, P9V_BUILTIN_VSCEDPUO,
RS6000_BTI_INTSI, RS6000_BTI_double, RS6000_BTI_double, 0 },
+ { P9V_BUILTIN_VEC_XL_LEN_R, P9V_BUILTIN_XL_LEN_R,
+ RS6000_BTI_unsigned_V16QI, ~RS6000_BTI_UINTQI,
+ RS6000_BTI_unsigned_long_long, 0 },
+
{ P9V_BUILTIN_VEC_LXVL, P9V_BUILTIN_LXVL,
RS6000_BTI_V16QI, ~RS6000_BTI_INTQI,
RS6000_BTI_unsigned_long_long, 0 },
@@ -4842,6 +4846,10 @@ const struct altivec_builtin_types altivec_overloaded_builtins[] = {
/* At an appropriate future time, add support for the
RS6000_BTI_Float16 (exact name to be determined) type here. */
+ { P9V_BUILTIN_VEC_XST_LEN_R, P9V_BUILTIN_XST_LEN_R,
+ RS6000_BTI_void, RS6000_BTI_unsigned_V16QI,
+ ~RS6000_BTI_UINTQI, RS6000_BTI_unsigned_long_long},
+
{ P9V_BUILTIN_VEC_STXVL, P9V_BUILTIN_STXVL,
RS6000_BTI_void, RS6000_BTI_V16QI, ~RS6000_BTI_INTQI,
RS6000_BTI_unsigned_long_long },
@@ -6245,7 +6253,8 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
/* If the second argument is an integer constant, if the value is in
the expected range, generate the built-in code if we can. We need
64-bit and direct move to extract the small integer vectors. */
- if (TREE_CODE (arg2) == INTEGER_CST && wi::ltu_p (arg2, nunits))
+ if (TREE_CODE (arg2) == INTEGER_CST
+ && wi::ltu_p (wi::to_wide (arg2), nunits))
{
switch (mode)
{
@@ -6407,7 +6416,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
mode = TYPE_MODE (arg1_type);
if ((mode == V2DFmode || mode == V2DImode) && VECTOR_UNIT_VSX_P (mode)
&& TREE_CODE (arg2) == INTEGER_CST
- && wi::ltu_p (arg2, 2))
+ && wi::ltu_p (wi::to_wide (arg2), 2))
{
tree call = NULL_TREE;
@@ -6423,7 +6432,7 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
}
else if (mode == V1TImode && VECTOR_UNIT_VSX_P (mode)
&& TREE_CODE (arg2) == INTEGER_CST
- && wi::eq_p (arg2, 0))
+ && wi::eq_p (wi::to_wide (arg2), 0))
{
tree call = rs6000_builtin_decls[VSX_BUILTIN_VEC_SET_V1TI];
@@ -6472,78 +6481,6 @@ altivec_resolve_overloaded_builtin (location_t loc, tree fndecl,
return stmt;
}
- /* Expand vec_st into an expression that masks the address and
- performs the store. We need to expand this early to allow
- the best aliasing, as by the time we get into RTL we no longer
- are able to honor __restrict__, for example. We may want to
- consider this for all memory access built-ins.
-
- When -maltivec=be is specified, or the wrong number of arguments
- is provided, simply punt to existing built-in processing. */
-
- if (fcode == ALTIVEC_BUILTIN_VEC_ST
- && (BYTES_BIG_ENDIAN || !VECTOR_ELT_ORDER_BIG)
- && nargs == 3)
- {
- tree arg0 = (*arglist)[0];
- tree arg1 = (*arglist)[1];
- tree arg2 = (*arglist)[2];
-
- /* Construct the masked address. Let existing error handling take
- over if we don't have a constant offset. */
- arg1 = fold (arg1);
-
- if (TREE_CODE (arg1) == INTEGER_CST)
- {
- if (!ptrofftype_p (TREE_TYPE (arg1)))
- arg1 = build1 (NOP_EXPR, sizetype, arg1);
-
- tree arg2_type = TREE_TYPE (arg2);
- if (TREE_CODE (arg2_type) == ARRAY_TYPE && c_dialect_cxx ())
- {
- /* Force array-to-pointer decay for C++. */
- arg2 = default_conversion (arg2);
- arg2_type = TREE_TYPE (arg2);
- }
-
- /* Find the built-in to make sure a compatible one exists; if not
- we fall back to default handling to get the error message. */
- for (desc = altivec_overloaded_builtins;
- desc->code && desc->code != fcode; desc++)
- continue;
-
- for (; desc->code == fcode; desc++)
- if (rs6000_builtin_type_compatible (TREE_TYPE (arg0), desc->op1)
- && rs6000_builtin_type_compatible (TREE_TYPE (arg1), desc->op2)
- && rs6000_builtin_type_compatible (TREE_TYPE (arg2),
- desc->op3))
- {
- tree addr = fold_build2_loc (loc, POINTER_PLUS_EXPR, arg2_type,
- arg2, arg1);
- tree aligned
- = fold_build2_loc (loc, BIT_AND_EXPR, arg2_type,
- addr, build_int_cst (arg2_type, -16));
-
- tree arg0_type = TREE_TYPE (arg0);
- if (TYPE_MODE (arg0_type) == V2DImode)
- /* Type-based aliasing analysis thinks vector long
- and vector long long are different and will put them
- in distinct alias classes. Force our address type
- to be a may-alias type to avoid this. */
- arg0_type
- = build_pointer_type_for_mode (arg0_type, Pmode,
- true/*can_alias_all*/);
- else
- arg0_type = build_pointer_type (arg0_type);
- aligned = build1 (NOP_EXPR, arg0_type, aligned);
- tree stg = build_indirect_ref (loc, aligned, RO_NULL);
- tree retval = build2 (MODIFY_EXPR, TREE_TYPE (stg), stg,
- convert (TREE_TYPE (stg), arg0));
- return retval;
- }
- }
- }
-
for (n = 0;
!VOID_TYPE_P (TREE_VALUE (fnargs)) && n < nargs;
fnargs = TREE_CHAIN (fnargs), n++)
diff --git a/gcc/config/rs6000/rs6000-p8swap.c b/gcc/config/rs6000/rs6000-p8swap.c
index 7d2c97f..e1324b7 100644
--- a/gcc/config/rs6000/rs6000-p8swap.c
+++ b/gcc/config/rs6000/rs6000-p8swap.c
@@ -335,21 +335,26 @@ const_load_sequence_p (swap_web_entry *insn_entry, rtx insn)
const_rtx tocrel_base;
- /* Find the unique use in the swap and locate its def. If the def
- isn't unique, punt. */
struct df_insn_info *insn_info = DF_INSN_INFO_GET (insn);
df_ref use;
FOR_EACH_INSN_INFO_USE (use, insn_info)
{
struct df_link *def_link = DF_REF_CHAIN (use);
- if (!def_link || def_link->next)
+
+ /* If there is no def or the def is artificial or there are
+ multiple defs, punt. */
+ if (!def_link || !def_link->ref || DF_REF_IS_ARTIFICIAL (def_link->ref)
+ || def_link->next)
return false;
rtx def_insn = DF_REF_INSN (def_link->ref);
unsigned uid2 = INSN_UID (def_insn);
+ /* If this is not a load or is not a swap, return false. */
if (!insn_entry[uid2].is_load || !insn_entry[uid2].is_swap)
return false;
+ /* If the source of the rtl def is not a set from memory, return
+ false. */
rtx body = PATTERN (def_insn);
if (GET_CODE (body) != SET
|| GET_CODE (SET_SRC (body)) != VEC_SELECT
@@ -358,11 +363,17 @@ const_load_sequence_p (swap_web_entry *insn_entry, rtx insn)
rtx mem = XEXP (SET_SRC (body), 0);
rtx base_reg = XEXP (mem, 0);
+ /* If the base address for the memory expression is not
+ represented by a register, punt. */
+ if (!REG_P (base_reg))
+ return false;
df_ref base_use;
insn_info = DF_INSN_INFO_GET (def_insn);
FOR_EACH_INSN_INFO_USE (base_use, insn_info)
{
+ /* If base_use does not represent base_reg, look for another
+ use. */
if (!rtx_equal_p (DF_REF_REG (base_use), base_reg))
continue;
@@ -370,6 +381,14 @@ const_load_sequence_p (swap_web_entry *insn_entry, rtx insn)
if (!base_def_link || base_def_link->next)
return false;
+ /* Constants held on the stack are not "true" constants
+ because their values are not part of the static load
+ image. If this constant's base reference is a stack
+ or frame pointer, it is seen as an artificial
+ reference. */
+ if (DF_REF_IS_ARTIFICIAL (base_def_link->ref))
+ return false;
+
rtx tocrel_insn = DF_REF_INSN (base_def_link->ref);
rtx tocrel_body = PATTERN (tocrel_insn);
rtx base, offset;
@@ -383,8 +402,26 @@ const_load_sequence_p (swap_web_entry *insn_entry, rtx insn)
if (!toc_relative_expr_p (tocrel_expr, false, &tocrel_base, NULL))
return false;
split_const (XVECEXP (tocrel_base, 0, 0), &base, &offset);
+
if (GET_CODE (base) != SYMBOL_REF || !CONSTANT_POOL_ADDRESS_P (base))
return false;
+ else
+ {
+ /* FIXME: The conditions under which
+ ((GET_CODE (const_vector) == SYMBOL_REF) &&
+ !CONSTANT_POOL_ADDRESS_P (const_vector))
+ are not well understood. This code prevents
+ an internal compiler error which will occur in
+ replace_swapped_load_constant () if we were to return
+ true. Some day, we should figure out how to properly
+ handle this condition in
+ replace_swapped_load_constant () and then we can
+ remove this special test. */
+ rtx const_vector = get_pool_constant (base);
+ if (GET_CODE (const_vector) == SYMBOL_REF
+ && !CONSTANT_POOL_ADDRESS_P (const_vector))
+ return false;
+ }
}
}
return true;
@@ -1281,6 +1318,195 @@ replace_swap_with_copy (swap_web_entry *insn_entry, unsigned i)
insn->set_deleted ();
}
+/* Given that swap_insn represents a swap of a load of a constant
+ vector value, replace with a single instruction that loads a
+ swapped variant of the original constant.
+
+ The "natural" representation of a byte array in memory is the same
+ for big endian and little endian.
+
+ unsigned char byte_array[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f };
+
+ However, when loaded into a vector register, the representation
+ depends on endian conventions.
+
+ In big-endian mode, the register holds:
+
+ MSB LSB
+ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f ]
+
+ In little-endian mode, the register holds:
+
+ MSB LSB
+ [ f, e, d, c, b, a, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 ]
+
+ Word arrays require different handling. Consider the word array:
+
+ unsigned int word_array[] =
+ { 0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f };
+
+ The in-memory representation depends on endian configuration. The
+ equivalent array, declared as a byte array, in memory would be:
+
+ unsigned char big_endian_word_array_data[] =
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f }
+
+ unsigned char little_endian_word_array_data[] =
+ { 3, 2, 1, 0, 7, 6, 5, 4, b, a, 9, 8, f, e, d, c }
+
+ In big-endian mode, the register holds:
+
+ MSB LSB
+ [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, a, b, c, d, e, f ]
+
+ In little-endian mode, the register holds:
+
+ MSB LSB
+ [ c, d, e, f, 8, 9, a, b, 4, 5, 6, 7, 0, 1, 2, 3 ]
+
+
+ Similar transformations apply to the vector of half-word and vector
+ of double-word representations.
+
+ For now, don't handle vectors of quad-precision values. Just return.
+ A better solution is to fix the code generator to emit lvx/stvx for
+ those. */
+static void
+replace_swapped_load_constant (swap_web_entry *insn_entry, rtx swap_insn)
+{
+ /* Find the load. */
+ struct df_insn_info *insn_info = DF_INSN_INFO_GET (swap_insn);
+ rtx_insn *load_insn;
+ df_ref use = DF_INSN_INFO_USES (insn_info);
+ struct df_link *def_link = DF_REF_CHAIN (use);
+ gcc_assert (def_link && !def_link->next);
+
+ load_insn = DF_REF_INSN (def_link->ref);
+ gcc_assert (load_insn);
+
+ /* Find the TOC-relative symbol access. */
+ insn_info = DF_INSN_INFO_GET (load_insn);
+ use = DF_INSN_INFO_USES (insn_info);
+
+ def_link = DF_REF_CHAIN (use);
+ gcc_assert (def_link && !def_link->next);
+
+ rtx_insn *tocrel_insn = DF_REF_INSN (def_link->ref);
+ gcc_assert (tocrel_insn);
+
+ /* Find the embedded CONST_VECTOR. We have to call toc_relative_expr_p
+ to set tocrel_base; otherwise it would be unnecessary as we've
+ already established it will return true. */
+ rtx base, offset;
+ rtx tocrel_expr = SET_SRC (PATTERN (tocrel_insn));
+ const_rtx tocrel_base;
+
+ /* There is an extra level of indirection for small/large code models. */
+ if (GET_CODE (tocrel_expr) == MEM)
+ tocrel_expr = XEXP (tocrel_expr, 0);
+
+ if (!toc_relative_expr_p (tocrel_expr, false, &tocrel_base, NULL))
+ gcc_unreachable ();
+
+ split_const (XVECEXP (tocrel_base, 0, 0), &base, &offset);
+ rtx const_vector = get_pool_constant (base);
+
+ /* With the extra indirection, get_pool_constant will produce the
+ real constant from the reg_equal expression, so get the real
+ constant. */
+ if (GET_CODE (const_vector) == SYMBOL_REF)
+ const_vector = get_pool_constant (const_vector);
+ gcc_assert (GET_CODE (const_vector) == CONST_VECTOR);
+
+ rtx new_mem;
+ enum machine_mode mode = GET_MODE (const_vector);
+
+ /* Create an adjusted constant from the original constant. */
+ if (mode == V1TImode)
+ /* Leave this code as is. */
+ return;
+ else if (mode == V16QImode)
+ {
+ rtx vals = gen_rtx_PARALLEL (mode, rtvec_alloc (16));
+ int i;
+
+ for (i = 0; i < 16; i++)
+ XVECEXP (vals, 0, ((i+8) % 16)) = XVECEXP (const_vector, 0, i);
+ rtx new_const_vector = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
+ new_mem = force_const_mem (mode, new_const_vector);
+ }
+ else if ((mode == V8HImode)
+#ifdef HAVE_V8HFmode
+ || (mode == V8HFmode)
+#endif
+ )
+ {
+ rtx vals = gen_rtx_PARALLEL (mode, rtvec_alloc (8));
+ int i;
+
+ for (i = 0; i < 8; i++)
+ XVECEXP (vals, 0, ((i+4) % 8)) = XVECEXP (const_vector, 0, i);
+ rtx new_const_vector = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
+ new_mem = force_const_mem (mode, new_const_vector);
+ }
+ else if ((mode == V4SImode) || (mode == V4SFmode))
+ {
+ rtx vals = gen_rtx_PARALLEL (mode, rtvec_alloc (4));
+ int i;
+
+ for (i = 0; i < 4; i++)
+ XVECEXP (vals, 0, ((i+2) % 4)) = XVECEXP (const_vector, 0, i);
+ rtx new_const_vector = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
+ new_mem = force_const_mem (mode, new_const_vector);
+ }
+ else if ((mode == V2DImode) || (mode == V2DFmode))
+ {
+ rtx vals = gen_rtx_PARALLEL (mode, rtvec_alloc (2));
+ int i;
+
+ for (i = 0; i < 2; i++)
+ XVECEXP (vals, 0, ((i+1) % 2)) = XVECEXP (const_vector, 0, i);
+ rtx new_const_vector = gen_rtx_CONST_VECTOR (mode, XVEC (vals, 0));
+ new_mem = force_const_mem (mode, new_const_vector);
+ }
+ else
+ {
+ /* We do not expect other modes to be constant-load-swapped. */
+ gcc_unreachable ();
+ }
+
+ /* This gives us a MEM whose base operand is a SYMBOL_REF, which we
+ can't recognize. Force the SYMBOL_REF into a register. */
+ if (!REG_P (XEXP (new_mem, 0))) {
+ rtx base_reg = force_reg (Pmode, XEXP (new_mem, 0));
+ XEXP (new_mem, 0) = base_reg;
+
+ /* Move the newly created insn ahead of the load insn. */
+ /* The last insn is the the insn that forced new_mem into a register. */
+ rtx_insn *force_insn = get_last_insn ();
+ /* Remove this insn from the end of the instruction sequence. */
+ remove_insn (force_insn);
+ rtx_insn *before_load_insn = PREV_INSN (load_insn);
+
+ /* And insert this insn back into the sequence before the previous
+ load insn so this new expression will be available when the
+ existing load is modified to load the swapped constant. */
+ add_insn_after (force_insn, before_load_insn, BLOCK_FOR_INSN (load_insn));
+ df_insn_rescan (before_load_insn);
+ df_insn_rescan (force_insn);
+ }
+
+ /* Replace the MEM in the load instruction and rescan it. */
+ XEXP (SET_SRC (PATTERN (load_insn)), 0) = new_mem;
+ INSN_CODE (load_insn) = -1; /* Force re-recognition. */
+ df_insn_rescan (load_insn);
+
+ unsigned int uid = INSN_UID (swap_insn);
+ mark_swaps_for_removal (insn_entry, uid);
+ replace_swap_with_copy (insn_entry, uid);
+}
+
/* Dump the swap table to DUMP_FILE. */
static void
dump_swap_insn_table (swap_web_entry *insn_entry)
@@ -1656,6 +1882,7 @@ rs6000_analyze_swaps (function *fun)
/* Pre-pass to recombine lvx and stvx patterns so we don't lose info. */
recombine_lvx_stvx_patterns (fun);
+ df_process_deferred_rescans ();
/* Allocate structure to represent webs of insns. */
insn_entry = XCNEWVEC (swap_web_entry, get_max_uid ());
@@ -1873,6 +2100,44 @@ rs6000_analyze_swaps (function *fun)
/* Clean up. */
free (insn_entry);
+
+ /* Use additional pass over rtl to replace swap(load(vector constant))
+ with load(swapped vector constant). */
+ swap_web_entry *pass2_insn_entry;
+ pass2_insn_entry = XCNEWVEC (swap_web_entry, get_max_uid ());
+
+ /* Walk the insns to gather basic data. */
+ FOR_ALL_BB_FN (bb, fun)
+ FOR_BB_INSNS_SAFE (bb, insn, curr_insn)
+ {
+ unsigned int uid = INSN_UID (insn);
+ if (NONDEBUG_INSN_P (insn))
+ {
+ pass2_insn_entry[uid].insn = insn;
+
+ pass2_insn_entry[uid].is_relevant = 1;
+ pass2_insn_entry[uid].is_load = insn_is_load_p (insn);
+ pass2_insn_entry[uid].is_store = insn_is_store_p (insn);
+
+ /* Determine if this is a doubleword swap. If not,
+ determine whether it can legally be swapped. */
+ if (insn_is_swap_p (insn))
+ pass2_insn_entry[uid].is_swap = 1;
+ }
+ }
+
+ e = get_max_uid ();
+ for (unsigned i = 0; i < e; ++i)
+ if (pass2_insn_entry[i].is_swap && !pass2_insn_entry[i].is_load
+ && !pass2_insn_entry[i].is_store)
+ {
+ insn = pass2_insn_entry[i].insn;
+ if (const_load_sequence_p (pass2_insn_entry, insn))
+ replace_swapped_load_constant (pass2_insn_entry, insn);
+ }
+
+ /* Clean up. */
+ free (pass2_insn_entry);
return 0;
}
diff --git a/gcc/config/rs6000/rs6000-protos.h b/gcc/config/rs6000/rs6000-protos.h
index 3f86aba..db0e692 100644
--- a/gcc/config/rs6000/rs6000-protos.h
+++ b/gcc/config/rs6000/rs6000-protos.h
@@ -128,7 +128,7 @@ extern void rs6000_emit_sISEL (machine_mode, rtx[]);
extern void rs6000_emit_sCOND (machine_mode, rtx[]);
extern void rs6000_emit_cbranch (machine_mode, rtx[]);
extern char * output_cbranch (rtx, const char *, int, rtx_insn *);
-extern const char * output_probe_stack_range (rtx, rtx);
+extern const char * output_probe_stack_range (rtx, rtx, rtx);
extern void rs6000_emit_dot_insn (rtx dst, rtx src, int dot, rtx ccreg);
extern bool rs6000_emit_set_const (rtx, rtx);
extern int rs6000_emit_cmove (rtx, rtx, rtx, rtx);
@@ -209,7 +209,6 @@ extern void rs6000_emit_epilogue (int);
extern void rs6000_expand_split_stack_prologue (void);
extern void rs6000_split_stack_space_check (rtx, rtx);
extern void rs6000_emit_eh_reg_restore (rtx, rtx);
-extern const char * output_isel (rtx *);
extern void rs6000_call_aix (rtx, rtx, rtx, rtx);
extern void rs6000_sibcall_aix (rtx, rtx, rtx, rtx);
extern void rs6000_aix_asm_output_dwarf_table_ref (char *);
@@ -230,6 +229,7 @@ extern void rs6000_cpu_cpp_builtins (struct cpp_reader *);
#ifdef TREE_CODE
extern bool rs6000_pragma_target_parse (tree, tree);
#endif
+extern void rs6000_activate_target_options (tree new_tree);
extern void rs6000_target_modify_macros (bool, HOST_WIDE_INT, HOST_WIDE_INT);
extern void (*rs6000_target_modify_macros_ptr) (bool, HOST_WIDE_INT,
HOST_WIDE_INT);
diff --git a/gcc/config/rs6000/rs6000-string.c b/gcc/config/rs6000/rs6000-string.c
index 19463c9..8c2a93e 100644
--- a/gcc/config/rs6000/rs6000-string.c
+++ b/gcc/config/rs6000/rs6000-string.c
@@ -674,10 +674,10 @@ expand_strncmp_align_check (rtx strncmp_label, rtx src, HOST_WIDE_INT bytes)
emit_move_insn (cond, gen_rtx_COMPARE (CCmode, src_check,
GEN_INT (4096 - bytes)));
- rtx cmp_rtx = gen_rtx_LT (VOIDmode, cond, const0_rtx);
+ rtx cmp_rtx = gen_rtx_GE (VOIDmode, cond, const0_rtx);
rtx ifelse = gen_rtx_IF_THEN_ELSE (VOIDmode, cmp_rtx,
- pc_rtx, lab_ref);
+ lab_ref, pc_rtx);
rtx j = emit_jump_insn (gen_rtx_SET (pc_rtx, ifelse));
JUMP_LABEL (j) = strncmp_label;
LABEL_NUSES (strncmp_label) += 1;
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 1978634..3095419 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -637,31 +637,10 @@ mode_supports_vsx_dform_quad (machine_mode mode)
}
-/* Target cpu costs. */
-
-struct processor_costs {
- const int mulsi; /* cost of SImode multiplication. */
- const int mulsi_const; /* cost of SImode multiplication by constant. */
- const int mulsi_const9; /* cost of SImode mult by short constant. */
- const int muldi; /* cost of DImode multiplication. */
- const int divsi; /* cost of SImode division. */
- const int divdi; /* cost of DImode division. */
- const int fp; /* cost of simple SFmode and DFmode insns. */
- const int dmul; /* cost of DFmode multiplication (and fmadd). */
- const int sdiv; /* cost of SFmode division (fdivs). */
- const int ddiv; /* cost of DFmode division (fdiv). */
- const int cache_line_size; /* cache line size in bytes. */
- const int l1_cache_size; /* size of l1 cache, in kilobytes. */
- const int l2_cache_size; /* size of l2 cache, in kilobytes. */
- const int simultaneous_prefetches; /* number of parallel prefetch
- operations. */
- const int sfdf_convert; /* cost of SF->DF conversion. */
-};
+/* Processor costs (relative to an add) */
const struct processor_costs *rs6000_cost;
-/* Processor costs (relative to an add) */
-
/* Instruction size costs on 32bit processors. */
static const
struct processor_costs size32_cost = {
@@ -1749,6 +1728,8 @@ static const struct attribute_spec rs6000_attribute_table[] =
#define TARGET_RTX_COSTS rs6000_rtx_costs
#undef TARGET_ADDRESS_COST
#define TARGET_ADDRESS_COST hook_int_rtx_mode_as_bool_0
+#undef TARGET_INSN_COST
+#define TARGET_INSN_COST rs6000_insn_cost
#undef TARGET_INIT_DWARF_REG_SIZES_EXTRA
#define TARGET_INIT_DWARF_REG_SIZES_EXTRA rs6000_init_dwarf_reg_sizes_extra
@@ -1974,6 +1955,12 @@ static const struct attribute_spec rs6000_attribute_table[] =
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS rs6000_can_change_mode_class
+
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT rs6000_constant_alignment
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET rs6000_starting_frame_offset
/* Processor table. */
@@ -3989,14 +3976,10 @@ static bool
rs6000_option_override_internal (bool global_init_p)
{
bool ret = true;
- bool have_cpu = false;
-
- /* The default cpu requested at configure time, if any. */
- const char *implicit_cpu = OPTION_TARGET_CPU_DEFAULT;
HOST_WIDE_INT set_masks;
HOST_WIDE_INT ignore_masks;
- int cpu_index;
+ int cpu_index = -1;
int tune_index;
struct cl_target_option *main_target_opt
= ((global_init_p || target_option_default_node == NULL)
@@ -4075,93 +4058,51 @@ rs6000_option_override_internal (bool global_init_p)
with -mtune on the command line. Process a '--with-cpu' configuration
request as an implicit --cpu. */
if (rs6000_cpu_index >= 0)
- {
- cpu_index = rs6000_cpu_index;
- have_cpu = true;
- }
+ cpu_index = rs6000_cpu_index;
else if (main_target_opt != NULL && main_target_opt->x_rs6000_cpu_index >= 0)
- {
- rs6000_cpu_index = cpu_index = main_target_opt->x_rs6000_cpu_index;
- have_cpu = true;
- }
- else if (implicit_cpu)
- {
- rs6000_cpu_index = cpu_index = rs6000_cpu_name_lookup (implicit_cpu);
- have_cpu = true;
- }
- else
- {
- /* PowerPC 64-bit LE requires at least ISA 2.07. */
- const char *default_cpu = ((!TARGET_POWERPC64)
- ? "powerpc"
- : ((BYTES_BIG_ENDIAN)
- ? "powerpc64"
- : "powerpc64le"));
-
- rs6000_cpu_index = cpu_index = rs6000_cpu_name_lookup (default_cpu);
- have_cpu = false;
- }
-
- gcc_assert (cpu_index >= 0);
+ cpu_index = main_target_opt->x_rs6000_cpu_index;
+ else if (OPTION_TARGET_CPU_DEFAULT)
+ cpu_index = rs6000_cpu_name_lookup (OPTION_TARGET_CPU_DEFAULT);
- if (have_cpu)
+ if (cpu_index >= 0)
{
-#ifndef HAVE_AS_POWER9
- if (processor_target_table[rs6000_cpu_index].processor
- == PROCESSOR_POWER9)
+ const char *unavailable_cpu = NULL;
+ switch (processor_target_table[cpu_index].processor)
{
- have_cpu = false;
- warning (0, "will not generate power9 instructions because "
- "assembler lacks power9 support");
- }
+#ifndef HAVE_AS_POWER9
+ case PROCESSOR_POWER9:
+ unavailable_cpu = "power9";
+ break;
#endif
#ifndef HAVE_AS_POWER8
- if (processor_target_table[rs6000_cpu_index].processor
- == PROCESSOR_POWER8)
- {
- have_cpu = false;
- warning (0, "will not generate power8 instructions because "
- "assembler lacks power8 support");
- }
+ case PROCESSOR_POWER8:
+ unavailable_cpu = "power8";
+ break;
#endif
#ifndef HAVE_AS_POPCNTD
- if (processor_target_table[rs6000_cpu_index].processor
- == PROCESSOR_POWER7)
- {
- have_cpu = false;
- warning (0, "will not generate power7 instructions because "
- "assembler lacks power7 support");
- }
+ case PROCESSOR_POWER7:
+ unavailable_cpu = "power7";
+ break;
#endif
#ifndef HAVE_AS_DFP
- if (processor_target_table[rs6000_cpu_index].processor
- == PROCESSOR_POWER6)
- {
- have_cpu = false;
- warning (0, "will not generate power6 instructions because "
- "assembler lacks power6 support");
- }
+ case PROCESSOR_POWER6:
+ unavailable_cpu = "power6";
+ break;
#endif
#ifndef HAVE_AS_POPCNTB
- if (processor_target_table[rs6000_cpu_index].processor
- == PROCESSOR_POWER5)
- {
- have_cpu = false;
- warning (0, "will not generate power5 instructions because "
- "assembler lacks power5 support");
- }
+ case PROCESSOR_POWER5:
+ unavailable_cpu = "power5";
+ break;
#endif
-
- if (!have_cpu)
+ default:
+ break;
+ }
+ if (unavailable_cpu)
{
- /* PowerPC 64-bit LE requires at least ISA 2.07. */
- const char *default_cpu = (!TARGET_POWERPC64
- ? "powerpc"
- : (BYTES_BIG_ENDIAN
- ? "powerpc64"
- : "powerpc64le"));
-
- rs6000_cpu_index = cpu_index = rs6000_cpu_name_lookup (default_cpu);
+ cpu_index = -1;
+ warning (0, "will not generate %qs instructions because "
+ "assembler lacks %qs support", unavailable_cpu,
+ unavailable_cpu);
}
}
@@ -4170,8 +4111,9 @@ rs6000_option_override_internal (bool global_init_p)
with those from the cpu, except for options that were explicitly set. If
we don't have a cpu, do not override the target bits set in
TARGET_DEFAULT. */
- if (have_cpu)
+ if (cpu_index >= 0)
{
+ rs6000_cpu_index = cpu_index;
rs6000_isa_flags &= ~set_masks;
rs6000_isa_flags |= (processor_target_table[cpu_index].target_enable
& set_masks);
@@ -4185,14 +4127,26 @@ rs6000_option_override_internal (bool global_init_p)
If there is a TARGET_DEFAULT, use that. Otherwise fall back to using
-mcpu=powerpc, -mcpu=powerpc64, or -mcpu=powerpc64le defaults. */
- HOST_WIDE_INT flags = ((TARGET_DEFAULT) ? TARGET_DEFAULT
- : processor_target_table[cpu_index].target_enable);
+ HOST_WIDE_INT flags;
+ if (TARGET_DEFAULT)
+ flags = TARGET_DEFAULT;
+ else
+ {
+ /* PowerPC 64-bit LE requires at least ISA 2.07. */
+ const char *default_cpu = (!TARGET_POWERPC64
+ ? "powerpc"
+ : (BYTES_BIG_ENDIAN
+ ? "powerpc64"
+ : "powerpc64le"));
+ int default_cpu_index = rs6000_cpu_name_lookup (default_cpu);
+ flags = processor_target_table[default_cpu_index].target_enable;
+ }
rs6000_isa_flags |= (flags & ~rs6000_isa_flags_explicit);
}
if (rs6000_tune_index >= 0)
tune_index = rs6000_tune_index;
- else if (have_cpu)
+ else if (cpu_index >= 0)
rs6000_tune_index = tune_index = cpu_index;
else
{
@@ -4204,7 +4158,7 @@ rs6000_option_override_internal (bool global_init_p)
for (i = 0; i < ARRAY_SIZE (processor_target_table); i++)
if (processor_target_table[i].processor == tune_proc)
{
- rs6000_tune_index = tune_index = i;
+ tune_index = i;
break;
}
}
@@ -4331,7 +4285,7 @@ rs6000_option_override_internal (bool global_init_p)
rs6000_isa_flags |= (ISA_3_0_MASKS_SERVER & ~ignore_masks);
else if (TARGET_P9_MINMAX)
{
- if (have_cpu)
+ if (cpu_index >= 0)
{
if (cpu_index == PROCESSOR_POWER9)
{
@@ -4834,7 +4788,7 @@ rs6000_option_override_internal (bool global_init_p)
default:
- if (have_cpu && !(rs6000_isa_flags_explicit & OPTION_MASK_ISEL))
+ if (cpu_index >= 0 && !(rs6000_isa_flags_explicit & OPTION_MASK_ISEL))
rs6000_isa_flags &= ~OPTION_MASK_ISEL;
break;
@@ -5468,9 +5422,7 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return 3;
case unaligned_load:
- if (TARGET_P9_VECTOR)
- return 3;
-
+ case vector_gather_load:
if (TARGET_EFFICIENT_UNALIGNED_VSX)
return 1;
@@ -5509,6 +5461,7 @@ rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return 2;
case unaligned_store:
+ case vector_scatter_store:
if (TARGET_EFFICIENT_UNALIGNED_VSX)
return 1;
@@ -9035,6 +8988,8 @@ rs6000_delegitimize_address (rtx orig_x)
static bool
rs6000_const_not_ok_for_debug_p (rtx x)
{
+ if (GET_CODE (x) == UNSPEC)
+ return true;
if (GET_CODE (x) == SYMBOL_REF
&& CONSTANT_POOL_ADDRESS_P (x))
{
@@ -9081,11 +9036,7 @@ rs6000_legitimate_combined_insn (rtx_insn *insn)
&& (icode == CODE_FOR_ctrsi_internal1
|| icode == CODE_FOR_ctrdi_internal1
|| icode == CODE_FOR_ctrsi_internal2
- || icode == CODE_FOR_ctrdi_internal2
- || icode == CODE_FOR_ctrsi_internal3
- || icode == CODE_FOR_ctrdi_internal3
- || icode == CODE_FOR_ctrsi_internal4
- || icode == CODE_FOR_ctrdi_internal4))
+ || icode == CODE_FOR_ctrdi_internal2))
return false;
return true;
@@ -11013,7 +10964,8 @@ rs6000_aggregate_candidate (const_tree type, machine_mode *modep)
- tree_to_uhwi (TYPE_MIN_VALUE (index)));
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -11043,7 +10995,8 @@ rs6000_aggregate_candidate (const_tree type, machine_mode *modep)
}
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -11075,7 +11028,8 @@ rs6000_aggregate_candidate (const_tree type, machine_mode *modep)
}
/* There must be no padding. */
- if (wi::ne_p (TYPE_SIZE (type), count * GET_MODE_BITSIZE (*modep)))
+ if (wi::to_wide (TYPE_SIZE (type))
+ != count * GET_MODE_BITSIZE (*modep))
return -1;
return count;
@@ -15146,14 +15100,15 @@ rs6000_expand_ternop_builtin (enum insn_code icode, tree exp, rtx target)
/* Check whether the 2nd and 3rd arguments are integer constants and in
range and prepare arguments. */
STRIP_NOPS (arg1);
- if (TREE_CODE (arg1) != INTEGER_CST || wi::geu_p (arg1, 2))
+ if (TREE_CODE (arg1) != INTEGER_CST || wi::geu_p (wi::to_wide (arg1), 2))
{
error ("argument 2 must be 0 or 1");
return CONST0_RTX (tmode);
}
STRIP_NOPS (arg2);
- if (TREE_CODE (arg2) != INTEGER_CST || wi::geu_p (arg2, 16))
+ if (TREE_CODE (arg2) != INTEGER_CST
+ || wi::geu_p (wi::to_wide (arg2), 16))
{
error ("argument 3 must be in the range 0..15");
return CONST0_RTX (tmode);
@@ -15568,6 +15523,9 @@ altivec_expand_builtin (tree exp, rtx target, bool *expandedp)
case P9V_BUILTIN_STXVL:
return altivec_expand_stxvl_builtin (CODE_FOR_stxvl, exp);
+ case P9V_BUILTIN_XST_LEN_R:
+ return altivec_expand_stxvl_builtin (CODE_FOR_xst_len_r, exp);
+
case VSX_BUILTIN_STXVD2X_V1TI:
return altivec_expand_stv_builtin (CODE_FOR_vsx_store_v1ti, exp);
case VSX_BUILTIN_STXVD2X_V2DF:
@@ -16157,6 +16115,25 @@ rs6000_fold_builtin (tree fndecl, int n_args ATTRIBUTE_UNUSED,
#endif
}
+/* Helper function to sort out which built-ins may be valid without having
+ a LHS. */
+static bool
+rs6000_builtin_valid_without_lhs (enum rs6000_builtins fn_code)
+{
+ switch (fn_code)
+ {
+ case ALTIVEC_BUILTIN_STVX_V16QI:
+ case ALTIVEC_BUILTIN_STVX_V8HI:
+ case ALTIVEC_BUILTIN_STVX_V4SI:
+ case ALTIVEC_BUILTIN_STVX_V4SF:
+ case ALTIVEC_BUILTIN_STVX_V2DI:
+ case ALTIVEC_BUILTIN_STVX_V2DF:
+ return true;
+ default:
+ return false;
+ }
+}
+
/* Fold a machine-dependent built-in in GIMPLE. (For folding into
a constant, use rs6000_fold_builtin.) */
@@ -16184,8 +16161,9 @@ rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
if (!rs6000_fold_gimple)
return false;
- /* Generic solution to prevent gimple folding of code without a LHS. */
- if (!gimple_call_lhs (stmt))
+ /* Prevent gimple folding for code that does not have a LHS, unless it is
+ allowed per the rs6000_builtin_valid_without_lhs helper function. */
+ if (!gimple_call_lhs (stmt) && !rs6000_builtin_valid_without_lhs (fn_code))
return false;
switch (fn_code)
@@ -16587,7 +16565,54 @@ rs6000_gimple_fold_builtin (gimple_stmt_iterator *gsi)
gsi_replace (gsi, g, true);
return true;
}
-
+ /* Vector stores. */
+ case ALTIVEC_BUILTIN_STVX_V16QI:
+ case ALTIVEC_BUILTIN_STVX_V8HI:
+ case ALTIVEC_BUILTIN_STVX_V4SI:
+ case ALTIVEC_BUILTIN_STVX_V4SF:
+ case ALTIVEC_BUILTIN_STVX_V2DI:
+ case ALTIVEC_BUILTIN_STVX_V2DF:
+ {
+ /* Do not fold for -maltivec=be on LE targets. */
+ if (VECTOR_ELT_ORDER_BIG && !BYTES_BIG_ENDIAN)
+ return false;
+ arg0 = gimple_call_arg (stmt, 0); /* Value to be stored. */
+ arg1 = gimple_call_arg (stmt, 1); /* Offset. */
+ tree arg2 = gimple_call_arg (stmt, 2); /* Store-to address. */
+ location_t loc = gimple_location (stmt);
+ tree arg0_type = TREE_TYPE (arg0);
+ /* Use ptr_type_node (no TBAA) for the arg2_type.
+ FIXME: (Richard) "A proper fix would be to transition this type as
+ seen from the frontend to GIMPLE, for example in a similar way we
+ do for MEM_REFs by piggy-backing that on an extra argument, a
+ constant zero pointer of the alias pointer type to use (which would
+ also serve as a type indicator of the store itself). I'd use a
+ target specific internal function for this (not sure if we can have
+ those target specific, but I guess if it's folded away then that's
+ fine) and get away with the overload set."
+ */
+ tree arg2_type = ptr_type_node;
+ /* POINTER_PLUS_EXPR wants the offset to be of type 'sizetype'. Create
+ the tree using the value from arg0. The resulting type will match
+ the type of arg2. */
+ gimple_seq stmts = NULL;
+ tree temp_offset = gimple_convert (&stmts, loc, sizetype, arg1);
+ tree temp_addr = gimple_build (&stmts, loc, POINTER_PLUS_EXPR,
+ arg2_type, arg2, temp_offset);
+ /* Mask off any lower bits from the address. */
+ tree aligned_addr = gimple_build (&stmts, loc, BIT_AND_EXPR,
+ arg2_type, temp_addr,
+ build_int_cst (arg2_type, -16));
+ gsi_insert_seq_before (gsi, stmts, GSI_SAME_STMT);
+ /* The desired gimple result should be similar to:
+ MEM[(__vector floatD.1407 *)_1] = vf1D.2697; */
+ gimple *g;
+ g = gimple_build_assign (build2 (MEM_REF, arg0_type, aligned_addr,
+ build_int_cst (arg2_type, 0)), arg0);
+ gimple_set_location (g, loc);
+ gsi_replace (gsi, g, true);
+ return true;
+ }
default:
if (TARGET_DEBUG_BUILTIN)
fprintf (stderr, "gimple builtin intrinsic not matched:%d %s %s\n",
@@ -17559,8 +17584,12 @@ altivec_init_builtins (void)
def_builtin ("__builtin_vec_stvrxl", void_ftype_v16qi_long_pvoid, ALTIVEC_BUILTIN_VEC_STVRXL);
if (TARGET_P9_VECTOR)
- def_builtin ("__builtin_altivec_stxvl", void_ftype_v16qi_pvoid_long,
- P9V_BUILTIN_STXVL);
+ {
+ def_builtin ("__builtin_altivec_stxvl", void_ftype_v16qi_pvoid_long,
+ P9V_BUILTIN_STXVL);
+ def_builtin ("__builtin_xst_len_r", void_ftype_v16qi_pvoid_long,
+ P9V_BUILTIN_XST_LEN_R);
+ }
/* Add the DST variants. */
d = bdesc_dst;
@@ -23230,24 +23259,6 @@ rs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond)
return 1;
}
-const char *
-output_isel (rtx *operands)
-{
- enum rtx_code code;
-
- code = GET_CODE (operands[1]);
-
- if (code == GE || code == GEU || code == LE || code == LEU || code == NE)
- {
- gcc_assert (GET_CODE (operands[2]) == REG
- && GET_CODE (operands[3]) == REG);
- PUT_CODE (operands[1], reverse_condition (code));
- return "isel %0,%3,%2,%j1";
- }
-
- return "isel %0,%2,%3,%j1";
-}
-
void
rs6000_emit_minmax (rtx dest, enum rtx_code code, rtx op0, rtx op1)
{
@@ -25458,6 +25469,221 @@ rs6000_emit_stack_tie (rtx fp, bool hard_frame_needed)
emit_insn (gen_stack_tie (gen_rtx_PARALLEL (VOIDmode, p)));
}
+/* Allocate SIZE_INT bytes on the stack using a store with update style insn
+ and set the appropriate attributes for the generated insn. Return the
+ first insn which adjusts the stack pointer or the last insn before
+ the stack adjustment loop.
+
+ SIZE_INT is used to create the CFI note for the allocation.
+
+ SIZE_RTX is an rtx containing the size of the adjustment. Note that
+ since stacks grow to lower addresses its runtime value is -SIZE_INT.
+
+ ORIG_SP contains the backchain value that must be stored at *sp. */
+
+static rtx_insn *
+rs6000_emit_allocate_stack_1 (HOST_WIDE_INT size_int, rtx orig_sp)
+{
+ rtx_insn *insn;
+
+ rtx size_rtx = GEN_INT (-size_int);
+ if (size_int > 32767)
+ {
+ rtx tmp_reg = gen_rtx_REG (Pmode, 0);
+ /* Need a note here so that try_split doesn't get confused. */
+ if (get_last_insn () == NULL_RTX)
+ emit_note (NOTE_INSN_DELETED);
+ insn = emit_move_insn (tmp_reg, size_rtx);
+ try_split (PATTERN (insn), insn, 0);
+ size_rtx = tmp_reg;
+ }
+
+ if (Pmode == SImode)
+ insn = emit_insn (gen_movsi_update_stack (stack_pointer_rtx,
+ stack_pointer_rtx,
+ size_rtx,
+ orig_sp));
+ else
+ insn = emit_insn (gen_movdi_di_update_stack (stack_pointer_rtx,
+ stack_pointer_rtx,
+ size_rtx,
+ orig_sp));
+ rtx par = PATTERN (insn);
+ gcc_assert (GET_CODE (par) == PARALLEL);
+ rtx set = XVECEXP (par, 0, 0);
+ gcc_assert (GET_CODE (set) == SET);
+ rtx mem = SET_DEST (set);
+ gcc_assert (MEM_P (mem));
+ MEM_NOTRAP_P (mem) = 1;
+ set_mem_alias_set (mem, get_frame_alias_set ());
+
+ RTX_FRAME_RELATED_P (insn) = 1;
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (stack_pointer_rtx,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT (-size_int))));
+
+ /* Emit a blockage to ensure the allocation/probing insns are
+ not optimized, combined, removed, etc. Add REG_STACK_CHECK
+ note for similar reasons. */
+ if (flag_stack_clash_protection)
+ {
+ add_reg_note (insn, REG_STACK_CHECK, const0_rtx);
+ emit_insn (gen_blockage ());
+ }
+
+ return insn;
+}
+
+static HOST_WIDE_INT
+get_stack_clash_protection_probe_interval (void)
+{
+ return (HOST_WIDE_INT_1U
+ << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL));
+}
+
+static HOST_WIDE_INT
+get_stack_clash_protection_guard_size (void)
+{
+ return (HOST_WIDE_INT_1U
+ << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE));
+}
+
+/* Allocate ORIG_SIZE bytes on the stack and probe the newly
+ allocated space every STACK_CLASH_PROTECTION_PROBE_INTERVAL bytes.
+
+ COPY_REG, if non-null, should contain a copy of the original
+ stack pointer at exit from this function.
+
+ This is subtly different than the Ada probing in that it tries hard to
+ prevent attacks that jump the stack guard. Thus it is never allowed to
+ allocate more than STACK_CLASH_PROTECTION_PROBE_INTERVAL bytes of stack
+ space without a suitable probe. */
+static rtx_insn *
+rs6000_emit_probe_stack_range_stack_clash (HOST_WIDE_INT orig_size,
+ rtx copy_reg)
+{
+ rtx orig_sp = copy_reg;
+
+ HOST_WIDE_INT probe_interval = get_stack_clash_protection_probe_interval ();
+
+ /* Round the size down to a multiple of PROBE_INTERVAL. */
+ HOST_WIDE_INT rounded_size = ROUND_DOWN (orig_size, probe_interval);
+
+ /* If explicitly requested,
+ or the rounded size is not the same as the original size
+ or the the rounded size is greater than a page,
+ then we will need a copy of the original stack pointer. */
+ if (rounded_size != orig_size
+ || rounded_size > probe_interval
+ || copy_reg)
+ {
+ /* If the caller did not request a copy of the incoming stack
+ pointer, then we use r0 to hold the copy. */
+ if (!copy_reg)
+ orig_sp = gen_rtx_REG (Pmode, 0);
+ emit_move_insn (orig_sp, stack_pointer_rtx);
+ }
+
+ /* There's three cases here.
+
+ One is a single probe which is the most common and most efficiently
+ implemented as it does not have to have a copy of the original
+ stack pointer if there are no residuals.
+
+ Second is unrolled allocation/probes which we use if there's just
+ a few of them. It needs to save the original stack pointer into a
+ temporary for use as a source register in the allocation/probe.
+
+ Last is a loop. This is the most uncommon case and least efficient. */
+ rtx_insn *retval = NULL;
+ if (rounded_size == probe_interval)
+ {
+ retval = rs6000_emit_allocate_stack_1 (probe_interval, stack_pointer_rtx);
+
+ dump_stack_clash_frame_info (PROBE_INLINE, rounded_size != orig_size);
+ }
+ else if (rounded_size <= 8 * probe_interval)
+ {
+ /* The ABI requires using the store with update insns to allocate
+ space and store the backchain into the stack
+
+ So we save the current stack pointer into a temporary, then
+ emit the store-with-update insns to store the saved stack pointer
+ into the right location in each new page. */
+ for (int i = 0; i < rounded_size; i += probe_interval)
+ {
+ rtx_insn *insn
+ = rs6000_emit_allocate_stack_1 (probe_interval, orig_sp);
+
+ /* Save the first stack adjustment in RETVAL. */
+ if (i == 0)
+ retval = insn;
+ }
+
+ dump_stack_clash_frame_info (PROBE_INLINE, rounded_size != orig_size);
+ }
+ else
+ {
+ /* Compute the ending address. */
+ rtx end_addr
+ = copy_reg ? gen_rtx_REG (Pmode, 0) : gen_rtx_REG (Pmode, 12);
+ rtx rs = GEN_INT (-rounded_size);
+ rtx_insn *insn;
+ if (add_operand (rs, Pmode))
+ insn = emit_insn (gen_add3_insn (end_addr, stack_pointer_rtx, rs));
+ else
+ {
+ emit_move_insn (end_addr, GEN_INT (-rounded_size));
+ insn = emit_insn (gen_add3_insn (end_addr, end_addr,
+ stack_pointer_rtx));
+ /* Describe the effect of INSN to the CFI engine. */
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (end_addr,
+ gen_rtx_PLUS (Pmode, stack_pointer_rtx,
+ rs)));
+ }
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ /* Emit the loop. */
+ if (TARGET_64BIT)
+ retval = emit_insn (gen_probe_stack_rangedi (stack_pointer_rtx,
+ stack_pointer_rtx, orig_sp,
+ end_addr));
+ else
+ retval = emit_insn (gen_probe_stack_rangesi (stack_pointer_rtx,
+ stack_pointer_rtx, orig_sp,
+ end_addr));
+ RTX_FRAME_RELATED_P (retval) = 1;
+ /* Describe the effect of INSN to the CFI engine. */
+ add_reg_note (retval, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (stack_pointer_rtx, end_addr));
+
+ /* Emit a blockage to ensure the allocation/probing insns are
+ not optimized, combined, removed, etc. Other cases handle this
+ within their call to rs6000_emit_allocate_stack_1. */
+ emit_insn (gen_blockage ());
+
+ dump_stack_clash_frame_info (PROBE_LOOP, rounded_size != orig_size);
+ }
+
+ if (orig_size != rounded_size)
+ {
+ /* Allocate (and implicitly probe) any residual space. */
+ HOST_WIDE_INT residual = orig_size - rounded_size;
+
+ rtx_insn *insn = rs6000_emit_allocate_stack_1 (residual, orig_sp);
+
+ /* If the residual was the only allocation, then we can return the
+ allocating insn. */
+ if (!retval)
+ retval = insn;
+ }
+
+ return retval;
+}
+
/* Emit the correct code for allocating stack space, as insns.
If COPY_REG, make sure a copy of the old frame is left there.
The generated code may use hard register 0 as a temporary. */
@@ -25469,7 +25695,6 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, rtx copy_reg, int copy_off)
rtx stack_reg = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
rtx tmp_reg = gen_rtx_REG (Pmode, 0);
rtx todec = gen_int_mode (-size, Pmode);
- rtx par, set, mem;
if (INTVAL (todec) != -size)
{
@@ -25509,6 +25734,23 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, rtx copy_reg, int copy_off)
warning (0, "stack limit expression is not supported");
}
+ if (flag_stack_clash_protection)
+ {
+ if (size < get_stack_clash_protection_guard_size ())
+ dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME, true);
+ else
+ {
+ rtx_insn *insn = rs6000_emit_probe_stack_range_stack_clash (size,
+ copy_reg);
+
+ /* If we asked for a copy with an offset, then we still need add in
+ the offset. */
+ if (copy_reg && copy_off)
+ emit_insn (gen_add3_insn (copy_reg, copy_reg, GEN_INT (copy_off)));
+ return insn;
+ }
+ }
+
if (copy_reg)
{
if (copy_off != 0)
@@ -25517,38 +25759,11 @@ rs6000_emit_allocate_stack (HOST_WIDE_INT size, rtx copy_reg, int copy_off)
emit_move_insn (copy_reg, stack_reg);
}
- if (size > 32767)
- {
- /* Need a note here so that try_split doesn't get confused. */
- if (get_last_insn () == NULL_RTX)
- emit_note (NOTE_INSN_DELETED);
- insn = emit_move_insn (tmp_reg, todec);
- try_split (PATTERN (insn), insn, 0);
- todec = tmp_reg;
- }
-
- insn = emit_insn (TARGET_32BIT
- ? gen_movsi_update_stack (stack_reg, stack_reg,
- todec, stack_reg)
- : gen_movdi_di_update_stack (stack_reg, stack_reg,
- todec, stack_reg));
/* Since we didn't use gen_frame_mem to generate the MEM, grab
it now and set the alias set/attributes. The above gen_*_update
calls will generate a PARALLEL with the MEM set being the first
operation. */
- par = PATTERN (insn);
- gcc_assert (GET_CODE (par) == PARALLEL);
- set = XVECEXP (par, 0, 0);
- gcc_assert (GET_CODE (set) == SET);
- mem = SET_DEST (set);
- gcc_assert (MEM_P (mem));
- MEM_NOTRAP_P (mem) = 1;
- set_mem_alias_set (mem, get_frame_alias_set ());
-
- RTX_FRAME_RELATED_P (insn) = 1;
- add_reg_note (insn, REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (stack_reg, gen_rtx_PLUS (Pmode, stack_reg,
- GEN_INT (-size))));
+ insn = rs6000_emit_allocate_stack_1 (size, stack_reg);
return insn;
}
@@ -25630,9 +25845,9 @@ rs6000_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
until it is equal to ROUNDED_SIZE. */
if (TARGET_64BIT)
- emit_insn (gen_probe_stack_rangedi (r12, r12, r0));
+ emit_insn (gen_probe_stack_rangedi (r12, r12, stack_pointer_rtx, r0));
else
- emit_insn (gen_probe_stack_rangesi (r12, r12, r0));
+ emit_insn (gen_probe_stack_rangesi (r12, r12, stack_pointer_rtx, r0));
/* Step 4: probe at FIRST + SIZE if we cannot assert at compile-time
@@ -25644,10 +25859,10 @@ rs6000_emit_probe_stack_range (HOST_WIDE_INT first, HOST_WIDE_INT size)
}
/* Probe a range of stack addresses from REG1 to REG2 inclusive. These are
- absolute addresses. */
+ addresses, not offsets. */
-const char *
-output_probe_stack_range (rtx reg1, rtx reg2)
+static const char *
+output_probe_stack_range_1 (rtx reg1, rtx reg2)
{
static int labelno = 0;
char loop_lab[32];
@@ -25714,6 +25929,63 @@ interesting_frame_related_regno (unsigned int regno)
return save_reg_p (regno);
}
+/* Probe a range of stack addresses from REG1 to REG3 inclusive. These are
+ addresses, not offsets.
+
+ REG2 contains the backchain that must be stored into *sp at each allocation.
+
+ This is subtly different than the Ada probing above in that it tries hard
+ to prevent attacks that jump the stack guard. Thus, it is never allowed
+ to allocate more than PROBE_INTERVAL bytes of stack space without a
+ suitable probe. */
+
+static const char *
+output_probe_stack_range_stack_clash (rtx reg1, rtx reg2, rtx reg3)
+{
+ static int labelno = 0;
+ char loop_lab[32];
+ rtx xops[3];
+
+ HOST_WIDE_INT probe_interval = get_stack_clash_protection_probe_interval ();
+
+ ASM_GENERATE_INTERNAL_LABEL (loop_lab, "LPSRL", labelno++);
+
+ ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, loop_lab);
+
+ /* This allocates and probes. */
+ xops[0] = reg1;
+ xops[1] = reg2;
+ xops[2] = GEN_INT (-probe_interval);
+ if (TARGET_64BIT)
+ output_asm_insn ("stdu %1,%2(%0)", xops);
+ else
+ output_asm_insn ("stwu %1,%2(%0)", xops);
+
+ /* Jump to LOOP_LAB if TEST_ADDR != LAST_ADDR. */
+ xops[0] = reg1;
+ xops[1] = reg3;
+ if (TARGET_64BIT)
+ output_asm_insn ("cmpd 0,%0,%1", xops);
+ else
+ output_asm_insn ("cmpw 0,%0,%1", xops);
+
+ fputs ("\tbne 0,", asm_out_file);
+ assemble_name_raw (asm_out_file, loop_lab);
+ fputc ('\n', asm_out_file);
+
+ return "";
+}
+
+/* Wrapper around the output_probe_stack_range routines. */
+const char *
+output_probe_stack_range (rtx reg1, rtx reg2, rtx reg3)
+{
+ if (flag_stack_clash_protection)
+ return output_probe_stack_range_stack_clash (reg1, reg2, reg3);
+ else
+ return output_probe_stack_range_1 (reg1, reg3);
+}
+
/* Add to 'insn' a note which is PATTERN (INSN) but with REG replaced
with (plus:P (reg 1) VAL), and with REG2 replaced with REPL2 if REG2
is not NULL. It would be nice if dwarf2out_frame_debug_expr could
@@ -26765,12 +27037,12 @@ rs6000_emit_prologue (void)
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
- rs6000_emit_probe_stack_range (STACK_CHECK_PROTECT,
- size - STACK_CHECK_PROTECT);
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+ rs6000_emit_probe_stack_range (get_stack_check_protect (),
+ size - get_stack_check_protect ());
}
else if (size > 0)
- rs6000_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
+ rs6000_emit_probe_stack_range (get_stack_check_protect (), size);
}
if (TARGET_FIX_AND_CONTINUE)
@@ -27327,6 +27599,13 @@ rs6000_emit_prologue (void)
}
}
+ /* If we are emitting stack probes, but allocate no stack, then
+ just note that in the dump file. */
+ if (flag_stack_clash_protection
+ && dump_file
+ && !info->push_p)
+ dump_stack_clash_frame_info (NO_PROBE_NO_FRAME, false);
+
/* Update stack and set back pointer unless this is V.4,
for which it was done previously. */
if (!WORLD_SAVE_P (info) && info->push_p
@@ -34100,7 +34379,8 @@ rs6000_xcoff_asm_output_aligned_decl_common (FILE *stream,
size, align2);
#ifdef HAVE_GAS_HIDDEN
- fputs (rs6000_xcoff_visibility (decl), stream);
+ if (decl != NULL)
+ fputs (rs6000_xcoff_visibility (decl), stream);
#endif
putc ('\n', stream);
}
@@ -34645,6 +34925,88 @@ rs6000_debug_rtx_costs (rtx x, machine_mode mode, int outer_code,
return ret;
}
+static int
+rs6000_insn_cost (rtx_insn *insn, bool speed)
+{
+ if (recog_memoized (insn) < 0)
+ return 0;
+
+ if (!speed)
+ return get_attr_length (insn);
+
+ int cost = get_attr_cost (insn);
+ if (cost > 0)
+ return cost;
+
+ int n = get_attr_length (insn) / 4;
+ enum attr_type type = get_attr_type (insn);
+
+ switch (type)
+ {
+ case TYPE_LOAD:
+ case TYPE_FPLOAD:
+ case TYPE_VECLOAD:
+ cost = COSTS_N_INSNS (n + 1);
+ break;
+
+ case TYPE_MUL:
+ switch (get_attr_size (insn))
+ {
+ case SIZE_8:
+ cost = COSTS_N_INSNS (n - 1) + rs6000_cost->mulsi_const9;
+ break;
+ case SIZE_16:
+ cost = COSTS_N_INSNS (n - 1) + rs6000_cost->mulsi_const;
+ break;
+ case SIZE_32:
+ cost = COSTS_N_INSNS (n - 1) + rs6000_cost->mulsi;
+ break;
+ case SIZE_64:
+ cost = COSTS_N_INSNS (n - 1) + rs6000_cost->muldi;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ case TYPE_DIV:
+ switch (get_attr_size (insn))
+ {
+ case SIZE_32:
+ cost = COSTS_N_INSNS (n - 1) + rs6000_cost->divsi;
+ break;
+ case SIZE_64:
+ cost = COSTS_N_INSNS (n - 1) + rs6000_cost->divdi;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case TYPE_FP:
+ cost = n * rs6000_cost->fp;
+ break;
+ case TYPE_DMUL:
+ cost = n * rs6000_cost->dmul;
+ break;
+ case TYPE_SDIV:
+ cost = n * rs6000_cost->sdiv;
+ break;
+ case TYPE_DDIV:
+ cost = n * rs6000_cost->ddiv;
+ break;
+
+ case TYPE_SYNC:
+ case TYPE_LOAD_L:
+ cost = COSTS_N_INSNS (n + 2);
+ break;
+
+ default:
+ cost = COSTS_N_INSNS (n);
+ }
+
+ return cost;
+}
+
/* Debug form of ADDRESS_COST that is selected if -mdebug=cost. */
static int
@@ -35594,8 +35956,7 @@ rs6000_expand_vec_perm_const (rtx operands[4])
/* Test whether a constant permutation is supported. */
static bool
-rs6000_vectorize_vec_perm_const_ok (machine_mode vmode,
- const unsigned char *sel)
+rs6000_vectorize_vec_perm_const_ok (machine_mode vmode, vec_perm_indices sel)
{
/* AltiVec (and thus VSX) can handle arbitrary permutations. */
if (TARGET_ALTIVEC)
@@ -36530,9 +36891,9 @@ rs6000_valid_attribute_p (tree fndecl,
{
struct cl_target_option cur_target;
bool ret;
- tree old_optimize = build_optimization_node (&global_options);
+ tree old_optimize;
tree new_target, new_optimize;
- tree func_optimize = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (fndecl);
+ tree func_optimize;
gcc_assert ((fndecl != NULL_TREE) && (args != NULL_TREE));
@@ -36667,6 +37028,7 @@ rs6000_pragma_target_parse (tree args, tree pop_target)
}
target_option_current_node = cur_tree;
+ rs6000_activate_target_options (target_option_current_node);
/* If we have the preprocessor linked in (i.e. C or C++ languages), possibly
change the macros that are defined. */
@@ -36707,7 +37069,7 @@ static GTY(()) tree rs6000_previous_fndecl;
/* Restore target's globals from NEW_TREE and invalidate the
rs6000_previous_fndecl cache. */
-static void
+void
rs6000_activate_target_options (tree new_tree)
{
cl_target_option_restore (&global_options, TREE_TARGET_OPTION (new_tree));
@@ -39129,6 +39491,27 @@ rs6000_optab_supported_p (int op, machine_mode mode1, machine_mode,
return true;
}
}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+rs6000_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST
+ && (STRICT_ALIGNMENT || !optimize_size))
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
+
+static HOST_WIDE_INT
+rs6000_starting_frame_offset (void)
+{
+ if (FRAME_GROWS_DOWNWARD)
+ return 0;
+ return RS6000_STARTING_FRAME_OFFSET;
+}
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h
index da2f4f5..1981104 100644
--- a/gcc/config/rs6000/rs6000.h
+++ b/gcc/config/rs6000/rs6000.h
@@ -565,8 +565,6 @@ extern int rs6000_vector_align[];
#define TARGET_ALTIVEC_ABI rs6000_altivec_abi
#define TARGET_LDBRX (TARGET_POPCNTD || rs6000_cpu == PROCESSOR_CELL)
-#define TARGET_ISEL64 (TARGET_ISEL && TARGET_POWERPC64)
-
/* ISA 2.01 allowed FCFID to be done in 32-bit, previously it was 64-bit only.
Enable 32-bit fcfid's on any of the switches for newer ISA machines or
XILINX. */
@@ -950,14 +948,6 @@ enum data_align { align_abi, align_opt, align_both };
#define LOCAL_ALIGNMENT(TYPE, ALIGN) \
rs6000_data_alignment (TYPE, ALIGN, align_both)
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (STRICT_ALIGNMENT || !optimize_size) \
- && (ALIGN) < BITS_PER_WORD \
- ? BITS_PER_WORD \
- : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
rs6000_data_alignment (TYPE, ALIGN, align_opt)
@@ -1560,15 +1550,13 @@ extern enum reg_class rs6000_constraints[RS6000_CONSTRAINT_MAX];
sizes of the fixed area and the parameter area must be a multiple of
STACK_BOUNDARY. */
-#define STARTING_FRAME_OFFSET \
- (FRAME_GROWS_DOWNWARD \
- ? 0 \
- : (cfun->calls_alloca \
- ? (RS6000_ALIGN (crtl->outgoing_args_size + RS6000_SAVE_AREA, \
- (TARGET_ALTIVEC || TARGET_VSX) ? 16 : 8 )) \
- : (RS6000_ALIGN (crtl->outgoing_args_size, \
- (TARGET_ALTIVEC || TARGET_VSX) ? 16 : 8) \
- + RS6000_SAVE_AREA)))
+#define RS6000_STARTING_FRAME_OFFSET \
+ (cfun->calls_alloca \
+ ? (RS6000_ALIGN (crtl->outgoing_args_size + RS6000_SAVE_AREA, \
+ (TARGET_ALTIVEC || TARGET_VSX) ? 16 : 8 )) \
+ : (RS6000_ALIGN (crtl->outgoing_args_size, \
+ (TARGET_ALTIVEC || TARGET_VSX) ? 16 : 8) \
+ + RS6000_SAVE_AREA))
/* Offset from the stack pointer register to an item dynamically
allocated on the stack, e.g., by `alloca'.
@@ -2073,6 +2061,29 @@ extern scalar_int_mode rs6000_pmode;
#define REVERSE_CONDITION(CODE, MODE) rs6000_reverse_condition (MODE, CODE)
+/* Target cpu costs. */
+
+struct processor_costs {
+ const int mulsi; /* cost of SImode multiplication. */
+ const int mulsi_const; /* cost of SImode multiplication by constant. */
+ const int mulsi_const9; /* cost of SImode mult by short constant. */
+ const int muldi; /* cost of DImode multiplication. */
+ const int divsi; /* cost of SImode division. */
+ const int divdi; /* cost of DImode division. */
+ const int fp; /* cost of simple SFmode and DFmode insns. */
+ const int dmul; /* cost of DFmode multiplication (and fmadd). */
+ const int sdiv; /* cost of SFmode division (fdivs). */
+ const int ddiv; /* cost of DFmode division (fdiv). */
+ const int cache_line_size; /* cache line size in bytes. */
+ const int l1_cache_size; /* size of l1 cache, in kilobytes. */
+ const int l2_cache_size; /* size of l2 cache, in kilobytes. */
+ const int simultaneous_prefetches; /* number of parallel prefetch
+ operations. */
+ const int sfdf_convert; /* cost of SF->DF conversion. */
+};
+
+extern const struct processor_costs *rs6000_cost;
+
/* Control the assembler format that we output. */
/* A C string constant describing how to begin a comment in the target
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 7f17628..62bd19b 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -140,7 +140,13 @@
UNSPEC_STACK_CHECK
UNSPEC_FUSION_P9
UNSPEC_FUSION_ADDIS
- UNSPEC_ROUND_TO_ODD
+ UNSPEC_ADD_ROUND_TO_ODD
+ UNSPEC_SUB_ROUND_TO_ODD
+ UNSPEC_MUL_ROUND_TO_ODD
+ UNSPEC_DIV_ROUND_TO_ODD
+ UNSPEC_FMA_ROUND_TO_ODD
+ UNSPEC_SQRT_ROUND_TO_ODD
+ UNSPEC_TRUNC_ROUND_TO_ODD
UNSPEC_SIGNBIT
UNSPEC_SF_FROM_SI
UNSPEC_SI_FROM_SF
@@ -187,6 +193,10 @@
;; This is used for insert, mul and others as necessary.
(define_attr "size" "8,16,32,64,128" (const_string "32"))
+;; What is the insn_cost for this insn? The target hook can still override
+;; this. For optimizing for size the "length" attribute is used instead.
+(define_attr "cost" "" (const_int 0))
+
;; Is this instruction record form ("dot", signed compare to 0, writing CR0)?
;; This is used for add, logical, shift, exts, mul.
(define_attr "dot" "no,yes" (const_string "no"))
@@ -568,9 +578,6 @@
; DImode bits
(define_mode_attr dbits [(QI "56") (HI "48") (SI "32")])
-;; ISEL/ISEL64 target selection
-(define_mode_attr sel [(SI "") (DI "64")])
-
;; Bitmask for shift instructions
(define_mode_attr hH [(SI "h") (DI "H")])
@@ -986,8 +993,11 @@
(define_insn "extendsi<mode>2"
- [(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r,r,wl,wu,wj,wK,wH")
- (sign_extend:EXTSI (match_operand:SI 1 "lwa_operand" "Y,r,Z,Z,r,wK,wH")))]
+ [(set (match_operand:EXTSI 0 "gpc_reg_operand"
+ "=r, r, wl, wu, wj, wK, wH, wr")
+
+ (sign_extend:EXTSI (match_operand:SI 1 "lwa_operand"
+ "Y, r, Z, Z, r, wK, wH, ?wIwH")))]
""
"@
lwa%U1%X1 %0,%1
@@ -996,10 +1006,23 @@
lxsiwax %x0,%y1
mtvsrwa %x0,%1
vextsw2d %0,%1
+ #
#"
- [(set_attr "type" "load,exts,fpload,fpload,mffgpr,vecexts,vecperm")
+ [(set_attr "type" "load,exts,fpload,fpload,mffgpr,vecexts,vecperm,mftgpr")
(set_attr "sign_extend" "yes")
- (set_attr "length" "4,4,4,4,4,4,8")])
+ (set_attr "length" "4,4,4,4,4,4,8,8")])
+
+(define_split
+ [(set (match_operand:EXTSI 0 "int_reg_operand")
+ (sign_extend:EXTSI (match_operand:SI 1 "vsx_register_operand")))]
+ "TARGET_DIRECT_MOVE_64BIT && reload_completed"
+ [(set (match_dup 2)
+ (match_dup 1))
+ (set (match_dup 0)
+ (sign_extend:DI (match_dup 2)))]
+{
+ operands[2] = gen_rtx_REG (SImode, reg_or_subregno (operands[0]));
+})
(define_split
[(set (match_operand:DI 0 "altivec_register_operand")
@@ -4889,7 +4912,7 @@
(if_then_else:GPR (match_operand 1 "comparison_operator" "")
(match_operand:GPR 2 "gpc_reg_operand" "")
(match_operand:GPR 3 "gpc_reg_operand" "")))]
- "TARGET_ISEL<sel>"
+ "TARGET_ISEL"
"
{
if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3]))
@@ -4912,13 +4935,11 @@
(match_operator 1 "scc_comparison_operator"
[(match_operand:CC 4 "cc_reg_operand" "y,y")
(const_int 0)])
- (match_operand:GPR 2 "reg_or_cint_operand" "O,b")
+ (match_operand:GPR 2 "reg_or_zero_operand" "O,b")
(match_operand:GPR 3 "gpc_reg_operand" "r,r")))]
- "TARGET_ISEL<sel>"
- "*
-{ return output_isel (operands); }"
- [(set_attr "type" "isel")
- (set_attr "length" "4")])
+ "TARGET_ISEL"
+ "isel %0,%2,%3,%j1"
+ [(set_attr "type" "isel")])
(define_insn "isel_unsigned_<mode>"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
@@ -4926,45 +4947,45 @@
(match_operator 1 "scc_comparison_operator"
[(match_operand:CCUNS 4 "cc_reg_operand" "y,y")
(const_int 0)])
- (match_operand:GPR 2 "reg_or_cint_operand" "O,b")
+ (match_operand:GPR 2 "reg_or_zero_operand" "O,b")
(match_operand:GPR 3 "gpc_reg_operand" "r,r")))]
- "TARGET_ISEL<sel>"
- "*
-{ return output_isel (operands); }"
- [(set_attr "type" "isel")
- (set_attr "length" "4")])
+ "TARGET_ISEL"
+ "isel %0,%2,%3,%j1"
+ [(set_attr "type" "isel")])
;; These patterns can be useful for combine; they let combine know that
;; isel can handle reversed comparisons so long as the operands are
;; registers.
(define_insn "*isel_reversed_signed_<mode>"
- [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+ [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(if_then_else:GPR
(match_operator 1 "scc_rev_comparison_operator"
- [(match_operand:CC 4 "cc_reg_operand" "y")
+ [(match_operand:CC 4 "cc_reg_operand" "y,y")
(const_int 0)])
- (match_operand:GPR 2 "gpc_reg_operand" "b")
- (match_operand:GPR 3 "gpc_reg_operand" "b")))]
- "TARGET_ISEL<sel>"
- "*
-{ return output_isel (operands); }"
- [(set_attr "type" "isel")
- (set_attr "length" "4")])
+ (match_operand:GPR 2 "gpc_reg_operand" "r,r")
+ (match_operand:GPR 3 "reg_or_zero_operand" "O,b")))]
+ "TARGET_ISEL"
+{
+ PUT_CODE (operands[1], reverse_condition (GET_CODE (operands[1])));
+ return "isel %0,%3,%2,%j1";
+}
+ [(set_attr "type" "isel")])
(define_insn "*isel_reversed_unsigned_<mode>"
- [(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
+ [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(if_then_else:GPR
(match_operator 1 "scc_rev_comparison_operator"
- [(match_operand:CCUNS 4 "cc_reg_operand" "y")
+ [(match_operand:CCUNS 4 "cc_reg_operand" "y,y")
(const_int 0)])
- (match_operand:GPR 2 "gpc_reg_operand" "b")
- (match_operand:GPR 3 "gpc_reg_operand" "b")))]
- "TARGET_ISEL<sel>"
- "*
-{ return output_isel (operands); }"
- [(set_attr "type" "isel")
- (set_attr "length" "4")])
+ (match_operand:GPR 2 "gpc_reg_operand" "r,r")
+ (match_operand:GPR 3 "reg_or_zero_operand" "O,b")))]
+ "TARGET_ISEL"
+{
+ PUT_CODE (operands[1], reverse_condition (GET_CODE (operands[1])));
+ return "isel %0,%3,%2,%j1";
+}
+ [(set_attr "type" "isel")])
;; Floating point conditional move
(define_expand "mov<mode>cc"
@@ -5899,6 +5920,14 @@
[(set_attr "type" "fpload")
(set_attr "length" "16")])
+(define_insn "lrintsfsi2"
+ [(set (match_operand:SI 0 "gpc_reg_operand" "=d")
+ (unspec:SI [(match_operand:DF 1 "gpc_reg_operand" "d")]
+ UNSPEC_FCTIW))]
+ "TARGET_SF_FPR && TARGET_FPRND"
+ "fctiw %0,%1"
+ [(set_attr "type" "fp")])
+
;; No VSX equivalent to fctid
(define_insn "lrint<mode>di2"
[(set (match_operand:DI 0 "gpc_reg_operand" "=d")
@@ -6790,25 +6819,25 @@
;; needed.
;; MR LWZ LFIWZX LXSIWZX STW
-;; STFS STXSSP STXSSPX VSX->GPR MTVSRWZ
-;; VSX->VSX
+;; STFS STXSSP STXSSPX VSX->GPR VSX->VSX
+;; MTVSRWZ
(define_insn_and_split "movsi_from_sf"
[(set (match_operand:SI 0 "nonimmediate_operand"
"=r, r, ?*wI, ?*wH, m,
- m, wY, Z, r, wIwH,
- ?wK")
+ m, wY, Z, r, ?*wIwH,
+ wIwH")
(unspec:SI [(match_operand:SF 1 "input_operand"
"r, m, Z, Z, r,
- f, wb, wu, wIwH, r,
- wK")]
+ f, wb, wu, wIwH, wIwH,
+ r")]
UNSPEC_SI_FROM_SF))
(clobber (match_scratch:V4SF 2
"=X, X, X, X, X,
- X, X, X, wa, X,
- wa"))]
+ X, X, X, wIwH, X,
+ X"))]
"TARGET_NO_SF_SUBREG
&& (register_operand (operands[0], SImode)
@@ -6823,63 +6852,52 @@
stxssp %1,%0
stxsspx %x1,%y0
#
- mtvsrwz %x0,%1
- #"
+ xscvdpspn %x0,%x1
+ mtvsrwz %x0,%1"
"&& reload_completed
- && register_operand (operands[0], SImode)
+ && int_reg_operand (operands[0], SImode)
&& vsx_reg_sfsubreg_ok (operands[1], SFmode)"
[(const_int 0)]
{
rtx op0 = operands[0];
rtx op1 = operands[1];
rtx op2 = operands[2];
- rtx op0_di = gen_rtx_REG (DImode, REGNO (op0));
+ rtx op0_di = gen_rtx_REG (DImode, reg_or_subregno (op0));
+ rtx op2_si = gen_rtx_REG (SImode, reg_or_subregno (op2));
emit_insn (gen_vsx_xscvdpspn_scalar (op2, op1));
-
- if (int_reg_operand (op0, SImode))
- {
- emit_insn (gen_p8_mfvsrd_4_disf (op0_di, op2));
- emit_insn (gen_lshrdi3 (op0_di, op0_di, GEN_INT (32)));
- }
- else
- {
- rtx op1_v16qi = gen_rtx_REG (V16QImode, REGNO (op1));
- rtx byte_off = VECTOR_ELT_ORDER_BIG ? const0_rtx : GEN_INT (12);
- emit_insn (gen_vextract4b (op0_di, op1_v16qi, byte_off));
- }
-
+ emit_insn (gen_zero_extendsidi2 (op0_di, op2_si));
DONE;
}
[(set_attr "type"
"*, load, fpload, fpload, store,
- fpstore, fpstore, fpstore, mftgpr, mffgpr,
- veclogical")
+ fpstore, fpstore, fpstore, mftgpr, fp,
+ mffgpr")
(set_attr "length"
"4, 4, 4, 4, 4,
- 4, 4, 4, 12, 4,
- 8")])
+ 4, 4, 4, 8, 4,
+ 4")])
;; movsi_from_sf with zero extension
;;
;; RLDICL LWZ LFIWZX LXSIWZX VSX->GPR
-;; MTVSRWZ VSX->VSX
+;; VSX->VSX MTVSRWZ
(define_insn_and_split "*movdi_from_sf_zero_ext"
[(set (match_operand:DI 0 "gpc_reg_operand"
"=r, r, ?*wI, ?*wH, r,
- wIwH, ?wK")
+ ?wK, wIwH")
(zero_extend:DI
(unspec:SI [(match_operand:SF 1 "input_operand"
"r, m, Z, Z, wIwH,
- r, wK")]
+ wIwH, r")]
UNSPEC_SI_FROM_SF)))
(clobber (match_scratch:V4SF 2
"=X, X, X, X, wa,
- X, wa"))]
+ wIwH, X"))]
"TARGET_DIRECT_MOVE_64BIT
&& (register_operand (operands[0], DImode)
@@ -6890,40 +6908,49 @@
lfiwzx %0,%y1
lxsiwzx %x0,%y1
#
- mtvsrwz %x0,%1
- #"
+ #
+ mtvsrwz %x0,%1"
"&& reload_completed
+ && register_operand (operands[0], DImode)
&& vsx_reg_sfsubreg_ok (operands[1], SFmode)"
[(const_int 0)]
{
rtx op0 = operands[0];
rtx op1 = operands[1];
rtx op2 = operands[2];
+ rtx op2_si = gen_rtx_REG (SImode, reg_or_subregno (op2));
emit_insn (gen_vsx_xscvdpspn_scalar (op2, op1));
-
- if (int_reg_operand (op0, DImode))
- {
- emit_insn (gen_p8_mfvsrd_4_disf (op0, op2));
- emit_insn (gen_lshrdi3 (op0, op0, GEN_INT (32)));
- }
- else
- {
- rtx op0_si = gen_rtx_REG (SImode, REGNO (op0));
- rtx op1_v16qi = gen_rtx_REG (V16QImode, REGNO (op1));
- rtx byte_off = VECTOR_ELT_ORDER_BIG ? const0_rtx : GEN_INT (12);
- emit_insn (gen_vextract4b (op0_si, op1_v16qi, byte_off));
- }
-
+ emit_insn (gen_zero_extendsidi2 (op0, op2_si));
DONE;
}
[(set_attr "type"
- "*, load, fpload, fpload, mftgpr,
- mffgpr, veclogical")
+ "*, load, fpload, fpload, two,
+ two, mffgpr")
(set_attr "length"
- "4, 4, 4, 4, 12,
- 4, 8")])
+ "4, 4, 4, 4, 8,
+ 8, 4")])
+
+;; Like movsi_from_sf, but combine a convert from DFmode to SFmode before
+;; moving it to SImode. We can do a SFmode store without having to do the
+;; conversion explicitly. If we are doing a register->register conversion, use
+;; XSCVDPSP instead of XSCVDPSPN, since the former handles cases where the
+;; input will not fit in a SFmode, and the later assumes the value has already
+;; been rounded.
+(define_insn "*movsi_from_df"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=wa,m,wY,Z")
+ (unspec:SI [(float_truncate:SF
+ (match_operand:DF 1 "gpc_reg_operand" "wa, f,wb,wa"))]
+ UNSPEC_SI_FROM_SF))]
+
+ "TARGET_NO_SF_SUBREG"
+ "@
+ xscvdpsp %x0,%x1
+ stfs%U0%X0 %1,%0
+ stxssp %1,%0
+ stxsspx %x1,%y0"
+ [(set_attr "type" "fp,fpstore,fpstore,fpstore")])
;; Split a load of a large constant into the appropriate two-insn
;; sequence.
@@ -8423,9 +8450,9 @@
(define_insn_and_split "reload_gpr_from_vsxsf"
[(set (match_operand:SF 0 "register_operand" "=r")
- (unspec:SF [(match_operand:SF 1 "register_operand" "wa")]
+ (unspec:SF [(match_operand:SF 1 "register_operand" "ww")]
UNSPEC_P8V_RELOAD_FROM_VSX))
- (clobber (match_operand:V4SF 2 "register_operand" "=wa"))]
+ (clobber (match_operand:V4SF 2 "register_operand" "=wIwH"))]
"TARGET_POWERPC64 && TARGET_DIRECT_MOVE"
"#"
"&& reload_completed"
@@ -8434,23 +8461,15 @@
rtx op0 = operands[0];
rtx op1 = operands[1];
rtx op2 = operands[2];
- rtx diop0 = simplify_gen_subreg (DImode, op0, SFmode, 0);
+ rtx op0_di = gen_rtx_REG (DImode, reg_or_subregno (op0));
+ rtx op2_si = gen_rtx_REG (SImode, reg_or_subregno (op2));
emit_insn (gen_vsx_xscvdpspn_scalar (op2, op1));
- emit_insn (gen_p8_mfvsrd_4_disf (diop0, op2));
- emit_insn (gen_lshrdi3 (diop0, diop0, GEN_INT (32)));
+ emit_insn (gen_zero_extendsidi2 (op0_di, op2_si));
DONE;
}
- [(set_attr "length" "12")
- (set_attr "type" "three")])
-
-(define_insn "p8_mfvsrd_4_disf"
- [(set (match_operand:DI 0 "register_operand" "=r")
- (unspec:DI [(match_operand:V4SF 1 "register_operand" "wa")]
- UNSPEC_P8V_RELOAD_FROM_VSX))]
- "TARGET_POWERPC64 && TARGET_DIRECT_MOVE"
- "mfvsrd %0,%x1"
- [(set_attr "type" "mftgpr")])
+ [(set_attr "length" "8")
+ (set_attr "type" "two")])
;; Next come the multi-word integer load and store and the load and store
@@ -10250,10 +10269,20 @@
;;
;; First, an insn to allocate new stack space for dynamic use (e.g., alloca).
;; We move the back-chain and decrement the stack pointer.
-
+;;
+;; Operand1 is more naturally reg_or_short_operand. However, for a large
+;; constant alloca, using that predicate will force the generic code to put
+;; the constant size into a register before calling the expander.
+;;
+;; As a result the expander would not have the constant size information
+;; in those cases and would have to generate less efficient code.
+;;
+;; Thus we allow reg_or_cint_operand instead so that the expander can see
+;; the constant size. The value is forced into a register if necessary.
+;;
(define_expand "allocate_stack"
[(set (match_operand 0 "gpc_reg_operand" "")
- (minus (reg 1) (match_operand 1 "reg_or_short_operand" "")))
+ (minus (reg 1) (match_operand 1 "reg_or_cint_operand" "")))
(set (reg 1)
(minus (reg 1) (match_dup 1)))]
""
@@ -10263,6 +10292,15 @@
rtx neg_op0;
rtx insn, par, set, mem;
+ /* By allowing reg_or_cint_operand as the predicate we can get
+ better code for stack-clash-protection because we do not lose
+ size information. But the rest of the code expects the operand
+ to be reg_or_short_operand. If it isn't, then force it into
+ a register. */
+ rtx orig_op1 = operands[1];
+ if (!reg_or_short_operand (operands[1], Pmode))
+ operands[1] = force_reg (Pmode, operands[1]);
+
emit_move_insn (chain, stack_bot);
/* Check stack bounds if necessary. */
@@ -10275,6 +10313,51 @@
emit_insn (gen_cond_trap (LTU, available, operands[1], const0_rtx));
}
+ /* Allocate and probe if requested.
+ This may look similar to the loop we use for prologue allocations,
+ but it is critically different. For the former we know the loop
+ will iterate, but do not know that generally here. The former
+ uses that knowledge to rotate the loop. Combining them would be
+ possible with some performance cost. */
+ if (flag_stack_clash_protection)
+ {
+ rtx rounded_size, last_addr, residual;
+ HOST_WIDE_INT probe_interval;
+ compute_stack_clash_protection_loop_data (&rounded_size, &last_addr,
+ &residual, &probe_interval,
+ orig_op1);
+
+ /* We do occasionally get in here with constant sizes, we might
+ as well do a reasonable job when we obviously can. */
+ if (rounded_size != const0_rtx)
+ {
+ rtx loop_lab, end_loop;
+ bool rotated = CONST_INT_P (rounded_size);
+
+ emit_stack_clash_protection_probe_loop_start (&loop_lab, &end_loop,
+ last_addr, rotated);
+
+ if (Pmode == SImode)
+ emit_insn (gen_movsi_update_stack (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-probe_interval),
+ chain));
+ else
+ emit_insn (gen_movdi_di_update_stack (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-probe_interval),
+ chain));
+ emit_stack_clash_protection_probe_loop_end (loop_lab, end_loop,
+ last_addr, rotated);
+ }
+
+ /* Now handle residuals. We just have to set operands[1] correctly
+ and let the rest of the expander run. */
+ operands[1] = residual;
+ if (!CONST_INT_P (residual))
+ operands[1] = force_reg (Pmode, operands[1]);
+ }
+
if (GET_CODE (operands[1]) != CONST_INT
|| INTVAL (operands[1]) < -32767
|| INTVAL (operands[1]) > 32768)
@@ -11074,7 +11157,7 @@
[(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
(match_operand 1 "" "g,g"))
(use (match_operand:P 2 "memory_operand" "<ptrm>,<ptrm>"))
- (set (reg:P TOC_REGNUM) (unspec [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+ (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_AIX"
"<ptrload> 2,%2\;b%T0l\;<ptrload> 2,%3(1)"
@@ -11086,7 +11169,7 @@
(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
(match_operand 2 "" "g,g")))
(use (match_operand:P 3 "memory_operand" "<ptrm>,<ptrm>"))
- (set (reg:P TOC_REGNUM) (unspec [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+ (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 4 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_AIX"
"<ptrload> 2,%3\;b%T1l\;<ptrload> 2,%4(1)"
@@ -11100,7 +11183,7 @@
(define_insn "*call_indirect_elfv2<mode>"
[(call (mem:SI (match_operand:P 0 "register_operand" "c,*l"))
(match_operand 1 "" "g,g"))
- (set (reg:P TOC_REGNUM) (unspec [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+ (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 2 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_ELFv2"
"b%T0l\;<ptrload> 2,%2(1)"
@@ -11111,7 +11194,7 @@
[(set (match_operand 0 "" "")
(call (mem:SI (match_operand:P 1 "register_operand" "c,*l"))
(match_operand 2 "" "g,g")))
- (set (reg:P TOC_REGNUM) (unspec [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
+ (set (reg:P TOC_REGNUM) (unspec:P [(match_operand:P 3 "const_int_operand" "n,n")] UNSPEC_TOCSLOT))
(clobber (reg:P LR_REGNO))]
"DEFAULT_ABI == ABI_ELFv2"
"b%T1l\;<ptrload> 2,%3(1)"
@@ -11413,12 +11496,13 @@
(set_attr "length" "4")])
(define_insn "probe_stack_range<P:mode>"
- [(set (match_operand:P 0 "register_operand" "=r")
+ [(set (match_operand:P 0 "register_operand" "=&r")
(unspec_volatile:P [(match_operand:P 1 "register_operand" "0")
- (match_operand:P 2 "register_operand" "r")]
+ (match_operand:P 2 "register_operand" "r")
+ (match_operand:P 3 "register_operand" "r")]
UNSPECV_PROBE_STACK_RANGE))]
""
- "* return output_probe_stack_range (operands[0], operands[2]);"
+ "* return output_probe_stack_range (operands[0], operands[2], operands[3]);"
[(set_attr "type" "three")])
;; Compare insns are next. Note that the RS/6000 has two types of compares,
@@ -12513,62 +12597,27 @@
(define_insn ""
[(set (pc)
(if_then_else (match_operator 1 "branch_comparison_operator"
- [(match_operand 2
- "cc_reg_operand" "y")
+ [(match_operand 2 "cc_reg_operand" "y")
(const_int 0)])
- (label_ref (match_operand 0 "" ""))
+ (label_ref (match_operand 0))
(pc)))]
""
- "*
{
- return output_cbranch (operands[1], \"%l0\", 0, insn);
-}"
+ return output_cbranch (operands[1], "%l0", 0, insn);
+}
[(set_attr "type" "branch")])
(define_insn ""
[(set (pc)
(if_then_else (match_operator 0 "branch_comparison_operator"
- [(match_operand 1
- "cc_reg_operand" "y")
+ [(match_operand 1 "cc_reg_operand" "y")
(const_int 0)])
(any_return)
(pc)))]
"<return_pred>"
- "*
{
return output_cbranch (operands[0], NULL, 0, insn);
-}"
- [(set_attr "type" "jmpreg")
- (set_attr "length" "4")])
-
-(define_insn ""
- [(set (pc)
- (if_then_else (match_operator 1 "branch_comparison_operator"
- [(match_operand 2
- "cc_reg_operand" "y")
- (const_int 0)])
- (pc)
- (label_ref (match_operand 0 "" ""))))]
- ""
- "*
-{
- return output_cbranch (operands[1], \"%l0\", 1, insn);
-}"
- [(set_attr "type" "branch")])
-
-(define_insn ""
- [(set (pc)
- (if_then_else (match_operator 0 "branch_comparison_operator"
- [(match_operand 1
- "cc_reg_operand" "y")
- (const_int 0)])
- (pc)
- (any_return)))]
- "<return_pred>"
- "*
-{
- return output_cbranch (operands[0], NULL, 1, insn);
-}"
+}
[(set_attr "type" "jmpreg")
(set_attr "length" "4")])
@@ -12689,7 +12738,7 @@
(define_insn "jump"
[(set (pc)
- (label_ref (match_operand 0 "" "")))]
+ (label_ref (match_operand 0)))]
""
"b %l0"
[(set_attr "type" "branch")])
@@ -12701,66 +12750,64 @@
[(set_attr "type" "jmpreg")])
(define_expand "indirect_jump"
- [(set (pc) (match_operand 0 "register_operand" ""))])
+ [(set (pc) (match_operand 0 "register_operand"))])
(define_insn "*indirect_jump<mode>"
- [(set (pc) (match_operand:P 0 "register_operand" "c,*l"))]
+ [(set (pc)
+ (match_operand:P 0 "register_operand" "c,*l"))]
""
- "@
- bctr
- blr"
+ "b%T0"
[(set_attr "type" "jmpreg")])
;; Table jump for switch statements:
(define_expand "tablejump"
- [(use (match_operand 0 "" ""))
- (use (label_ref (match_operand 1 "" "")))]
+ [(use (match_operand 0))
+ (use (label_ref (match_operand 1)))]
""
- "
{
if (TARGET_32BIT)
emit_jump_insn (gen_tablejumpsi (operands[0], operands[1]));
else
emit_jump_insn (gen_tablejumpdi (operands[0], operands[1]));
DONE;
-}")
+})
(define_expand "tablejumpsi"
[(set (match_dup 3)
- (plus:SI (match_operand:SI 0 "" "")
+ (plus:SI (match_operand:SI 0)
(match_dup 2)))
- (parallel [(set (pc) (match_dup 3))
- (use (label_ref (match_operand 1 "" "")))])]
+ (parallel [(set (pc)
+ (match_dup 3))
+ (use (label_ref (match_operand 1)))])]
"TARGET_32BIT"
- "
-{ operands[0] = force_reg (SImode, operands[0]);
+{
+ operands[0] = force_reg (SImode, operands[0]);
operands[2] = force_reg (SImode, gen_rtx_LABEL_REF (SImode, operands[1]));
operands[3] = gen_reg_rtx (SImode);
-}")
+})
(define_expand "tablejumpdi"
[(set (match_dup 4)
- (sign_extend:DI (match_operand:SI 0 "lwa_operand" "")))
+ (sign_extend:DI (match_operand:SI 0 "lwa_operand")))
(set (match_dup 3)
(plus:DI (match_dup 4)
(match_dup 2)))
- (parallel [(set (pc) (match_dup 3))
- (use (label_ref (match_operand 1 "" "")))])]
+ (parallel [(set (pc)
+ (match_dup 3))
+ (use (label_ref (match_operand 1)))])]
"TARGET_64BIT"
- "
-{ operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[1]));
+{
+ operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[1]));
operands[3] = gen_reg_rtx (DImode);
operands[4] = gen_reg_rtx (DImode);
-}")
+})
(define_insn "*tablejump<mode>_internal1"
[(set (pc)
(match_operand:P 0 "register_operand" "c,*l"))
- (use (label_ref (match_operand 1 "" "")))]
+ (use (label_ref (match_operand 1)))]
""
- "@
- bctr
- blr"
+ "b%T0"
[(set_attr "type" "jmpreg")])
(define_insn "nop"
@@ -12771,21 +12818,19 @@
(define_insn "group_ending_nop"
[(unspec [(const_int 0)] UNSPEC_GRP_END_NOP)]
""
- "*
{
if (rs6000_cpu_attr == CPU_POWER6)
- return \"ori 1,1,0\";
- return \"ori 2,2,0\";
-}")
+ return "ori 1,1,0";
+ return "ori 2,2,0";
+})
;; Define the subtract-one-and-jump insns, starting with the template
;; so loop.c knows what to generate.
(define_expand "doloop_end"
- [(use (match_operand 0 "" "")) ; loop pseudo
- (use (match_operand 1 "" ""))] ; label
+ [(use (match_operand 0)) ; loop pseudo
+ (use (match_operand 1))] ; label
""
- "
{
if (TARGET_64BIT)
{
@@ -12800,19 +12845,19 @@
emit_jump_insn (gen_ctrsi (operands[0], operands[1]));
}
DONE;
-}")
+})
(define_expand "ctr<mode>"
[(parallel [(set (pc)
- (if_then_else (ne (match_operand:P 0 "register_operand" "")
+ (if_then_else (ne (match_operand:P 0 "register_operand")
(const_int 1))
- (label_ref (match_operand 1 "" ""))
+ (label_ref (match_operand 1))
(pc)))
(set (match_dup 0)
(plus:P (match_dup 0)
(const_int -1)))
- (clobber (match_scratch:CC 2 ""))
- (clobber (match_scratch:P 3 ""))])]
+ (clobber (match_scratch:CC 2))
+ (clobber (match_scratch:P 3))])]
""
"")
@@ -12828,97 +12873,47 @@
[(set (pc)
(if_then_else (ne (match_operand:P 1 "register_operand" "c,*b,*b,*b")
(const_int 1))
- (label_ref (match_operand 0 "" ""))
+ (label_ref (match_operand 0))
(pc)))
(set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*d*wi*c*l")
(plus:P (match_dup 1)
- (const_int -1)))
- (clobber (match_scratch:CC 3 "=X,&x,&x,&x"))
- (clobber (match_scratch:P 4 "=X,X,&r,r"))]
- ""
- "*
-{
- if (which_alternative != 0)
- return \"#\";
- else if (get_attr_length (insn) == 4)
- return \"bdnz %l0\";
- else
- return \"bdz $+8\;b %l0\";
-}"
- [(set_attr "type" "branch")
- (set_attr "length" "*,16,20,20")])
-
-(define_insn "ctr<mode>_internal2"
- [(set (pc)
- (if_then_else (ne (match_operand:P 1 "register_operand" "c,*b,*b,*b")
- (const_int 1))
- (pc)
- (label_ref (match_operand 0 "" ""))))
- (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*d*wi*c*l")
- (plus:P (match_dup 1)
- (const_int -1)))
+ (const_int -1)))
(clobber (match_scratch:CC 3 "=X,&x,&x,&x"))
(clobber (match_scratch:P 4 "=X,X,&r,r"))]
""
- "*
{
if (which_alternative != 0)
- return \"#\";
+ return "#";
else if (get_attr_length (insn) == 4)
- return \"bdz %l0\";
+ return "bdnz %l0";
else
- return \"bdnz $+8\;b %l0\";
-}"
+ return "bdz $+8\;b %l0";
+}
[(set_attr "type" "branch")
(set_attr "length" "*,16,20,20")])
;; Similar but use EQ
-(define_insn "ctr<mode>_internal3"
+(define_insn "ctr<mode>_internal2"
[(set (pc)
(if_then_else (eq (match_operand:P 1 "register_operand" "c,*b,*b,*b")
(const_int 1))
- (label_ref (match_operand 0 "" ""))
+ (label_ref (match_operand 0))
(pc)))
(set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*d*wi*c*l")
(plus:P (match_dup 1)
- (const_int -1)))
- (clobber (match_scratch:CC 3 "=X,&x,&x,&x"))
- (clobber (match_scratch:P 4 "=X,X,&r,r"))]
- ""
- "*
-{
- if (which_alternative != 0)
- return \"#\";
- else if (get_attr_length (insn) == 4)
- return \"bdz %l0\";
- else
- return \"bdnz $+8\;b %l0\";
-}"
- [(set_attr "type" "branch")
- (set_attr "length" "*,16,20,20")])
-
-(define_insn "ctr<mode>_internal4"
- [(set (pc)
- (if_then_else (eq (match_operand:P 1 "register_operand" "c,*b,*b,*b")
- (const_int 1))
- (pc)
- (label_ref (match_operand 0 "" ""))))
- (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*d*wi*c*l")
- (plus:P (match_dup 1)
- (const_int -1)))
+ (const_int -1)))
(clobber (match_scratch:CC 3 "=X,&x,&x,&x"))
(clobber (match_scratch:P 4 "=X,X,&r,r"))]
""
- "*
{
if (which_alternative != 0)
- return \"#\";
+ return "#";
else if (get_attr_length (insn) == 4)
- return \"bdnz %l0\";
+ return "bdz %l0";
else
- return \"bdz $+8\;b %l0\";
-}"
+ return "bdnz $+8\;b %l0";
+}
[(set_attr "type" "branch")
(set_attr "length" "*,16,20,20")])
@@ -12927,14 +12922,15 @@
(define_split
[(set (pc)
(if_then_else (match_operator 2 "comparison_operator"
- [(match_operand:P 1 "gpc_reg_operand" "")
+ [(match_operand:P 1 "gpc_reg_operand")
(const_int 1)])
- (match_operand 5 "" "")
- (match_operand 6 "" "")))
- (set (match_operand:P 0 "int_reg_operand" "")
- (plus:P (match_dup 1) (const_int -1)))
- (clobber (match_scratch:CC 3 ""))
- (clobber (match_scratch:P 4 ""))]
+ (match_operand 5)
+ (match_operand 6)))
+ (set (match_operand:P 0 "int_reg_operand")
+ (plus:P (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3))
+ (clobber (match_scratch:P 4))]
"reload_completed"
[(set (match_dup 3)
(compare:CC (match_dup 1)
@@ -12942,25 +12938,28 @@
(set (match_dup 0)
(plus:P (match_dup 1)
(const_int -1)))
- (set (pc) (if_then_else (match_dup 7)
- (match_dup 5)
- (match_dup 6)))]
- "
-{ operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[2]), VOIDmode,
- operands[3], const0_rtx); }")
+ (set (pc)
+ (if_then_else (match_dup 7)
+ (match_dup 5)
+ (match_dup 6)))]
+{
+ operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[2]), VOIDmode, operands[3],
+ const0_rtx);
+})
(define_split
[(set (pc)
(if_then_else (match_operator 2 "comparison_operator"
- [(match_operand:P 1 "gpc_reg_operand" "")
+ [(match_operand:P 1 "gpc_reg_operand")
(const_int 1)])
- (match_operand 5 "" "")
- (match_operand 6 "" "")))
- (set (match_operand:P 0 "nonimmediate_operand" "")
- (plus:P (match_dup 1) (const_int -1)))
- (clobber (match_scratch:CC 3 ""))
- (clobber (match_scratch:P 4 ""))]
- "reload_completed && ! gpc_reg_operand (operands[0], SImode)"
+ (match_operand 5)
+ (match_operand 6)))
+ (set (match_operand:P 0 "nonimmediate_operand")
+ (plus:P (match_dup 1)
+ (const_int -1)))
+ (clobber (match_scratch:CC 3))
+ (clobber (match_scratch:P 4))]
+ "reload_completed && !gpc_reg_operand (operands[0], SImode)"
[(set (match_dup 3)
(compare:CC (match_dup 1)
(const_int 1)))
@@ -12969,12 +12968,14 @@
(const_int -1)))
(set (match_dup 0)
(match_dup 4))
- (set (pc) (if_then_else (match_dup 7)
- (match_dup 5)
- (match_dup 6)))]
- "
-{ operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[2]), VOIDmode,
- operands[3], const0_rtx); }")
+ (set (pc)
+ (if_then_else (match_dup 7)
+ (match_dup 5)
+ (match_dup 6)))]
+{
+ operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[2]), VOIDmode, operands[3],
+ const0_rtx);
+})
(define_insn "trap"
[(trap_if (const_int 1) (const_int 0))]
@@ -13161,14 +13162,12 @@
; Some 32-bit ABIs do not have a red zone, so the stack deallocation has to
; stay behind all restores from the stack, it cannot be reordered to before
-; one. See PR77687. This insn is an add or mr, and a stack_tie on the
-; operands of that.
+; one. See PR77687. This insn is an add or mr, and a memory clobber.
(define_insn "stack_restore_tie"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r,r")
(plus:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")
(match_operand:SI 2 "reg_or_cint_operand" "O,rI")))
- (set (mem:BLK (match_dup 0)) (const_int 0))
- (set (mem:BLK (match_dup 1)) (const_int 0))]
+ (set (mem:BLK (scratch)) (const_int 0))]
"TARGET_32BIT"
"@
mr %0,%1
@@ -14428,7 +14427,8 @@
"#"
"&& 1"
[(set (match_dup 2)
- (unspec:DF [(match_dup 1)] UNSPEC_ROUND_TO_ODD))
+ (unspec:DF [(match_dup 1)]
+ UNSPEC_TRUNC_ROUND_TO_ODD))
(set (match_dup 0)
(float_truncate:SF (match_dup 2)))]
{
@@ -14605,10 +14605,116 @@
(set_attr "size" "128")])
;; IEEE 128-bit instructions with round to odd semantics
-(define_insn "*trunc<mode>df2_odd"
+(define_insn "add<mode>3_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")
+ (match_operand:IEEE128 2 "altivec_register_operand" "v")]
+ UNSPEC_ADD_ROUND_TO_ODD))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsaddqpo %0,%1,%2"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "sub<mode>3_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")
+ (match_operand:IEEE128 2 "altivec_register_operand" "v")]
+ UNSPEC_SUB_ROUND_TO_ODD))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xssubqpo %0,%1,%2"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "mul<mode>3_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")
+ (match_operand:IEEE128 2 "altivec_register_operand" "v")]
+ UNSPEC_MUL_ROUND_TO_ODD))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsmulqpo %0,%1,%2"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "div<mode>3_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")
+ (match_operand:IEEE128 2 "altivec_register_operand" "v")]
+ UNSPEC_DIV_ROUND_TO_ODD))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsdivqpo %0,%1,%2"
+ [(set_attr "type" "vecdiv")
+ (set_attr "size" "128")])
+
+(define_insn "sqrt<mode>2_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")]
+ UNSPEC_SQRT_ROUND_TO_ODD))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xssqrtqpo %0,%1"
+ [(set_attr "type" "vecdiv")
+ (set_attr "size" "128")])
+
+(define_insn "fma<mode>4_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "v")
+ (match_operand:IEEE128 2 "altivec_register_operand" "v")
+ (match_operand:IEEE128 3 "altivec_register_operand" "0")]
+ UNSPEC_FMA_ROUND_TO_ODD))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsmaddqpo %0,%1,%2"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "*fms<mode>4_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "%v")
+ (match_operand:IEEE128 2 "altivec_register_operand" "v")
+ (neg:IEEE128
+ (match_operand:IEEE128 3 "altivec_register_operand" "0"))]
+ UNSPEC_FMA_ROUND_TO_ODD))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsmsubqpo %0,%1,%2"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "*nfma<mode>4_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (neg:IEEE128
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "%v")
+ (match_operand:IEEE128 2 "altivec_register_operand" "v")
+ (match_operand:IEEE128 3 "altivec_register_operand" "0")]
+ UNSPEC_FMA_ROUND_TO_ODD)))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsnmaddqpo %0,%1,%2"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "*nfms<mode>4_odd"
+ [(set (match_operand:IEEE128 0 "altivec_register_operand" "=v")
+ (neg:IEEE128
+ (unspec:IEEE128
+ [(match_operand:IEEE128 1 "altivec_register_operand" "%v")
+ (match_operand:IEEE128 2 "altivec_register_operand" "v")
+ (neg:IEEE128
+ (match_operand:IEEE128 3 "altivec_register_operand" "0"))]
+ UNSPEC_FMA_ROUND_TO_ODD)))]
+ "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
+ "xsnmsubqpo %0,%1,%2"
+ [(set_attr "type" "vecfloat")
+ (set_attr "size" "128")])
+
+(define_insn "trunc<mode>df2_odd"
[(set (match_operand:DF 0 "vsx_register_operand" "=v")
(unspec:DF [(match_operand:IEEE128 1 "altivec_register_operand" "v")]
- UNSPEC_ROUND_TO_ODD))]
+ UNSPEC_TRUNC_ROUND_TO_ODD))]
"TARGET_FLOAT128_HW && FLOAT128_IEEE_P (<MODE>mode)"
"xscvqpdpo %0,%1"
[(set_attr "type" "vecfloat")
diff --git a/gcc/config/rs6000/sysv4.h b/gcc/config/rs6000/sysv4.h
index e381ce9..37bd63f 100644
--- a/gcc/config/rs6000/sysv4.h
+++ b/gcc/config/rs6000/sysv4.h
@@ -160,7 +160,7 @@ do { \
{ \
rs6000_sdata = SDATA_NONE; \
error ("%<%s=%s%> and %<%s-%s%> are incompatible", \
- "-msdata", "-mcall", rs6000_sdata_name, rs6000_abi_name); \
+ "-msdata", rs6000_sdata_name, "-mcall", rs6000_abi_name); \
} \
\
targetm.have_srodata_section = rs6000_sdata == SDATA_EABI; \
diff --git a/gcc/config/rs6000/vsx.md b/gcc/config/rs6000/vsx.md
index 9b24c7b..35be5de 100644
--- a/gcc/config/rs6000/vsx.md
+++ b/gcc/config/rs6000/vsx.md
@@ -382,8 +382,16 @@
UNSPEC_VSX_VTSTDC
UNSPEC_VSX_VEC_INIT
UNSPEC_VSX_VSIGNED2
+
UNSPEC_LXVL
+ UNSPEC_LXVLL
+ UNSPEC_LVSL_REG
+ UNSPEC_LVSR_REG
UNSPEC_STXVL
+ UNSPEC_STXVLL
+ UNSPEC_XL_LEN_R
+ UNSPEC_XST_LEN_R
+
UNSPEC_VCLZLSBB
UNSPEC_VCTZLSBB
UNSPEC_VEXTUBLX
@@ -1781,6 +1789,15 @@
"xscvspdp %x0,%x1"
[(set_attr "type" "fp")])
+;; Same as vsx_xscvspdp, but use SF as the type
+(define_insn "vsx_xscvspdp_scalar2"
+ [(set (match_operand:SF 0 "vsx_register_operand" "=ww")
+ (unspec:SF [(match_operand:V4SF 1 "vsx_register_operand" "wa")]
+ UNSPEC_VSX_CVSPDP))]
+ "VECTOR_UNIT_VSX_P (V4SFmode)"
+ "xscvspdp %x0,%x1"
+ [(set_attr "type" "fp")])
+
;; Generate xvcvhpsp instruction
(define_insn "vsx_xvcvhpsp"
[(set (match_operand:V4SF 0 "vsx_register_operand" "=wa")
@@ -1794,41 +1811,32 @@
;; format of scalars is actually DF.
(define_insn "vsx_xscvdpsp_scalar"
[(set (match_operand:V4SF 0 "vsx_register_operand" "=wa")
- (unspec:V4SF [(match_operand:SF 1 "vsx_register_operand" "f")]
+ (unspec:V4SF [(match_operand:SF 1 "vsx_register_operand" "ww")]
UNSPEC_VSX_CVSPDP))]
"VECTOR_UNIT_VSX_P (V4SFmode)"
"xscvdpsp %x0,%x1"
[(set_attr "type" "fp")])
-;; Same as vsx_xscvspdp, but use SF as the type
-(define_insn "vsx_xscvspdp_scalar2"
- [(set (match_operand:SF 0 "vsx_register_operand" "=ww")
- (unspec:SF [(match_operand:V4SF 1 "vsx_register_operand" "wa")]
- UNSPEC_VSX_CVSPDP))]
- "VECTOR_UNIT_VSX_P (V4SFmode)"
- "xscvspdp %x0,%x1"
- [(set_attr "type" "fp")])
-
;; ISA 2.07 xscvdpspn/xscvspdpn that does not raise an error on signalling NaNs
(define_insn "vsx_xscvdpspn"
- [(set (match_operand:V4SF 0 "vsx_register_operand" "=ww,?ww")
- (unspec:V4SF [(match_operand:DF 1 "vsx_register_operand" "wd,wa")]
+ [(set (match_operand:V4SF 0 "vsx_register_operand" "=ww")
+ (unspec:V4SF [(match_operand:DF 1 "vsx_register_operand" "ws")]
UNSPEC_VSX_CVDPSPN))]
"TARGET_XSCVDPSPN"
"xscvdpspn %x0,%x1"
[(set_attr "type" "fp")])
(define_insn "vsx_xscvspdpn"
- [(set (match_operand:DF 0 "vsx_register_operand" "=ws,?ws")
- (unspec:DF [(match_operand:V4SF 1 "vsx_register_operand" "wf,wa")]
+ [(set (match_operand:DF 0 "vsx_register_operand" "=ws")
+ (unspec:DF [(match_operand:V4SF 1 "vsx_register_operand" "wa")]
UNSPEC_VSX_CVSPDPN))]
"TARGET_XSCVSPDPN"
"xscvspdpn %x0,%x1"
[(set_attr "type" "fp")])
(define_insn "vsx_xscvdpspn_scalar"
- [(set (match_operand:V4SF 0 "vsx_register_operand" "=wf,?wa")
- (unspec:V4SF [(match_operand:SF 1 "vsx_register_operand" "ww,ww")]
+ [(set (match_operand:V4SF 0 "vsx_register_operand" "=wa")
+ (unspec:V4SF [(match_operand:SF 1 "vsx_register_operand" "ww")]
UNSPEC_VSX_CVDPSPN))]
"TARGET_XSCVDPSPN"
"xscvdpspn %x0,%x1"
@@ -4352,6 +4360,43 @@
[(set_attr "length" "8")
(set_attr "type" "vecload")])
+(define_insn "lxvll"
+ [(set (match_operand:V16QI 0 "vsx_register_operand" "=wa")
+ (unspec:V16QI [(match_operand:DI 1 "gpc_reg_operand" "b")
+ (match_operand:DI 2 "register_operand" "r")]
+ UNSPEC_LXVLL))]
+ "TARGET_P9_VECTOR"
+ "lxvll %x0,%1,%2"
+ [(set_attr "type" "vecload")])
+
+;; Expand for builtin xl_len_r
+(define_expand "xl_len_r"
+ [(match_operand:V16QI 0 "vsx_register_operand")
+ (match_operand:DI 1 "register_operand")
+ (match_operand:DI 2 "register_operand")]
+ ""
+{
+ rtx shift_mask = gen_reg_rtx (V16QImode);
+ rtx rtx_vtmp = gen_reg_rtx (V16QImode);
+ rtx tmp = gen_reg_rtx (DImode);
+
+ emit_insn (gen_altivec_lvsl_reg (shift_mask, operands[2]));
+ emit_insn (gen_ashldi3 (tmp, operands[2], GEN_INT (56)));
+ emit_insn (gen_lxvll (rtx_vtmp, operands[1], tmp));
+ emit_insn (gen_altivec_vperm_v8hiv16qi (operands[0], rtx_vtmp, rtx_vtmp,
+ shift_mask));
+ DONE;
+})
+
+(define_insn "stxvll"
+ [(set (mem:V16QI (match_operand:DI 1 "gpc_reg_operand" "b"))
+ (unspec:V16QI [(match_operand:V16QI 0 "vsx_register_operand" "wa")
+ (match_operand:DI 2 "register_operand" "r")]
+ UNSPEC_STXVLL))]
+ "TARGET_P9_VECTOR"
+ "stxvll %x0,%1,%2"
+ [(set_attr "type" "vecstore")])
+
;; Store VSX Vector with Length
(define_expand "stxvl"
[(set (match_dup 3)
@@ -4377,6 +4422,25 @@
[(set_attr "length" "8")
(set_attr "type" "vecstore")])
+;; Expand for builtin xst_len_r
+(define_expand "xst_len_r"
+ [(match_operand:V16QI 0 "vsx_register_operand" "=wa")
+ (match_operand:DI 1 "register_operand" "b")
+ (match_operand:DI 2 "register_operand" "r")]
+ "UNSPEC_XST_LEN_R"
+{
+ rtx shift_mask = gen_reg_rtx (V16QImode);
+ rtx rtx_vtmp = gen_reg_rtx (V16QImode);
+ rtx tmp = gen_reg_rtx (DImode);
+
+ emit_insn (gen_altivec_lvsr_reg (shift_mask, operands[2]));
+ emit_insn (gen_altivec_vperm_v8hiv16qi (rtx_vtmp, operands[0], operands[0],
+ shift_mask));
+ emit_insn (gen_ashldi3 (tmp, operands[2], GEN_INT (56)));
+ emit_insn (gen_stxvll (rtx_vtmp, operands[1], tmp));
+ DONE;
+})
+
;; Vector Compare Not Equal Byte
(define_insn "vcmpneb"
[(set (match_operand:V16QI 0 "altivec_register_operand" "=v")
@@ -4733,9 +4797,10 @@
(SFBOOL_SHL_D 7) ;; shift left dest
(SFBOOL_SHL_A 8) ;; shift left arg
(SFBOOL_MTVSR_D 9) ;; move to vecter dest
- (SFBOOL_BOOL_A_DI 10) ;; SFBOOL_BOOL_A1/A2 as DImode
- (SFBOOL_TMP_VSX_DI 11) ;; SFBOOL_TMP_VSX as DImode
- (SFBOOL_MTVSR_D_V4SF 12)]) ;; SFBOOL_MTVSRD_D as V4SFmode
+ (SFBOOL_MFVSR_A_V4SF 10) ;; SFBOOL_MFVSR_A as V4SFmode
+ (SFBOOL_BOOL_A_DI 11) ;; SFBOOL_BOOL_A1/A2 as DImode
+ (SFBOOL_TMP_VSX_DI 12) ;; SFBOOL_TMP_VSX as DImode
+ (SFBOOL_MTVSR_D_V4SF 13)]) ;; SFBOOL_MTVSRD_D as V4SFmode
;; Attempt to optimize some common GLIBC operations using logical operations to
;; pick apart SFmode operations. For example, there is code from e_powf.c
@@ -4773,29 +4838,22 @@
;;
;; (set (reg:DI reg3) (unspec:DI [(reg:V4SF reg2)] UNSPEC_P8V_RELOAD_FROM_VSX))
;;
-;; (set (reg:DI reg3) (lshiftrt:DI (reg:DI reg3) (const_int 32)))
-;;
-;; (set (reg:DI reg5) (and:DI (reg:DI reg3) (reg:DI reg4)))
+;; (set (reg:DI reg4) (and:DI (reg:DI reg3) (reg:DI reg3)))
;;
-;; (set (reg:DI reg6) (ashift:DI (reg:DI reg5) (const_int 32)))
+;; (set (reg:DI reg5) (ashift:DI (reg:DI reg4) (const_int 32)))
;;
-;; (set (reg:SF reg7) (unspec:SF [(reg:DI reg6)] UNSPEC_P8V_MTVSRD))
+;; (set (reg:SF reg6) (unspec:SF [(reg:DI reg5)] UNSPEC_P8V_MTVSRD))
;;
-;; (set (reg:SF reg7) (unspec:SF [(reg:SF reg7)] UNSPEC_VSX_CVSPDPN))
+;; (set (reg:SF reg6) (unspec:SF [(reg:SF reg6)] UNSPEC_VSX_CVSPDPN))
(define_peephole2
[(match_scratch:DI SFBOOL_TMP_GPR "r")
(match_scratch:V4SF SFBOOL_TMP_VSX "wa")
- ;; MFVSRD
+ ;; MFVSRWZ (aka zero_extend)
(set (match_operand:DI SFBOOL_MFVSR_D "int_reg_operand")
- (unspec:DI [(match_operand:V4SF SFBOOL_MFVSR_A "vsx_register_operand")]
- UNSPEC_P8V_RELOAD_FROM_VSX))
-
- ;; SRDI
- (set (match_dup SFBOOL_MFVSR_D)
- (lshiftrt:DI (match_dup SFBOOL_MFVSR_D)
- (const_int 32)))
+ (zero_extend:DI
+ (match_operand:SI SFBOOL_MFVSR_A "vsx_register_operand")))
;; AND/IOR/XOR operation on int
(set (match_operand:SI SFBOOL_BOOL_D "int_reg_operand")
@@ -4820,15 +4878,15 @@
&& (REG_P (operands[SFBOOL_BOOL_A2])
|| CONST_INT_P (operands[SFBOOL_BOOL_A2]))
&& (REGNO (operands[SFBOOL_BOOL_D]) == REGNO (operands[SFBOOL_MFVSR_D])
- || peep2_reg_dead_p (3, operands[SFBOOL_MFVSR_D]))
+ || peep2_reg_dead_p (2, operands[SFBOOL_MFVSR_D]))
&& (REGNO (operands[SFBOOL_MFVSR_D]) == REGNO (operands[SFBOOL_BOOL_A1])
|| (REG_P (operands[SFBOOL_BOOL_A2])
&& REGNO (operands[SFBOOL_MFVSR_D])
== REGNO (operands[SFBOOL_BOOL_A2])))
&& REGNO (operands[SFBOOL_BOOL_D]) == REGNO (operands[SFBOOL_SHL_A])
&& (REGNO (operands[SFBOOL_SHL_D]) == REGNO (operands[SFBOOL_BOOL_D])
- || peep2_reg_dead_p (4, operands[SFBOOL_BOOL_D]))
- && peep2_reg_dead_p (5, operands[SFBOOL_SHL_D])"
+ || peep2_reg_dead_p (3, operands[SFBOOL_BOOL_D]))
+ && peep2_reg_dead_p (4, operands[SFBOOL_SHL_D])"
[(set (match_dup SFBOOL_TMP_GPR)
(ashift:DI (match_dup SFBOOL_BOOL_A_DI)
(const_int 32)))
@@ -4837,12 +4895,13 @@
(match_dup SFBOOL_TMP_GPR))
(set (match_dup SFBOOL_MTVSR_D_V4SF)
- (and_ior_xor:V4SF (match_dup SFBOOL_MFVSR_A)
+ (and_ior_xor:V4SF (match_dup SFBOOL_MFVSR_A_V4SF)
(match_dup SFBOOL_TMP_VSX)))]
{
rtx bool_a1 = operands[SFBOOL_BOOL_A1];
rtx bool_a2 = operands[SFBOOL_BOOL_A2];
int regno_mfvsr_d = REGNO (operands[SFBOOL_MFVSR_D]);
+ int regno_mfvsr_a = REGNO (operands[SFBOOL_MFVSR_A]);
int regno_tmp_vsx = REGNO (operands[SFBOOL_TMP_VSX]);
int regno_mtvsr_d = REGNO (operands[SFBOOL_MTVSR_D]);
@@ -4861,6 +4920,7 @@
operands[SFBOOL_BOOL_A_DI] = gen_rtx_REG (DImode, regno_bool_a);
}
+ operands[SFBOOL_MFVSR_A_V4SF] = gen_rtx_REG (V4SFmode, regno_mfvsr_a);
operands[SFBOOL_TMP_VSX_DI] = gen_rtx_REG (DImode, regno_tmp_vsx);
operands[SFBOOL_MTVSR_D_V4SF] = gen_rtx_REG (V4SFmode, regno_mtvsr_d);
})
diff --git a/gcc/config/rx/rx.h b/gcc/config/rx/rx.h
index 4bc43c2..850033c 100644
--- a/gcc/config/rx/rx.h
+++ b/gcc/config/rx/rx.h
@@ -169,7 +169,6 @@
#define HAS_LONG_UNCOND_BRANCH 0
#define MOVE_MAX 4
-#define STARTING_FRAME_OFFSET 0
#define HAVE_PRE_DECREMENT 1
#define HAVE_POST_INCREMENT 1
diff --git a/gcc/config/s390/predicates.md b/gcc/config/s390/predicates.md
index db966dd..bbff8d8 100644
--- a/gcc/config/s390/predicates.md
+++ b/gcc/config/s390/predicates.md
@@ -508,3 +508,10 @@
}
return true;
})
+
+(define_predicate "const_shift_by_byte_operand"
+ (match_code "const_int")
+{
+ unsigned HOST_WIDE_INT val = INTVAL (op);
+ return val <= 128 && val % 8 == 0;
+})
diff --git a/gcc/config/s390/s390-builtin-types.def b/gcc/config/s390/s390-builtin-types.def
index b7f3303..fa03f42 100644
--- a/gcc/config/s390/s390-builtin-types.def
+++ b/gcc/config/s390/s390-builtin-types.def
@@ -54,74 +54,74 @@
s390_builtin_types[T6])
DEF_TYPE (BT_INT, integer_type_node, 0)
DEF_TYPE (BT_VOID, void_type_node, 0)
-DEF_TYPE (BT_ULONG, long_unsigned_type_node, 0)
DEF_TYPE (BT_UINT64, c_uint64_type_node, 0)
-DEF_TYPE (BT_INT128, intTI_type_node, 0)
DEF_TYPE (BT_UINT, unsigned_type_node, 0)
DEF_TYPE (BT_VOIDCONST, void_type_node, 1)
-DEF_TYPE (BT_USHORTCONST, short_unsigned_type_node, 1)
-DEF_TYPE (BT_SHORTCONST, short_integer_type_node, 1)
-DEF_TYPE (BT_UCHARCONST, unsigned_char_type_node, 1)
DEF_TYPE (BT_INTCONST, integer_type_node, 1)
-DEF_TYPE (BT_SCHARCONST, signed_char_type_node, 1)
DEF_TYPE (BT_UCHAR, unsigned_char_type_node, 0)
-DEF_TYPE (BT_SHORT, short_integer_type_node, 0)
-DEF_TYPE (BT_LONG, long_integer_type_node, 0)
-DEF_TYPE (BT_SCHAR, signed_char_type_node, 0)
-DEF_TYPE (BT_USHORT, short_unsigned_type_node, 0)
-DEF_TYPE (BT_ULONGLONG, long_long_unsigned_type_node, 0)
-DEF_TYPE (BT_DBLCONST, double_type_node, 1)
+DEF_TYPE (BT_UINTCONST, unsigned_type_node, 1)
DEF_TYPE (BT_FLT, float_type_node, 0)
-DEF_TYPE (BT_DBL, double_type_node, 0)
DEF_TYPE (BT_FLTCONST, float_type_node, 1)
-DEF_TYPE (BT_ULONGLONGCONST, long_long_unsigned_type_node, 1)
DEF_TYPE (BT_LONGLONG, long_long_integer_type_node, 0)
+DEF_TYPE (BT_ULONGLONG, long_long_unsigned_type_node, 0)
DEF_TYPE (BT_LONGLONGCONST, long_long_integer_type_node, 1)
-DEF_TYPE (BT_UINTCONST, unsigned_type_node, 1)
-DEF_VECTOR_TYPE (BT_UV2DI, BT_ULONGLONG, 2)
-DEF_VECTOR_TYPE (BT_V2DI, BT_LONGLONG, 2)
-DEF_VECTOR_TYPE (BT_V8HI, BT_SHORT, 8)
+DEF_TYPE (BT_ULONGLONGCONST, long_long_unsigned_type_node, 1)
+DEF_TYPE (BT_DBL, double_type_node, 0)
+DEF_TYPE (BT_DBLCONST, double_type_node, 1)
+DEF_TYPE (BT_USHORT, short_unsigned_type_node, 0)
+DEF_TYPE (BT_SCHAR, signed_char_type_node, 0)
+DEF_TYPE (BT_LONG, long_integer_type_node, 0)
+DEF_TYPE (BT_SHORT, short_integer_type_node, 0)
+DEF_TYPE (BT_SCHARCONST, signed_char_type_node, 1)
+DEF_TYPE (BT_UCHARCONST, unsigned_char_type_node, 1)
+DEF_TYPE (BT_SHORTCONST, short_integer_type_node, 1)
+DEF_TYPE (BT_USHORTCONST, short_unsigned_type_node, 1)
+DEF_TYPE (BT_INT128, intTI_type_node, 0)
+DEF_TYPE (BT_ULONG, long_unsigned_type_node, 0)
DEF_VECTOR_TYPE (BT_V4SI, BT_INT, 4)
DEF_VECTOR_TYPE (BT_UV4SI, BT_UINT, 4)
-DEF_VECTOR_TYPE (BT_V16QI, BT_SCHAR, 16)
-DEF_VECTOR_TYPE (BT_UV8HI, BT_USHORT, 8)
DEF_VECTOR_TYPE (BT_V4SF, BT_FLT, 4)
+DEF_VECTOR_TYPE (BT_V2DI, BT_LONGLONG, 2)
+DEF_VECTOR_TYPE (BT_UV2DI, BT_ULONGLONG, 2)
DEF_VECTOR_TYPE (BT_V2DF, BT_DBL, 2)
DEF_VECTOR_TYPE (BT_UV16QI, BT_UCHAR, 16)
-DEF_POINTER_TYPE (BT_USHORTPTR, BT_USHORT)
-DEF_POINTER_TYPE (BT_UINTCONSTPTR, BT_UINTCONST)
+DEF_VECTOR_TYPE (BT_UV8HI, BT_USHORT, 8)
+DEF_VECTOR_TYPE (BT_V16QI, BT_SCHAR, 16)
+DEF_VECTOR_TYPE (BT_V8HI, BT_SHORT, 8)
DEF_POINTER_TYPE (BT_VOIDPTR, BT_VOID)
-DEF_POINTER_TYPE (BT_ULONGLONGCONSTPTR, BT_ULONGLONGCONST)
DEF_POINTER_TYPE (BT_UINT64PTR, BT_UINT64)
+DEF_POINTER_TYPE (BT_VOIDCONSTPTR, BT_VOIDCONST)
+DEF_POINTER_TYPE (BT_INTCONSTPTR, BT_INTCONST)
+DEF_POINTER_TYPE (BT_UINTCONSTPTR, BT_UINTCONST)
DEF_POINTER_TYPE (BT_FLTCONSTPTR, BT_FLTCONST)
-DEF_POINTER_TYPE (BT_USHORTCONSTPTR, BT_USHORTCONST)
+DEF_POINTER_TYPE (BT_LONGLONGCONSTPTR, BT_LONGLONGCONST)
+DEF_POINTER_TYPE (BT_ULONGLONGCONSTPTR, BT_ULONGLONGCONST)
+DEF_POINTER_TYPE (BT_DBLCONSTPTR, BT_DBLCONST)
DEF_POINTER_TYPE (BT_SCHARPTR, BT_SCHAR)
DEF_POINTER_TYPE (BT_UCHARPTR, BT_UCHAR)
-DEF_POINTER_TYPE (BT_VOIDCONSTPTR, BT_VOIDCONST)
-DEF_POINTER_TYPE (BT_LONGLONGCONSTPTR, BT_LONGLONGCONST)
DEF_POINTER_TYPE (BT_SHORTPTR, BT_SHORT)
-DEF_POINTER_TYPE (BT_DBLCONSTPTR, BT_DBLCONST)
+DEF_POINTER_TYPE (BT_USHORTPTR, BT_USHORT)
DEF_POINTER_TYPE (BT_INTPTR, BT_INT)
DEF_POINTER_TYPE (BT_UINTPTR, BT_UINT)
DEF_POINTER_TYPE (BT_LONGLONGPTR, BT_LONGLONG)
DEF_POINTER_TYPE (BT_ULONGLONGPTR, BT_ULONGLONG)
-DEF_POINTER_TYPE (BT_INTCONSTPTR, BT_INTCONST)
+DEF_POINTER_TYPE (BT_FLTPTR, BT_FLT)
DEF_POINTER_TYPE (BT_DBLPTR, BT_DBL)
-DEF_POINTER_TYPE (BT_SHORTCONSTPTR, BT_SHORTCONST)
-DEF_POINTER_TYPE (BT_UCHARCONSTPTR, BT_UCHARCONST)
DEF_POINTER_TYPE (BT_SCHARCONSTPTR, BT_SCHARCONST)
-DEF_POINTER_TYPE (BT_FLTPTR, BT_FLT)
-DEF_DISTINCT_TYPE (BT_BCHAR, BT_UCHAR)
-DEF_DISTINCT_TYPE (BT_BSHORT, BT_USHORT)
+DEF_POINTER_TYPE (BT_UCHARCONSTPTR, BT_UCHARCONST)
+DEF_POINTER_TYPE (BT_SHORTCONSTPTR, BT_SHORTCONST)
+DEF_POINTER_TYPE (BT_USHORTCONSTPTR, BT_USHORTCONST)
DEF_DISTINCT_TYPE (BT_BINT, BT_UINT)
DEF_DISTINCT_TYPE (BT_BLONGLONG, BT_ULONGLONG)
-DEF_OPAQUE_VECTOR_TYPE (BT_BV8HI, BT_BSHORT, 8)
+DEF_DISTINCT_TYPE (BT_BCHAR, BT_UCHAR)
+DEF_DISTINCT_TYPE (BT_BSHORT, BT_USHORT)
DEF_OPAQUE_VECTOR_TYPE (BT_OV4SI, BT_INT, 4)
-DEF_OPAQUE_VECTOR_TYPE (BT_BV16QI, BT_BCHAR, 16)
-DEF_OPAQUE_VECTOR_TYPE (BT_BV2DI, BT_BLONGLONG, 2)
-DEF_OPAQUE_VECTOR_TYPE (BT_OV2DI, BT_LONGLONG, 2)
DEF_OPAQUE_VECTOR_TYPE (BT_OUV4SI, BT_UINT, 4)
DEF_OPAQUE_VECTOR_TYPE (BT_BV4SI, BT_BINT, 4)
+DEF_OPAQUE_VECTOR_TYPE (BT_BV2DI, BT_BLONGLONG, 2)
+DEF_OPAQUE_VECTOR_TYPE (BT_BV16QI, BT_BCHAR, 16)
+DEF_OPAQUE_VECTOR_TYPE (BT_BV8HI, BT_BSHORT, 8)
+DEF_OPAQUE_VECTOR_TYPE (BT_OV2DI, BT_LONGLONG, 2)
DEF_FN_TYPE_0 (BT_FN_INT, BT_INT)
DEF_FN_TYPE_0 (BT_FN_UINT, BT_UINT)
DEF_FN_TYPE_1 (BT_FN_INT_INT, BT_INT, BT_INT)
@@ -312,6 +312,7 @@ DEF_FN_TYPE_3 (BT_FN_V16QI_V8HI_V8HI_INTPTR, BT_V16QI, BT_V8HI, BT_V8HI, BT_INTP
DEF_FN_TYPE_3 (BT_FN_V2DF_UV2DI_INT_INT, BT_V2DF, BT_UV2DI, BT_INT, BT_INT)
DEF_FN_TYPE_3 (BT_FN_V2DF_V2DF_DBL_INT, BT_V2DF, BT_V2DF, BT_DBL, BT_INT)
DEF_FN_TYPE_3 (BT_FN_V2DF_V2DF_UCHAR_UCHAR, BT_V2DF, BT_V2DF, BT_UCHAR, BT_UCHAR)
+DEF_FN_TYPE_3 (BT_FN_V2DF_V2DF_UINT_UINT, BT_V2DF, BT_V2DF, BT_UINT, BT_UINT)
DEF_FN_TYPE_3 (BT_FN_V2DF_V2DF_V2DF_INT, BT_V2DF, BT_V2DF, BT_V2DF, BT_INT)
DEF_FN_TYPE_3 (BT_FN_V2DF_V2DF_V2DF_V2DF, BT_V2DF, BT_V2DF, BT_V2DF, BT_V2DF)
DEF_FN_TYPE_3 (BT_FN_V2DF_V2DI_INT_INT, BT_V2DF, BT_V2DI, BT_INT, BT_INT)
@@ -664,6 +665,7 @@ DEF_OV_TYPE (BT_OV_V2DF_UV2DI_INT, BT_V2DF, BT_UV2DI, BT_INT)
DEF_OV_TYPE (BT_OV_V2DF_V2DF, BT_V2DF, BT_V2DF)
DEF_OV_TYPE (BT_OV_V2DF_V2DF_BV2DI, BT_V2DF, BT_V2DF, BT_BV2DI)
DEF_OV_TYPE (BT_OV_V2DF_V2DF_UCHAR, BT_V2DF, BT_V2DF, BT_UCHAR)
+DEF_OV_TYPE (BT_OV_V2DF_V2DF_UCHAR_UCHAR, BT_V2DF, BT_V2DF, BT_UCHAR, BT_UCHAR)
DEF_OV_TYPE (BT_OV_V2DF_V2DF_UV2DI, BT_V2DF, BT_V2DF, BT_UV2DI)
DEF_OV_TYPE (BT_OV_V2DF_V2DF_UV2DI_DBLCONSTPTR_UCHAR, BT_V2DF, BT_V2DF, BT_UV2DI, BT_DBLCONSTPTR, BT_UCHAR)
DEF_OV_TYPE (BT_OV_V2DF_V2DF_V2DF, BT_V2DF, BT_V2DF, BT_V2DF)
@@ -717,6 +719,7 @@ DEF_OV_TYPE (BT_OV_V4SF_LONG_FLTPTR, BT_V4SF, BT_LONG, BT_FLTPTR)
DEF_OV_TYPE (BT_OV_V4SF_V4SF, BT_V4SF, BT_V4SF)
DEF_OV_TYPE (BT_OV_V4SF_V4SF_BV4SI, BT_V4SF, BT_V4SF, BT_BV4SI)
DEF_OV_TYPE (BT_OV_V4SF_V4SF_UCHAR, BT_V4SF, BT_V4SF, BT_UCHAR)
+DEF_OV_TYPE (BT_OV_V4SF_V4SF_UCHAR_UCHAR, BT_V4SF, BT_V4SF, BT_UCHAR, BT_UCHAR)
DEF_OV_TYPE (BT_OV_V4SF_V4SF_UV4SI, BT_V4SF, BT_V4SF, BT_UV4SI)
DEF_OV_TYPE (BT_OV_V4SF_V4SF_UV4SI_FLTCONSTPTR_UCHAR, BT_V4SF, BT_V4SF, BT_UV4SI, BT_FLTCONSTPTR, BT_UCHAR)
DEF_OV_TYPE (BT_OV_V4SF_V4SF_V4SF, BT_V4SF, BT_V4SF, BT_V4SF)
diff --git a/gcc/config/s390/s390-builtins.def b/gcc/config/s390/s390-builtins.def
index ddcf370..ea561f7 100644
--- a/gcc/config/s390/s390-builtins.def
+++ b/gcc/config/s390/s390-builtins.def
@@ -1621,6 +1621,9 @@ OB_DEF_VAR (s390_vec_xor_s64_c, s390_vx, B_DEP,
OB_DEF_VAR (s390_vec_xor_u64_a, s390_vx, B_DEP, 0, BT_OV_UV2DI_BV2DI_UV2DI)
OB_DEF_VAR (s390_vec_xor_u64_b, s390_vx, 0, 0, BT_OV_UV2DI_UV2DI_UV2DI)
OB_DEF_VAR (s390_vec_xor_u64_c, s390_vx, B_DEP, 0, BT_OV_UV2DI_UV2DI_BV2DI)
+OB_DEF_VAR (s390_vec_xor_flt_a, s390_vx, B_VXE | B_DEP, 0, BT_OV_V4SF_BV4SI_V4SF)
+OB_DEF_VAR (s390_vec_xor_flt_b, s390_vx, B_VXE, 0, BT_OV_V4SF_V4SF_V4SF)
+OB_DEF_VAR (s390_vec_xor_flt_c, s390_vx, B_VXE | B_DEP, 0, BT_OV_V4SF_V4SF_BV4SI)
OB_DEF_VAR (s390_vec_xor_dbl_a, s390_vx, B_DEP, 0, BT_OV_V2DF_BV2DI_V2DF)
OB_DEF_VAR (s390_vec_xor_dbl_b, s390_vx, 0, 0, BT_OV_V2DF_V2DF_V2DF)
OB_DEF_VAR (s390_vec_xor_dbl_c, s390_vx, B_DEP, 0, BT_OV_V2DF_V2DF_BV2DI)
@@ -1701,7 +1704,7 @@ B_DEF (s390_vmxlg, umaxv2di3, 0,
B_DEF (s390_vfmaxsb, vfmaxv4sf, 0, B_VXE, O3_U4, BT_FN_V4SF_V4SF_V4SF_INT)
B_DEF (s390_vfmaxdb, vfmaxv2df, 0, B_VXE, O3_U4, BT_FN_V2DF_V2DF_V2DF_INT)
B_DEF (s390_vfmaxsb_4, smaxv4sf3, 0, B_INT | B_VXE, 0, BT_FN_V4SF_V4SF_V4SF)
-B_DEF (s390_vfmaxdb_4, smaxv2df3, 0, B_INT | B_VXE, 0, BT_FN_V2DF_V2DF_V2DF)
+B_DEF (s390_vfmaxdb_4, smaxv2df3, 0, B_INT | B_VX, 0, BT_FN_V2DF_V2DF_V2DF)
OB_DEF (s390_vec_min, s390_vec_min_s8_a, s390_vec_min_dbl, B_VX, BT_FN_OV4SI_OV4SI_OV4SI)
OB_DEF_VAR (s390_vec_min_s8_a, s390_vmnb, B_DEP, 0, BT_OV_V16QI_BV16QI_V16QI)
@@ -1729,7 +1732,7 @@ OB_DEF_VAR (s390_vec_min_u64_a, s390_vmnlg, B_DEP,
OB_DEF_VAR (s390_vec_min_u64_b, s390_vmnlg, 0, 0, BT_OV_UV2DI_UV2DI_UV2DI)
OB_DEF_VAR (s390_vec_min_u64_c, s390_vmnlg, B_DEP, 0, BT_OV_UV2DI_UV2DI_BV2DI)
OB_DEF_VAR (s390_vec_min_flt, s390_vfminsb_4, B_VXE, 0, BT_OV_V4SF_V4SF_V4SF)
-OB_DEF_VAR (s390_vec_min_dbl, s390_vfmindb_4, B_VXE, 0, BT_OV_V2DF_V2DF_V2DF)
+OB_DEF_VAR (s390_vec_min_dbl, s390_vfmindb_4, 0, 0, BT_OV_V2DF_V2DF_V2DF)
B_DEF (s390_vmnb, sminv16qi3, 0, B_VX, 0, BT_FN_V16QI_BV16QI_V16QI)
B_DEF (s390_vmnlb, uminv16qi3, 0, B_VX, 0, BT_FN_UV16QI_UV16QI_UV16QI)
@@ -1742,7 +1745,7 @@ B_DEF (s390_vmnlg, uminv2di3, 0,
B_DEF (s390_vfminsb, vfminv4sf, 0, B_VXE, O3_U4, BT_FN_V4SF_V4SF_V4SF_INT)
B_DEF (s390_vfmindb, vfminv2df, 0, B_VXE, O3_U4, BT_FN_V2DF_V2DF_V2DF_INT)
B_DEF (s390_vfminsb_4, sminv4sf3, 0, B_INT | B_VXE, 0, BT_FN_V4SF_V4SF_V4SF) /* vfminsb */
-B_DEF (s390_vfmindb_4, sminv2df3, 0, B_INT | B_VXE, 0, BT_FN_V2DF_V2DF_V2DF) /* vfmindb */
+B_DEF (s390_vfmindb_4, sminv2df3, 0, B_INT | B_VX, 0, BT_FN_V2DF_V2DF_V2DF) /* vfmindb */
OB_DEF (s390_vec_mladd, s390_vec_mladd_u8, s390_vec_mladd_s32_c,B_VX, BT_FN_OV4SI_OV4SI_OV4SI_OV4SI)
OB_DEF_VAR (s390_vec_mladd_u8, s390_vmalb, 0, 0, BT_OV_UV16QI_UV16QI_UV16QI_UV16QI)
@@ -2271,7 +2274,7 @@ OB_DEF_VAR (s390_vec_test_mask_dbl, s390_vtm, 0,
B_DEF (s390_vtm, vec_test_mask_intv16qi,0, B_VX, 0, BT_FN_INT_UV16QI_UV16QI)
B_DEF (s390_vec_msum_u128, vec_msumv2di, 0, B_VXE, O4_U2, BT_FN_UV16QI_UV2DI_UV2DI_UV16QI_INT)
-B_DEF (s390_vmslg, vmslg, 0, B_VXE, O4_U2, BT_FN_INT128_UV2DI_UV2DI_INT128_INT)
+B_DEF (s390_vmslg, vmslg, 0, B_VXE, O4_U4, BT_FN_INT128_UV2DI_UV2DI_INT128_INT)
OB_DEF (s390_vec_eqv, s390_vec_eqv_b8, s390_vec_eqv_dbl_c, B_VXE, BT_FN_OV4SI_OV4SI_OV4SI)
OB_DEF_VAR (s390_vec_eqv_b8, s390_vnx, 0, 0, BT_OV_BV16QI_BV16QI_BV16QI)
@@ -2778,6 +2781,10 @@ OB_DEF (s390_vec_ctd, s390_vec_ctd_s64, s390_vec_ctd_u64,
OB_DEF_VAR (s390_vec_ctd_s64, s390_vec_ctd_s64, 0, O2_U5, BT_OV_V2DF_V2DI_INT) /* vcdgb */
OB_DEF_VAR (s390_vec_ctd_u64, s390_vec_ctd_u64, 0, O2_U5, BT_OV_V2DF_UV2DI_INT) /* vcdlgb */
+OB_DEF (s390_vfi, s390_vfi_flt, s390_vfi_dbl, B_VX, BT_FN_V2DF_V2DF_UINT_UINT)
+OB_DEF_VAR (s390_vfi_flt, s390_vfisb, B_VXE, O2_U4 | O3_U3, BT_OV_V4SF_V4SF_UCHAR_UCHAR) /* vfisb */
+OB_DEF_VAR (s390_vfi_dbl, s390_vfidb, 0, O2_U4 | O3_U3, BT_OV_V2DF_V2DF_UCHAR_UCHAR) /* vfidb */
+
B_DEF (s390_vec_ctd_s64, vec_ctd_s64, 0, B_VX, O2_U3, BT_FN_V2DF_V2DI_INT) /* vcdgb */
B_DEF (s390_vec_ctd_u64, vec_ctd_u64, 0, B_VX, O2_U3, BT_FN_V2DF_UV2DI_INT) /* vcdlgb */
B_DEF (s390_vcdgb, vcdgb, 0, B_VX, O2_U4 | O3_U3, BT_FN_V2DF_V2DI_INT_INT)
@@ -2832,13 +2839,13 @@ OB_DEF_VAR (s390_vec_nmsub_dbl, s390_vfnmsdb, 0,
B_DEF (s390_vflnsb, negabsv4sf2, 0, B_VXE, 0, BT_FN_V4SF_V4SF)
B_DEF (s390_vflndb, negabsv2df2, 0, B_VX, 0, BT_FN_V2DF_V2DF)
-OB_DEF (s390_vec_nabs, s390_vec_nabs_flt, s390_vec_nabs_dbl, B_VXE, BT_FN_OV4SI_OV4SI)
-OB_DEF_VAR (s390_vec_nabs_flt, s390_vflnsb, 0, 0, BT_OV_V4SF_V4SF)
-OB_DEF_VAR (s390_vec_nabs_dbl, s390_vflndb, B_VX, 0, BT_OV_V2DF_V2DF)
+OB_DEF (s390_vec_nabs, s390_vec_nabs_flt, s390_vec_nabs_dbl, B_VX, BT_FN_OV4SI_OV4SI)
+OB_DEF_VAR (s390_vec_nabs_flt, s390_vflnsb, B_VXE, 0, BT_OV_V4SF_V4SF)
+OB_DEF_VAR (s390_vec_nabs_dbl, s390_vflndb, 0, 0, BT_OV_V2DF_V2DF)
-OB_DEF (s390_vec_sqrt, s390_vec_sqrt_flt, s390_vec_sqrt_dbl, B_VXE, BT_FN_OV4SI_OV4SI)
-OB_DEF_VAR (s390_vec_sqrt_flt, s390_vfsqsb, 0, 0, BT_OV_V4SF_V4SF)
-OB_DEF_VAR (s390_vec_sqrt_dbl, s390_vfsqdb, B_VX, 0, BT_OV_V2DF_V2DF)
+OB_DEF (s390_vec_sqrt, s390_vec_sqrt_flt, s390_vec_sqrt_dbl, B_VX, BT_FN_OV4SI_OV4SI)
+OB_DEF_VAR (s390_vec_sqrt_flt, s390_vfsqsb, B_VXE, 0, BT_OV_V4SF_V4SF)
+OB_DEF_VAR (s390_vec_sqrt_dbl, s390_vfsqdb, 0, 0, BT_OV_V2DF_V2DF)
/* Test data class with boolean result *AND* cc mode. */
diff --git a/gcc/config/s390/s390.c b/gcc/config/s390/s390.c
index f8cf213..4e08955 100644
--- a/gcc/config/s390/s390.c
+++ b/gcc/config/s390/s390.c
@@ -83,6 +83,7 @@ along with GCC; see the file COPYING3. If not see
#include "symbol-summary.h"
#include "ipa-prop.h"
#include "ipa-fnsummary.h"
+#include "sched-int.h"
/* This file should be included last. */
#include "target-def.h"
@@ -355,6 +356,18 @@ static rtx_insn *last_scheduled_insn;
#define MAX_SCHED_UNITS 3
static int last_scheduled_unit_distance[MAX_SCHED_UNITS];
+#define NUM_SIDES 2
+static int current_side = 1;
+#define LONGRUNNING_THRESHOLD 5
+
+/* Estimate of number of cycles a long-running insn occupies an
+ execution unit. */
+static unsigned fxu_longrunning[NUM_SIDES];
+static unsigned vfu_longrunning[NUM_SIDES];
+
+/* Factor to scale latencies by, determined by measurements. */
+#define LATENCY_FACTOR 4
+
/* The maximum score added for an instruction whose unit hasn't been
in use for MAX_SCHED_MIX_DISTANCE steps. Increase this value to
give instruction mix scheduling more priority over instruction
@@ -1102,11 +1115,11 @@ s390_handle_hotpatch_attribute (tree *node, tree name, tree args,
err = 1;
else if (TREE_CODE (expr) != INTEGER_CST
|| !INTEGRAL_TYPE_P (TREE_TYPE (expr))
- || wi::gtu_p (expr, s390_hotpatch_hw_max))
+ || wi::gtu_p (wi::to_wide (expr), s390_hotpatch_hw_max))
err = 1;
else if (TREE_CODE (expr2) != INTEGER_CST
|| !INTEGRAL_TYPE_P (TREE_TYPE (expr2))
- || wi::gtu_p (expr2, s390_hotpatch_hw_max))
+ || wi::gtu_p (wi::to_wide (expr2), s390_hotpatch_hw_max))
err = 1;
else
err = 0;
@@ -3717,6 +3730,8 @@ s390_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
case vector_stmt:
case vector_load:
case vector_store:
+ case vector_gather_load:
+ case vector_scatter_store:
case vec_to_scalar:
case scalar_to_vec:
case cond_branch_not_taken:
@@ -6396,16 +6411,16 @@ s390_expand_vec_compare (rtx target, enum rtx_code cond,
/* UNLT: a u< b -> !(a >= b) */
case UNLT: cond = GE; neg_p = true; break;
case UNEQ:
- emit_insn (gen_vec_cmpuneqv2df (target, cmp_op1, cmp_op2));
+ emit_insn (gen_vec_cmpuneq (target, cmp_op1, cmp_op2));
return;
case LTGT:
- emit_insn (gen_vec_cmpltgtv2df (target, cmp_op1, cmp_op2));
+ emit_insn (gen_vec_cmpltgt (target, cmp_op1, cmp_op2));
return;
case ORDERED:
- emit_insn (gen_vec_orderedv2df (target, cmp_op1, cmp_op2));
+ emit_insn (gen_vec_ordered (target, cmp_op1, cmp_op2));
return;
case UNORDERED:
- emit_insn (gen_vec_unorderedv2df (target, cmp_op1, cmp_op2));
+ emit_insn (gen_vec_unordered (target, cmp_op1, cmp_op2));
return;
default: break;
}
@@ -11155,6 +11170,183 @@ pass_s390_early_mach::execute (function *fun)
} // anon namespace
+/* Calculate TARGET = REG + OFFSET as s390_emit_prologue would do it.
+ - push too big immediates to the literal pool and annotate the refs
+ - emit frame related notes for stack pointer changes. */
+
+static rtx
+s390_prologue_plus_offset (rtx target, rtx reg, rtx offset, bool frame_related_p)
+{
+ rtx insn;
+ rtx orig_offset = offset;
+
+ gcc_assert (REG_P (target));
+ gcc_assert (REG_P (reg));
+ gcc_assert (CONST_INT_P (offset));
+
+ if (offset == const0_rtx) /* lr/lgr */
+ {
+ insn = emit_move_insn (target, reg);
+ }
+ else if (DISP_IN_RANGE (INTVAL (offset))) /* la */
+ {
+ insn = emit_move_insn (target, gen_rtx_PLUS (Pmode, reg,
+ offset));
+ }
+ else
+ {
+ if (!satisfies_constraint_K (offset) /* ahi/aghi */
+ && (!TARGET_EXTIMM
+ || (!satisfies_constraint_Op (offset) /* alfi/algfi */
+ && !satisfies_constraint_On (offset)))) /* slfi/slgfi */
+ offset = force_const_mem (Pmode, offset);
+
+ if (target != reg)
+ {
+ insn = emit_move_insn (target, reg);
+ RTX_FRAME_RELATED_P (insn) = frame_related_p ? 1 : 0;
+ }
+
+ insn = emit_insn (gen_add2_insn (target, offset));
+
+ if (!CONST_INT_P (offset))
+ {
+ annotate_constant_pool_refs (&PATTERN (insn));
+
+ if (frame_related_p)
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR,
+ gen_rtx_SET (target,
+ gen_rtx_PLUS (Pmode, target,
+ orig_offset)));
+ }
+ }
+
+ RTX_FRAME_RELATED_P (insn) = frame_related_p ? 1 : 0;
+
+ /* If this is a stack adjustment and we are generating a stack clash
+ prologue, then add a REG_STACK_CHECK note to signal that this insn
+ should be left alone. */
+ if (flag_stack_clash_protection && target == stack_pointer_rtx)
+ add_reg_note (insn, REG_STACK_CHECK, const0_rtx);
+
+ return insn;
+}
+
+/* Emit a compare instruction with a volatile memory access as stack
+ probe. It does not waste store tags and does not clobber any
+ registers apart from the condition code. */
+static void
+s390_emit_stack_probe (rtx addr)
+{
+ rtx tmp = gen_rtx_MEM (Pmode, addr);
+ MEM_VOLATILE_P (tmp) = 1;
+ s390_emit_compare (EQ, gen_rtx_REG (Pmode, 0), tmp);
+ emit_insn (gen_blockage ());
+}
+
+/* Use a runtime loop if we have to emit more probes than this. */
+#define MIN_UNROLL_PROBES 3
+
+/* Allocate SIZE bytes of stack space, using TEMP_REG as a temporary
+ if necessary. LAST_PROBE_OFFSET contains the offset of the closest
+ probe relative to the stack pointer.
+
+ Note that SIZE is negative.
+
+ The return value is true if TEMP_REG has been clobbered. */
+static bool
+allocate_stack_space (rtx size, HOST_WIDE_INT last_probe_offset,
+ rtx temp_reg)
+{
+ bool temp_reg_clobbered_p = false;
+ HOST_WIDE_INT probe_interval
+ = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL);
+ HOST_WIDE_INT guard_size
+ = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE);
+
+ if (flag_stack_clash_protection)
+ {
+ if (last_probe_offset + -INTVAL (size) < guard_size)
+ dump_stack_clash_frame_info (NO_PROBE_SMALL_FRAME, true);
+ else
+ {
+ rtx offset = GEN_INT (probe_interval - UNITS_PER_LONG);
+ HOST_WIDE_INT rounded_size = -INTVAL (size) & -probe_interval;
+ HOST_WIDE_INT num_probes = rounded_size / probe_interval;
+ HOST_WIDE_INT residual = -INTVAL (size) - rounded_size;
+
+ if (num_probes < MIN_UNROLL_PROBES)
+ {
+ /* Emit unrolled probe statements. */
+
+ for (unsigned int i = 0; i < num_probes; i++)
+ {
+ s390_prologue_plus_offset (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-probe_interval), true);
+ s390_emit_stack_probe (gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ offset));
+ }
+ dump_stack_clash_frame_info (PROBE_INLINE, residual != 0);
+ }
+ else
+ {
+ /* Emit a loop probing the pages. */
+
+ rtx_code_label *loop_start_label = gen_label_rtx ();
+
+ /* From now on temp_reg will be the CFA register. */
+ s390_prologue_plus_offset (temp_reg, stack_pointer_rtx,
+ GEN_INT (-rounded_size), true);
+ emit_label (loop_start_label);
+
+ s390_prologue_plus_offset (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-probe_interval), false);
+ s390_emit_stack_probe (gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ offset));
+ emit_cmp_and_jump_insns (stack_pointer_rtx, temp_reg,
+ GT, NULL_RTX,
+ Pmode, 1, loop_start_label);
+
+ /* Without this make_edges ICEes. */
+ JUMP_LABEL (get_last_insn ()) = loop_start_label;
+ LABEL_NUSES (loop_start_label) = 1;
+
+ /* That's going to be a NOP since stack pointer and
+ temp_reg are supposed to be the same here. We just
+ emit it to set the CFA reg back to r15. */
+ s390_prologue_plus_offset (stack_pointer_rtx, temp_reg,
+ const0_rtx, true);
+ temp_reg_clobbered_p = true;
+ dump_stack_clash_frame_info (PROBE_LOOP, residual != 0);
+ }
+
+ /* Handle any residual allocation request. */
+ s390_prologue_plus_offset (stack_pointer_rtx,
+ stack_pointer_rtx,
+ GEN_INT (-residual), true);
+ last_probe_offset += residual;
+ if (last_probe_offset >= probe_interval)
+ s390_emit_stack_probe (gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT (residual
+ - UNITS_PER_LONG)));
+
+ return temp_reg_clobbered_p;
+ }
+ }
+
+ /* Subtract frame size from stack pointer. */
+ s390_prologue_plus_offset (stack_pointer_rtx,
+ stack_pointer_rtx,
+ size, true);
+
+ return temp_reg_clobbered_p;
+}
+
/* Expand the prologue into a bunch of separate insns. */
void
@@ -11179,6 +11371,19 @@ s390_emit_prologue (void)
else
temp_reg = gen_rtx_REG (Pmode, 1);
+ /* When probing for stack-clash mitigation, we have to track the distance
+ between the stack pointer and closest known reference.
+
+ Most of the time we have to make a worst case assumption. The
+ only exception is when TARGET_BACKCHAIN is active, in which case
+ we know *sp (offset 0) was written. */
+ HOST_WIDE_INT probe_interval
+ = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL);
+ HOST_WIDE_INT last_probe_offset
+ = (TARGET_BACKCHAIN
+ ? (TARGET_PACKED_STACK ? STACK_POINTER_OFFSET - UNITS_PER_LONG : 0)
+ : probe_interval - (STACK_BOUNDARY / UNITS_PER_WORD));
+
s390_save_gprs_to_fprs ();
/* Save call saved gprs. */
@@ -11190,6 +11395,14 @@ s390_emit_prologue (void)
- cfun_frame_layout.first_save_gpr_slot),
cfun_frame_layout.first_save_gpr,
cfun_frame_layout.last_save_gpr);
+
+ /* This is not 100% correct. If we have more than one register saved,
+ then LAST_PROBE_OFFSET can move even closer to sp. */
+ last_probe_offset
+ = (cfun_frame_layout.gprs_offset +
+ UNITS_PER_LONG * (cfun_frame_layout.first_save_gpr
+ - cfun_frame_layout.first_save_gpr_slot));
+
emit_insn (insn);
}
@@ -11206,6 +11419,8 @@ s390_emit_prologue (void)
if (cfun_fpr_save_p (i))
{
save_fpr (stack_pointer_rtx, offset, i);
+ if (offset < last_probe_offset)
+ last_probe_offset = offset;
offset += 8;
}
else if (!TARGET_PACKED_STACK || cfun->stdarg)
@@ -11219,6 +11434,8 @@ s390_emit_prologue (void)
if (cfun_fpr_save_p (i))
{
insn = save_fpr (stack_pointer_rtx, offset, i);
+ if (offset < last_probe_offset)
+ last_probe_offset = offset;
offset += 8;
/* If f4 and f6 are call clobbered they are saved due to
@@ -11241,6 +11458,8 @@ s390_emit_prologue (void)
if (cfun_fpr_save_p (i))
{
insn = save_fpr (stack_pointer_rtx, offset, i);
+ if (offset < last_probe_offset)
+ last_probe_offset = offset;
RTX_FRAME_RELATED_P (insn) = 1;
offset -= 8;
@@ -11260,10 +11479,11 @@ s390_emit_prologue (void)
if (cfun_frame_layout.frame_size > 0)
{
rtx frame_off = GEN_INT (-cfun_frame_layout.frame_size);
- rtx real_frame_off;
+ rtx_insn *stack_pointer_backup_loc;
+ bool temp_reg_clobbered_p;
if (s390_stack_size)
- {
+ {
HOST_WIDE_INT stack_guard;
if (s390_stack_guard)
@@ -11329,35 +11549,36 @@ s390_emit_prologue (void)
if (s390_warn_dynamicstack_p && cfun->calls_alloca)
warning (0, "%qs uses dynamic stack allocation", current_function_name ());
- /* Save incoming stack pointer into temp reg. */
- if (TARGET_BACKCHAIN || next_fpr)
- insn = emit_insn (gen_move_insn (temp_reg, stack_pointer_rtx));
+ /* Save the location where we could backup the incoming stack
+ pointer. */
+ stack_pointer_backup_loc = get_last_insn ();
- /* Subtract frame size from stack pointer. */
+ temp_reg_clobbered_p = allocate_stack_space (frame_off, last_probe_offset,
+ temp_reg);
- if (DISP_IN_RANGE (INTVAL (frame_off)))
- {
- insn = gen_rtx_SET (stack_pointer_rtx,
- gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- frame_off));
- insn = emit_insn (insn);
- }
- else
+ if (TARGET_BACKCHAIN || next_fpr)
{
- if (!CONST_OK_FOR_K (INTVAL (frame_off)))
- frame_off = force_const_mem (Pmode, frame_off);
-
- insn = emit_insn (gen_add2_insn (stack_pointer_rtx, frame_off));
- annotate_constant_pool_refs (&PATTERN (insn));
+ if (temp_reg_clobbered_p)
+ {
+ /* allocate_stack_space had to make use of temp_reg and
+ we need it to hold a backup of the incoming stack
+ pointer. Calculate back that value from the current
+ stack pointer. */
+ s390_prologue_plus_offset (temp_reg, stack_pointer_rtx,
+ GEN_INT (cfun_frame_layout.frame_size),
+ false);
+ }
+ else
+ {
+ /* allocate_stack_space didn't actually required
+ temp_reg. Insert the stack pointer backup insn
+ before the stack pointer decrement code - knowing now
+ that the value will survive. */
+ emit_insn_after (gen_move_insn (temp_reg, stack_pointer_rtx),
+ stack_pointer_backup_loc);
+ }
}
- RTX_FRAME_RELATED_P (insn) = 1;
- real_frame_off = GEN_INT (-cfun_frame_layout.frame_size);
- add_reg_note (insn, REG_FRAME_RELATED_EXPR,
- gen_rtx_SET (stack_pointer_rtx,
- gen_rtx_PLUS (Pmode, stack_pointer_rtx,
- real_frame_off)));
-
/* Set backchain. */
if (TARGET_BACKCHAIN)
@@ -11381,6 +11602,8 @@ s390_emit_prologue (void)
emit_clobber (addr);
}
}
+ else if (flag_stack_clash_protection)
+ dump_stack_clash_frame_info (NO_PROBE_NO_FRAME, false);
/* Save fprs 8 - 15 (64 bit ABI). */
@@ -14396,6 +14619,28 @@ s390_z10_prevent_earlyload_conflicts (rtx_insn **ready, int *nready_p)
ready[0] = tmp;
}
+/* Returns TRUE if BB is entered via a fallthru edge and all other
+ incoming edges are less than unlikely. */
+static bool
+s390_bb_fallthru_entry_likely (basic_block bb)
+{
+ edge e, fallthru_edge;
+ edge_iterator ei;
+
+ if (!bb)
+ return false;
+
+ fallthru_edge = find_fallthru_edge (bb->preds);
+ if (!fallthru_edge)
+ return false;
+
+ FOR_EACH_EDGE (e, ei, bb->preds)
+ if (e != fallthru_edge
+ && e->probability >= profile_probability::unlikely ())
+ return false;
+
+ return true;
+}
/* The s390_sched_state variable tracks the state of the current or
the last instruction group.
@@ -14404,7 +14649,7 @@ s390_z10_prevent_earlyload_conflicts (rtx_insn **ready, int *nready_p)
3 the last group is complete - normal insns
4 the last group was a cracked/expanded insn */
-static int s390_sched_state;
+static int s390_sched_state = 0;
#define S390_SCHED_STATE_NORMAL 3
#define S390_SCHED_STATE_CRACKED 4
@@ -14545,7 +14790,24 @@ s390_sched_score (rtx_insn *insn)
if (m & unit_mask)
score += (last_scheduled_unit_distance[i] * MAX_SCHED_MIX_SCORE /
MAX_SCHED_MIX_DISTANCE);
+
+ unsigned latency = insn_default_latency (insn);
+
+ int other_side = 1 - current_side;
+
+ /* Try to delay long-running insns when side is busy. */
+ if (latency > LONGRUNNING_THRESHOLD)
+ {
+ if (get_attr_z13_unit_fxu (insn) && fxu_longrunning[current_side]
+ && fxu_longrunning[other_side] <= fxu_longrunning[current_side])
+ score = MAX (0, score - 10);
+
+ if (get_attr_z13_unit_vfu (insn) && vfu_longrunning[current_side]
+ && vfu_longrunning[other_side] <= vfu_longrunning[current_side])
+ score = MAX (0, score - 10);
+ }
}
+
return score;
}
@@ -14664,6 +14926,8 @@ s390_sched_variable_issue (FILE *file, int verbose, rtx_insn *insn, int more)
{
last_scheduled_insn = insn;
+ bool starts_group = false;
+
if (s390_tune >= PROCESSOR_2827_ZEC12
&& reload_completed
&& recog_memoized (insn) >= 0)
@@ -14671,6 +14935,11 @@ s390_sched_variable_issue (FILE *file, int verbose, rtx_insn *insn, int more)
unsigned int mask = s390_get_sched_attrmask (insn);
if ((mask & S390_SCHED_ATTR_MASK_CRACKED) != 0
+ || (mask & S390_SCHED_ATTR_MASK_EXPANDED) != 0
+ || (mask & S390_SCHED_ATTR_MASK_GROUPALONE) != 0)
+ starts_group = true;
+
+ if ((mask & S390_SCHED_ATTR_MASK_CRACKED) != 0
|| (mask & S390_SCHED_ATTR_MASK_EXPANDED) != 0)
s390_sched_state = S390_SCHED_STATE_CRACKED;
else if ((mask & S390_SCHED_ATTR_MASK_ENDGROUP) != 0
@@ -14682,14 +14951,15 @@ s390_sched_variable_issue (FILE *file, int verbose, rtx_insn *insn, int more)
switch (s390_sched_state)
{
case 0:
+ starts_group = true;
+ /* fallthrough */
case 1:
case 2:
+ s390_sched_state++;
+ break;
case S390_SCHED_STATE_NORMAL:
- if (s390_sched_state == S390_SCHED_STATE_NORMAL)
- s390_sched_state = 1;
- else
- s390_sched_state++;
-
+ starts_group = true;
+ s390_sched_state = 1;
break;
case S390_SCHED_STATE_CRACKED:
s390_sched_state = S390_SCHED_STATE_NORMAL;
@@ -14712,6 +14982,27 @@ s390_sched_variable_issue (FILE *file, int verbose, rtx_insn *insn, int more)
last_scheduled_unit_distance[i]++;
}
+ /* If this insn started a new group, the side flipped. */
+ if (starts_group)
+ current_side = current_side ? 0 : 1;
+
+ for (int i = 0; i < 2; i++)
+ {
+ if (fxu_longrunning[i] >= 1)
+ fxu_longrunning[i] -= 1;
+ if (vfu_longrunning[i] >= 1)
+ vfu_longrunning[i] -= 1;
+ }
+
+ unsigned latency = insn_default_latency (insn);
+ if (latency > LONGRUNNING_THRESHOLD)
+ {
+ if (get_attr_z13_unit_fxu (insn))
+ fxu_longrunning[current_side] = latency * LATENCY_FACTOR;
+ else
+ vfu_longrunning[current_side] = latency * LATENCY_FACTOR;
+ }
+
if (verbose > 5)
{
unsigned int sched_mask;
@@ -14768,7 +15059,21 @@ s390_sched_init (FILE *file ATTRIBUTE_UNUSED,
{
last_scheduled_insn = NULL;
memset (last_scheduled_unit_distance, 0, MAX_SCHED_UNITS * sizeof (int));
- s390_sched_state = 0;
+
+ /* If the next basic block is most likely entered via a fallthru edge
+ we keep the last sched state. Otherwise we start a new group.
+ The scheduler traverses basic blocks in "instruction stream" ordering
+ so if we see a fallthru edge here, s390_sched_state will be of its
+ source block.
+
+ current_sched_info->prev_head is the insn before the first insn of the
+ block of insns to be scheduled.
+ */
+ rtx_insn *insn = current_sched_info->prev_head
+ ? NEXT_INSN (current_sched_info->prev_head) : NULL;
+ basic_block bb = insn ? BLOCK_FOR_INSN (insn) : NULL;
+ if (s390_tune < PROCESSOR_2964_Z13 || !s390_bb_fallthru_entry_likely (bb))
+ s390_sched_state = 0;
}
/* This target hook implementation for TARGET_LOOP_UNROLL_ADJUST calculates
@@ -15651,6 +15956,14 @@ s390_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
static machine_mode
s390_preferred_simd_mode (scalar_mode mode)
{
+ if (TARGET_VXE)
+ switch (mode)
+ {
+ case E_SFmode:
+ return V4SFmode;
+ default:;
+ }
+
if (TARGET_VX)
switch (mode)
{
@@ -15698,6 +16011,15 @@ s390_vector_alignment (const_tree type)
return MIN (64, tree_to_shwi (TYPE_SIZE (type)));
}
+/* Implement TARGET_CONSTANT_ALIGNMENT. Alignment on even addresses for
+ LARL instruction. */
+
+static HOST_WIDE_INT
+s390_constant_alignment (const_tree, HOST_WIDE_INT align)
+{
+ return MAX (align, 16);
+}
+
#ifdef HAVE_AS_MACHINE_MACHINEMODE
/* Implement TARGET_ASM_FILE_START. */
static void
@@ -16117,6 +16439,9 @@ s390_asan_shadow_offset (void)
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS s390_can_change_mode_class
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT s390_constant_alignment
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-s390.h"
diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h
index 00652da..15d3390 100644
--- a/gcc/config/s390/s390.h
+++ b/gcc/config/s390/s390.h
@@ -315,7 +315,6 @@ extern const char *s390_host_detect_local_cpu (int argc, const char **argv);
#define EMPTY_FIELD_BOUNDARY 32
/* Alignment on even addresses for LARL instruction. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) (ALIGN) < 16 ? 16 : (ALIGN)
#define DATA_ABI_ALIGNMENT(TYPE, ALIGN) (ALIGN) < 16 ? 16 : (ALIGN)
/* Alignment is not required by the hardware. */
@@ -591,9 +590,6 @@ extern const enum reg_class regclass_map[FIRST_PSEUDO_REGISTER];
/* Offset from stack-pointer to first location of outgoing args. */
#define STACK_POINTER_OFFSET (TARGET_64BIT ? 160 : 96)
-/* Offset within stack frame to start allocating local variables at. */
-#define STARTING_FRAME_OFFSET 0
-
/* Offset from the stack pointer register to an item dynamically
allocated on the stack, e.g., by `alloca'. */
#define STACK_DYNAMIC_OFFSET(FUNDECL) \
diff --git a/gcc/config/s390/vecintrin.h b/gcc/config/s390/vecintrin.h
index 38cc069..80eb2b3 100644
--- a/gcc/config/s390/vecintrin.h
+++ b/gcc/config/s390/vecintrin.h
@@ -113,8 +113,6 @@ __lcbb(const void *ptr, int bndry)
#define vec_unsigned(X) __builtin_s390_vclgdb((X), 0, 0)
#define vec_doublee(X) __builtin_s390_vfll((X))
#define vec_floate(X) __builtin_s390_vflr((X), 0, 0)
-#define vec_madd __builtin_s390_vfmadb
-#define vec_msub __builtin_s390_vfmsdb
#define vec_load_len_r(X,Y) __builtin_s390_vlrl((Y),(X))
#define vec_store_len_r(X,Y) __builtin_s390_vstrl((Y),(X))
@@ -306,6 +304,8 @@ __lcbb(const void *ptr, int bndry)
#define vec_ld2f __builtin_s390_vec_ld2f
#define vec_st2f __builtin_s390_vec_st2f
#define vec_double __builtin_s390_vec_double
+#define vec_madd __builtin_s390_vec_madd
+#define vec_msub __builtin_s390_vec_msub
#define vec_nmadd __builtin_s390_vec_nmadd
#define vec_nmsub __builtin_s390_vec_nmsub
#define vec_nabs __builtin_s390_vec_nabs
diff --git a/gcc/config/s390/vector.md b/gcc/config/s390/vector.md
index 3cf7989..d40bf1e 100644
--- a/gcc/config/s390/vector.md
+++ b/gcc/config/s390/vector.md
@@ -980,15 +980,43 @@
; Pattern used by e.g. popcount
(define_insn "*vec_srb<mode>"
- [(set (match_operand:V_HW 0 "register_operand" "=v")
- (unspec:V_HW [(match_operand:V_HW 1 "register_operand" "v")
- (match_operand:<tointvec> 2 "register_operand" "v")]
- UNSPEC_VEC_SRLB))]
+ [(set (match_operand:V_128 0 "register_operand" "=v")
+ (unspec:V_128 [(match_operand:V_128 1 "register_operand" "v")
+ (match_operand:V16QI 2 "register_operand" "v")]
+ UNSPEC_VEC_SRLB))]
"TARGET_VX"
"vsrlb\t%v0,%v1,%v2"
[(set_attr "op_type" "VRR")])
+; Vector shift left by byte
+
+(define_insn "*vec_slb<mode>"
+ [(set (match_operand:V_128 0 "register_operand" "=v")
+ (unspec:V_128 [(match_operand:V_128 1 "register_operand" "v")
+ (match_operand:V16QI 2 "register_operand" "v")]
+ UNSPEC_VEC_SLB))]
+ "TARGET_VX"
+ "vslb\t%v0,%v1,%v2"
+ [(set_attr "op_type" "VRR")])
+
+; vec_shr is defined as shift towards element 0
+; this means it is a left shift on BE targets!
+(define_expand "vec_shr_<mode>"
+ [(set (match_dup 3)
+ (unspec:V16QI [(match_operand:SI 2 "const_shift_by_byte_operand" "")
+ (const_int 7)
+ (match_dup 3)]
+ UNSPEC_VEC_SET))
+ (set (match_operand:V_128 0 "register_operand" "")
+ (unspec:V_128 [(match_operand:V_128 1 "register_operand" "")
+ (match_dup 3)]
+ UNSPEC_VEC_SLB))]
+ "TARGET_VX"
+ {
+ operands[3] = gen_reg_rtx(V16QImode);
+ })
+
; vmnb, vmnh, vmnf, vmng
(define_insn "smin<mode>3"
[(set (match_operand:VI 0 "register_operand" "=v")
@@ -1065,10 +1093,85 @@
"vmlo<bhfgq>\t%v0,%v1,%v2"
[(set_attr "op_type" "VRR")])
-; vec_widen_umult_hi
-; vec_widen_umult_lo
-; vec_widen_smult_hi
-; vec_widen_smult_lo
+
+; Widening hi/lo multiplications
+
+; The S/390 instructions vml and vmh return the low or high parts of
+; the double sized result elements in the corresponding elements of
+; the target register. That's NOT what the vec_widen_umult_lo/hi
+; patterns are expected to do.
+
+; We emulate the widening lo/hi multiplies with the even/odd versions
+; followed by a vector merge
+
+
+(define_expand "vec_widen_umult_lo_<mode>"
+ [(set (match_dup 3)
+ (unspec:<vec_double> [(match_operand:VI_QHS 1 "register_operand" "%v")
+ (match_operand:VI_QHS 2 "register_operand" "v")]
+ UNSPEC_VEC_UMULT_EVEN))
+ (set (match_dup 4)
+ (unspec:<vec_double> [(match_dup 1) (match_dup 2)]
+ UNSPEC_VEC_UMULT_ODD))
+ (set (match_operand:<vec_double> 0 "register_operand" "=v")
+ (unspec:<vec_double> [(match_dup 3) (match_dup 4)]
+ UNSPEC_VEC_MERGEL))]
+ "TARGET_VX"
+ {
+ operands[3] = gen_reg_rtx (<vec_double>mode);
+ operands[4] = gen_reg_rtx (<vec_double>mode);
+ })
+
+(define_expand "vec_widen_umult_hi_<mode>"
+ [(set (match_dup 3)
+ (unspec:<vec_double> [(match_operand:VI_QHS 1 "register_operand" "%v")
+ (match_operand:VI_QHS 2 "register_operand" "v")]
+ UNSPEC_VEC_UMULT_EVEN))
+ (set (match_dup 4)
+ (unspec:<vec_double> [(match_dup 1) (match_dup 2)]
+ UNSPEC_VEC_UMULT_ODD))
+ (set (match_operand:<vec_double> 0 "register_operand" "=v")
+ (unspec:<vec_double> [(match_dup 3) (match_dup 4)]
+ UNSPEC_VEC_MERGEH))]
+ "TARGET_VX"
+ {
+ operands[3] = gen_reg_rtx (<vec_double>mode);
+ operands[4] = gen_reg_rtx (<vec_double>mode);
+ })
+
+(define_expand "vec_widen_smult_lo_<mode>"
+ [(set (match_dup 3)
+ (unspec:<vec_double> [(match_operand:VI_QHS 1 "register_operand" "%v")
+ (match_operand:VI_QHS 2 "register_operand" "v")]
+ UNSPEC_VEC_SMULT_EVEN))
+ (set (match_dup 4)
+ (unspec:<vec_double> [(match_dup 1) (match_dup 2)]
+ UNSPEC_VEC_SMULT_ODD))
+ (set (match_operand:<vec_double> 0 "register_operand" "=v")
+ (unspec:<vec_double> [(match_dup 3) (match_dup 4)]
+ UNSPEC_VEC_MERGEL))]
+ "TARGET_VX"
+ {
+ operands[3] = gen_reg_rtx (<vec_double>mode);
+ operands[4] = gen_reg_rtx (<vec_double>mode);
+ })
+
+(define_expand "vec_widen_smult_hi_<mode>"
+ [(set (match_dup 3)
+ (unspec:<vec_double> [(match_operand:VI_QHS 1 "register_operand" "%v")
+ (match_operand:VI_QHS 2 "register_operand" "v")]
+ UNSPEC_VEC_SMULT_EVEN))
+ (set (match_dup 4)
+ (unspec:<vec_double> [(match_dup 1) (match_dup 2)]
+ UNSPEC_VEC_SMULT_ODD))
+ (set (match_operand:<vec_double> 0 "register_operand" "=v")
+ (unspec:<vec_double> [(match_dup 3) (match_dup 4)]
+ UNSPEC_VEC_MERGEH))]
+ "TARGET_VX"
+ {
+ operands[3] = gen_reg_rtx (<vec_double>mode);
+ operands[4] = gen_reg_rtx (<vec_double>mode);
+ })
; vec_widen_ushiftl_hi
; vec_widen_ushiftl_lo
@@ -1303,6 +1406,22 @@
operands[3] = gen_reg_rtx (<tointvec>mode);
})
+(define_expand "vec_cmpuneq"
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "register_operand" "")
+ (match_operand 2 "register_operand" "")]
+ "TARGET_VX"
+{
+ if (GET_MODE (operands[1]) == V4SFmode)
+ emit_insn (gen_vec_cmpuneqv4sf (operands[0], operands[1], operands[2]));
+ else if (GET_MODE (operands[1]) == V2DFmode)
+ emit_insn (gen_vec_cmpuneqv2df (operands[0], operands[1], operands[2]));
+ else
+ gcc_unreachable ();
+
+ DONE;
+})
+
; LTGT a <> b -> a > b | b > a
(define_expand "vec_cmpltgt<mode>"
[(set (match_operand:<tointvec> 0 "register_operand" "=v")
@@ -1315,6 +1434,22 @@
operands[3] = gen_reg_rtx (<tointvec>mode);
})
+(define_expand "vec_cmpltgt"
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "register_operand" "")
+ (match_operand 2 "register_operand" "")]
+ "TARGET_VX"
+{
+ if (GET_MODE (operands[1]) == V4SFmode)
+ emit_insn (gen_vec_cmpltgtv4sf (operands[0], operands[1], operands[2]));
+ else if (GET_MODE (operands[1]) == V2DFmode)
+ emit_insn (gen_vec_cmpltgtv2df (operands[0], operands[1], operands[2]));
+ else
+ gcc_unreachable ();
+
+ DONE;
+})
+
; ORDERED (a, b): a >= b | b > a
(define_expand "vec_ordered<mode>"
[(set (match_operand:<tointvec> 0 "register_operand" "=v")
@@ -1327,6 +1462,22 @@
operands[3] = gen_reg_rtx (<tointvec>mode);
})
+(define_expand "vec_ordered"
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "register_operand" "")
+ (match_operand 2 "register_operand" "")]
+ "TARGET_VX"
+{
+ if (GET_MODE (operands[1]) == V4SFmode)
+ emit_insn (gen_vec_orderedv4sf (operands[0], operands[1], operands[2]));
+ else if (GET_MODE (operands[1]) == V2DFmode)
+ emit_insn (gen_vec_orderedv2df (operands[0], operands[1], operands[2]));
+ else
+ gcc_unreachable ();
+
+ DONE;
+})
+
; UNORDERED (a, b): !ORDERED (a, b)
(define_expand "vec_unordered<mode>"
[(set (match_operand:<tointvec> 0 "register_operand" "=v")
@@ -1340,6 +1491,22 @@
operands[3] = gen_reg_rtx (<tointvec>mode);
})
+(define_expand "vec_unordered"
+ [(match_operand 0 "register_operand" "")
+ (match_operand 1 "register_operand" "")
+ (match_operand 2 "register_operand" "")]
+ "TARGET_VX"
+{
+ if (GET_MODE (operands[1]) == V4SFmode)
+ emit_insn (gen_vec_unorderedv4sf (operands[0], operands[1], operands[2]));
+ else if (GET_MODE (operands[1]) == V2DFmode)
+ emit_insn (gen_vec_unorderedv2df (operands[0], operands[1], operands[2]));
+ else
+ gcc_unreachable ();
+
+ DONE;
+})
+
(define_insn "*vec_load_pair<mode>"
[(set (match_operand:V_HW_64 0 "register_operand" "=v,v")
(vec_concat:V_HW_64 (match_operand:<non_vec> 1 "register_operand" "d,v")
@@ -1549,7 +1716,7 @@
"vuphb\t%0,%1"
[(set_attr "op_type" "VRR")])
-(define_insn "vec_unpacks_low_v16qi"
+(define_insn "vec_unpacks_lo_v16qi"
[(set (match_operand:V8HI 0 "register_operand" "=v")
(sign_extend:V8HI
(vec_select:V8QI
@@ -1573,7 +1740,7 @@
"vuplhb\t%0,%1"
[(set_attr "op_type" "VRR")])
-(define_insn "vec_unpacku_low_v16qi"
+(define_insn "vec_unpacku_lo_v16qi"
[(set (match_operand:V8HI 0 "register_operand" "=v")
(zero_extend:V8HI
(vec_select:V8QI
@@ -1678,7 +1845,7 @@
;; vector load lengthened
-; vflls
+; vflls float -> double
(define_insn "*vec_extendv4sf"
[(set (match_operand:V2DF 0 "register_operand" "=v")
(float_extend:V2DF
@@ -1689,6 +1856,34 @@
"vldeb\t%v0,%v1"
[(set_attr "op_type" "VRR")])
+(define_expand "vec_unpacks_lo_v4sf"
+ [(set (match_dup 2)
+ (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "v")
+ (match_dup 1)]
+ UNSPEC_VEC_MERGEL))
+ (set (match_operand:V2DF 0 "register_operand" "=v")
+ (float_extend:V2DF
+ (vec_select:V2SF
+ (match_dup 2)
+ (parallel [(const_int 0) (const_int 2)]))))]
+ "TARGET_VX"
+{ operands[2] = gen_reg_rtx(V4SFmode); })
+
+(define_expand "vec_unpacks_hi_v4sf"
+ [(set (match_dup 2)
+ (unspec:V4SF [(match_operand:V4SF 1 "register_operand" "v")
+ (match_dup 1)]
+ UNSPEC_VEC_MERGEH))
+ (set (match_operand:V2DF 0 "register_operand" "=v")
+ (float_extend:V2DF
+ (vec_select:V2SF
+ (match_dup 2)
+ (parallel [(const_int 0) (const_int 2)]))))]
+ "TARGET_VX"
+{ operands[2] = gen_reg_rtx(V4SFmode); })
+
+
+; double -> long double
(define_insn "*vec_extendv2df"
[(set (match_operand:V1TF 0 "register_operand" "=v")
(float_extend:V1TF
@@ -1699,14 +1894,77 @@
"wflld\t%v0,%v1"
[(set_attr "op_type" "VRR")])
+(define_expand "vec_unpacks_lo_v2df"
+ [(set (match_dup 2)
+ (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "v")
+ (match_dup 1)]
+ UNSPEC_VEC_MERGEL))
+ (set (match_operand:V1TF 0 "register_operand" "=v")
+ (float_extend:V1TF
+ (vec_select:V1DF
+ (match_dup 2)
+ (parallel [(const_int 0)]))))]
+ "TARGET_VXE"
+{ operands[2] = gen_reg_rtx (V2DFmode); })
+
+(define_expand "vec_unpacks_hi_v2df"
+ [(set (match_dup 2)
+ (unspec:V2DF [(match_operand:V2DF 1 "register_operand" "v")
+ (match_dup 1)]
+ UNSPEC_VEC_MERGEH))
+ (set (match_operand:V1TF 0 "register_operand" "=v")
+ (float_extend:V1TF
+ (vec_select:V1DF
+ (match_dup 2)
+ (parallel [(const_int 0)]))))]
+ "TARGET_VXE"
+{ operands[2] = gen_reg_rtx (V2DFmode); })
+
+
+; 2 x v2df -> 1 x v4sf
+(define_expand "vec_pack_trunc_v2df"
+ [(set (match_dup 3)
+ (unspec:V4SF [(match_operand:V2DF 1 "register_operand" "")
+ (const_int VEC_INEXACT)
+ (const_int VEC_RND_CURRENT)]
+ UNSPEC_VEC_VFLR))
+ (set (match_dup 4)
+ (unspec:V4SF [(match_operand:V2DF 2 "register_operand" "")
+ (const_int VEC_INEXACT)
+ (const_int VEC_RND_CURRENT)]
+ UNSPEC_VEC_VFLR))
+ (set (match_dup 6)
+ (unspec:V16QI [(subreg:V16QI (match_dup 3) 0)
+ (subreg:V16QI (match_dup 4) 0)
+ (match_dup 5)]
+ UNSPEC_VEC_PERM))
+ (set (match_operand:V4SF 0 "register_operand" "")
+ (subreg:V4SF (match_dup 6) 0))]
+ "TARGET_VX"
+{
+ rtx constv, perm[16];
+ int i;
+
+ for (i = 0; i < 4; ++i)
+ {
+ perm[i] = GEN_INT (i);
+ perm[i + 4] = GEN_INT (i + 8);
+ perm[i + 8] = GEN_INT (i + 16);
+ perm[i + 12] = GEN_INT (i + 24);
+ }
+ constv = gen_rtx_CONST_VECTOR (V16QImode, gen_rtvec_v (16, perm));
+
+ operands[3] = gen_reg_rtx (V4SFmode);
+ operands[4] = gen_reg_rtx (V4SFmode);
+ operands[5] = force_reg (V16QImode, constv);
+ operands[6] = gen_reg_rtx (V16QImode);
+})
+
; reduc_smin
; reduc_smax
; reduc_umin
; reduc_umax
-; vec_shl vrep + vsl
-; vec_shr
-
; vec_pack_sfix_trunc: convert + pack ?
; vec_pack_ufix_trunc
; vec_unpacks_float_hi
diff --git a/gcc/config/s390/vx-builtins.md b/gcc/config/s390/vx-builtins.md
index 54796df..1149355 100644
--- a/gcc/config/s390/vx-builtins.md
+++ b/gcc/config/s390/vx-builtins.md
@@ -211,9 +211,9 @@
; (vec_select op0) (vec_select op1)
; vmrhb, vmrhh, vmrhf, vmrhg
(define_insn "vec_mergeh<mode>"
- [(set (match_operand:VEC_HW 0 "register_operand" "=v")
- (unspec:VEC_HW [(match_operand:VEC_HW 1 "register_operand" "v")
- (match_operand:VEC_HW 2 "register_operand" "v")]
+ [(set (match_operand:V_128_NOSINGLE 0 "register_operand" "=v")
+ (unspec:V_128_NOSINGLE [(match_operand:V_128_NOSINGLE 1 "register_operand" "v")
+ (match_operand:V_128_NOSINGLE 2 "register_operand" "v")]
UNSPEC_VEC_MERGEH))]
"TARGET_VX"
"vmrh<bhfgq>\t%v0,%1,%2"
@@ -221,9 +221,9 @@
; vmrlb, vmrlh, vmrlf, vmrlg
(define_insn "vec_mergel<mode>"
- [(set (match_operand:VEC_HW 0 "register_operand" "=v")
- (unspec:VEC_HW [(match_operand:VEC_HW 1 "register_operand" "v")
- (match_operand:VEC_HW 2 "register_operand" "v")]
+ [(set (match_operand:V_128_NOSINGLE 0 "register_operand" "=v")
+ (unspec:V_128_NOSINGLE [(match_operand:V_128_NOSINGLE 1 "register_operand" "v")
+ (match_operand:V_128_NOSINGLE 2 "register_operand" "v")]
UNSPEC_VEC_MERGEL))]
"TARGET_VX"
"vmrl<bhfgq>\t%v0,%1,%2"
@@ -1005,15 +1005,16 @@
; Vector shift left by byte
-(define_insn "vec_slb<mode>"
- [(set (match_operand:V_HW 0 "register_operand" "=v")
- (unspec:V_HW [(match_operand:V_HW 1 "register_operand" "v")
- (match_operand:<tointvec> 2 "register_operand" "v")]
+; Pattern definition in vector.md, see vec_vslb
+(define_expand "vec_slb<mode>"
+ [(set (match_operand:V_HW 0 "register_operand" "")
+ (unspec:V_HW [(match_operand:V_HW 1 "register_operand" "")
+ (match_operand:<tointvec> 2 "register_operand" "")]
UNSPEC_VEC_SLB))]
"TARGET_VX"
- "vslb\t%v0,%v1,%v2"
- [(set_attr "op_type" "VRR")])
-
+{
+ PUT_MODE (operands[2], V16QImode);
+})
; Vector shift left double by byte
@@ -1076,14 +1077,16 @@
; Vector shift right logical by byte
-; Pattern definition in vector.md
+; Pattern definition in vector.md, see vec_vsrb
(define_expand "vec_srb<mode>"
[(set (match_operand:V_HW 0 "register_operand" "")
(unspec:V_HW [(match_operand:V_HW 1 "register_operand" "")
(match_operand:<tointvec> 2 "register_operand" "")]
UNSPEC_VEC_SRLB))]
- "TARGET_VX")
-
+ "TARGET_VX"
+{
+ PUT_MODE (operands[2], V16QImode);
+})
; Vector subtract
@@ -1187,7 +1190,7 @@
(match_operand:QI 4 "const_mask_operand" "C")]
UNSPEC_VEC_MSUM))]
"TARGET_VXE"
- "vmslg\t%v0,%v1,%v2,%v3"
+ "vmslg\t%v0,%v1,%v2,%v3,%4"
[(set_attr "op_type" "VRR")])
(define_insn "vmslg"
@@ -1198,7 +1201,7 @@
(match_operand:QI 4 "const_mask_operand" "C")]
UNSPEC_VEC_MSUM))]
"TARGET_VXE"
- "vmslg\t%v0,%v1,%v2,%v3"
+ "vmslg\t%v0,%v1,%v2,%v3,%4"
[(set_attr "op_type" "VRR")])
diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c
index fa9f9ad..3c6d525 100644
--- a/gcc/config/sh/sh.c
+++ b/gcc/config/sh/sh.c
@@ -657,6 +657,9 @@ static const struct attribute_spec sh_attribute_table[] =
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS sh_can_change_mode_class
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h
index a18044d..f5d80da 100644
--- a/gcc/config/sh/sh.h
+++ b/gcc/config/sh/sh.h
@@ -462,12 +462,6 @@ extern const sh_atomic_model& selected_atomic_model (void);
/* The best alignment to use in cases where we have a choice. */
#define FASTEST_ALIGNMENT (32)
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* get_mode_alignment assumes complex values are always held in multiple
registers, but that is not the case on the SH; CQImode and CHImode are
held in a single integer register. */
@@ -1115,10 +1109,6 @@ extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER];
are at negative offsets from the frame pointer. */
#define FRAME_GROWS_DOWNWARD 1
-/* Offset from the frame pointer to the first local variable slot to
- be allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* If we generate an insn to push BYTES bytes,
this says how many the stack pointer really advances by. */
/* Don't define PUSH_ROUNDING, since the hardware doesn't do this.
diff --git a/gcc/config/sparc/sparc.c b/gcc/config/sparc/sparc.c
index 749a7f8..a9945e2 100644
--- a/gcc/config/sparc/sparc.c
+++ b/gcc/config/sparc/sparc.c
@@ -684,6 +684,7 @@ static bool sparc_hard_regno_mode_ok (unsigned int, machine_mode);
static bool sparc_modes_tieable_p (machine_mode, machine_mode);
static bool sparc_can_change_mode_class (machine_mode, machine_mode,
reg_class_t);
+static HOST_WIDE_INT sparc_constant_alignment (const_tree, HOST_WIDE_INT);
#ifdef SUBTARGET_ATTRIBUTE_TABLE
/* Table of valid machine attributes. */
@@ -925,6 +926,9 @@ char sparc_hard_reg_printed[8];
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS sparc_can_change_mode_class
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT sparc_constant_alignment
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Return the memory reference contained in X if any, zero otherwise. */
@@ -5272,8 +5276,9 @@ sparc_compute_frame_size (HOST_WIDE_INT size, int leaf_function)
frame_size = apparent_frame_size = 0;
else
{
- /* We subtract STARTING_FRAME_OFFSET, remember it's negative. */
- apparent_frame_size = ROUND_UP (size - STARTING_FRAME_OFFSET, 8);
+ /* We subtract TARGET_STARTING_FRAME_OFFSET, remember it's negative. */
+ apparent_frame_size
+ = ROUND_UP (size - targetm.starting_frame_offset (), 8);
apparent_frame_size += n_global_fp_regs * 4;
/* We need to add the size of the outgoing argument area. */
@@ -5734,16 +5739,17 @@ sparc_expand_prologue (void)
if (flag_stack_usage_info)
current_function_static_stack_size = size;
- if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
{
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
- sparc_emit_probe_stack_range (STACK_CHECK_PROTECT,
- size - STACK_CHECK_PROTECT);
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+ sparc_emit_probe_stack_range (get_stack_check_protect (),
+ size - get_stack_check_protect ());
}
else if (size > 0)
- sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
+ sparc_emit_probe_stack_range (get_stack_check_protect (), size);
}
if (size == 0)
@@ -5845,16 +5851,17 @@ sparc_flat_expand_prologue (void)
if (flag_stack_usage_info)
current_function_static_stack_size = size;
- if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
+ if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK
+ || flag_stack_clash_protection)
{
if (crtl->is_leaf && !cfun->calls_alloca)
{
- if (size > PROBE_INTERVAL && size > STACK_CHECK_PROTECT)
- sparc_emit_probe_stack_range (STACK_CHECK_PROTECT,
- size - STACK_CHECK_PROTECT);
+ if (size > PROBE_INTERVAL && size > get_stack_check_protect ())
+ sparc_emit_probe_stack_range (get_stack_check_protect (),
+ size - get_stack_check_protect ());
}
else if (size > 0)
- sparc_emit_probe_stack_range (STACK_CHECK_PROTECT, size);
+ sparc_emit_probe_stack_range (get_stack_check_protect (), size);
}
if (sparc_save_local_in_regs_p)
@@ -13427,4 +13434,14 @@ sparc_can_change_mode_class (machine_mode from, machine_mode to,
return true;
}
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+sparc_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST)
+ return MAX (align, FASTEST_ALIGNMENT);
+ return align;
+}
+
#include "gt-sparc.h"
diff --git a/gcc/config/sparc/sparc.h b/gcc/config/sparc/sparc.h
index 946605d..a0b5612 100644
--- a/gcc/config/sparc/sparc.h
+++ b/gcc/config/sparc/sparc.h
@@ -579,12 +579,6 @@ extern enum cmodel sparc_cmodel;
#define STACK_SAVEAREA_MODE(LEVEL) \
((LEVEL) == SAVE_NONLOCAL ? (TARGET_ARCH64 ? TImode : DImode) : Pmode)
-/* Make strings word-aligned so strcpy from constants will be faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
@@ -1049,12 +1043,6 @@ extern char leaf_reg_remap[];
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* Offset of first parameter from the argument pointer register value.
!v9: This is 64 for the ins and locals, plus 4 for the struct-return reg
even if this function isn't going to use it.
diff --git a/gcc/config/spu/spu.c b/gcc/config/spu/spu.c
index a35f0b8..eda7fca 100644
--- a/gcc/config/spu/spu.c
+++ b/gcc/config/spu/spu.c
@@ -1767,7 +1767,7 @@ spu_expand_prologue (void)
if (total_size > 0)
{
- if (flag_stack_check)
+ if (flag_stack_check || flag_stack_clash_protection)
{
/* We compare against total_size-1 because
($sp >= total_size) <=> ($sp > total_size-1) */
@@ -3055,7 +3055,7 @@ spu_sched_adjust_cost (rtx_insn *insn, int dep_type, rtx_insn *dep_insn,
jump_insn. We adjust here so higher cost insns will get scheduled
earlier. */
if (JUMP_P (insn) && dep_type == REG_DEP_ANTI)
- return insn_cost (dep_insn) - 3;
+ return insn_sched_cost (dep_insn) - 3;
return cost;
}
@@ -4159,7 +4159,7 @@ spu_encode_section_info (tree decl, rtx rtl, int first)
which is both 16-byte aligned and padded to a 16-byte boundary. This
would make it safe to store with a single instruction.
We guarantee the alignment and padding for static objects by aligning
- all of them to 16-bytes. (DATA_ALIGNMENT and CONSTANT_ALIGNMENT.)
+ all of them to 16-bytes. (DATA_ALIGNMENT and TARGET_CONSTANT_ALIGNMENT.)
FIXME: We currently cannot guarantee this for objects on the stack
because assign_parm_setup_stack calls assign_stack_local with the
alignment of the parameter mode and in that case the alignment never
@@ -5390,7 +5390,7 @@ spu_allocate_stack (rtx op0, rtx op1)
emit_insn (gen_spu_convert (sp, stack_pointer_rtx));
emit_insn (gen_subv4si3 (sp, sp, splatted));
- if (flag_stack_check)
+ if (flag_stack_check || flag_stack_clash_protection)
{
rtx avail = gen_reg_rtx(SImode);
rtx result = gen_reg_rtx(SImode);
@@ -6640,6 +6640,8 @@ spu_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost,
return 2;
case unaligned_load:
+ case vector_gather_load:
+ case vector_scatter_store:
return 2;
case cond_branch_taken:
@@ -7193,6 +7195,18 @@ spu_truly_noop_truncation (unsigned int outprec, unsigned int inprec)
{
return inprec <= 32 && outprec <= inprec;
}
+
+/* Implement TARGET_CONSTANT_ALIGNMENT.
+
+ Make all static objects 16-byte aligned. This allows us to assume
+ they are also padded to 16 bytes, which means we can use a single
+ load or store instruction to access them. */
+
+static HOST_WIDE_INT
+spu_constant_alignment (const_tree, HOST_WIDE_INT align)
+{
+ return MAX (align, 128);
+}
/* Table of machine attributes. */
static const struct attribute_spec spu_attribute_table[] =
@@ -7433,6 +7447,9 @@ static const struct attribute_spec spu_attribute_table[] =
#undef TARGET_TRULY_NOOP_TRUNCATION
#define TARGET_TRULY_NOOP_TRUNCATION spu_truly_noop_truncation
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT spu_constant_alignment
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-spu.h"
diff --git a/gcc/config/spu/spu.h b/gcc/config/spu/spu.h
index 4cf426b..cf99b88 100644
--- a/gcc/config/spu/spu.h
+++ b/gcc/config/spu/spu.h
@@ -96,7 +96,6 @@ extern GTY(()) int spu_tune;
on the stack. (Except a bug (?) allows some stack objects to be
unaligned.) */
#define DATA_ALIGNMENT(TYPE,ALIGN) ((ALIGN) > 128 ? (ALIGN) : 128)
-#define CONSTANT_ALIGNMENT(TYPE,ALIGN) ((ALIGN) > 128 ? (ALIGN) : 128)
#define LOCAL_ALIGNMENT(TYPE,ALIGN) ((ALIGN) > 128 ? (ALIGN) : 128)
#define EMPTY_FIELD_BOUNDARY 32
@@ -223,8 +222,6 @@ targetm.resolve_overloaded_builtin = spu_resolve_overloaded_builtin; \
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET (0)
-
#define STACK_POINTER_OFFSET 32
#define FIRST_PARM_OFFSET(FNDECL) (0)
diff --git a/gcc/config/stormy16/stormy16.c b/gcc/config/stormy16/stormy16.c
index 89f474e..d0bd433 100644
--- a/gcc/config/stormy16/stormy16.c
+++ b/gcc/config/stormy16/stormy16.c
@@ -2715,6 +2715,9 @@ xstormy16_modes_tieable_p (machine_mode mode1, machine_mode mode2)
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P xstormy16_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-stormy16.h"
diff --git a/gcc/config/stormy16/stormy16.h b/gcc/config/stormy16/stormy16.h
index 0f19686..3f8a535 100644
--- a/gcc/config/stormy16/stormy16.h
+++ b/gcc/config/stormy16/stormy16.h
@@ -87,10 +87,6 @@
&& TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
&& (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
-
#define STRICT_ALIGNMENT 1
#define PCC_BITFIELD_TYPE_MATTERS 1
@@ -220,8 +216,6 @@ enum reg_class
#define ARGS_GROW_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
-
#define FIRST_PARM_OFFSET(FUNDECL) 0
#define RETURN_ADDR_RTX(COUNT, FRAMEADDR) \
diff --git a/gcc/config/t-netbsd b/gcc/config/t-netbsd
new file mode 100644
index 0000000..770895b
--- /dev/null
+++ b/gcc/config/t-netbsd
@@ -0,0 +1,21 @@
+# Copyright (C) 2017 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
+# <http://www.gnu.org/licenses/>.
+
+netbsd.o: $(srcdir)/config/netbsd.c
+ $(COMPILE) $<
+ $(POSTCOMPILE)
diff --git a/gcc/config/tilegx/tilegx.c b/gcc/config/tilegx/tilegx.c
index 368821e..63fe340 100644
--- a/gcc/config/tilegx/tilegx.c
+++ b/gcc/config/tilegx/tilegx.c
@@ -5734,6 +5734,9 @@ tilegx_truly_noop_truncation (unsigned int outprec, unsigned int inprec)
#undef TARGET_TRULY_NOOP_TRUNCATION
#define TARGET_TRULY_NOOP_TRUNCATION tilegx_truly_noop_truncation
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-tilegx.h"
diff --git a/gcc/config/tilegx/tilegx.h b/gcc/config/tilegx/tilegx.h
index 55fd89a..ea3c1b3 100644
--- a/gcc/config/tilegx/tilegx.h
+++ b/gcc/config/tilegx/tilegx.h
@@ -94,13 +94,6 @@
#define BIGGEST_FIELD_ALIGNMENT 128
#define WIDEST_HARDWARE_FP_SIZE 64
-/* Make strings word-aligned so strcpy from constants will be
- faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
@@ -249,7 +242,6 @@ enum reg_class
#define STACK_GROWS_DOWNWARD 1
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
#define DYNAMIC_CHAIN_ADDRESS(FRAME) \
plus_constant (Pmode, (FRAME), UNITS_PER_WORD)
diff --git a/gcc/config/tilepro/tilepro.c b/gcc/config/tilepro/tilepro.c
index ae3337b..ee9bc0a 100644
--- a/gcc/config/tilepro/tilepro.c
+++ b/gcc/config/tilepro/tilepro.c
@@ -5091,6 +5091,9 @@ tilepro_file_end (void)
#undef TARGET_CAN_USE_DOLOOP_P
#define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT constant_alignment_word_strings
+
struct gcc_target targetm = TARGET_INITIALIZER;
#include "gt-tilepro.h"
diff --git a/gcc/config/tilepro/tilepro.h b/gcc/config/tilepro/tilepro.h
index 325b2ed..3aa6dc8 100644
--- a/gcc/config/tilepro/tilepro.h
+++ b/gcc/config/tilepro/tilepro.h
@@ -58,13 +58,6 @@
#define FASTEST_ALIGNMENT 32
#define BIGGEST_FIELD_ALIGNMENT 64
-/* Make strings word-aligned so strcpy from constants will be
- faster. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- ((TREE_CODE (EXP) == STRING_CST \
- && (ALIGN) < FASTEST_ALIGNMENT) \
- ? FASTEST_ALIGNMENT : (ALIGN))
-
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
(TREE_CODE (TYPE) == ARRAY_TYPE \
@@ -212,7 +205,6 @@ enum reg_class
#define STACK_GROWS_DOWNWARD 1
#define FRAME_GROWS_DOWNWARD 1
-#define STARTING_FRAME_OFFSET 0
#define DYNAMIC_CHAIN_ADDRESS(FRAME) \
plus_constant (Pmode, (FRAME), UNITS_PER_WORD)
diff --git a/gcc/config/v850/v850.h b/gcc/config/v850/v850.h
index da096f7..5eb2e88 100644
--- a/gcc/config/v850/v850.h
+++ b/gcc/config/v850/v850.h
@@ -398,13 +398,6 @@ enum reg_class
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-
-#define STARTING_FRAME_OFFSET 0
-
/* Offset of first parameter from the argument pointer register value. */
/* Is equal to the size of the saved fp + pc, even if an fp isn't
saved since the value is used before we know. */
diff --git a/gcc/config/vax/elf.h b/gcc/config/vax/elf.h
index 1ff1814..e699c12 100644
--- a/gcc/config/vax/elf.h
+++ b/gcc/config/vax/elf.h
@@ -66,10 +66,6 @@ along with GCC; see the file COPYING3. If not see
16))
-/* Reserve the top of the stack for exception handler stackadj value. */
-#undef STARTING_FRAME_OFFSET
-#define STARTING_FRAME_OFFSET -4
-
/* The VAX wants no space between the case instruction and the jump table. */
#undef ASM_OUTPUT_BEFORE_CASE_LABEL
#define ASM_OUTPUT_BEFORE_CASE_LABEL(FILE, PREFIX, NUM, TABLE)
diff --git a/gcc/config/vax/vax.c b/gcc/config/vax/vax.c
index 5989607..82f13da 100644
--- a/gcc/config/vax/vax.c
+++ b/gcc/config/vax/vax.c
@@ -62,6 +62,7 @@ static void vax_asm_trampoline_template (FILE *);
static void vax_trampoline_init (rtx, tree, rtx);
static int vax_return_pops_args (tree, tree, int);
static bool vax_mode_dependent_address_p (const_rtx, addr_space_t);
+static HOST_WIDE_INT vax_starting_frame_offset (void);
/* Initialize the GCC target structure. */
#undef TARGET_ASM_ALIGNED_HI_OP
@@ -120,6 +121,9 @@ static bool vax_mode_dependent_address_p (const_rtx, addr_space_t);
#undef TARGET_OPTION_OVERRIDE
#define TARGET_OPTION_OVERRIDE vax_option_override
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET vax_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
/* Set global variables as needed for the options enabled. */
@@ -208,7 +212,7 @@ vax_expand_prologue (void)
/* Allocate the local stack frame. */
size = get_frame_size ();
- size -= STARTING_FRAME_OFFSET;
+ size -= vax_starting_frame_offset ();
emit_insn (gen_addsi3 (stack_pointer_rtx,
stack_pointer_rtx, GEN_INT (-size)));
@@ -2179,3 +2183,12 @@ vax_function_arg_advance (cumulative_args_t cum_v, machine_mode mode,
? (GET_MODE_SIZE (mode) + 3) & ~3
: (int_size_in_bytes (type) + 3) & ~3);
}
+
+static HOST_WIDE_INT
+vax_starting_frame_offset (void)
+{
+ /* On ELF targets, reserve the top of the stack for exception handler
+ stackadj value. */
+ return TARGET_ELF ? -4 : 0;
+}
+
diff --git a/gcc/config/vax/vax.h b/gcc/config/vax/vax.h
index 04a865c..990140d 100644
--- a/gcc/config/vax/vax.h
+++ b/gcc/config/vax/vax.h
@@ -228,12 +228,6 @@ enum reg_class { NO_REGS, ALL_REGS, LIM_REG_CLASSES };
goes at a more negative offset in the frame. */
#define FRAME_GROWS_DOWNWARD 1
-/* Offset within stack frame to start allocating local variables at.
- If FRAME_GROWS_DOWNWARD, this is the offset to the END of the
- first local allocated. Otherwise, it is the offset to the BEGINNING
- of the first local allocated. */
-#define STARTING_FRAME_OFFSET 0
-
/* Given an rtx for the address of a frame,
return an rtx for the address of the word in the frame
that holds the dynamic chain--the previous frame's address. */
diff --git a/gcc/config/visium/visium.c b/gcc/config/visium/visium.c
index 4dd66dc..3311dd2 100644
--- a/gcc/config/visium/visium.c
+++ b/gcc/config/visium/visium.c
@@ -237,6 +237,8 @@ static bool visium_modes_tieable_p (machine_mode, machine_mode);
static bool visium_can_change_mode_class (machine_mode, machine_mode,
reg_class_t);
+static HOST_WIDE_INT visium_constant_alignment (const_tree, HOST_WIDE_INT);
+
/* Setup the global target hooks structure. */
#undef TARGET_MAX_ANCHOR_OFFSET
@@ -360,6 +362,9 @@ static bool visium_can_change_mode_class (machine_mode, machine_mode,
#undef TARGET_CAN_CHANGE_MODE_CLASS
#define TARGET_CAN_CHANGE_MODE_CLASS visium_can_change_mode_class
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT visium_constant_alignment
+
struct gcc_target targetm = TARGET_INITIALIZER;
namespace {
@@ -834,6 +839,14 @@ visium_data_alignment (tree type, unsigned int align)
return align;
}
+/* Implement TARGET_CONSTANT_ALIGNMENT. */
+
+static HOST_WIDE_INT
+visium_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ return visium_data_alignment (TREE_TYPE (exp), align);
+}
+
/* Helper function for HARD_REGNO_RENAME_OK (FROM, TO). Return non-zero if
it is OK to rename a hard register FROM to another hard register TO. */
@@ -2925,12 +2938,6 @@ visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
/* This is a btst, the result is in C instead of Z. */
return CCCmode;
- case CONST_INT:
- /* This is a degenerate case, typically an uninitialized variable. */
- gcc_assert (op0 == constm1_rtx);
-
- /* ... fall through ... */
-
case REG:
case AND:
case IOR:
@@ -2947,6 +2954,17 @@ visium_select_cc_mode (enum rtx_code code, rtx op0, rtx op1)
when applied to a comparison with zero. */
return CCmode;
+ /* ??? Cater to the junk RTXes sent by try_merge_compare. */
+ case ASM_OPERANDS:
+ case CALL:
+ case CONST_INT:
+ case LO_SUM:
+ case HIGH:
+ case MEM:
+ case UNSPEC:
+ case ZERO_EXTEND:
+ return CCmode;
+
default:
gcc_unreachable ();
}
diff --git a/gcc/config/visium/visium.h b/gcc/config/visium/visium.h
index 4b086d3..3b229f1 100644
--- a/gcc/config/visium/visium.h
+++ b/gcc/config/visium/visium.h
@@ -236,16 +236,6 @@
this macro is used instead of that alignment to align the object. */
#define DATA_ALIGNMENT(TYPE,ALIGN) visium_data_alignment (TYPE, ALIGN)
-/* `CONSTANT_ALIGNMENT (CONSTANT, BASIC-ALIGN)`
-
- If defined, a C expression to compute the alignment given to a
- constant that is being placed in memory. CONSTANT is the constant
- and BASIC-ALIGN is the alignment that the object would ordinarily
- have. The value of this macro is used instead of that alignment to
- align the object. */
-#define CONSTANT_ALIGNMENT(EXP,ALIGN) \
- visium_data_alignment (TREE_TYPE (EXP), ALIGN)
-
/* `LOCAL_ALIGNMENT (TYPE, BASIC-ALIGN)`
If defined, a C expression to compute the alignment for a variable
@@ -737,17 +727,6 @@ enum reg_class
pointer to a smaller address. */
#define STACK_GROWS_DOWNWARD 1
-/* `STARTING_FRAME_OFFSET'
-
- Offset from the frame pointer to the first local variable slot to
- be allocated.
-
- If `FRAME_GROWS_DOWNWARD', find the next slot's offset by
- subtracting the first slot's length from `STARTING_FRAME_OFFSET'.
- Otherwise, it is found by adding the length of the first slot to
- the value `STARTING_FRAME_OFFSET'. */
-#define STARTING_FRAME_OFFSET 0
-
/* `FIRST_PARM_OFFSET (FUNDECL)'
Offset from the argument pointer register to the first argument's
diff --git a/gcc/config/vms/vms-c.c b/gcc/config/vms/vms-c.c
index c666ad1..278c8e2 100644
--- a/gcc/config/vms/vms-c.c
+++ b/gcc/config/vms/vms-c.c
@@ -418,7 +418,7 @@ vms_c_register_includes (const char *sysroot,
if (!stdinc)
return;
- for (dir = get_added_cpp_dirs (SYSTEM); dir != NULL; dir = dir->next)
+ for (dir = get_added_cpp_dirs (INC_SYSTEM); dir != NULL; dir = dir->next)
{
const char * const *lib;
for (lib = vms_std_modules; *lib != NULL; lib++)
@@ -441,7 +441,7 @@ vms_c_register_includes (const char *sysroot,
p->sysp = 1;
p->construct = vms_construct_include_filename;
p->user_supplied_p = 0;
- add_cpp_dir_path (p, SYSTEM);
+ add_cpp_dir_path (p, INC_SYSTEM);
}
else
free (path);
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index 9c11ae0..1e73b2f 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -181,6 +181,8 @@ static void xtensa_conditional_register_usage (void);
static unsigned int xtensa_hard_regno_nregs (unsigned int, machine_mode);
static bool xtensa_hard_regno_mode_ok (unsigned int, machine_mode);
static bool xtensa_modes_tieable_p (machine_mode, machine_mode);
+static HOST_WIDE_INT xtensa_constant_alignment (const_tree, HOST_WIDE_INT);
+static HOST_WIDE_INT xtensa_starting_frame_offset (void);
@@ -317,6 +319,12 @@ static bool xtensa_modes_tieable_p (machine_mode, machine_mode);
#undef TARGET_MODES_TIEABLE_P
#define TARGET_MODES_TIEABLE_P xtensa_modes_tieable_p
+#undef TARGET_CONSTANT_ALIGNMENT
+#define TARGET_CONSTANT_ALIGNMENT xtensa_constant_alignment
+
+#undef TARGET_STARTING_FRAME_OFFSET
+#define TARGET_STARTING_FRAME_OFFSET xtensa_starting_frame_offset
+
struct gcc_target targetm = TARGET_INITIALIZER;
@@ -4380,4 +4388,29 @@ enum reg_class xtensa_regno_to_class (int regno)
return regno_to_class[regno];
}
+/* Implement TARGET_CONSTANT_ALIGNMENT. Align string constants and
+ constructors to at least a word boundary. The typical use of this
+ macro is to increase alignment for string constants to be word
+ aligned so that 'strcpy' calls that copy constants can be done
+ inline. */
+
+static HOST_WIDE_INT
+xtensa_constant_alignment (const_tree exp, HOST_WIDE_INT align)
+{
+ if ((TREE_CODE (exp) == STRING_CST || TREE_CODE (exp) == CONSTRUCTOR)
+ && !optimize_size)
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
+/* Implement TARGET_STARTING_FRAME_OFFSET. */
+
+static HOST_WIDE_INT
+xtensa_starting_frame_offset (void)
+{
+ if (FRAME_GROWS_DOWNWARD)
+ return 0;
+ return crtl->outgoing_args_size;
+}
+
#include "gt-xtensa.h"
diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h
index 74c5e52..b4cf537 100644
--- a/gcc/config/xtensa/xtensa.h
+++ b/gcc/config/xtensa/xtensa.h
@@ -169,17 +169,6 @@ along with GCC; see the file COPYING3. If not see
bitfields and the structures that contain them. */
#define PCC_BITFIELD_TYPE_MATTERS 1
-/* Align string constants and constructors to at least a word boundary.
- The typical use of this macro is to increase alignment for string
- constants to be word aligned so that 'strcpy' calls that copy
- constants can be done inline. */
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
- (!optimize_size && \
- (TREE_CODE (EXP) == STRING_CST || TREE_CODE (EXP) == CONSTRUCTOR) \
- && (ALIGN) < BITS_PER_WORD \
- ? BITS_PER_WORD \
- : (ALIGN))
-
/* Align arrays, unions and records to at least a word boundary.
One use of this macro is to increase alignment of medium-size
data to make it all fit in fewer cache lines. Another is to
@@ -443,10 +432,6 @@ enum reg_class
#define FRAME_GROWS_DOWNWARD flag_stack_protect
-/* Offset within stack frame to start allocating local variables at. */
-#define STARTING_FRAME_OFFSET \
- (FRAME_GROWS_DOWNWARD ? 0 : crtl->outgoing_args_size)
-
/* The ARG_POINTER and FRAME_POINTER are not real Xtensa registers, so
they are eliminated to either the stack pointer or hard frame pointer. */
#define ELIMINABLE_REGS \
diff --git a/gcc/configure b/gcc/configure
index 13f97cd..aa5937d 100755
--- a/gcc/configure
+++ b/gcc/configure
@@ -4987,7 +4987,7 @@ acx_cv_cc_gcc_supports_ada=no
# Other compilers, like HP Tru64 UNIX cc, exit successfully when
# given a .adb file, but produce no object file. So we must check
# if an object file was really produced to guard against this.
-errors=`(${CC} -I"$srcdir"/ada -c conftest.adb) 2>&1 || echo failure`
+errors=`(${CC} -I"$srcdir"/ada/libgnat -c conftest.adb) 2>&1 || echo failure`
if test x"$errors" = x && test -f conftest.$ac_objext; then
acx_cv_cc_gcc_supports_ada=yes
fi
diff --git a/gcc/configure.ac b/gcc/configure.ac
index 8271138..d905d0d 100644
--- a/gcc/configure.ac
+++ b/gcc/configure.ac
@@ -362,7 +362,7 @@ rm -f a.out a.exe b.out
# Find the native compiler
AC_PROG_CC
AC_PROG_CXX
-ACX_PROG_GNAT([-I"$srcdir"/ada])
+ACX_PROG_GNAT([-I"$srcdir"/ada/libgnat])
# Do configure tests with the C++ compiler, since that's what we build with.
AC_LANG(C++)
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 01a03f9..8c587a3 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,3 +1,432 @@
+2017-10-24 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82466
+ * decl.c (duplicate_decls): Warn for built-in functions declared as
+ non-function, use OPT_Wbuiltin_declaration_mismatch.
+
+ * decl.c (duplicate_decls): Avoid redundant '+' in warning_at.
+
+2017-10-24 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80991
+ * pt.c (value_dependent_expression_p, [TRAIT_EXPR]): Handle
+ a TREE_LIST as TRAIT_EXPR_TYPE2.
+
+2017-10-24 Mukesh Kapoor <mukesh.kapoor@oracle.com>
+ Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82307
+ * cvt.c (type_promotes_to): Implement C++17, 7.6/4, about unscoped
+ enumeration type whose underlying type is fixed.
+
+2017-10-23 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80449
+ * semantics.c (finish_compound_literal): Check do_auto_deduction
+ return value for error_mark_node.
+
+2017-10-23 Jason Merrill <jason@redhat.com>
+
+ PR c++/77369 - wrong noexcept handling in C++14 and below
+ * tree.c (strip_typedefs): Canonicalize TYPE_RAISES_EXCEPTIONS.
+
+2017-10-20 Nathan Sidwell <nathan@acm.org>
+
+ * class.c (layout_class_type): Cleanup as-base creation, determine
+ mode here.
+ (finish_struct_1): ... not here.
+
+2017-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82600
+ * typeck.c (check_return_expr): Don't call
+ maybe_warn_about_returning_address_of_local in templates.
+
+2017-10-17 Nathan Sidwell <nathan@acm.org>
+
+ PR c++/82560
+ * call.c (build_over_call): Don't pass tf_no_cleanup to nested
+ calls.
+
+ PR middle-end/82546
+ * cp-objcp-common.c (cp_tree_size): Reformat. Adjust returns size
+ of TYPE nodes.
+
+2017-10-13 Jason Merrill <jason@redhat.com>
+
+ PR c++/82357 - bit-field in template
+ * tree.c (cp_stabilize_reference): Just return a NON_DEPENDENT_EXPR.
+
+2017-10-13 David Malcolm <dmalcolm@redhat.com>
+
+ * cp-tree.h (maybe_show_extern_c_location): New decl.
+ * decl.c (grokfndecl): When complaining about literal operators
+ with C linkage, issue a note giving the location of the
+ extern "C".
+ * parser.c (cp_parser_new): Initialize new field
+ "innermost_linkage_specification_location".
+ (cp_parser_linkage_specification): Store the location
+ of the linkage specification within the cp_parser.
+ (cp_parser_explicit_specialization): When complaining about
+ template specializations with C linkage, issue a note giving the
+ location of the extern "C".
+ (cp_parser_explicit_template_declaration): Likewise for templates.
+ (maybe_show_extern_c_location): New function.
+ * parser.h (struct cp_parser): New field
+ "innermost_linkage_specification_location".
+
+2017-10-12 Nathan Sidwell <nathan@acm.org>
+
+ * cp-tree.h (cp_expr): Add const operator * and operator->
+ accessors.
+ (cp_tree_node_structure_enum): Delete TS_CP_BINDING,
+ TS_CP_WRAPPER, LAST_TS_CP_ENUM.
+
+2017-10-12 David Malcolm <dmalcolm@redhat.com>
+
+ * parser.c (get_required_cpp_ttype): New function.
+ (cp_parser_error_1): Call it, using the result to call
+ maybe_suggest_missing_token_insertion.
+
+2017-10-12 David Malcolm <dmalcolm@redhat.com>
+
+ * parser.c (get_matching_symbol): Move to before...
+ (cp_parser_error): Split out into...
+ (cp_parser_error_1): ...this new function, merging in content
+ from...
+ (cp_parser_required_error): ...here. Eliminate partial duplicate
+ of body of cp_parser_error in favor of a call to the new
+ cp_parser_error_1 helper function.
+
+2017-10-11 Nathan Sidwell <nathan@acm.org>
+
+ * decl2.c (struct mangled_decl_hash): Use DECL_ASSEMBLER_NAME_RAW.
+ (record_mangling): Likewise.
+
+2017-10-10 Nathan Sidwell <nathan@acm.org>
+
+ * name-lookup.c (extern_c_fns): Rename to ...
+ (extern_c_decls): ... here.
+ (check_extern_c_conflict, extern_c_linkage_bindings): Update.
+ (do_pushdecl): Check extern-c fns and vars.
+
+ * cp-tree.h (default_hash_traits <lang_identifier *>): Delete
+ specialization.
+
+ * decl2.c (struct mangled_decl_hash): New hash traits.
+ (mangled_decls): Make hash_table<mangled_decl_hash>.
+ (generate_mangling_alias, record_mangling): Adjust.
+
+2017-10-10 Jason Merrill <jason@redhat.com>
+
+ More delayed lambda capture fixes.
+ * call.c (add_function_candidate): Use build_address.
+ (build_op_call_1): Call mark_lvalue_use early.
+ (build_over_call): Handle error from build_this.
+ * constexpr.c (cxx_bind_parameters_in_call): Use build_address.
+ (cxx_eval_increment_expression): Don't use rvalue().
+ * cvt.c (convert_to_void): Use mark_discarded_use.
+ * expr.c (mark_use): Handle PARM_DECL, NON_DEPENDENT_EXPR. Fix
+ reference handling. Don't copy the expression.
+ (mark_discarded_use): New.
+ * lambda.c (insert_capture_proxy): Add some sanity checking.
+ (maybe_add_lambda_conv_op): Set cp_unevaluated_operand.
+ * pt.c (register_local_specialization): Add sanity check.
+ * semantics.c (process_outer_var_ref): Fix check for existing proxy.
+ * typeck.c (cp_build_addr_expr_1): Handle error from
+ mark_lvalue_use.
+ (cp_build_modify_expr): Call mark_lvalue_use_nonread, handle error
+ from rvalue.
+
+ Handle generic lambda capture in dependent expressions.
+ * lambda.c (need_generic_capture, dependent_capture_r)
+ (do_dependent_capture): New.
+ * pt.c (processing_nonlambda_template): Use need_generic_capture.
+ * semantics.c (maybe_cleanup_point_expr)
+ (maybe_cleanup_point_expr_void, finish_goto_stmt)
+ (maybe_convert_cond): Call do_dependent_capture.
+ * typeck.c (build_static_cast): Remove dependent capture handling.
+
+ * typeck.c (condition_conversion): Assert !processing_template_decl.
+ * semantics.c (finish_omp_clauses): Don't
+ fold_build_cleanup_point_expr if processing_template_decl.
+ (outer_var_p): A temporary can't be from an outer scope.
+ * pt.c (type_dependent_expression_p): Fix dependency checking of
+ functions without DECL_TEMPLATE_INFO.
+ (instantiate_decl): Use lss_copy.
+ * constexpr.c (is_valid_constexpr_fn): Fix lambdas before C++17.
+
+ * typeck.c (check_return_expr): Check non-dependent conversion in
+ templates.
+ * constraint.cc (check_function_concept): Don't complain about an
+ empty concept if seen_error.
+
+2017-10-10 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * cvt.c (ignore_overflows): Use wi::to_wide when
+ operating on trees as wide_ints.
+ * decl.c (check_array_designated_initializer): Likewise.
+ * mangle.c (write_integer_cst): Likewise.
+ * semantics.c (cp_finish_omp_clause_depend_sink): Likewise.
+
+2017-10-10 Nathan Sidwell <nathan@acm.org>
+
+ * name-lookup.c (set_global_binding): Don't deal with STAT_HACK.
+
+2017-10-06 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/47791
+ * decl.c (finish_function): Take a bool intead of an int; adjust.
+ * cp-tree.h (finish_function): Adjust declaration.
+ * decl2.c (generate_tls_wrapper, finish_objects,
+ finish_static_storage_duration_function): Adjust calls.
+ * lambda.c (maybe_add_lambda_conv_op, finish_lambda_function):
+ Likewise.
+ * method.c (synthesize_method): Likewise.
+ * optimize.c (maybe_thunk_body, maybe_clone_body): Likewise.
+ * pt.c (instantiate_decl): Likewise.
+ * parser.c (cp_parser_function_definition_after_declarator,
+ cp_parser_late_parsing_for_member, cp_parser_omp_declare_reduction):
+ Likewise.
+ (cp_parser_ctor_initializer_opt,
+ cp_parser_ctor_initializer_opt_and_function_body,
+ cp_parser_function_try_block,
+ cp_parser_function_definition_after_declarator,
+ cp_parser_function_transaction): Return void; adjust declarations.
+
+2017-10-06 Nathan Sidwell <nathan@acm.org>
+
+ PR c++/82424
+ * name-lookup.c (check_local_shadow): Don't try and convert
+ dependent types.
+
+2017-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82299
+ * decl.c (reshape_init): Suppress warn_useless_cast for direct enum
+ init.
+ * typeck.c (convert_for_assignment): Likewise.
+
+ P0704R1 - fixing const-qualified pointers to members
+ * typeck2.c (build_m_component_ref): For -std=c++2a allow
+ pointer to const & qualified method on rvalue.
+
+2017-10-06 Nathan Sidwell <nathan@acm.org>
+
+ Use hash_table for extern "C" names
+ * name-lookup.c (extern_c_fns): Use hash_table.
+ (check_extern_c_conflict): Adjust.
+ (c_linkage_bindings): Adjust.
+
+ Use hash_table for namespace bindings
+ * cp-tree.h (struct named_decl_hash): New.
+ (lang_decl_ns): Change type of bindings field.
+ * lex.c (maybe_add_lang_decl_raw): Adjust.
+ * name-lookup.c (find_namespace_slot): Adjust.
+ (do_pushdecl): Push NULL-named namespace.
+ (do_push_nested_namespace): Adjust.
+ (push_namespace): Push anonymous namespace as NULL name.
+
+2017-10-05 Jason Merrill <jason@redhat.com>
+
+ Pass variadic class objects exactly like named by-value args.
+ * call.c (convert_arg_to_ellipsis): Use the result of force_rvalue.
+
+2017-10-05 Nathan Sidwell <nathan@acm.org>
+
+ Warn on MVP declarations
+ * cp-tree.h (struct cp_declarator): Add parenthesized field.
+ * decl.c (grokdeclarator): Warn about unnecessary parens.
+ * parser.c (make_declarator): Init parenthesized field.
+ (cp_parser_direct_declarator): Set parenthesized field.
+
+ Kill IDENTIFIER_GLOBAL_VALUE, SET_IDENTIFIER_GLOBAL_VALUE
+ * cp-tree.h (IDENTIFIER_GLOBAL_VALUE,
+ SET_IDENTIFIER_GLOBAL_VALUE): Delete.
+ * name-lookup.h (set_global_binding): Remove NAME parm.
+ (get_global_binding): New inline fn.
+ * name-lookup.c (set_global_binding): Remove NAME parm. Adjust.
+ (identifier_global_value): Move to ...
+ * cp-objcp-common.c (identifier_global_value): ... here.
+ * class.c (build_ctor_vtbl_group, build_vtbl_initializer): Adjust.
+ * decl.c (record_builtin_type, expand_static_init,
+ grokdeclarator): Adjust.
+ * decl2.c (get_guard, get_local_tls_init_fn, get_tls_init_fn,
+ get_tls_wrapper_fn, maybe_warn_sized_delete): Adjust.
+ * except.c (declare_library_fn, build_throw): Adjust.
+ * init.c (throw_bad_array_length): Adjust.
+ * rtti.c (throw_bad_cast, throw_bad_typeid, get_tinfo_decl): Adjust.
+
+ * decl2.c (record_mangling): Fix spello and formatting from
+ previous patch.
+
+2017-10-04 Nathan Sidwell <nathan@acm.org>
+
+ Give builtin types the correct name.
+ * name-lookup.c (set_global_binding): Assert name is DECL_NAME.
+ * decl.c (record_builtin_type): Reimplement, use new TYPE_DECL for
+ rname.
+
+2017-10-04 Paolo Carlini <paolo.carlini@oracle.com>
+ Andrew Pinski <apinski@cavium.com>
+
+ PR c++/71946
+ * parser.c (cp_parser_lambda_body): Set parser->in_function_body.
+
+2017-10-04 Nathan Sidwell <nathan@acm.org>
+
+ Move mangling aliases out of global namespace.
+ * cp-tree.h (record_mangling): New.
+ (maybe_remove_implicit_alias): Delete.
+ * decl2.c (mangled_decls): New hash map.
+ (generate_mangling_alias): Reimplement using mangled_decls.
+ (record_mangling): New.
+ * mangle.c (decl_implicit_alias_p,
+ maybe_remove_implicit_alias): Delete.
+ (mangle_decl): Use record_mangling.
+ * name-lookup.c (supplement_binding_1): Remove
+ maybe_remove_implicit_alias check.
+
+2017-10-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82373
+ * error.c (dump_function_decl): If show_return, call dump_type_suffix
+ on the same return type dump_type_prefix has been called on.
+
+2017-10-04 Jason Merrill <jason@redhat.com>
+
+ PR c++/81525 - broken handling of auto in generic lambda.
+ * pt.c (tsubst_decl) [VAR_DECL]: Use strip_innermost_template_args.
+
+2017-10-04 Nathan Sidwell <nathan@acm.org>
+
+ * call.c (convert_arg_to_ellipsis): Correct comment about passing
+ by reference.
+
+2017-10-02 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * constexpr.c (cxx_eval_store_expression): Use wi::to_widest
+ when comparing the array bounds with an ARRAY_REF index.
+
+2017-09-30 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/68754
+ * method.c (defaulted_late_check): Early return if the defaulted
+ declaration does not match the expected signature.
+
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ P0683R1 - default member initializers for bit-fields
+ * cp-tree.h (grokbitfield): Add INIT parameter.
+ * parser.c (cp_parser_constant_expression): Add STRICT_P argument,
+ if true, parse a conditional-expression rather than
+ assignment-expression.
+ (cp_parser_member_declaration): For C++11 and later pass true
+ as STRICT_P to cp_parser_constant_expression. Parse C++2A bitfield
+ NSDMIs. Adjust grokbitfield caller. Handle DECL_INITIAL also for
+ DECL_C_BIT_FIELDs.
+ (cp_parser_objc_class_ivars): Adjust grokbitfield caller.
+ * class.c (check_field_decl): Recurse even for DECL_C_BIT_FIELDs.
+ (check_field_decls): Call check_field_decl even for DECL_C_BIT_FIELDs.
+ * decl2.c (grokbitfield): Add INIT parameter, pass it to
+ cp_finish_decl.
+ * pt.c (tsubst_decl): Handle DECL_INITIAL for all FIELD_DECLs, not
+ just non-bitfields.
+
+ * class.c (check_bitfield_decl): Retrieve and clear width from
+ DECL_BIT_FIELD_REPRESENTATIVE rather than DECL_INITIAL.
+ (check_field_decls): Test DECL_BIT_FIELD_REPRESENTATIVE rather than
+ DECL_INITIAL.
+ (remove_zero_width_bit_fields): Adjust comment.
+ * decl2.c (grokbitfield): Stash width into
+ DECL_BIT_FIELD_REPRESENTATIVE rather than DECL_INITIAL.
+ * pt.c (tsubst_decl): For DECL_C_BIT_FIELD, tsubst_expr
+ DECL_BIT_FIELD_REPRESENTATIVE rather than DECL_INITIAL for width.
+
+ * parser.c (cp_parser_member_declaration): Parse attributes before
+ colon of a bitfield in addition to after colon.
+
+ * Make-lang.in (check-c++-all): Test also c++2a.
+
+2017-09-28 Jason Merrill <jason@redhat.com>
+
+ PR c++/56973, DR 696 - capture constant variables only as needed.
+ * expr.c (mark_use): Split out from mark_rvalue_use and
+ mark_lvalue_use. Handle lambda capture of constant variables.
+ (mark_lvalue_use_nonread): New.
+ * semantics.c (process_outer_var_ref): Don't capture a constant
+ variable until forced.
+ * pt.c (processing_nonlambda_template): New.
+ * call.c (build_this): Check it.
+ * decl2.c (grok_array_decl): Call mark_rvalue_use and
+ mark_lvalue_use_nonread.
+ * init.c (constant_value_1): Don't call mark_rvalue_use.
+ * typeck.c (build_static_cast): Handle lambda capture.
+
+ Use local_specializations to find capture proxies.
+ * cp-tree.h (DECL_CAPTURED_VARIABLE): New.
+ * lambda.c (build_capture_proxy): Set it.
+ (add_capture): Pass initializer to build_capture_proxy.
+ (start_lambda_function): Likewise.
+ (insert_capture_proxy): Use register_local_specialization.
+ (is_lambda_ignored_entity): Always ignore proxies.
+ * name-lookup.c (qualify_lookup): Don't check
+ is_lambda_ignored_entity if LOOKUP_HIDDEN is set.
+ * semantics.c (process_outer_var_ref): Use
+ retrieve_local_specialization.
+ * parser.c (cp_parser_lambda_body): Push local_specializations.
+ * pt.c (tsubst_expr): Pass LOOKUP_HIDDEN when looking for a proxy.
+ (tsubst_lambda_expr): Push local_specializations sooner.
+ (tsubst_copy_and_build): Don't register_local_specialization.
+
+ * call.c (build_special_member_call): Use the return value of
+ mark_lvalue_use.
+ * decl.c (compute_array_index_type): Likewise.
+ * parser.c (cp_parser_oacc_wait_list): Likewise.
+ * lambda.c (is_normal_capture_proxy): Handle *this capture.
+ (add_capture): Clarify internal_error message.
+
+2017-09-22 Eric Botcazou <ebotcazou@adacore.com>
+
+ PR bootstrap/81926
+ * cp-objcp-common.c (cp_get_debug_type): Do only one lookup.
+
+2017-09-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/81929
+ * tree.c (struct replace_placeholders_t): Add pset field.
+ (replace_placeholders_r): Call cp_walk_tree with d->pset as
+ last argument instead of NULL. Formatting fix.
+ (replace_placeholders): Add pset variable, add its address
+ into data. Pass &pset instead of NULL to cp_walk_tree.
+
+2017-09-22 David Malcolm <dmalcolm@redhat.com>
+
+ * call.c (get_fndecl_argument_location): New function.
+ (convert_like_real): Use it when complaining about argument type
+ mismatches.
+ * cp-tree.h (struct cp_parameter_declarator): Add "loc" field.
+ * parser.c (make_parameter_declarator): Add "loc" param and use
+ it to initialize the new field.
+ (cp_parser_translation_unit): Add UNKNOWN_LOCATION for "loc" of
+ the "no_parameters" parameter.
+ (cp_parser_parameter_declaration_list): Set the location of the
+ result of grokdeclarator to be the parameter's loc, assuming no
+ errors.
+ (cp_parser_parameter_declaration): Generate a location for the
+ parameter and pass to make_parameter_declarator.
+
+2017-09-20 Nathan Sidwell <nathan@acm.org>
+
+ * name-lookup.c (member_name_cmp): Use DECL_UID for final
+ ordering.
+
+2017-09-20 Jakub Jelinek <jakub@redhat.com>
+
+ P0409R2 - allow lambda capture [=, this]
+ * parser.c (cp_parser_lambda_introducer): For cxx2a don't pedwarn on
+ redundant [=, this].
+
2017-09-18 Jason Merrill <jason@redhat.com>
PR c++/82069 - ICE with lambda in template
diff --git a/gcc/cp/Make-lang.in b/gcc/cp/Make-lang.in
index 24e9d7c..a46845c 100644
--- a/gcc/cp/Make-lang.in
+++ b/gcc/cp/Make-lang.in
@@ -176,7 +176,7 @@ check-c++17:
# Run the testsuite in all standard conformance levels.
check-c++-all:
- $(MAKE) RUNTESTFLAGS="$(RUNTESTFLAGS) --stds=98,11,14,17,concepts" check-g++
+ $(MAKE) RUNTESTFLAGS="$(RUNTESTFLAGS) --stds=98,11,14,17,2a,concepts" check-g++
# Run the testsuite with garbage collection at every opportunity.
check-g++-strict-gc:
diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 4fa0d03..8f33ab5 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -2160,7 +2160,10 @@ add_function_candidate (struct z_candidate **candidates,
else
{
parmtype = build_pointer_type (parmtype);
- arg = build_this (arg);
+ /* We don't use build_this here because we don't want to
+ capture the object argument until we've chosen a
+ non-static member function. */
+ arg = build_address (arg);
argtype = lvalue_type (arg);
}
}
@@ -3362,7 +3365,7 @@ build_this (tree obj)
{
/* In a template, we are only concerned about the type of the
expression, so we can take a shortcut. */
- if (processing_template_decl)
+ if (processing_nonlambda_template ())
return build_address (obj);
return cp_build_addr_expr (obj, tf_warning_or_error);
@@ -4446,14 +4449,17 @@ build_op_call_1 (tree obj, vec<tree, va_gc> **args, tsubst_flags_t complain)
{
struct z_candidate *candidates = 0, *cand;
tree fns, convs, first_mem_arg = NULL_TREE;
- tree type = TREE_TYPE (obj);
bool any_viable_p;
tree result = NULL_TREE;
void *p;
+ obj = mark_lvalue_use (obj);
+
if (error_operand_p (obj))
return error_mark_node;
+ tree type = TREE_TYPE (obj);
+
obj = prep_operand (obj);
if (TYPE_PTRMEMFUNC_P (type))
@@ -6579,6 +6585,30 @@ maybe_print_user_conv_context (conversion *convs)
}
}
+/* Locate the parameter with the given index within FNDECL.
+ ARGNUM is zero based, -1 indicates the `this' argument of a method.
+ Return the location of the FNDECL itself if there are problems. */
+
+static location_t
+get_fndecl_argument_location (tree fndecl, int argnum)
+{
+ int i;
+ tree param;
+
+ /* Locate param by index within DECL_ARGUMENTS (fndecl). */
+ for (i = 0, param = FUNCTION_FIRST_USER_PARM (fndecl);
+ i < argnum && param;
+ i++, param = TREE_CHAIN (param))
+ ;
+
+ /* If something went wrong (e.g. if we have a builtin and thus no arguments),
+ return the location of FNDECL. */
+ if (param == NULL)
+ return DECL_SOURCE_LOCATION (fndecl);
+
+ return DECL_SOURCE_LOCATION (param);
+}
+
/* Perform the conversions in CONVS on the expression EXPR. FN and
ARGNUM are used for diagnostics. ARGNUM is zero based, -1
indicates the `this' argument of a method. INNER is nonzero when
@@ -6680,7 +6710,7 @@ convert_like_real (conversion *convs, tree expr, tree fn, int argnum,
complained = permerror (loc, "invalid conversion from %qH to %qI",
TREE_TYPE (expr), totype);
if (complained && fn)
- inform (DECL_SOURCE_LOCATION (fn),
+ inform (get_fndecl_argument_location (fn, argnum),
" initializing argument %P of %qD", argnum, fn);
return cp_convert (totype, expr, complain);
@@ -7141,13 +7171,9 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
/* In a template (or ill-formed code), we can have an incomplete type
even after require_complete_type_sfinae, in which case we don't know
whether it has trivial copy or not. */
- && COMPLETE_TYPE_P (arg_type))
+ && COMPLETE_TYPE_P (arg_type)
+ && !cp_unevaluated_operand)
{
- /* Build up a real lvalue-to-rvalue conversion in case the
- copy constructor is trivial but not callable. */
- if (!cp_unevaluated_operand && CLASS_TYPE_P (arg_type))
- force_rvalue (arg, complain);
-
/* [expr.call] 5.2.2/7:
Passing a potentially-evaluated argument of class type (Clause 9)
with a non-trivial copy constructor or a non-trivial destructor
@@ -7159,10 +7185,10 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
If the call appears in the context of a sizeof expression,
it is not potentially-evaluated. */
- if (cp_unevaluated_operand == 0
- && (type_has_nontrivial_copy_init (arg_type)
- || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (arg_type)))
+ if (type_has_nontrivial_copy_init (arg_type)
+ || TYPE_HAS_NONTRIVIAL_DESTRUCTOR (arg_type))
{
+ arg = force_rvalue (arg, complain);
if (complain & tf_warning)
warning (OPT_Wconditionally_supported,
"passing objects of non-trivially-copyable "
@@ -7170,6 +7196,11 @@ convert_arg_to_ellipsis (tree arg, tsubst_flags_t complain)
arg_type);
return cp_build_addr_expr (arg, complain);
}
+ /* Build up a real lvalue-to-rvalue conversion in case the
+ copy constructor is trivial but not callable. */
+ else if (CLASS_TYPE_P (arg_type))
+ force_rvalue (arg, complain);
+
}
return arg;
@@ -7686,8 +7717,11 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
}
/* N3276 magic doesn't apply to nested calls. */
- int decltype_flag = (complain & tf_decltype);
+ tsubst_flags_t decltype_flag = (complain & tf_decltype);
complain &= ~tf_decltype;
+ /* No-Cleanup doesn't apply to nested calls either. */
+ tsubst_flags_t no_cleanup_complain = complain;
+ complain &= ~tf_no_cleanup;
/* Find maximum size of vector to hold converted arguments. */
parmlen = list_length (parm);
@@ -7747,6 +7781,9 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
tree converted_arg;
tree base_binfo;
+ if (arg == error_mark_node)
+ return error_mark_node;
+
if (convs[i]->bad_p)
{
if (complain & tf_error)
@@ -7882,7 +7919,7 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
if (flags & LOOKUP_NO_CONVERSION)
conv->user_conv_p = true;
- tsubst_flags_t arg_complain = complain & (~tf_no_cleanup);
+ tsubst_flags_t arg_complain = complain;
if (!conversion_warning)
arg_complain &= ~tf_warning;
@@ -8130,7 +8167,8 @@ build_over_call (struct z_candidate *cand, int flags, tsubst_flags_t complain)
else if (default_ctor_p (fn))
{
if (is_dummy_object (argarray[0]))
- return force_target_expr (DECL_CONTEXT (fn), void_node, complain);
+ return force_target_expr (DECL_CONTEXT (fn), void_node,
+ no_cleanup_complain);
else
return cp_build_indirect_ref (argarray[0], RO_NULL, complain);
}
@@ -8821,7 +8859,7 @@ build_special_member_call (tree instance, tree name, vec<tree, va_gc> **args,
&& (flags & LOOKUP_DELEGATING_CONS))
check_self_delegation (arg);
/* Avoid change of behavior on Wunused-var-2.C. */
- mark_lvalue_use (instance);
+ instance = mark_lvalue_use (instance);
return build2 (INIT_EXPR, class_type, instance, arg);
}
}
@@ -9028,7 +9066,6 @@ build_new_method_call_1 (tree instance, tree fns, vec<tree, va_gc> **args,
static member function. */
instance = mark_type_use (instance);
-
/* Figure out whether to skip the first argument for the error
message we will display to users if an error occurs. We don't
want to display any compiler-generated arguments. The "this"
diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index 97e29c0..9ef5065 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -3231,12 +3231,12 @@ check_bitfield_decl (tree field)
tree w;
/* Extract the declared width of the bitfield, which has been
- temporarily stashed in DECL_INITIAL. */
- w = DECL_INITIAL (field);
+ temporarily stashed in DECL_BIT_FIELD_REPRESENTATIVE by grokbitfield. */
+ w = DECL_BIT_FIELD_REPRESENTATIVE (field);
gcc_assert (w != NULL_TREE);
/* Remove the bit-field width indicator so that the rest of the
- compiler does not treat that value as an initializer. */
- DECL_INITIAL (field) = NULL_TREE;
+ compiler does not treat that value as a qualifier. */
+ DECL_BIT_FIELD_REPRESENTATIVE (field) = NULL_TREE;
/* Detect invalid bit-field type. */
if (!INTEGRAL_OR_ENUMERATION_TYPE_P (type))
@@ -3324,7 +3324,7 @@ check_field_decl (tree field,
{
for (tree fields = TYPE_FIELDS (type); fields;
fields = DECL_CHAIN (fields))
- if (TREE_CODE (fields) == FIELD_DECL && !DECL_C_BIT_FIELD (field))
+ if (TREE_CODE (fields) == FIELD_DECL)
any_default_members |= check_field_decl (fields, t,
cant_have_const_ctor,
no_const_asn_ref);
@@ -3571,7 +3571,8 @@ check_field_decls (tree t, tree *access_decls,
DECL_PACKED (x) = 1;
}
- if (DECL_C_BIT_FIELD (x) && integer_zerop (DECL_INITIAL (x)))
+ if (DECL_C_BIT_FIELD (x)
+ && integer_zerop (DECL_BIT_FIELD_REPRESENTATIVE (x)))
/* We don't treat zero-width bitfields as making a class
non-empty. */
;
@@ -3635,10 +3636,10 @@ check_field_decls (tree t, tree *access_decls,
/* We set DECL_C_BIT_FIELD in grokbitfield.
If the type and width are valid, we'll also set DECL_BIT_FIELD. */
- if ((! DECL_C_BIT_FIELD (x) || ! check_bitfield_decl (x))
- && check_field_decl (x, t,
- cant_have_const_ctor_p,
- no_const_asn_ref_p))
+ if (DECL_C_BIT_FIELD (x))
+ check_bitfield_decl (x);
+
+ if (check_field_decl (x, t, cant_have_const_ctor_p, no_const_asn_ref_p))
{
if (any_default_members
&& TREE_CODE (t) == UNION_TYPE)
@@ -5268,9 +5269,9 @@ remove_zero_width_bit_fields (tree t)
{
if (TREE_CODE (*fieldsp) == FIELD_DECL
&& DECL_C_BIT_FIELD (*fieldsp)
- /* We should not be confused by the fact that grokbitfield
+ /* We should not be confused by the fact that grokbitfield
temporarily sets the width of the bit field into
- DECL_INITIAL (*fieldsp).
+ DECL_BIT_FIELD_REPRESENTATIVE (*fieldsp).
check_bitfield_decl eventually sets DECL_SIZE (*fieldsp)
to that width. */
&& (DECL_SIZE (*fieldsp) == NULL_TREE
@@ -5991,8 +5992,6 @@ layout_class_type (tree t, tree *virtuals_p)
bool last_field_was_bitfield = false;
/* The location at which the next field should be inserted. */
tree *next_field;
- /* T, as a base class. */
- tree base_t;
/* Keep track of the first non-static data member. */
non_static_data_members = TYPE_FIELDS (t);
@@ -6217,15 +6216,11 @@ layout_class_type (tree t, tree *virtuals_p)
that the type is laid out they are no longer important. */
remove_zero_width_bit_fields (t);
- /* Create the version of T used for virtual bases. We do not use
- make_class_type for this version; this is an artificial type. For
- a POD type, we just reuse T. */
if (CLASSTYPE_NON_LAYOUT_POD_P (t) || CLASSTYPE_EMPTY_P (t))
{
- base_t = make_node (TREE_CODE (t));
-
- /* Set the size and alignment for the new type. */
- tree eoc;
+ /* T needs a different layout as a base (eliding virtual bases
+ or whatever). Create that version. */
+ tree base_t = make_node (TREE_CODE (t));
/* If the ABI version is not at least two, and the last
field was a bit-field, RLI may not be on a byte
@@ -6234,7 +6229,7 @@ layout_class_type (tree t, tree *virtuals_p)
indicates the total number of bits used. Therefore,
rli_size_so_far, rather than rli_size_unit_so_far, is
used to compute TYPE_SIZE_UNIT. */
- eoc = end_of_class (t, /*include_virtuals_p=*/0);
+ tree eoc = end_of_class (t, /*include_virtuals_p=*/0);
TYPE_SIZE_UNIT (base_t)
= size_binop (MAX_EXPR,
fold_convert (sizetype,
@@ -6251,7 +6246,8 @@ layout_class_type (tree t, tree *virtuals_p)
SET_TYPE_ALIGN (base_t, rli->record_align);
TYPE_USER_ALIGN (base_t) = TYPE_USER_ALIGN (t);
- /* Copy the fields from T. */
+ /* Copy the non-static data members of T. This will include its
+ direct non-virtual bases & vtable. */
next_field = &TYPE_FIELDS (base_t);
for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
if (TREE_CODE (field) == FIELD_DECL)
@@ -6262,9 +6258,14 @@ layout_class_type (tree t, tree *virtuals_p)
}
*next_field = NULL_TREE;
+ /* We use the base type for trivial assignments, and hence it
+ needs a mode. */
+ compute_record_mode (base_t);
+
+ TYPE_CONTEXT (base_t) = t;
+
/* Record the base version of the type. */
CLASSTYPE_AS_BASE (t) = base_t;
- TYPE_CONTEXT (base_t) = t;
}
else
CLASSTYPE_AS_BASE (t) = t;
@@ -6821,11 +6822,6 @@ finish_struct_1 (tree t)
set_class_bindings (t);
- if (CLASSTYPE_AS_BASE (t) != t)
- /* We use the base type for trivial assignments, and hence it
- needs a mode. */
- compute_record_mode (CLASSTYPE_AS_BASE (t));
-
/* With the layout complete, check for flexible array members and
zero-length arrays that might overlap other members in the final
layout. */
@@ -8911,7 +8907,7 @@ build_ctor_vtbl_group (tree binfo, tree t)
/* See if we've already created this construction vtable group. */
id = mangle_ctor_vtbl_for_type (t, binfo);
- if (IDENTIFIER_GLOBAL_VALUE (id))
+ if (get_global_binding (id))
return;
gcc_assert (!SAME_BINFO_TYPE_P (BINFO_TYPE (binfo), t));
@@ -9293,7 +9289,7 @@ build_vtbl_initializer (tree binfo,
if (!dvirt_fn)
{
tree name = get_identifier ("__cxa_deleted_virtual");
- dvirt_fn = IDENTIFIER_GLOBAL_VALUE (name);
+ dvirt_fn = get_global_binding (name);
if (!dvirt_fn)
dvirt_fn = push_library_fn
(name,
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index a89ee49..5919282 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -196,7 +196,14 @@ is_valid_constexpr_fn (tree fun, bool complain)
}
}
- if (!DECL_CONSTRUCTOR_P (fun))
+ if (LAMBDA_TYPE_P (CP_DECL_CONTEXT (fun)) && cxx_dialect < cxx17)
+ {
+ ret = false;
+ if (complain)
+ inform (DECL_SOURCE_LOCATION (fun),
+ "lambdas are implicitly constexpr only in C++17 and later");
+ }
+ else if (!DECL_CONSTRUCTOR_P (fun))
{
tree rettype = TREE_TYPE (TREE_TYPE (fun));
if (!literal_type_p (rettype))
@@ -1261,7 +1268,10 @@ cxx_bind_parameters_in_call (const constexpr_ctx *ctx, tree t,
&& is_dummy_object (x))
{
x = ctx->object;
- x = cp_build_addr_expr (x, tf_warning_or_error);
+ /* We don't use cp_build_addr_expr here because we don't want to
+ capture the object argument until we've chosen a non-static member
+ function. */
+ x = build_address (x);
}
bool lval = false;
arg = cxx_eval_constant_expression (ctx, x, lval,
@@ -3379,7 +3389,7 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
VERIFY_CONSTANT (nelts);
gcc_assert (TREE_CODE (nelts) == INTEGER_CST
&& TREE_CODE (TREE_OPERAND (probe, 1)) == INTEGER_CST);
- if (wi::eq_p (TREE_OPERAND (probe, 1), nelts))
+ if (wi::to_widest (TREE_OPERAND (probe, 1)) == wi::to_widest (nelts))
{
diag_array_subscript (ctx, ary, TREE_OPERAND (probe, 1));
*non_constant_p = true;
@@ -3635,9 +3645,9 @@ cxx_eval_increment_expression (const constexpr_ctx *ctx, tree t,
non_constant_p, overflow_p);
/* The operand as an rvalue. */
- tree val = rvalue (op);
- val = cxx_eval_constant_expression (ctx, val, false,
- non_constant_p, overflow_p);
+ tree val
+ = cxx_eval_constant_expression (ctx, op, false,
+ non_constant_p, overflow_p);
/* Don't VERIFY_CONSTANT if this might be dealing with a pointer to
a local array in a constexpr function. */
bool ptr = POINTER_TYPE_P (TREE_TYPE (val));
diff --git a/gcc/cp/constraint.cc b/gcc/cp/constraint.cc
index 64a8ea9..8b49455 100644
--- a/gcc/cp/constraint.cc
+++ b/gcc/cp/constraint.cc
@@ -2504,7 +2504,12 @@ check_function_concept (tree fn)
{
location_t loc = DECL_SOURCE_LOCATION (fn);
if (TREE_CODE (body) == STATEMENT_LIST && !STATEMENT_LIST_HEAD (body))
- error_at (loc, "definition of concept %qD is empty", fn);
+ {
+ if (seen_error ())
+ /* The definition was probably erroneous, not empty. */;
+ else
+ error_at (loc, "definition of concept %qD is empty", fn);
+ }
else
error_at (loc, "definition of concept %qD has multiple statements", fn);
}
diff --git a/gcc/cp/cp-objcp-common.c b/gcc/cp/cp-objcp-common.c
index 183e7f7..e051d66 100644
--- a/gcc/cp/cp-objcp-common.c
+++ b/gcc/cp/cp-objcp-common.c
@@ -61,43 +61,34 @@ cxx_warn_unused_global_decl (const_tree decl)
size_t
cp_tree_size (enum tree_code code)
{
+ gcc_checking_assert (code >= NUM_TREE_CODES);
switch (code)
{
- case PTRMEM_CST: return sizeof (struct ptrmem_cst);
- case BASELINK: return sizeof (struct tree_baselink);
+ case PTRMEM_CST: return sizeof (ptrmem_cst);
+ case BASELINK: return sizeof (tree_baselink);
case TEMPLATE_PARM_INDEX: return sizeof (template_parm_index);
- case DEFAULT_ARG: return sizeof (struct tree_default_arg);
- case DEFERRED_NOEXCEPT: return sizeof (struct tree_deferred_noexcept);
- case OVERLOAD: return sizeof (struct tree_overload);
- case STATIC_ASSERT: return sizeof (struct tree_static_assert);
+ case DEFAULT_ARG: return sizeof (tree_default_arg);
+ case DEFERRED_NOEXCEPT: return sizeof (tree_deferred_noexcept);
+ case OVERLOAD: return sizeof (tree_overload);
+ case STATIC_ASSERT: return sizeof (tree_static_assert);
case TYPE_ARGUMENT_PACK:
- case TYPE_PACK_EXPANSION:
- return sizeof (struct tree_common);
-
+ case TYPE_PACK_EXPANSION: return sizeof (tree_type_non_common);
case NONTYPE_ARGUMENT_PACK:
- case EXPR_PACK_EXPANSION:
- return sizeof (struct tree_exp);
-
- case ARGUMENT_PACK_SELECT:
- return sizeof (struct tree_argument_pack_select);
-
- case TRAIT_EXPR:
- return sizeof (struct tree_trait_expr);
-
- case LAMBDA_EXPR: return sizeof (struct tree_lambda_expr);
-
- case TEMPLATE_INFO: return sizeof (struct tree_template_info);
-
- case CONSTRAINT_INFO: return sizeof (struct tree_constraint_info);
-
- case USERDEF_LITERAL: return sizeof (struct tree_userdef_literal);
-
- case TEMPLATE_DECL: return sizeof (struct tree_template_decl);
-
+ case EXPR_PACK_EXPANSION: return sizeof (tree_exp);
+ case ARGUMENT_PACK_SELECT: return sizeof (tree_argument_pack_select);
+ case TRAIT_EXPR: return sizeof (tree_trait_expr);
+ case LAMBDA_EXPR: return sizeof (tree_lambda_expr);
+ case TEMPLATE_INFO: return sizeof (tree_template_info);
+ case CONSTRAINT_INFO: return sizeof (tree_constraint_info);
+ case USERDEF_LITERAL: return sizeof (tree_userdef_literal);
+ case TEMPLATE_DECL: return sizeof (tree_template_decl);
default:
- if (TREE_CODE_CLASS (code) == tcc_declaration)
- return sizeof (struct tree_decl_non_common);
- gcc_unreachable ();
+ switch (TREE_CODE_CLASS (code))
+ {
+ case tcc_declaration: return sizeof (tree_decl_non_common);
+ case tcc_type: return sizeof (tree_type_non_common);
+ default: gcc_unreachable ();
+ }
}
/* NOTREACHED */
}
@@ -162,13 +153,13 @@ cp_get_debug_type (const_tree type)
types on the fly for the debug info only, they would not be attached
to any GC root and always be swept, so we would make the contents of
the debug info depend on the collection points. */
- struct tree_map in, *h;
+ struct tree_map in, *h, **slot;
in.base.from = CONST_CAST_TREE (type);
in.hash = htab_hash_pointer (type);
- h = debug_type_hash->find_with_hash (&in, in.hash);
- if (h)
- return h->to;
+ slot = debug_type_hash->find_slot_with_hash (&in, in.hash, INSERT);
+ if (*slot)
+ return (*slot)->to;
tree t = build_offset_type (TYPE_PTRMEMFUNC_OBJECT_TYPE (type),
TREE_TYPE (TYPE_PTRMEMFUNC_FN_TYPE (type)));
@@ -177,7 +168,7 @@ cp_get_debug_type (const_tree type)
h->base.from = CONST_CAST_TREE (type);
h->hash = htab_hash_pointer (type);
h->to = t;
- *debug_type_hash->find_slot_with_hash (h, h->hash, INSERT) = h;
+ *slot = h;
return t;
}
@@ -400,6 +391,15 @@ cp_pushdecl (tree decl)
return pushdecl (decl);
}
+/* Get the global value binding of NAME. Called directly from
+ c-common.c, not via a hook. */
+
+tree
+identifier_global_value (tree name)
+{
+ return get_global_binding (name);
+}
+
/* Register c++-specific dumps. */
void
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index e508598..b74b6d9 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -65,7 +65,9 @@ public:
/* Implicit conversions to tree. */
operator tree () const { return m_value; }
tree & operator* () { return m_value; }
+ tree operator* () const { return m_value; }
tree & operator-> () { return m_value; }
+ tree operator-> () const { return m_value; }
tree get_value () const { return m_value; }
location_t get_location () const { return m_loc; }
@@ -572,30 +574,6 @@ identifier_p (tree t)
return NULL;
}
-/* Hash trait specialization for lang_identifiers. This allows
- PCH-safe maps keyed by DECL_NAME. If it wasn't for PCH, we could
- just use a regular tree key. */
-
-template <>
-struct default_hash_traits <lang_identifier *>
- : pointer_hash <tree_node>
-{
- /* Use a regular tree as the type, to make using the hash table
- simpler. We'll get dynamic type checking with the hash function
- itself. */
- GTY((skip)) typedef tree value_type;
- GTY((skip)) typedef tree compare_type;
-
- static hashval_t hash (const value_type id)
- {
- return IDENTIFIER_HASH_VALUE (id);
- }
-
- /* Nothing is deletable. Everything is insertable. */
- static bool is_deleted (value_type) { return false; }
- static void remove (value_type) { gcc_unreachable (); }
-};
-
#define LANG_IDENTIFIER_CAST(NODE) \
((struct lang_identifier*)IDENTIFIER_NODE_CHECK (NODE))
@@ -613,11 +591,6 @@ struct GTY(()) ptrmem_cst {
};
typedef struct ptrmem_cst * ptrmem_cst_t;
-#define IDENTIFIER_GLOBAL_VALUE(NODE) \
- get_namespace_binding (NULL_TREE, (NODE))
-#define SET_IDENTIFIER_GLOBAL_VALUE(NODE, VAL) \
- set_global_binding ((NODE), (VAL))
-
#define CLEANUP_P(NODE) TREE_LANG_FLAG_0 (TRY_BLOCK_CHECK (NODE))
#define BIND_EXPR_TRY_BLOCK(NODE) \
@@ -833,6 +806,25 @@ class lkp_iterator : public ovl_iterator
}
};
+/* hash traits for declarations. Hashes potential overload sets via
+ DECL_NAME. */
+
+struct named_decl_hash : ggc_remove <tree>
+{
+ typedef tree value_type; /* A DECL or OVERLOAD */
+ typedef tree compare_type; /* An identifier. */
+
+ inline static hashval_t hash (const value_type decl);
+ inline static bool equal (const value_type existing, compare_type candidate);
+
+ static inline void mark_empty (value_type &p) {p = NULL_TREE;}
+ static inline bool is_empty (value_type p) {return !p;}
+
+ /* Nothing is deletable. Everything is insertable. */
+ static bool is_deleted (value_type) { return false; }
+ static void mark_deleted (value_type) { gcc_unreachable (); }
+};
+
struct GTY(()) tree_template_decl {
struct tree_decl_common common;
tree arguments;
@@ -1477,11 +1469,9 @@ enum cp_tree_node_structure_enum {
TS_CP_IDENTIFIER,
TS_CP_TPI,
TS_CP_PTRMEM,
- TS_CP_BINDING,
TS_CP_OVERLOAD,
TS_CP_BASELINK,
TS_CP_TEMPLATE_DECL,
- TS_CP_WRAPPER,
TS_CP_DEFAULT_ARG,
TS_CP_DEFERRED_NOEXCEPT,
TS_CP_STATIC_ASSERT,
@@ -1490,8 +1480,7 @@ enum cp_tree_node_structure_enum {
TS_CP_LAMBDA_EXPR,
TS_CP_TEMPLATE_INFO,
TS_CP_CONSTRAINT_INFO,
- TS_CP_USERDEF_LITERAL,
- LAST_TS_CP_ENUM
+ TS_CP_USERDEF_LITERAL
};
/* The resulting tree type. */
@@ -2471,10 +2460,12 @@ struct GTY(()) lang_decl_min {
union lang_decl_u2 {
/* In a FUNCTION_DECL for which DECL_THUNK_P holds, this is
THUNK_VIRTUAL_OFFSET.
+ In a VAR_DECL for which DECL_HAS_VALUE_EXPR_P holds,
+ this is DECL_CAPTURED_VARIABLE.
Otherwise this is DECL_ACCESS. */
tree GTY ((tag ("0"))) access;
- /* For VAR_DECL in function, this is DECL_DISCRIMINATOR. */
+ /* For TREE_STATIC VAR_DECL in function, this is DECL_DISCRIMINATOR. */
int GTY ((tag ("1"))) discriminator;
} GTY ((desc ("%0.u.base.u2sel"))) u2;
};
@@ -2551,10 +2542,10 @@ struct GTY(()) lang_decl_ns {
vec<tree, va_gc> *usings;
vec<tree, va_gc> *inlinees;
- /* Map from IDENTIFIER nodes to DECLS. It'd be nice to have this
- inline, but as the hash_map has a dtor, we can't then put this
- struct into a union (until moving to c++11). */
- hash_map<lang_identifier *, tree> *bindings;
+ /* Hash table of bound decls. It'd be nice to have this inline, but
+ as the hash_map has a dtor, we can't then put this struct into a
+ union (until moving to c++11). */
+ hash_table<named_decl_hash> *bindings;
};
/* DECL_LANG_SPECIFIC for parameters. */
@@ -3240,6 +3231,10 @@ extern void decl_shadowed_for_var_insert (tree, tree);
(DECL_LANG_SPECIFIC (VAR_TEMPL_TYPE_FIELD_OR_FUNCTION_DECL_CHECK (NODE)) \
->u.min.template_info)
+/* For a lambda capture proxy, its captured variable. */
+#define DECL_CAPTURED_VARIABLE(NODE) \
+ (LANG_DECL_U2_CHECK (NODE, 0)->access)
+
/* For a VAR_DECL, indicates that the variable is actually a
non-static data member of anonymous union that has been promoted to
variable status. */
@@ -5659,6 +5654,8 @@ struct cp_parameter_declarator {
tree default_argument;
/* True iff this is a template parameter pack. */
bool template_parameter_pack_p;
+ /* Location within source. */
+ location_t loc;
};
/* A declarator. */
@@ -5668,6 +5665,10 @@ struct cp_declarator {
/* Whether we parsed an ellipsis (`...') just before the declarator,
to indicate this is a parameter pack. */
BOOL_BITFIELD parameter_pack_p : 1;
+ /* If this declarator is parenthesized, this the open-paren. It is
+ UNKNOWN_LOCATION when not parenthesized. */
+ location_t parenthesized;
+
location_t id_loc; /* Currently only set for cdk_id, cdk_decomp and
cdk_function. */
/* GNU Attributes that apply to this declarator. If the declarator
@@ -6099,7 +6100,7 @@ extern bool start_function (cp_decl_specifier_seq *,
extern tree begin_function_body (void);
extern void finish_function_body (tree);
extern tree outer_curly_brace_block (tree);
-extern tree finish_function (int);
+extern tree finish_function (bool);
extern tree grokmethod (cp_decl_specifier_seq *, const cp_declarator *, tree);
extern void maybe_register_incomplete_var (tree);
extern void maybe_commonize_var (tree);
@@ -6134,6 +6135,7 @@ extern tree finish_case_label (location_t, tree, tree);
extern tree cxx_maybe_build_cleanup (tree, tsubst_flags_t);
/* in decl2.c */
+extern void record_mangling (tree, bool);
extern void note_mangling_alias (tree, tree);
extern void generate_mangling_aliases (void);
extern tree build_memfn_type (tree, tree, cp_cv_quals, cp_ref_qualifier);
@@ -6151,7 +6153,7 @@ extern void check_member_template (tree);
extern tree grokfield (const cp_declarator *, cp_decl_specifier_seq *,
tree, bool, tree, tree);
extern tree grokbitfield (const cp_declarator *, cp_decl_specifier_seq *,
- tree, tree);
+ tree, tree, tree);
extern bool any_dependent_type_attributes_p (tree);
extern tree cp_reconstruct_complex_type (tree, tree);
extern bool attributes_naming_typedef_ok (tree);
@@ -6241,7 +6243,9 @@ extern tree mark_rvalue_use (tree,
location_t = UNKNOWN_LOCATION,
bool = true);
extern tree mark_lvalue_use (tree);
+extern tree mark_lvalue_use_nonread (tree);
extern tree mark_type_use (tree);
+extern tree mark_discarded_use (tree);
extern void mark_exp_read (tree);
/* friend.c */
@@ -6352,6 +6356,7 @@ extern bool parsing_nsdmi (void);
extern bool parsing_default_capturing_generic_lambda_in_template (void);
extern void inject_this_parameter (tree, cp_cv_quals);
extern location_t defarg_location (tree);
+extern void maybe_show_extern_c_location (void);
/* in pt.c */
extern bool check_template_shadow (tree);
@@ -6404,6 +6409,8 @@ extern tree lookup_template_variable (tree, tree);
extern int uses_template_parms (tree);
extern bool uses_template_parms_level (tree, int);
extern bool in_template_function (void);
+extern bool need_generic_capture (void);
+extern bool processing_nonlambda_template (void);
extern tree instantiate_class_template (tree);
extern tree instantiate_template (tree, tree, tsubst_flags_t);
extern tree fn_type_unification (tree, tree, tree,
@@ -6712,7 +6719,7 @@ extern tree finish_template_type (tree, tree, int);
extern tree finish_base_specifier (tree, tree, bool);
extern void finish_member_declaration (tree);
extern bool outer_automatic_var_p (tree);
-extern tree process_outer_var_ref (tree, tsubst_flags_t);
+extern tree process_outer_var_ref (tree, tsubst_flags_t, bool force_use = false);
extern cp_expr finish_id_expression (tree, tree, tree,
cp_id_kind *,
bool, bool, bool *,
@@ -6791,7 +6798,7 @@ extern tree lambda_function (tree);
extern void apply_deduced_return_type (tree, tree);
extern tree add_capture (tree, tree, tree, bool, bool);
extern tree add_default_capture (tree, tree, tree);
-extern tree build_capture_proxy (tree);
+extern tree build_capture_proxy (tree, tree);
extern void insert_capture_proxy (tree);
extern void insert_pending_capture_proxies (void);
extern bool is_capture_proxy (tree);
@@ -6804,6 +6811,7 @@ extern tree current_nonlambda_function (void);
extern tree nonlambda_method_basetype (void);
extern tree current_nonlambda_scope (void);
extern bool generic_lambda_fn_p (tree);
+extern tree do_dependent_capture (tree, bool = false);
extern bool lambda_fn_in_template_p (tree);
extern void maybe_add_lambda_conv_op (tree);
extern bool is_lambda_ignored_entity (tree);
@@ -7144,7 +7152,6 @@ extern tree add_exception_specifier (tree, tree, int);
extern tree merge_exception_specifiers (tree, tree);
/* in mangle.c */
-extern bool maybe_remove_implicit_alias (tree);
extern void init_mangle (void);
extern void mangle_decl (tree);
extern const char *mangle_type_string (tree);
@@ -7361,6 +7368,20 @@ type_unknown_p (const_tree expr)
return TREE_TYPE (expr) == unknown_type_node;
}
+inline hashval_t
+named_decl_hash::hash (const value_type decl)
+{
+ tree name = OVL_NAME (decl);
+ return name ? IDENTIFIER_HASH_VALUE (name) : 0;
+}
+
+inline bool
+named_decl_hash::equal (const value_type existing, compare_type candidate)
+{
+ tree name = OVL_NAME (existing);
+ return candidate == name;
+}
+
/* -- end of C++ */
#endif /* ! GCC_CP_TREE_H */
diff --git a/gcc/cp/cvt.c b/gcc/cp/cvt.c
index a3bd4a1..9ce094e 100644
--- a/gcc/cp/cvt.c
+++ b/gcc/cp/cvt.c
@@ -582,7 +582,7 @@ ignore_overflows (tree expr, tree orig)
{
gcc_assert (!TREE_OVERFLOW (orig));
/* Ensure constant sharing. */
- expr = wide_int_to_tree (TREE_TYPE (expr), expr);
+ expr = wide_int_to_tree (TREE_TYPE (expr), wi::to_wide (expr));
}
return expr;
}
@@ -1055,24 +1055,10 @@ convert_to_void (tree expr, impl_conv_void implicit, tsubst_flags_t complain)
|| TREE_TYPE (expr) == error_mark_node)
return error_mark_node;
+ expr = mark_discarded_use (expr);
if (implicit == ICV_CAST)
+ /* An explicit cast to void avoids all -Wunused-but-set* warnings. */
mark_exp_read (expr);
- else
- {
- tree exprv = expr;
-
- while (TREE_CODE (exprv) == COMPOUND_EXPR)
- exprv = TREE_OPERAND (exprv, 1);
- if (DECL_P (exprv)
- || handled_component_p (exprv)
- || INDIRECT_REF_P (exprv))
- /* Expr is not being 'used' here, otherwise we whould have
- called mark_{rl}value_use use here, which would have in turn
- called mark_exp_read. Rather, we call mark_exp_read directly
- to avoid some warnings when
- -Wunused-but-set-{variable,parameter} is in effect. */
- mark_exp_read (exprv);
- }
if (!TREE_TYPE (expr))
return expr;
@@ -1848,12 +1834,27 @@ type_promotes_to (tree type)
|| type == char32_type_node
|| type == wchar_type_node)
{
+ tree prom = type;
+
+ if (TREE_CODE (type) == ENUMERAL_TYPE)
+ {
+ prom = ENUM_UNDERLYING_TYPE (prom);
+ if (!ENUM_IS_SCOPED (type)
+ && ENUM_FIXED_UNDERLYING_TYPE_P (type))
+ {
+ /* ISO C++17, 7.6/4. A prvalue of an unscoped enumeration type
+ whose underlying type is fixed (10.2) can be converted to a
+ prvalue of its underlying type. Moreover, if integral promotion
+ can be applied to its underlying type, a prvalue of an unscoped
+ enumeration type whose underlying type is fixed can also be
+ converted to a prvalue of the promoted underlying type. */
+ return type_promotes_to (prom);
+ }
+ }
+
int precision = MAX (TYPE_PRECISION (type),
TYPE_PRECISION (integer_type_node));
tree totype = c_common_type_for_size (precision, 0);
- tree prom = type;
- if (TREE_CODE (prom) == ENUMERAL_TYPE)
- prom = ENUM_UNDERLYING_TYPE (prom);
if (TYPE_UNSIGNED (prom)
&& ! int_fits_type_p (TYPE_MAX_VALUE (prom), totype))
prom = c_common_type_for_size (precision, 1);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 858747e..bb48099 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -1431,7 +1431,15 @@ duplicate_decls (tree newdecl, tree olddecl, bool newdecl_is_friend)
/* Avoid warnings redeclaring built-ins which have not been
explicitly declared. */
if (DECL_ANTICIPATED (olddecl))
- return NULL_TREE;
+ {
+ if (TREE_PUBLIC (newdecl)
+ && CP_DECL_CONTEXT (newdecl) == global_namespace)
+ warning_at (DECL_SOURCE_LOCATION (newdecl),
+ OPT_Wbuiltin_declaration_mismatch,
+ "built-in function %qD declared as non-function",
+ newdecl);
+ return NULL_TREE;
+ }
/* If you declare a built-in or predefined function name as static,
the old definition is overridden, but optionally warn this was a
@@ -1522,7 +1530,7 @@ next_arg:;
warning_at (DECL_SOURCE_LOCATION (newdecl),
OPT_Wbuiltin_declaration_mismatch,
- "declaration of %q+#D conflicts with built-in "
+ "declaration of %q#D conflicts with built-in "
"declaration %q#D", newdecl, olddecl);
}
else if ((DECL_EXTERN_C_P (newdecl)
@@ -2566,7 +2574,7 @@ next_arg:;
DECL_FUNCTION_VERSIONED (newdecl) = 1;
/* newdecl will be purged after copying to olddecl and is no longer
a version. */
- cgraph_node::delete_function_version (newdecl);
+ cgraph_node::delete_function_version_by_decl (newdecl);
}
if (TREE_CODE (newdecl) == FUNCTION_DECL)
@@ -3895,47 +3903,47 @@ make_unbound_class_template (tree context, tree name, tree parm_list,
/* Push the declarations of builtin types into the global namespace.
RID_INDEX is the index of the builtin type in the array
RID_POINTERS. NAME is the name used when looking up the builtin
- type. TYPE is the _TYPE node for the builtin type. */
+ type. TYPE is the _TYPE node for the builtin type.
+
+ The calls to set_global_binding below should be
+ eliminated. Built-in types should not be looked up name; their
+ names are keywords that the parser can recognize. However, there
+ is code in c-common.c that uses identifier_global_value to look up
+ built-in types by name. */
void
record_builtin_type (enum rid rid_index,
const char* name,
tree type)
{
- tree rname = NULL_TREE, tname = NULL_TREE;
- tree tdecl = NULL_TREE;
+ tree decl = NULL_TREE;
- if ((int) rid_index < (int) RID_MAX)
- rname = ridpointers[(int) rid_index];
if (name)
- tname = get_identifier (name);
-
- /* The calls to SET_IDENTIFIER_GLOBAL_VALUE below should be
- eliminated. Built-in types should not be looked up name; their
- names are keywords that the parser can recognize. However, there
- is code in c-common.c that uses identifier_global_value to look
- up built-in types by name. */
- if (tname)
{
- tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL, tname, type);
+ tree tname = get_identifier (name);
+ tree tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL, tname, type);
DECL_ARTIFICIAL (tdecl) = 1;
- SET_IDENTIFIER_GLOBAL_VALUE (tname, tdecl);
+ set_global_binding (tdecl);
+ decl = tdecl;
}
- if (rname)
- {
- if (!tdecl)
+
+ if ((int) rid_index < (int) RID_MAX)
+ if (tree rname = ridpointers[(int) rid_index])
+ if (!decl || DECL_NAME (decl) != rname)
{
- tdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL, rname, type);
- DECL_ARTIFICIAL (tdecl) = 1;
+ tree rdecl = build_decl (BUILTINS_LOCATION, TYPE_DECL, rname, type);
+ DECL_ARTIFICIAL (rdecl) = 1;
+ set_global_binding (rdecl);
+ if (!decl)
+ decl = rdecl;
}
- SET_IDENTIFIER_GLOBAL_VALUE (rname, tdecl);
- }
- if (!TYPE_NAME (type))
- TYPE_NAME (type) = tdecl;
-
- if (tdecl)
- debug_hooks->type_decl (tdecl, 0);
+ if (decl)
+ {
+ if (!TYPE_NAME (type))
+ TYPE_NAME (type) = decl;
+ debug_hooks->type_decl (decl, 0);
+ }
}
/* Push a type into the namespace so that the back ends ignore it. */
@@ -4509,7 +4517,7 @@ build_cp_library_fn_ptr (const char* name, tree type, int ecf_flags)
}
/* Like build_library_fn, but also pushes the function so that we will
- be able to find it via IDENTIFIER_GLOBAL_VALUE. Also, the function
+ be able to find it via get_global_binding. Also, the function
may throw exceptions listed in RAISES. */
tree
@@ -5298,7 +5306,7 @@ check_array_designated_initializer (constructor_elt *ce,
== INTEGER_CST))
{
/* A C99 designator is OK if it matches the current index. */
- if (wi::eq_p (ce_index, index))
+ if (wi::to_wide (ce_index) == index)
return true;
else
sorry ("non-trivial designated initializers not supported");
@@ -6047,7 +6055,10 @@ reshape_init (tree type, tree init, tsubst_flags_t complain)
tree elt = CONSTRUCTOR_ELT (init, 0)->value;
type = cv_unqualified (type);
if (check_narrowing (ENUM_UNDERLYING_TYPE (type), elt, complain))
- return cp_build_c_cast (type, elt, tf_warning_or_error);
+ {
+ warning_sentinel w (warn_useless_cast);
+ return cp_build_c_cast (type, elt, tf_warning_or_error);
+ }
else
return error_mark_node;
}
@@ -6864,6 +6875,8 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
DECL_INITIAL (decl) = NULL_TREE;
}
+ init = do_dependent_capture (init);
+
/* Generally, initializers in templates are expanded when the
template is instantiated. But, if DECL is a variable constant
then it can be used in future constant expressions, so its value
@@ -7824,7 +7837,7 @@ start_cleanup_fn (void)
static void
end_cleanup_fn (void)
{
- expand_or_defer_fn (finish_function (0));
+ expand_or_defer_fn (finish_function (/*inline_p=*/false));
pop_from_top_level ();
}
@@ -8055,9 +8068,9 @@ expand_static_init (tree decl, tree init)
acquire_name = get_identifier ("__cxa_guard_acquire");
release_name = get_identifier ("__cxa_guard_release");
abort_name = get_identifier ("__cxa_guard_abort");
- acquire_fn = identifier_global_value (acquire_name);
- release_fn = identifier_global_value (release_name);
- abort_fn = identifier_global_value (abort_name);
+ acquire_fn = get_global_binding (acquire_name);
+ release_fn = get_global_binding (release_name);
+ abort_fn = get_global_binding (abort_name);
if (!acquire_fn)
acquire_fn = push_library_fn
(acquire_name, build_function_type_list (integer_type_node,
@@ -8724,6 +8737,7 @@ grokfndecl (tree ctype,
if (DECL_LANGUAGE (decl) == lang_c)
{
error ("literal operator with C linkage");
+ maybe_show_extern_c_location ();
return NULL_TREE;
}
@@ -9329,7 +9343,7 @@ compute_array_index_type (tree name, tree size, tsubst_flags_t complain)
{
tree type = TREE_TYPE (size);
- mark_rvalue_use (size);
+ size = mark_rvalue_use (size);
if (cxx_dialect < cxx11 && TREE_CODE (size) == NOP_EXPR
&& TREE_SIDE_EFFECTS (size))
@@ -10126,7 +10140,7 @@ grokdeclarator (const cp_declarator *declarator,
gcc_assert (flags == NO_SPECIAL);
flags = TYPENAME_FLAG;
sfk = sfk_conversion;
- tree glob = IDENTIFIER_GLOBAL_VALUE (dname);
+ tree glob = get_global_binding (dname);
if (glob && TREE_CODE (glob) == TYPE_DECL)
name = identifier_to_locale (IDENTIFIER_POINTER (dname));
else
@@ -10807,6 +10821,13 @@ grokdeclarator (const cp_declarator *declarator,
attr_flags);
}
+ /* We don't want to warn in parmeter context because we don't
+ yet know if the parse will succeed, and this might turn out
+ to be a constructor call. */
+ if (decl_context != PARM
+ && declarator->parenthesized != UNKNOWN_LOCATION)
+ warning_at (declarator->parenthesized, OPT_Wparentheses,
+ "unnecessary parentheses in declaration of %qs", name);
if (declarator->kind == cdk_id || declarator->kind == cdk_decomp)
break;
@@ -15449,20 +15470,16 @@ maybe_save_function_definition (tree fun)
/* Finish up a function declaration and compile that function
all the way to assembler language output. The free the storage
- for the function definition.
-
- FLAGS is a bitwise or of the following values:
- 2 - INCLASS_INLINE
- We just finished processing the body of an in-class inline
- function definition. (This processing will have taken place
- after the class definition is complete.) */
+ for the function definition. INLINE_P is TRUE if we just
+ finished processing the body of an in-class inline function
+ definition. (This processing will have taken place after the
+ class definition is complete.) */
tree
-finish_function (int flags)
+finish_function (bool inline_p)
{
tree fndecl = current_function_decl;
tree fntype, ctype = NULL_TREE;
- int inclass_inline = (flags & 2) != 0;
/* When we get some parse errors, we can end up without a
current_function_decl, so cope. */
@@ -15722,7 +15739,7 @@ finish_function (int flags)
bindings for the template parameters that we added in
maybe_begin_member_template_processing when start_function was
called. */
- if (inclass_inline)
+ if (inline_p)
maybe_end_member_template_processing ();
/* Leave the scope of the class. */
diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c
index 03e91b7..bc50962 100644
--- a/gcc/cp/decl2.c
+++ b/gcc/cp/decl2.c
@@ -102,6 +102,36 @@ static GTY(()) vec<tree, va_gc> *no_linkage_decls;
is to be an alias for the former if the former is defined. */
static GTY(()) vec<tree, va_gc> *mangling_aliases;
+/* hash traits for declarations. Hashes single decls via
+ DECL_ASSEMBLER_NAME_RAW. */
+
+struct mangled_decl_hash : ggc_remove <tree>
+{
+ typedef tree value_type; /* A DECL. */
+ typedef tree compare_type; /* An identifier. */
+
+ static hashval_t hash (const value_type decl)
+ {
+ return IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME_RAW (decl));
+ }
+ static bool equal (const value_type existing, compare_type candidate)
+ {
+ tree name = DECL_ASSEMBLER_NAME_RAW (existing);
+ return candidate == name;
+ }
+
+ static inline void mark_empty (value_type &p) {p = NULL_TREE;}
+ static inline bool is_empty (value_type p) {return !p;}
+
+ /* Nothing is deletable. Everything is insertable. */
+ static bool is_deleted (value_type) { return false; }
+ static void mark_deleted (value_type) { gcc_unreachable (); }
+};
+
+/* A hash table of decls keyed by mangled name. Used to figure out if
+ we need compatibility aliases. */
+static GTY(()) hash_table<mangled_decl_hash> *mangled_decls;
+
/* Nonzero if we're done parsing and into end-of-file activities. */
int at_eof;
@@ -427,6 +457,11 @@ grok_array_decl (location_t loc, tree array_expr, tree index_exp,
if (array_expr == error_mark_node || index_exp == error_mark_node)
error ("ambiguous conversion for array subscript");
+ if (TREE_CODE (TREE_TYPE (array_expr)) == POINTER_TYPE)
+ array_expr = mark_rvalue_use (array_expr);
+ else
+ array_expr = mark_lvalue_use_nonread (array_expr);
+ index_exp = mark_rvalue_use (index_exp);
expr = build_array_ref (input_location, array_expr, index_exp);
}
if (processing_template_decl && expr != error_mark_node)
@@ -969,14 +1004,16 @@ grokfield (const cp_declarator *declarator,
}
/* Like `grokfield', but for bitfields.
- WIDTH is non-NULL for bit fields only, and is an INTEGER_CST node. */
+ WIDTH is the width of the bitfield, a constant expression.
+ The other parameters are as for grokfield. */
tree
grokbitfield (const cp_declarator *declarator,
- cp_decl_specifier_seq *declspecs, tree width,
+ cp_decl_specifier_seq *declspecs, tree width, tree init,
tree attrlist)
{
- tree value = grokdeclarator (declarator, declspecs, BITFIELD, 0, &attrlist);
+ tree value = grokdeclarator (declarator, declspecs, BITFIELD,
+ init != NULL_TREE, &attrlist);
if (value == error_mark_node)
return NULL_TREE; /* friends went bad. */
@@ -1031,7 +1068,11 @@ grokbitfield (const cp_declarator *declarator,
error ("static member %qD cannot be a bit-field", value);
return NULL_TREE;
}
- cp_finish_decl (value, NULL_TREE, false, NULL_TREE, 0);
+
+ int flags = LOOKUP_IMPLICIT;
+ if (init && DIRECT_LIST_INIT_P (init))
+ flags = LOOKUP_NORMAL;
+ cp_finish_decl (value, init, false, NULL_TREE, flags);
if (width != error_mark_node)
{
@@ -1042,7 +1083,10 @@ grokbitfield (const cp_declarator *declarator,
TREE_TYPE (width));
else
{
- DECL_INITIAL (value) = width;
+ /* Temporarily stash the width in DECL_BIT_FIELD_REPRESENTATIVE.
+ check_bitfield_decl picks it from there later and sets DECL_SIZE
+ accordingly. */
+ DECL_BIT_FIELD_REPRESENTATIVE (value) = width;
SET_DECL_C_BIT_FIELD (value);
}
}
@@ -2967,7 +3011,7 @@ get_guard (tree decl)
tree guard;
sname = mangle_guard_variable (decl);
- guard = IDENTIFIER_GLOBAL_VALUE (sname);
+ guard = get_global_binding (sname);
if (! guard)
{
tree guard_type;
@@ -3135,7 +3179,7 @@ static tree
get_local_tls_init_fn (void)
{
tree sname = get_identifier ("__tls_init");
- tree fn = IDENTIFIER_GLOBAL_VALUE (sname);
+ tree fn = get_global_binding (sname);
if (!fn)
{
fn = build_lang_decl (FUNCTION_DECL, sname,
@@ -3145,7 +3189,7 @@ get_local_tls_init_fn (void)
TREE_PUBLIC (fn) = false;
DECL_ARTIFICIAL (fn) = true;
mark_used (fn);
- SET_IDENTIFIER_GLOBAL_VALUE (sname, fn);
+ set_global_binding (fn);
}
return fn;
}
@@ -3173,7 +3217,7 @@ get_tls_init_fn (tree var)
return get_local_tls_init_fn ();
tree sname = mangle_tls_init_fn (var);
- tree fn = IDENTIFIER_GLOBAL_VALUE (sname);
+ tree fn = get_global_binding (sname);
if (!fn)
{
fn = build_lang_decl (FUNCTION_DECL, sname,
@@ -3207,7 +3251,7 @@ get_tls_init_fn (tree var)
DECL_BEFRIENDING_CLASSES (fn) = var;
- SET_IDENTIFIER_GLOBAL_VALUE (sname, fn);
+ set_global_binding (fn);
}
return fn;
}
@@ -3225,7 +3269,7 @@ get_tls_wrapper_fn (tree var)
return NULL_TREE;
tree sname = mangle_tls_wrapper_fn (var);
- tree fn = IDENTIFIER_GLOBAL_VALUE (sname);
+ tree fn = get_global_binding (sname);
if (!fn)
{
/* A named rvalue reference is an lvalue, so the wrapper should
@@ -3264,7 +3308,7 @@ get_tls_wrapper_fn (tree var)
DECL_BEFRIENDING_CLASSES (fn) = var;
- SET_IDENTIFIER_GLOBAL_VALUE (sname, fn);
+ set_global_binding (fn);
}
return fn;
}
@@ -3310,7 +3354,7 @@ generate_tls_wrapper (tree fn)
TREE_READONLY (fn) = true;
finish_return_stmt (convert_from_reference (var));
finish_function_body (body);
- expand_or_defer_fn (finish_function (0));
+ expand_or_defer_fn (finish_function (/*inline_p=*/false));
}
/* Start the process of running a particular set of global constructors
@@ -3377,7 +3421,7 @@ finish_objects (int method_type, int initp, tree body)
/* Finish up. */
finish_compound_stmt (body);
- fn = finish_function (0);
+ fn = finish_function (/*inline_p=*/false);
if (method_type == 'I')
{
@@ -3517,7 +3561,7 @@ finish_static_storage_duration_function (tree body)
{
/* Close out the function. */
finish_compound_stmt (body);
- expand_or_defer_fn (finish_function (0));
+ expand_or_defer_fn (finish_function (/*inline_p=*/false));
}
/* Return the information about the indicated PRIORITY level. If no
@@ -4266,7 +4310,7 @@ handle_tls_init (void)
finish_then_clause (if_stmt);
finish_if_stmt (if_stmt);
finish_function_body (body);
- expand_or_defer_fn (finish_function (0));
+ expand_or_defer_fn (finish_function (/*inline_p=*/false));
}
/* We're at the end of compilation, so generate any mangling aliases that
@@ -4276,25 +4320,35 @@ handle_tls_init (void)
static void
generate_mangling_alias (tree decl, tree id2)
{
+ struct cgraph_node *n = NULL;
+
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ n = cgraph_node::get (decl);
+ if (!n)
+ /* Don't create an alias to an unreferenced function. */
+ return;
+ }
+
+ tree *slot
+ = mangled_decls->find_slot_with_hash (id2, IDENTIFIER_HASH_VALUE (id2),
+ INSERT);
+
/* If there's a declaration already using this mangled name,
don't create a compatibility alias that conflicts. */
- if (IDENTIFIER_GLOBAL_VALUE (id2))
- return;
-
- struct cgraph_node *n = NULL;
- if (TREE_CODE (decl) == FUNCTION_DECL
- && !(n = cgraph_node::get (decl)))
- /* Don't create an alias to an unreferenced function. */
+ if (*slot)
return;
tree alias = make_alias_for (decl, id2);
- SET_IDENTIFIER_GLOBAL_VALUE (id2, alias);
+ *slot = alias;
+
DECL_IGNORED_P (alias) = 1;
TREE_PUBLIC (alias) = TREE_PUBLIC (decl);
DECL_VISIBILITY (alias) = DECL_VISIBILITY (decl);
if (vague_linkage_p (decl))
DECL_WEAK (alias) = 1;
- if (TREE_CODE (decl) == FUNCTION_DECL)
+
+ if (n)
n->create_same_body_alias (alias, decl);
else
varpool_node::create_extra_name_alias (alias, decl);
@@ -4333,6 +4387,49 @@ generate_mangling_aliases ()
defer_mangling_aliases = false;
}
+/* Record a mangling of DECL, whose DECL_ASSEMBLER_NAME has just been
+ set. NEED_WARNING is true if we must warn about collisions. We do
+ this to spot changes in mangling that may require compatibility
+ aliases. */
+
+void
+record_mangling (tree decl, bool need_warning)
+{
+ if (!mangled_decls)
+ mangled_decls = hash_table<mangled_decl_hash>::create_ggc (499);
+
+ gcc_checking_assert (DECL_ASSEMBLER_NAME_SET_P (decl));
+ tree id = DECL_ASSEMBLER_NAME_RAW (decl);
+ tree *slot
+ = mangled_decls->find_slot_with_hash (id, IDENTIFIER_HASH_VALUE (id),
+ INSERT);
+
+ /* If this is already an alias, remove the alias, because the real
+ decl takes precedence. */
+ if (*slot && DECL_ARTIFICIAL (*slot) && DECL_IGNORED_P (*slot))
+ if (symtab_node *n = symtab_node::get (*slot))
+ if (n->cpp_implicit_alias)
+ {
+ n->remove ();
+ *slot = NULL_TREE;
+ }
+
+ if (!*slot)
+ *slot = decl;
+ else if (need_warning)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "mangling of %q#D as %qE conflicts with a previous mangle",
+ decl, id);
+ inform (DECL_SOURCE_LOCATION (*slot),
+ "previous mangling %q#D", *slot);
+ inform (DECL_SOURCE_LOCATION (decl),
+ "a later -fabi-version= (or =0)"
+ " avoids this error with a change in mangling");
+ *slot = decl;
+ }
+}
+
/* The entire file is now complete. If requested, dump everything
to a file. */
@@ -4358,7 +4455,7 @@ maybe_warn_sized_delete (enum tree_code code)
tree sized = NULL_TREE;
tree unsized = NULL_TREE;
- for (ovl_iterator iter (IDENTIFIER_GLOBAL_VALUE (cp_operator_id (code)));
+ for (ovl_iterator iter (get_global_binding (cp_operator_id (code)));
iter; ++iter)
{
tree fn = *iter;
@@ -5180,7 +5277,7 @@ vtv_finish_verification_constructor_init_function (tree function_body)
tree fn;
finish_compound_stmt (function_body);
- fn = finish_function (0);
+ fn = finish_function (/*inline_p=*/false);
DECL_STATIC_CONSTRUCTOR (fn) = 1;
decl_init_priority_insert (fn, MAX_RESERVED_INIT_PRIORITY - 1);
diff --git a/gcc/cp/error.c b/gcc/cp/error.c
index e407154..7a98d2e 100644
--- a/gcc/cp/error.c
+++ b/gcc/cp/error.c
@@ -1574,6 +1574,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
int do_outer_scope = ! (flags & TFF_UNQUALIFIED_NAME);
tree exceptions;
bool constexpr_p;
+ tree ret = NULL_TREE;
flags &= ~(TFF_UNQUALIFIED_NAME | TFF_TEMPLATE_NAME);
if (TREE_CODE (t) == TEMPLATE_DECL)
@@ -1636,7 +1637,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
&& !DECL_DESTRUCTOR_P (t) && !deduction_guide_p (t));
if (show_return)
{
- tree ret = fndecl_declared_return_type (t);
+ ret = fndecl_declared_return_type (t);
dump_type_prefix (pp, ret, flags);
}
@@ -1677,7 +1678,7 @@ dump_function_decl (cxx_pretty_printer *pp, tree t, int flags)
}
if (show_return)
- dump_type_suffix (pp, TREE_TYPE (fntype), flags);
+ dump_type_suffix (pp, ret, flags);
else if (deduction_guide_p (t))
{
pp_cxx_ws_string (pp, "->");
diff --git a/gcc/cp/except.c b/gcc/cp/except.c
index 2ee7e97..ecc8941 100644
--- a/gcc/cp/except.c
+++ b/gcc/cp/except.c
@@ -147,7 +147,7 @@ declare_library_fn (const char *name, tree rtype, tree ptype,
int ecf, int tm_ecf)
{
tree ident = get_identifier (name);
- tree res = IDENTIFIER_GLOBAL_VALUE (ident);
+ tree res = get_global_binding (ident);
if (!res)
{
tree type = build_function_type_list (rtype, ptype, NULL_TREE);
@@ -158,7 +158,7 @@ declare_library_fn (const char *name, tree rtype, tree ptype,
char *tm_name = concat ("_ITM_", name + 2, NULL_TREE);
tree tm_ident = get_identifier (tm_name);
free (tm_name);
- tree tm_fn = IDENTIFIER_GLOBAL_VALUE (tm_ident);
+ tree tm_fn = get_global_binding (tm_ident);
if (!tm_fn)
tm_fn = push_library_fn (tm_ident, type, except, ecf | tm_ecf);
record_tm_replacement (res, tm_fn);
@@ -609,7 +609,7 @@ build_throw (tree exp)
if (!throw_fn)
{
tree name = get_identifier ("__cxa_throw");
- throw_fn = IDENTIFIER_GLOBAL_VALUE (name);
+ throw_fn = get_global_binding (name);
if (!throw_fn)
{
/* Declare void __cxa_throw (void*, void*, void (*)(void*)). */
@@ -622,7 +622,7 @@ build_throw (tree exp)
if (flag_tm)
{
tree itm_name = get_identifier ("_ITM_cxa_throw");
- tree itm_fn = IDENTIFIER_GLOBAL_VALUE (itm_name);
+ tree itm_fn = get_global_binding (itm_name);
if (!itm_fn)
itm_fn = push_throw_library_fn (itm_name, tmp);
apply_tm_attr (itm_fn, get_identifier ("transaction_pure"));
@@ -764,7 +764,7 @@ build_throw (tree exp)
if (!rethrow_fn)
{
tree name = get_identifier ("__cxa_rethrow");
- rethrow_fn = IDENTIFIER_GLOBAL_VALUE (name);
+ rethrow_fn = get_global_binding (name);
if (!rethrow_fn)
/* Declare void __cxa_rethrow (void). */
rethrow_fn = push_throw_library_fn
diff --git a/gcc/cp/expr.c b/gcc/cp/expr.c
index 8bd341b..23e30cf 100644
--- a/gcc/cp/expr.c
+++ b/gcc/cp/expr.c
@@ -86,21 +86,147 @@ cplus_expand_constant (tree cst)
return cst;
}
+/* We've seen an actual use of EXPR. Possibly replace an outer variable
+ reference inside with its constant value or a lambda capture. */
+
+static tree
+mark_use (tree expr, bool rvalue_p, bool read_p,
+ location_t loc /* = UNKNOWN_LOCATION */,
+ bool reject_builtin /* = true */)
+{
+#define RECUR(t) mark_use ((t), rvalue_p, read_p, loc, reject_builtin)
+
+ if (expr == NULL_TREE || expr == error_mark_node)
+ return expr;
+
+ if (reject_builtin && reject_gcc_builtin (expr, loc))
+ return error_mark_node;
+
+ if (read_p)
+ mark_exp_read (expr);
+
+ tree oexpr = expr;
+ bool recurse_op[3] = { false, false, false };
+ switch (TREE_CODE (expr))
+ {
+ case VAR_DECL:
+ case PARM_DECL:
+ if (outer_automatic_var_p (expr)
+ && decl_constant_var_p (expr))
+ {
+ if (rvalue_p)
+ {
+ tree t = maybe_constant_value (expr);
+ if (TREE_CONSTANT (t))
+ {
+ expr = t;
+ break;
+ }
+ }
+ expr = process_outer_var_ref (expr, tf_warning_or_error, true);
+ if (!(TREE_TYPE (oexpr)
+ && TREE_CODE (TREE_TYPE (oexpr)) == REFERENCE_TYPE))
+ expr = convert_from_reference (expr);
+ }
+ break;
+ case COMPONENT_REF:
+ case NON_DEPENDENT_EXPR:
+ recurse_op[0] = true;
+ break;
+ case COMPOUND_EXPR:
+ recurse_op[1] = true;
+ break;
+ case COND_EXPR:
+ recurse_op[2] = true;
+ if (TREE_OPERAND (expr, 1))
+ recurse_op[1] = true;
+ break;
+ case INDIRECT_REF:
+ if (REFERENCE_REF_P (expr))
+ {
+ /* Try to look through the reference. */
+ tree ref = TREE_OPERAND (expr, 0);
+ tree r = mark_rvalue_use (ref, loc, reject_builtin);
+ if (r != ref)
+ expr = convert_from_reference (r);
+ }
+ break;
+ default:
+ break;
+ }
+
+ for (int i = 0; i < 3; ++i)
+ if (recurse_op[i])
+ {
+ tree op = TREE_OPERAND (expr, i);
+ op = RECUR (op);
+ if (op == error_mark_node)
+ return error_mark_node;
+ TREE_OPERAND (expr, i) = op;
+ }
+
+ return expr;
+#undef RECUR
+}
+
/* Called whenever the expression EXPR is used in an rvalue context.
When REJECT_BUILTIN is true the expression is checked to make sure
it doesn't make it possible to obtain the address of a GCC built-in
function with no library fallback (or any of its bits, such as in
a conversion to bool). */
+
tree
-mark_rvalue_use (tree expr,
+mark_rvalue_use (tree e,
location_t loc /* = UNKNOWN_LOCATION */,
bool reject_builtin /* = true */)
{
- if (reject_builtin && reject_gcc_builtin (expr, loc))
- return error_mark_node;
+ return mark_use (e, true, true, loc, reject_builtin);
+}
- mark_exp_read (expr);
- return expr;
+/* Called when expr appears as a discarded-value expression. */
+
+tree
+mark_discarded_use (tree expr)
+{
+ /* The lvalue-to-rvalue conversion (7.1) is applied if and only if the
+ expression is a glvalue of volatile-qualified type and it is one of the
+ following:
+ * ( expression ), where expression is one of these expressions,
+ * id-expression (8.1.4),
+ * subscripting (8.2.1),
+ * class member access (8.2.5),
+ * indirection (8.3.1),
+ * pointer-to-member operation (8.5),
+ * conditional expression (8.16) where both the second and the third
+ operands are one of these expressions, or
+ * comma expression (8.19) where the right operand is one of these
+ expressions. */
+ if (expr == NULL_TREE)
+ return expr;
+
+ switch (TREE_CODE (expr))
+ {
+ case COND_EXPR:
+ TREE_OPERAND (expr, 2) = mark_discarded_use (TREE_OPERAND (expr, 2));
+ gcc_fallthrough ();
+ case COMPOUND_EXPR:
+ TREE_OPERAND (expr, 1) = mark_discarded_use (TREE_OPERAND (expr, 1));
+ return expr;
+
+ case COMPONENT_REF:
+ case ARRAY_REF:
+ case INDIRECT_REF:
+ case MEMBER_REF:
+ break;
+ default:
+ if (DECL_P (expr))
+ break;
+ else
+ return expr;
+ }
+
+ /* Like mark_rvalue_use, but don't reject built-ins. */
+ return mark_use (expr, true, true, input_location, false);
}
/* Called whenever an expression is used in an lvalue context. */
@@ -108,8 +234,15 @@ mark_rvalue_use (tree expr,
tree
mark_lvalue_use (tree expr)
{
- mark_exp_read (expr);
- return expr;
+ return mark_use (expr, false, true, input_location, false);
+}
+
+/* As above, but don't consider this use a read. */
+
+tree
+mark_lvalue_use_nonread (tree expr)
+{
+ return mark_use (expr, false, false, input_location, false);
}
/* Called whenever an expression is used in a type use context. */
diff --git a/gcc/cp/init.c b/gcc/cp/init.c
index b01d662..ad30f24 100644
--- a/gcc/cp/init.c
+++ b/gcc/cp/init.c
@@ -2213,7 +2213,6 @@ constant_value_1 (tree decl, bool strict_p, bool return_aggregate_cst_ok_p)
initializer for the static data member is not processed
until needed; we need it now. */
mark_used (decl, tf_none);
- mark_rvalue_use (decl);
init = DECL_INITIAL (decl);
if (init == error_mark_node)
{
@@ -2447,7 +2446,7 @@ throw_bad_array_new_length (void)
{
tree name = get_identifier ("__cxa_throw_bad_array_new_length");
- fn = IDENTIFIER_GLOBAL_VALUE (name);
+ fn = get_global_binding (name);
if (!fn)
fn = push_throw_library_fn
(name, build_function_type_list (sizetype, NULL_TREE));
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index e441256..76f2f29 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -283,6 +283,8 @@ is_normal_capture_proxy (tree decl)
if (val == error_mark_node)
return true;
+ if (TREE_CODE (val) == ADDR_EXPR)
+ val = TREE_OPERAND (val, 0);
gcc_assert (TREE_CODE (val) == COMPONENT_REF);
val = TREE_OPERAND (val, 1);
return DECL_NORMAL_CAPTURE_P (val);
@@ -294,6 +296,19 @@ is_normal_capture_proxy (tree decl)
void
insert_capture_proxy (tree var)
{
+ if (is_normal_capture_proxy (var))
+ {
+ tree cap = DECL_CAPTURED_VARIABLE (var);
+ if (CHECKING_P)
+ {
+ gcc_assert (!is_normal_capture_proxy (cap));
+ tree old = retrieve_local_specialization (cap);
+ if (old)
+ gcc_assert (DECL_CONTEXT (old) != DECL_CONTEXT (var));
+ }
+ register_local_specialization (var, cap);
+ }
+
/* Put the capture proxy in the extra body block so that it won't clash
with a later local variable. */
pushdecl_outermost_localscope (var);
@@ -362,7 +377,7 @@ lambda_proxy_type (tree ref)
debugging. */
tree
-build_capture_proxy (tree member)
+build_capture_proxy (tree member, tree init)
{
tree var, object, fn, closure, name, lam, type;
@@ -412,6 +427,29 @@ build_capture_proxy (tree member)
TREE_USED (var) = 1;
DECL_CONTEXT (var) = fn;
+ if (DECL_NORMAL_CAPTURE_P (member))
+ {
+ if (DECL_VLA_CAPTURE_P (member))
+ {
+ init = CONSTRUCTOR_ELT (init, 0)->value;
+ init = TREE_OPERAND (init, 0); // Strip ADDR_EXPR.
+ init = TREE_OPERAND (init, 0); // Strip ARRAY_REF.
+ }
+ else
+ {
+ if (PACK_EXPANSION_P (init))
+ init = PACK_EXPANSION_PATTERN (init);
+ if (TREE_CODE (init) == INDIRECT_REF)
+ init = TREE_OPERAND (init, 0);
+ STRIP_NOPS (init);
+ }
+ gcc_assert (VAR_P (init) || TREE_CODE (init) == PARM_DECL);
+ while (is_normal_capture_proxy (init))
+ init = DECL_CAPTURED_VARIABLE (init);
+ retrofit_lang_decl (var);
+ DECL_CAPTURED_VARIABLE (var) = init;
+ }
+
if (name == this_identifier)
{
gcc_assert (LAMBDA_EXPR_THIS_CAPTURE (lam) == member);
@@ -592,7 +630,8 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
&& current_class_type == LAMBDA_EXPR_CLOSURE (lambda))
{
if (COMPLETE_TYPE_P (current_class_type))
- internal_error ("trying to capture %qD after closure is complete", id);
+ internal_error ("trying to capture %qD in instantiation of "
+ "generic lambda", id);
finish_member_declaration (member);
}
@@ -606,7 +645,7 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
= tree_cons (listmem, initializer, LAMBDA_EXPR_CAPTURE_LIST (lambda));
if (LAMBDA_EXPR_CLOSURE (lambda))
- return build_capture_proxy (member);
+ return build_capture_proxy (member, initializer);
/* For explicit captures we haven't started the function yet, so we wait
and build the proxy from cp_parser_lambda_body. */
return NULL_TREE;
@@ -948,6 +987,121 @@ generic_lambda_fn_p (tree callop)
&& PRIMARY_TEMPLATE_P (DECL_TI_TEMPLATE (callop)));
}
+/* Returns true iff we need to consider default capture for an enclosing
+ generic lambda. */
+
+bool
+need_generic_capture (void)
+{
+ if (!processing_template_decl)
+ return false;
+
+ tree outer_closure = NULL_TREE;
+ for (tree t = current_class_type; t;
+ t = decl_type_context (TYPE_MAIN_DECL (t)))
+ {
+ tree lam = CLASSTYPE_LAMBDA_EXPR (t);
+ if (!lam || LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lam) == CPLD_NONE)
+ /* No default capture. */
+ break;
+ outer_closure = t;
+ }
+
+ if (!outer_closure)
+ /* No lambda. */
+ return false;
+ else if (dependent_type_p (outer_closure))
+ /* The enclosing context isn't instantiated. */
+ return false;
+ else
+ return true;
+}
+
+/* A lambda-expression...is said to implicitly capture the entity...if the
+ compound-statement...names the entity in a potentially-evaluated
+ expression where the enclosing full-expression depends on a generic lambda
+ parameter declared within the reaching scope of the lambda-expression. */
+
+static tree
+dependent_capture_r (tree *tp, int *walk_subtrees, void *data)
+{
+ hash_set<tree> *pset = (hash_set<tree> *)data;
+
+ if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+
+ if (outer_automatic_var_p (*tp))
+ {
+ tree t = process_outer_var_ref (*tp, tf_warning_or_error, /*force*/true);
+ if (t != *tp
+ && TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
+ && TREE_CODE (TREE_TYPE (*tp)) != REFERENCE_TYPE)
+ t = convert_from_reference (t);
+ *tp = t;
+ }
+
+ if (pset->add (*tp))
+ *walk_subtrees = 0;
+
+ switch (TREE_CODE (*tp))
+ {
+ /* Don't walk into unevaluated context or another lambda. */
+ case SIZEOF_EXPR:
+ case ALIGNOF_EXPR:
+ case TYPEID_EXPR:
+ case NOEXCEPT_EXPR:
+ case LAMBDA_EXPR:
+ *walk_subtrees = 0;
+ break;
+
+ /* Don't walk into statements whose subexpressions we already
+ handled. */
+ case TRY_BLOCK:
+ case EH_SPEC_BLOCK:
+ case HANDLER:
+ case IF_STMT:
+ case FOR_STMT:
+ case RANGE_FOR_STMT:
+ case WHILE_STMT:
+ case DO_STMT:
+ case SWITCH_STMT:
+ case STATEMENT_LIST:
+ case RETURN_EXPR:
+ *walk_subtrees = 0;
+ break;
+
+ case DECL_EXPR:
+ {
+ tree decl = DECL_EXPR_DECL (*tp);
+ if (VAR_P (decl))
+ {
+ /* walk_tree_1 won't step in here. */
+ cp_walk_tree (&DECL_INITIAL (decl),
+ dependent_capture_r, &pset, NULL);
+ *walk_subtrees = 0;
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return NULL_TREE;
+}
+
+tree
+do_dependent_capture (tree expr, bool force)
+{
+ if (!need_generic_capture ()
+ || (!force && !instantiation_dependent_expression_p (expr)))
+ return expr;
+
+ hash_set<tree> pset;
+ cp_walk_tree (&expr, dependent_capture_r, &pset, NULL);
+ return expr;
+}
+
/* If the closure TYPE has a static op(), also add a conversion to function
pointer. */
@@ -1044,7 +1198,10 @@ maybe_add_lambda_conv_op (tree type)
if (generic_lambda_p)
{
+ /* Avoid capturing variables in this context. */
+ ++cp_unevaluated_operand;
tree a = forward_parm (tgt);
+ --cp_unevaluated_operand;
CALL_EXPR_ARG (call, ix) = a;
if (decltype_call)
@@ -1194,7 +1351,7 @@ maybe_add_lambda_conv_op (tree type)
finish_compound_stmt (compound_stmt);
finish_function_body (body);
- fn = finish_function (/*inline*/2);
+ fn = finish_function (/*inline_p=*/true);
if (!generic_lambda_p)
expand_or_defer_fn (fn);
@@ -1212,7 +1369,7 @@ maybe_add_lambda_conv_op (tree type)
finish_compound_stmt (compound_stmt);
finish_function_body (body);
- fn = finish_function (/*inline*/2);
+ fn = finish_function (/*inline_p=*/true);
if (!generic_lambda_p)
expand_or_defer_fn (fn);
@@ -1240,8 +1397,8 @@ lambda_static_thunk_p (tree fn)
bool
is_lambda_ignored_entity (tree val)
{
- /* In unevaluated context, look past normal capture proxies. */
- if (cp_unevaluated_operand && is_normal_capture_proxy (val))
+ /* Look past normal capture proxies. */
+ if (is_normal_capture_proxy (val))
return true;
/* Always ignore lambda fields, their names are only for debugging. */
@@ -1322,7 +1479,7 @@ start_lambda_function (tree fco, tree lambda_expr)
/* Push the proxies for any explicit captures. */
for (tree cap = LAMBDA_EXPR_CAPTURE_LIST (lambda_expr); cap;
cap = TREE_CHAIN (cap))
- build_capture_proxy (TREE_PURPOSE (cap));
+ build_capture_proxy (TREE_PURPOSE (cap), TREE_VALUE (cap));
return body;
}
@@ -1333,7 +1490,7 @@ finish_lambda_function (tree body)
finish_function_body (body);
/* Finish the function and generate code for it if necessary. */
- tree fn = finish_function (/*inline*/2);
+ tree fn = finish_function (/*inline_p=*/true);
/* Only expand if the call op is not a template. */
if (!DECL_TEMPLATE_INFO (fn))
diff --git a/gcc/cp/lex.c b/gcc/cp/lex.c
index 5bdea7b..fd93401 100644
--- a/gcc/cp/lex.c
+++ b/gcc/cp/lex.c
@@ -651,7 +651,7 @@ maybe_add_lang_decl_raw (tree t, bool decomp_p)
if (sel == lds_ns)
/* Who'd create a namespace, only to put nothing in it? */
- ld->u.ns.bindings = hash_map<lang_identifier *, tree>::create_ggc (499);
+ ld->u.ns.bindings = hash_table<named_decl_hash>::create_ggc (499);
if (GATHER_STATISTICS)
{
diff --git a/gcc/cp/mangle.c b/gcc/cp/mangle.c
index 33cd00e..64397cd 100644
--- a/gcc/cp/mangle.c
+++ b/gcc/cp/mangle.c
@@ -1725,7 +1725,7 @@ write_integer_cst (const tree cst)
type = c_common_signed_or_unsigned_type (1, TREE_TYPE (cst));
base = build_int_cstu (type, chunk);
- n = wide_int_to_tree (type, cst);
+ n = wide_int_to_tree (type, wi::to_wide (cst));
if (sign < 0)
{
@@ -3783,38 +3783,6 @@ get_mangled_id (tree decl)
return targetm.mangle_decl_assembler_name (decl, id);
}
-/* If DECL is an implicit mangling alias, return its symtab node; otherwise
- return NULL. */
-
-static symtab_node *
-decl_implicit_alias_p (tree decl)
-{
- if (DECL_P (decl) && DECL_ARTIFICIAL (decl)
- && DECL_IGNORED_P (decl)
- && (TREE_CODE (decl) == FUNCTION_DECL
- || (VAR_P (decl) && TREE_STATIC (decl))))
- {
- symtab_node *n = symtab_node::get (decl);
- if (n && n->cpp_implicit_alias)
- return n;
- }
- return NULL;
-}
-
-/* If DECL is a mangling alias, remove it from the symbol table and return
- true; otherwise return false. */
-
-bool
-maybe_remove_implicit_alias (tree decl)
-{
- if (symtab_node *n = decl_implicit_alias_p (decl))
- {
- n->remove();
- return true;
- }
- return false;
-}
-
/* Create an identifier for the external mangled name of DECL. */
void
@@ -3871,29 +3839,11 @@ mangle_decl (const tree decl)
if (!DECL_REALLY_EXTERN (decl))
{
- bool set = false;
-
- /* Check IDENTIFIER_GLOBAL_VALUE before setting to avoid redundant
- errors from multiple definitions. */
- tree d = IDENTIFIER_GLOBAL_VALUE (id);
- if (!d || decl_implicit_alias_p (d))
- {
- set = true;
- SET_IDENTIFIER_GLOBAL_VALUE (id, decl);
- }
+ record_mangling (decl, G.need_abi_warning);
if (!G.need_abi_warning)
return;
- /* If the mangling will change in the future, emit an alias with the
- future mangled name for forward-compatibility. */
- if (!set)
- {
- SET_IDENTIFIER_GLOBAL_VALUE (id, decl);
- inform (DECL_SOURCE_LOCATION (decl), "a later -fabi-version= (or "
- "=0) avoids this error with a change in mangling");
- }
-
flag_abi_version = flag_abi_compat_version;
id2 = mangle_decl_string (decl);
id2 = targetm.mangle_decl_assembler_name (decl, id2);
diff --git a/gcc/cp/method.c b/gcc/cp/method.c
index b83a6f2..4e56874 100644
--- a/gcc/cp/method.c
+++ b/gcc/cp/method.c
@@ -953,7 +953,7 @@ synthesize_method (tree fndecl)
}
finish_function_body (stmt);
- expand_or_defer_fn (finish_function (0));
+ expand_or_defer_fn (finish_function (/*inline_p=*/false));
input_location = save_input_location;
@@ -2191,9 +2191,11 @@ defaulted_late_check (tree 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);
+ error ("defaulted declaration %q+D does not match the "
+ "expected signature", fn);
+ inform (DECL_SOURCE_LOCATION (fn),
+ "expected signature: %qD", implicit_fn);
+ return;
}
if (DECL_DELETED_FN (implicit_fn))
diff --git a/gcc/cp/name-lookup.c b/gcc/cp/name-lookup.c
index d0aaf2b1..b1b4ebb 100644
--- a/gcc/cp/name-lookup.c
+++ b/gcc/cp/name-lookup.c
@@ -86,17 +86,9 @@ create_local_binding (cp_binding_level *level, tree name)
static tree *
find_namespace_slot (tree ns, tree name, bool create_p = false)
{
- tree *slot;
-
- if (create_p)
- {
- bool existed;
- slot = &DECL_NAMESPACE_BINDINGS (ns)->get_or_insert (name, &existed);
- if (!existed)
- *slot = NULL_TREE;
- }
- else
- slot = DECL_NAMESPACE_BINDINGS (ns)->get (name);
+ tree *slot = DECL_NAMESPACE_BINDINGS (ns)
+ ->find_slot_with_hash (name, name ? IDENTIFIER_HASH_VALUE (name) : 0,
+ create_p ? INSERT : NO_INSERT);
return slot;
}
@@ -1434,29 +1426,38 @@ member_name_cmp (const void *a_p, const void *b_p)
b = OVL_FUNCTION (b);
/* We're in STAT_HACK or USING_DECL territory (or possibly error-land). */
- if (TREE_CODE (a) == TREE_CODE (b))
- /* We can get two TYPE_DECLs or two USING_DECLs. Place in source
- order. */
- return DECL_SOURCE_LOCATION (a) < DECL_SOURCE_LOCATION (b) ? -1 : +1;
-
- /* If one of them is a TYPE_DECL, it loses. */
- if (TREE_CODE (a) == TYPE_DECL)
- return +1;
- else if (TREE_CODE (b) == TYPE_DECL)
- return -1;
-
- /* If one of them is a USING_DECL, it loses. */
- if (TREE_CODE (a) == USING_DECL)
- return +1;
- else if (TREE_CODE (b) == USING_DECL)
- return -1;
-
- /* There are no other cases, as duplicate detection should have
- kicked in earlier. However, some erroneous cases get though.
- Order by source location. We should really prevent this
- happening. */
- gcc_assert (errorcount);
- return DECL_SOURCE_LOCATION (a) < DECL_SOURCE_LOCATION (b) ? -1 : +1;
+ if (TREE_CODE (a) != TREE_CODE (b))
+ {
+ /* If one of them is a TYPE_DECL, it loses. */
+ if (TREE_CODE (a) == TYPE_DECL)
+ return +1;
+ else if (TREE_CODE (b) == TYPE_DECL)
+ return -1;
+
+ /* If one of them is a USING_DECL, it loses. */
+ if (TREE_CODE (a) == USING_DECL)
+ return +1;
+ else if (TREE_CODE (b) == USING_DECL)
+ return -1;
+
+ /* There are no other cases with different kinds of decls, as
+ duplicate detection should have kicked in earlier. However,
+ some erroneous cases get though. */
+ gcc_assert (errorcount);
+ }
+
+ /* Using source location would be the best thing here, but we can
+ get identically-located decls in the following circumstances:
+
+ 1) duplicate artificial type-decls for the same type.
+
+ 2) pack expansions of using-decls.
+
+ We should not be doing #1, but in either case it doesn't matter
+ how we order these. Use UID as a proxy for source ordering, so
+ that identically-located decls still have a well-defined stable
+ ordering. */
+ return DECL_UID (a) < DECL_UID (b) ? -1 : +1;
}
static struct {
@@ -2246,12 +2247,6 @@ supplement_binding_1 (cxx_binding *binding, tree decl)
region to refer only to the namespace to which it already
refers. */
ok = false;
- else if (maybe_remove_implicit_alias (bval))
- {
- /* There was a mangling compatibility alias using this mangled name,
- but now we have a real decl that wants to use it instead. */
- binding->value = decl;
- }
else
{
if (!error_operand_p (bval))
@@ -2516,13 +2511,13 @@ update_binding (cp_binding_level *level, cxx_binding *binding, tree *slot,
return decl;
}
-/* Map of identifiers to extern C functions (or LISTS thereof). */
+/* Table of identifiers to extern C declarations (or LISTS thereof). */
-static GTY(()) hash_map<lang_identifier *, tree> *extern_c_fns;
+static GTY(()) hash_table<named_decl_hash> *extern_c_decls;
-/* DECL has C linkage. If we have an existing instance, make sure it
- has the same exception specification [7.5, 7.6]. If there's no
- instance, add DECL to the map. */
+/* DECL has C linkage. If we have an existing instance, make sure the
+ new one is compatible. Make sure it has the same exception
+ specification [7.5, 7.6]. Add DECL to the map. */
static void
check_extern_c_conflict (tree decl)
@@ -2531,18 +2526,16 @@ check_extern_c_conflict (tree decl)
if (DECL_ARTIFICIAL (decl) || DECL_IN_SYSTEM_HEADER (decl))
return;
- if (!extern_c_fns)
- extern_c_fns = hash_map<lang_identifier *,tree>::create_ggc (127);
+ if (!extern_c_decls)
+ extern_c_decls = hash_table<named_decl_hash>::create_ggc (127);
- bool existed;
- tree *slot = &extern_c_fns->get_or_insert (DECL_NAME (decl), &existed);
- if (!existed)
- *slot = decl;
- else
+ tree *slot = extern_c_decls
+ ->find_slot_with_hash (DECL_NAME (decl),
+ IDENTIFIER_HASH_VALUE (DECL_NAME (decl)), INSERT);
+ if (tree old = *slot)
{
- tree old = *slot;
- if (TREE_CODE (old) == TREE_LIST)
- old = TREE_VALUE (old);
+ if (TREE_CODE (old) == OVERLOAD)
+ old = OVL_FUNCTION (old);
int mismatch = 0;
if (DECL_CONTEXT (old) == DECL_CONTEXT (decl))
@@ -2550,9 +2543,10 @@ check_extern_c_conflict (tree decl)
about a (possible) mismatch, when inserting the decl. */
else if (!decls_match (decl, old))
mismatch = 1;
- else if (!comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old)),
- TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)),
- ce_normal))
+ else if (TREE_CODE (decl) == FUNCTION_DECL
+ && !comp_except_specs (TYPE_RAISES_EXCEPTIONS (TREE_TYPE (old)),
+ TYPE_RAISES_EXCEPTIONS (TREE_TYPE (decl)),
+ ce_normal))
mismatch = -1;
else if (DECL_ASSEMBLER_NAME_SET_P (old))
SET_DECL_ASSEMBLER_NAME (decl, DECL_ASSEMBLER_NAME (old));
@@ -2560,17 +2554,32 @@ check_extern_c_conflict (tree decl)
if (mismatch)
{
pedwarn (input_location, 0,
- "declaration of %q#D with C language linkage", decl);
- pedwarn (DECL_SOURCE_LOCATION (old), 0,
- "conflicts with previous declaration %q#D", old);
+ "conflicting C language linkage declaration %q#D", decl);
+ inform (DECL_SOURCE_LOCATION (old),
+ "previous declaration %q#D", old);
if (mismatch < 0)
- pedwarn (input_location, 0,
- "due to different exception specifications");
+ inform (input_location,
+ "due to different exception specifications");
}
else
- /* Chain it on for c_linkage_binding's use. */
- *slot = tree_cons (NULL_TREE, decl, *slot);
+ {
+ if (old == *slot)
+ /* The hash table expects OVERLOADS, so construct one with
+ OLD as both the function and the chain. This allocate
+ an excess OVERLOAD node, but it's rare to have multiple
+ extern "C" decls of the same name. And we save
+ complicating the hash table logic (which is used
+ elsewhere). */
+ *slot = ovl_make (old, old);
+
+ slot = &OVL_CHAIN (*slot);
+
+ /* Chain it on for c_linkage_binding's use. */
+ *slot = tree_cons (NULL_TREE, decl, *slot);
+ }
}
+ else
+ *slot = decl;
}
/* Returns a list of C-linkage decls with the name NAME. Used in
@@ -2579,9 +2588,16 @@ check_extern_c_conflict (tree decl)
tree
c_linkage_bindings (tree name)
{
- if (extern_c_fns)
- if (tree *slot = extern_c_fns->get (name))
- return *slot;
+ if (extern_c_decls)
+ if (tree *slot = extern_c_decls
+ ->find_slot_with_hash (name, IDENTIFIER_HASH_VALUE (name), NO_INSERT))
+ {
+ tree result = *slot;
+ if (TREE_CODE (result) == OVERLOAD)
+ result = OVL_CHAIN (result);
+ return result;
+ }
+
return NULL_TREE;
}
@@ -2713,7 +2729,11 @@ check_local_shadow (tree decl)
else if (warn_shadow_local)
warning_code = OPT_Wshadow_local;
else if (warn_shadow_compatible_local
- && can_convert (TREE_TYPE (old), TREE_TYPE (decl), tf_none))
+ && (same_type_p (TREE_TYPE (old), TREE_TYPE (decl))
+ || (!dependent_type_p (TREE_TYPE (decl))
+ && !dependent_type_p (TREE_TYPE (old))
+ && can_convert (TREE_TYPE (old), TREE_TYPE (decl),
+ tf_none))))
warning_code = OPT_Wshadow_compatible_local;
else
return;
@@ -2947,7 +2967,10 @@ do_pushdecl (tree decl, bool is_friend)
while (level->kind == sk_class)
level = level->level_chain;
- if (tree name = DECL_NAME (decl))
+ /* An anonymous namespace has a NULL DECL_NAME, but we still want to
+ insert it. Other NULL-named decls, not so much. */
+ tree name = DECL_NAME (decl);
+ if (name || TREE_CODE (decl) == NAMESPACE_DECL)
{
cxx_binding *binding = NULL; /* Local scope binding. */
tree ns = NULL_TREE; /* Searched namespace. */
@@ -3008,9 +3031,8 @@ do_pushdecl (tree decl, bool is_friend)
else
*slot = head;
}
- if (TREE_CODE (match) == FUNCTION_DECL
- && DECL_EXTERN_C_P (match))
- /* We need to check and register the fn now. */
+ if (DECL_EXTERN_C_P (match))
+ /* We need to check and register the decl now. */
check_extern_c_conflict (match);
}
return match;
@@ -3091,7 +3113,9 @@ do_pushdecl (tree decl, bool is_friend)
}
else if (VAR_P (decl))
maybe_register_incomplete_var (decl);
- else if (TREE_CODE (decl) == FUNCTION_DECL && DECL_EXTERN_C_P (decl))
+
+ if ((VAR_P (decl) || TREE_CODE (decl) == FUNCTION_DECL)
+ && DECL_EXTERN_C_P (decl))
check_extern_c_conflict (decl);
}
else
@@ -3771,16 +3795,6 @@ identifier_type_value (tree id)
return ret;
}
-
-/* Return the IDENTIFIER_GLOBAL_VALUE of T, for use in common code, since
- the definition of IDENTIFIER_GLOBAL_VALUE is different for C and C++. */
-
-tree
-identifier_global_value (tree t)
-{
- return IDENTIFIER_GLOBAL_VALUE (t);
-}
-
/* Push a definition of struct, union or enum tag named ID. into
binding_level B. DECL is a TYPE_DECL for the type. We assume that
the tag ID is not already defined. */
@@ -4836,31 +4850,23 @@ get_namespace_binding (tree ns, tree name)
return ret;
}
-/* Set value binding of NAME in the global namespace to VAL. Does not
- add it to the list of things in the namespace. */
+/* Push internal DECL into the global namespace. Does not do the
+ full overload fn handling and does not add it to the list of things
+ in the namespace. */
void
-set_global_binding (tree name, tree val)
+set_global_binding (tree decl)
{
bool subtime = timevar_cond_start (TV_NAME_LOOKUP);
- tree *slot = find_namespace_slot (global_namespace, name, true);
- tree old = MAYBE_STAT_DECL (*slot);
+ tree *slot = find_namespace_slot (global_namespace, DECL_NAME (decl), true);
- if (!old)
- *slot = val;
- else if (old == val)
- ;
- else if (!STAT_HACK_P (*slot)
- && TREE_CODE (val) == TYPE_DECL && DECL_ARTIFICIAL (val))
- *slot = stat_hack (old, val);
- else if (!STAT_HACK_P (*slot)
- && TREE_CODE (old) == TYPE_DECL && DECL_ARTIFICIAL (old))
- *slot = stat_hack (val, old);
- else
- /* The user's placed something in the implementor's
- namespace. */
- diagnose_name_conflict (val, old);
+ if (*slot)
+ /* The user's placed something in the implementor's namespace. */
+ diagnose_name_conflict (decl, MAYBE_STAT_DECL (*slot));
+
+ /* Force the binding, so compiler internals continue to work. */
+ *slot = decl;
timevar_cond_stop (TV_NAME_LOOKUP, subtime);
}
@@ -5287,7 +5293,7 @@ qualify_lookup (tree val, int flags)
if (flags & (LOOKUP_PREFER_NAMESPACES | LOOKUP_PREFER_TYPES))
return false;
/* Look through lambda things that we shouldn't be able to see. */
- if (is_lambda_ignored_entity (val))
+ if (!(flags & LOOKUP_HIDDEN) && is_lambda_ignored_entity (val))
return false;
return true;
}
@@ -6621,9 +6627,7 @@ do_push_nested_namespace (tree ns)
{
do_push_nested_namespace (CP_DECL_CONTEXT (ns));
gcc_checking_assert
- (find_namespace_value (current_namespace,
- DECL_NAME (ns) ? DECL_NAME (ns)
- : anon_identifier) == ns);
+ (find_namespace_value (current_namespace, DECL_NAME (ns)) == ns);
resume_scope (NAMESPACE_LEVEL (ns));
current_namespace = ns;
}
@@ -6781,10 +6785,7 @@ push_namespace (tree name, bool make_inline)
/* We should not get here if the global_namespace is not yet constructed
nor if NAME designates the global namespace: The global scope is
constructed elsewhere. */
- gcc_assert (global_namespace != NULL && name != global_identifier);
-
- if (!name)
- name = anon_identifier;
+ gcc_checking_assert (global_namespace != NULL && name != global_identifier);
tree ns = NULL_TREE;
{
@@ -6830,11 +6831,9 @@ push_namespace (tree name, bool make_inline)
ns = NULL_TREE;
else
{
- if (name == anon_identifier)
+ if (!name)
{
- /* Clear DECL_NAME for the benefit of debugging back ends. */
- SET_DECL_ASSEMBLER_NAME (ns, name);
- DECL_NAME (ns) = NULL_TREE;
+ SET_DECL_ASSEMBLER_NAME (ns, anon_identifier);
if (!make_inline)
add_using_namespace (DECL_NAMESPACE_USING (current_namespace),
@@ -6849,7 +6848,7 @@ push_namespace (tree name, bool make_inline)
vec_safe_push (DECL_NAMESPACE_INLINEES (current_namespace), ns);
}
- if (name == anon_identifier || make_inline)
+ if (!name || make_inline)
emit_debug_info_using_namespace (current_namespace, ns, true);
}
}
diff --git a/gcc/cp/name-lookup.h b/gcc/cp/name-lookup.h
index 2e5539f..bf0bf85 100644
--- a/gcc/cp/name-lookup.h
+++ b/gcc/cp/name-lookup.h
@@ -178,9 +178,6 @@ struct GTY(()) cp_label_binding {
CURRENT_BINDING_LEVEL. You should use lookup_name_current_level
instead. */
-/* Note that the information in the `names' component of the global contour
- is duplicated in the IDENTIFIER_GLOBAL_VALUEs of all identifiers. */
-
struct GTY(()) cp_binding_level {
/* A chain of _DECL nodes for all variables, constants, functions,
and typedef types. These are in the reverse of the order
@@ -303,7 +300,11 @@ extern tree lookup_name_prefer_type (tree, int);
extern tree lookup_name_real (tree, int, int, bool, int, int);
extern tree lookup_type_scope (tree, tag_scope);
extern tree get_namespace_binding (tree ns, tree id);
-extern void set_global_binding (tree id, tree val);
+extern void set_global_binding (tree decl);
+inline tree get_global_binding (tree id)
+{
+ return get_namespace_binding (NULL_TREE, id);
+}
extern tree lookup_qualified_name (tree, tree, int, bool, /*hidden*/bool = false);
extern tree lookup_name_nonclass (tree);
extern bool is_local_extern (tree);
diff --git a/gcc/cp/optimize.c b/gcc/cp/optimize.c
index 09ffbda..2645ae4 100644
--- a/gcc/cp/optimize.c
+++ b/gcc/cp/optimize.c
@@ -416,7 +416,7 @@ maybe_thunk_body (tree fn, bool force)
}
DECL_ABSTRACT_ORIGIN (clone) = NULL;
- expand_or_defer_fn (finish_function (0));
+ expand_or_defer_fn (finish_function (/*inline_p=*/false));
}
return 1;
}
@@ -657,7 +657,7 @@ maybe_clone_body (tree fn)
cp_function_chain->can_throw = !TREE_NOTHROW (fn);
/* Now, expand this function into RTL, if appropriate. */
- finish_function (0);
+ finish_function (/*inline_p=*/false);
BLOCK_ABSTRACT_ORIGIN (DECL_INITIAL (clone)) = DECL_INITIAL (fn);
if (alias)
{
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index c9cb3cb..2337be5 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -1451,6 +1451,7 @@ make_declarator (cp_declarator_kind kind)
declarator = (cp_declarator *) alloc_declarator (sizeof (cp_declarator));
declarator->kind = kind;
+ declarator->parenthesized = UNKNOWN_LOCATION;
declarator->attributes = NULL_TREE;
declarator->std_attributes = NULL_TREE;
declarator->declarator = NULL;
@@ -1691,6 +1692,7 @@ cp_parameter_declarator *
make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
cp_declarator *declarator,
tree default_argument,
+ location_t loc,
bool template_parameter_pack_p = false)
{
cp_parameter_declarator *parameter;
@@ -1705,6 +1707,7 @@ make_parameter_declarator (cp_decl_specifier_seq *decl_specifiers,
parameter->declarator = declarator;
parameter->default_argument = default_argument;
parameter->template_parameter_pack_p = template_parameter_pack_p;
+ parameter->loc = loc;
return parameter;
}
@@ -2087,7 +2090,7 @@ static enum tree_code cp_parser_assignment_operator_opt
static cp_expr cp_parser_expression
(cp_parser *, cp_id_kind * = NULL, bool = false, bool = false);
static cp_expr cp_parser_constant_expression
- (cp_parser *, bool = false, bool * = NULL);
+ (cp_parser *, bool = false, bool * = NULL, bool = false);
static cp_expr cp_parser_builtin_offsetof
(cp_parser *);
static cp_expr cp_parser_lambda_expression
@@ -2254,7 +2257,7 @@ static cp_expr cp_parser_braced_list
static vec<constructor_elt, va_gc> *cp_parser_initializer_list
(cp_parser *, bool *);
-static bool cp_parser_ctor_initializer_opt_and_function_body
+static void cp_parser_ctor_initializer_opt_and_function_body
(cp_parser *, bool);
static tree cp_parser_late_parsing_omp_declare_simd
@@ -2307,7 +2310,7 @@ static tree cp_parser_conversion_type_id
(cp_parser *);
static cp_declarator *cp_parser_conversion_declarator_opt
(cp_parser *);
-static bool cp_parser_ctor_initializer_opt
+static void cp_parser_ctor_initializer_opt
(cp_parser *);
static void cp_parser_mem_initializer_list
(cp_parser *);
@@ -2350,7 +2353,7 @@ static void cp_parser_explicit_specialization
static tree cp_parser_try_block
(cp_parser *);
-static bool cp_parser_function_try_block
+static void cp_parser_function_try_block
(cp_parser *);
static void cp_parser_handler_seq
(cp_parser *);
@@ -2435,7 +2438,7 @@ static tree cp_parser_transaction
(cp_parser *, cp_token *);
static tree cp_parser_transaction_expression
(cp_parser *, enum rid);
-static bool cp_parser_function_transaction
+static void cp_parser_function_transaction
(cp_parser *, enum rid);
static tree cp_parser_transaction_cancel
(cp_parser *);
@@ -2767,53 +2770,161 @@ cp_lexer_peek_conflict_marker (cp_lexer *lexer, enum cpp_ttype tok1_kind,
return true;
}
-/* If not parsing tentatively, issue a diagnostic of the form
+/* Get a description of the matching symbol to TOKEN_DESC e.g. "(" for
+ RT_CLOSE_PAREN. */
+
+static const char *
+get_matching_symbol (required_token token_desc)
+{
+ switch (token_desc)
+ {
+ default:
+ gcc_unreachable ();
+ return "";
+ case RT_CLOSE_BRACE:
+ return "{";
+ case RT_CLOSE_PAREN:
+ return "(";
+ }
+}
+
+/* Attempt to convert TOKEN_DESC from a required_token to an
+ enum cpp_ttype, returning CPP_EOF if there is no good conversion. */
+
+static enum cpp_ttype
+get_required_cpp_ttype (required_token token_desc)
+{
+ switch (token_desc)
+ {
+ case RT_SEMICOLON:
+ return CPP_SEMICOLON;
+ case RT_OPEN_PAREN:
+ return CPP_OPEN_PAREN;
+ case RT_CLOSE_BRACE:
+ return CPP_CLOSE_BRACE;
+ case RT_OPEN_BRACE:
+ return CPP_OPEN_BRACE;
+ case RT_CLOSE_SQUARE:
+ return CPP_CLOSE_SQUARE;
+ case RT_OPEN_SQUARE:
+ return CPP_OPEN_SQUARE;
+ case RT_COMMA:
+ return CPP_COMMA;
+ case RT_COLON:
+ return CPP_COLON;
+ case RT_CLOSE_PAREN:
+ return CPP_CLOSE_PAREN;
+
+ default:
+ /* Use CPP_EOF as a "no completions possible" code. */
+ return CPP_EOF;
+ }
+}
+
+
+/* Subroutine of cp_parser_error and cp_parser_required_error.
+
+ Issue a diagnostic of the form
FILE:LINE: MESSAGE before TOKEN
where TOKEN is the next token in the input stream. MESSAGE
(specified by the caller) is usually of the form "expected
- OTHER-TOKEN". */
+ OTHER-TOKEN".
+
+ This bypasses the check for tentative passing, and potentially
+ adds material needed by cp_parser_required_error.
+
+ If MISSING_TOKEN_DESC is not RT_NONE, then potentially add fix-it hints
+ suggesting insertion of the missing token.
+
+ Additionally, if MATCHING_LOCATION is not UNKNOWN_LOCATION, then we
+ have an unmatched symbol at MATCHING_LOCATION; highlight this secondary
+ location. */
static void
-cp_parser_error (cp_parser* parser, const char* gmsgid)
+cp_parser_error_1 (cp_parser* parser, const char* gmsgid,
+ required_token missing_token_desc,
+ location_t matching_location)
{
- if (!cp_parser_simulate_error (parser))
+ cp_token *token = cp_lexer_peek_token (parser->lexer);
+ /* This diagnostic makes more sense if it is tagged to the line
+ of the token we just peeked at. */
+ cp_lexer_set_source_position_from_token (token);
+
+ if (token->type == CPP_PRAGMA)
{
- cp_token *token = cp_lexer_peek_token (parser->lexer);
- /* This diagnostic makes more sense if it is tagged to the line
- of the token we just peeked at. */
- cp_lexer_set_source_position_from_token (token);
+ error_at (token->location,
+ "%<#pragma%> is not allowed here");
+ cp_parser_skip_to_pragma_eol (parser, token);
+ return;
+ }
- if (token->type == CPP_PRAGMA)
+ /* If this is actually a conflict marker, report it as such. */
+ if (token->type == CPP_LSHIFT
+ || token->type == CPP_RSHIFT
+ || token->type == CPP_EQ_EQ)
+ {
+ location_t loc;
+ if (cp_lexer_peek_conflict_marker (parser->lexer, token->type, &loc))
{
- error_at (token->location,
- "%<#pragma%> is not allowed here");
- cp_parser_skip_to_pragma_eol (parser, token);
+ error_at (loc, "version control conflict marker in file");
return;
}
+ }
- /* If this is actually a conflict marker, report it as such. */
- if (token->type == CPP_LSHIFT
- || token->type == CPP_RSHIFT
- || token->type == CPP_EQ_EQ)
- {
- location_t loc;
- if (cp_lexer_peek_conflict_marker (parser->lexer, token->type, &loc))
- {
- error_at (loc, "version control conflict marker in file");
- return;
- }
- }
+ gcc_rich_location richloc (input_location);
+
+ bool added_matching_location = false;
- rich_location richloc (line_table, input_location);
- c_parse_error (gmsgid,
- /* Because c_parser_error does not understand
- CPP_KEYWORD, keywords are treated like
- identifiers. */
- (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
- token->u.value, token->flags, &richloc);
+ if (missing_token_desc != RT_NONE)
+ {
+ /* Potentially supply a fix-it hint, suggesting to add the
+ missing token immediately after the *previous* token.
+ This may move the primary location within richloc. */
+ enum cpp_ttype ttype = get_required_cpp_ttype (missing_token_desc);
+ location_t prev_token_loc
+ = cp_lexer_previous_token (parser->lexer)->location;
+ maybe_suggest_missing_token_insertion (&richloc, ttype, prev_token_loc);
+
+ /* If matching_location != UNKNOWN_LOCATION, highlight it.
+ Attempt to consolidate diagnostics by printing it as a
+ secondary range within the main diagnostic. */
+ if (matching_location != UNKNOWN_LOCATION)
+ added_matching_location
+ = richloc.add_location_if_nearby (matching_location);
+ }
+
+ /* Actually emit the error. */
+ c_parse_error (gmsgid,
+ /* Because c_parser_error does not understand
+ CPP_KEYWORD, keywords are treated like
+ identifiers. */
+ (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
+ token->u.value, token->flags, &richloc);
+
+ if (missing_token_desc != RT_NONE)
+ {
+ /* If we weren't able to consolidate matching_location, then
+ print it as a secondary diagnostic. */
+ if (matching_location != UNKNOWN_LOCATION
+ && !added_matching_location)
+ inform (matching_location, "to match this %qs",
+ get_matching_symbol (missing_token_desc));
}
}
+/* If not parsing tentatively, issue a diagnostic of the form
+ FILE:LINE: MESSAGE before TOKEN
+ where TOKEN is the next token in the input stream. MESSAGE
+ (specified by the caller) is usually of the form "expected
+ OTHER-TOKEN". */
+
+static void
+cp_parser_error (cp_parser* parser, const char* gmsgid)
+{
+ if (!cp_parser_simulate_error (parser))
+ cp_parser_error_1 (parser, gmsgid, RT_NONE, UNKNOWN_LOCATION);
+}
+
/* Issue an error about name-lookup failing. NAME is the
IDENTIFIER_NODE DECL is the result of
the lookup (as returned from cp_parser_lookup_name). DESIRED is
@@ -3826,6 +3937,9 @@ cp_parser_new (void)
/* Allow constrained-type-specifiers. */
parser->prevent_constrained_type_specifiers = 0;
+ /* We haven't yet seen an 'extern "C"'. */
+ parser->innermost_linkage_specification_location = UNKNOWN_LOCATION;
+
return parser;
}
@@ -4379,7 +4493,8 @@ cp_parser_translation_unit (cp_parser* parser)
/* Create the error declarator. */
cp_error_declarator = make_declarator (cdk_error);
/* Create the empty parameter list. */
- no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE);
+ no_parameters = make_parameter_declarator (NULL, NULL, NULL_TREE,
+ UNKNOWN_LOCATION);
/* Remember where the base of the declarator obstack lies. */
declarator_obstack_base = obstack_next_free (&declarator_obstack);
}
@@ -9623,12 +9738,15 @@ cp_parser_expression (cp_parser* parser, cp_id_kind * pidk,
If ALLOW_NON_CONSTANT_P a non-constant expression is silently
accepted. If ALLOW_NON_CONSTANT_P is true and the expression is not
constant, *NON_CONSTANT_P is set to TRUE. If ALLOW_NON_CONSTANT_P
- is false, NON_CONSTANT_P should be NULL. */
+ is false, NON_CONSTANT_P should be NULL. If STRICT_P is true,
+ only parse a conditional-expression, otherwise parse an
+ assignment-expression. See below for rationale. */
static cp_expr
cp_parser_constant_expression (cp_parser* parser,
bool allow_non_constant_p,
- bool *non_constant_p)
+ bool *non_constant_p,
+ bool strict_p)
{
bool saved_integral_constant_expression_p;
bool saved_allow_non_integral_constant_expression_p;
@@ -9662,16 +9780,27 @@ cp_parser_constant_expression (cp_parser* parser,
parser->allow_non_integral_constant_expression_p
= (allow_non_constant_p || cxx_dialect >= cxx11);
parser->non_integral_constant_expression_p = false;
- /* Although the grammar says "conditional-expression", we parse an
- "assignment-expression", which also permits "throw-expression"
- and the use of assignment operators. In the case that
- ALLOW_NON_CONSTANT_P is false, we get better errors than we would
+ /* Although the grammar says "conditional-expression", when not STRICT_P,
+ we parse an "assignment-expression", which also permits
+ "throw-expression" and the use of assignment operators. In the case
+ that ALLOW_NON_CONSTANT_P is false, we get better errors than we would
otherwise. In the case that ALLOW_NON_CONSTANT_P is true, it is
actually essential that we look for an assignment-expression.
For example, cp_parser_initializer_clauses uses this function to
determine whether a particular assignment-expression is in fact
constant. */
- expression = cp_parser_assignment_expression (parser);
+ if (strict_p)
+ {
+ /* Parse the binary expressions (logical-or-expression). */
+ expression = cp_parser_binary_expression (parser, false, false, false,
+ PREC_NOT_OPERATOR, NULL);
+ /* If the next token is a `?' then we're actually looking at
+ a conditional-expression; otherwise we're done. */
+ if (cp_lexer_next_token_is (parser->lexer, CPP_QUERY))
+ expression = cp_parser_question_colon_clause (parser, expression);
+ }
+ else
+ expression = cp_parser_assignment_expression (parser);
/* Restore the old settings. */
parser->integral_constant_expression_p
= saved_integral_constant_expression_p;
@@ -10183,7 +10312,8 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_THIS))
{
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
- if (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) == CPLD_COPY)
+ if (cxx_dialect < cxx2a
+ && LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda_expr) == CPLD_COPY)
pedwarn (loc, 0, "explicit by-copy capture of %<this%> redundant "
"with by-copy capture default");
cp_lexer_consume_token (parser->lexer);
@@ -10539,6 +10669,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
{
bool nested = (current_function_decl != NULL_TREE);
bool local_variables_forbidden_p = parser->local_variables_forbidden_p;
+ bool in_function_body = parser->in_function_body;
if (nested)
push_function_context ();
else
@@ -10549,6 +10680,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
save_omp_privatization_clauses (omp_privatization_save);
/* Clear this in case we're in the middle of a default argument. */
parser->local_variables_forbidden_p = false;
+ parser->in_function_body = true;
/* Finish the function call operator
- class_specifier
@@ -10556,6 +10688,8 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
+ function_definition_after_declarator
+ ctor_initializer_opt_and_function_body */
{
+ local_specialization_stack s (lss_copy);
+
tree fco = lambda_function (lambda_expr);
tree body = start_lambda_function (fco, lambda_expr);
bool done = false;
@@ -10633,6 +10767,7 @@ cp_parser_lambda_body (cp_parser* parser, tree lambda_expr)
restore_omp_privatization_clauses (omp_privatization_save);
parser->local_variables_forbidden_p = local_variables_forbidden_p;
+ parser->in_function_body = in_function_body;
if (nested)
pop_function_context();
else
@@ -11849,6 +11984,8 @@ cp_convert_range_for (tree statement, tree range_decl, tree range_expr,
tree iter_type, begin_expr, end_expr;
tree condition, expression;
+ range_expr = mark_lvalue_use (range_expr);
+
if (range_decl == error_mark_node || range_expr == error_mark_node)
/* If an error happened previously do nothing or else a lot of
unhelpful errors would be issued. */
@@ -13714,9 +13851,11 @@ cp_parser_linkage_specification (cp_parser* parser)
tree linkage;
/* Look for the `extern' keyword. */
- cp_parser_require_keyword (parser, RID_EXTERN, RT_EXTERN);
+ cp_token *extern_token
+ = cp_parser_require_keyword (parser, RID_EXTERN, RT_EXTERN);
/* Look for the string-literal. */
+ cp_token *string_token = cp_lexer_peek_token (parser->lexer);
linkage = cp_parser_string_literal (parser, false, false);
/* Transform the literal into an identifier. If the literal is a
@@ -13735,6 +13874,20 @@ cp_parser_linkage_specification (cp_parser* parser)
/* We're now using the new linkage. */
push_lang_context (linkage);
+ /* Preserve the location of the the innermost linkage specification,
+ tracking the locations of nested specifications via a local. */
+ location_t saved_location
+ = parser->innermost_linkage_specification_location;
+ /* Construct a location ranging from the start of the "extern" to
+ the end of the string-literal, with the caret at the start, e.g.:
+ extern "C" {
+ ^~~~~~~~~~
+ */
+ parser->innermost_linkage_specification_location
+ = make_location (extern_token->location,
+ extern_token->location,
+ get_finish (string_token->location));
+
/* If the next token is a `{', then we're using the first
production. */
if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_BRACE))
@@ -13765,6 +13918,9 @@ cp_parser_linkage_specification (cp_parser* parser)
/* We're done with the linkage-specification. */
pop_lang_context ();
+
+ /* Restore location of parent linkage specification, if any. */
+ parser->innermost_linkage_specification_location = saved_location;
}
/* Parse a static_assert-declaration.
@@ -14229,11 +14385,9 @@ cp_parser_conversion_declarator_opt (cp_parser* parser)
/* Parse an (optional) ctor-initializer.
ctor-initializer:
- : mem-initializer-list
-
- Returns TRUE iff the ctor-initializer was actually present. */
+ : mem-initializer-list */
-static bool
+static void
cp_parser_ctor_initializer_opt (cp_parser* parser)
{
/* If the next token is not a `:', then there is no
@@ -14243,16 +14397,13 @@ cp_parser_ctor_initializer_opt (cp_parser* parser)
/* Do default initialization of any bases and members. */
if (DECL_CONSTRUCTOR_P (current_function_decl))
finish_mem_initializers (NULL_TREE);
-
- return false;
+ return;
}
/* Consume the `:' token. */
cp_lexer_consume_token (parser->lexer);
/* And the mem-initializer-list. */
cp_parser_mem_initializer_list (parser);
-
- return true;
}
/* Parse a mem-initializer-list.
@@ -16514,6 +16665,7 @@ cp_parser_explicit_specialization (cp_parser* parser)
if (current_lang_name == lang_name_c)
{
error_at (token->location, "template specialization with C linkage");
+ maybe_show_extern_c_location ();
/* Give it C++ linkage to avoid confusing other parts of the
front end. */
push_lang_context (lang_name_cplusplus);
@@ -19785,6 +19937,7 @@ cp_parser_direct_declarator (cp_parser* parser,
bool saved_in_declarator_p = parser->in_declarator_p;
bool first = true;
tree pushed_scope = NULL_TREE;
+ cp_token *open_paren = NULL, *close_paren = NULL;
while (true)
{
@@ -19835,6 +19988,8 @@ cp_parser_direct_declarator (cp_parser* parser,
tree params;
bool is_declarator = false;
+ open_paren = NULL;
+
/* In a member-declarator, the only valid interpretation
of a parenthesis is the start of a
parameter-declaration-clause. (It is invalid to
@@ -19956,6 +20111,7 @@ cp_parser_direct_declarator (cp_parser* parser,
parser->default_arg_ok_p = saved_default_arg_ok_p;
parser->in_declarator_p = saved_in_declarator_p;
+ open_paren = token;
/* Consume the `('. */
matching_parens parens;
parens.consume_open (parser);
@@ -19969,6 +20125,7 @@ cp_parser_direct_declarator (cp_parser* parser,
parser->in_type_id_in_expr_p = saved_in_type_id_in_expr_p;
first = false;
/* Expect a `)'. */
+ close_paren = cp_lexer_peek_token (parser->lexer);
if (!parens.require_close (parser))
declarator = cp_error_declarator;
if (declarator == cp_error_declarator)
@@ -19990,6 +20147,7 @@ cp_parser_direct_declarator (cp_parser* parser,
if (ctor_dtor_or_conv_p)
*ctor_dtor_or_conv_p = 0;
+ open_paren = NULL;
first = false;
parser->default_arg_ok_p = false;
parser->in_declarator_p = true;
@@ -20285,6 +20443,22 @@ cp_parser_direct_declarator (cp_parser* parser,
point. That's an error; the declarator is not optional. */
if (!declarator)
cp_parser_error (parser, "expected declarator");
+ else if (open_paren)
+ {
+ /* Record overly parenthesized declarator so we can give a
+ diagnostic about confusing decl/expr disambiguation. */
+ if (declarator->kind == cdk_array)
+ {
+ /* If the open and close parens are on different lines, this
+ is probably a formatting thing, so ignore. */
+ expanded_location open = expand_location (open_paren->location);
+ expanded_location close = expand_location (close_paren->location);
+ if (open.line != close.line || open.file != close.file)
+ open_paren = NULL;
+ }
+ if (open_paren)
+ declarator->parenthesized = open_paren->location;
+ }
/* If we entered a scope, we must exit it now. */
if (pushed_scope)
@@ -21217,6 +21391,8 @@ cp_parser_parameter_declaration_list (cp_parser* parser, bool *is_error)
PARM,
parameter->default_argument != NULL_TREE,
&parameter->decl_specifiers.attributes);
+ if (decl != error_mark_node && parameter->loc != UNKNOWN_LOCATION)
+ DECL_SOURCE_LOCATION (decl) = parameter->loc;
}
deprecated_state = DEPRECATED_NORMAL;
@@ -21370,6 +21546,7 @@ cp_parser_parameter_declaration (cp_parser *parser,
= G_("types may not be defined in parameter types");
/* Parse the declaration-specifiers. */
+ cp_token *decl_spec_token_start = cp_lexer_peek_token (parser->lexer);
cp_parser_decl_specifier_seq (parser,
CP_PARSER_FLAGS_NONE,
&decl_specifiers,
@@ -21554,9 +21731,33 @@ cp_parser_parameter_declaration (cp_parser *parser,
else
default_argument = NULL_TREE;
+ /* Generate a location for the parameter, ranging from the start of the
+ initial token to the end of the final token (using input_location for
+ the latter, set up by cp_lexer_set_source_position_from_token when
+ consuming tokens).
+
+ If we have a identifier, then use it for the caret location, e.g.
+
+ extern int callee (int one, int (*two)(int, int), float three);
+ ~~~~~~^~~~~~~~~~~~~~
+
+ otherwise, reuse the start location for the caret location e.g.:
+
+ extern int callee (int one, int (*)(int, int), float three);
+ ^~~~~~~~~~~~~~~~~
+
+ */
+ location_t caret_loc = (declarator && declarator->id_loc != UNKNOWN_LOCATION
+ ? declarator->id_loc
+ : decl_spec_token_start->location);
+ location_t param_loc = make_location (caret_loc,
+ decl_spec_token_start->location,
+ input_location);
+
return make_parameter_declarator (&decl_specifiers,
declarator,
default_argument,
+ param_loc,
template_parameter_pack_p);
}
@@ -21628,12 +21829,11 @@ cp_parser_function_body (cp_parser *parser, bool in_function_try_block)
true if a ctor-initializer was present. When IN_FUNCTION_TRY_BLOCK
is true we are parsing a function-try-block. */
-static bool
+static void
cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser,
bool in_function_try_block)
{
tree body, list;
- bool ctor_initializer_p;
const bool check_body_p =
DECL_CONSTRUCTOR_P (current_function_decl)
&& DECL_DECLARED_CONSTEXPR_P (current_function_decl);
@@ -21642,7 +21842,7 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser,
/* Begin the function body. */
body = begin_function_body ();
/* Parse the optional ctor-initializer. */
- ctor_initializer_p = cp_parser_ctor_initializer_opt (parser);
+ cp_parser_ctor_initializer_opt (parser);
/* If we're parsing a constexpr constructor definition, we need
to check that the constructor body is indeed empty. However,
@@ -21662,8 +21862,6 @@ cp_parser_ctor_initializer_opt_and_function_body (cp_parser *parser,
check_constexpr_ctor_body (last, list, /*complain=*/true);
/* Finish the function body. */
finish_function_body (body);
-
- return ctor_initializer_p;
}
/* Parse an initializer.
@@ -23412,35 +23610,99 @@ cp_parser_member_declaration (cp_parser* parser)
{
tree attributes = NULL_TREE;
tree first_attribute;
+ tree initializer;
+ bool is_bitfld = false;
+ bool named_bitfld = false;
/* Peek at the next token. */
token = cp_lexer_peek_token (parser->lexer);
+ /* The following code wants to know early if it is a bit-field
+ or some other declaration. Attributes can appear before
+ the `:' token, but are hopefully rare enough that the
+ simplicity of the tentative lookup pays off. */
+ if (cp_next_tokens_can_be_attribute_p (parser)
+ || (token->type == CPP_NAME
+ && cp_nth_tokens_can_be_attribute_p (parser, 2)
+ && (named_bitfld = true)))
+ {
+ cp_parser_parse_tentatively (parser);
+ if (named_bitfld)
+ cp_lexer_consume_token (parser->lexer);
+ cp_parser_attributes_opt (parser);
+ token = cp_lexer_peek_token (parser->lexer);
+ is_bitfld = cp_lexer_next_token_is (parser->lexer, CPP_COLON);
+ cp_parser_abort_tentative_parse (parser);
+ }
+
/* Check for a bitfield declaration. */
- if (token->type == CPP_COLON
+ if (is_bitfld
+ || token->type == CPP_COLON
|| (token->type == CPP_NAME
- && cp_lexer_peek_nth_token (parser->lexer, 2)->type
- == CPP_COLON))
+ && cp_lexer_nth_token_is (parser->lexer, 2, CPP_COLON)
+ && (named_bitfld = true)))
{
tree identifier;
tree width;
+ tree late_attributes = NULL_TREE;
- /* Get the name of the bitfield. Note that we cannot just
- check TOKEN here because it may have been invalidated by
- the call to cp_lexer_peek_nth_token above. */
- if (cp_lexer_peek_token (parser->lexer)->type != CPP_COLON)
+ if (named_bitfld)
identifier = cp_parser_identifier (parser);
else
identifier = NULL_TREE;
+ /* Look for attributes that apply to the bitfield. */
+ attributes = cp_parser_attributes_opt (parser);
+
/* Consume the `:' token. */
cp_lexer_consume_token (parser->lexer);
+
/* Get the width of the bitfield. */
- width
- = cp_parser_constant_expression (parser);
+ width = cp_parser_constant_expression (parser, false, NULL,
+ cxx_dialect >= cxx11);
+
+ /* In C++2A and as extension for C++11 and above we allow
+ default member initializers for bit-fields. */
+ initializer = NULL_TREE;
+ if (cxx_dialect >= cxx11
+ && (cp_lexer_next_token_is (parser->lexer, CPP_EQ)
+ || cp_lexer_next_token_is (parser->lexer,
+ CPP_OPEN_BRACE)))
+ {
+ location_t loc
+ = cp_lexer_peek_token (parser->lexer)->location;
+ if (cxx_dialect < cxx2a
+ && !in_system_header_at (loc)
+ && identifier != NULL_TREE)
+ pedwarn (loc, 0,
+ "default member initializers for bit-fields "
+ "only available with -std=c++2a or "
+ "-std=gnu++2a");
+
+ initializer = cp_parser_save_nsdmi (parser);
+ if (identifier == NULL_TREE)
+ {
+ error_at (loc, "default member initializer for "
+ "unnamed bit-field");
+ initializer = NULL_TREE;
+ }
+ }
+ else
+ {
+ /* Look for attributes that apply to the bitfield after
+ the `:' token and width. This is where GCC used to
+ parse attributes in the past, pedwarn if there is
+ a std attribute. */
+ if (cp_next_tokens_can_be_std_attribute_p (parser))
+ pedwarn (input_location, OPT_Wpedantic,
+ "ISO C++ allows bit-field attributes only "
+ "before the %<:%> token");
+
+ late_attributes = cp_parser_attributes_opt (parser);
+ }
+
+ attributes = chainon (attributes, late_attributes);
- /* Look for attributes that apply to the bitfield. */
- attributes = cp_parser_attributes_opt (parser);
/* Remember which attributes are prefix attributes and
which are not. */
first_attribute = attributes;
@@ -23454,13 +23716,12 @@ cp_parser_member_declaration (cp_parser* parser)
sfk_none)
: NULL,
&decl_specifiers,
- width,
+ width, initializer,
attributes);
}
else
{
cp_declarator *declarator;
- tree initializer;
tree asm_specification;
int ctor_dtor_or_conv_p;
@@ -23679,7 +23940,6 @@ cp_parser_member_declaration (cp_parser* parser)
if (TREE_CODE (decl) == FUNCTION_DECL)
cp_parser_save_default_args (parser, decl);
else if (TREE_CODE (decl) == FIELD_DECL
- && !DECL_C_BIT_FIELD (decl)
&& DECL_INITIAL (decl))
/* Add DECL to the queue of NSDMI to be parsed later. */
vec_safe_push (unparsed_nsdmis, decl);
@@ -24229,20 +24489,19 @@ cp_parser_try_block (cp_parser* parser)
function-try-block:
try ctor-initializer [opt] function-body handler-seq */
-static bool
+static void
cp_parser_function_try_block (cp_parser* parser)
{
tree compound_stmt;
tree try_block;
- bool ctor_initializer_p;
/* Look for the `try' keyword. */
if (!cp_parser_require_keyword (parser, RID_TRY, RT_TRY))
- return false;
+ return;
/* Let the rest of the front end know where we are. */
try_block = begin_function_try_block (&compound_stmt);
/* Parse the function-body. */
- ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body
+ cp_parser_ctor_initializer_opt_and_function_body
(parser, /*in_function_try_block=*/true);
/* We're done with the `try' part. */
finish_function_try_block (try_block);
@@ -24250,8 +24509,6 @@ cp_parser_function_try_block (cp_parser* parser)
cp_parser_handler_seq (parser);
/* We're done with the handlers. */
finish_function_handler_sequence (try_block, compound_stmt);
-
- return ctor_initializer_p;
}
/* Parse a handler-seq.
@@ -26426,7 +26683,6 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
bool inline_p)
{
tree fn;
- bool ctor_initializer_p = false;
bool saved_in_unbraced_linkage_specification_p;
bool saved_in_function_body;
unsigned saved_num_template_parameter_lists;
@@ -26484,21 +26740,18 @@ cp_parser_function_definition_after_declarator (cp_parser* parser,
or function-transaction-block. Note that all of these include the
function-body. */
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRANSACTION_ATOMIC))
- ctor_initializer_p = cp_parser_function_transaction (parser,
- RID_TRANSACTION_ATOMIC);
+ cp_parser_function_transaction (parser, RID_TRANSACTION_ATOMIC);
else if (cp_lexer_next_token_is_keyword (parser->lexer,
RID_TRANSACTION_RELAXED))
- ctor_initializer_p = cp_parser_function_transaction (parser,
- RID_TRANSACTION_RELAXED);
+ cp_parser_function_transaction (parser, RID_TRANSACTION_RELAXED);
else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
- ctor_initializer_p = cp_parser_function_try_block (parser);
+ cp_parser_function_try_block (parser);
else
- ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body
+ cp_parser_ctor_initializer_opt_and_function_body
(parser, /*in_function_try_block=*/false);
/* Finish the function. */
- fn = finish_function ((ctor_initializer_p ? 1 : 0) |
- (inline_p ? 2 : 0));
+ fn = finish_function (inline_p);
/* Generate code for it, if necessary. */
expand_or_defer_fn (fn);
/* Restore the saved values. */
@@ -26749,6 +27002,7 @@ cp_parser_explicit_template_declaration (cp_parser* parser, bool member_p)
if (current_lang_name == lang_name_c)
{
error_at (location, "template with C linkage");
+ maybe_show_extern_c_location ();
/* Give it C++ linkage to avoid confusing other parts of the
front end. */
push_lang_context (lang_name_cplusplus);
@@ -27369,7 +27623,7 @@ cp_parser_late_parsing_for_member (cp_parser* parser, tree member_function)
{
parser->lexer->in_pragma = true;
cp_parser_omp_declare_reduction_exprs (member_function, parser);
- finish_function (/*inline*/2);
+ finish_function (/*inline_p=*/true);
cp_check_omp_declare_reduction (member_function);
}
else
@@ -27959,24 +28213,6 @@ cp_parser_friend_p (const cp_decl_specifier_seq *decl_specifiers)
return decl_spec_seq_has_spec_p (decl_specifiers, ds_friend);
}
-/* Get a description of the matching symbol to TOKEN_DESC e.g. "(" for
- RT_CLOSE_PAREN. */
-
-static const char *
-get_matching_symbol (required_token token_desc)
-{
- switch (token_desc)
- {
- default:
- gcc_unreachable ();
- return "";
- case RT_CLOSE_BRACE:
- return "{";
- case RT_CLOSE_PAREN:
- return "(";
- }
-}
-
/* Issue an error message indicating that TOKEN_DESC was expected.
If KEYWORD is true, it indicated this function is called by
cp_parser_require_keword and the required token can only be
@@ -28154,31 +28390,7 @@ cp_parser_required_error (cp_parser *parser,
}
if (gmsgid)
- {
- /* Emulate rest of cp_parser_error. */
- cp_token *token = cp_lexer_peek_token (parser->lexer);
- cp_lexer_set_source_position_from_token (token);
-
- gcc_rich_location richloc (input_location);
-
- /* If matching_location != UNKNOWN_LOCATION, highlight it.
- Attempt to consolidate diagnostics by printing it as a
- secondary range within the main diagnostic. */
- bool added_matching_location = false;
- if (matching_location != UNKNOWN_LOCATION)
- added_matching_location
- = richloc.add_location_if_nearby (matching_location);
-
- c_parse_error (gmsgid,
- (token->type == CPP_KEYWORD ? CPP_NAME : token->type),
- token->u.value, token->flags, &richloc);
-
- /* If we weren't able to consolidate matching_location, then
- print it as a secondary diagnostic. */
- if (matching_location != UNKNOWN_LOCATION && !added_matching_location)
- inform (matching_location, "to match this %qs",
- get_matching_symbol (token_desc));
- }
+ cp_parser_error_1 (parser, gmsgid, token_desc, matching_location);
}
@@ -30020,10 +30232,9 @@ cp_parser_objc_class_ivars (cp_parser* parser)
attributes = chainon (prefix_attributes, attributes);
if (width)
- /* Create the bitfield declaration. */
- decl = grokbitfield (declarator, &declspecs,
- width,
- attributes);
+ /* Create the bitfield declaration. */
+ decl = grokbitfield (declarator, &declspecs,
+ width, NULL_TREE, attributes);
else
decl = grokfield (declarator, &declspecs,
NULL_TREE, /*init_const_expr_p=*/false,
@@ -31681,7 +31892,7 @@ cp_parser_oacc_wait_list (cp_parser *parser, location_t clause_loc, tree list)
{
tree c = build_omp_clause (clause_loc, OMP_CLAUSE_WAIT);
- mark_rvalue_use (targ);
+ targ = mark_rvalue_use (targ);
OMP_CLAUSE_DECL (c) = targ;
OMP_CLAUSE_CHAIN (c) = list;
list = c;
@@ -37558,7 +37769,7 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
if (!cp_parser_omp_declare_reduction_exprs (fndecl, parser))
{
if (!block_scope)
- finish_function (0);
+ finish_function (/*inline_p=*/false);
else
DECL_CONTEXT (fndecl) = current_function_decl;
if (cp)
@@ -37568,7 +37779,7 @@ cp_parser_omp_declare_reduction (cp_parser *parser, cp_token *pragma_tok,
if (cp)
cp_parser_pop_lexer (parser);
if (!block_scope)
- finish_function (0);
+ finish_function (/*inline_p=*/false);
else
{
DECL_CONTEXT (fndecl) = current_function_decl;
@@ -38263,13 +38474,12 @@ cp_parser_transaction_expression (cp_parser *parser, enum rid keyword)
__transaction_relaxed function-try-block
*/
-static bool
+static void
cp_parser_function_transaction (cp_parser *parser, enum rid keyword)
{
unsigned char old_in = parser->in_transaction;
unsigned char new_in = 1;
tree compound_stmt, stmt, attrs;
- bool ctor_initializer_p;
cp_token *token;
gcc_assert (keyword == RID_TRANSACTION_ATOMIC
@@ -38293,16 +38503,14 @@ cp_parser_function_transaction (cp_parser *parser, enum rid keyword)
parser->in_transaction = new_in;
if (cp_lexer_next_token_is_keyword (parser->lexer, RID_TRY))
- ctor_initializer_p = cp_parser_function_try_block (parser);
+ cp_parser_function_try_block (parser);
else
- ctor_initializer_p = cp_parser_ctor_initializer_opt_and_function_body
+ cp_parser_ctor_initializer_opt_and_function_body
(parser, /*in_function_try_block=*/false);
parser->in_transaction = old_in;
finish_transaction_stmt (stmt, compound_stmt, new_in, NULL_TREE);
-
- return ctor_initializer_p;
}
/* Parse a __transaction_cancel statement.
@@ -39368,4 +39576,17 @@ finish_fully_implicit_template (cp_parser *parser, tree member_decl_opt)
return member_decl_opt;
}
+/* Helper function for diagnostics that have complained about things
+ being used with 'extern "C"' linkage.
+
+ Attempt to issue a note showing where the 'extern "C"' linkage began. */
+
+void
+maybe_show_extern_c_location (void)
+{
+ if (the_parser->innermost_linkage_specification_location != UNKNOWN_LOCATION)
+ inform (the_parser->innermost_linkage_specification_location,
+ "%<extern \"C\"%> linkage started here");
+}
+
#include "gt-cp-parser.h"
diff --git a/gcc/cp/parser.h b/gcc/cp/parser.h
index 0994e1e..f4f4a01 100644
--- a/gcc/cp/parser.h
+++ b/gcc/cp/parser.h
@@ -412,6 +412,10 @@ struct GTY(()) cp_parser {
context e.g., because they could never be deduced. */
int prevent_constrained_type_specifiers;
+ /* Location of the string-literal token within the current linkage
+ specification, if any, or UNKNOWN_LOCATION otherwise. */
+ location_t innermost_linkage_specification_location;
+
};
/* In parser.c */
diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c
index f12ab26..be39da7 100644
--- a/gcc/cp/pt.c
+++ b/gcc/cp/pt.c
@@ -1895,6 +1895,7 @@ reregister_specialization (tree spec, tree tinfo, tree new_spec)
void
register_local_specialization (tree spec, tree tmpl)
{
+ gcc_assert (tmpl != spec);
local_specializations->put (tmpl, spec);
}
@@ -9494,6 +9495,16 @@ in_template_function (void)
return ret;
}
+/* Returns true iff we are currently within a template other than a
+ default-capturing generic lambda, so we don't need to worry about semantic
+ processing. */
+
+bool
+processing_nonlambda_template (void)
+{
+ return processing_template_decl && !need_generic_capture ();
+}
+
/* Returns true if T depends on any template parameter with level LEVEL. */
bool
@@ -12809,14 +12820,13 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
cp_apply_type_quals_to_decl (cp_type_quals (type), r);
if (DECL_C_BIT_FIELD (r))
- /* For bit-fields, DECL_INITIAL gives the number of bits. For
- non-bit-fields DECL_INITIAL is a non-static data member
- initializer, which gets deferred instantiation. */
- DECL_INITIAL (r)
- = tsubst_expr (DECL_INITIAL (t), args,
+ /* For bit-fields, DECL_BIT_FIELD_REPRESENTATIVE gives the
+ number of bits. */
+ DECL_BIT_FIELD_REPRESENTATIVE (r)
+ = tsubst_expr (DECL_BIT_FIELD_REPRESENTATIVE (t), args,
complain, in_decl,
/*integral_constant_expression_p=*/true);
- else if (DECL_INITIAL (t))
+ if (DECL_INITIAL (t))
{
/* Set up DECL_TEMPLATE_INFO so that we can get at the
NSDMI in perform_member_init. Still set DECL_INITIAL
@@ -13017,15 +13027,20 @@ tsubst_decl (tree t, tree args, tsubst_flags_t complain)
&& VAR_HAD_UNKNOWN_BOUND (t)
&& type != error_mark_node)
type = strip_array_domain (type);
- tree auto_node = type_uses_auto (type);
- int len = TREE_VEC_LENGTH (args);
- if (auto_node)
- /* Mask off any template args past the variable's context so we
- don't replace the auto with an unrelated argument. */
- TREE_VEC_LENGTH (args) = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
- type = tsubst (type, args, complain, in_decl);
- if (auto_node)
- TREE_VEC_LENGTH (args) = len;
+ tree sub_args = args;
+ if (tree auto_node = type_uses_auto (type))
+ {
+ /* Mask off any template args past the variable's context so we
+ don't replace the auto with an unrelated argument. */
+ int nouter = TEMPLATE_TYPE_LEVEL (auto_node) - 1;
+ int extra = TMPL_ARGS_DEPTH (args) - nouter;
+ if (extra > 0)
+ /* This should never happen with the new lambda instantiation
+ model, but keep the handling just in case. */
+ gcc_assert (!CHECKING_P),
+ sub_args = strip_innermost_template_args (args, extra);
+ }
+ type = tsubst (type, sub_args, complain, in_decl);
}
if (VAR_P (r))
{
@@ -15986,7 +16001,8 @@ tsubst_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl,
{
/* We're in tsubst_lambda_expr, we've already inserted a new
capture proxy, so look it up and register it. */
- tree inst = lookup_name (DECL_NAME (decl));
+ tree inst = lookup_name_real (DECL_NAME (decl), 0, 0,
+ /*block_p=*/true, 0, LOOKUP_HIDDEN);
gcc_assert (inst != decl && is_capture_proxy (inst));
register_local_specialization (inst, decl);
break;
@@ -16906,10 +16922,10 @@ tsubst_lambda_expr (tree t, tree args, tsubst_flags_t complain, tree in_decl)
if (nested)
push_function_context ();
- tree body = start_lambda_function (fn, r);
-
local_specialization_stack s (lss_copy);
+ tree body = start_lambda_function (fn, r);
+
register_parameter_specializations (oldfn, fn);
tsubst_expr (DECL_SAVED_TREE (oldfn), args, complain, r,
@@ -18136,11 +18152,7 @@ tsubst_copy_and_build (tree t,
r = build_cxx_call (wrap, 0, NULL, tf_warning_or_error);
}
else if (outer_automatic_var_p (r))
- {
- r = process_outer_var_ref (r, complain);
- if (is_capture_proxy (r) && !DECL_PACK_P (t))
- register_local_specialization (r, t);
- }
+ r = process_outer_var_ref (r, complain);
if (TREE_CODE (TREE_TYPE (t)) != REFERENCE_TYPE)
/* If the original type was a reference, we'll be wrapped in
@@ -23197,15 +23209,9 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
synthesize_method (d);
else if (TREE_CODE (d) == FUNCTION_DECL)
{
- hash_map<tree, tree> *saved_local_specializations;
- tree block = NULL_TREE;
-
- /* Save away the current list, in case we are instantiating one
- template from within the body of another. */
- saved_local_specializations = local_specializations;
-
/* Set up the list of local specializations. */
- local_specializations = new hash_map<tree, tree>;
+ local_specialization_stack lss (push_to_top ? lss_blank : lss_copy);
+ tree block = NULL_TREE;
/* Set up context. */
if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
@@ -23244,17 +23250,13 @@ instantiate_decl (tree d, bool defer_ok, bool expl_inst_class_mem_p)
= DECL_STRUCT_FUNCTION (code_pattern)->language->infinite_loop;
}
- /* We don't need the local specializations any more. */
- delete local_specializations;
- local_specializations = saved_local_specializations;
-
/* Finish the function. */
if (DECL_OMP_DECLARE_REDUCTION_P (code_pattern)
&& TREE_CODE (DECL_CONTEXT (code_pattern)) == FUNCTION_DECL)
DECL_SAVED_TREE (d) = pop_stmt_list (block);
else
{
- d = finish_function (0);
+ d = finish_function (/*inline_p=*/false);
expand_or_defer_fn (d);
}
@@ -24017,8 +24019,21 @@ value_dependent_expression_p (tree expression)
case TRAIT_EXPR:
{
tree type2 = TRAIT_EXPR_TYPE2 (expression);
- return (dependent_type_p (TRAIT_EXPR_TYPE1 (expression))
- || (type2 ? dependent_type_p (type2) : false));
+
+ if (dependent_type_p (TRAIT_EXPR_TYPE1 (expression)))
+ return true;
+
+ if (!type2)
+ return false;
+
+ if (TREE_CODE (type2) != TREE_LIST)
+ return dependent_type_p (type2);
+
+ for (; type2; type2 = TREE_CHAIN (type2))
+ if (dependent_type_p (TREE_VALUE (type2)))
+ return true;
+
+ return false;
}
case MODOP_EXPR:
@@ -24280,21 +24295,22 @@ type_dependent_expression_p (tree expression)
&& (any_dependent_template_arguments_p
(INNERMOST_TEMPLATE_ARGS (DECL_TI_ARGS (expression)))))
return true;
+ }
- /* Otherwise, if the decl isn't from a dependent scope, it can't be
- type-dependent. Checking this is important for functions with auto
- return type, which looks like a dependent type. */
- if (TREE_CODE (expression) == FUNCTION_DECL
- && (!DECL_CLASS_SCOPE_P (expression)
- || !dependent_type_p (DECL_CONTEXT (expression)))
- && (!DECL_FRIEND_CONTEXT (expression)
- || !dependent_type_p (DECL_FRIEND_CONTEXT (expression)))
- && !DECL_LOCAL_FUNCTION_P (expression))
- {
- gcc_assert (!dependent_type_p (TREE_TYPE (expression))
- || undeduced_auto_decl (expression));
- return false;
- }
+ /* Otherwise, if the function decl isn't from a dependent scope, it can't be
+ type-dependent. Checking this is important for functions with auto return
+ type, which looks like a dependent type. */
+ if (TREE_CODE (expression) == FUNCTION_DECL
+ && !(DECL_CLASS_SCOPE_P (expression)
+ && dependent_type_p (DECL_CONTEXT (expression)))
+ && !(DECL_FRIEND_P (expression)
+ && (!DECL_FRIEND_CONTEXT (expression)
+ || dependent_type_p (DECL_FRIEND_CONTEXT (expression))))
+ && !DECL_LOCAL_FUNCTION_P (expression))
+ {
+ gcc_assert (!dependent_type_p (TREE_TYPE (expression))
+ || undeduced_auto_decl (expression));
+ return false;
}
/* Always dependent, on the number of arguments if nothing else. */
diff --git a/gcc/cp/rtti.c b/gcc/cp/rtti.c
index a660cdd..5b2326c 100644
--- a/gcc/cp/rtti.c
+++ b/gcc/cp/rtti.c
@@ -52,7 +52,7 @@ along with GCC; see the file COPYING3. If not see
type_info objects for static initialization.
The type information VAR_DECL of a type is held on the
- IDENTIFIER_GLOBAL_VALUE of the type's mangled name. That VAR_DECL
+ get_global_binding of the type's mangled name. That VAR_DECL
will be the internal type. It will usually have the correct
internal type reflecting the kind of type it represents (pointer,
array, function, class, inherited class, etc). When the type it
@@ -226,7 +226,7 @@ throw_bad_cast (void)
if (!fn)
{
tree name = get_identifier ("__cxa_bad_cast");
- fn = IDENTIFIER_GLOBAL_VALUE (name);
+ fn = get_global_binding (name);
if (!fn)
fn = push_throw_library_fn
(name, build_function_type_list (ptr_type_node, NULL_TREE));
@@ -245,7 +245,7 @@ throw_bad_typeid (void)
if (!fn)
{
tree name = get_identifier ("__cxa_bad_typeid");
- fn = IDENTIFIER_GLOBAL_VALUE (name);
+ fn = get_global_binding (name);
if (!fn)
{
tree t = build_reference_type (const_type_info_type_node);
@@ -446,7 +446,7 @@ get_tinfo_decl (tree type)
name = mangle_typeinfo_for_type (type);
- d = IDENTIFIER_GLOBAL_VALUE (name);
+ d = get_global_binding (name);
if (!d)
{
int ix = get_pseudo_ti_index (type);
diff --git a/gcc/cp/semantics.c b/gcc/cp/semantics.c
index 3a3ae55..71318b9 100644
--- a/gcc/cp/semantics.c
+++ b/gcc/cp/semantics.c
@@ -410,6 +410,8 @@ maybe_cleanup_point_expr (tree expr)
{
if (!processing_template_decl && stmts_are_full_exprs_p ())
expr = fold_build_cleanup_point_expr (TREE_TYPE (expr), expr);
+ else
+ expr = do_dependent_capture (expr);
return expr;
}
@@ -423,6 +425,8 @@ maybe_cleanup_point_expr_void (tree expr)
{
if (!processing_template_decl && stmts_are_full_exprs_p ())
expr = fold_build_cleanup_point_expr (void_type_node, expr);
+ else
+ expr = do_dependent_capture (expr);
return expr;
}
@@ -629,6 +633,8 @@ finish_goto_stmt (tree destination)
= fold_build_cleanup_point_expr (TREE_TYPE (destination),
destination);
}
+ else
+ destination = do_dependent_capture (destination);
}
check_goto (destination);
@@ -650,7 +656,7 @@ maybe_convert_cond (tree cond)
/* Wait until we instantiate templates before doing conversion. */
if (processing_template_decl)
- return cond;
+ return do_dependent_capture (cond);
if (warn_sequence_point)
verify_sequence_points (cond);
@@ -2705,8 +2711,12 @@ finish_compound_literal (tree type, tree compound_literal,
if (tree anode = type_uses_auto (type))
if (CLASS_PLACEHOLDER_TEMPLATE (anode))
- type = do_auto_deduction (type, compound_literal, anode, complain,
- adc_variable_type);
+ {
+ type = do_auto_deduction (type, compound_literal, anode, complain,
+ adc_variable_type);
+ if (type == error_mark_node)
+ return error_mark_node;
+ }
if (processing_template_decl)
{
@@ -3265,6 +3275,8 @@ outer_var_p (tree decl)
{
return ((VAR_P (decl) || TREE_CODE (decl) == PARM_DECL)
&& DECL_FUNCTION_SCOPE_P (decl)
+ /* Don't get confused by temporaries. */
+ && DECL_NAME (decl)
&& (DECL_CONTEXT (decl) != current_function_decl
|| parsing_nsdmi ()));
}
@@ -3282,7 +3294,7 @@ outer_automatic_var_p (tree decl)
rewrite it for lambda capture. */
tree
-process_outer_var_ref (tree decl, tsubst_flags_t complain)
+process_outer_var_ref (tree decl, tsubst_flags_t complain, bool force_use)
{
if (cp_unevaluated_operand)
/* It's not a use (3.2) if we're in an unevaluated context. */
@@ -3303,16 +3315,29 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
if (parsing_nsdmi ())
containing_function = NULL_TREE;
- if (containing_function && DECL_TEMPLATE_INFO (context)
- && LAMBDA_FUNCTION_P (containing_function))
+ /* Core issue 696: Only an odr-use of an outer automatic variable causes a
+ capture (or error), and a constant variable can decay to a prvalue
+ constant without odr-use. So don't capture yet. */
+ if (decl_constant_var_p (decl) && !force_use)
+ return decl;
+
+ if (containing_function && LAMBDA_FUNCTION_P (containing_function))
{
- /* Check whether we've already built a proxy;
- insert_pending_capture_proxies doesn't update
- local_specializations. */
- tree d = lookup_name (DECL_NAME (decl));
- if (d && is_capture_proxy (d)
- && DECL_CONTEXT (d) == containing_function)
- return d;
+ /* Check whether we've already built a proxy. */
+ tree var = decl;
+ while (is_normal_capture_proxy (var))
+ var = DECL_CAPTURED_VARIABLE (var);
+ tree d = retrieve_local_specialization (var);
+
+ if (d && d != decl && is_capture_proxy (d))
+ {
+ if (DECL_CONTEXT (d) == containing_function)
+ /* We already have an inner proxy. */
+ return d;
+ else
+ /* We need to capture an outer proxy. */
+ return process_outer_var_ref (d, complain, force_use);
+ }
}
/* If we are in a lambda function, we can move out until we hit
@@ -3350,20 +3375,6 @@ process_outer_var_ref (tree decl, tsubst_flags_t complain)
&& uses_template_parms (DECL_TI_ARGS (containing_function)))
return decl;
- /* Core issue 696: "[At the July 2009 meeting] the CWG expressed
- support for an approach in which a reference to a local
- [constant] automatic variable in a nested class or lambda body
- would enter the expression as an rvalue, which would reduce
- the complexity of the problem"
-
- FIXME update for final resolution of core issue 696. */
- if (decl_constant_var_p (decl))
- {
- tree t = maybe_constant_value (convert_from_reference (decl));
- if (TREE_CONSTANT (t))
- return t;
- }
-
if (lambda_expr && VAR_P (decl)
&& DECL_ANON_UNION_VAR_P (decl))
{
@@ -5766,7 +5777,7 @@ cp_finish_omp_clause_depend_sink (tree sink_clause)
if (TREE_CODE (TREE_TYPE (decl)) == POINTER_TYPE)
{
tree offset = TREE_PURPOSE (t);
- bool neg = wi::neg_p ((wide_int) offset);
+ bool neg = wi::neg_p (wi::to_wide (offset));
offset = fold_unary (ABS_EXPR, TREE_TYPE (offset), offset);
decl = mark_rvalue_use (decl);
decl = convert_from_reference (decl);
@@ -6218,8 +6229,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
"positive");
t = integer_one_node;
}
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
}
- t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
}
OMP_CLAUSE_OPERAND (c, 1) = t;
}
@@ -7100,8 +7111,8 @@ finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
"integral constant");
remove = true;
}
+ t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
}
- t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
}
/* Update list item. */
diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c
index f387f38..48d4094 100644
--- a/gcc/cp/tree.c
+++ b/gcc/cp/tree.c
@@ -333,6 +333,10 @@ cp_stabilize_reference (tree ref)
{
switch (TREE_CODE (ref))
{
+ case NON_DEPENDENT_EXPR:
+ /* We aren't actually evaluating this. */
+ return ref;
+
/* We need to treat specially anything stabilize_reference doesn't
handle specifically. */
case VAR_DECL:
@@ -1435,7 +1439,11 @@ strip_typedefs (tree t, bool *remove_attributes)
is_variant = true;
type = strip_typedefs (TREE_TYPE (t), remove_attributes);
- changed = type != TREE_TYPE (t) || is_variant;
+ tree canon_spec = (flag_noexcept_type
+ ? canonical_eh_spec (TYPE_RAISES_EXCEPTIONS (t))
+ : NULL_TREE);
+ changed = (type != TREE_TYPE (t) || is_variant
+ || TYPE_RAISES_EXCEPTIONS (t) != canon_spec);
for (arg_node = TYPE_ARG_TYPES (t);
arg_node;
@@ -1494,9 +1502,8 @@ strip_typedefs (tree t, bool *remove_attributes)
type_memfn_rqual (t));
}
- if (TYPE_RAISES_EXCEPTIONS (t))
- result = build_exception_variant (result,
- TYPE_RAISES_EXCEPTIONS (t));
+ if (canon_spec)
+ result = build_exception_variant (result, canon_spec);
if (TYPE_HAS_LATE_RETURN_TYPE (t))
TYPE_HAS_LATE_RETURN_TYPE (result) = 1;
}
@@ -3063,6 +3070,7 @@ struct replace_placeholders_t
{
tree obj; /* The object to be substituted for a PLACEHOLDER_EXPR. */
bool seen; /* Whether we've encountered a PLACEHOLDER_EXPR. */
+ hash_set<tree> *pset; /* To avoid walking same trees multiple times. */
};
/* Like substitute_placeholder_in_expr, but handle C++ tree codes and
@@ -3085,8 +3093,8 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
case PLACEHOLDER_EXPR:
{
tree x = obj;
- for (; !(same_type_ignoring_top_level_qualifiers_p
- (TREE_TYPE (*t), TREE_TYPE (x)));
+ for (; !same_type_ignoring_top_level_qualifiers_p (TREE_TYPE (*t),
+ TREE_TYPE (x));
x = TREE_OPERAND (x, 0))
gcc_assert (TREE_CODE (x) == COMPONENT_REF);
*t = x;
@@ -3118,8 +3126,7 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
valp = &TARGET_EXPR_INITIAL (*valp);
}
d->obj = subob;
- cp_walk_tree (valp, replace_placeholders_r,
- data_, NULL);
+ cp_walk_tree (valp, replace_placeholders_r, data_, d->pset);
d->obj = obj;
}
*walk_subtrees = false;
@@ -3151,10 +3158,11 @@ replace_placeholders (tree exp, tree obj, bool *seen_p)
return exp;
tree *tp = &exp;
- replace_placeholders_t data = { obj, false };
+ hash_set<tree> pset;
+ replace_placeholders_t data = { obj, false, &pset };
if (TREE_CODE (exp) == TARGET_EXPR)
tp = &TARGET_EXPR_INITIAL (exp);
- cp_walk_tree (tp, replace_placeholders_r, &data, NULL);
+ cp_walk_tree (tp, replace_placeholders_r, &data, &pset);
if (seen_p)
*seen_p = data.seen;
return exp;
diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c
index 028d56f..19fbe3c 100644
--- a/gcc/cp/typeck.c
+++ b/gcc/cp/typeck.c
@@ -5603,8 +5603,9 @@ tree
condition_conversion (tree expr)
{
tree t;
- if (processing_template_decl)
- return expr;
+ /* Anything that might happen in a template should go through
+ maybe_convert_cond. */
+ gcc_assert (!processing_template_decl);
t = perform_implicit_conversion_flags (boolean_type_node, expr,
tf_warning_or_error, LOOKUP_NORMAL);
t = fold_build_cleanup_point_expr (boolean_type_node, t);
@@ -5653,6 +5654,9 @@ cp_build_addr_expr_1 (tree arg, bool strict_lvalue, tsubst_flags_t complain)
return error_mark_node;
arg = mark_lvalue_use (arg);
+ if (error_operand_p (arg))
+ return error_mark_node;
+
argtype = lvalue_type (arg);
gcc_assert (!(identifier_p (arg) && IDENTIFIER_ANY_OP_P (arg)));
@@ -7044,17 +7048,21 @@ build_static_cast_1 (tree type, tree expr, bool c_cast_p,
/* Return an expression representing static_cast<TYPE>(EXPR). */
tree
-build_static_cast (tree type, tree expr, tsubst_flags_t complain)
+build_static_cast (tree type, tree oexpr, tsubst_flags_t complain)
{
+ tree expr = oexpr;
tree result;
bool valid_p;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
- if (processing_template_decl)
+ bool dependent = (dependent_type_p (type)
+ || type_dependent_expression_p (expr));
+ if (dependent)
{
- expr = build_min (STATIC_CAST_EXPR, type, expr);
+ tmpl:
+ expr = build_min (STATIC_CAST_EXPR, type, oexpr);
/* We don't know if it will or will not have side effects. */
TREE_SIDE_EFFECTS (expr) = 1;
return convert_from_reference (expr);
@@ -7076,6 +7084,8 @@ build_static_cast (tree type, tree expr, tsubst_flags_t complain)
maybe_warn_about_useless_cast (type, expr, complain);
maybe_warn_about_cast_ignoring_quals (type, complain);
}
+ if (processing_template_decl)
+ goto tmpl;
return result;
}
@@ -7691,6 +7701,8 @@ tree
cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
tree rhs, tsubst_flags_t complain)
{
+ lhs = mark_lvalue_use_nonread (lhs);
+
tree result = NULL_TREE;
tree newrhs = rhs;
tree lhstype = TREE_TYPE (lhs);
@@ -7913,6 +7925,8 @@ cp_build_modify_expr (location_t loc, tree lhs, enum tree_code modifycode,
operator. -- end note ] */
lhs = cp_stabilize_reference (lhs);
rhs = rvalue (rhs);
+ if (rhs == error_mark_node)
+ return error_mark_node;
rhs = stabilize_expr (rhs, &init);
newrhs = cp_build_binary_op (loc, modifycode, lhs, rhs, complain);
if (newrhs == error_mark_node)
@@ -8517,7 +8531,10 @@ convert_for_assignment (tree type, tree rhs,
{
tree elt = CONSTRUCTOR_ELT (rhs, 0)->value;
if (check_narrowing (ENUM_UNDERLYING_TYPE (type), elt, complain))
- rhs = cp_build_c_cast (type, elt, complain);
+ {
+ warning_sentinel w (warn_useless_cast);
+ rhs = cp_build_c_cast (type, elt, complain);
+ }
else
rhs = error_mark_node;
}
@@ -8944,10 +8961,14 @@ check_return_expr (tree retval, bool *no_warning)
if (check_for_bare_parameter_packs (retval))
return error_mark_node;
- if (WILDCARD_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl)))
+ /* If one of the types might be void, we can't tell whether we're
+ returning a value. */
+ if ((WILDCARD_TYPE_P (TREE_TYPE (DECL_RESULT (current_function_decl)))
+ && !current_function_auto_return_pattern)
|| (retval != NULL_TREE
- && type_dependent_expression_p (retval)))
- return retval;
+ && (TREE_TYPE (retval) == NULL_TREE
+ || WILDCARD_TYPE_P (TREE_TYPE (retval)))))
+ goto dependent;
}
functype = TREE_TYPE (TREE_TYPE (current_function_decl));
@@ -9085,11 +9106,13 @@ check_return_expr (tree retval, bool *no_warning)
warning (OPT_Weffc__, "%<operator=%> should return a reference to %<*this%>");
}
- if (processing_template_decl)
+ if (dependent_type_p (functype)
+ || type_dependent_expression_p (retval))
{
+ dependent:
/* We should not have changed the return value. */
gcc_assert (retval == saved_retval);
- return retval;
+ return do_dependent_capture (retval, /*force*/true);
}
/* The fabled Named Return Value optimization, as per [class.copy]/15:
@@ -9113,6 +9136,7 @@ check_return_expr (tree retval, bool *no_warning)
named_return_value_okay_p =
(retval != NULL_TREE
+ && !processing_template_decl
/* Must be a local, automatic variable. */
&& VAR_P (retval)
&& DECL_CONTEXT (retval) == current_function_decl
@@ -9204,11 +9228,15 @@ check_return_expr (tree retval, bool *no_warning)
&& TREE_CODE (TREE_OPERAND (retval, 1)) == AGGR_INIT_EXPR)
retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
TREE_OPERAND (retval, 0));
- else if (maybe_warn_about_returning_address_of_local (retval))
+ else if (!processing_template_decl
+ && maybe_warn_about_returning_address_of_local (retval))
retval = build2 (COMPOUND_EXPR, TREE_TYPE (retval), retval,
build_zero_cst (TREE_TYPE (retval)));
}
+ if (processing_template_decl)
+ return saved_retval;
+
/* Actually copy the value returned into the appropriate location. */
if (retval && retval != result)
retval = build2 (INIT_EXPR, TREE_TYPE (result), result, retval);
diff --git a/gcc/cp/typeck2.c b/gcc/cp/typeck2.c
index 82e18ec..39bc97a 100644
--- a/gcc/cp/typeck2.c
+++ b/gcc/cp/typeck2.c
@@ -1908,9 +1908,10 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain)
{
/* 5.5/6: In a .* expression whose object expression is an rvalue, the
program is ill-formed if the second operand is a pointer to member
- function with ref-qualifier &. In a .* expression whose object
- expression is an lvalue, the program is ill-formed if the second
- operand is a pointer to member function with ref-qualifier &&. */
+ function with ref-qualifier & (for C++2A: unless its cv-qualifier-seq
+ is const). In a .* expression whose object expression is an lvalue,
+ the program is ill-formed if the second operand is a pointer to member
+ function with ref-qualifier &&. */
if (FUNCTION_REF_QUALIFIED (type))
{
bool lval = lvalue_p (datum);
@@ -1921,7 +1922,12 @@ build_m_component_ref (tree datum, tree component, tsubst_flags_t complain)
ptrmem_type);
return error_mark_node;
}
- else if (!lval && !FUNCTION_RVALUE_QUALIFIED (type))
+ else if (!lval
+ && !FUNCTION_RVALUE_QUALIFIED (type)
+ && (cxx_dialect < cxx2a
+ || ((type_memfn_quals (type)
+ & (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE))
+ != TYPE_QUAL_CONST)))
{
if (complain & tf_error)
error ("pointer-to-member-function type %qT requires an lvalue",
diff --git a/gcc/cse.c b/gcc/cse.c
index 672fd2e..65cc9ae 100644
--- a/gcc/cse.c
+++ b/gcc/cse.c
@@ -3607,12 +3607,12 @@ fold_rtx (rtx x, rtx_insn *insn)
enum rtx_code associate_code;
if (is_shift
- && (INTVAL (const_arg1) >= GET_MODE_PRECISION (mode)
+ && (INTVAL (const_arg1) >= GET_MODE_UNIT_PRECISION (mode)
|| INTVAL (const_arg1) < 0))
{
if (SHIFT_COUNT_TRUNCATED)
canon_const_arg1 = GEN_INT (INTVAL (const_arg1)
- & (GET_MODE_BITSIZE (mode)
+ & (GET_MODE_UNIT_BITSIZE (mode)
- 1));
else
break;
@@ -3656,12 +3656,13 @@ fold_rtx (rtx x, rtx_insn *insn)
break;
if (is_shift
- && (INTVAL (inner_const) >= GET_MODE_PRECISION (mode)
+ && (INTVAL (inner_const) >= GET_MODE_UNIT_PRECISION (mode)
|| INTVAL (inner_const) < 0))
{
if (SHIFT_COUNT_TRUNCATED)
inner_const = GEN_INT (INTVAL (inner_const)
- & (GET_MODE_BITSIZE (mode) - 1));
+ & (GET_MODE_UNIT_BITSIZE (mode)
+ - 1));
else
break;
}
@@ -3686,12 +3687,12 @@ fold_rtx (rtx x, rtx_insn *insn)
if (is_shift
&& CONST_INT_P (new_const)
- && INTVAL (new_const) >= GET_MODE_PRECISION (mode))
+ && INTVAL (new_const) >= GET_MODE_UNIT_PRECISION (mode))
{
/* As an exception, we can turn an ASHIFTRT of this
form into a shift of the number of bits - 1. */
if (code == ASHIFTRT)
- new_const = GEN_INT (GET_MODE_BITSIZE (mode) - 1);
+ new_const = GEN_INT (GET_MODE_UNIT_BITSIZE (mode) - 1);
else if (!side_effects_p (XEXP (y, 0)))
return CONST0_RTX (mode);
else
@@ -5977,7 +5978,6 @@ cse_insn (rtx_insn *insn)
rtx new_src = 0;
unsigned src_hash;
struct table_elt *src_elt;
- int byte = 0;
/* Ignore invalid entries. */
if (!REG_P (elt->exp)
@@ -5990,13 +5990,8 @@ cse_insn (rtx_insn *insn)
new_src = elt->exp;
else
{
- /* Calculate big endian correction for the SUBREG_BYTE.
- We have already checked that M1 (GET_MODE (dest))
- is not narrower than M2 (new_mode). */
- if (BYTES_BIG_ENDIAN)
- byte = (GET_MODE_SIZE (GET_MODE (dest))
- - GET_MODE_SIZE (new_mode));
-
+ unsigned int byte
+ = subreg_lowpart_offset (new_mode, GET_MODE (dest));
new_src = simplify_gen_subreg (new_mode, elt->exp,
GET_MODE (dest), byte);
}
diff --git a/gcc/dbxout.c b/gcc/dbxout.c
index ea7c97c..0615e84 100644
--- a/gcc/dbxout.c
+++ b/gcc/dbxout.c
@@ -714,7 +714,7 @@ stabstr_O (tree cst)
/* If the value is zero, the base indicator will serve as the value
all by itself. */
- if (wi::eq_p (cst, 0))
+ if (wi::to_wide (cst) == 0)
return;
/* GDB wants constants with no extra leading "1" bits, so
@@ -722,19 +722,19 @@ stabstr_O (tree cst)
present. */
if (res_pres == 1)
{
- digit = wi::extract_uhwi (cst, prec - 1, 1);
+ digit = wi::extract_uhwi (wi::to_wide (cst), prec - 1, 1);
stabstr_C ('0' + digit);
}
else if (res_pres == 2)
{
- digit = wi::extract_uhwi (cst, prec - 2, 2);
+ digit = wi::extract_uhwi (wi::to_wide (cst), prec - 2, 2);
stabstr_C ('0' + digit);
}
prec -= res_pres;
for (i = prec - 3; i >= 0; i = i - 3)
{
- digit = wi::extract_uhwi (cst, i, 3);
+ digit = wi::extract_uhwi (wi::to_wide (cst), i, 3);
stabstr_C ('0' + digit);
}
}
diff --git a/gcc/defaults.h b/gcc/defaults.h
index d3265fc..99cd9db 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -1265,10 +1265,6 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#define LOAD_EXTEND_OP(M) UNKNOWN
#endif
-#ifndef CONSTANT_ALIGNMENT
-#define CONSTANT_ALIGNMENT(EXP, ALIGN) ALIGN
-#endif
-
#ifndef INITIAL_FRAME_ADDRESS_RTX
#define INITIAL_FRAME_ADDRESS_RTX NULL
#endif
diff --git a/gcc/diagnostic-color.c b/gcc/diagnostic-color.c
index 6adb872..b8cf6f2 100644
--- a/gcc/diagnostic-color.c
+++ b/gcc/diagnostic-color.c
@@ -20,6 +20,10 @@
#include "system.h"
#include "diagnostic-color.h"
+#ifdef __MINGW32__
+# include <windows.h>
+#endif
+
/* Select Graphic Rendition (SGR, "\33[...m") strings. */
/* Also Erase in Line (EL) to Right ("\33[K") by default. */
/* Why have EL to Right after SGR?
@@ -275,23 +279,28 @@ parse_gcc_colors (void)
return true;
}
-#if defined(_WIN32)
-bool
-colorize_init (diagnostic_color_rule_t)
-{
- return false;
-}
-#else
-
/* Return true if we should use color when in auto mode, false otherwise. */
static bool
should_colorize (void)
{
+#ifdef __MINGW32__
+ /* For consistency reasons, one should check the handle returned by
+ _get_osfhandle(_fileno(stderr)) because the function
+ pp_write_text_to_stream() in pretty-print.c calls fputs() on
+ that stream. However, the code below for non-Windows doesn't seem
+ to care about it either... */
+ HANDLE h;
+ DWORD m;
+
+ h = GetStdHandle (STD_ERROR_HANDLE);
+ return (h != INVALID_HANDLE_VALUE) && (h != NULL)
+ && GetConsoleMode (h, &m);
+#else
char const *t = getenv ("TERM");
return t && strcmp (t, "dumb") != 0 && isatty (STDERR_FILENO);
+#endif
}
-
bool
colorize_init (diagnostic_color_rule_t rule)
{
@@ -310,4 +319,3 @@ colorize_init (diagnostic_color_rule_t rule)
gcc_unreachable ();
}
}
-#endif
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index a66a795..b1b9c29 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2783,23 +2783,25 @@ The @code{ifunc} attribute is used to mark a function as an indirect
function using the STT_GNU_IFUNC symbol type extension to the ELF
standard. This allows the resolution of the symbol value to be
determined dynamically at load time, and an optimized version of the
-routine can be selected for the particular processor or other system
+routine to be selected for the particular processor or other system
characteristics determined then. To use this attribute, first define
the implementation functions available, and a resolver function that
returns a pointer to the selected implementation function. The
implementation functions' declarations must match the API of the
-function being implemented, the resolver's declaration is be a
-function returning pointer to void function returning void:
+function being implemented. The resolver should be declared to
+be a function taking no arguments and returning a pointer to
+a function of the same type as the implementation. For example:
@smallexample
void *my_memcpy (void *dst, const void *src, size_t len)
@{
@dots{}
+ return dst;
@}
-static void (*resolve_memcpy (void)) (void)
+static void * (*resolve_memcpy (void))(void *, const void *, size_t)
@{
- return my_memcpy; // we'll just always select this routine
+ return my_memcpy; // we will just always select this routine
@}
@end smallexample
@@ -2812,15 +2814,56 @@ extern void *memcpy (void *, const void *, size_t);
@end smallexample
@noindent
-allowing the user to call this as a regular function, unaware of the
-implementation. Finally, the indirect function needs to be defined in
-the same translation unit as the resolver function:
+allowing the user to call @code{memcpy} as a regular function, unaware of
+the actual implementation. Finally, the indirect function needs to be
+defined in the same translation unit as the resolver function:
@smallexample
void *memcpy (void *, const void *, size_t)
__attribute__ ((ifunc ("resolve_memcpy")));
@end smallexample
+In C++, the @code{ifunc} attribute takes a string that is the mangled name
+of the resolver function. A C++ resolver for a non-static member function
+of class @code{C} should be declared to return a pointer to a non-member
+function taking pointer to @code{C} as the first argument, followed by
+the same arguments as of the implementation function. G++ checks
+the signatures of the two functions and issues
+a @option{-Wattribute-alias} warning for mismatches. To suppress a warning
+for the necessary cast from a pointer to the implementation member function
+to the type of the corresponding non-member function use
+the @option{-Wno-pmf-conversions} option. For example:
+
+@smallexample
+class S
+@{
+private:
+ int debug_impl (int);
+ int optimized_impl (int);
+
+ typedef int Func (S*, int);
+
+ static Func* resolver ();
+public:
+
+ int interface (int);
+@};
+
+int S::debug_impl (int) @{ /* @r{@dots{}} */ @}
+int S::optimized_impl (int) @{ /* @r{@dots{}} */ @}
+
+S::Func* S::resolver ()
+@{
+ int (S::*pimpl) (int)
+ = getenv ("DEBUG") ? &S::debug_impl : &S::optimized_impl;
+
+ // Cast triggers -Wno-pmf-conversions.
+ return reinterpret_cast<Func*>(pimpl);
+@}
+
+int S::interface (int) __attribute__ ((ifunc ("_ZN1S8resolverEv")));
+@end smallexample
+
Indirect functions cannot be weak. Binutils version 2.20.1 or higher
and GNU C Library version 2.11.1 are required to use this feature.
@@ -5647,6 +5690,58 @@ Specify which floating-point unit to use. You must specify the
@code{target("fpmath=sse,387")} option as
@code{target("fpmath=sse+387")} because the comma would separate
different options.
+
+@item nocf_check
+@cindex @code{nocf_check} function attribute
+The @code{nocf_check} attribute on a function is used to inform the
+compiler that the function's prologue should not be instrumented when
+compiled with the @option{-fcf-protection=branch} option. The
+compiler assumes that the function's address is a valid target for a
+control-flow transfer.
+
+The @code{nocf_check} attribute on a type of pointer to function is
+used to inform the compiler that a call through the pointer should
+not be instrumented when compiled with the
+@option{-fcf-protection=branch} option. The compiler assumes
+that the function's address from the pointer is a valid target for
+a control-flow transfer. A direct function call through a function
+name is assumed to be a safe call thus direct calls are not
+instrumented by the compiler.
+
+The @code{nocf_check} attribute is applied to an object's type.
+In case of assignment of a function address or a function pointer to
+another pointer, the attribute is not carried over from the right-hand
+object's type; the type of left-hand object stays unchanged. The
+compiler checks for @code{nocf_check} attribute mismatch and reports
+a warning in case of mismatch.
+
+@smallexample
+@{
+int foo (void) __attribute__(nocf_check);
+void (*foo1)(void) __attribute__(nocf_check);
+void (*foo2)(void);
+
+int
+foo (void) /* The function's address is assumed to be valid. */
+
+ /* This call site is not checked for control-flow validity. */
+ (*foo1)();
+
+ foo1 = foo2; /* A warning is printed about attribute mismatch. */
+ /* This call site is still not checked for control-flow validity. */
+ (*foo1)();
+
+ /* This call site is checked for control-flow validity. */
+ (*foo2)();
+
+ foo2 = foo1; /* A warning is printed about attribute mismatch. */
+ /* This call site is still checked for control-flow validity. */
+ (*foo2)();
+
+ return 0;
+@}
+@end smallexample
+
@end table
On the x86, the inliner does not inline a
@@ -8079,7 +8174,7 @@ A comma-separated list of C expressions read by the instructions in the
@item Clobbers
A comma-separated list of registers or other values changed by the
@var{AssemblerTemplate}, beyond those listed as outputs.
-An empty list is permitted. @xref{Clobbers}.
+An empty list is permitted. @xref{Clobbers and Scratch Registers}.
@item GotoLabels
When you are using the @code{goto} form of @code{asm}, this section contains
@@ -8439,7 +8534,7 @@ The enclosing parentheses are a required part of the syntax.
When the compiler selects the registers to use to
represent the output operands, it does not use any of the clobbered registers
-(@pxref{Clobbers}).
+(@pxref{Clobbers and Scratch Registers}).
Output operand expressions must be lvalues. The compiler cannot check whether
the operands have data types that are reasonable for the instruction being
@@ -8675,7 +8770,8 @@ as input. The enclosing parentheses are a required part of the syntax.
@end table
When the compiler selects the registers to use to represent the input
-operands, it does not use any of the clobbered registers (@pxref{Clobbers}).
+operands, it does not use any of the clobbered registers
+(@pxref{Clobbers and Scratch Registers}).
If there are no output operands but there are input operands, place two
consecutive colons where the output operands would go:
@@ -8726,9 +8822,10 @@ asm ("cmoveq %1, %2, %[result]"
: "r" (test), "r" (new), "[result]" (old));
@end example
-@anchor{Clobbers}
-@subsubsection Clobbers
+@anchor{Clobbers and Scratch Registers}
+@subsubsection Clobbers and Scratch Registers
@cindex @code{asm} clobbers
+@cindex @code{asm} scratch registers
While the compiler is aware of changes to entries listed in the output
operands, the inline @code{asm} code may modify more than just the outputs. For
@@ -8759,7 +8856,7 @@ registers:
asm volatile ("movc3 %0, %1, %2"
: /* No outputs. */
: "g" (from), "g" (to), "g" (count)
- : "r0", "r1", "r2", "r3", "r4", "r5");
+ : "r0", "r1", "r2", "r3", "r4", "r5", "memory");
@end example
Also, there are two special clobber arguments:
@@ -8790,14 +8887,141 @@ Note that this clobber does not prevent the @emph{processor} from doing
speculative reads past the @code{asm} statement. To prevent that, you need
processor-specific fence instructions.
-Flushing registers to memory has performance implications and may be an issue
-for time-sensitive code. You can use a trick to avoid this if the size of
-the memory being accessed is known at compile time. For example, if accessing
-ten bytes of a string, use a memory input like:
+@end table
-@code{@{"m"( (@{ struct @{ char x[10]; @} *p = (void *)ptr ; *p; @}) )@}}.
+Flushing registers to memory has performance implications and may be
+an issue for time-sensitive code. You can provide better information
+to GCC to avoid this, as shown in the following examples. At a
+minimum, aliasing rules allow GCC to know what memory @emph{doesn't}
+need to be flushed.
-@end table
+Here is a fictitious sum of squares instruction, that takes two
+pointers to floating point values in memory and produces a floating
+point register output.
+Notice that @code{x}, and @code{y} both appear twice in the @code{asm}
+parameters, once to specify memory accessed, and once to specify a
+base register used by the @code{asm}. You won't normally be wasting a
+register by doing this as GCC can use the same register for both
+purposes. However, it would be foolish to use both @code{%1} and
+@code{%3} for @code{x} in this @code{asm} and expect them to be the
+same. In fact, @code{%3} may well not be a register. It might be a
+symbolic memory reference to the object pointed to by @code{x}.
+
+@smallexample
+asm ("sumsq %0, %1, %2"
+ : "+f" (result)
+ : "r" (x), "r" (y), "m" (*x), "m" (*y));
+@end smallexample
+
+Here is a fictitious @code{*z++ = *x++ * *y++} instruction.
+Notice that the @code{x}, @code{y} and @code{z} pointer registers
+must be specified as input/output because the @code{asm} modifies
+them.
+
+@smallexample
+asm ("vecmul %0, %1, %2"
+ : "+r" (z), "+r" (x), "+r" (y), "=m" (*z)
+ : "m" (*x), "m" (*y));
+@end smallexample
+
+An x86 example where the string memory argument is of unknown length.
+
+@smallexample
+asm("repne scasb"
+ : "=c" (count), "+D" (p)
+ : "m" (*(const char (*)[]) p), "0" (-1), "a" (0));
+@end smallexample
+
+If you know the above will only be reading a ten byte array then you
+could instead use a memory input like:
+@code{"m" (*(const char (*)[10]) p)}.
+
+Here is an example of a PowerPC vector scale implemented in assembly,
+complete with vector and condition code clobbers, and some initialized
+offset registers that are unchanged by the @code{asm}.
+
+@smallexample
+void
+dscal (size_t n, double *x, double alpha)
+@{
+ asm ("/* lots of asm here */"
+ : "+m" (*(double (*)[n]) x), "+&r" (n), "+b" (x)
+ : "d" (alpha), "b" (32), "b" (48), "b" (64),
+ "b" (80), "b" (96), "b" (112)
+ : "cr0",
+ "vs32","vs33","vs34","vs35","vs36","vs37","vs38","vs39",
+ "vs40","vs41","vs42","vs43","vs44","vs45","vs46","vs47");
+@}
+@end smallexample
+
+Rather than allocating fixed registers via clobbers to provide scratch
+registers for an @code{asm} statement, an alternative is to define a
+variable and make it an early-clobber output as with @code{a2} and
+@code{a3} in the example below. This gives the compiler register
+allocator more freedom. You can also define a variable and make it an
+output tied to an input as with @code{a0} and @code{a1}, tied
+respectively to @code{ap} and @code{lda}. Of course, with tied
+outputs your @code{asm} can't use the input value after modifying the
+output register since they are one and the same register. What's
+more, if you omit the early-clobber on the output, it is possible that
+GCC might allocate the same register to another of the inputs if GCC
+could prove they had the same value on entry to the @code{asm}. This
+is why @code{a1} has an early-clobber. Its tied input, @code{lda}
+might conceivably be known to have the value 16 and without an
+early-clobber share the same register as @code{%11}. On the other
+hand, @code{ap} can't be the same as any of the other inputs, so an
+early-clobber on @code{a0} is not needed. It is also not desirable in
+this case. An early-clobber on @code{a0} would cause GCC to allocate
+a separate register for the @code{"m" (*(const double (*)[]) ap)}
+input. Note that tying an input to an output is the way to set up an
+initialized temporary register modified by an @code{asm} statement.
+An input not tied to an output is assumed by GCC to be unchanged, for
+example @code{"b" (16)} below sets up @code{%11} to 16, and GCC might
+use that register in following code if the value 16 happened to be
+needed. You can even use a normal @code{asm} output for a scratch if
+all inputs that might share the same register are consumed before the
+scratch is used. The VSX registers clobbered by the @code{asm}
+statement could have used this technique except for GCC's limit on the
+number of @code{asm} parameters.
+
+@smallexample
+static void
+dgemv_kernel_4x4 (long n, const double *ap, long lda,
+ const double *x, double *y, double alpha)
+@{
+ double *a0;
+ double *a1;
+ double *a2;
+ double *a3;
+
+ __asm__
+ (
+ /* lots of asm here */
+ "#n=%1 ap=%8=%12 lda=%13 x=%7=%10 y=%0=%2 alpha=%9 o16=%11\n"
+ "#a0=%3 a1=%4 a2=%5 a3=%6"
+ :
+ "+m" (*(double (*)[n]) y),
+ "+&r" (n), // 1
+ "+b" (y), // 2
+ "=b" (a0), // 3
+ "=&b" (a1), // 4
+ "=&b" (a2), // 5
+ "=&b" (a3) // 6
+ :
+ "m" (*(const double (*)[n]) x),
+ "m" (*(const double (*)[]) ap),
+ "d" (alpha), // 9
+ "r" (x), // 10
+ "b" (16), // 11
+ "3" (ap), // 12
+ "4" (lda) // 13
+ :
+ "cr0",
+ "vs32","vs33","vs34","vs35","vs36","vs37",
+ "vs40","vs41","vs42","vs43","vs44","vs45","vs46","vs47"
+ );
+@}
+@end smallexample
@anchor{GotoLabels}
@subsubsection Goto Labels
@@ -10697,6 +10921,7 @@ in the Cilk Plus language manual which can be found at
@cindex built-in functions
@findex __builtin_alloca
@findex __builtin_alloca_with_align
+@findex __builtin_alloca_with_align_and_max
@findex __builtin_call_with_static_chain
@findex __builtin_fpclassify
@findex __builtin_isfinite
@@ -11344,6 +11569,16 @@ an extension. @xref{Variable Length}, for details.
@end deftypefn
+@deftypefn {Built-in Function} void *__builtin_alloca_with_align_and_max (size_t size, size_t alignment, size_t max_size)
+Similar to @code{__builtin_alloca_with_align} but takes an extra argument
+specifying an upper bound for @var{size} in case its value cannot be computed
+at compile time, for use by @option{-fstack-usage}, @option{-Wstack-usage}
+and @option{-Walloca-larger-than}. @var{max_size} must be a constant integer
+expression, it has no effect on code generation and no attempt is made to
+check its compatibility with @var{size}.
+
+@end deftypefn
+
@deftypefn {Built-in Function} int __builtin_types_compatible_p (@var{type1}, @var{type2})
You can use the built-in function @code{__builtin_types_compatible_p} to
@@ -12039,6 +12274,7 @@ instructions, but allow the compiler to schedule those calls.
* PowerPC Built-in Functions::
* PowerPC AltiVec/VSX Built-in Functions::
* PowerPC Hardware Transactional Memory Built-in Functions::
+* PowerPC Atomic Memory Operation Functions::
* RX Built-in Functions::
* S/390 System z Built-in Functions::
* SH Built-in Functions::
@@ -15346,14 +15582,47 @@ that use the ISA 3.0 instruction set.
@table @code
@item __float128 __builtin_sqrtf128 (__float128)
-Similar to @code{__builtin_sqrtf}, except the return and input types
-are @code{__float128}.
+Perform a 128-bit IEEE floating point square root operation.
@findex __builtin_sqrtf128
@item __float128 __builtin_fmaf128 (__float128, __float128, __float128)
-Similar to @code{__builtin_fma}, except the return and input types are
-@code{__float128}.
+Perform a 128-bit IEEE floating point fused multiply and add operation.
@findex __builtin_fmaf128
+
+@item __float128 __builtin_addf128_round_to_odd (__float128, __float128)
+Perform a 128-bit IEEE floating point add using round to odd as the
+rounding mode.
+@findex __builtin_addf128_round_to_odd
+
+@item __float128 __builtin_subf128_round_to_odd (__float128, __float128)
+Perform a 128-bit IEEE floating point subtract using round to odd as
+the rounding mode.
+@findex __builtin_subf128_round_to_odd
+
+@item __float128 __builtin_mulf128_round_to_odd (__float128, __float128)
+Perform a 128-bit IEEE floating point multiply using round to odd as
+the rounding mode.
+@findex __builtin_mulf128_round_to_odd
+
+@item __float128 __builtin_divf128_round_to_odd (__float128, __float128)
+Perform a 128-bit IEEE floating point divide using round to odd as
+the rounding mode.
+@findex __builtin_divf128_round_to_odd
+
+@item __float128 __builtin_sqrtf128_round_to_odd (__float128)
+Perform a 128-bit IEEE floating point square root using round to odd
+as the rounding mode.
+@findex __builtin_sqrtf128_round_to_odd
+
+@item __float128 __builtin_fmaf128 (__float128, __float128, __float128)
+Perform a 128-bit IEEE floating point fused multiply and add operation
+using round to odd as the rounding mode.
+@findex __builtin_fmaf128_round_to_odd
+
+@item double __builtin_truncf128_round_to_odd (__float128)
+Convert a 128-bit IEEE floating point value to @code{double} using
+round to odd as the rounding mode.
+@findex __builtin_truncf128_round_to_odd
@end table
The following built-in functions are available for the PowerPC family
@@ -15651,6 +15920,8 @@ vector unsigned short vec_xl_len (unsigned short *addr, size_t len);
vector double vec_xl_len (double *addr, size_t len);
vector float vec_xl_len (float *addr, size_t len);
+vector unsigned char vec_xl_len_r (unsigned char *addr, size_t len);
+
void vec_xst_len (vector signed char data, signed char *addr, size_t len);
void vec_xst_len (vector unsigned char data, unsigned char *addr, size_t len);
void vec_xst_len (vector signed int data, signed int *addr, size_t len);
@@ -15664,6 +15935,8 @@ void vec_xst_len (vector signed __int128 data, signed __int128 *addr, size_t len
void vec_xst_len (vector double data, double *addr, size_t len);
void vec_xst_len (vector float data, float *addr, size_t len);
+void vec_xst_len_r (vector unsigned char data, unsigned char *addr, size_t len);
+
signed char vec_xlx (unsigned int index, vector signed char data);
unsigned char vec_xlx (unsigned int index, vector unsigned char data);
signed short vec_xlx (unsigned int index, vector signed short data);
@@ -19087,6 +19360,67 @@ while (1)
@}
@end smallexample
+@node PowerPC Atomic Memory Operation Functions
+@subsection PowerPC Atomic Memory Operation Functions
+ISA 3.0 of the PowerPC added new atomic memory operation (amo)
+instructions. GCC provides support for these instructions in 64-bit
+environments. All of the functions are declared in the include file
+@code{amo.h}.
+
+The functions supported are:
+
+@smallexample
+#include <amo.h>
+
+uint32_t amo_lwat_add (uint32_t *, uint32_t);
+uint32_t amo_lwat_xor (uint32_t *, uint32_t);
+uint32_t amo_lwat_ior (uint32_t *, uint32_t);
+uint32_t amo_lwat_and (uint32_t *, uint32_t);
+uint32_t amo_lwat_umax (uint32_t *, uint32_t);
+uint32_t amo_lwat_umin (uint32_t *, uint32_t);
+uint32_t amo_lwat_swap (uint32_t *, uint32_t);
+
+int32_t amo_lwat_sadd (int32_t *, int32_t);
+int32_t amo_lwat_smax (int32_t *, int32_t);
+int32_t amo_lwat_smin (int32_t *, int32_t);
+int32_t amo_lwat_sswap (int32_t *, int32_t);
+
+uint64_t amo_ldat_add (uint64_t *, uint64_t);
+uint64_t amo_ldat_xor (uint64_t *, uint64_t);
+uint64_t amo_ldat_ior (uint64_t *, uint64_t);
+uint64_t amo_ldat_and (uint64_t *, uint64_t);
+uint64_t amo_ldat_umax (uint64_t *, uint64_t);
+uint64_t amo_ldat_umin (uint64_t *, uint64_t);
+uint64_t amo_ldat_swap (uint64_t *, uint64_t);
+
+int64_t amo_ldat_sadd (int64_t *, int64_t);
+int64_t amo_ldat_smax (int64_t *, int64_t);
+int64_t amo_ldat_smin (int64_t *, int64_t);
+int64_t amo_ldat_sswap (int64_t *, int64_t);
+
+void amo_stwat_add (uint32_t *, uint32_t);
+void amo_stwat_xor (uint32_t *, uint32_t);
+void amo_stwat_ior (uint32_t *, uint32_t);
+void amo_stwat_and (uint32_t *, uint32_t);
+void amo_stwat_umax (uint32_t *, uint32_t);
+void amo_stwat_umin (uint32_t *, uint32_t);
+
+void amo_stwat_sadd (int32_t *, int32_t);
+void amo_stwat_smax (int32_t *, int32_t);
+void amo_stwat_smin (int32_t *, int32_t);
+
+void amo_stdat_add (uint64_t *, uint64_t);
+void amo_stdat_xor (uint64_t *, uint64_t);
+void amo_stdat_ior (uint64_t *, uint64_t);
+void amo_stdat_and (uint64_t *, uint64_t);
+void amo_stdat_umax (uint64_t *, uint64_t);
+void amo_stdat_umin (uint64_t *, uint64_t);
+
+void amo_stdat_sadd (int64_t *, int64_t);
+void amo_stdat_smax (int64_t *, int64_t);
+void amo_stdat_smin (int64_t *, int64_t);
+@end smallexample
+
@node RX Built-in Functions
@subsection RX Built-in Functions
GCC supports some of the RX instructions which cannot be expressed in
@@ -21185,6 +21519,25 @@ void __builtin_ia32_wrpkru (unsigned int)
unsigned int __builtin_ia32_rdpkru ()
@end smallexample
+The following built-in functions are available when @option{-mcet} is used.
+They are used to support Intel Control-flow Enforcment Technology (CET).
+Each built-in function generates the machine instruction that is part of the
+function's name.
+@smallexample
+unsigned int __builtin_ia32_rdsspd (unsigned int)
+unsigned long long __builtin_ia32_rdsspq (unsigned long long)
+void __builtin_ia32_incsspd (unsigned int)
+void __builtin_ia32_incsspq (unsigned long long)
+void __builtin_ia32_saveprevssp(void);
+void __builtin_ia32_rstorssp(void *);
+void __builtin_ia32_wrssd(unsigned int, void *);
+void __builtin_ia32_wrssq(unsigned long long, void *);
+void __builtin_ia32_wrussd(unsigned int, void *);
+void __builtin_ia32_wrussq(unsigned long long, void *);
+void __builtin_ia32_setssbsy(void);
+void __builtin_ia32_clrssbsy(void *);
+@end smallexample
+
@node x86 transactional memory intrinsics
@subsection x86 Transactional Memory Intrinsics
diff --git a/gcc/doc/gimple.texi b/gcc/doc/gimple.texi
index 635abd3..fa98800 100644
--- a/gcc/doc/gimple.texi
+++ b/gcc/doc/gimple.texi
@@ -1310,11 +1310,13 @@ operand is validated with @code{is_gimple_operand}).
@end deftypefn
-@deftypefn {GIMPLE function} gcall *gimple_build_call_from_tree (tree call_expr)
-Build a @code{GIMPLE_CALL} from a @code{CALL_EXPR} node. The arguments and the
-function are taken from the expression directly. This routine
-assumes that @code{call_expr} is already in GIMPLE form. That is, its
-operands are GIMPLE values and the function call needs no further
+@deftypefn {GIMPLE function} gcall *gimple_build_call_from_tree (tree call_expr, @
+tree fnptrtype)
+Build a @code{GIMPLE_CALL} from a @code{CALL_EXPR} node. The arguments
+and the function are taken from the expression directly. The type of the
+@code{GIMPLE_CALL} is set from the second parameter passed by a caller.
+This routine assumes that @code{call_expr} is already in GIMPLE form.
+That is, its operands are GIMPLE values and the function call needs no further
simplification. All the call flags in @code{call_expr} are copied over
to the new @code{GIMPLE_CALL}.
@end deftypefn
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index da360da..82a6360 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -2492,6 +2492,13 @@ useful to verify the full @option{-fcompare-debug} testing coverage. It
must be used along with @code{bootstrap-debug-lean} and
@code{bootstrap-debug-lib}.
+@item @samp{bootstrap-cet}
+This option enables Intel CET for host tools during bootstrapping.
+@samp{BUILD_CONFIG=bootstrap-cet} is equivalent to adding
+@option{-fcf-protection -mcet} to @samp{BOOT_CFLAGS}. This option
+assumes that the host supports Intel CET (e.g. GNU assembler version
+2.30 or later).
+
@item @samp{bootstrap-time}
Arranges for the run time of each program started by the GCC driver,
built in any stage, to be logged to @file{time.log}, in the top level of
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 204c9b7..71b2445 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -461,6 +461,7 @@ Objective-C and Objective-C++ Dialects}.
-fchkp-check-read -fchkp-check-write -fchkp-store-bounds @gol
-fchkp-instrument-calls -fchkp-instrument-marked-only @gol
-fchkp-use-wrappers -fchkp-flexible-struct-trailing-arrays@gol
+-fcf-protection==@r{[}full@r{|}branch@r{|}return@r{|}none@r{]} @gol
-fstack-protector -fstack-protector-all -fstack-protector-strong @gol
-fstack-protector-explicit -fstack-check @gol
-fstack-limit-register=@var{reg} -fstack-limit-symbol=@var{sym} @gol
@@ -1194,7 +1195,7 @@ See RS/6000 and PowerPC Options.
-mincoming-stack-boundary=@var{num} @gol
-mcld -mcx16 -msahf -mmovbe -mcrc32 @gol
-mrecip -mrecip=@var{opt} @gol
--mvzeroupper -mprefer-avx128 @gol
+-mvzeroupper -mprefer-avx128 -mprefer-avx256 @gol
-mmmx -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx @gol
-mavx2 -mavx512f -mavx512pf -mavx512er -mavx512cd -mavx512vl @gol
-mavx512bw -mavx512dq -mavx512ifma -mavx512vbmi -msha -maes @gol
@@ -1203,6 +1204,7 @@ See RS/6000 and PowerPC Options.
-msse4a -m3dnow -m3dnowa -mpopcnt -mabm -mbmi -mtbm -mfma4 -mxop @gol
-mlzcnt -mbmi2 -mfxsr -mxsave -mxsaveopt -mrtm -mlwp -mmpx @gol
-mmwaitx -mclzero -mpku -mthreads @gol
+-mcet -mibt -mshstk @gol
-mms-bitfields -mno-align-stringops -minline-all-stringops @gol
-minline-stringops-dynamically -mstringop-strategy=@var{alg} @gol
-mmemcpy-strategy=@var{strategy} -mmemset-strategy=@var{strategy} @gol
@@ -4579,6 +4581,17 @@ in the @code{?}: operator is a boolean expression, the omitted value is
always 1. Often programmers expect it to be a value computed
inside the conditional expression instead.
+For C++ this also warns for some cases of unnecessary parentheses in
+declarations, which can indicate an attempt at a function call instead
+of a declaration:
+@smallexample
+@{
+ // Declares a local variable called mymutex.
+ std::unique_lock<std::mutex> (mymutex);
+ // User meant std::unique_lock<std::mutex> lock (mymutex);
+@}
+@end smallexample
+
This warning is enabled by @option{-Wall}.
@item -Wsequence-point
@@ -5190,7 +5203,7 @@ whether to issue a warning. Similarly to @option{-Wstringop-overflow=3} this
setting of the option may result in warnings for benign code.
@end table
-@item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{]}
+@item -Wsuggest-attribute=@r{[}pure@r{|}const@r{|}noreturn@r{|}format@r{|}cold@r{]}
@opindex Wsuggest-attribute=
@opindex Wno-suggest-attribute=
Warn for cases where adding an attribute may be beneficial. The
@@ -5242,6 +5255,15 @@ might be appropriate for any function that calls a function like
@code{vprintf} or @code{vscanf}, but this might not always be the
case, and some functions for which @code{format} attributes are
appropriate may not be detected.
+
+@item -Wsuggest-attribute=cold
+@opindex Wsuggest-attribute=cold
+@opindex Wno-suggest-attribute=cold
+
+Warn about functions that might be candidates for @code{cold} attribute. This
+is based on static detection and generally will only warn about functions which
+always leads to a call to another @code{cold} function such as wrappers of
+C++ @code{throw} or fatal error reporting functions leading to @code{abort}.
@end table
@item -Wsuggest-final-types
@@ -5382,6 +5404,11 @@ pointers. This warning level may give a larger number of
false positives and is deactivated by default.
@end table
+@item -Wattribute-alias
+Warn about declarations using the @code{alias} and similar attributes whose
+target is incompatible with the type of the alias. @xref{Function Attributes,
+,Declaring Attributes of Functions}.
+
@item -Wbool-compare
@opindex Wno-bool-compare
@opindex Wbool-compare
@@ -6293,7 +6320,8 @@ attributes.
@item -Wno-builtin-declaration-mismatch
@opindex Wno-builtin-declaration-mismatch
@opindex Wbuiltin-declaration-mismatch
-Warn if a built-in function is declared with the wrong signature.
+Warn if a built-in function is declared with the wrong signature or
+as non-function.
This warning is enabled by default.
@item -Wno-builtin-macro-redefined
@@ -7038,7 +7066,7 @@ Allow using extensions of later DWARF standard version than selected with
@opindex gno-column-info
Emit location column information into DWARF debugging information, rather
than just file and line.
-This option is disabled by default.
+This option is enabled by default.
@item -gz@r{[}=@var{type}@r{]}
@opindex gz
@@ -7812,7 +7840,7 @@ Use @option{-fno-delete-null-pointer-checks} to disable this optimization
for programs that depend on that behavior.
This option is enabled by default on most targets. On Nios II ELF, it
-defaults to off. On AVR and CR16, this option is completely disabled.
+defaults to off. On AVR, CR16, and MSP430, this option is completely disabled.
Passes that use the dataflow information
are enabled independently at different optimization levels.
@@ -9687,18 +9715,26 @@ file if the target supports arbitrary sections. The name of the
function or the name of the data item determines the section's name
in the output file.
-Use these options on systems where the linker can perform optimizations
-to improve locality of reference in the instruction space. Most systems
-using the ELF object format and SPARC processors running Solaris 2 have
-linkers with such optimizations. AIX may have these optimizations in
-the future.
-
-Only use these options when there are significant benefits from doing
-so. When you specify these options, the assembler and linker
-create larger object and executable files and are also slower.
-You cannot use @command{gprof} on all systems if you
-specify this option, and you may have problems with debugging if
-you specify both this option and @option{-g}.
+Use these options on systems where the linker can perform optimizations to
+improve locality of reference in the instruction space. Most systems using the
+ELF object format have linkers with such optimizations. On AIX, the linker
+rearranges sections (CSECTs) based on the call graph. The performance impact
+varies.
+
+Together with a linker garbage collection (linker @option{--gc-sections}
+option) these options may lead to smaller statically-linked executables (after
+stripping).
+
+On ELF/DWARF systems these options do not degenerate the quality of the debug
+information. There could be issues with other object files/debug info formats.
+
+Only use these options when there are significant benefits from doing so. When
+you specify these options, the assembler and linker create larger object and
+executable files and are also slower. These options affect code generation.
+They prevent optimizations by the compiler and assembler using relative
+locations inside a translation unit since the locations are unknown until
+link time. An example of such an optimization is relaxing calls to short call
+instructions.
@item -fbranch-target-load-optimize
@opindex fbranch-target-load-optimize
@@ -10187,6 +10223,21 @@ compilation without. The value for compilation with profile feedback
needs to be more conservative (higher) in order to make tracer
effective.
+@item stack-clash-protection-guard-size
+Specify the size of the operating system provided stack guard as
+2 raised to @var{num} bytes. The default value is 12 (4096 bytes).
+Acceptable values are between 12 and 30. Higher values may reduce the
+number of explicit probes, but a value larger than the operating system
+provided guard will leave code vulnerable to stack clash style attacks.
+
+@item stack-clash-protection-probe-interval
+Stack clash protection involves probing stack space as it is allocated. This
+param controls the maximum distance between probes into the stack as 2 raised
+to @var{num} bytes. Acceptable values are between 10 and 16 and defaults to
+12. Higher values may reduce the number of explicit probes, but a value
+larger than the operating system provided guard will leave code vulnerable to
+stack clash style attacks.
+
@item max-cse-path-length
The maximum number of basic blocks on path that CSE considers.
@@ -10497,13 +10548,9 @@ sequence pairs. This option only applies when using
@item graphite-max-nb-scop-params
To avoid exponential effects in the Graphite loop transforms, the
number of parameters in a Static Control Part (SCoP) is bounded. The
-default value is 10 parameters. A variable whose value is unknown at
-compilation time and defined outside a SCoP is a parameter of the SCoP.
-
-@item graphite-max-bbs-per-function
-To avoid exponential effects in the detection of SCoPs, the size of
-the functions analyzed by Graphite is bounded. The default value is
-100 basic blocks.
+default value is 10 parameters, a value of zero can be used to lift
+the bound. A variable whose value is unknown at compilation time and
+defined outside a SCoP is a parameter of the SCoP.
@item loop-block-tile-size
Loop blocking or strip mining transforms, enabled with
@@ -11105,6 +11152,15 @@ to verify the referenced object has the correct dynamic type.
This option enables instrumentation of pointer arithmetics. If the pointer
arithmetics overflows, a run-time error is issued.
+@item -fsanitize=builtin
+@opindex fsanitize=builtin
+
+This option enables instrumentation of arguments to selected builtin
+functions. If an invalid value is passed to such arguments, a run-time
+error is issued. E.g.@ passing 0 as the argument to @code{__builtin_ctz}
+or @code{__builtin_clz} invokes undefined behavior and is diagnosed
+by this option.
+
@end table
While @option{-ftrapv} causes traps for signed overflows to be emitted,
@@ -11365,6 +11421,33 @@ is used to link a program, the GCC driver automatically links
against @file{libmpxwrappers}. See also @option{-static-libmpxwrappers}.
Enabled by default.
+@item -fcf-protection==@r{[}full@r{|}branch@r{|}return@r{|}none@r{]}
+@opindex fcf-protection
+Enable code instrumentation of control-flow transfers to increase
+program security by checking that target addresses of control-flow
+transfer instructions (such as indirect function call, function return,
+indirect jump) are valid. This prevents diverting the flow of control
+to an unexpected target. This is intended to protect against such
+threats as Return-oriented Programming (ROP), and similarly
+call/jmp-oriented programming (COP/JOP).
+
+The value @code{branch} tells the compiler to implement checking of
+validity of control-flow transfer at the point of indirect branch
+instructions, i.e. call/jmp instructions. The value @code{return}
+implements checking of validity at the point of returning from a
+function. The value @code{full} is an alias for specifying both
+@code{branch} and @code{return}. The value @code{none} turns off
+instrumentation.
+
+You can also use the @code{nocf_check} attribute to identify
+which functions and calls should be skipped from instrumentation
+(@pxref{Function Attributes}).
+
+Currently the x86 GNU/Linux target provides an implementation based
+on Intel Control-flow Enforcement Technology (CET). Instrumentation
+for x86 is controlled by target-specific options @option{-mcet},
+@option{-mibt} and @option{-mshstk} (@pxref{x86 Options}).
+
@item -fstack-protector
@opindex fstack-protector
Emit extra code to check for buffer overflows, such as stack smashing
@@ -11412,7 +11495,8 @@ target support in the compiler but comes with the following drawbacks:
@enumerate
@item
Modified allocation strategy for large objects: they are always
-allocated dynamically if their size exceeds a fixed threshold.
+allocated dynamically if their size exceeds a fixed threshold. Note this
+may change the semantics of some code.
@item
Fixed limit on the size of the static frame of functions: when it is
@@ -11427,6 +11511,25 @@ generic implementation, code performance is hampered.
Note that old-style stack checking is also the fallback method for
@samp{specific} if no target support has been added in the compiler.
+@samp{-fstack-check=} is designed for Ada's needs to detect infinite recursion
+and stack overflows. @samp{specific} is an excellent choice when compiling
+Ada code. It is not generally sufficient to protect against stack-clash
+attacks. To protect against those you want @samp{-fstack-clash-protection}.
+
+@item -fstack-clash-protection
+@opindex fstack-clash-protection
+Generate code to prevent stack clash style attacks. When this option is
+enabled, the compiler will only allocate one page of stack space at a time
+and each page is accessed immediately after allocation. Thus, it prevents
+allocations from jumping over any stack guard page provided by the
+operating system.
+
+Most targets do not fully support stack clash protection. However, on
+those targets @option{-fstack-clash-protection} will protect dynamic stack
+allocations. @option{-fstack-clash-protection} may also provide limited
+protection for static stack allocations if the target supports
+@option{-fstack-check=specific}.
+
@item -fstack-limit-register=@var{reg}
@itemx -fstack-limit-symbol=@var{sym}
@itemx -fno-stack-limit
@@ -14326,6 +14429,8 @@ Enable FP16 extension. This also enables floating-point instructions.
Enable the RcPc extension. This does not change code generation from GCC,
but is passed on to the assembler, enabling inline asm statements to use
instructions from the RcPc extension.
+@item dotprod
+Enable the Dot Product extension. This also enables Advanced SIMD instructions.
@end table
@@ -15566,6 +15671,9 @@ The ARMv8.1 Advanced SIMD and floating-point instructions.
The cryptographic instructions. This also enables the Advanced SIMD and
floating-point instructions.
+@item +dotprod
+Enable the Dot Product extension. This also enables Advanced SIMD instructions.
+
@item +nocrypto
Disable the cryptographic extension.
@@ -15752,6 +15860,9 @@ Permissible names for this option are the same as those for
The following extension options are common to the listed CPUs:
@table @samp
+@item +nodsp
+Disable the DSP instructions on @samp{cortex-m33}.
+
@item +nofp
Disables the floating-point instructions on @samp{arm9e},
@samp{arm946e-s}, @samp{arm966e-s}, @samp{arm968e-s}, @samp{arm10e},
@@ -25054,6 +25165,12 @@ SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA,
BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, AVX512F, AVX512PF, AVX512ER and
AVX512CD instruction set support.
+@item knm
+Intel Knights Mill CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3,
+SSSE3, SSE4.1, SSE4.2, POPCNT, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA,
+BMI, BMI2, F16C, RDSEED, ADCX, PREFETCHW, AVX512F, AVX512PF, AVX512ER, AVX512CD,
+AVX5124VNNIW, AVX5124FMAPS and AVX512VPOPCNTDQ instruction set support.
+
@item skylake-avx512
Intel Skylake Server CPU with 64-bit extensions, MOVBE, MMX, SSE, SSE2, SSE3,
SSSE3, SSE4.1, SSE4.2, POPCNT, PKU, AVX, AVX2, AES, PCLMUL, FSGSBASE, RDRND, FMA,
@@ -25742,15 +25859,19 @@ preferred alignment to @option{-mpreferred-stack-boundary=2}.
@need 200
@itemx -mclzero
@opindex mclzero
+@need 200
@itemx -mpku
@opindex mpku
+@need 200
+@itemx -mcet
+@opindex mcet
These switches enable the use of instructions in the MMX, SSE,
SSE2, SSE3, SSSE3, SSE4.1, AVX, AVX2, AVX512F, AVX512PF, AVX512ER, AVX512CD,
SHA, AES, PCLMUL, FSGSBASE, RDRND, F16C, FMA, SSE4A, FMA4, XOP, LWP, ABM,
AVX512VL, AVX512BW, AVX512DQ, AVX512IFMA AVX512VBMI, BMI, BMI2, FXSR,
-XSAVE, XSAVEOPT, LZCNT, RTM, MPX, MWAITX, PKU, 3DNow!@: or enhanced 3DNow!@:
-extended instruction sets. Each has a corresponding @option{-mno-} option
-to disable use of these instructions.
+XSAVE, XSAVEOPT, LZCNT, RTM, MPX, MWAITX, PKU, IBT, SHSTK,
+3DNow!@: or enhanced 3DNow!@: extended instruction sets. Each has a
+corresponding @option{-mno-} option to disable use of these instructions.
These extensions are also available as built-in functions: see
@ref{x86 Built-in Functions}, for details of the functions enabled and
@@ -25770,6 +25891,13 @@ supported architecture, using the appropriate flags. In particular,
the file containing the CPU detection code should be compiled without
these options.
+The @option{-mcet} option turns on the @option{-mibt} and @option{-mshstk}
+options. The @option{-mibt} option enables indirect branch tracking support
+and the @option{-mshstk} option enables shadow stack support from
+Intel Control-flow Enforcement Technology (CET). The compiler also provides
+a number of built-in functions for fine-grained control in a CET-based
+application. See @xref{x86 Built-in Functions}, for more information.
+
@item -mdump-tune-features
@opindex mdump-tune-features
This option instructs GCC to dump the names of the x86 performance
@@ -25817,6 +25945,11 @@ intrinsics.
This option instructs GCC to use 128-bit AVX instructions instead of
256-bit AVX instructions in the auto-vectorizer.
+@item -mprefer-avx256
+@opindex mprefer-avx256
+This option instructs GCC to use 256-bit AVX instructions instead of
+512-bit AVX instructions in the auto-vectorizer.
+
@item -mcx16
@opindex mcx16
This option enables GCC to generate @code{CMPXCHG16B} instructions in 64-bit
@@ -25843,6 +25976,24 @@ see @ref{Other Builtins} for details.
This option enables use of the @code{movbe} instruction to implement
@code{__builtin_bswap32} and @code{__builtin_bswap64}.
+@item -mibt
+@opindex mibt
+This option tells the compiler to use indirect branch tracking support
+(for indirect calls and jumps) from x86 Control-flow Enforcement
+Technology (CET). The option has effect only if the
+@option{-fcf-protection=full} or @option{-fcf-protection=branch} option
+is specified. The option @option{-mibt} is on by default when the
+@code{-mcet} option is specified.
+
+@item -mshstk
+@opindex mshstk
+This option tells the compiler to use shadow stack support (return
+address tracking) from x86 Control-flow Enforcement Technology (CET).
+The option has effect only if the @option{-fcf-protection=full} or
+@option{-fcf-protection=return} option is specified. The option
+@option{-mshstk} is on by default when the @option{-mcet} option is
+specified.
+
@item -mcrc32
@opindex mcrc32
This option enables built-in functions @code{__builtin_ia32_crc32qi},
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index 14aab94..c4c1138 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -6734,6 +6734,15 @@ scheduler and other passes from moving instructions and using register
equivalences across the boundary defined by the blockage insn.
This needs to be an UNSPEC_VOLATILE pattern or a volatile ASM.
+@cindex @code{memory_blockage} instruction pattern
+@item @samp{memory_blockage}
+This pattern, if defined, represents a compiler memory barrier, and will be
+placed at points across which RTL passes may not propagate memory accesses.
+This instruction needs to read and write volatile BLKmode memory. It does
+not need to generate any machine instruction. If this pattern is not defined,
+the compiler falls back to emitting an instruction corresponding
+to @code{asm volatile ("" ::: "memory")}.
+
@cindex @code{memory_barrier} instruction pattern
@item @samp{memory_barrier}
If the target memory model is not fully synchronous, then this pattern
diff --git a/gcc/doc/rtl.texi b/gcc/doc/rtl.texi
index 3b2b247..7f67685 100644
--- a/gcc/doc/rtl.texi
+++ b/gcc/doc/rtl.texi
@@ -1786,11 +1786,11 @@ If @code{FRAME_GROWS_DOWNWARD} is defined to a nonzero value, this points
to immediately above the first variable on the stack. Otherwise, it points
to the first variable on the stack.
-@cindex @code{STARTING_FRAME_OFFSET} and virtual registers
+@cindex @code{TARGET_STARTING_FRAME_OFFSET} and virtual registers
@cindex @code{FRAME_POINTER_REGNUM} and virtual registers
@code{VIRTUAL_STACK_VARS_REGNUM} is replaced with the sum of the
register given by @code{FRAME_POINTER_REGNUM} and the value
-@code{STARTING_FRAME_OFFSET}.
+@code{TARGET_STARTING_FRAME_OFFSET}.
@findex VIRTUAL_STACK_DYNAMIC_REGNUM
@item VIRTUAL_STACK_DYNAMIC_REGNUM
@@ -4040,6 +4040,22 @@ is used in place of the actual insn pattern. This is done in cases where
the pattern is either complex or misleading.
@end table
+The note @code{REG_CALL_NOCF_CHECK} is used in conjunction with the
+@option{-fcf-protection=branch} option. The note is set if a
+@code{nocf_check} attribute is specified for a function type or a
+pointer to function type. The note is stored in the @code{REG_NOTES}
+field of an insn.
+
+@table @code
+@findex REG_CALL_NOCF_CHECK
+@item REG_CALL_NOCF_CHECK
+Users have control through the @code{nocf_check} attribute to identify
+which calls to a function should be skipped from control-flow instrumentation
+when the option @option{-fcf-protection=branch} is specified. The compiler
+puts a @code{REG_CALL_NOCF_CHECK} note on each @code{CALL_INSN} instruction
+that has a function type marked with a @code{nocf_check} attribute.
+@end table
+
For convenience, the machine mode in an @code{insn_list} or
@code{expr_list} is printed using these symbolic codes in debugging dumps.
diff --git a/gcc/doc/sourcebuild.texi b/gcc/doc/sourcebuild.texi
index 9901c94..7d6d4a3 100644
--- a/gcc/doc/sourcebuild.texi
+++ b/gcc/doc/sourcebuild.texi
@@ -1357,6 +1357,12 @@ Target has runtime support for any options added with
@item fortran_integer_16
Target supports Fortran @code{integer} that is 16 bytes or longer.
+@item fortran_real_10
+Target supports Fortran @code{real} that is 10 bytes or longer.
+
+@item fortran_real_16
+Target supports Fortran @code{real} that is 16 bytes or longer.
+
@item fortran_large_int
Target supports Fortran @code{integer} kinds larger than @code{integer(8)}.
@@ -1398,6 +1404,9 @@ Target supports a vector misalign access.
@item vect_no_align
Target does not support a vector alignment mechanism.
+@item vect_peeling_profitable
+Target might require to peel loops for alignment purposes.
+
@item vect_no_int_min_max
Target does not support a vector min and max instruction on @code{int}.
@@ -1416,6 +1425,9 @@ Target supports @code{vector short} multiplication.
@item vect_int_mult
Target supports @code{vector int} multiplication.
+@item vect_long_mult
+Target supports 64 bit @code{vector long} multiplication.
+
@item vect_extract_even_odd
Target supports vector even/odd element extraction.
@@ -1499,8 +1511,20 @@ Target supports conversion from @code{float} to @code{signed int}.
@item vect_floatuint_cvt
Target supports conversion from @code{float} to @code{unsigned int}.
+@item vect_intdouble_cvt
+Target supports conversion from @code{signed int} to @code{double}.
+
+@item vect_doubleint_cvt
+Target supports conversion from @code{double} to @code{signed int}.
+
@item vect_max_reduc
Target supports max reduction for vectors.
+
+@item vect_sizes_16B_8B
+Target supports 16- and 8-bytes vectors.
+
+@item vect_sizes_32B_16B
+Target supports 32- and 16-bytes vectors.
@end table
@subsubsection Thread Local Storage attributes
@@ -2334,6 +2358,9 @@ Skip the test if the target does not support the @code{-fstack-check}
option. If @var{check} is @code{""}, support for @code{-fstack-check}
is checked, for @code{-fstack-check=("@var{check}")} otherwise.
+@item dg-require-stack-size @var{size}
+Skip the test if the target does not support a stack size of @var{size}.
+
@item dg-require-visibility @var{vis}
Skip the test if the target does not support the @code{visibility} attribute.
If @var{vis} is @code{""}, support for @code{visibility("hidden")} is
diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi
index ae65e4f..8484c1d 100644
--- a/gcc/doc/tm.texi
+++ b/gcc/doc/tm.texi
@@ -1102,19 +1102,18 @@ must be aligned to 16 byte boundaries.
If this macro is not defined, then @var{basic-align} is used.
@end defmac
-@defmac CONSTANT_ALIGNMENT (@var{constant}, @var{basic-align})
-If defined, a C expression to compute the alignment given to a constant
-that is being placed in memory. @var{constant} is the constant and
-@var{basic-align} is the alignment that the object would ordinarily
-have. The value of this macro is used instead of that alignment to
-align the object.
+@deftypefn {Target Hook} HOST_WIDE_INT TARGET_CONSTANT_ALIGNMENT (const_tree @var{constant}, HOST_WIDE_INT @var{basic_align})
+This hook returns the alignment in bits of a constant that is being
+placed in memory. @var{constant} is the constant and @var{basic_align}
+is the alignment that the object would ordinarily have.
-The default definition just returns @var{basic-align}.
+The default definition just returns @var{basic_align}.
-The typical use of this macro is to increase alignment for string
+The typical use of this hook is to increase alignment for string
constants to be word aligned so that @code{strcpy} calls that copy
-constants can be done inline.
-@end defmac
+constants can be done inline. The function
+@code{constant_alignment_word_strings} provides such a definition.
+@end deftypefn
@defmac LOCAL_ALIGNMENT (@var{type}, @var{basic-align})
If defined, a C expression to compute the alignment for a variable in
@@ -2967,22 +2966,19 @@ Define this macro if successive arguments to a function occupy decreasing
addresses on the stack.
@end defmac
-@defmac STARTING_FRAME_OFFSET
-Offset from the frame pointer to the first local variable slot to be allocated.
-
-If @code{FRAME_GROWS_DOWNWARD}, find the next slot's offset by
-subtracting the first slot's length from @code{STARTING_FRAME_OFFSET}.
-Otherwise, it is found by adding the length of the first slot to the
-value @code{STARTING_FRAME_OFFSET}.
-@c i'm not sure if the above is still correct.. had to change it to get
-@c rid of an overfull. --mew 2feb93
-@end defmac
+@deftypefn {Target Hook} HOST_WIDE_INT TARGET_STARTING_FRAME_OFFSET (void)
+This hook returns the offset from the frame pointer to the first local
+variable slot to be allocated. If @code{FRAME_GROWS_DOWNWARD}, it is the
+offset to @emph{end} of the first slot allocated, otherwise it is the
+offset to @emph{beginning} of the first slot allocated. The default
+implementation returns 0.
+@end deftypefn
@defmac STACK_ALIGNMENT_NEEDED
Define to zero to disable final alignment of the stack during reload.
The nonzero default for this macro is suitable for most ports.
-On ports where @code{STARTING_FRAME_OFFSET} is nonzero or where there
+On ports where @code{TARGET_STARTING_FRAME_OFFSET} is nonzero or where there
is a register save block following the local block that doesn't require
alignment to @code{STACK_BOUNDARY}, it may be beneficial to disable
stack alignment and do it in the backend.
@@ -3411,6 +3407,10 @@ GCC computed the default from the values of the above macros and you will
normally not need to override that default.
@end defmac
+@deftypefn {Target Hook} bool TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE (rtx @var{residual})
+Some targets make optimistic assumptions about the state of stack probing when they emit their prologues. On such targets a probe into the end of any dynamically allocated space is likely required for safety against stack clash style attacks. Define this variable to return nonzero if such a probe is required or zero otherwise. You need not define this macro if it would always have the value zero.
+@end deftypefn
+
@need 2000
@node Frame Registers
@subsection Registers That Address the Stack Frame
@@ -5754,11 +5754,23 @@ For vector memory operations the cost may depend on type (@var{vectype}) and
misalignment value (@var{misalign}).
@end deftypefn
+@deftypefn {Target Hook} HOST_WIDE_INT TARGET_VECTORIZE_PREFERRED_VECTOR_ALIGNMENT (const_tree @var{type})
+This hook returns the preferred alignment in bits for accesses to
+vectors of type @var{type} in vectorized code. This might be less than
+or greater than the ABI-defined value returned by
+@code{TARGET_VECTOR_ALIGNMENT}. It can be equal to the alignment of
+a single element, in which case the vectorizer will not try to optimize
+for alignment.
+
+The default hook returns @code{TYPE_ALIGN (@var{type})}, which is
+correct for most targets.
+@end deftypefn
+
@deftypefn {Target Hook} bool TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE (const_tree @var{type}, bool @var{is_packed})
Return true if vector alignment is reachable (by peeling N iterations) for the given scalar type @var{type}. @var{is_packed} is false if the scalar access using @var{type} is known to be naturally aligned.
@end deftypefn
-@deftypefn {Target Hook} bool TARGET_VECTORIZE_VEC_PERM_CONST_OK (machine_mode, const unsigned char *@var{sel})
+@deftypefn {Target Hook} bool TARGET_VECTORIZE_VEC_PERM_CONST_OK (machine_mode, @var{vec_perm_indices})
Return true if a vector created for @code{vec_perm_const} is valid.
@end deftypefn
@@ -6637,6 +6649,18 @@ should probably only be given to addresses with different numbers of
registers on machines with lots of registers.
@end deftypefn
+@deftypefn {Target Hook} int TARGET_INSN_COST (rtx_insn *@var{insn}, bool @var{speed})
+This target hook describes the relative costs of RTL instructions.
+
+In implementing this hook, you can use the construct
+@code{COSTS_N_INSNS (@var{n})} to specify a cost equal to @var{n} fast
+instructions.
+
+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}.
+@end deftypefn
+
@deftypefn {Target Hook} {unsigned int} TARGET_MAX_NOCE_IFCVT_SEQ_COST (edge @var{e})
This hook returns a value in the same units as @code{TARGET_RTX_COSTS},
giving the maximum acceptable cost for a sequence generated by the RTL
diff --git a/gcc/doc/tm.texi.in b/gcc/doc/tm.texi.in
index 733466d..015f59e 100644
--- a/gcc/doc/tm.texi.in
+++ b/gcc/doc/tm.texi.in
@@ -1050,19 +1050,7 @@ must be aligned to 16 byte boundaries.
If this macro is not defined, then @var{basic-align} is used.
@end defmac
-@defmac CONSTANT_ALIGNMENT (@var{constant}, @var{basic-align})
-If defined, a C expression to compute the alignment given to a constant
-that is being placed in memory. @var{constant} is the constant and
-@var{basic-align} is the alignment that the object would ordinarily
-have. The value of this macro is used instead of that alignment to
-align the object.
-
-The default definition just returns @var{basic-align}.
-
-The typical use of this macro is to increase alignment for string
-constants to be word aligned so that @code{strcpy} calls that copy
-constants can be done inline.
-@end defmac
+@hook TARGET_CONSTANT_ALIGNMENT
@defmac LOCAL_ALIGNMENT (@var{type}, @var{basic-align})
If defined, a C expression to compute the alignment for a variable in
@@ -2423,22 +2411,13 @@ Define this macro if successive arguments to a function occupy decreasing
addresses on the stack.
@end defmac
-@defmac STARTING_FRAME_OFFSET
-Offset from the frame pointer to the first local variable slot to be allocated.
-
-If @code{FRAME_GROWS_DOWNWARD}, find the next slot's offset by
-subtracting the first slot's length from @code{STARTING_FRAME_OFFSET}.
-Otherwise, it is found by adding the length of the first slot to the
-value @code{STARTING_FRAME_OFFSET}.
-@c i'm not sure if the above is still correct.. had to change it to get
-@c rid of an overfull. --mew 2feb93
-@end defmac
+@hook TARGET_STARTING_FRAME_OFFSET
@defmac STACK_ALIGNMENT_NEEDED
Define to zero to disable final alignment of the stack during reload.
The nonzero default for this macro is suitable for most ports.
-On ports where @code{STARTING_FRAME_OFFSET} is nonzero or where there
+On ports where @code{TARGET_STARTING_FRAME_OFFSET} is nonzero or where there
is a register save block following the local block that doesn't require
alignment to @code{STACK_BOUNDARY}, it may be beneficial to disable
stack alignment and do it in the backend.
@@ -2847,6 +2826,8 @@ GCC computed the default from the values of the above macros and you will
normally not need to override that default.
@end defmac
+@hook TARGET_STACK_CLASH_PROTECTION_FINAL_DYNAMIC_PROBE
+
@need 2000
@node Frame Registers
@subsection Registers That Address the Stack Frame
@@ -4086,6 +4067,8 @@ address; but often a machine-dependent strategy can generate better code.
@hook TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST
+@hook TARGET_VECTORIZE_PREFERRED_VECTOR_ALIGNMENT
+
@hook TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE
@hook TARGET_VECTORIZE_VEC_PERM_CONST_OK
@@ -4608,6 +4591,8 @@ Define this macro if a non-short-circuit operation produced by
@hook TARGET_ADDRESS_COST
+@hook TARGET_INSN_COST
+
@hook TARGET_MAX_NOCE_IFCVT_SEQ_COST
@hook TARGET_NOCE_CONVERSION_PROFITABLE_P
diff --git a/gcc/domwalk.c b/gcc/domwalk.c
index ff6604e..102a293 100644
--- a/gcc/domwalk.c
+++ b/gcc/domwalk.c
@@ -174,13 +174,29 @@ sort_bbs_postorder (basic_block *bbs, int n)
If SKIP_UNREACHBLE_BLOCKS is true, then we need to set
EDGE_EXECUTABLE on every edge in the CFG. */
dom_walker::dom_walker (cdi_direction direction,
- bool skip_unreachable_blocks)
+ bool skip_unreachable_blocks,
+ int *bb_index_to_rpo)
: m_dom_direction (direction),
m_skip_unreachable_blocks (skip_unreachable_blocks),
- m_unreachable_dom (NULL)
+ m_user_bb_to_rpo (bb_index_to_rpo != NULL),
+ m_unreachable_dom (NULL),
+ m_bb_to_rpo (bb_index_to_rpo)
{
+ /* Compute the basic-block index to RPO mapping if not provided by
+ the user. */
+ if (! m_bb_to_rpo && direction == CDI_DOMINATORS)
+ {
+ int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
+ int postorder_num = pre_and_rev_post_order_compute (NULL, postorder,
+ true);
+ m_bb_to_rpo = XNEWVEC (int, last_basic_block_for_fn (cfun));
+ for (int i = 0; i < postorder_num; ++i)
+ m_bb_to_rpo[postorder[i]] = i;
+ free (postorder);
+ }
+
/* If we are not skipping unreachable blocks, then there is nothing
- to do. */
+ further to do. */
if (!m_skip_unreachable_blocks)
return;
@@ -194,6 +210,14 @@ dom_walker::dom_walker (cdi_direction direction,
}
}
+/* Destructor. */
+
+dom_walker::~dom_walker ()
+{
+ if (! m_user_bb_to_rpo)
+ free (m_bb_to_rpo);
+}
+
/* Return TRUE if BB is reachable, false otherwise. */
bool
@@ -254,6 +278,8 @@ dom_walker::propagate_unreachable_to_edges (basic_block bb,
m_unreachable_dom = bb;
}
+const edge dom_walker::STOP = (edge)-1;
+
/* Recursively walk the dominator tree.
BB is the basic block we are currently visiting. */
@@ -264,17 +290,7 @@ dom_walker::walk (basic_block bb)
basic_block *worklist = XNEWVEC (basic_block,
n_basic_blocks_for_fn (cfun) * 2);
int sp = 0;
- int *postorder, postorder_num;
-
- if (m_dom_direction == CDI_DOMINATORS)
- {
- postorder = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
- postorder_num = pre_and_rev_post_order_compute (NULL, postorder, true);
- bb_postorder = XNEWVEC (int, last_basic_block_for_fn (cfun));
- for (int i = 0; i < postorder_num; ++i)
- bb_postorder[postorder[i]] = i;
- free (postorder);
- }
+ bb_postorder = m_bb_to_rpo;
while (true)
{
@@ -283,13 +299,14 @@ dom_walker::walk (basic_block bb)
|| bb == ENTRY_BLOCK_PTR_FOR_FN (cfun)
|| bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
{
+ edge taken_edge = NULL;
/* Callback for subclasses to do custom things before we have walked
the dominator children, but before we walk statements. */
if (this->bb_reachable (cfun, bb))
{
- edge taken_edge = before_dom_children (bb);
- if (taken_edge)
+ taken_edge = before_dom_children (bb);
+ if (taken_edge && taken_edge != STOP)
{
edge_iterator ei;
edge e;
@@ -306,12 +323,17 @@ dom_walker::walk (basic_block bb)
worklist[sp++] = bb;
worklist[sp++] = NULL;
- int saved_sp = sp;
- for (dest = first_dom_son (m_dom_direction, bb);
- dest; dest = next_dom_son (m_dom_direction, dest))
- worklist[sp++] = dest;
- if (sp - saved_sp > 1 && m_dom_direction == CDI_DOMINATORS)
- sort_bbs_postorder (&worklist[saved_sp], sp - saved_sp);
+ /* If the callback returned NONE then we are supposed to
+ stop and not even propagate EDGE_EXECUTABLE further. */
+ if (taken_edge != STOP)
+ {
+ int saved_sp = sp;
+ for (dest = first_dom_son (m_dom_direction, bb);
+ dest; dest = next_dom_son (m_dom_direction, dest))
+ worklist[sp++] = dest;
+ if (sp - saved_sp > 1 && m_dom_direction == CDI_DOMINATORS)
+ sort_bbs_postorder (&worklist[saved_sp], sp - saved_sp);
+ }
}
/* NULL is used to mark pop operations in the recursion stack. */
while (sp > 0 && !worklist[sp - 1])
@@ -331,10 +353,6 @@ dom_walker::walk (basic_block bb)
else
break;
}
- if (m_dom_direction == CDI_DOMINATORS)
- {
- free (bb_postorder);
- bb_postorder = NULL;
- }
+ bb_postorder = NULL;
free (worklist);
}
diff --git a/gcc/domwalk.h b/gcc/domwalk.h
index 4b9f70a..6ac93eb 100644
--- a/gcc/domwalk.h
+++ b/gcc/domwalk.h
@@ -30,14 +30,22 @@ along with GCC; see the file COPYING3. If not see
class dom_walker
{
public:
+ static const edge STOP;
+
/* Use SKIP_UNREACHBLE_BLOCKS = true when your client can discover
that some edges are not executable.
If a client can discover that a COND, SWITCH or GOTO has a static
target in the before_dom_children callback, the taken edge should
be returned. The generic walker will clear EDGE_EXECUTABLE on all
- edges it can determine are not executable. */
- dom_walker (cdi_direction direction, bool skip_unreachable_blocks = false);
+ edges it can determine are not executable.
+
+ You can provide a mapping of basic-block index to RPO if you
+ have that readily available or you do multiple walks. */
+ dom_walker (cdi_direction direction, bool skip_unreachable_blocks = false,
+ int *bb_index_to_rpo = NULL);
+
+ ~dom_walker ();
/* Walk the dominator tree. */
void walk (basic_block);
@@ -48,7 +56,10 @@ public:
edges, NULL otherwise. When skipping unreachable blocks, the walker
uses the taken edge information to clear EDGE_EXECUTABLE on the other
edges, exposing unreachable blocks. A NULL return value means all
- outgoing edges should still be considered executable. */
+ outgoing edges should still be considered executable. A return value
+ of STOP means to stop the domwalk from processing dominated blocks from
+ here. This can be used to process a SEME region only (note domwalk
+ will still do work linear in function size). */
virtual edge before_dom_children (basic_block) { return NULL; }
/* Function to call after the recursive walk of the dominator children. */
@@ -61,7 +72,9 @@ private:
dominator tree. */
const ENUM_BITFIELD (cdi_direction) m_dom_direction : 2;
bool m_skip_unreachable_blocks;
+ bool m_user_bb_to_rpo;
basic_block m_unreachable_dom;
+ int *m_bb_to_rpo;
/* Query whether or not the given block is reachable or not. */
bool bb_reachable (struct function *, basic_block);
diff --git a/gcc/dse.c b/gcc/dse.c
index cff3ac4..563ca9f 100644
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -1653,7 +1653,7 @@ find_shift_sequence (int access_size,
cost = 0;
for (insn = shift_seq; insn != NULL_RTX; insn = NEXT_INSN (insn))
if (INSN_P (insn))
- cost += insn_rtx_cost (PATTERN (insn), speed);
+ cost += insn_cost (insn, speed);
/* The computation up to here is essentially independent
of the arguments and could be precomputed. It may
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 1a4f1a2..dcc624e 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3702,24 +3702,24 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
#ifndef DEBUG_DWO_INFO_SECTION
#define DEBUG_DWO_INFO_SECTION ".debug_info.dwo"
#endif
-#ifndef DEBUG_LTO_DWO_INFO_SECTION
-#define DEBUG_LTO_DWO_INFO_SECTION ".gnu.debuglto_.debug_info.dwo"
-#endif
#ifndef DEBUG_LTO_INFO_SECTION
#define DEBUG_LTO_INFO_SECTION ".gnu.debuglto_.debug_info"
#endif
+#ifndef DEBUG_LTO_DWO_INFO_SECTION
+#define DEBUG_LTO_DWO_INFO_SECTION ".gnu.debuglto_.debug_info.dwo"
+#endif
#ifndef DEBUG_ABBREV_SECTION
#define DEBUG_ABBREV_SECTION ".debug_abbrev"
#endif
+#ifndef DEBUG_LTO_ABBREV_SECTION
+#define DEBUG_LTO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev"
+#endif
#ifndef DEBUG_DWO_ABBREV_SECTION
#define DEBUG_DWO_ABBREV_SECTION ".debug_abbrev.dwo"
#endif
#ifndef DEBUG_LTO_DWO_ABBREV_SECTION
#define DEBUG_LTO_DWO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev.dwo"
#endif
-#ifndef DEBUG_LTO_ABBREV_SECTION
-#define DEBUG_LTO_ABBREV_SECTION ".gnu.debuglto_.debug_abbrev"
-#endif
#ifndef DEBUG_ARANGES_SECTION
#define DEBUG_ARANGES_SECTION ".debug_aranges"
#endif
@@ -3729,35 +3729,38 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
#ifndef DEBUG_MACINFO_SECTION
#define DEBUG_MACINFO_SECTION ".debug_macinfo"
#endif
+#ifndef DEBUG_LTO_MACINFO_SECTION
+#define DEBUG_LTO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo"
+#endif
#ifndef DEBUG_DWO_MACINFO_SECTION
#define DEBUG_DWO_MACINFO_SECTION ".debug_macinfo.dwo"
#endif
#ifndef DEBUG_LTO_DWO_MACINFO_SECTION
#define DEBUG_LTO_DWO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo.dwo"
#endif
-#ifndef DEBUG_LTO_MACINFO_SECTION
-#define DEBUG_LTO_MACINFO_SECTION ".gnu.debuglto_.debug_macinfo"
+#ifndef DEBUG_MACRO_SECTION
+#define DEBUG_MACRO_SECTION ".debug_macro"
+#endif
+#ifndef DEBUG_LTO_MACRO_SECTION
+#define DEBUG_LTO_MACRO_SECTION ".gnu.debuglto_.debug_macro"
#endif
#ifndef DEBUG_DWO_MACRO_SECTION
#define DEBUG_DWO_MACRO_SECTION ".debug_macro.dwo"
#endif
-#ifndef DEBUG_MACRO_SECTION
-#define DEBUG_MACRO_SECTION ".debug_macro"
-#endif
#ifndef DEBUG_LTO_DWO_MACRO_SECTION
#define DEBUG_LTO_DWO_MACRO_SECTION ".gnu.debuglto_.debug_macro.dwo"
#endif
-#ifndef DEBUG_LTO_MACRO_SECTION
-#define DEBUG_LTO_MACRO_SECTION ".gnu.debuglto_.debug_macro"
-#endif
#ifndef DEBUG_LINE_SECTION
#define DEBUG_LINE_SECTION ".debug_line"
#endif
+#ifndef DEBUG_LTO_LINE_SECTION
+#define DEBUG_LTO_LINE_SECTION ".gnu.debuglto_.debug_line"
+#endif
#ifndef DEBUG_DWO_LINE_SECTION
#define DEBUG_DWO_LINE_SECTION ".debug_line.dwo"
#endif
-#ifndef DEBUG_LTO_LINE_SECTION
-#define DEBUG_LTO_LINE_SECTION ".gnu.debuglto_.debug_line.dwo"
+#ifndef DEBUG_LTO_DWO_LINE_SECTION
+#define DEBUG_LTO_DWO_LINE_SECTION ".gnu.debuglto_.debug_line.dwo"
#endif
#ifndef DEBUG_LOC_SECTION
#define DEBUG_LOC_SECTION ".debug_loc"
@@ -3790,18 +3793,18 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
#ifndef DEBUG_LTO_DWO_STR_OFFSETS_SECTION
#define DEBUG_LTO_DWO_STR_OFFSETS_SECTION ".gnu.debuglto_.debug_str_offsets.dwo"
#endif
-#ifndef DEBUG_STR_DWO_SECTION
-#define DEBUG_STR_DWO_SECTION ".debug_str.dwo"
-#endif
-#ifndef DEBUG_LTO_STR_DWO_SECTION
-#define DEBUG_LTO_STR_DWO_SECTION ".gnu.debuglto_.debug_str.dwo"
-#endif
#ifndef DEBUG_STR_SECTION
#define DEBUG_STR_SECTION ".debug_str"
#endif
#ifndef DEBUG_LTO_STR_SECTION
#define DEBUG_LTO_STR_SECTION ".gnu.debuglto_.debug_str"
#endif
+#ifndef DEBUG_STR_DWO_SECTION
+#define DEBUG_STR_DWO_SECTION ".debug_str.dwo"
+#endif
+#ifndef DEBUG_LTO_STR_DWO_SECTION
+#define DEBUG_LTO_STR_DWO_SECTION ".gnu.debuglto_.debug_str.dwo"
+#endif
#ifndef DEBUG_RANGES_SECTION
#define DEBUG_RANGES_SECTION ".debug_ranges"
#endif
@@ -3811,6 +3814,9 @@ new_addr_loc_descr (rtx addr, enum dtprel_bool dtprel)
#ifndef DEBUG_LINE_STR_SECTION
#define DEBUG_LINE_STR_SECTION ".debug_line_str"
#endif
+#ifndef DEBUG_LTO_LINE_STR_SECTION
+#define DEBUG_LTO_LINE_STR_SECTION ".gnu.debuglto_.debug_line_str"
+#endif
/* Standard ELF section names for compiled code and data. */
#ifndef TEXT_SECTION_NAME
@@ -5358,6 +5364,16 @@ splice_child_die (dw_die_ref parent, dw_die_ref child)
reparent_child (child, parent);
}
+/* Create and return a new die with TAG_VALUE as tag. */
+
+static inline dw_die_ref
+new_die_raw (enum dwarf_tag tag_value)
+{
+ dw_die_ref die = ggc_cleared_alloc<die_node> ();
+ die->die_tag = tag_value;
+ return die;
+}
+
/* Create and return a new die with a parent of PARENT_DIE. If
PARENT_DIE is NULL, the new DIE is placed in limbo and an
associated tree T must be supplied to determine parenthood
@@ -5366,9 +5382,7 @@ splice_child_die (dw_die_ref parent, dw_die_ref child)
static inline dw_die_ref
new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
{
- dw_die_ref die = ggc_cleared_alloc<die_node> ();
-
- die->die_tag = tag_value;
+ dw_die_ref die = new_die_raw (tag_value);
if (parent_die != NULL)
add_child_die (parent_die, die);
@@ -5562,8 +5576,7 @@ add_AT_external_die_ref (dw_die_ref die, enum dwarf_attribute attr_kind,
{
/* Create a fake DIE that contains the reference. Don't use
new_die because we don't want to end up in the limbo list. */
- dw_die_ref ref = ggc_cleared_alloc<die_node> ();
- ref->die_tag = die->die_tag;
+ dw_die_ref ref = new_die_raw (die->die_tag);
ref->die_id.die_symbol = IDENTIFIER_POINTER (get_identifier (symbol));
ref->die_offset = offset;
ref->with_offset = 1;
@@ -7706,13 +7719,10 @@ should_move_die_to_comdat (dw_die_ref die)
static dw_die_ref
clone_die (dw_die_ref die)
{
- dw_die_ref clone;
+ dw_die_ref clone = new_die_raw (die->die_tag);
dw_attr_node *a;
unsigned ix;
- clone = ggc_cleared_alloc<die_node> ();
- clone->die_tag = die->die_tag;
-
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
add_dwarf_attr (clone, a);
@@ -7756,8 +7766,7 @@ clone_as_declaration (dw_die_ref die)
return clone;
}
- clone = ggc_cleared_alloc<die_node> ();
- clone->die_tag = die->die_tag;
+ clone = new_die_raw (die->die_tag);
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
{
@@ -12084,9 +12093,6 @@ base_type_die (tree type, bool reverse)
struct fixed_point_type_info fpt_info;
tree type_bias = NULL_TREE;
- if (TREE_CODE (type) == ERROR_MARK || TREE_CODE (type) == VOID_TYPE)
- return 0;
-
/* If this is a subtype that should not be emitted as a subrange type,
use the base type. See subrange_type_for_debug_p. */
if (TREE_CODE (type) == INTEGER_TYPE && TREE_TYPE (type) != NULL_TREE)
@@ -12179,7 +12185,7 @@ base_type_die (tree type, bool reverse)
gcc_unreachable ();
}
- base_type_result = new_die (DW_TAG_base_type, comp_unit_die (), type);
+ base_type_result = new_die_raw (DW_TAG_base_type);
add_AT_unsigned (base_type_result, DW_AT_byte_size,
int_size_in_bytes (type));
@@ -12235,8 +12241,6 @@ base_type_die (tree type, bool reverse)
| dw_scalar_form_reference,
NULL);
- add_pubtype (type, base_type_result);
-
return base_type_result;
}
@@ -12264,8 +12268,6 @@ is_base_type (tree type)
{
switch (TREE_CODE (type))
{
- case ERROR_MARK:
- case VOID_TYPE:
case INTEGER_TYPE:
case REAL_TYPE:
case FIXED_POINT_TYPE:
@@ -12274,6 +12276,7 @@ is_base_type (tree type)
case POINTER_BOUNDS_TYPE:
return 1;
+ case VOID_TYPE:
case ARRAY_TYPE:
case RECORD_TYPE:
case UNION_TYPE:
@@ -12479,6 +12482,8 @@ modified_type_die (tree type, int cv_quals, bool reverse,
/* Only these cv-qualifiers are currently handled. */
const int cv_qual_mask = (TYPE_QUAL_CONST | TYPE_QUAL_VOLATILE
| TYPE_QUAL_RESTRICT | TYPE_QUAL_ATOMIC);
+ const bool reverse_base_type
+ = need_endianity_attribute_p (reverse) && is_base_type (type);
if (code == ERROR_MARK)
return NULL;
@@ -12529,29 +12534,33 @@ modified_type_die (tree type, int cv_quals, bool reverse,
qualified_type = size_type_node;
}
-
/* If we do, then we can just use its DIE, if it exists. */
if (qualified_type)
{
mod_type_die = lookup_type_die (qualified_type);
- /* DW_AT_endianity doesn't come from a qualifier on the type. */
+ /* DW_AT_endianity doesn't come from a qualifier on the type, so it is
+ dealt with specially: the DIE with the attribute, if it exists, is
+ placed immediately after the regular DIE for the same base type. */
if (mod_type_die
- && (!need_endianity_attribute_p (reverse)
- || !is_base_type (type)
- || get_AT_unsigned (mod_type_die, DW_AT_endianity)))
+ && (!reverse_base_type
+ || ((mod_type_die = mod_type_die->die_sib) != NULL
+ && get_AT_unsigned (mod_type_die, DW_AT_endianity))))
return mod_type_die;
}
name = qualified_type ? TYPE_NAME (qualified_type) : NULL;
/* Handle C typedef types. */
- if (name && TREE_CODE (name) == TYPE_DECL && DECL_ORIGINAL_TYPE (name)
+ if (name
+ && TREE_CODE (name) == TYPE_DECL
+ && DECL_ORIGINAL_TYPE (name)
&& !DECL_ARTIFICIAL (name))
{
tree dtype = TREE_TYPE (name);
- if (qualified_type == dtype)
+ /* Skip the typedef for base types with DW_AT_endianity, no big deal. */
+ if (qualified_type == dtype && !reverse_base_type)
{
tree origin = decl_ultimate_origin (name);
@@ -12664,8 +12673,7 @@ modified_type_die (tree type, int cv_quals, bool reverse,
}
if (first)
{
- d = ggc_cleared_alloc<die_node> ();
- d->die_tag = dwarf_qual_info[i].t;
+ d = new_die_raw (dwarf_qual_info[i].t);
add_child_die_after (mod_scope, d, last);
last = d;
}
@@ -12723,7 +12731,21 @@ modified_type_die (tree type, int cv_quals, bool reverse,
item_type = TREE_TYPE (type);
}
else if (is_base_type (type))
- mod_type_die = base_type_die (type, reverse);
+ {
+ mod_type_die = base_type_die (type, reverse);
+
+ /* The DIE with DW_AT_endianity is placed right after the naked DIE. */
+ if (reverse_base_type)
+ {
+ dw_die_ref after_die
+ = modified_type_die (type, cv_quals, false, context_die);
+ add_child_die_after (comp_unit_die (), mod_type_die, after_die);
+ }
+ else
+ add_child_die (comp_unit_die (), mod_type_die);
+
+ add_pubtype (type, mod_type_die);
+ }
else
{
gen_type_die (type, context_die);
@@ -12785,7 +12807,7 @@ modified_type_die (tree type, int cv_quals, bool reverse,
name ? IDENTIFIER_POINTER (name) : "__unknown__");
}
- if (qualified_type)
+ if (qualified_type && !reverse_base_type)
equate_type_number_to_die (qualified_type, mod_type_die);
if (item_type)
@@ -13718,9 +13740,17 @@ expansion_failed (tree expr, rtx rtl, char const *reason)
static bool
const_ok_for_output_1 (rtx rtl)
{
- if (GET_CODE (rtl) == UNSPEC)
+ if (targetm.const_not_ok_for_debug_p (rtl))
{
- /* If delegitimize_address couldn't do anything with the UNSPEC, assume
+ if (GET_CODE (rtl) != UNSPEC)
+ {
+ expansion_failed (NULL_TREE, rtl,
+ "Expression rejected for debug by the backend.\n");
+ return false;
+ }
+
+ /* If delegitimize_address couldn't do anything with the UNSPEC, and
+ the target hook doesn't explicitly allow it in debug info, assume
we can't express it in the debug info. */
/* Don't complain about TLS UNSPECs, those are just too hard to
delegitimize. Note this could be a non-decl SYMBOL_REF such as
@@ -13747,13 +13777,6 @@ const_ok_for_output_1 (rtx rtl)
return false;
}
- if (targetm.const_not_ok_for_debug_p (rtl))
- {
- expansion_failed (NULL_TREE, rtl,
- "Expression rejected for debug by the backend.\n");
- return false;
- }
-
/* FIXME: Refer to PR60655. It is possible for simplification
of rtl expressions in var tracking to produce such expressions.
We should really identify / validate expressions
@@ -17460,7 +17483,7 @@ loc_list_from_tree_1 (tree loc, int want_address,
&& (INTEGRAL_TYPE_P (TREE_TYPE (loc))
|| POINTER_TYPE_P (TREE_TYPE (loc)))
&& DECL_CONTEXT (loc) == current_function_decl
- && (GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (loc)))
+ && (GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (TREE_TYPE (loc)))
<= DWARF2_ADDR_SIZE))
{
dw_die_ref ref = lookup_decl_die (loc);
@@ -19071,12 +19094,11 @@ rtl_for_decl_location (tree decl)
else if (VAR_P (decl)
&& rtl
&& MEM_P (rtl)
- && GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl))
- && BYTES_BIG_ENDIAN)
+ && GET_MODE (rtl) != TYPE_MODE (TREE_TYPE (decl)))
{
machine_mode addr_mode = get_address_mode (rtl);
- int rsize = GET_MODE_SIZE (GET_MODE (rtl));
- int dsize = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (decl)));
+ HOST_WIDE_INT offset = byte_lowpart_offset (TYPE_MODE (TREE_TYPE (decl)),
+ GET_MODE (rtl));
/* If a variable is declared "register" yet is smaller than
a register, then if we store the variable to memory, it
@@ -19084,10 +19106,9 @@ rtl_for_decl_location (tree decl)
fact we are not. We need to adjust the offset of the
storage location to reflect the actual value's bytes,
else gdb will not be able to display it. */
- if (rsize > dsize)
+ if (offset != 0)
rtl = gen_rtx_MEM (TYPE_MODE (TREE_TYPE (decl)),
- plus_constant (addr_mode, XEXP (rtl, 0),
- rsize - dsize));
+ plus_constant (addr_mode, XEXP (rtl, 0), offset));
}
/* A variable with no DECL_RTL but a DECL_INITIAL is a compile-time constant,
@@ -19440,6 +19461,19 @@ tree_add_const_value_attribute (dw_die_ref die, tree t)
init = t;
gcc_assert (!DECL_P (init));
+ if (TREE_CODE (init) == INTEGER_CST)
+ {
+ if (tree_fits_uhwi_p (init))
+ {
+ add_AT_unsigned (die, DW_AT_const_value, tree_to_uhwi (init));
+ return true;
+ }
+ if (tree_fits_shwi_p (init))
+ {
+ add_AT_int (die, DW_AT_const_value, tree_to_shwi (init));
+ return true;
+ }
+ }
if (! early_dwarf)
{
rtl = rtl_for_decl_init (init, type);
@@ -19801,7 +19835,7 @@ add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
the precision of its type. The precision and signedness
of the type will be necessary to re-interpret it
unambiguously. */
- add_AT_wide (die, attr, value);
+ add_AT_wide (die, attr, wi::to_wide (value));
return;
}
@@ -20483,8 +20517,7 @@ dwarf2out_vms_debug_main_pointer (void)
dw_die_ref die;
/* Allocate the VMS debug main subprogram die. */
- die = ggc_cleared_alloc<die_node> ();
- die->die_tag = DW_TAG_subprogram;
+ die = new_die_raw (DW_TAG_subprogram);
add_name_attribute (die, VMS_DEBUG_MAIN_POINTER);
ASM_GENERATE_INTERNAL_LABEL (label, PROLOGUE_END_LABEL,
current_function_funcdef_no);
@@ -21217,7 +21250,7 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
/* Enumeration constants may be wider than HOST_WIDE_INT. Handle
that here. TODO: This should be re-worked to use correct
signed/unsigned double tags for all cases. */
- add_AT_wide (enum_die, DW_AT_const_value, value);
+ add_AT_wide (enum_die, DW_AT_const_value, wi::to_wide (value));
}
add_gnat_descriptive_type_attribute (type_die, type, context_die);
@@ -21227,8 +21260,6 @@ gen_enumeration_type_die (tree type, dw_die_ref context_die)
else
add_AT_flag (type_die, DW_AT_declaration, 1);
- add_alignment_attribute (type_die, type);
-
add_pubtype (type, type_die);
return type_die;
@@ -23330,7 +23361,6 @@ gen_producer_string (void)
case OPT_SPECIAL_program_name:
case OPT_SPECIAL_input_file:
case OPT_grecord_gcc_switches:
- case OPT_gno_record_gcc_switches:
case OPT__output_pch_:
case OPT_fdiagnostics_show_location_:
case OPT_fdiagnostics_show_option:
@@ -25474,10 +25504,16 @@ dwarf2out_early_global_decl (tree decl)
so that all nested DIEs are generated at the proper scope in the
first shot. */
tree context = decl_function_context (decl);
- if (context != NULL && lookup_decl_die (context) == NULL)
+ if (context != NULL)
{
+ dw_die_ref context_die = lookup_decl_die (context);
current_function_decl = context;
- dwarf2out_decl (context);
+
+ /* Avoid emitting DIEs multiple times, but still process CONTEXT
+ enough so that it lands in its own context. This avoids type
+ pruning issues later on. */
+ if (context_die == NULL || is_declaration_die (context_die))
+ dwarf2out_decl (context);
}
/* Emit an abstract origin of a function first. This happens
@@ -27188,7 +27224,8 @@ output_macinfo (const char *debug_line_label, bool early_lto_debug)
static void
init_sections_and_labels (bool early_lto_debug)
{
- /* As we may get called multiple times have a generation count for labels. */
+ /* As we may get called multiple times have a generation count for
+ labels. */
static unsigned generation = 0;
if (early_lto_debug)
@@ -27201,14 +27238,14 @@ init_sections_and_labels (bool early_lto_debug)
debug_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
- debug_macinfo_section_name = ((dwarf_strict && dwarf_version < 5)
- ? DEBUG_LTO_MACINFO_SECTION
- : DEBUG_LTO_MACRO_SECTION);
+ debug_macinfo_section_name
+ = ((dwarf_strict && dwarf_version < 5)
+ ? DEBUG_LTO_MACINFO_SECTION : DEBUG_LTO_MACRO_SECTION);
debug_macinfo_section = get_section (debug_macinfo_section_name,
SECTION_DEBUG
| SECTION_EXCLUDE, NULL);
- /* For macro info we have to refer to a debug_line section, so similar
- to split-dwarf emit a skeleton one for early debug. */
+ /* For macro info we have to refer to a debug_line section, so
+ similar to split-dwarf emit a skeleton one for early debug. */
debug_skeleton_line_section
= get_section (DEBUG_LTO_LINE_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
@@ -27228,15 +27265,16 @@ init_sections_and_labels (bool early_lto_debug)
debug_skeleton_info_section = get_section (DEBUG_LTO_INFO_SECTION,
SECTION_DEBUG
| SECTION_EXCLUDE, NULL);
- debug_skeleton_abbrev_section = get_section (DEBUG_LTO_ABBREV_SECTION,
- SECTION_DEBUG
- | SECTION_EXCLUDE, NULL);
+ debug_skeleton_abbrev_section
+ = get_section (DEBUG_LTO_ABBREV_SECTION,
+ SECTION_DEBUG | SECTION_EXCLUDE, NULL);
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_abbrev_section_label,
DEBUG_SKELETON_ABBREV_SECTION_LABEL,
generation);
- /* Somewhat confusing detail: The skeleton_[abbrev|info] sections stay in
- the main .o, but the skeleton_line goes into the split off dwo. */
+ /* Somewhat confusing detail: The skeleton_[abbrev|info] sections
+ stay in the main .o, but the skeleton_line goes into the split
+ off dwo. */
debug_skeleton_line_section
= get_section (DEBUG_LTO_LINE_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE, NULL);
@@ -27251,9 +27289,10 @@ init_sections_and_labels (bool early_lto_debug)
DEBUG_SKELETON_INFO_SECTION_LABEL,
generation);
debug_str_dwo_section = get_section (DEBUG_LTO_STR_DWO_SECTION,
- DEBUG_STR_DWO_SECTION_FLAGS, NULL);
+ DEBUG_STR_DWO_SECTION_FLAGS,
+ NULL);
debug_macinfo_section_name
- = (dwarf_strict
+ = ((dwarf_strict && dwarf_version < 5)
? DEBUG_LTO_DWO_MACINFO_SECTION : DEBUG_LTO_DWO_MACRO_SECTION);
debug_macinfo_section = get_section (debug_macinfo_section_name,
SECTION_DEBUG | SECTION_EXCLUDE,
@@ -27262,6 +27301,10 @@ init_sections_and_labels (bool early_lto_debug)
debug_str_section = get_section (DEBUG_LTO_STR_SECTION,
DEBUG_STR_SECTION_FLAGS
| SECTION_EXCLUDE, NULL);
+ if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+ debug_line_str_section
+ = get_section (DEBUG_LTO_LINE_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS | SECTION_EXCLUDE, NULL);
}
else
{
@@ -27271,10 +27314,13 @@ init_sections_and_labels (bool early_lto_debug)
SECTION_DEBUG, NULL);
debug_abbrev_section = get_section (DEBUG_ABBREV_SECTION,
SECTION_DEBUG, NULL);
- debug_loc_section = get_section (DEBUG_LOC_SECTION,
+ debug_loc_section = get_section (dwarf_version >= 5
+ ? DEBUG_LOCLISTS_SECTION
+ : DEBUG_LOC_SECTION,
SECTION_DEBUG, NULL);
debug_macinfo_section_name
- = dwarf_strict ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION;
+ = ((dwarf_strict && dwarf_version < 5)
+ ? DEBUG_MACINFO_SECTION : DEBUG_MACRO_SECTION);
debug_macinfo_section = get_section (debug_macinfo_section_name,
SECTION_DEBUG, NULL);
}
@@ -27311,15 +27357,17 @@ init_sections_and_labels (bool early_lto_debug)
ASM_GENERATE_INTERNAL_LABEL (debug_skeleton_info_section_label,
DEBUG_SKELETON_INFO_SECTION_LABEL,
generation);
- debug_loc_section = get_section (DEBUG_DWO_LOC_SECTION,
+ debug_loc_section = get_section (dwarf_version >= 5
+ ? DEBUG_DWO_LOCLISTS_SECTION
+ : DEBUG_DWO_LOC_SECTION,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
debug_str_dwo_section = get_section (DEBUG_STR_DWO_SECTION,
DEBUG_STR_DWO_SECTION_FLAGS,
NULL);
debug_macinfo_section_name
- = (dwarf_strict && dwarf_version < 5)
- ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION;
+ = ((dwarf_strict && dwarf_version < 5)
+ ? DEBUG_DWO_MACINFO_SECTION : DEBUG_DWO_MACRO_SECTION);
debug_macinfo_section = get_section (debug_macinfo_section_name,
SECTION_DEBUG | SECTION_EXCLUDE,
NULL);
@@ -27334,6 +27382,9 @@ init_sections_and_labels (bool early_lto_debug)
SECTION_DEBUG, NULL);
debug_str_section = get_section (DEBUG_STR_SECTION,
DEBUG_STR_SECTION_FLAGS, NULL);
+ if (!dwarf_split_debug_info && !DWARF2_ASM_LINE_DEBUG_INFO)
+ debug_line_str_section = get_section (DEBUG_LINE_STR_SECTION,
+ DEBUG_STR_SECTION_FLAGS, NULL);
debug_ranges_section = get_section (dwarf_version >= 5
? DEBUG_RNGLISTS_SECTION
: DEBUG_RANGES_SECTION,
@@ -27355,7 +27406,7 @@ init_sections_and_labels (bool early_lto_debug)
ASM_GENERATE_INTERNAL_LABEL (ranges_base_label,
DEBUG_RANGES_SECTION_LABEL, 2 + generation);
ASM_GENERATE_INTERNAL_LABEL (debug_addr_section_label,
- DEBUG_ADDR_SECTION_LABEL, generation);
+ DEBUG_ADDR_SECTION_LABEL, generation);
ASM_GENERATE_INTERNAL_LABEL (macinfo_section_label,
(dwarf_strict && dwarf_version < 5)
? DEBUG_MACINFO_SECTION_LABEL
diff --git a/gcc/emit-rtl.c b/gcc/emit-rtl.c
index e790cbc..d91988e 100644
--- a/gcc/emit-rtl.c
+++ b/gcc/emit-rtl.c
@@ -3789,6 +3789,7 @@ try_split (rtx pat, rtx_insn *trial, int last)
case REG_NORETURN:
case REG_SETJMP:
case REG_TM:
+ case REG_CALL_NOCF_CHECK:
for (insn = insn_last; insn != NULL_RTX; insn = PREV_INSN (insn))
{
if (CALL_P (insn))
diff --git a/gcc/except.c b/gcc/except.c
index 10b5a7c..041f89a 100644
--- a/gcc/except.c
+++ b/gcc/except.c
@@ -147,7 +147,9 @@ along with GCC; see the file COPYING3. If not see
static GTY(()) int call_site_base;
-static GTY (()) hash_map<tree_hash, tree> *type_to_runtime_map;
+static GTY(()) hash_map<tree_hash, tree> *type_to_runtime_map;
+
+static GTY(()) tree setjmp_fn;
/* Describe the SjLj_Function_Context structure. */
static GTY(()) tree sjlj_fc_type_node;
@@ -331,6 +333,16 @@ init_eh (void)
sjlj_fc_jbuf_ofs
= (tree_to_uhwi (DECL_FIELD_OFFSET (f_jbuf))
+ tree_to_uhwi (DECL_FIELD_BIT_OFFSET (f_jbuf)) / BITS_PER_UNIT);
+
+#ifdef DONT_USE_BUILTIN_SETJMP
+ tmp = build_function_type_list (integer_type_node, TREE_TYPE (f_jbuf),
+ NULL);
+ setjmp_fn = build_decl (BUILTINS_LOCATION, FUNCTION_DECL,
+ get_identifier ("setjmp"), tmp);
+ TREE_PUBLIC (setjmp_fn) = 1;
+ DECL_EXTERNAL (setjmp_fn) = 1;
+ DECL_ASSEMBLER_NAME (setjmp_fn);
+#endif
}
}
@@ -1176,8 +1188,7 @@ sjlj_emit_function_enter (rtx_code_label *dispatch_label)
addr = convert_memory_address (ptr_mode, addr);
tree addr_tree = make_tree (ptr_type_node, addr);
- tree fn = builtin_decl_implicit (BUILT_IN_SETJMP);
- tree call_expr = build_call_expr (fn, 1, addr_tree);
+ tree call_expr = build_call_expr (setjmp_fn, 1, addr_tree);
rtx x = expand_call (call_expr, NULL_RTX, false);
emit_cmp_and_jump_insns (x, const0_rtx, NE, 0,
@@ -1209,6 +1220,28 @@ sjlj_emit_function_enter (rtx_code_label *dispatch_label)
fn_begin_outside_block = false;
}
+#ifdef DONT_USE_BUILTIN_SETJMP
+ if (dispatch_label)
+ {
+ /* The sequence contains a branch in the middle so we need to force
+ the creation of a new basic block by means of BB_SUPERBLOCK. */
+ if (fn_begin_outside_block)
+ {
+ basic_block bb
+ = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
+ if (JUMP_P (BB_END (bb)))
+ emit_insn_before (seq, BB_END (bb));
+ else
+ emit_insn_after (seq, BB_END (bb));
+ }
+ else
+ emit_insn_after (seq, fn_begin);
+
+ single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))->flags |= BB_SUPERBLOCK;
+ return;
+ }
+#endif
+
if (fn_begin_outside_block)
insert_insn_on_edge (seq, single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
else
diff --git a/gcc/explow.c b/gcc/explow.c
index 638dc5f..662865d 100644
--- a/gcc/explow.c
+++ b/gcc/explow.c
@@ -40,8 +40,10 @@ along with GCC; see the file COPYING3. If not see
#include "expr.h"
#include "common/common-target.h"
#include "output.h"
+#include "params.h"
static rtx break_out_memory_refs (rtx);
+static void anti_adjust_stack_and_probe_stack_clash (rtx);
/* Truncate and perhaps sign-extend C as appropriate for MODE. */
@@ -1283,6 +1285,29 @@ get_dynamic_stack_size (rtx *psize, unsigned size_align,
*psize = size;
}
+/* Return the number of bytes to "protect" on the stack for -fstack-check.
+
+ "protect" in the context of -fstack-check means how many bytes we
+ should always ensure are available on the stack. More importantly
+ this is how many bytes are skipped when probing the stack.
+
+ On some targets we want to reuse the -fstack-check prologue support
+ to give a degree of protection against stack clashing style attacks.
+
+ In that scenario we do not want to skip bytes before probing as that
+ would render the stack clash protections useless.
+
+ So we never use STACK_CHECK_PROTECT directly. Instead we indirect though
+ this helper which allows us to provide different values for
+ -fstack-check and -fstack-clash-protection. */
+HOST_WIDE_INT
+get_stack_check_protect (void)
+{
+ if (flag_stack_clash_protection)
+ return 0;
+ return STACK_CHECK_PROTECT;
+}
+
/* Return an rtx representing the address of an area of memory dynamically
pushed on the stack.
@@ -1297,6 +1322,9 @@ get_dynamic_stack_size (rtx *psize, unsigned size_align,
REQUIRED_ALIGN is the alignment (in bits) required for the region
of memory.
+ MAX_SIZE is an upper bound for SIZE, if SIZE is not constant, or -1 if
+ no such upper bound is known.
+
If CANNOT_ACCUMULATE is set to TRUE, the caller guarantees that the
stack space allocated by the generated code cannot be added with itself
in the course of the execution of the function. It is always safe to
@@ -1306,7 +1334,9 @@ get_dynamic_stack_size (rtx *psize, unsigned size_align,
rtx
allocate_dynamic_stack_space (rtx size, unsigned size_align,
- unsigned required_align, bool cannot_accumulate)
+ unsigned required_align,
+ HOST_WIDE_INT max_size,
+ bool cannot_accumulate)
{
HOST_WIDE_INT stack_usage_size = -1;
rtx_code_label *final_label;
@@ -1345,8 +1375,12 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
}
}
- /* If the size is not constant, we can't say anything. */
- if (stack_usage_size == -1)
+ /* If the size is not constant, try the maximum size. */
+ if (stack_usage_size < 0)
+ stack_usage_size = max_size;
+
+ /* If the size is still not constant, we can't say anything. */
+ if (stack_usage_size < 0)
{
current_function_has_unbounded_dynamic_stack_size = 1;
stack_usage_size = 0;
@@ -1441,7 +1475,7 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
probe_stack_range (STACK_OLD_CHECK_PROTECT + STACK_CHECK_MAX_FRAME_SIZE,
size);
else if (flag_stack_check == STATIC_BUILTIN_STACK_CHECK)
- probe_stack_range (STACK_CHECK_PROTECT, size);
+ probe_stack_range (get_stack_check_protect (), size);
/* Don't let anti_adjust_stack emit notes. */
suppress_reg_args_size = true;
@@ -1494,6 +1528,8 @@ allocate_dynamic_stack_space (rtx size, unsigned size_align,
if (flag_stack_check && STACK_CHECK_MOVING_SP)
anti_adjust_stack_and_probe (size, false);
+ else if (flag_stack_clash_protection)
+ anti_adjust_stack_and_probe_stack_clash (size);
else
anti_adjust_stack (size);
@@ -1769,6 +1805,220 @@ probe_stack_range (HOST_WIDE_INT first, rtx size)
emit_insn (gen_blockage ());
}
+/* Compute parameters for stack clash probing a dynamic stack
+ allocation of SIZE bytes.
+
+ We compute ROUNDED_SIZE, LAST_ADDR, RESIDUAL and PROBE_INTERVAL.
+
+ Additionally we conditionally dump the type of probing that will
+ be needed given the values computed. */
+
+void
+compute_stack_clash_protection_loop_data (rtx *rounded_size, rtx *last_addr,
+ rtx *residual,
+ HOST_WIDE_INT *probe_interval,
+ rtx size)
+{
+ /* Round SIZE down to STACK_CLASH_PROTECTION_PROBE_INTERVAL */
+ *probe_interval
+ = 1 << PARAM_VALUE (PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL);
+ *rounded_size = simplify_gen_binary (AND, Pmode, size,
+ GEN_INT (-*probe_interval));
+
+ /* Compute the value of the stack pointer for the last iteration.
+ It's just SP + ROUNDED_SIZE. */
+ rtx rounded_size_op = force_operand (*rounded_size, NULL_RTX);
+ *last_addr = force_operand (gen_rtx_fmt_ee (STACK_GROW_OP, Pmode,
+ stack_pointer_rtx,
+ rounded_size_op),
+ NULL_RTX);
+
+ /* Compute any residuals not allocated by the loop above. Residuals
+ are just the ROUNDED_SIZE - SIZE. */
+ *residual = simplify_gen_binary (MINUS, Pmode, size, *rounded_size);
+
+ /* Dump key information to make writing tests easy. */
+ if (dump_file)
+ {
+ if (*rounded_size == CONST0_RTX (Pmode))
+ fprintf (dump_file,
+ "Stack clash skipped dynamic allocation and probing loop.\n");
+ else if (CONST_INT_P (*rounded_size)
+ && INTVAL (*rounded_size) <= 4 * *probe_interval)
+ fprintf (dump_file,
+ "Stack clash dynamic allocation and probing inline.\n");
+ else if (CONST_INT_P (*rounded_size))
+ fprintf (dump_file,
+ "Stack clash dynamic allocation and probing in "
+ "rotated loop.\n");
+ else
+ fprintf (dump_file,
+ "Stack clash dynamic allocation and probing in loop.\n");
+
+ if (*residual != CONST0_RTX (Pmode))
+ fprintf (dump_file,
+ "Stack clash dynamic allocation and probing residuals.\n");
+ else
+ fprintf (dump_file,
+ "Stack clash skipped dynamic allocation and "
+ "probing residuals.\n");
+ }
+}
+
+/* Emit the start of an allocate/probe loop for stack
+ clash protection.
+
+ LOOP_LAB and END_LAB are returned for use when we emit the
+ end of the loop.
+
+ LAST addr is the value for SP which stops the loop. */
+void
+emit_stack_clash_protection_probe_loop_start (rtx *loop_lab,
+ rtx *end_lab,
+ rtx last_addr,
+ bool rotated)
+{
+ /* Essentially we want to emit any setup code, the top of loop
+ label and the comparison at the top of the loop. */
+ *loop_lab = gen_label_rtx ();
+ *end_lab = gen_label_rtx ();
+
+ emit_label (*loop_lab);
+ if (!rotated)
+ emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, EQ, NULL_RTX,
+ Pmode, 1, *end_lab);
+}
+
+/* Emit the end of a stack clash probing loop.
+
+ This consists of just the jump back to LOOP_LAB and
+ emitting END_LOOP after the loop. */
+
+void
+emit_stack_clash_protection_probe_loop_end (rtx loop_lab, rtx end_loop,
+ rtx last_addr, bool rotated)
+{
+ if (rotated)
+ emit_cmp_and_jump_insns (stack_pointer_rtx, last_addr, NE, NULL_RTX,
+ Pmode, 1, loop_lab);
+ else
+ emit_jump (loop_lab);
+
+ emit_label (end_loop);
+
+}
+
+/* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
+ while probing it. This pushes when SIZE is positive. SIZE need not
+ be constant.
+
+ This is subtly different than anti_adjust_stack_and_probe to try and
+ prevent stack-clash attacks
+
+ 1. It must assume no knowledge of the probing state, any allocation
+ must probe.
+
+ Consider the case of a 1 byte alloca in a loop. If the sum of the
+ allocations is large, then this could be used to jump the guard if
+ probes were not emitted.
+
+ 2. It never skips probes, whereas anti_adjust_stack_and_probe will
+ skip probes on the first couple PROBE_INTERVALs on the assumption
+ they're done elsewhere.
+
+ 3. It only allocates and probes SIZE bytes, it does not need to
+ allocate/probe beyond that because this probing style does not
+ guarantee signal handling capability if the guard is hit. */
+
+static void
+anti_adjust_stack_and_probe_stack_clash (rtx size)
+{
+ /* First ensure SIZE is Pmode. */
+ if (GET_MODE (size) != VOIDmode && GET_MODE (size) != Pmode)
+ size = convert_to_mode (Pmode, size, 1);
+
+ /* We can get here with a constant size on some targets. */
+ rtx rounded_size, last_addr, residual;
+ HOST_WIDE_INT probe_interval;
+ compute_stack_clash_protection_loop_data (&rounded_size, &last_addr,
+ &residual, &probe_interval, size);
+
+ if (rounded_size != CONST0_RTX (Pmode))
+ {
+ if (CONST_INT_P (rounded_size)
+ && INTVAL (rounded_size) <= 4 * probe_interval)
+ {
+ for (HOST_WIDE_INT i = 0;
+ i < INTVAL (rounded_size);
+ i += probe_interval)
+ {
+ anti_adjust_stack (GEN_INT (probe_interval));
+
+ /* The prologue does not probe residuals. Thus the offset
+ here to probe just beyond what the prologue had already
+ allocated. */
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ (probe_interval
+ - GET_MODE_SIZE (word_mode))));
+ emit_insn (gen_blockage ());
+ }
+ }
+ else
+ {
+ rtx loop_lab, end_loop;
+ bool rotate_loop = CONST_INT_P (rounded_size);
+ emit_stack_clash_protection_probe_loop_start (&loop_lab, &end_loop,
+ last_addr, rotate_loop);
+
+ anti_adjust_stack (GEN_INT (probe_interval));
+
+ /* The prologue does not probe residuals. Thus the offset here
+ to probe just beyond what the prologue had already allocated. */
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ (probe_interval
+ - GET_MODE_SIZE (word_mode))));
+
+ emit_stack_clash_protection_probe_loop_end (loop_lab, end_loop,
+ last_addr, rotate_loop);
+ emit_insn (gen_blockage ());
+ }
+ }
+
+ if (residual != CONST0_RTX (Pmode))
+ {
+ rtx x = force_reg (Pmode, plus_constant (Pmode, residual,
+ -GET_MODE_SIZE (word_mode)));
+ anti_adjust_stack (residual);
+ emit_stack_probe (gen_rtx_PLUS (Pmode, stack_pointer_rtx, x));
+ emit_insn (gen_blockage ());
+ }
+
+ /* Some targets make optimistic assumptions in their prologues about
+ how the caller may have probed the stack. Make sure we honor
+ those assumptions when needed. */
+ if (size != CONST0_RTX (Pmode)
+ && targetm.stack_clash_protection_final_dynamic_probe (residual))
+ {
+ /* Ideally we would just probe at *sp. However, if SIZE is not
+ a compile-time constant, but is zero at runtime, then *sp
+ might hold live data. So probe at *sp if we know that
+ an allocation was made, otherwise probe into the red zone
+ which is obviously undesirable. */
+ if (CONST_INT_P (size))
+ {
+ emit_stack_probe (stack_pointer_rtx);
+ emit_insn (gen_blockage ());
+ }
+ else
+ {
+ emit_stack_probe (plus_constant (Pmode, stack_pointer_rtx,
+ -GET_MODE_SIZE (word_mode)));
+ emit_insn (gen_blockage ());
+ }
+ }
+}
+
+
/* Adjust the stack pointer by minus SIZE (an rtx for a number of bytes)
while probing it. This pushes when SIZE is positive. SIZE need not
be constant. If ADJUST_BACK is true, adjust back the stack pointer
diff --git a/gcc/explow.h b/gcc/explow.h
index 217a322..8eca20b 100644
--- a/gcc/explow.h
+++ b/gcc/explow.h
@@ -69,6 +69,15 @@ extern void anti_adjust_stack (rtx);
/* Add some bytes to the stack while probing it. An rtx says how many. */
extern void anti_adjust_stack_and_probe (rtx, bool);
+/* Support for building allocation/probing loops for stack-clash
+ protection of dyamically allocated stack space. */
+extern void compute_stack_clash_protection_loop_data (rtx *, rtx *, rtx *,
+ HOST_WIDE_INT *, rtx);
+extern void emit_stack_clash_protection_probe_loop_start (rtx *, rtx *,
+ rtx, bool);
+extern void emit_stack_clash_protection_probe_loop_end (rtx, rtx,
+ rtx, bool);
+
/* This enum is used for the following two functions. */
enum save_level {SAVE_BLOCK, SAVE_FUNCTION, SAVE_NONLOCAL};
@@ -85,7 +94,8 @@ extern void update_nonlocal_goto_save_area (void);
extern void record_new_stack_level (void);
/* Allocate some space on the stack dynamically and return its address. */
-extern rtx allocate_dynamic_stack_space (rtx, unsigned, unsigned, bool);
+extern rtx allocate_dynamic_stack_space (rtx, unsigned, unsigned,
+ HOST_WIDE_INT, bool);
/* Calculate the necessary size of a constant dynamic stack allocation from the
size of the variable area. */
diff --git a/gcc/expmed.c b/gcc/expmed.c
index 27f5ae4..eeb25d3 100644
--- a/gcc/expmed.c
+++ b/gcc/expmed.c
@@ -2337,12 +2337,10 @@ expand_shift_1 (enum tree_code code, machine_mode mode, rtx shifted,
optab lrotate_optab = rotl_optab;
optab rrotate_optab = rotr_optab;
machine_mode op1_mode;
- machine_mode scalar_mode = mode;
+ scalar_mode scalar_mode = GET_MODE_INNER (mode);
int attempt;
bool speed = optimize_insn_for_speed_p ();
- if (VECTOR_MODE_P (mode))
- scalar_mode = GET_MODE_INNER (mode);
op1 = amount;
op1_mode = GET_MODE (op1);
diff --git a/gcc/expr.c b/gcc/expr.c
index a9689a6..496d492 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -4541,15 +4541,8 @@ emit_push_insn (rtx x, machine_mode mode, tree type, rtx size,
else
#endif
{
- if (CONST_INT_P (args_so_far))
- addr
- = memory_address (mode,
- plus_constant (Pmode, args_addr,
- INTVAL (args_so_far)));
- else
- addr = memory_address (mode, gen_rtx_PLUS (Pmode, args_addr,
- args_so_far));
- dest = gen_rtx_MEM (mode, addr);
+ addr = simplify_gen_binary (PLUS, Pmode, args_addr, args_so_far);
+ dest = gen_rtx_MEM (mode, memory_address (mode, addr));
/* We do *not* set_mem_attributes here, because incoming arguments
may overlap with sibling call outgoing arguments and we cannot
@@ -6756,8 +6749,11 @@ store_field (rtx target, HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
return const0_rtx;
/* If we have nothing to store, do nothing unless the expression has
- side-effects. */
- if (bitsize == 0)
+ side-effects. Don't do that for zero sized addressable lhs of
+ calls. */
+ if (bitsize == 0
+ && (!TREE_ADDRESSABLE (TREE_TYPE (exp))
+ || TREE_CODE (exp) != CALL_EXPR))
return expand_expr (exp, const0_rtx, VOIDmode, EXPAND_NORMAL);
if (GET_CODE (target) == CONCAT)
@@ -7160,7 +7156,7 @@ get_inner_reference (tree exp, HOST_WIDE_INT *pbitsize,
if (wi::neg_p (bit_offset) || !wi::fits_shwi_p (bit_offset))
{
offset_int mask = wi::mask <offset_int> (LOG2_BITS_PER_UNIT, false);
- offset_int tem = bit_offset.and_not (mask);
+ offset_int tem = wi::bit_and_not (bit_offset, mask);
/* TEM is the bitpos rounded to BITS_PER_UNIT towards -Inf.
Subtract it to BIT_OFFSET and add it (scaled) to OFFSET. */
bit_offset -= tem;
@@ -8457,7 +8453,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
if (modifier == EXPAND_STACK_PARM)
target = 0;
if (TREE_CODE (treeop0) == INTEGER_CST
- && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT
+ && HWI_COMPUTABLE_MODE_P (mode)
&& TREE_CONSTANT (treeop1))
{
rtx constant_part;
@@ -8480,7 +8476,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
}
else if (TREE_CODE (treeop1) == INTEGER_CST
- && GET_MODE_PRECISION (mode) <= HOST_BITS_PER_WIDE_INT
+ && HWI_COMPUTABLE_MODE_P (mode)
&& TREE_CONSTANT (treeop0))
{
rtx constant_part;
@@ -8565,14 +8561,7 @@ expand_expr_real_2 (sepops ops, rtx target, machine_mode tmode,
{
expand_operands (treeop0, treeop1,
NULL_RTX, &op0, &op1, modifier);
-
- /* If the last operand is a CONST_INT, use plus_constant of
- the negated constant. Else make the MINUS. */
- if (CONST_INT_P (op1))
- return REDUCE_BIT_FIELD (plus_constant (mode, op0,
- -INTVAL (op1)));
- else
- return REDUCE_BIT_FIELD (gen_rtx_MINUS (mode, op0, op1));
+ return simplify_gen_binary (MINUS, mode, op0, op1);
}
/* No sense saving up arithmetic to be done
@@ -11783,7 +11772,7 @@ const_vector_from_tree (tree exp)
RTVEC_ELT (v, i) = CONST_FIXED_FROM_FIXED_VALUE (TREE_FIXED_CST (elt),
inner);
else
- RTVEC_ELT (v, i) = immed_wide_int_const (elt, inner);
+ RTVEC_ELT (v, i) = immed_wide_int_const (wi::to_wide (elt), inner);
}
return gen_rtx_CONST_VECTOR (mode, v);
diff --git a/gcc/file-find.c b/gcc/file-find.c
index b072a49..b5a1fe8 100644
--- a/gcc/file-find.c
+++ b/gcc/file-find.c
@@ -208,38 +208,3 @@ prefix_from_string (const char *p, struct path_prefix *pprefix)
}
free (nstore);
}
-
-void
-remove_prefix (const char *prefix, struct path_prefix *pprefix)
-{
- struct prefix_list *remove, **prev, **remove_prev = NULL;
- int max_len = 0;
-
- if (pprefix->plist)
- {
- prev = &pprefix->plist;
- for (struct prefix_list *pl = pprefix->plist; pl->next; pl = pl->next)
- {
- if (strcmp (prefix, pl->prefix) == 0)
- {
- remove = pl;
- remove_prev = prev;
- continue;
- }
-
- int l = strlen (pl->prefix);
- if (l > max_len)
- max_len = l;
-
- prev = &pl;
- }
-
- if (remove_prev)
- {
- *remove_prev = remove->next;
- free (remove);
- }
-
- pprefix->max_len = max_len;
- }
-}
diff --git a/gcc/file-find.h b/gcc/file-find.h
index 8f49a3a..407feba 100644
--- a/gcc/file-find.h
+++ b/gcc/file-find.h
@@ -41,7 +41,6 @@ extern void find_file_set_debug (bool);
extern char *find_a_file (struct path_prefix *, const char *, int);
extern void add_prefix (struct path_prefix *, const char *);
extern void add_prefix_begin (struct path_prefix *, const char *);
-extern void remove_prefix (const char *prefix, struct path_prefix *);
extern void prefix_from_env (const char *, struct path_prefix *);
extern void prefix_from_string (const char *, struct path_prefix *);
diff --git a/gcc/final.c b/gcc/final.c
index eff2ee6..0ddf779 100644
--- a/gcc/final.c
+++ b/gcc/final.c
@@ -3199,14 +3199,7 @@ alter_subreg (rtx *xp, bool final_p)
/* For paradoxical subregs on big-endian machines, SUBREG_BYTE
contains 0 instead of the proper offset. See simplify_subreg. */
if (paradoxical_subreg_p (x))
- {
- int difference = GET_MODE_SIZE (GET_MODE (y))
- - GET_MODE_SIZE (GET_MODE (x));
- if (WORDS_BIG_ENDIAN)
- offset += (difference / UNITS_PER_WORD) * UNITS_PER_WORD;
- if (BYTES_BIG_ENDIAN)
- offset += difference % UNITS_PER_WORD;
- }
+ offset = byte_lowpart_offset (GET_MODE (x), GET_MODE (y));
if (final_p)
*xp = adjust_address (y, GET_MODE (x), offset);
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 4938f69..2b23029 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -166,7 +166,14 @@ enum permitted_flt_eval_methods
PERMITTED_FLT_EVAL_METHODS_C11
};
-/* Type of stack check. */
+/* Type of stack check.
+
+ Stack checking is designed to detect infinite recursion and stack
+ overflows for Ada programs. Furthermore stack checking tries to ensure
+ in that scenario that enough stack space is left to run a signal handler.
+
+ -fstack-check= does not prevent stack-clash style attacks. For that
+ you want -fstack-clash-protection. */
enum stack_check_type
{
/* Do not check the stack. */
@@ -239,6 +246,7 @@ enum sanitize_code {
SANITIZE_VPTR = 1UL << 22,
SANITIZE_BOUNDS_STRICT = 1UL << 23,
SANITIZE_POINTER_OVERFLOW = 1UL << 24,
+ SANITIZE_BUILTIN = 1UL << 25,
SANITIZE_SHIFT = SANITIZE_SHIFT_BASE | SANITIZE_SHIFT_EXPONENT,
SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
| SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
@@ -247,7 +255,7 @@ enum sanitize_code {
| SANITIZE_NONNULL_ATTRIBUTE
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE
| SANITIZE_OBJECT_SIZE | SANITIZE_VPTR
- | SANITIZE_POINTER_OVERFLOW,
+ | SANITIZE_POINTER_OVERFLOW | SANITIZE_BUILTIN,
SANITIZE_UNDEFINED_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
| SANITIZE_BOUNDS_STRICT
};
@@ -318,4 +326,13 @@ enum gfc_convert
};
+/* Control-Flow Protection values. */
+enum cf_protection_level
+{
+ CF_NONE = 0,
+ CF_BRANCH = 1 << 0,
+ CF_RETURN = 1 << 1,
+ CF_FULL = CF_BRANCH | CF_RETURN,
+ CF_SET = 1 << 2
+};
#endif /* ! GCC_FLAG_TYPES_H */
diff --git a/gcc/fold-const-call.c b/gcc/fold-const-call.c
index 71f0b52..98ac091 100644
--- a/gcc/fold-const-call.c
+++ b/gcc/fold-const-call.c
@@ -60,7 +60,8 @@ host_size_t_cst_p (tree t, size_t *size_out)
{
if (types_compatible_p (size_type_node, TREE_TYPE (t))
&& integer_cst_p (t)
- && wi::min_precision (t, UNSIGNED) <= sizeof (size_t) * CHAR_BIT)
+ && (wi::min_precision (wi::to_wide (t), UNSIGNED)
+ <= sizeof (size_t) * CHAR_BIT))
{
*size_out = tree_to_uhwi (t);
return true;
@@ -1041,8 +1042,8 @@ fold_const_call_1 (combined_fn fn, tree type, tree arg)
if (SCALAR_INT_MODE_P (mode))
{
wide_int result;
- if (fold_const_call_ss (&result, fn, arg, TYPE_PRECISION (type),
- TREE_TYPE (arg)))
+ if (fold_const_call_ss (&result, fn, wi::to_wide (arg),
+ TYPE_PRECISION (type), TREE_TYPE (arg)))
return wide_int_to_tree (type, result);
}
return NULL_TREE;
@@ -1322,7 +1323,8 @@ fold_const_call_1 (combined_fn fn, tree type, tree arg0, tree arg1)
/* real, int -> real. */
REAL_VALUE_TYPE result;
if (fold_const_call_sss (&result, fn, TREE_REAL_CST_PTR (arg0),
- arg1, REAL_MODE_FORMAT (mode)))
+ wi::to_wide (arg1),
+ REAL_MODE_FORMAT (mode)))
return build_real (type, result);
}
return NULL_TREE;
@@ -1336,7 +1338,7 @@ fold_const_call_1 (combined_fn fn, tree type, tree arg0, tree arg1)
{
/* int, real -> real. */
REAL_VALUE_TYPE result;
- if (fold_const_call_sss (&result, fn, arg0,
+ if (fold_const_call_sss (&result, fn, wi::to_wide (arg0),
TREE_REAL_CST_PTR (arg1),
REAL_MODE_FORMAT (mode)))
return build_real (type, result);
diff --git a/gcc/fold-const.c b/gcc/fold-const.c
index fa9d1bb..c16959b 100644
--- a/gcc/fold-const.c
+++ b/gcc/fold-const.c
@@ -360,7 +360,7 @@ may_negate_without_overflow_p (const_tree t)
if (TYPE_UNSIGNED (type))
return false;
- return !wi::only_sign_bit_p (t);
+ return !wi::only_sign_bit_p (wi::to_wide (t));
}
/* Determine whether an expression T can be cheaply negated using
@@ -452,9 +452,11 @@ negate_expr_p (tree t)
if (INTEGRAL_TYPE_P (TREE_TYPE (t))
&& ! TYPE_OVERFLOW_WRAPS (TREE_TYPE (t))
&& ! ((TREE_CODE (TREE_OPERAND (t, 0)) == INTEGER_CST
- && wi::popcount (wi::abs (TREE_OPERAND (t, 0))) != 1)
+ && (wi::popcount
+ (wi::abs (wi::to_wide (TREE_OPERAND (t, 0))))) != 1)
|| (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST
- && wi::popcount (wi::abs (TREE_OPERAND (t, 1))) != 1)))
+ && (wi::popcount
+ (wi::abs (wi::to_wide (TREE_OPERAND (t, 1))))) != 1)))
break;
/* Fall through. */
@@ -503,7 +505,7 @@ negate_expr_p (tree t)
if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
{
tree op1 = TREE_OPERAND (t, 1);
- if (wi::eq_p (op1, TYPE_PRECISION (type) - 1))
+ if (wi::to_wide (op1) == TYPE_PRECISION (type) - 1)
return true;
}
break;
@@ -695,7 +697,7 @@ fold_negate_expr_1 (location_t loc, tree t)
if (TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST)
{
tree op1 = TREE_OPERAND (t, 1);
- if (wi::eq_p (op1, TYPE_PRECISION (type) - 1))
+ if (wi::to_wide (op1) == TYPE_PRECISION (type) - 1)
{
tree ntype = TYPE_UNSIGNED (type)
? signed_type_for (type)
@@ -959,20 +961,21 @@ int_binop_types_match_p (enum tree_code code, const_tree type1, const_tree type2
}
-/* Combine two integer constants ARG1 and ARG2 under operation CODE
+/* Combine two integer constants PARG1 and PARG2 under operation CODE
to produce a new constant. Return NULL_TREE if we don't know how
to evaluate CODE at compile-time. */
static tree
-int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree parg2,
+int_const_binop_1 (enum tree_code code, const_tree parg1, const_tree parg2,
int overflowable)
{
wide_int res;
tree t;
- tree type = TREE_TYPE (arg1);
+ tree type = TREE_TYPE (parg1);
signop sign = TYPE_SIGN (type);
bool overflow = false;
+ wi::tree_to_wide_ref arg1 = wi::to_wide (parg1);
wide_int arg2 = wi::to_wide (parg2, TYPE_PRECISION (type));
switch (code)
@@ -1106,7 +1109,7 @@ int_const_binop_1 (enum tree_code code, const_tree arg1, const_tree parg2,
t = force_fit_type (type, res, overflowable,
(((sign == SIGNED || overflowable == -1)
&& overflow)
- | TREE_OVERFLOW (arg1) | TREE_OVERFLOW (parg2)));
+ | TREE_OVERFLOW (parg1) | TREE_OVERFLOW (parg2)));
return t;
}
@@ -1258,7 +1261,7 @@ const_binop (enum tree_code code, tree arg1, tree arg2)
{
if (TREE_CODE (arg2) != INTEGER_CST)
return NULL_TREE;
- wide_int w2 = arg2;
+ wi::tree_to_wide_ref w2 = wi::to_wide (arg2);
f2.data.high = w2.elt (1);
f2.data.low = w2.ulow ();
f2.mode = SImode;
@@ -1909,7 +1912,7 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg
if (real_less (&r, &l))
{
overflow = true;
- val = lt;
+ val = wi::to_wide (lt);
}
}
@@ -1922,7 +1925,7 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, const_tree arg
if (real_less (&u, &r))
{
overflow = true;
- val = ut;
+ val = wi::to_wide (ut);
}
}
}
@@ -3793,47 +3796,6 @@ invert_truthvalue_loc (location_t loc, tree arg)
: TRUTH_NOT_EXPR,
type, arg);
}
-
-/* Knowing that ARG0 and ARG1 are both RDIV_EXPRs, simplify a binary operation
- with code CODE. This optimization is unsafe. */
-static tree
-distribute_real_division (location_t loc, enum tree_code code, tree type,
- tree arg0, tree arg1)
-{
- bool mul0 = TREE_CODE (arg0) == MULT_EXPR;
- bool mul1 = TREE_CODE (arg1) == MULT_EXPR;
-
- /* (A / C) +- (B / C) -> (A +- B) / C. */
- if (mul0 == mul1
- && operand_equal_p (TREE_OPERAND (arg0, 1),
- TREE_OPERAND (arg1, 1), 0))
- return fold_build2_loc (loc, mul0 ? MULT_EXPR : RDIV_EXPR, type,
- fold_build2_loc (loc, code, type,
- TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg1, 0)),
- TREE_OPERAND (arg0, 1));
-
- /* (A / C1) +- (A / C2) -> A * (1 / C1 +- 1 / C2). */
- if (operand_equal_p (TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg1, 0), 0)
- && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
- && TREE_CODE (TREE_OPERAND (arg1, 1)) == REAL_CST)
- {
- REAL_VALUE_TYPE r0, r1;
- r0 = TREE_REAL_CST (TREE_OPERAND (arg0, 1));
- r1 = TREE_REAL_CST (TREE_OPERAND (arg1, 1));
- if (!mul0)
- real_arithmetic (&r0, RDIV_EXPR, &dconst1, &r0);
- if (!mul1)
- real_arithmetic (&r1, RDIV_EXPR, &dconst1, &r1);
- real_arithmetic (&r0, code, &r0, &r1);
- return fold_build2_loc (loc, MULT_EXPR, type,
- TREE_OPERAND (arg0, 0),
- build_real (type, r0));
- }
-
- return NULL_TREE;
-}
/* Return a BIT_FIELD_REF of type TYPE to refer to BITSIZE bits of INNER
starting at BITPOS. The field is unsigned if UNSIGNEDP is nonzero
@@ -4010,21 +3972,20 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
size_int (nbitsize - lbitsize - lbitpos));
if (! const_p)
- /* If not comparing with constant, just rework the comparison
- and return. */
- return fold_build2_loc (loc, code, compare_type,
- fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type,
- make_bit_field_ref (loc, linner, lhs,
- unsigned_type,
- nbitsize, nbitpos,
- 1, lreversep),
- mask),
- fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type,
- make_bit_field_ref (loc, rinner, rhs,
- unsigned_type,
- nbitsize, nbitpos,
- 1, rreversep),
- mask));
+ {
+ if (nbitpos < 0)
+ return 0;
+
+ /* If not comparing with constant, just rework the comparison
+ and return. */
+ tree t1 = make_bit_field_ref (loc, linner, lhs, unsigned_type,
+ nbitsize, nbitpos, 1, lreversep);
+ t1 = fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type, t1, mask);
+ tree t2 = make_bit_field_ref (loc, rinner, rhs, unsigned_type,
+ nbitsize, nbitpos, 1, rreversep);
+ t2 = fold_build2_loc (loc, BIT_AND_EXPR, unsigned_type, t2, mask);
+ return fold_build2_loc (loc, code, compare_type, t1, t2);
+ }
/* Otherwise, we are handling the constant case. See if the constant is too
big for the field. Warn and return a tree for 0 (false) if so. We do
@@ -4037,7 +3998,7 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
if (lunsignedp)
{
- if (wi::lrshift (rhs, lbitsize) != 0)
+ if (wi::lrshift (wi::to_wide (rhs), lbitsize) != 0)
{
warning (0, "comparison is always %d due to width of bit-field",
code == NE_EXPR);
@@ -4046,7 +4007,7 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
}
else
{
- wide_int tem = wi::arshift (rhs, lbitsize - 1);
+ wide_int tem = wi::arshift (wi::to_wide (rhs), lbitsize - 1);
if (tem != 0 && tem != -1)
{
warning (0, "comparison is always %d due to width of bit-field",
@@ -4055,6 +4016,9 @@ optimize_bit_field_compare (location_t loc, enum tree_code code,
}
}
+ if (nbitpos < 0)
+ return 0;
+
/* Single-bit compares should always be against zero. */
if (lbitsize == 1 && ! integer_zerop (rhs))
{
@@ -4196,7 +4160,7 @@ all_ones_mask_p (const_tree mask, unsigned int size)
if (size > precision || TYPE_SIGN (type) == UNSIGNED)
return false;
- return wi::mask (size, false, precision) == mask;
+ return wi::mask (size, false, precision) == wi::to_wide (mask);
}
/* Subroutine for fold: determine if VAL is the INTEGER_CONST that
@@ -4222,7 +4186,7 @@ sign_bit_p (tree exp, const_tree val)
return NULL_TREE;
width = TYPE_PRECISION (t);
- if (wi::only_sign_bit_p (val, width))
+ if (wi::only_sign_bit_p (wi::to_wide (val), width))
return exp;
/* Handle extension from a narrower type. */
@@ -4851,7 +4815,7 @@ build_range_check (location_t loc, tree type, tree exp, int in_p,
{
int prec = TYPE_PRECISION (etype);
- if (wi::mask (prec - 1, false, prec) == high)
+ if (wi::mask <widest_int> (prec - 1, false) == wi::to_widest (high))
{
if (TYPE_UNSIGNED (etype))
{
@@ -5449,7 +5413,8 @@ unextend (tree c, int p, int unsignedp, tree mask)
/* We work by getting just the sign bit into the low-order bit, then
into the high-order bit, then sign-extend. We then XOR that value
with C. */
- temp = build_int_cst (TREE_TYPE (c), wi::extract_uhwi (c, p - 1, 1));
+ temp = build_int_cst (TREE_TYPE (c),
+ wi::extract_uhwi (wi::to_wide (c), p - 1, 1));
/* We must use a signed type in order to get an arithmetic right shift.
However, we must also avoid introducing accidental overflows, so that
@@ -5870,7 +5835,10 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
results. */
ll_mask = const_binop (BIT_IOR_EXPR, ll_mask, rl_mask);
lr_mask = const_binop (BIT_IOR_EXPR, lr_mask, rr_mask);
- if (lnbitsize == rnbitsize && xll_bitpos == xlr_bitpos)
+ if (lnbitsize == rnbitsize
+ && xll_bitpos == xlr_bitpos
+ && lnbitpos >= 0
+ && rnbitpos >= 0)
{
lhs = make_bit_field_ref (loc, ll_inner, ll_arg,
lntype, lnbitsize, lnbitpos,
@@ -5894,10 +5862,14 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
Note that we still must mask the lhs/rhs expressions. Furthermore,
the mask must be shifted to account for the shift done by
make_bit_field_ref. */
- if ((ll_bitsize + ll_bitpos == rl_bitpos
- && lr_bitsize + lr_bitpos == rr_bitpos)
- || (ll_bitpos == rl_bitpos + rl_bitsize
- && lr_bitpos == rr_bitpos + rr_bitsize))
+ if (((ll_bitsize + ll_bitpos == rl_bitpos
+ && lr_bitsize + lr_bitpos == rr_bitpos)
+ || (ll_bitpos == rl_bitpos + rl_bitsize
+ && lr_bitpos == rr_bitpos + rr_bitsize))
+ && ll_bitpos >= 0
+ && rl_bitpos >= 0
+ && lr_bitpos >= 0
+ && rr_bitpos >= 0)
{
tree type;
@@ -5966,6 +5938,9 @@ fold_truth_andor_1 (location_t loc, enum tree_code code, tree truth_type,
}
}
+ if (lnbitpos < 0)
+ return 0;
+
/* Construct the expression we will return. First get the component
reference we will make. Unless the mask is all ones the width of
that field, perform the mask operation. Then compare with the
@@ -6055,7 +6030,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
/* For a constant, we can always simplify if we are a multiply
or (for divide and modulus) if it is a multiple of our constant. */
if (code == MULT_EXPR
- || wi::multiple_of_p (t, c, TYPE_SIGN (type)))
+ || wi::multiple_of_p (wi::to_wide (t), wi::to_wide (c),
+ TYPE_SIGN (type)))
{
tree tem = const_binop (code, fold_convert (ctype, t),
fold_convert (ctype, c));
@@ -6172,7 +6148,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
&& (tcode == RSHIFT_EXPR || TYPE_UNSIGNED (TREE_TYPE (op0)))
/* const_binop may not detect overflow correctly,
so check for it explicitly here. */
- && wi::gtu_p (TYPE_PRECISION (TREE_TYPE (size_one_node)), op1)
+ && wi::gtu_p (TYPE_PRECISION (TREE_TYPE (size_one_node)),
+ wi::to_wide (op1))
&& 0 != (t1 = fold_convert (ctype,
const_binop (LSHIFT_EXPR,
size_one_node,
@@ -6241,7 +6218,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
/* If it's a multiply or a division/modulus operation of a multiple
of our constant, do the operation and verify it doesn't overflow. */
if (code == MULT_EXPR
- || wi::multiple_of_p (op1, c, TYPE_SIGN (type)))
+ || wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c),
+ TYPE_SIGN (type)))
{
op1 = const_binop (code, fold_convert (ctype, op1),
fold_convert (ctype, c));
@@ -6280,7 +6258,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
/* If the multiplication can overflow we cannot optimize this. */
&& TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (t))
&& TREE_CODE (TREE_OPERAND (t, 1)) == INTEGER_CST
- && wi::multiple_of_p (op1, c, TYPE_SIGN (type)))
+ && wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c),
+ TYPE_SIGN (type)))
{
*strict_overflow_p = true;
return omit_one_operand (type, integer_zero_node, op0);
@@ -6342,7 +6321,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
&& code != FLOOR_MOD_EXPR && code != ROUND_MOD_EXPR
&& code != MULT_EXPR)))
{
- if (wi::multiple_of_p (op1, c, TYPE_SIGN (type)))
+ if (wi::multiple_of_p (wi::to_wide (op1), wi::to_wide (c),
+ TYPE_SIGN (type)))
{
if (TYPE_OVERFLOW_UNDEFINED (ctype))
*strict_overflow_p = true;
@@ -6351,7 +6331,8 @@ extract_muldiv_1 (tree t, tree c, enum tree_code code, tree wide_type,
const_binop (TRUNC_DIV_EXPR,
op1, c)));
}
- else if (wi::multiple_of_p (c, op1, TYPE_SIGN (type)))
+ else if (wi::multiple_of_p (wi::to_wide (c), wi::to_wide (op1),
+ TYPE_SIGN (type)))
{
if (TYPE_OVERFLOW_UNDEFINED (ctype))
*strict_overflow_p = true;
@@ -6534,7 +6515,7 @@ fold_div_compare (enum tree_code code, tree c1, tree c2, tree *lo,
/* We have to do this the hard way to detect unsigned overflow.
prod = int_const_binop (MULT_EXPR, c1, c2); */
- wide_int val = wi::mul (c1, c2, sign, &overflow);
+ wide_int val = wi::mul (wi::to_wide (c1), wi::to_wide (c2), sign, &overflow);
prod = force_fit_type (type, val, -1, overflow);
*neg_overflow = false;
@@ -6544,7 +6525,7 @@ fold_div_compare (enum tree_code code, tree c1, tree c2, tree *lo,
*lo = prod;
/* Likewise *hi = int_const_binop (PLUS_EXPR, prod, tmp). */
- val = wi::add (prod, tmp, sign, &overflow);
+ val = wi::add (wi::to_wide (prod), wi::to_wide (tmp), sign, &overflow);
*hi = force_fit_type (type, val, -1, overflow | TREE_OVERFLOW (prod));
}
else if (tree_int_cst_sgn (c1) >= 0)
@@ -6688,7 +6669,7 @@ fold_single_bit_test (location_t loc, enum tree_code code,
if (TREE_CODE (inner) == RSHIFT_EXPR
&& TREE_CODE (TREE_OPERAND (inner, 1)) == INTEGER_CST
&& bitnum < TYPE_PRECISION (type)
- && wi::ltu_p (TREE_OPERAND (inner, 1),
+ && wi::ltu_p (wi::to_wide (TREE_OPERAND (inner, 1)),
TYPE_PRECISION (type) - bitnum))
{
bitnum += tree_to_uhwi (TREE_OPERAND (inner, 1));
@@ -6868,7 +6849,7 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type,
arg10 = build_one_cst (type);
/* As we canonicalize A - 2 to A + -2 get rid of that sign for
the purpose of this canonicalization. */
- if (wi::neg_p (arg1, TYPE_SIGN (TREE_TYPE (arg1)))
+ if (wi::neg_p (wi::to_wide (arg1), TYPE_SIGN (TREE_TYPE (arg1)))
&& negate_expr_p (arg1)
&& code == PLUS_EXPR)
{
@@ -6960,7 +6941,8 @@ fold_plusminus_mult_expr (location_t loc, enum tree_code code, tree type,
/* If the sum evaluated to a constant that is not -INF the multiplication
cannot overflow. */
if (TREE_CODE (tem) == INTEGER_CST
- && ! wi::eq_p (tem, wi::min_value (TYPE_PRECISION (utype), SIGNED)))
+ && (wi::to_wide (tem)
+ != wi::min_value (TYPE_PRECISION (utype), SIGNED)))
return fold_build2_loc (loc, MULT_EXPR, type,
fold_convert (type, tem), same);
@@ -6982,11 +6964,15 @@ native_encode_int (const_tree expr, unsigned char *ptr, int len, int off)
int byte, offset, word, words;
unsigned char value;
- if ((off == -1 && total_bytes > len)
- || off >= total_bytes)
+ if ((off == -1 && total_bytes > len) || off >= total_bytes)
return 0;
if (off == -1)
off = 0;
+
+ if (ptr == NULL)
+ /* Dry run. */
+ return MIN (len, total_bytes - off);
+
words = total_bytes / UNITS_PER_WORD;
for (byte = 0; byte < total_bytes; byte++)
@@ -7009,8 +6995,7 @@ native_encode_int (const_tree expr, unsigned char *ptr, int len, int off)
}
else
offset = BYTES_BIG_ENDIAN ? (total_bytes - 1) - byte : byte;
- if (offset >= off
- && offset - off < len)
+ if (offset >= off && offset - off < len)
ptr[offset - off] = value;
}
return MIN (len, total_bytes - off);
@@ -7036,8 +7021,7 @@ native_encode_fixed (const_tree expr, unsigned char *ptr, int len, int off)
i_type = lang_hooks.types.type_for_size (GET_MODE_BITSIZE (mode), 1);
- if (NULL_TREE == i_type
- || TYPE_PRECISION (i_type) != total_bytes)
+ if (NULL_TREE == i_type || TYPE_PRECISION (i_type) != total_bytes)
return 0;
value = TREE_FIXED_CST (expr);
@@ -7065,11 +7049,15 @@ native_encode_real (const_tree expr, unsigned char *ptr, int len, int off)
up to 192 bits. */
long tmp[6];
- if ((off == -1 && total_bytes > len)
- || off >= total_bytes)
+ if ((off == -1 && total_bytes > len) || off >= total_bytes)
return 0;
if (off == -1)
off = 0;
+
+ if (ptr == NULL)
+ /* Dry run. */
+ return MIN (len, total_bytes - off);
+
words = (32 / BITS_PER_UNIT) / UNITS_PER_WORD;
real_to_target (tmp, TREE_REAL_CST_PTR (expr), TYPE_MODE (type));
@@ -7123,15 +7111,14 @@ native_encode_complex (const_tree expr, unsigned char *ptr, int len, int off)
part = TREE_REALPART (expr);
rsize = native_encode_expr (part, ptr, len, off);
- if (off == -1
- && rsize == 0)
+ if (off == -1 && rsize == 0)
return 0;
part = TREE_IMAGPART (expr);
if (off != -1)
off = MAX (0, off - GET_MODE_SIZE (SCALAR_TYPE_MODE (TREE_TYPE (part))));
- isize = native_encode_expr (part, ptr+rsize, len-rsize, off);
- if (off == -1
- && isize != rsize)
+ isize = native_encode_expr (part, ptr ? ptr + rsize : NULL,
+ len - rsize, off);
+ if (off == -1 && isize != rsize)
return 0;
return rsize + isize;
}
@@ -7161,9 +7148,9 @@ native_encode_vector (const_tree expr, unsigned char *ptr, int len, int off)
continue;
}
elem = VECTOR_CST_ELT (expr, i);
- int res = native_encode_expr (elem, ptr+offset, len-offset, off);
- if ((off == -1 && res != size)
- || res == 0)
+ int res = native_encode_expr (elem, ptr ? ptr + offset : NULL,
+ len - offset, off);
+ if ((off == -1 && res != size) || res == 0)
return 0;
offset += res;
if (offset >= len)
@@ -7183,16 +7170,24 @@ native_encode_vector (const_tree expr, unsigned char *ptr, int len, int off)
static int
native_encode_string (const_tree expr, unsigned char *ptr, int len, int off)
{
- if (! can_native_encode_string_p (expr))
+ tree type = TREE_TYPE (expr);
+
+ /* Wide-char strings are encoded in target byte-order so native
+ encoding them is trivial. */
+ if (BITS_PER_UNIT != CHAR_BIT
+ || TREE_CODE (type) != ARRAY_TYPE
+ || TREE_CODE (TREE_TYPE (type)) != INTEGER_TYPE
+ || !tree_fits_shwi_p (TYPE_SIZE_UNIT (type)))
return 0;
HOST_WIDE_INT total_bytes = tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (expr)));
- if ((off == -1 && total_bytes > len)
- || off >= total_bytes)
+ if ((off == -1 && total_bytes > len) || off >= total_bytes)
return 0;
if (off == -1)
off = 0;
- if (TREE_STRING_LENGTH (expr) - off < MIN (total_bytes, len))
+ if (ptr == NULL)
+ /* Dry run. */;
+ else if (TREE_STRING_LENGTH (expr) - off < MIN (total_bytes, len))
{
int written = 0;
if (off < TREE_STRING_LENGTH (expr))
@@ -7211,7 +7206,8 @@ native_encode_string (const_tree expr, unsigned char *ptr, int len, int off)
/* Subroutine of fold_view_convert_expr. Encode the INTEGER_CST,
REAL_CST, COMPLEX_CST or VECTOR_CST specified by EXPR into the
- buffer PTR of length LEN bytes. If OFF is not -1 then start
+ buffer PTR of length LEN bytes. If PTR is NULL, don't actually store
+ anything, just do a dry run. If OFF is not -1 then start
the encoding at byte offset OFF and encode at most LEN bytes.
Return the number of bytes placed in the buffer, or zero upon failure. */
@@ -7459,43 +7455,6 @@ can_native_interpret_type_p (tree type)
}
}
-/* Return true iff a constant of type TYPE is accepted by
- native_encode_expr. */
-
-bool
-can_native_encode_type_p (tree type)
-{
- switch (TREE_CODE (type))
- {
- case INTEGER_TYPE:
- case REAL_TYPE:
- case FIXED_POINT_TYPE:
- case COMPLEX_TYPE:
- case VECTOR_TYPE:
- case POINTER_TYPE:
- return true;
- default:
- return false;
- }
-}
-
-/* Return true iff a STRING_CST S is accepted by
- native_encode_expr. */
-
-bool
-can_native_encode_string_p (const_tree expr)
-{
- tree type = TREE_TYPE (expr);
-
- /* Wide-char strings are encoded in target byte-order so native
- encoding them is trivial. */
- if (BITS_PER_UNIT != CHAR_BIT
- || TREE_CODE (type) != ARRAY_TYPE
- || TREE_CODE (TREE_TYPE (type)) != INTEGER_TYPE
- || !tree_fits_shwi_p (TYPE_SIZE_UNIT (type)))
- return false;
- return true;
-}
/* Fold a VIEW_CONVERT_EXPR of a constant expression EXPR to type
TYPE at compile-time. If we're unable to perform the conversion
@@ -8238,7 +8197,7 @@ pointer_may_wrap_p (tree base, tree offset, HOST_WIDE_INT bitpos)
else if (TREE_CODE (offset) != INTEGER_CST || TREE_OVERFLOW (offset))
return true;
else
- wi_offset = offset;
+ wi_offset = wi::to_wide (offset);
bool overflow;
wide_int units = wi::shwi (bitpos / BITS_PER_UNIT, precision);
@@ -9040,7 +8999,7 @@ expr_not_equal_to (tree t, const wide_int &w)
switch (TREE_CODE (t))
{
case INTEGER_CST:
- return wi::ne_p (t, w);
+ return wi::to_wide (t) != w;
case SSA_NAME:
if (!INTEGRAL_TYPE_P (TREE_TYPE (t)))
@@ -9395,12 +9354,6 @@ fold_binary_loc (location_t loc,
}
}
- if (flag_unsafe_math_optimizations
- && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
- && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
- && (tem = distribute_real_division (loc, code, type, arg0, arg1)))
- return tem;
-
/* Convert a + (b*c + d*e) into (a + b*c) + d*e.
We associate floats only if the user has specified
-fassociative-math. */
@@ -9441,7 +9394,10 @@ fold_binary_loc (location_t loc,
/* (A << C1) + (A >> C2) if A is unsigned and C1+C2 is the size of A
is a rotate of A by C1 bits. */
/* (A << B) + (A >> (Z - B)) if A is unsigned and Z is the size of A
- is a rotate of A by B bits. */
+ is a rotate of A by B bits.
+ Similarly for (A << B) | (A >> (-B & C3)) where C3 is Z-1,
+ though in this case CODE must be | and not + or ^, otherwise
+ it doesn't return A when B is 0. */
{
enum tree_code code0, code1;
tree rtype;
@@ -9459,25 +9415,32 @@ fold_binary_loc (location_t loc,
== GET_MODE_UNIT_PRECISION (TYPE_MODE (rtype))))
{
tree tree01, tree11;
+ tree orig_tree01, orig_tree11;
enum tree_code code01, code11;
- tree01 = TREE_OPERAND (arg0, 1);
- tree11 = TREE_OPERAND (arg1, 1);
+ tree01 = orig_tree01 = TREE_OPERAND (arg0, 1);
+ tree11 = orig_tree11 = TREE_OPERAND (arg1, 1);
STRIP_NOPS (tree01);
STRIP_NOPS (tree11);
code01 = TREE_CODE (tree01);
code11 = TREE_CODE (tree11);
+ if (code11 != MINUS_EXPR
+ && (code01 == MINUS_EXPR || code01 == BIT_AND_EXPR))
+ {
+ std::swap (code0, code1);
+ std::swap (code01, code11);
+ std::swap (tree01, tree11);
+ std::swap (orig_tree01, orig_tree11);
+ }
if (code01 == INTEGER_CST
&& code11 == INTEGER_CST
&& (wi::to_widest (tree01) + wi::to_widest (tree11)
- == element_precision (TREE_TYPE (TREE_OPERAND (arg0, 0)))))
+ == element_precision (rtype)))
{
tem = build2_loc (loc, LROTATE_EXPR,
- TREE_TYPE (TREE_OPERAND (arg0, 0)),
- TREE_OPERAND (arg0, 0),
+ rtype, TREE_OPERAND (arg0, 0),
code0 == LSHIFT_EXPR
- ? TREE_OPERAND (arg0, 1)
- : TREE_OPERAND (arg1, 1));
+ ? orig_tree01 : orig_tree11);
return fold_convert_loc (loc, type, tem);
}
else if (code11 == MINUS_EXPR)
@@ -9489,39 +9452,37 @@ fold_binary_loc (location_t loc,
STRIP_NOPS (tree111);
if (TREE_CODE (tree110) == INTEGER_CST
&& 0 == compare_tree_int (tree110,
- element_precision
- (TREE_TYPE (TREE_OPERAND
- (arg0, 0))))
+ element_precision (rtype))
&& operand_equal_p (tree01, tree111, 0))
- return
- fold_convert_loc (loc, type,
- build2 ((code0 == LSHIFT_EXPR
- ? LROTATE_EXPR
- : RROTATE_EXPR),
- TREE_TYPE (TREE_OPERAND (arg0, 0)),
- TREE_OPERAND (arg0, 0),
- TREE_OPERAND (arg0, 1)));
+ {
+ tem = build2_loc (loc, (code0 == LSHIFT_EXPR
+ ? LROTATE_EXPR : RROTATE_EXPR),
+ rtype, TREE_OPERAND (arg0, 0),
+ orig_tree01);
+ return fold_convert_loc (loc, type, tem);
+ }
}
- else if (code01 == MINUS_EXPR)
+ else if (code == BIT_IOR_EXPR
+ && code11 == BIT_AND_EXPR
+ && pow2p_hwi (element_precision (rtype)))
{
- tree tree010, tree011;
- tree010 = TREE_OPERAND (tree01, 0);
- tree011 = TREE_OPERAND (tree01, 1);
- STRIP_NOPS (tree010);
- STRIP_NOPS (tree011);
- if (TREE_CODE (tree010) == INTEGER_CST
- && 0 == compare_tree_int (tree010,
- element_precision
- (TREE_TYPE (TREE_OPERAND
- (arg0, 0))))
- && operand_equal_p (tree11, tree011, 0))
- return fold_convert_loc
- (loc, type,
- build2 ((code0 != LSHIFT_EXPR
- ? LROTATE_EXPR
- : RROTATE_EXPR),
- TREE_TYPE (TREE_OPERAND (arg0, 0)),
- TREE_OPERAND (arg0, 0), TREE_OPERAND (arg1, 1)));
+ tree tree110, tree111;
+ tree110 = TREE_OPERAND (tree11, 0);
+ tree111 = TREE_OPERAND (tree11, 1);
+ STRIP_NOPS (tree110);
+ STRIP_NOPS (tree111);
+ if (TREE_CODE (tree110) == NEGATE_EXPR
+ && TREE_CODE (tree111) == INTEGER_CST
+ && 0 == compare_tree_int (tree111,
+ element_precision (rtype) - 1)
+ && operand_equal_p (tree01, TREE_OPERAND (tree110, 0), 0))
+ {
+ tem = build2_loc (loc, (code0 == LSHIFT_EXPR
+ ? LROTATE_EXPR : RROTATE_EXPR),
+ rtype, TREE_OPERAND (arg0, 0),
+ orig_tree01);
+ return fold_convert_loc (loc, type, tem);
+ }
}
}
}
@@ -9792,13 +9753,6 @@ fold_binary_loc (location_t loc,
return tem;
}
- if (FLOAT_TYPE_P (type)
- && flag_unsafe_math_optimizations
- && (TREE_CODE (arg0) == RDIV_EXPR || TREE_CODE (arg0) == MULT_EXPR)
- && (TREE_CODE (arg1) == RDIV_EXPR || TREE_CODE (arg1) == MULT_EXPR)
- && (tem = distribute_real_division (loc, code, type, arg0, arg1)))
- return tem;
-
/* Handle (A1 * C1) - (A2 * C2) with A1, A2 or C1, C2 being the same or
one. Make sure the type is not saturating and has the signedness of
the stripped operands, as fold_plusminus_mult_expr will re-associate.
@@ -9899,8 +9853,8 @@ fold_binary_loc (location_t loc,
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
int width = TYPE_PRECISION (type), w;
- wide_int c1 = TREE_OPERAND (arg0, 1);
- wide_int c2 = arg1;
+ wide_int c1 = wi::to_wide (TREE_OPERAND (arg0, 1));
+ wide_int c2 = wi::to_wide (arg1);
/* If (C1&C2) == C1, then (X&C1)|C2 becomes (X,C2). */
if ((c1 & c2) == c1)
@@ -9911,7 +9865,7 @@ fold_binary_loc (location_t loc,
TYPE_PRECISION (TREE_TYPE (arg1)));
/* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */
- if (msk.and_not (c1 | c2) == 0)
+ if (wi::bit_and_not (msk, c1 | c2) == 0)
{
tem = fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
return fold_build2_loc (loc, BIT_IOR_EXPR, type, tem, arg1);
@@ -9922,12 +9876,13 @@ fold_binary_loc (location_t loc,
mode which allows further optimizations. */
c1 &= msk;
c2 &= msk;
- wide_int c3 = c1.and_not (c2);
+ wide_int c3 = wi::bit_and_not (c1, c2);
for (w = BITS_PER_UNIT; w <= width; w <<= 1)
{
wide_int mask = wi::mask (w, false,
TYPE_PRECISION (type));
- if (((c1 | c2) & mask) == mask && c1.and_not (mask) == 0)
+ if (((c1 | c2) & mask) == mask
+ && wi::bit_and_not (c1, mask) == 0)
{
c3 = mask;
break;
@@ -10001,7 +9956,7 @@ fold_binary_loc (location_t loc,
multiple of 1 << CST. */
if (TREE_CODE (arg1) == INTEGER_CST)
{
- wide_int cst1 = arg1;
+ wi::tree_to_wide_ref cst1 = wi::to_wide (arg1);
wide_int ncst1 = -cst1;
if ((cst1 & ncst1) == ncst1
&& multiple_of_p (type, arg0,
@@ -10015,8 +9970,9 @@ fold_binary_loc (location_t loc,
&& TREE_CODE (arg0) == MULT_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST)
{
- wide_int warg1 = arg1;
- wide_int masked = mask_with_tz (type, warg1, TREE_OPERAND (arg0, 1));
+ wi::tree_to_wide_ref warg1 = wi::to_wide (arg1);
+ wide_int masked
+ = mask_with_tz (type, warg1, wi::to_wide (TREE_OPERAND (arg0, 1)));
if (masked == 0)
return omit_two_operands_loc (loc, type, build_zero_cst (type),
@@ -10043,7 +9999,7 @@ fold_binary_loc (location_t loc,
If B is constant and (B & M) == 0, fold into A & M. */
if (TREE_CODE (arg1) == INTEGER_CST)
{
- wide_int cst1 = arg1;
+ wi::tree_to_wide_ref cst1 = wi::to_wide (arg1);
if ((~cst1 != 0) && (cst1 & (cst1 + 1)) == 0
&& INTEGRAL_TYPE_P (TREE_TYPE (arg0))
&& (TREE_CODE (arg0) == PLUS_EXPR
@@ -10079,8 +10035,7 @@ fold_binary_loc (location_t loc,
if (TREE_CODE (TREE_OPERAND (pmop[which], 1))
!= INTEGER_CST)
break;
- cst0 = TREE_OPERAND (pmop[which], 1);
- cst0 &= cst1;
+ cst0 = wi::to_wide (TREE_OPERAND (pmop[which], 1)) & cst1;
if (TREE_CODE (pmop[which]) == BIT_AND_EXPR)
{
if (cst0 != cst1)
@@ -10098,7 +10053,7 @@ fold_binary_loc (location_t loc,
omitted (assumed 0). */
if ((TREE_CODE (arg0) == PLUS_EXPR
|| (TREE_CODE (arg0) == MINUS_EXPR && which == 0))
- && (cst1 & pmop[which]) == 0)
+ && (cst1 & wi::to_wide (pmop[which])) == 0)
pmop[which] = NULL;
break;
default:
@@ -10156,7 +10111,7 @@ fold_binary_loc (location_t loc,
{
prec = element_precision (TREE_TYPE (TREE_OPERAND (arg0, 0)));
- wide_int mask = wide_int::from (arg1, prec, UNSIGNED);
+ wide_int mask = wide_int::from (wi::to_wide (arg1), prec, UNSIGNED);
if (mask == -1)
return
fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
@@ -10199,7 +10154,7 @@ fold_binary_loc (location_t loc,
{
tree sh_cnt = TREE_OPERAND (arg1, 1);
tree pow2 = build_int_cst (TREE_TYPE (sh_cnt),
- wi::exact_log2 (sval));
+ wi::exact_log2 (wi::to_wide (sval)));
if (strict_overflow_p)
fold_overflow_warning (("assuming signed overflow does not "
@@ -10330,7 +10285,8 @@ fold_binary_loc (location_t loc,
if (code == RROTATE_EXPR && TREE_CODE (arg1) == INTEGER_CST
&& TREE_CODE (arg0) == RROTATE_EXPR
&& TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
- && wi::umod_trunc (wi::add (arg1, TREE_OPERAND (arg0, 1)),
+ && wi::umod_trunc (wi::to_wide (arg1)
+ + wi::to_wide (TREE_OPERAND (arg0, 1)),
prec) == 0)
return fold_convert_loc (loc, type, TREE_OPERAND (arg0, 0));
@@ -10512,40 +10468,6 @@ fold_binary_loc (location_t loc,
&& code == NE_EXPR)
return non_lvalue_loc (loc, fold_convert_loc (loc, type, arg0));
- /* Transform comparisons of the form X +- Y CMP X to Y CMP 0. */
- if ((TREE_CODE (arg0) == PLUS_EXPR
- || TREE_CODE (arg0) == POINTER_PLUS_EXPR
- || TREE_CODE (arg0) == MINUS_EXPR)
- && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg0,
- 0)),
- arg1, 0)
- && (INTEGRAL_TYPE_P (TREE_TYPE (arg0))
- || POINTER_TYPE_P (TREE_TYPE (arg0))))
- {
- tree val = TREE_OPERAND (arg0, 1);
- val = fold_build2_loc (loc, code, type, val,
- build_int_cst (TREE_TYPE (val), 0));
- return omit_two_operands_loc (loc, type, val,
- TREE_OPERAND (arg0, 0), arg1);
- }
-
- /* Transform comparisons of the form X CMP X +- Y to Y CMP 0. */
- if ((TREE_CODE (arg1) == PLUS_EXPR
- || TREE_CODE (arg1) == POINTER_PLUS_EXPR
- || TREE_CODE (arg1) == MINUS_EXPR)
- && operand_equal_p (tree_strip_nop_conversions (TREE_OPERAND (arg1,
- 0)),
- arg0, 0)
- && (INTEGRAL_TYPE_P (TREE_TYPE (arg1))
- || POINTER_TYPE_P (TREE_TYPE (arg1))))
- {
- tree val = TREE_OPERAND (arg1, 1);
- val = fold_build2_loc (loc, code, type, val,
- build_int_cst (TREE_TYPE (val), 0));
- return omit_two_operands_loc (loc, type, val,
- TREE_OPERAND (arg1, 0), arg0);
- }
-
/* If this is an EQ or NE comparison with zero and ARG0 is
(1 << foo) & bar, convert it to (bar >> foo) & 1. Both require
two operations, but the latter can be done in one less insn
@@ -10617,7 +10539,7 @@ fold_binary_loc (location_t loc,
prec = TYPE_PRECISION (itype);
/* Check for a valid shift count. */
- if (wi::ltu_p (arg001, prec))
+ if (wi::ltu_p (wi::to_wide (arg001), prec))
{
tree arg01 = TREE_OPERAND (arg0, 1);
tree arg000 = TREE_OPERAND (TREE_OPERAND (arg0, 0), 0);
@@ -10693,7 +10615,7 @@ fold_binary_loc (location_t loc,
tree arg00 = TREE_OPERAND (arg0, 0);
tree arg01 = TREE_OPERAND (arg0, 1);
tree itype = TREE_TYPE (arg00);
- if (wi::eq_p (arg01, element_precision (itype) - 1))
+ if (wi::to_wide (arg01) == element_precision (itype) - 1)
{
if (TYPE_UNSIGNED (itype))
{
@@ -10928,130 +10850,38 @@ fold_binary_loc (location_t loc,
/* Transform comparisons of the form X +- C CMP X. */
if ((TREE_CODE (arg0) == PLUS_EXPR || TREE_CODE (arg0) == MINUS_EXPR)
&& operand_equal_p (TREE_OPERAND (arg0, 0), arg1, 0)
- && ((TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
- && !HONOR_SNANS (arg0))
- || (TREE_CODE (TREE_OPERAND (arg0, 1)) == INTEGER_CST
- && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))))
+ && TREE_CODE (TREE_OPERAND (arg0, 1)) == REAL_CST
+ && !HONOR_SNANS (arg0))
{
tree arg01 = TREE_OPERAND (arg0, 1);
enum tree_code code0 = TREE_CODE (arg0);
- int is_positive;
-
- if (TREE_CODE (arg01) == REAL_CST)
- is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1;
- else
- is_positive = tree_int_cst_sgn (arg01);
+ int is_positive = REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg01)) ? -1 : 1;
/* (X - c) > X becomes false. */
if (code == GT_EXPR
&& ((code0 == MINUS_EXPR && is_positive >= 0)
|| (code0 == PLUS_EXPR && is_positive <= 0)))
- {
- if (TREE_CODE (arg01) == INTEGER_CST
- && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does not "
- "occur when assuming that (X - c) > X "
- "is always false"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (0, type);
- }
+ return constant_boolean_node (0, type);
/* Likewise (X + c) < X becomes false. */
if (code == LT_EXPR
&& ((code0 == PLUS_EXPR && is_positive >= 0)
|| (code0 == MINUS_EXPR && is_positive <= 0)))
- {
- if (TREE_CODE (arg01) == INTEGER_CST
- && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does not "
- "occur when assuming that "
- "(X + c) < X is always false"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (0, type);
- }
+ return constant_boolean_node (0, type);
/* Convert (X - c) <= X to true. */
if (!HONOR_NANS (arg1)
&& code == LE_EXPR
&& ((code0 == MINUS_EXPR && is_positive >= 0)
|| (code0 == PLUS_EXPR && is_positive <= 0)))
- {
- if (TREE_CODE (arg01) == INTEGER_CST
- && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does not "
- "occur when assuming that "
- "(X - c) <= X is always true"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (1, type);
- }
+ return constant_boolean_node (1, type);
/* Convert (X + c) >= X to true. */
if (!HONOR_NANS (arg1)
&& code == GE_EXPR
&& ((code0 == PLUS_EXPR && is_positive >= 0)
|| (code0 == MINUS_EXPR && is_positive <= 0)))
- {
- if (TREE_CODE (arg01) == INTEGER_CST
- && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does not "
- "occur when assuming that "
- "(X + c) >= X is always true"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (1, type);
- }
-
- if (TREE_CODE (arg01) == INTEGER_CST)
- {
- /* Convert X + c > X and X - c < X to true for integers. */
- if (code == GT_EXPR
- && ((code0 == PLUS_EXPR && is_positive > 0)
- || (code0 == MINUS_EXPR && is_positive < 0)))
- {
- if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does "
- "not occur when assuming that "
- "(X + c) > X is always true"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (1, type);
- }
-
- if (code == LT_EXPR
- && ((code0 == MINUS_EXPR && is_positive > 0)
- || (code0 == PLUS_EXPR && is_positive < 0)))
- {
- if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does "
- "not occur when assuming that "
- "(X - c) < X is always true"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (1, type);
- }
-
- /* Convert X + c <= X and X - c >= X to false for integers. */
- if (code == LE_EXPR
- && ((code0 == PLUS_EXPR && is_positive > 0)
- || (code0 == MINUS_EXPR && is_positive < 0)))
- {
- if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does "
- "not occur when assuming that "
- "(X + c) <= X is always false"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (0, type);
- }
-
- if (code == GE_EXPR
- && ((code0 == MINUS_EXPR && is_positive > 0)
- || (code0 == PLUS_EXPR && is_positive < 0)))
- {
- if (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (arg1)))
- fold_overflow_warning (("assuming signed overflow does "
- "not occur when assuming that "
- "(X - c) >= X is always false"),
- WARN_STRICT_OVERFLOW_ALL);
- return constant_boolean_node (0, type);
- }
- }
+ return constant_boolean_node (1, type);
}
/* If we are comparing an ABS_EXPR with a constant, we can
@@ -11443,7 +11273,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
(inner_width, outer_width - inner_width, false,
TYPE_PRECISION (TREE_TYPE (arg1)));
- wide_int common = mask & arg1;
+ wide_int common = mask & wi::to_wide (arg1);
if (common == mask)
{
tem_type = signed_type_for (TREE_TYPE (tem));
@@ -11666,7 +11496,7 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
/* Make sure that the perm value is in an acceptable
range. */
- wide_int t = val;
+ wi::tree_to_wide_ref t = wi::to_wide (val);
need_mask_canon |= wi::gtu_p (t, mask);
need_mask_canon2 |= wi::gtu_p (t, mask2);
unsigned int elt = t.to_uhwi () & mask;
@@ -11748,9 +11578,9 @@ fold_ternary_loc (location_t loc, enum tree_code code, tree type,
{
unsigned HOST_WIDE_INT bitpos = tree_to_uhwi (op2);
unsigned bitsize = TYPE_PRECISION (TREE_TYPE (arg1));
- wide_int tem = wi::bit_and (arg0,
- wi::shifted_mask (bitpos, bitsize, true,
- TYPE_PRECISION (type)));
+ wide_int tem = (wi::to_wide (arg0)
+ & wi::shifted_mask (bitpos, bitsize, true,
+ TYPE_PRECISION (type)));
wide_int tem2
= wi::lshift (wi::zext (wi::to_wide (arg1, TYPE_PRECISION (type)),
bitsize), bitpos);
@@ -12570,7 +12400,8 @@ multiple_of_p (tree type, const_tree top, const_tree bottom)
op1 = TREE_OPERAND (top, 1);
/* const_binop may not detect overflow correctly,
so check for it explicitly here. */
- if (wi::gtu_p (TYPE_PRECISION (TREE_TYPE (size_one_node)), op1)
+ if (wi::gtu_p (TYPE_PRECISION (TREE_TYPE (size_one_node)),
+ wi::to_wide (op1))
&& 0 != (t1 = fold_convert (type,
const_binop (LSHIFT_EXPR,
size_one_node,
@@ -13704,7 +13535,7 @@ fold_negate_const (tree arg0, tree type)
case INTEGER_CST:
{
bool overflow;
- wide_int val = wi::neg (arg0, &overflow);
+ wide_int val = wi::neg (wi::to_wide (arg0), &overflow);
t = force_fit_type (type, val, 1,
(overflow && ! TYPE_UNSIGNED (type))
|| TREE_OVERFLOW (arg0));
@@ -13751,7 +13582,7 @@ fold_abs_const (tree arg0, tree type)
{
/* If the value is unsigned or non-negative, then the absolute value
is the same as the ordinary value. */
- if (!wi::neg_p (arg0, TYPE_SIGN (type)))
+ if (!wi::neg_p (wi::to_wide (arg0), TYPE_SIGN (type)))
t = arg0;
/* If the value is negative, then the absolute value is
@@ -13759,7 +13590,7 @@ fold_abs_const (tree arg0, tree type)
else
{
bool overflow;
- wide_int val = wi::neg (arg0, &overflow);
+ wide_int val = wi::neg (wi::to_wide (arg0), &overflow);
t = force_fit_type (type, val, -1,
overflow | TREE_OVERFLOW (arg0));
}
@@ -13788,7 +13619,7 @@ fold_not_const (const_tree arg0, tree type)
{
gcc_assert (TREE_CODE (arg0) == INTEGER_CST);
- return force_fit_type (type, wi::bit_not (arg0), 0, TREE_OVERFLOW (arg0));
+ return force_fit_type (type, ~wi::to_wide (arg0), 0, TREE_OVERFLOW (arg0));
}
/* Given CODE, a relational operator, the target type, TYPE and two
@@ -14243,7 +14074,7 @@ round_up_loc (location_t loc, tree value, unsigned int divisor)
{
if (TREE_CODE (value) == INTEGER_CST)
{
- wide_int val = value;
+ wide_int val = wi::to_wide (value);
bool overflow_p;
if ((val & (divisor - 1)) == 0)
diff --git a/gcc/fold-const.h b/gcc/fold-const.h
index 46d5639..0684ae7 100644
--- a/gcc/fold-const.h
+++ b/gcc/fold-const.h
@@ -27,8 +27,6 @@ extern int folding_initializer;
/* Convert between trees and native memory representation. */
extern int native_encode_expr (const_tree, unsigned char *, int, int off = -1);
extern tree native_interpret_expr (tree, const unsigned char *, int);
-extern bool can_native_encode_type_p (tree);
-extern bool can_native_encode_string_p (const_tree);
/* Fold constants as much as possible in an expression.
Returns the simplified expression.
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index b6abf24..6bf4f1d 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,338 @@
+2017-10-21 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82586
+ * decl.c (gfc_get_pdt_instance): Remove the error message that
+ the parameter does not have a corresponding component since
+ this is now taken care of when the derived type is resolved. Go
+ straight to error return instead.
+ (gfc_match_formal_arglist): Make the PDT relevant errors
+ immediate so that parsing of the derived type can continue.
+ (gfc_match_derived_decl): Do not check the match status on
+ return from gfc_match_formal_arglist for the same reason.
+ * resolve.c (resolve_fl_derived0): Check that each type
+ parameter has a corresponding component.
+
+ PR fortran/82587
+ * resolve.c (resolve_generic_f): Check that the derived type
+ can be used before resolving the struture constructor.
+
+ PR fortran/82589
+ * symbol.c (check_conflict): Add the conflicts involving PDT
+ KIND and LEN attributes.
+
+2017-10-19 Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
+
+ * interface.c (check_sym_interfaces, check_uop_interfaces,
+ gfc_check_interfaces): Base interface_name buffer off
+ GFC_MAX_SYMBOL_LEN.
+
+2017-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR fortran/82568
+ * gfortran.h (gfc_resolve_do_iterator): Add a bool arg.
+ (gfc_resolve_omp_local_vars): New declaration.
+ * openmp.c (omp_current_ctx): Make static.
+ (gfc_resolve_omp_parallel_blocks): Handle EXEC_OMP_TASKLOOP
+ and EXEC_OMP_TASKLOOP_SIMD.
+ (gfc_resolve_do_iterator): Add ADD_CLAUSE argument, if false,
+ don't actually add any clause. Move omp_current_ctx test
+ earlier.
+ (handle_local_var, gfc_resolve_omp_local_vars): New functions.
+ * resolve.c (gfc_resolve_code): Call gfc_resolve_omp_parallel_blocks
+ instead of just gfc_resolve_omp_do_blocks for EXEC_OMP_TASKLOOP
+ and EXEC_OMP_TASKLOOP_SIMD.
+ (gfc_resolve_code): Adjust gfc_resolve_do_iterator caller.
+ (resolve_codes): Call gfc_resolve_omp_local_vars.
+
+2017-10-19 Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
+
+ * gfortran.h (gfc_lookup_function_fuzzy): New declaration.
+ (gfc_closest_fuzzy_match): New declaration.
+ (vec_push): New definition.
+ * misc.c (gfc_closest_fuzzy_match): New definition.
+ * resolve.c: Include spellcheck.h.
+ (lookup_function_fuzzy_find_candidates): New static function.
+ (lookup_uop_fuzzy_find_candidates): Likewise.
+ (lookup_uop_fuzzy): Likewise.
+ (resolve_operator) <INTRINSIC_USER>: Call lookup_uop_fuzzy.
+ (gfc_lookup_function_fuzzy): New definition.
+ (resolve_unknown_f): Call gfc_lookup_function_fuzzy.
+ * interface.c (check_interface0): Likewise.
+ (lookup_arg_fuzzy_find_candidates): New static function.
+ (lookup_arg_fuzzy ): Likewise.
+ (compare_actual_formal): Call lookup_arg_fuzzy.
+ * symbol.c: Include spellcheck.h.
+ (lookup_symbol_fuzzy_find_candidates): New static function.
+ (lookup_symbol_fuzzy): Likewise.
+ (gfc_set_default_type): Call lookup_symbol_fuzzy.
+ (lookup_component_fuzzy_find_candidates): New static function.
+ (lookup_component_fuzzy): Likewise.
+ (gfc_find_component): Call lookup_component_fuzzy.
+
+2017-10-18 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/82567
+ * frontend-passes.c (combine_array_constructor): If an array
+ constructor is all constants and has more elements than a small
+ constant, don't convert a*[b,c] to [a*b,a*c] to reduce compilation
+ times.
+
+2017-10-18 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/79795
+ * resolve.c (resovle_symbol): Change gcc_assert to
+ sensible error message.
+
+2017-10-18 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82550
+ * trans_decl.c (gfc_get_symbol_decl): Procedure symbols that
+ have the 'used_in_submodule' attribute should be processed by
+ 'gfc_get_extern_function_decl'.
+
+2017-10-16 Fritz Reese <fritzoreese@gmail.com>
+
+ PR fortran/82511
+ * trans-io.c (transfer_expr): Treat BT_UNION as BT_DERIVED.
+
+2017-10-15 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/82372
+ * fortran/scanner.c (last_error_char): New global variable.
+ (gfc_scanner_init_1): Set last_error_char to NULL.
+ (gfc_gobble_whitespace): If a character not printable or
+ not newline, issue an error.
+
+2017-10-13 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/81048
+ * resolve.c (resolve_symbol): Ensure that derived type array
+ results get default initialization.
+
+2017-10-11 Nathan Sidwell <nathan@acm.org>
+
+ * cpp.c (gfc_cpp_add_include_path): Update incpath_e names.
+ (gfc_cpp_add_include_path_after): Likewise.
+
+2017-10-10 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * target-memory.c (gfc_interpret_logical): Use wi::to_wide when
+ operating on trees as wide_ints.
+ * trans-const.c (gfc_conv_tree_to_mpz): Likewise.
+ * trans-expr.c (gfc_conv_cst_int_power): Likewise.
+ * trans-intrinsic.c (trans_this_image): Likewise.
+ (gfc_conv_intrinsic_bound): Likewise.
+ (conv_intrinsic_cobound): Likewise.
+
+2017-10-08 Steven G. Kargl <kargl@gcc.gnu.org>
+
+ * check.c (gfc_check_x): Remove function.
+ * intrinsic.c (add_functions): Use gfc_check_fn_r.
+
+2017-10-08 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82375
+ * module.c : Bump up MOD_VERSION to 15.
+ (mio_component): Edit comment about PDT specification list.
+ (mio_expr, mio_symbol): Include the expression and symbol PDT
+ specification lists in the same way as in mio_component.
+
+2017-10-08 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * dump_prase_tree (show_symbol): Output list of variables in
+ NAMELIST.
+ (show_code_node): Add new line for ELSE and END DO for DO
+ CONCURRENT.
+ * invoke.texi: Document that the output of
+ -fdump-fortran-original, -fdump-fortran-optimized and
+ -fdump-parse-tree is unsable and may lead to ICEs.
+
+2017-10-07 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82375
+ * class.c (gfc_find_derived_vtab): Return NULL for a passed
+ pdt template to prevent bad procedures from being written.
+ * decl.c (gfc_get_pdt_instance): Do not use the default
+ initializer for pointer and allocatable pdt type components. If
+ the component is allocatbale, set the 'alloc_comp' attribute of
+ 'instance'.
+ * module.c : Add a prototype for 'mio_actual_arglist'. Add a
+ boolean argument 'pdt'.
+ (mio_component): Call it for the parameter list of pdt type
+ components with 'pdt' set to true.
+ (mio_actual_arg): Add the boolean 'pdt' and, if it is set, call
+ mio_integer for the 'spec_type'.
+ (mio_actual_arglist): Add the boolean 'pdt' and use it in the
+ call to mio_actual_arg.
+ (mio_expr, mio_omp_udr_expr): Call mio_actual_arglist with
+ 'pdt' set false.
+ * resolve.c (get_pdt_spec_expr): Add the parameter name to the
+ KIND parameter error.
+ (get_pdt_constructor): Check that cons->expr is non-null.
+ * trans-array.c (structure_alloc_comps): For deallocation of
+ allocatable components, ensure that parameterized components
+ are deallocated first. Likewise, when parameterized components
+ are allocated, nullify allocatable components first. Do not
+ recurse into pointer or allocatable pdt components while
+ allocating or deallocating parameterized components. Test that
+ parameterized arrays or strings are allocated before freeing
+ them.
+ (gfc_trans_pointer_assignment): Call the new function. Tidy up
+ a minor whitespace issue.
+ trans-decl.c (gfc_trans_deferred_vars): Set 'tmp' to NULL_TREE
+ to prevent the expression from being used a second time.
+
+2017-10-07 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/49232
+ * expr.c (gfc_check_pointer_assign): Error
+ for non-contiguous rhs.
+
+2017-10-07 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * gfortran.h (async_io_dt): Add external reference.
+ * io.c (async_io_dt): Add variable.
+ (compare_to_allowed_values): Add prototyte. Add optional argument
+ num. If present, set it to the number of the entry that was
+ matched.
+ (check_io_constraints): If this is for an asynchronous I/O
+ statement, set async_io_dt and set the asynchronous flag for
+ a SIZE tag.
+ * resolve.c (resolve_transfer): If async_io_dt is set, set
+ the asynchronous flag on the variable.
+ (resolve_fl_namelist): If async_io_dt is set, set the asynchronous
+ flag on all elements of the namelist.
+
+2017-10-04 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/60458
+ PR fortran/77296
+ * resolve.c (resolve_assoc_var): Deferred character type
+ associate names must not receive an integer conatant length.
+ * symbol.c (gfc_is_associate_pointer): Deferred character
+ length functions also require an associate pointer.
+ * trans-decl.c (gfc_get_symbol_decl): Deferred character
+ length functions or derived type components require the assoc
+ name to have variable string length.
+ * trans-stmt.c (trans_associate_var): Set the string length of
+ deferred string length associate names. The address expression
+ is not needed for allocatable, pointer or dummy targets. Change
+ the comment about defered string length targets.
+
+2017-10-03 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * io.c (match_wait_element): Correctly match END and EOR tags.
+ * dump-parse-tree.c (show_code_node): Handle EXEC_WAIT.
+
+2017-10-02 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82312
+ * resolve.c (gfc_resolve_code): Simplify condition for class
+ pointer assignments becoming regular assignments by asserting
+ that only class valued targets are permitted.
+ * trans-expr.c (trans_class_pointer_fcn): New function using a
+ block of code from gfc_trans_pointer_assignment.
+ (gfc_trans_pointer_assignment): Call the new function. Tidy up
+ a minor whitespace issue.
+
+2017-10-01 Dominique d'Humieres <dominiq@lps.ens.fr>
+
+ PR fortran/61450
+ * parse.c (gfc_global_used): Replace the gfc_internal_error
+ with an error.
+
+2017-09-29 Dominique d'Humieres <dominiq@lps.ens.fr>
+
+ PR fortran/25071
+ * interface.c (compare_actual_formal): Change warnings to errors
+ when "Actual argument contains too few elements for dummy
+ argument", unless -std=legacy is used.
+
+2017-09-27 Thomas Schwinge <thomas@codesourcery.com>
+
+ * lang.opt <Wdo-subscript>: End help text with a period.
+
+2017-09-26 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * frontend-passes.c (do_subscript): Don't do anything
+ if inside an associate list.
+
+2017-09-25 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * lang.opt: Add -Wdo-subscript.
+ * frontend-passes.c (do_t): New type.
+ (doloop_list): Use variable of do_type.
+ (if_level): Variable to track if levels.
+ (select_level): Variable to track select levels.
+ (gfc_run_passes): Initialize i_level and select_level.
+ (doloop_code): Record current level of if + select
+ level in doloop_list. Add seen_goto if there could
+ be a branch outside the loop. Use different type for
+ doloop_list.
+ (doloop_function): Call do_intent and do_subscript; move
+ functionality of checking INTENT to do_intent.
+ (insert_index_t): New type, for callback_insert_index.
+ (callback_insert_index): New function.
+ (insert_index): New function.
+ (do_subscript): New function.
+ (do_intent): New function.
+ (gfc_code_walker): Keep track of if_level and select_level.
+ * invoke.texi: Document -Wdo-subscript.
+
+2017-09-25 Janne Blomqvist <jb@gcc.gnu.org>
+
+ * trans.c (gfc_unlikely): Remove unnecessary fold_convert.
+ (gfc_likely): Likewise.
+
+2017-09-24 Thomas Koenig <tkoenig@gcc.gnu.org>
+ Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/80118
+ * expr.c (gfc_get_full_arrayspec_from_expr): If there is
+ no symtree, set array spec to NULL.
+
+2017-09-23 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/82143
+ * lang.opt: Add the options -fdefault-real-10 and -fdefault-real-16.
+ Rename flag_default_real to flag_default_real_8.
+ * invoke.texi: Add documentation.
+ * module.c (use_iso_fortran_env_module): flag_default_real is renamed.
+ * trans-types.c (gfc_init_kinds): Implement the flags
+ -fdefault-real-10 and -fdefault-real-16. Make -fdefault-double-8 work
+ without -fdefault-real-8.
+
+2017-09-21 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/52832
+ * match.c (gfc_match_associate): Before failing the association
+ try again, allowing a proc pointer selector.
+
+ PR fortran/80120
+ PR fortran/81903
+ PR fortran/82121
+ * primary.c (gfc_match_varspec): Introduce 'tgt_expr', which
+ points to the associate selector, if any. Go through selector
+ references, after resolution for variables, to catch any full
+ or section array references. If a class associate name does
+ not have the same declared type as the selector, resolve the
+ selector and copy the declared type to the associate name.
+ Before throwing a no implicit type error, resolve all allowed
+ selector expressions, and copy the resulting typespec.
+
+ PR fortran/67543
+ * resolve.c (resolve_assoc_var): Selector must cannot be the
+ NULL expression and it must have a type.
+
+ PR fortran/78152
+ * resolve.c (resolve_symbol): Allow associate names to be
+ coarrays.
+
+2017-09-21 Cesar Philippidis <cesar@codesourcery.com>
+
+ * openmp.c (gfc_match_oacc_wait): Don't restrict wait directive
+ arguments to constant integers.
+
2017-09-17 Paul Thomas <pault@gcc.gnu.org>
PR fortran/82173
diff --git a/gcc/fortran/check.c b/gcc/fortran/check.c
index e85e398..681950e 100644
--- a/gcc/fortran/check.c
+++ b/gcc/fortran/check.c
@@ -2262,6 +2262,7 @@ gfc_check_fn_c (gfc_expr *a)
return true;
}
+
/* A single real argument. */
bool
@@ -5512,19 +5513,6 @@ gfc_check_ttynam (gfc_expr *unit)
}
-/* Common check function for the half a dozen intrinsics that have a
- single real argument. */
-
-bool
-gfc_check_x (gfc_expr *x)
-{
- if (!type_check (x, 0, BT_REAL))
- return false;
-
- return true;
-}
-
-
/************* Check functions for intrinsic subroutines *************/
bool
diff --git a/gcc/fortran/class.c b/gcc/fortran/class.c
index a345d13..ebbd41b 100644
--- a/gcc/fortran/class.c
+++ b/gcc/fortran/class.c
@@ -2211,6 +2211,9 @@ gfc_find_derived_vtab (gfc_symbol *derived)
gfc_gsymbol *gsym = NULL;
gfc_symbol *dealloc = NULL, *arg = NULL;
+ if (derived->attr.pdt_template)
+ return NULL;
+
/* Find the top-level namespace. */
for (ns = gfc_current_ns; ns; ns = ns->parent)
if (!ns->parent)
diff --git a/gcc/fortran/cpp.c b/gcc/fortran/cpp.c
index 4d1b56a..af8a69c 100644
--- a/gcc/fortran/cpp.c
+++ b/gcc/fortran/cpp.c
@@ -683,14 +683,14 @@ gfc_cpp_add_include_path (char *path, bool user_supplied)
include path. Fortran does not define any system include paths. */
int cxx_aware = 0;
- add_path (path, BRACKET, cxx_aware, user_supplied);
+ add_path (path, INC_BRACKET, cxx_aware, user_supplied);
}
void
gfc_cpp_add_include_path_after (char *path, bool user_supplied)
{
int cxx_aware = 0;
- add_path (path, AFTER, cxx_aware, user_supplied);
+ add_path (path, INC_AFTER, cxx_aware, user_supplied);
}
void
diff --git a/gcc/fortran/decl.c b/gcc/fortran/decl.c
index 18220a1..1a2d8f0 100644
--- a/gcc/fortran/decl.c
+++ b/gcc/fortran/decl.c
@@ -3242,13 +3242,10 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
param = type_param_name_list->sym;
c1 = gfc_find_component (pdt, param->name, false, true, NULL);
+ /* An error should already have been thrown in resolve.c
+ (resolve_fl_derived0). */
if (!pdt->attr.use_assoc && !c1)
- {
- gfc_error ("The type parameter name list at %L contains a parameter "
- "'%qs' , which is not declared as a component of the type",
- &pdt->declared_at, param->name);
- goto error_return;
- }
+ goto error_return;
kind_expr = NULL;
if (!name_seen)
@@ -3570,7 +3567,11 @@ gfc_get_pdt_instance (gfc_actual_arglist *param_list, gfc_symbol **sym,
type_param_spec_list = old_param_spec_list;
c2->param_list = params;
- c2->initializer = gfc_default_initializer (&c2->ts);
+ if (!(c2->attr.pointer || c2->attr.allocatable))
+ c2->initializer = gfc_default_initializer (&c2->ts);
+
+ if (c2->attr.allocatable)
+ instance->attr.alloc_comp = 1;
}
}
@@ -5980,7 +5981,7 @@ gfc_match_formal_arglist (gfc_symbol *progname, int st_flag,
/* The name of a program unit can be in a different namespace,
so check for it explicitly. After the statement is accepted,
the name is checked for especially in gfc_get_symbol(). */
- if (gfc_new_block != NULL && sym != NULL
+ if (gfc_new_block != NULL && sym != NULL && !typeparam
&& strcmp (sym->name, gfc_new_block->name) == 0)
{
gfc_error ("Name %qs at %C is the name of the procedure",
@@ -5995,7 +5996,11 @@ gfc_match_formal_arglist (gfc_symbol *progname, int st_flag,
m = gfc_match_char (',');
if (m != MATCH_YES)
{
- gfc_error ("Unexpected junk in formal argument list at %C");
+ if (typeparam)
+ gfc_error_now ("Expected parameter list in type declaration "
+ "at %C");
+ else
+ gfc_error ("Unexpected junk in formal argument list at %C");
goto cleanup;
}
}
@@ -6012,8 +6017,12 @@ ok:
for (q = p->next; q; q = q->next)
if (p->sym == q->sym)
{
- gfc_error ("Duplicate symbol %qs in formal argument list "
- "at %C", p->sym->name);
+ if (typeparam)
+ gfc_error_now ("Duplicate name %qs in parameter "
+ "list at %C", p->sym->name);
+ else
+ gfc_error ("Duplicate symbol %qs in formal argument "
+ "list at %C", p->sym->name);
m = MATCH_ERROR;
goto cleanup;
@@ -9810,9 +9819,9 @@ gfc_match_derived_decl (void)
if (parameterized_type)
{
- m = gfc_match_formal_arglist (sym, 0, 0, true);
- if (m != MATCH_YES)
- return m;
+ /* Ignore error or mismatches to avoid the component declarations
+ causing problems later. */
+ gfc_match_formal_arglist (sym, 0, 0, true);
m = gfc_match_eos ();
if (m != MATCH_YES)
return m;
diff --git a/gcc/fortran/dump-parse-tree.c b/gcc/fortran/dump-parse-tree.c
index a9107c1..5193c29 100644
--- a/gcc/fortran/dump-parse-tree.c
+++ b/gcc/fortran/dump-parse-tree.c
@@ -967,8 +967,17 @@ show_symbol (gfc_symbol *sym)
show_indent ();
fputs ("PDT parameters", dumpfile);
show_actual_arglist (sym->param_list);
+ }
+ if (sym->attr.flavor == FL_NAMELIST)
+ {
+ gfc_namelist *nl;
+ show_indent ();
+ fputs ("variables : ", dumpfile);
+ for (nl = sym->namelist; nl; nl = nl->next)
+ fprintf (dumpfile, " %s",nl->sym->name);
}
+
--show_level;
}
@@ -1979,8 +1988,8 @@ show_code_node (int level, gfc_code *c)
d = d->block;
for (; d; d = d->block)
{
+ fputs("\n", dumpfile);
code_indent (level, 0);
-
if (d->expr1 == NULL)
fputs ("ELSE", dumpfile);
else
@@ -2170,9 +2179,12 @@ show_code_node (int level, gfc_code *c)
fputc (',', dumpfile);
}
show_expr (c->expr1);
+ ++show_level;
show_code (level + 1, c->block->next);
+ --show_level;
code_indent (level, c->label1);
+ show_indent ();
fputs ("END DO", dumpfile);
break;
@@ -2727,6 +2739,41 @@ show_code_node (int level, gfc_code *c)
fprintf (dumpfile, " EOR=%d", dt->eor->value);
break;
+ case EXEC_WAIT:
+ fputs ("WAIT", dumpfile);
+
+ if (c->ext.wait != NULL)
+ {
+ gfc_wait *wait = c->ext.wait;
+ if (wait->unit)
+ {
+ fputs (" UNIT=", dumpfile);
+ show_expr (wait->unit);
+ }
+ if (wait->iostat)
+ {
+ fputs (" IOSTAT=", dumpfile);
+ show_expr (wait->iostat);
+ }
+ if (wait->iomsg)
+ {
+ fputs (" IOMSG=", dumpfile);
+ show_expr (wait->iomsg);
+ }
+ if (wait->id)
+ {
+ fputs (" ID=", dumpfile);
+ show_expr (wait->id);
+ }
+ if (wait->err)
+ fprintf (dumpfile, " ERR=%d", wait->err->value);
+ if (wait->end)
+ fprintf (dumpfile, " END=%d", wait->end->value);
+ if (wait->eor)
+ fprintf (dumpfile, " EOR=%d", wait->eor->value);
+ }
+ break;
+
case EXEC_OACC_PARALLEL_LOOP:
case EXEC_OACC_PARALLEL:
case EXEC_OACC_KERNELS_LOOP:
diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c
index 87ea09f..bc05db2 100644
--- a/gcc/fortran/expr.c
+++ b/gcc/fortran/expr.c
@@ -3851,6 +3851,14 @@ gfc_check_pointer_assign (gfc_expr *lvalue, gfc_expr *rvalue)
}
}
+ /* Error for assignments of contiguous pointers to targets which is not
+ contiguous. Be lenient in the definition of what counts as
+ congiguous. */
+
+ if (lhs_attr.contiguous && !gfc_is_simply_contiguous (rvalue, false, true))
+ gfc_error ("Assignment to contiguous pointer from non-contiguous "
+ "target at %L", &rvalue->where);
+
/* Warn if it is the LHS pointer may lives longer than the RHS target. */
if (warn_target_lifetime
&& rvalue->expr_type == EXPR_VARIABLE
@@ -4568,7 +4576,11 @@ gfc_get_full_arrayspec_from_expr (gfc_expr *expr)
if (expr->expr_type == EXPR_VARIABLE
|| expr->expr_type == EXPR_CONSTANT)
{
- as = expr->symtree->n.sym->as;
+ if (expr->symtree)
+ as = expr->symtree->n.sym->as;
+ else
+ as = NULL;
+
for (ref = expr->ref; ref; ref = ref->next)
{
switch (ref->type)
diff --git a/gcc/fortran/frontend-passes.c b/gcc/fortran/frontend-passes.c
index 2631849..fcfaf95 100644
--- a/gcc/fortran/frontend-passes.c
+++ b/gcc/fortran/frontend-passes.c
@@ -39,6 +39,8 @@ static bool optimize_lexical_comparison (gfc_expr *);
static void optimize_minmaxloc (gfc_expr **);
static bool is_empty_string (gfc_expr *e);
static void doloop_warn (gfc_namespace *);
+static int do_intent (gfc_expr **);
+static int do_subscript (gfc_expr **);
static void optimize_reduction (gfc_namespace *);
static int callback_reduction (gfc_expr **, int *, void *);
static void realloc_strings (gfc_namespace *);
@@ -98,10 +100,20 @@ static int iterator_level;
/* Keep track of DO loop levels. */
-static vec<gfc_code *> doloop_list;
+typedef struct {
+ gfc_code *c;
+ int branch_level;
+ bool seen_goto;
+} do_t;
+static vec<do_t> doloop_list;
static int doloop_level;
+/* Keep track of if and select case levels. */
+
+static int if_level;
+static int select_level;
+
/* Vector of gfc_expr * to keep track of DO loops. */
struct my_struct *evec;
@@ -133,6 +145,8 @@ gfc_run_passes (gfc_namespace *ns)
change. */
doloop_level = 0;
+ if_level = 0;
+ select_level = 0;
doloop_warn (ns);
doloop_list.release ();
int w, e;
@@ -1621,6 +1635,8 @@ combine_array_constructor (gfc_expr *e)
gfc_constructor *c, *new_c;
gfc_constructor_base oldbase, newbase;
bool scalar_first;
+ int n_elem;
+ bool all_const;
/* Array constructors have rank one. */
if (e->rank != 1)
@@ -1660,12 +1676,38 @@ combine_array_constructor (gfc_expr *e)
if (op2->ts.type == BT_CHARACTER)
return false;
- scalar = create_var (gfc_copy_expr (op2), "constr");
+ /* This might be an expanded constructor with very many constant values. If
+ we perform the operation here, we might end up with a long compile time
+ and actually longer execution time, so a length bound is in order here.
+ If the constructor constains something which is not a constant, it did
+ not come from an expansion, so leave it alone. */
+
+#define CONSTR_LEN_MAX 4
oldbase = op1->value.constructor;
+
+ n_elem = 0;
+ all_const = true;
+ for (c = gfc_constructor_first (oldbase); c; c = gfc_constructor_next(c))
+ {
+ if (c->expr->expr_type != EXPR_CONSTANT)
+ {
+ all_const = false;
+ break;
+ }
+ n_elem += 1;
+ }
+
+ if (all_const && n_elem > CONSTR_LEN_MAX)
+ return false;
+
+#undef CONSTR_LEN_MAX
+
newbase = NULL;
e->expr_type = EXPR_ARRAY;
+ scalar = create_var (gfc_copy_expr (op2), "constr");
+
for (c = gfc_constructor_first (oldbase); c;
c = gfc_constructor_next (c))
{
@@ -2231,6 +2273,8 @@ doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
gfc_formal_arglist *f;
gfc_actual_arglist *a;
gfc_code *cl;
+ do_t loop, *lp;
+ bool seen_goto;
co = *c;
@@ -2239,14 +2283,65 @@ doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
if ((unsigned) doloop_level < doloop_list.length())
doloop_list.truncate (doloop_level);
+ seen_goto = false;
switch (co->op)
{
case EXEC_DO:
if (co->ext.iterator && co->ext.iterator->var)
- doloop_list.safe_push (co);
+ loop.c = co;
else
- doloop_list.safe_push ((gfc_code *) NULL);
+ loop.c = NULL;
+
+ loop.branch_level = if_level + select_level;
+ loop.seen_goto = false;
+ doloop_list.safe_push (loop);
+ break;
+
+ /* If anything could transfer control away from a suspicious
+ subscript, make sure to set seen_goto in the current DO loop
+ (if any). */
+ case EXEC_GOTO:
+ case EXEC_EXIT:
+ case EXEC_STOP:
+ case EXEC_ERROR_STOP:
+ case EXEC_CYCLE:
+ seen_goto = true;
+ break;
+
+ case EXEC_OPEN:
+ if (co->ext.open->err)
+ seen_goto = true;
+ break;
+
+ case EXEC_CLOSE:
+ if (co->ext.close->err)
+ seen_goto = true;
+ break;
+
+ case EXEC_BACKSPACE:
+ case EXEC_ENDFILE:
+ case EXEC_REWIND:
+ case EXEC_FLUSH:
+
+ if (co->ext.filepos->err)
+ seen_goto = true;
+ break;
+
+ case EXEC_INQUIRE:
+ if (co->ext.filepos->err)
+ seen_goto = true;
+ break;
+
+ case EXEC_READ:
+ case EXEC_WRITE:
+ if (co->ext.dt->err || co->ext.dt->end || co->ext.dt->eor)
+ seen_goto = true;
+ break;
+
+ case EXEC_WAIT:
+ if (co->ext.wait->err || co->ext.wait->end || co->ext.wait->eor)
+ loop.seen_goto = true;
break;
case EXEC_CALL:
@@ -2265,9 +2360,10 @@ doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
while (a && f)
{
- FOR_EACH_VEC_ELT (doloop_list, i, cl)
+ FOR_EACH_VEC_ELT (doloop_list, i, lp)
{
gfc_symbol *do_sym;
+ cl = lp->c;
if (cl == NULL)
break;
@@ -2282,14 +2378,14 @@ doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
"value inside loop beginning at %L as "
"INTENT(OUT) argument to subroutine %qs",
do_sym->name, &a->expr->where,
- &doloop_list[i]->loc,
+ &(doloop_list[i].c->loc),
co->symtree->n.sym->name);
else if (f->sym->attr.intent == INTENT_INOUT)
gfc_error_now ("Variable %qs at %L not definable inside "
"loop beginning at %L as INTENT(INOUT) "
"argument to subroutine %qs",
do_sym->name, &a->expr->where,
- &doloop_list[i]->loc,
+ &(doloop_list[i].c->loc),
co->symtree->n.sym->name);
}
}
@@ -2301,20 +2397,271 @@ doloop_code (gfc_code **c, int *walk_subtrees ATTRIBUTE_UNUSED,
default:
break;
}
+ if (seen_goto && doloop_level > 0)
+ doloop_list[doloop_level-1].seen_goto = true;
+
return 0;
}
-/* Callback function for functions checking that we do not pass a DO variable
- to an INTENT(OUT) or INTENT(INOUT) dummy variable. */
+/* Callback function to warn about different things within DO loops. */
static int
do_function (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED)
{
+ do_t *last;
+
+ if (doloop_list.length () == 0)
+ return 0;
+
+ if ((*e)->expr_type == EXPR_FUNCTION)
+ do_intent (e);
+
+ last = &doloop_list.last();
+ if (last->seen_goto && !warn_do_subscript)
+ return 0;
+
+ if ((*e)->expr_type == EXPR_VARIABLE)
+ do_subscript (e);
+
+ return 0;
+}
+
+typedef struct
+{
+ gfc_symbol *sym;
+ mpz_t val;
+} insert_index_t;
+
+/* Callback function - if the expression is the variable in data->sym,
+ replace it with a constant from data->val. */
+
+static int
+callback_insert_index (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
+ void *data)
+{
+ insert_index_t *d;
+ gfc_expr *ex, *n;
+
+ ex = (*e);
+ if (ex->expr_type != EXPR_VARIABLE)
+ return 0;
+
+ d = (insert_index_t *) data;
+ if (ex->symtree->n.sym != d->sym)
+ return 0;
+
+ n = gfc_get_constant_expr (BT_INTEGER, ex->ts.kind, &ex->where);
+ mpz_set (n->value.integer, d->val);
+
+ gfc_free_expr (ex);
+ *e = n;
+ return 0;
+}
+
+/* In the expression e, replace occurrences of the variable sym with
+ val. If this results in a constant expression, return true and
+ return the value in ret. Return false if the expression already
+ is a constant. Caller has to clear ret in that case. */
+
+static bool
+insert_index (gfc_expr *e, gfc_symbol *sym, mpz_t val, mpz_t ret)
+{
+ gfc_expr *n;
+ insert_index_t data;
+ bool rc;
+
+ if (e->expr_type == EXPR_CONSTANT)
+ return false;
+
+ n = gfc_copy_expr (e);
+ data.sym = sym;
+ mpz_init_set (data.val, val);
+ gfc_expr_walker (&n, callback_insert_index, (void *) &data);
+ gfc_simplify_expr (n, 0);
+
+ if (n->expr_type == EXPR_CONSTANT)
+ {
+ rc = true;
+ mpz_init_set (ret, n->value.integer);
+ }
+ else
+ rc = false;
+
+ mpz_clear (data.val);
+ gfc_free_expr (n);
+ return rc;
+
+}
+
+/* Check array subscripts for possible out-of-bounds accesses in DO
+ loops with constant bounds. */
+
+static int
+do_subscript (gfc_expr **e)
+{
+ gfc_expr *v;
+ gfc_array_ref *ar;
+ gfc_ref *ref;
+ int i,j;
+ gfc_code *dl;
+ do_t *lp;
+
+ v = *e;
+ /* Constants are already checked. */
+ if (v->expr_type == EXPR_CONSTANT)
+ return 0;
+
+ /* Wrong warnings will be generated in an associate list. */
+ if (in_assoc_list)
+ return 0;
+
+ for (ref = v->ref; ref; ref = ref->next)
+ {
+ if (ref->type == REF_ARRAY && ref->u.ar.type == AR_ELEMENT)
+ {
+ ar = & ref->u.ar;
+ FOR_EACH_VEC_ELT (doloop_list, j, lp)
+ {
+ gfc_symbol *do_sym;
+ mpz_t do_start, do_step, do_end;
+ bool have_do_start, have_do_end;
+ bool error_not_proven;
+ int warn;
+
+ dl = lp->c;
+ if (dl == NULL)
+ break;
+
+ /* If we are within a branch, or a goto or equivalent
+ was seen in the DO loop before, then we cannot prove that
+ this expression is actually evaluated. Don't do anything
+ unless we want to see it all. */
+ error_not_proven = lp->seen_goto
+ || lp->branch_level < if_level + select_level;
+
+ if (error_not_proven && !warn_do_subscript)
+ break;
+
+ if (error_not_proven)
+ warn = OPT_Wdo_subscript;
+ else
+ warn = 0;
+
+ do_sym = dl->ext.iterator->var->symtree->n.sym;
+ if (do_sym->ts.type != BT_INTEGER)
+ continue;
+
+ /* If we do not know about the stepsize, the loop may be zero trip.
+ Do not warn in this case. */
+
+ if (dl->ext.iterator->step->expr_type == EXPR_CONSTANT)
+ mpz_init_set (do_step, dl->ext.iterator->step->value.integer);
+ else
+ continue;
+
+ if (dl->ext.iterator->start->expr_type == EXPR_CONSTANT)
+ {
+ have_do_start = true;
+ mpz_init_set (do_start, dl->ext.iterator->start->value.integer);
+ }
+ else
+ have_do_start = false;
+
+
+ if (dl->ext.iterator->end->expr_type == EXPR_CONSTANT)
+ {
+ have_do_end = true;
+ mpz_init_set (do_end, dl->ext.iterator->end->value.integer);
+ }
+ else
+ have_do_end = false;
+
+ if (!have_do_start && !have_do_end)
+ return 0;
+
+ /* May have to correct the end value if the step does not equal
+ one. */
+ if (have_do_start && have_do_end && mpz_cmp_ui (do_step, 1) != 0)
+ {
+ mpz_t diff, rem;
+
+ mpz_init (diff);
+ mpz_init (rem);
+ mpz_sub (diff, do_end, do_start);
+ mpz_tdiv_r (rem, diff, do_step);
+ mpz_sub (do_end, do_end, rem);
+ mpz_clear (diff);
+ mpz_clear (rem);
+ }
+
+ for (i = 0; i< ar->dimen; i++)
+ {
+ mpz_t val;
+ if (ar->dimen_type[i] == DIMEN_ELEMENT && have_do_start
+ && insert_index (ar->start[i], do_sym, do_start, val))
+ {
+ if (ar->as->lower[i]
+ && ar->as->lower[i]->expr_type == EXPR_CONSTANT
+ && mpz_cmp (val, ar->as->lower[i]->value.integer) < 0)
+ gfc_warning (warn, "Array reference at %L out of bounds "
+ "(%ld < %ld) in loop beginning at %L",
+ &ar->start[i]->where, mpz_get_si (val),
+ mpz_get_si (ar->as->lower[i]->value.integer),
+ &doloop_list[j].c->loc);
+
+ if (ar->as->upper[i]
+ && ar->as->upper[i]->expr_type == EXPR_CONSTANT
+ && mpz_cmp (val, ar->as->upper[i]->value.integer) > 0)
+ gfc_warning (warn, "Array reference at %L out of bounds "
+ "(%ld > %ld) in loop beginning at %L",
+ &ar->start[i]->where, mpz_get_si (val),
+ mpz_get_si (ar->as->upper[i]->value.integer),
+ &doloop_list[j].c->loc);
+
+ mpz_clear (val);
+ }
+
+ if (ar->dimen_type[i] == DIMEN_ELEMENT && have_do_end
+ && insert_index (ar->start[i], do_sym, do_end, val))
+ {
+ if (ar->as->lower[i]
+ && ar->as->lower[i]->expr_type == EXPR_CONSTANT
+ && mpz_cmp (val, ar->as->lower[i]->value.integer) < 0)
+ gfc_warning (warn, "Array reference at %L out of bounds "
+ "(%ld < %ld) in loop beginning at %L",
+ &ar->start[i]->where, mpz_get_si (val),
+ mpz_get_si (ar->as->lower[i]->value.integer),
+ &doloop_list[j].c->loc);
+
+ if (ar->as->upper[i]
+ && ar->as->upper[i]->expr_type == EXPR_CONSTANT
+ && mpz_cmp (val, ar->as->upper[i]->value.integer) > 0)
+ gfc_warning (warn, "Array reference at %L out of bounds "
+ "(%ld > %ld) in loop beginning at %L",
+ &ar->start[i]->where, mpz_get_si (val),
+ mpz_get_si (ar->as->upper[i]->value.integer),
+ &doloop_list[j].c->loc);
+
+ mpz_clear (val);
+ }
+ }
+ }
+ }
+ }
+ return 0;
+}
+/* Function for functions checking that we do not pass a DO variable
+ to an INTENT(OUT) or INTENT(INOUT) dummy variable. */
+
+static int
+do_intent (gfc_expr **e)
+{
gfc_formal_arglist *f;
gfc_actual_arglist *a;
gfc_expr *expr;
gfc_code *dl;
+ do_t *lp;
int i;
expr = *e;
@@ -2337,10 +2684,10 @@ do_function (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
while (a && f)
{
- FOR_EACH_VEC_ELT (doloop_list, i, dl)
+ FOR_EACH_VEC_ELT (doloop_list, i, lp)
{
gfc_symbol *do_sym;
-
+ dl = lp->c;
if (dl == NULL)
break;
@@ -2353,13 +2700,13 @@ do_function (gfc_expr **e, int *walk_subtrees ATTRIBUTE_UNUSED,
gfc_error_now ("Variable %qs at %L set to undefined value "
"inside loop beginning at %L as INTENT(OUT) "
"argument to function %qs", do_sym->name,
- &a->expr->where, &doloop_list[i]->loc,
+ &a->expr->where, &doloop_list[i].c->loc,
expr->symtree->n.sym->name);
else if (f->sym->attr.intent == INTENT_INOUT)
gfc_error_now ("Variable %qs at %L not definable inside loop"
" beginning at %L as INTENT(INOUT) argument to"
" function %qs", do_sym->name,
- &a->expr->where, &doloop_list[i]->loc,
+ &a->expr->where, &doloop_list[i].c->loc,
expr->symtree->n.sym->name);
}
}
@@ -4055,6 +4402,10 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
WALK_SUBEXPR (co->ext.iterator->step);
break;
+ case EXEC_IF:
+ if_level ++;
+ break;
+
case EXEC_WHERE:
in_where = true;
break;
@@ -4073,6 +4424,7 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
case EXEC_SELECT:
WALK_SUBEXPR (co->expr1);
+ select_level ++;
for (b = co->block; b; b = b->block)
{
gfc_case *cp;
@@ -4329,6 +4681,12 @@ gfc_code_walker (gfc_code **c, walk_code_fn_t codefn, walk_expr_fn_t exprfn,
if (co->op == EXEC_DO)
doloop_level --;
+ if (co->op == EXEC_IF)
+ if_level --;
+
+ if (co->op == EXEC_SELECT)
+ select_level --;
+
in_omp_workshare = saved_in_omp_workshare;
in_where = saved_in_where;
}
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 18a534d..2c2fc63 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -2796,6 +2796,17 @@ void gfc_done_2 (void);
int get_c_kind (const char *, CInteropKind_t *);
+const char *gfc_closest_fuzzy_match (const char *, char **);
+static inline void
+vec_push (char **&optr, size_t &osz, const char *elt)
+{
+ /* {auto,}vec.safe_push () replacement. Don't ask.. */
+ // if (strlen (elt) < 4) return; premature optimization: eliminated by cutoff
+ optr = XRESIZEVEC (char *, optr, osz + 2);
+ optr[osz] = CONST_CAST (char *, elt);
+ optr[++osz] = NULL;
+}
+
/* options.c */
unsigned int gfc_option_lang_mask (void);
void gfc_init_options_struct (struct gcc_options *);
@@ -3103,7 +3114,8 @@ void gfc_free_omp_declare_simd_list (gfc_omp_declare_simd *);
void gfc_free_omp_udr (gfc_omp_udr *);
gfc_omp_udr *gfc_omp_udr_find (gfc_symtree *, gfc_typespec *);
void gfc_resolve_omp_directive (gfc_code *, gfc_namespace *);
-void gfc_resolve_do_iterator (gfc_code *, gfc_symbol *);
+void gfc_resolve_do_iterator (gfc_code *, gfc_symbol *, bool);
+void gfc_resolve_omp_local_vars (gfc_namespace *);
void gfc_resolve_omp_parallel_blocks (gfc_code *, gfc_namespace *);
void gfc_resolve_omp_do_blocks (gfc_code *, gfc_namespace *);
void gfc_resolve_omp_declare_simd (gfc_namespace *);
@@ -3228,6 +3240,7 @@ bool gfc_type_is_extensible (gfc_symbol *);
bool gfc_resolve_intrinsic (gfc_symbol *, locus *);
bool gfc_explicit_interface_required (gfc_symbol *, char *, int);
extern int gfc_do_concurrent_flag;
+const char* gfc_lookup_function_fuzzy (const char *, gfc_symtree *);
/* array.c */
@@ -3311,6 +3324,7 @@ void gfc_free_dt (gfc_dt *);
bool gfc_resolve_dt (gfc_dt *, locus *);
void gfc_free_wait (gfc_wait *);
bool gfc_resolve_wait (gfc_wait *);
+extern bool async_io_dt;
/* module.c */
void gfc_module_init_2 (void);
diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c
index fb6db21..9f0fcc8 100644
--- a/gcc/fortran/interface.c
+++ b/gcc/fortran/interface.c
@@ -1793,13 +1793,27 @@ check_interface0 (gfc_interface *p, const char *interface_name)
|| !p->sym->attr.if_source)
&& !gfc_fl_struct (p->sym->attr.flavor))
{
+ const char *guessed
+ = gfc_lookup_function_fuzzy (p->sym->name, p->sym->ns->sym_root);
+
if (p->sym->attr.external)
- gfc_error ("Procedure %qs in %s at %L has no explicit interface",
- p->sym->name, interface_name, &p->sym->declared_at);
+ if (guessed)
+ gfc_error ("Procedure %qs in %s at %L has no explicit interface"
+ "; did you mean %qs?",
+ p->sym->name, interface_name, &p->sym->declared_at,
+ guessed);
+ else
+ gfc_error ("Procedure %qs in %s at %L has no explicit interface",
+ p->sym->name, interface_name, &p->sym->declared_at);
else
- gfc_error ("Procedure %qs in %s at %L is neither function nor "
- "subroutine", p->sym->name, interface_name,
- &p->sym->declared_at);
+ if (guessed)
+ gfc_error ("Procedure %qs in %s at %L is neither function nor "
+ "subroutine; did you mean %qs?", p->sym->name,
+ interface_name, &p->sym->declared_at, guessed);
+ else
+ gfc_error ("Procedure %qs in %s at %L is neither function nor "
+ "subroutine", p->sym->name, interface_name,
+ &p->sym->declared_at);
return true;
}
@@ -1904,7 +1918,7 @@ check_interface1 (gfc_interface *p, gfc_interface *q0,
static void
check_sym_interfaces (gfc_symbol *sym)
{
- char interface_name[100];
+ char interface_name[GFC_MAX_SYMBOL_LEN + sizeof("generic interface ''")];
gfc_interface *p;
if (sym->ns != gfc_current_ns)
@@ -1941,7 +1955,7 @@ check_sym_interfaces (gfc_symbol *sym)
static void
check_uop_interfaces (gfc_user_op *uop)
{
- char interface_name[100];
+ char interface_name[GFC_MAX_SYMBOL_LEN + sizeof("operator interface ''")];
gfc_user_op *uop2;
gfc_namespace *ns;
@@ -2018,7 +2032,7 @@ void
gfc_check_interfaces (gfc_namespace *ns)
{
gfc_namespace *old_ns, *ns2;
- char interface_name[100];
+ char interface_name[GFC_MAX_SYMBOL_LEN + sizeof("intrinsic '' operator")];
int i;
old_ns = gfc_current_ns;
@@ -2778,6 +2792,31 @@ is_procptr_result (gfc_expr *expr)
}
+/* Recursively append candidate argument ARG to CANDIDATES. Store the
+ number of total candidates in CANDIDATES_LEN. */
+
+static void
+lookup_arg_fuzzy_find_candidates (gfc_formal_arglist *arg,
+ char **&candidates,
+ size_t &candidates_len)
+{
+ for (gfc_formal_arglist *p = arg; p && p->sym; p = p->next)
+ vec_push (candidates, candidates_len, p->sym->name);
+}
+
+
+/* Lookup argument ARG fuzzily, taking names in ARGUMENTS into account. */
+
+static const char*
+lookup_arg_fuzzy (const char *arg, gfc_formal_arglist *arguments)
+{
+ char **candidates = NULL;
+ size_t candidates_len = 0;
+ lookup_arg_fuzzy_find_candidates (arguments, candidates, candidates_len);
+ return gfc_closest_fuzzy_match (arg, candidates);
+}
+
+
/* Given formal and actual argument lists, see if they are compatible.
If they are compatible, the actual argument list is sorted to
correspond with the formal list, and elements for missing optional
@@ -2831,8 +2870,16 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
if (f == NULL)
{
if (where)
- gfc_error ("Keyword argument %qs at %L is not in "
- "the procedure", a->name, &a->expr->where);
+ {
+ const char *guessed = lookup_arg_fuzzy (a->name, formal);
+ if (guessed)
+ gfc_error ("Keyword argument %qs at %L is not in "
+ "the procedure; did you mean %qs?",
+ a->name, &a->expr->where, guessed);
+ else
+ gfc_error ("Keyword argument %qs at %L is not in "
+ "the procedure", a->name, &a->expr->where);
+ }
return false;
}
@@ -2991,11 +3038,20 @@ compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal,
f->sym->name, actual_size, formal_size,
&a->expr->where);
else if (where)
- gfc_warning (OPT_Wargument_mismatch,
- "Actual argument contains too few "
- "elements for dummy argument %qs (%lu/%lu) at %L",
- f->sym->name, actual_size, formal_size,
- &a->expr->where);
+ {
+ /* Emit a warning for -std=legacy and an error otherwise. */
+ if (gfc_option.warn_std == 0)
+ gfc_warning (OPT_Wargument_mismatch,
+ "Actual argument contains too few "
+ "elements for dummy argument %qs (%lu/%lu) "
+ "at %L", f->sym->name, actual_size,
+ formal_size, &a->expr->where);
+ else
+ gfc_error_now ("Actual argument contains too few "
+ "elements for dummy argument %qs (%lu/%lu) "
+ "at %L", f->sym->name, actual_size,
+ formal_size, &a->expr->where);
+ }
return false;
}
@@ -3543,8 +3599,15 @@ gfc_procedure_use (gfc_symbol *sym, gfc_actual_arglist **ap, locus *where)
{
if (sym->ns->has_implicit_none_export && sym->attr.proc == PROC_UNKNOWN)
{
- gfc_error ("Procedure %qs called at %L is not explicitly declared",
- sym->name, where);
+ const char *guessed
+ = gfc_lookup_function_fuzzy (sym->name, sym->ns->sym_root);
+ if (guessed)
+ gfc_error ("Procedure %qs called at %L is not explicitly declared"
+ "; did you mean %qs?",
+ sym->name, where, guessed);
+ else
+ gfc_error ("Procedure %qs called at %L is not explicitly declared",
+ sym->name, where);
return false;
}
if (warn_implicit_interface)
diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c
index 8965d50..da96e8f 100644
--- a/gcc/fortran/intrinsic.c
+++ b/gcc/fortran/intrinsic.c
@@ -1760,8 +1760,8 @@ add_functions (void)
make_generic ("eoshift", GFC_ISYM_EOSHIFT, GFC_STD_F95);
- add_sym_1 ("epsilon", GFC_ISYM_EPSILON, CLASS_INQUIRY, ACTUAL_NO, BT_REAL, dr, GFC_STD_F95,
- gfc_check_x, gfc_simplify_epsilon, NULL,
+ add_sym_1 ("epsilon", GFC_ISYM_EPSILON, CLASS_INQUIRY, ACTUAL_NO, BT_REAL, dr,
+ GFC_STD_F95, gfc_check_fn_r, gfc_simplify_epsilon, NULL,
x, BT_REAL, dr, REQUIRED);
make_generic ("epsilon", GFC_ISYM_EPSILON, GFC_STD_F95);
@@ -1827,8 +1827,8 @@ add_functions (void)
make_generic ("exp", GFC_ISYM_EXP, GFC_STD_F77);
- add_sym_1 ("exponent", GFC_ISYM_EXPONENT, CLASS_ELEMENTAL, ACTUAL_NO, BT_INTEGER, di, GFC_STD_F95,
- gfc_check_x, gfc_simplify_exponent, gfc_resolve_exponent,
+ add_sym_1 ("exponent", GFC_ISYM_EXPONENT, CLASS_ELEMENTAL, ACTUAL_NO, BT_INTEGER, di,
+ GFC_STD_F95, gfc_check_fn_r, gfc_simplify_exponent, gfc_resolve_exponent,
x, BT_REAL, dr, REQUIRED);
make_generic ("exponent", GFC_ISYM_EXPONENT, GFC_STD_F95);
@@ -1865,8 +1865,8 @@ add_functions (void)
make_generic ("fnum", GFC_ISYM_FNUM, GFC_STD_GNU);
- add_sym_1 ("fraction", GFC_ISYM_FRACTION, CLASS_ELEMENTAL, ACTUAL_NO, BT_REAL, dr, GFC_STD_F95,
- gfc_check_x, gfc_simplify_fraction, gfc_resolve_fraction,
+ add_sym_1 ("fraction", GFC_ISYM_FRACTION, CLASS_ELEMENTAL, ACTUAL_NO, BT_REAL, dr,
+ GFC_STD_F95, gfc_check_fn_r, gfc_simplify_fraction, gfc_resolve_fraction,
x, BT_REAL, dr, REQUIRED);
make_generic ("fraction", GFC_ISYM_FRACTION, GFC_STD_F95);
@@ -2449,8 +2449,8 @@ add_functions (void)
make_generic ("max", GFC_ISYM_MAX, GFC_STD_F77);
- add_sym_1 ("maxexponent", GFC_ISYM_MAXEXPONENT, CLASS_INQUIRY, ACTUAL_NO, BT_INTEGER, di,
- GFC_STD_F95, gfc_check_x, gfc_simplify_maxexponent, NULL,
+ add_sym_1 ("maxexponent", GFC_ISYM_MAXEXPONENT, CLASS_INQUIRY, ACTUAL_NO, BT_INTEGER,
+ di, GFC_STD_F95, gfc_check_fn_r, gfc_simplify_maxexponent, NULL,
x, BT_UNKNOWN, dr, REQUIRED);
make_generic ("maxexponent", GFC_ISYM_MAXEXPONENT, GFC_STD_F95);
@@ -2525,8 +2525,8 @@ add_functions (void)
make_generic ("min", GFC_ISYM_MIN, GFC_STD_F77);
- add_sym_1 ("minexponent", GFC_ISYM_MINEXPONENT, CLASS_INQUIRY, ACTUAL_NO, BT_INTEGER, di,
- GFC_STD_F95, gfc_check_x, gfc_simplify_minexponent, NULL,
+ add_sym_1 ("minexponent", GFC_ISYM_MINEXPONENT, CLASS_INQUIRY, ACTUAL_NO, BT_INTEGER,
+ di, GFC_STD_F95, gfc_check_fn_r, gfc_simplify_minexponent, NULL,
x, BT_UNKNOWN, dr, REQUIRED);
make_generic ("minexponent", GFC_ISYM_MINEXPONENT, GFC_STD_F95);
@@ -2753,8 +2753,8 @@ add_functions (void)
make_generic ("reshape", GFC_ISYM_RESHAPE, GFC_STD_F95);
- add_sym_1 ("rrspacing", GFC_ISYM_RRSPACING, CLASS_ELEMENTAL, ACTUAL_NO, BT_REAL, dr, GFC_STD_F95,
- gfc_check_x, gfc_simplify_rrspacing, gfc_resolve_rrspacing,
+ add_sym_1 ("rrspacing", GFC_ISYM_RRSPACING, CLASS_ELEMENTAL, ACTUAL_NO, BT_REAL, dr,
+ GFC_STD_F95, gfc_check_fn_r, gfc_simplify_rrspacing, gfc_resolve_rrspacing,
x, BT_REAL, dr, REQUIRED);
make_generic ("rrspacing", GFC_ISYM_RRSPACING, GFC_STD_F95);
@@ -2960,8 +2960,8 @@ add_functions (void)
NULL, gfc_simplify_compiler_version, NULL);
make_from_module();
- add_sym_1 ("spacing", GFC_ISYM_SPACING, CLASS_ELEMENTAL, ACTUAL_NO, BT_REAL, dr, GFC_STD_F95,
- gfc_check_x, gfc_simplify_spacing, gfc_resolve_spacing,
+ add_sym_1 ("spacing", GFC_ISYM_SPACING, CLASS_ELEMENTAL, ACTUAL_NO, BT_REAL, dr,
+ GFC_STD_F95, gfc_check_fn_r, gfc_simplify_spacing, gfc_resolve_spacing,
x, BT_REAL, dr, REQUIRED);
make_generic ("spacing", GFC_ISYM_SPACING, GFC_STD_F95);
@@ -3070,8 +3070,7 @@ add_functions (void)
make_generic ("time8", GFC_ISYM_TIME8, GFC_STD_GNU);
add_sym_1 ("tiny", GFC_ISYM_TINY, CLASS_INQUIRY, ACTUAL_NO, BT_REAL, dr, GFC_STD_F95,
- gfc_check_x, gfc_simplify_tiny, NULL,
- x, BT_REAL, dr, REQUIRED);
+ gfc_check_fn_r, gfc_simplify_tiny, NULL, x, BT_REAL, dr, REQUIRED);
make_generic ("tiny", GFC_ISYM_TINY, GFC_STD_F95);
diff --git a/gcc/fortran/invoke.texi b/gcc/fortran/invoke.texi
index a478aed..8892d50 100644
--- a/gcc/fortran/invoke.texi
+++ b/gcc/fortran/invoke.texi
@@ -119,8 +119,8 @@ by type. Explanations are in the following sections.
@gccoptlist{-fall-intrinsics -fbackslash -fcray-pointer -fd-lines-as-code @gol
-fd-lines-as-comments @gol
-fdec -fdec-structure -fdec-intrinsic-ints -fdec-static -fdec-math @gol
--fdefault-double-8 -fdefault-integer-8 @gol
--fdefault-real-8 -fdollar-ok -ffixed-line-length-@var{n} @gol
+-fdefault-double-8 -fdefault-integer-8 -fdefault-real-8 @gol
+-fdefault-real-10 -fdefault-real-16 -fdollar-ok -ffixed-line-length-@var{n} @gol
-ffixed-line-length-none -ffree-form -ffree-line-length-@var{n} @gol
-ffree-line-length-none -fimplicit-none -finteger-4-integer-8 @gol
-fmax-identifier-length -fmodule-private -ffixed-form -fno-range-check @gol
@@ -145,8 +145,8 @@ by type. Explanations are in the following sections.
@xref{Error and Warning Options,,Options to request or suppress errors
and warnings}.
@gccoptlist{-Waliasing -Wall -Wampersand -Wargument-mismatch -Warray-bounds
--Wc-binding-type -Wcharacter-truncation @gol
--Wconversion -Wfunction-elimination -Wimplicit-interface @gol
+-Wc-binding-type -Wcharacter-truncation -Wconversion @gol
+-Wdo-subscript -Wfunction-elimination -Wimplicit-interface @gol
-Wimplicit-procedure -Wintrinsic-shadow -Wuse-without-only -Wintrinsics-std @gol
-Wline-truncation -Wno-align-commons -Wno-tabs -Wreal-q-constant @gol
-Wsurprising -Wunderflow -Wunused-parameter -Wrealloc-lhs -Wrealloc-lhs-all @gol
@@ -404,6 +404,22 @@ the default width of @code{DOUBLE PRECISION} to 16 bytes if possible, unless
@code{-fdefault-double-8} is given, too. Unlike @option{-freal-4-real-8},
it does not promote variables with explicit kind declaration.
+@item -fdefault-real-10
+@opindex @code{fdefault-real-10}
+Set the default real type to a 10 byte wide type. This option also affects
+the kind of non-double real constants like @code{1.0}, and does promote
+the default width of @code{DOUBLE PRECISION} to 16 bytes if possible, unless
+@code{-fdefault-double-8} is given. Unlike @option{-freal-4-real-10},
+it does not promote variables with explicit kind declaration.
+
+@item -fdefault-real-16
+@opindex @code{fdefault-real-16}
+Set the default real type to a 16 byte wide type. This option also affects
+the kind of non-double real constants like @code{1.0}, and does promote
+the default width of @code{DOUBLE PRECISION} to 16 bytes if possible, unless
+@code{-fdefault-double-8} is given. Unlike @option{-freal-4-real-16},
+it does not promote variables with explicit kind declaration.
+
@item -fdefault-double-8
@opindex @code{fdefault-double-8}
Set the @code{DOUBLE PRECISION} type to an 8 byte wide type. Do nothing if this
@@ -891,8 +907,8 @@ option does @emph{not} imply @option{-Wconversion}.
@cindex extra warnings
@cindex warnings, extra
Enables some warning options for usages of language features which
-may be problematic. This currently includes @option{-Wcompare-reals}
-and @option{-Wunused-parameter}.
+may be problematic. This currently includes @option{-Wcompare-reals},
+@option{-Wunused-parameter} and @option{-Wdo-subscript}.
@item -Wimplicit-interface
@opindex @code{Wimplicit-interface}
@@ -1064,6 +1080,21 @@ target. This option is implied by @option{-Wall}.
Warn if a @code{DO} loop is known to execute zero times at compile
time. This option is implied by @option{-Wall}.
+@item -Wdo-subscript
+@opindex @code{Wdo-subscript}
+Warn if an array subscript inside a DO loop could lead to an
+out-of-bounds access even if the compiler can not prove that the
+statement is actually executed, in cases like
+@smallexample
+ real a(3)
+ do i=1,4
+ if (condition(i)) then
+ a(i) = 1.2
+ end if
+ end do
+@end smallexample
+This option is implied by @option{-Wextra}.
+
@item -Werror
@opindex @code{Werror}
@cindex warnings, to errors
@@ -1089,20 +1120,28 @@ either your program or the GNU Fortran compiler.
@item -fdump-fortran-original
@opindex @code{fdump-fortran-original}
Output the internal parse tree after translating the source program
-into internal representation. Only really useful for debugging the
-GNU Fortran compiler itself.
+into internal representation. This option is mostly useful for
+debugging the GNU Fortran compiler itself. The output generated by
+this option might change between releases. This option may also
+generate internal compiler errors for features which have only
+recently been added.
@item -fdump-fortran-optimized
@opindex @code{fdump-fortran-optimized}
-Output the parse tree after front-end optimization. Only really
-useful for debugging the GNU Fortran compiler itself.
+Output the parse tree after front-end optimization. Mostly useful for
+debugging the GNU Fortran compiler itself. The output generated by
+this option might change between releases. This option may also
+generate internal compiler errors for features which have only
+recently been added.
@item -fdump-parse-tree
@opindex @code{fdump-parse-tree}
Output the internal parse tree after translating the source program
-into internal representation. Only really useful for debugging the
-GNU Fortran compiler itself. This option is deprecated; use
-@code{-fdump-fortran-original} instead.
+into internal representation. Mostly useful for debugging the GNU
+Fortran compiler itself. The output generated by this option might
+change between releases. This option may also generate internal
+compiler errors for features which have only recently been added. This
+option is deprecated; use @code{-fdump-fortran-original} instead.
@item -ffpe-trap=@var{list}
@opindex @code{ffpe-trap=}@var{list}
diff --git a/gcc/fortran/io.c b/gcc/fortran/io.c
index 2c3d761..463c00c 100644
--- a/gcc/fortran/io.c
+++ b/gcc/fortran/io.c
@@ -111,6 +111,9 @@ static gfc_dt *current_dt;
#define RESOLVE_TAG(x, y) if (!resolve_tag (x, y)) return false;
+/* Are we currently processing an asynchronous I/O statement? */
+
+bool async_io_dt;
/**************** Fortran 95 FORMAT parser *****************/
@@ -1944,7 +1947,15 @@ static int
compare_to_allowed_values (const char *specifier, const char *allowed[],
const char *allowed_f2003[],
const char *allowed_gnu[], gfc_char_t *value,
- const char *statement, bool warn)
+ const char *statement, bool warn,
+ int *num = NULL);
+
+
+static int
+compare_to_allowed_values (const char *specifier, const char *allowed[],
+ const char *allowed_f2003[],
+ const char *allowed_gnu[], gfc_char_t *value,
+ const char *statement, bool warn, int *num)
{
int i;
unsigned int len;
@@ -1961,7 +1972,11 @@ compare_to_allowed_values (const char *specifier, const char *allowed[],
for (i = 0; allowed[i]; i++)
if (len == strlen (allowed[i])
&& gfc_wide_strncasecmp (value, allowed[i], strlen (allowed[i])) == 0)
+ {
+ if (num)
+ *num = i;
return 1;
+ }
for (i = 0; allowed_f2003 && allowed_f2003[i]; i++)
if (len == strlen (allowed_f2003[i])
@@ -3611,7 +3626,8 @@ terminate_io (gfc_code *io_code)
/* Check the constraints for a data transfer statement. The majority of the
constraints appearing in 9.4 of the standard appear here. Some are handled
- in resolve_tag and others in gfc_resolve_dt. */
+ in resolve_tag and others in gfc_resolve_dt. Also set the async_io_dt flag
+ and, if necessary, the asynchronous flag on the SIZE argument. */
static match
check_io_constraints (io_kind k, gfc_dt *dt, gfc_code *io_code,
@@ -3719,6 +3735,7 @@ if (condition) \
if (dt->asynchronous)
{
+ int num;
static const char * asynchronous[] = { "YES", "NO", NULL };
if (!gfc_reduce_init_expr (dt->asynchronous))
@@ -3734,9 +3751,16 @@ if (condition) \
if (!compare_to_allowed_values
("ASYNCHRONOUS", asynchronous, NULL, NULL,
dt->asynchronous->value.character.string,
- io_kind_name (k), warn))
+ io_kind_name (k), warn, &num))
return MATCH_ERROR;
+
+ /* Best to put this here because the yes/no info is still around. */
+ async_io_dt = num == 0;
+ if (async_io_dt && dt->size)
+ dt->size->symtree->n.sym->attr.asynchronous = 1;
}
+ else
+ async_io_dt = false;
if (dt->id)
{
@@ -4641,8 +4665,8 @@ match_wait_element (gfc_wait *wait)
m = match_etag (&tag_unit, &wait->unit);
RETM m = match_ltag (&tag_err, &wait->err);
- RETM m = match_ltag (&tag_end, &wait->eor);
- RETM m = match_ltag (&tag_eor, &wait->end);
+ RETM m = match_ltag (&tag_end, &wait->end);
+ RETM m = match_ltag (&tag_eor, &wait->eor);
RETM m = match_etag (&tag_iomsg, &wait->iomsg);
if (m == MATCH_YES && !check_char_variable (wait->iomsg))
return MATCH_ERROR;
diff --git a/gcc/fortran/lang.opt b/gcc/fortran/lang.opt
index 94185da..88f6af5 100644
--- a/gcc/fortran/lang.opt
+++ b/gcc/fortran/lang.opt
@@ -237,6 +237,10 @@ Wconversion-extra
Fortran Var(warn_conversion_extra) Warning
Warn about most implicit conversions.
+Wdo-subscript
+Fortran Var(warn_do_subscript) Warning LangEnabledBy(Fortran,Wextra)
+Warn about possibly incorrect subscripts in do loops.
+
Wextra
Fortran Warning
; Documented in common
@@ -457,9 +461,17 @@ Fortran Var(flag_default_integer)
Set the default integer kind to an 8 byte wide type.
fdefault-real-8
-Fortran Var(flag_default_real)
+Fortran Var(flag_default_real_8)
Set the default real kind to an 8 byte wide type.
+fdefault-real-10
+Fortran Var(flag_default_real_10)
+Set the default real kind to an 10 byte wide type.
+
+fdefault-real-16
+Fortran Var(flag_default_real_16)
+Set the default real kind to an 16 byte wide type.
+
fdollar-ok
Fortran Var(flag_dollar_ok)
Allow dollar signs in entity names.
diff --git a/gcc/fortran/match.c b/gcc/fortran/match.c
index 6e9125f..4d657e0 100644
--- a/gcc/fortran/match.c
+++ b/gcc/fortran/match.c
@@ -1885,8 +1885,15 @@ gfc_match_associate (void)
if (gfc_match (" %n => %e", newAssoc->name, &newAssoc->target)
!= MATCH_YES)
{
- gfc_error ("Expected association at %C");
- goto assocListError;
+ /* Have another go, allowing for procedure pointer selectors. */
+ gfc_matching_procptr_assignment = 1;
+ if (gfc_match (" %n => %e", newAssoc->name, &newAssoc->target)
+ != MATCH_YES)
+ {
+ gfc_error ("Expected association at %C");
+ goto assocListError;
+ }
+ gfc_matching_procptr_assignment = 0;
}
newAssoc->where = gfc_current_locus;
diff --git a/gcc/fortran/misc.c b/gcc/fortran/misc.c
index a2c199e..f47d111 100644
--- a/gcc/fortran/misc.c
+++ b/gcc/fortran/misc.c
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "gfortran.h"
+#include "spellcheck.h"
/* Initialize a typespec to unknown. */
@@ -280,3 +281,43 @@ get_c_kind(const char *c_kind_name, CInteropKind_t kinds_table[])
return ISOCBINDING_INVALID;
}
+
+
+/* For a given name TYPO, determine the best candidate from CANDIDATES
+ perusing Levenshtein distance. Frees CANDIDATES before returning. */
+
+const char *
+gfc_closest_fuzzy_match (const char *typo, char **candidates)
+{
+ /* Determine closest match. */
+ const char *best = NULL;
+ char **cand = candidates;
+ edit_distance_t best_distance = MAX_EDIT_DISTANCE;
+ const size_t tl = strlen (typo);
+
+ while (cand && *cand)
+ {
+ edit_distance_t dist = levenshtein_distance (typo, tl, *cand,
+ strlen (*cand));
+ if (dist < best_distance)
+ {
+ best_distance = dist;
+ best = *cand;
+ }
+ cand++;
+ }
+ /* If more than half of the letters were misspelled, the suggestion is
+ likely to be meaningless. */
+ if (best)
+ {
+ unsigned int cutoff = MAX (tl, strlen (best)) / 2;
+
+ if (best_distance > cutoff)
+ {
+ XDELETEVEC (candidates);
+ return NULL;
+ }
+ XDELETEVEC (candidates);
+ }
+ return best;
+}
diff --git a/gcc/fortran/module.c b/gcc/fortran/module.c
index d71221c..16585a9 100644
--- a/gcc/fortran/module.c
+++ b/gcc/fortran/module.c
@@ -84,7 +84,7 @@ along with GCC; see the file COPYING3. If not see
/* Don't put any single quote (') in MOD_VERSION, if you want it to be
recognized. */
-#define MOD_VERSION "14"
+#define MOD_VERSION "15"
/* Structure that describes a position within a module file. */
@@ -2788,6 +2788,7 @@ mio_component_ref (gfc_component **cp)
static void mio_namespace_ref (gfc_namespace **nsp);
static void mio_formal_arglist (gfc_formal_arglist **formal);
static void mio_typebound_proc (gfc_typebound_proc** proc);
+static void mio_actual_arglist (gfc_actual_arglist **ap, bool pdt);
static void
mio_component (gfc_component *c, int vtype)
@@ -2819,6 +2820,9 @@ mio_component (gfc_component *c, int vtype)
/* PDT templates store the expression for the kind of a component here. */
mio_expr (&c->kind_expr);
+ /* PDT types store the component specification list here. */
+ mio_actual_arglist (&c->param_list, true);
+
mio_symbol_attribute (&c->attr);
if (c->ts.type == BT_CLASS)
c->attr.class_ok = 1;
@@ -2874,17 +2878,19 @@ mio_component_list (gfc_component **cp, int vtype)
static void
-mio_actual_arg (gfc_actual_arglist *a)
+mio_actual_arg (gfc_actual_arglist *a, bool pdt)
{
mio_lparen ();
mio_pool_string (&a->name);
mio_expr (&a->expr);
+ if (pdt)
+ mio_integer ((int *)&a->spec_type);
mio_rparen ();
}
static void
-mio_actual_arglist (gfc_actual_arglist **ap)
+mio_actual_arglist (gfc_actual_arglist **ap, bool pdt)
{
gfc_actual_arglist *a, *tail;
@@ -2893,7 +2899,7 @@ mio_actual_arglist (gfc_actual_arglist **ap)
if (iomode == IO_OUTPUT)
{
for (a = *ap; a; a = a->next)
- mio_actual_arg (a);
+ mio_actual_arg (a, pdt);
}
else
@@ -2913,7 +2919,7 @@ mio_actual_arglist (gfc_actual_arglist **ap)
tail->next = a;
tail = a;
- mio_actual_arg (a);
+ mio_actual_arg (a, pdt);
}
}
@@ -3538,7 +3544,7 @@ mio_expr (gfc_expr **ep)
case EXPR_FUNCTION:
mio_symtree_ref (&e->symtree);
- mio_actual_arglist (&e->value.function.actual);
+ mio_actual_arglist (&e->value.function.actual, false);
if (iomode == IO_OUTPUT)
{
@@ -3660,6 +3666,9 @@ mio_expr (gfc_expr **ep)
break;
}
+ /* PDT types store the expression specification list here. */
+ mio_actual_arglist (&e->param_list, true);
+
mio_rparen ();
}
@@ -4203,7 +4212,7 @@ mio_omp_udr_expr (gfc_omp_udr *udr, gfc_symbol **sym1, gfc_symbol **sym2,
int flag;
mio_name (1, omp_declare_reduction_stmt);
mio_symtree_ref (&ns->code->symtree);
- mio_actual_arglist (&ns->code->ext.actual);
+ mio_actual_arglist (&ns->code->ext.actual, false);
flag = ns->code->resolved_isym != NULL;
mio_integer (&flag);
@@ -4245,7 +4254,7 @@ mio_omp_udr_expr (gfc_omp_udr *udr, gfc_symbol **sym1, gfc_symbol **sym2,
int flag;
ns->code = gfc_get_code (EXEC_CALL);
mio_symtree_ref (&ns->code->symtree);
- mio_actual_arglist (&ns->code->ext.actual);
+ mio_actual_arglist (&ns->code->ext.actual, false);
mio_integer (&flag);
if (flag)
@@ -4315,6 +4324,9 @@ mio_symbol (gfc_symbol *sym)
/* Load/save the f2k_derived namespace of a derived-type symbol. */
mio_full_f2k_derived (sym);
+ /* PDT types store the symbol specification list here. */
+ mio_actual_arglist (&sym->param_list, true);
+
mio_namelist (sym);
/* Add the fields that say whether this is from an intrinsic module,
@@ -6741,7 +6753,7 @@ use_iso_fortran_env_module (void)
"standard", symbol[i].name, &u->where))
continue;
- if ((flag_default_integer || flag_default_real)
+ if ((flag_default_integer || flag_default_real_8)
&& symbol[i].id == ISOFORTRANENV_NUMERIC_STORAGE_SIZE)
gfc_warning_now (0, "Use of the NUMERIC_STORAGE_SIZE named "
"constant from intrinsic module "
@@ -6808,7 +6820,7 @@ use_iso_fortran_env_module (void)
if ((gfc_option.allow_std & symbol[i].standard) == 0)
continue;
- if ((flag_default_integer || flag_default_real)
+ if ((flag_default_integer || flag_default_real_8)
&& symbol[i].id == ISOFORTRANENV_NUMERIC_STORAGE_SIZE)
gfc_warning_now (0,
"Use of the NUMERIC_STORAGE_SIZE named constant "
diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c
index 8400354..2606323 100644
--- a/gcc/fortran/openmp.c
+++ b/gcc/fortran/openmp.c
@@ -2185,8 +2185,7 @@ gfc_match_oacc_wait (void)
}
if (!gfc_resolve_expr (el->expr)
- || el->expr->ts.type != BT_INTEGER || el->expr->rank != 0
- || el->expr->expr_type != EXPR_CONSTANT)
+ || el->expr->ts.type != BT_INTEGER || el->expr->rank != 0)
{
gfc_error ("WAIT clause at %L requires a scalar INTEGER expression",
&el->expr->where);
@@ -5263,7 +5262,7 @@ resolve_omp_atomic (gfc_code *code)
}
-struct fortran_omp_context
+static struct fortran_omp_context
{
gfc_code *code;
hash_set<gfc_symbol *> *sharing_clauses;
@@ -5346,6 +5345,8 @@ gfc_resolve_omp_parallel_blocks (gfc_code *code, gfc_namespace *ns)
case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO:
case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD:
+ case EXEC_OMP_TASKLOOP:
+ case EXEC_OMP_TASKLOOP_SIMD:
case EXEC_OMP_TEAMS_DISTRIBUTE:
case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO:
case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
@@ -5391,8 +5392,11 @@ gfc_omp_restore_state (struct gfc_omp_saved_state *state)
construct, where they are predetermined private. */
void
-gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym)
+gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym, bool add_clause)
{
+ if (omp_current_ctx == NULL)
+ return;
+
int i = omp_current_do_collapse;
gfc_code *c = omp_current_do_code;
@@ -5411,9 +5415,6 @@ gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym)
c = c->block->next;
}
- if (omp_current_ctx == NULL)
- return;
-
/* An openacc context may represent a data clause. Abort if so. */
if (!omp_current_ctx->is_openmp && !oacc_is_loop (omp_current_ctx->code))
return;
@@ -5422,7 +5423,7 @@ gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym)
&& omp_current_ctx->sharing_clauses->contains (sym))
return;
- if (! omp_current_ctx->private_iterators->add (sym))
+ if (! omp_current_ctx->private_iterators->add (sym) && add_clause)
{
gfc_omp_clauses *omp_clauses = omp_current_ctx->code->ext.omp_clauses;
gfc_omp_namelist *p;
@@ -5434,6 +5435,22 @@ gfc_resolve_do_iterator (gfc_code *code, gfc_symbol *sym)
}
}
+static void
+handle_local_var (gfc_symbol *sym)
+{
+ if (sym->attr.flavor != FL_VARIABLE
+ || sym->as != NULL
+ || (sym->ts.type != BT_INTEGER && sym->ts.type != BT_REAL))
+ return;
+ gfc_resolve_do_iterator (sym->ns->code, sym, false);
+}
+
+void
+gfc_resolve_omp_local_vars (gfc_namespace *ns)
+{
+ if (omp_current_ctx)
+ gfc_traverse_ns (ns, handle_local_var);
+}
static void
resolve_omp_do (gfc_code *code)
diff --git a/gcc/fortran/parse.c b/gcc/fortran/parse.c
index e958e6d..eb0f92e 100644
--- a/gcc/fortran/parse.c
+++ b/gcc/fortran/parse.c
@@ -5742,16 +5742,28 @@ gfc_global_used (gfc_gsymbol *sym, locus *where)
name = "MODULE";
break;
default:
- gfc_internal_error ("gfc_global_used(): Bad type");
name = NULL;
}
- if (sym->binding_label)
- gfc_error ("Global binding name %qs at %L is already being used as a %s "
- "at %L", sym->binding_label, where, name, &sym->where);
+ if (name)
+ {
+ if (sym->binding_label)
+ gfc_error ("Global binding name %qs at %L is already being used "
+ "as a %s at %L", sym->binding_label, where, name,
+ &sym->where);
+ else
+ gfc_error ("Global name %qs at %L is already being used as "
+ "a %s at %L", sym->name, where, name, &sym->where);
+ }
else
- gfc_error ("Global name %qs at %L is already being used as a %s at %L",
- sym->name, where, name, &sym->where);
+ {
+ if (sym->binding_label)
+ gfc_error ("Global binding name %qs at %L is already being used "
+ "at %L", sym->binding_label, where, &sym->where);
+ else
+ gfc_error ("Global name %qs at %L is already being used at %L",
+ sym->name, where, &sym->where);
+ }
}
diff --git a/gcc/fortran/primary.c b/gcc/fortran/primary.c
index 21e5be2..8537d93 100644
--- a/gcc/fortran/primary.c
+++ b/gcc/fortran/primary.c
@@ -1937,6 +1937,7 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
gfc_ref *substring, *tail, *tmp;
gfc_component *component;
gfc_symbol *sym = primary->symtree->n.sym;
+ gfc_expr *tgt_expr = NULL;
match m;
bool unknown;
char sep;
@@ -1965,6 +1966,9 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
}
}
+ if (sym->assoc && sym->assoc->target)
+ tgt_expr = sym->assoc->target;
+
/* For associate names, we may not yet know whether they are arrays or not.
If the selector expression is unambiguously an array; eg. a full array
or an array section, then the associate name must be an array and we can
@@ -1976,26 +1980,43 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
&& sym->ts.type != BT_CLASS
&& !sym->attr.dimension)
{
- if ((!sym->assoc->dangling
- && sym->assoc->target
- && sym->assoc->target->ref
- && sym->assoc->target->ref->type == REF_ARRAY
- && (sym->assoc->target->ref->u.ar.type == AR_FULL
- || sym->assoc->target->ref->u.ar.type == AR_SECTION))
- ||
- (!(sym->assoc->dangling || sym->ts.type == BT_CHARACTER)
- && sym->assoc->st
- && sym->assoc->st->n.sym
- && sym->assoc->st->n.sym->attr.dimension == 0))
- {
- sym->attr.dimension = 1;
- if (sym->as == NULL && sym->assoc
+ gfc_ref *ref = NULL;
+
+ if (!sym->assoc->dangling && tgt_expr)
+ {
+ if (tgt_expr->expr_type == EXPR_VARIABLE)
+ gfc_resolve_expr (tgt_expr);
+
+ ref = tgt_expr->ref;
+ for (; ref; ref = ref->next)
+ if (ref->type == REF_ARRAY
+ && (ref->u.ar.type == AR_FULL
+ || ref->u.ar.type == AR_SECTION))
+ break;
+ }
+
+ if (ref || (!(sym->assoc->dangling || sym->ts.type == BT_CHARACTER)
+ && sym->assoc->st
+ && sym->assoc->st->n.sym
+ && sym->assoc->st->n.sym->attr.dimension == 0))
+ {
+ sym->attr.dimension = 1;
+ if (sym->as == NULL
&& sym->assoc->st
&& sym->assoc->st->n.sym
&& sym->assoc->st->n.sym->as)
sym->as = gfc_copy_array_spec (sym->assoc->st->n.sym->as);
}
}
+ else if (sym->ts.type == BT_CLASS
+ && tgt_expr
+ && tgt_expr->expr_type == EXPR_VARIABLE
+ && sym->ts.u.derived != tgt_expr->ts.u.derived)
+ {
+ gfc_resolve_expr (tgt_expr);
+ if (tgt_expr->rank)
+ sym->ts.u.derived = tgt_expr->ts.u.derived;
+ }
if ((equiv_flag && gfc_peek_ascii_char () == '(')
|| gfc_peek_ascii_char () == '[' || sym->attr.codimension
@@ -2055,14 +2076,24 @@ gfc_match_varspec (gfc_expr *primary, int equiv_flag, bool sub_flag,
&& gfc_get_default_type (sym->name, sym->ns)->type == BT_DERIVED)
gfc_set_default_type (sym, 0, sym->ns);
- /* Before throwing an error try resolving the target expression of
- associate names. This should resolve function calls, for example. */
+ /* See if there is a usable typespec in the "no IMPLICIT type" error. */
if (sym->ts.type == BT_UNKNOWN && m == MATCH_YES)
{
- if (sym->assoc && sym->assoc->target)
+ bool permissible;
+
+ /* These target expressions can ge resolved at any time. */
+ permissible = tgt_expr && tgt_expr->symtree && tgt_expr->symtree->n.sym
+ && (tgt_expr->symtree->n.sym->attr.use_assoc
+ || tgt_expr->symtree->n.sym->attr.host_assoc
+ || tgt_expr->symtree->n.sym->attr.if_source
+ == IFSRC_DECL);
+ permissible = permissible
+ || (tgt_expr && tgt_expr->expr_type == EXPR_OP);
+
+ if (permissible)
{
- gfc_resolve_expr (sym->assoc->target);
- sym->ts = sym->assoc->target->ts;
+ gfc_resolve_expr (tgt_expr);
+ sym->ts = tgt_expr->ts;
}
if (sym->ts.type == BT_UNKNOWN)
diff --git a/gcc/fortran/resolve.c b/gcc/fortran/resolve.c
index 89dea5f..5062bcb 100644
--- a/gcc/fortran/resolve.c
+++ b/gcc/fortran/resolve.c
@@ -1161,8 +1161,8 @@ get_pdt_spec_expr (gfc_component *c, gfc_expr *expr)
param_tail->spec_type = SPEC_ASSUMED;
if (c->attr.pdt_kind)
{
- gfc_error ("The KIND parameter in the PDT constructor "
- "at %C has no value");
+ gfc_error ("The KIND parameter %qs in the PDT constructor "
+ "at %C has no value", param->name);
return false;
}
}
@@ -1188,7 +1188,8 @@ get_pdt_constructor (gfc_expr *expr, gfc_constructor **constr,
for (; comp && cons; comp = comp->next, cons = gfc_constructor_next (cons))
{
- if (cons->expr->expr_type == EXPR_STRUCTURE
+ if (cons->expr
+ && cons->expr->expr_type == EXPR_STRUCTURE
&& comp->ts.type == BT_DERIVED)
{
t = get_pdt_constructor (cons->expr, NULL, comp->ts.u.derived);
@@ -2693,6 +2694,8 @@ generic:
if (!gfc_convert_to_structure_constructor (expr, intr->sym, NULL,
NULL, false))
return false;
+ if (!gfc_use_derived (expr->ts.u.derived))
+ return false;
return resolve_structure_cons (expr, 0);
}
@@ -2800,6 +2803,43 @@ resolve_specific_f (gfc_expr *expr)
return true;
}
+/* Recursively append candidate SYM to CANDIDATES. Store the number of
+ candidates in CANDIDATES_LEN. */
+
+static void
+lookup_function_fuzzy_find_candidates (gfc_symtree *sym,
+ char **&candidates,
+ size_t &candidates_len)
+{
+ gfc_symtree *p;
+
+ if (sym == NULL)
+ return;
+ if ((sym->n.sym->ts.type != BT_UNKNOWN || sym->n.sym->attr.external)
+ && sym->n.sym->attr.flavor == FL_PROCEDURE)
+ vec_push (candidates, candidates_len, sym->name);
+
+ p = sym->left;
+ if (p)
+ lookup_function_fuzzy_find_candidates (p, candidates, candidates_len);
+
+ p = sym->right;
+ if (p)
+ lookup_function_fuzzy_find_candidates (p, candidates, candidates_len);
+}
+
+
+/* Lookup function FN fuzzily, taking names in SYMROOT into account. */
+
+const char*
+gfc_lookup_function_fuzzy (const char *fn, gfc_symtree *symroot)
+{
+ char **candidates = NULL;
+ size_t candidates_len = 0;
+ lookup_function_fuzzy_find_candidates (symroot, candidates, candidates_len);
+ return gfc_closest_fuzzy_match (fn, candidates);
+}
+
/* Resolve a procedure call not known to be generic nor specific. */
@@ -2850,8 +2890,15 @@ set_type:
if (ts->type == BT_UNKNOWN)
{
- gfc_error ("Function %qs at %L has no IMPLICIT type",
- sym->name, &expr->where);
+ const char *guessed
+ = gfc_lookup_function_fuzzy (sym->name, sym->ns->sym_root);
+ if (guessed)
+ gfc_error ("Function %qs at %L has no IMPLICIT type"
+ "; did you mean %qs?",
+ sym->name, &expr->where, guessed);
+ else
+ gfc_error ("Function %qs at %L has no IMPLICIT type",
+ sym->name, &expr->where);
return false;
}
else
@@ -3712,6 +3759,46 @@ logical_to_bitwise (gfc_expr *e)
return e;
}
+/* Recursively append candidate UOP to CANDIDATES. Store the number of
+ candidates in CANDIDATES_LEN. */
+static void
+lookup_uop_fuzzy_find_candidates (gfc_symtree *uop,
+ char **&candidates,
+ size_t &candidates_len)
+{
+ gfc_symtree *p;
+
+ if (uop == NULL)
+ return;
+
+ /* Not sure how to properly filter here. Use all for a start.
+ n.uop.op is NULL for empty interface operators (is that legal?) disregard
+ these as i suppose they don't make terribly sense. */
+
+ if (uop->n.uop->op != NULL)
+ vec_push (candidates, candidates_len, uop->name);
+
+ p = uop->left;
+ if (p)
+ lookup_uop_fuzzy_find_candidates (p, candidates, candidates_len);
+
+ p = uop->right;
+ if (p)
+ lookup_uop_fuzzy_find_candidates (p, candidates, candidates_len);
+}
+
+/* Lookup user-operator OP fuzzily, taking names in UOP into account. */
+
+static const char*
+lookup_uop_fuzzy (const char *op, gfc_symtree *uop)
+{
+ char **candidates = NULL;
+ size_t candidates_len = 0;
+ lookup_uop_fuzzy_find_candidates (uop, candidates, candidates_len);
+ return gfc_closest_fuzzy_match (op, candidates);
+}
+
+
/* Resolve an operator expression node. This can involve replacing the
operation with a user defined function call. */
@@ -3934,8 +4021,16 @@ resolve_operator (gfc_expr *e)
case INTRINSIC_USER:
if (e->value.op.uop->op == NULL)
- sprintf (msg, _("Unknown operator %%<%s%%> at %%L"),
- e->value.op.uop->name);
+ {
+ const char *name = e->value.op.uop->name;
+ const char *guessed;
+ guessed = lookup_uop_fuzzy (name, e->value.op.uop->ns->uop_root);
+ if (guessed)
+ sprintf (msg, _("Unknown operator %%<%s%%> at %%L; did you mean '%s'?"),
+ name, guessed);
+ else
+ sprintf (msg, _("Unknown operator %%<%s%%> at %%L"), name);
+ }
else if (op2 == NULL)
sprintf (msg, _("Operand of user operator %%<%s%%> at %%L is %s"),
e->value.op.uop->name, gfc_typename (&op1->ts));
@@ -8396,11 +8491,23 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
sym->attr.subref_array_pointer = 1;
}
+ if (target->expr_type == EXPR_NULL)
+ {
+ gfc_error ("Selector at %L cannot be NULL()", &target->where);
+ return;
+ }
+ else if (target->ts.type == BT_UNKNOWN)
+ {
+ gfc_error ("Selector at %L has no type", &target->where);
+ return;
+ }
+
/* Get type if this was not already set. Note that it can be
some other type than the target in case this is a SELECT TYPE
selector! So we must not update when the type is already there. */
if (sym->ts.type == BT_UNKNOWN)
sym->ts = target->ts;
+
gcc_assert (sym->ts.type != BT_UNKNOWN);
/* See if this is a valid association-to-variable. */
@@ -8518,7 +8625,7 @@ resolve_assoc_var (gfc_symbol* sym, bool resolve_target)
if (!sym->ts.u.cl)
sym->ts.u.cl = target->ts.u.cl;
- if (!sym->ts.u.cl->length)
+ if (!sym->ts.u.cl->length && !sym->ts.deferred)
sym->ts.u.cl->length
= gfc_get_int_expr (gfc_default_integer_kind,
NULL, target->value.character.length);
@@ -9184,6 +9291,9 @@ resolve_transfer (gfc_code *code)
"an assumed-size array", &code->loc);
return;
}
+
+ if (async_io_dt && exp->expr_type == EXPR_VARIABLE)
+ exp->symtree->n.sym->attr.asynchronous = 1;
}
@@ -10900,6 +11010,8 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns)
case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD:
case EXEC_OMP_TASK:
+ case EXEC_OMP_TASKLOOP:
+ case EXEC_OMP_TASKLOOP_SIMD:
case EXEC_OMP_TEAMS:
case EXEC_OMP_TEAMS_DISTRIBUTE:
case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO:
@@ -10915,8 +11027,6 @@ gfc_resolve_code (gfc_code *code, gfc_namespace *ns)
case EXEC_OMP_DO_SIMD:
case EXEC_OMP_SIMD:
case EXEC_OMP_TARGET_SIMD:
- case EXEC_OMP_TASKLOOP:
- case EXEC_OMP_TASKLOOP_SIMD:
gfc_resolve_omp_do_blocks (code, ns);
break;
case EXEC_SELECT_TYPE:
@@ -11107,11 +11217,8 @@ start:
/* Assigning a class object always is a regular assign. */
if (code->expr2->ts.type == BT_CLASS
+ && code->expr1->ts.type == BT_CLASS
&& !CLASS_DATA (code->expr2)->attr.dimension
- && !(UNLIMITED_POLY (code->expr2)
- && code->expr1->ts.type == BT_DERIVED
- && (code->expr1->ts.u.derived->attr.sequence
- || code->expr1->ts.u.derived->attr.is_bind_c))
&& !(gfc_expr_attr (code->expr1).proc_pointer
&& code->expr2->expr_type == EXPR_VARIABLE
&& code->expr2->symtree->n.sym->attr.flavor
@@ -11180,7 +11287,8 @@ start:
{
gfc_iterator *iter = code->ext.iterator;
if (gfc_resolve_iterator (iter, true, false))
- gfc_resolve_do_iterator (code, iter->var->symtree->n.sym);
+ gfc_resolve_do_iterator (code, iter->var->symtree->n.sym,
+ true);
}
break;
@@ -11926,6 +12034,7 @@ deferred_requirements (gfc_symbol *sym)
if (sym->ts.deferred
&& !(sym->attr.pointer
|| sym->attr.allocatable
+ || sym->attr.associate_var
|| sym->attr.omp_udr_artificial_var))
{
gfc_error ("Entity %qs at %L has a deferred type parameter and "
@@ -13830,6 +13939,7 @@ resolve_fl_derived0 (gfc_symbol *sym)
{
gfc_symbol* super_type;
gfc_component *c;
+ gfc_formal_arglist *f;
bool success;
if (sym->attr.unlimited_polymorphic)
@@ -13882,6 +13992,22 @@ resolve_fl_derived0 (gfc_symbol *sym)
&& !ensure_not_abstract (sym, super_type))
return false;
+ /* Check that there is a component for every PDT parameter. */
+ if (sym->attr.pdt_template)
+ {
+ for (f = sym->formal; f; f = f->next)
+ {
+ c = gfc_find_component (sym, f->sym->name, true, true, NULL);
+ if (c == NULL)
+ {
+ gfc_error ("Parameterized type %qs does not have a component "
+ "corresponding to parameter %qs at %L", sym->name,
+ f->sym->name, &sym->declared_at);
+ break;
+ }
+ }
+ }
+
/* Add derived type to the derived type list. */
add_dt_to_dt_list (sym);
@@ -14069,6 +14195,11 @@ resolve_fl_namelist (gfc_symbol *sym)
}
}
+ if (async_io_dt)
+ {
+ for (nl = sym->namelist; nl; nl = nl->next)
+ nl->sym->attr.asynchronous = 1;
+ }
return true;
}
@@ -14384,7 +14515,23 @@ resolve_symbol (gfc_symbol *sym)
if (as)
{
- gcc_assert (as->type != AS_IMPLIED_SHAPE);
+ /* If AS_IMPLIED_SHAPE makes it to here, it must be a bad
+ specification expression. */
+ if (as->type == AS_IMPLIED_SHAPE)
+ {
+ int i;
+ for (i=0; i<as->rank; i++)
+ {
+ if (as->lower[i] != NULL && as->upper[i] == NULL)
+ {
+ gfc_error ("Bad specification for assumed size array at %L",
+ &as->lower[i]->where);
+ return;
+ }
+ }
+ gcc_unreachable();
+ }
+
if (((as->type == AS_ASSUMED_SIZE && !as->cp_was_assumed)
|| as->type == AS_ASSUMED_SHAPE)
&& !sym->attr.dummy && !sym->attr.select_type_temporary)
@@ -14763,6 +14910,7 @@ resolve_symbol (gfc_symbol *sym)
if (class_attr.codimension
&& !(class_attr.allocatable || sym->attr.dummy || sym->attr.save
|| sym->attr.select_type_temporary
+ || sym->attr.associate_var
|| (sym->ns->save_all && !sym->attr.automatic)
|| sym->ns->proc_name->attr.flavor == FL_MODULE
|| sym->ns->proc_name->attr.is_main_program
@@ -14947,7 +15095,12 @@ resolve_symbol (gfc_symbol *sym)
if ((!a->save && !a->dummy && !a->pointer
&& !a->in_common && !a->use_assoc
- && !a->result && !a->function)
+ && a->referenced
+ && !((a->function || a->result)
+ && (!a->dimension
+ || sym->ts.u.derived->attr.alloc_comp
+ || sym->ts.u.derived->attr.pointer_comp))
+ && !(a->function && sym != sym->result))
|| (a->dummy && a->intent == INTENT_OUT && !a->pointer))
apply_default_init (sym);
else if (a->function && sym->result && a->access != ACCESS_PRIVATE
@@ -16219,6 +16372,7 @@ resolve_codes (gfc_namespace *ns)
bitmap_obstack_initialize (&labels_obstack);
gfc_resolve_oacc_declare (ns);
+ gfc_resolve_omp_local_vars (ns);
gfc_resolve_code (ns->code, ns);
bitmap_obstack_release (&labels_obstack);
diff --git a/gcc/fortran/scanner.c b/gcc/fortran/scanner.c
index 82f431d..49decfa 100644
--- a/gcc/fortran/scanner.c
+++ b/gcc/fortran/scanner.c
@@ -80,6 +80,7 @@ static struct gfc_file_change
size_t file_changes_cur, file_changes_count;
size_t file_changes_allocated;
+static gfc_char_t *last_error_char;
/* Functions dealing with our wide characters (gfc_char_t) and
sequences of such characters. */
@@ -269,6 +270,7 @@ gfc_scanner_init_1 (void)
continue_line = 0;
end_flag = 0;
+ last_error_char = NULL;
}
@@ -1700,6 +1702,14 @@ gfc_gobble_whitespace (void)
}
while (gfc_is_whitespace (c));
+ if (!ISPRINT(c) && c != '\n' && last_error_char != gfc_current_locus.nextc)
+ {
+ char buf[20];
+ last_error_char = gfc_current_locus.nextc;
+ snprintf (buf, 20, "%2.2X", c);
+ gfc_error_now ("Invalid character 0x%s at %C", buf);
+ }
+
gfc_current_locus = old_loc;
}
diff --git a/gcc/fortran/symbol.c b/gcc/fortran/symbol.c
index 68a76c4..11b6f60 100644
--- a/gcc/fortran/symbol.c
+++ b/gcc/fortran/symbol.c
@@ -245,6 +245,44 @@ gfc_get_default_type (const char *name, gfc_namespace *ns)
}
+/* Recursively append candidate SYM to CANDIDATES. Store the number of
+ candidates in CANDIDATES_LEN. */
+
+static void
+lookup_symbol_fuzzy_find_candidates (gfc_symtree *sym,
+ char **&candidates,
+ size_t &candidates_len)
+{
+ gfc_symtree *p;
+
+ if (sym == NULL)
+ return;
+
+ if (sym->n.sym->ts.type != BT_UNKNOWN && sym->n.sym->ts.type != BT_PROCEDURE)
+ vec_push (candidates, candidates_len, sym->name);
+ p = sym->left;
+ if (p)
+ lookup_symbol_fuzzy_find_candidates (p, candidates, candidates_len);
+
+ p = sym->right;
+ if (p)
+ lookup_symbol_fuzzy_find_candidates (p, candidates, candidates_len);
+}
+
+
+/* Lookup symbol SYM_NAME fuzzily, taking names in SYMBOL into account. */
+
+static const char*
+lookup_symbol_fuzzy (const char *sym_name, gfc_symbol *symbol)
+{
+ char **candidates = NULL;
+ size_t candidates_len = 0;
+ lookup_symbol_fuzzy_find_candidates (symbol->ns->sym_root, candidates,
+ candidates_len);
+ return gfc_closest_fuzzy_match (sym_name, candidates);
+}
+
+
/* Given a pointer to a symbol, set its type according to the first
letter of its name. Fails if the letter in question has no default
type. */
@@ -263,8 +301,14 @@ gfc_set_default_type (gfc_symbol *sym, int error_flag, gfc_namespace *ns)
{
if (error_flag && !sym->attr.untyped)
{
- gfc_error ("Symbol %qs at %L has no IMPLICIT type",
- sym->name, &sym->declared_at);
+ const char *guessed = lookup_symbol_fuzzy (sym->name, sym);
+ if (guessed)
+ gfc_error ("Symbol %qs at %L has no IMPLICIT type"
+ "; did you mean %qs?",
+ sym->name, &sym->declared_at, guessed);
+ else
+ gfc_error ("Symbol %qs at %L has no IMPLICIT type",
+ sym->name, &sym->declared_at);
sym->attr.untyped = 1; /* Ensure we only give an error once. */
}
@@ -382,7 +426,8 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
*is_bind_c = "BIND(C)", *procedure = "PROCEDURE",
*proc_pointer = "PROCEDURE POINTER", *abstract = "ABSTRACT",
*asynchronous = "ASYNCHRONOUS", *codimension = "CODIMENSION",
- *contiguous = "CONTIGUOUS", *generic = "GENERIC", *automatic = "AUTOMATIC";
+ *contiguous = "CONTIGUOUS", *generic = "GENERIC", *automatic = "AUTOMATIC",
+ *pdt_len = "LEN", *pdt_kind = "KIND";
static const char *threadprivate = "THREADPRIVATE";
static const char *omp_declare_target = "OMP DECLARE TARGET";
static const char *omp_declare_target_link = "OMP DECLARE TARGET LINK";
@@ -663,6 +708,23 @@ check_conflict (symbol_attribute *attr, const char *name, locus *where)
conf (entry, oacc_declare_deviceptr)
conf (entry, oacc_declare_device_resident)
+ conf (pdt_kind, allocatable)
+ conf (pdt_kind, pointer)
+ conf (pdt_kind, dimension)
+ conf (pdt_kind, codimension)
+
+ conf (pdt_len, allocatable)
+ conf (pdt_len, pointer)
+ conf (pdt_len, dimension)
+ conf (pdt_len, codimension)
+
+ if (attr->access == ACCESS_PRIVATE)
+ {
+ a1 = privat;
+ conf2 (pdt_kind);
+ conf2 (pdt_len);
+ }
+
a1 = gfc_code2string (flavors, attr->flavor);
if (attr->in_namelist
@@ -2336,6 +2398,32 @@ find_union_component (gfc_symbol *un, const char *name,
}
+/* Recursively append candidate COMPONENT structures to CANDIDATES. Store
+ the number of total candidates in CANDIDATES_LEN. */
+
+static void
+lookup_component_fuzzy_find_candidates (gfc_component *component,
+ char **&candidates,
+ size_t &candidates_len)
+{
+ for (gfc_component *p = component; p; p = p->next)
+ vec_push (candidates, candidates_len, p->name);
+}
+
+
+/* Lookup component MEMBER fuzzily, taking names in COMPONENT into account. */
+
+static const char*
+lookup_component_fuzzy (const char *member, gfc_component *component)
+{
+ char **candidates = NULL;
+ size_t candidates_len = 0;
+ lookup_component_fuzzy_find_candidates (component, candidates,
+ candidates_len);
+ return gfc_closest_fuzzy_match (member, candidates);
+}
+
+
/* Given a derived type node and a component name, try to locate the
component structure. Returns the NULL pointer if the component is
not found or the components are private. If noaccess is set, no access
@@ -2433,8 +2521,16 @@ gfc_find_component (gfc_symbol *sym, const char *name,
}
if (p == NULL && !silent)
- gfc_error ("%qs at %C is not a member of the %qs structure",
- name, sym->name);
+ {
+ const char *guessed = lookup_component_fuzzy (name, sym->components);
+ if (guessed)
+ gfc_error ("%qs at %C is not a member of the %qs structure"
+ "; did you mean %qs?",
+ name, sym->name, guessed);
+ else
+ gfc_error ("%qs at %C is not a member of the %qs structure",
+ name, sym->name);
+ }
/* Component was found; build the ultimate component reference. */
if (p != NULL && ref)
@@ -5054,6 +5150,12 @@ gfc_is_associate_pointer (gfc_symbol* sym)
if (sym->ts.type == BT_CLASS)
return true;
+ if (sym->ts.type == BT_CHARACTER
+ && sym->ts.deferred
+ && sym->assoc->target
+ && sym->assoc->target->expr_type == EXPR_FUNCTION)
+ return true;
+
if (!sym->assoc->variable)
return false;
diff --git a/gcc/fortran/target-memory.c b/gcc/fortran/target-memory.c
index ceca3ac..b2fe8ee 100644
--- a/gcc/fortran/target-memory.c
+++ b/gcc/fortran/target-memory.c
@@ -429,7 +429,7 @@ gfc_interpret_logical (int kind, unsigned char *buffer, size_t buffer_size,
{
tree t = native_interpret_expr (gfc_get_logical_type (kind), buffer,
buffer_size);
- *logical = wi::eq_p (t, 0) ? 0 : 1;
+ *logical = wi::to_wide (t) == 0 ? 0 : 1;
return size_logical (kind);
}
diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index 328da4e..a357389 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -8400,6 +8400,19 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
return tmp;
}
+ if (purpose == DEALLOCATE_ALLOC_COMP && der_type->attr.pdt_type)
+ {
+ tmp = structure_alloc_comps (der_type, decl, NULL_TREE, rank,
+ DEALLOCATE_PDT_COMP, 0);
+ gfc_add_expr_to_block (&fnblock, tmp);
+ }
+ else if (purpose == ALLOCATE_PDT_COMP && der_type->attr.alloc_comp)
+ {
+ tmp = structure_alloc_comps (der_type, decl, NULL_TREE, rank,
+ NULLIFY_ALLOC_COMP, 0);
+ gfc_add_expr_to_block (&fnblock, tmp);
+ }
+
/* Otherwise, act on the components or recursively call self to
act on a chain of components. */
for (c = der_type->components; c; c = c->next)
@@ -9072,7 +9085,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
/* Recurse in to PDT components. */
if ((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
- && c->ts.u.derived && c->ts.u.derived->attr.pdt_type)
+ && c->ts.u.derived && c->ts.u.derived->attr.pdt_type
+ && !(c->attr.pointer || c->attr.allocatable))
{
bool is_deferred = false;
gfc_actual_arglist *tail = c->param_list;
@@ -9106,7 +9120,8 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
/* Recurse in to PDT components. */
if ((c->ts.type == BT_DERIVED || c->ts.type == BT_CLASS)
- && c->ts.u.derived && c->ts.u.derived->attr.pdt_type)
+ && c->ts.u.derived && c->ts.u.derived->attr.pdt_type
+ && (!c->attr.pointer && !c->attr.allocatable))
{
tmp = gfc_deallocate_pdt_comp (c->ts.u.derived, comp,
c->as ? c->as->rank : 0);
@@ -9116,13 +9131,23 @@ structure_alloc_comps (gfc_symbol * der_type, tree decl,
if (c->attr.pdt_array)
{
tmp = gfc_conv_descriptor_data_get (comp);
+ null_cond = fold_build2_loc (input_location, NE_EXPR,
+ boolean_type_node, tmp,
+ build_int_cst (TREE_TYPE (tmp), 0));
tmp = gfc_call_free (tmp);
+ tmp = build3_v (COND_EXPR, null_cond, tmp,
+ build_empty_stmt (input_location));
gfc_add_expr_to_block (&fnblock, tmp);
gfc_conv_descriptor_data_set (&fnblock, comp, null_pointer_node);
}
else if (c->attr.pdt_string)
{
+ null_cond = fold_build2_loc (input_location, NE_EXPR,
+ boolean_type_node, comp,
+ build_int_cst (TREE_TYPE (comp), 0));
tmp = gfc_call_free (comp);
+ tmp = build3_v (COND_EXPR, null_cond, tmp,
+ build_empty_stmt (input_location));
gfc_add_expr_to_block (&fnblock, tmp);
tmp = fold_convert (TREE_TYPE (comp), null_pointer_node);
gfc_add_modify (&fnblock, comp, tmp);
diff --git a/gcc/fortran/trans-const.c b/gcc/fortran/trans-const.c
index 128d47d..62b85f7 100644
--- a/gcc/fortran/trans-const.c
+++ b/gcc/fortran/trans-const.c
@@ -211,7 +211,7 @@ gfc_conv_mpz_to_tree (mpz_t i, int kind)
void
gfc_conv_tree_to_mpz (mpz_t i, tree source)
{
- wi::to_mpz (source, i, TYPE_SIGN (TREE_TYPE (source)));
+ wi::to_mpz (wi::to_wide (source), i, TYPE_SIGN (TREE_TYPE (source)));
}
/* Converts a real constant into backend form. */
diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c
index d227d51..c21611c 100644
--- a/gcc/fortran/trans-decl.c
+++ b/gcc/fortran/trans-decl.c
@@ -1670,7 +1670,9 @@ gfc_get_symbol_decl (gfc_symbol * sym)
{
/* Catch functions. Only used for actual parameters,
procedure pointers and procptr initialization targets. */
- if (sym->attr.use_assoc || sym->attr.intrinsic
+ if (sym->attr.use_assoc
+ || sym->attr.used_in_submodule
+ || sym->attr.intrinsic
|| sym->attr.if_source != IFSRC_DECL)
{
decl = gfc_get_extern_function_decl (sym);
@@ -1695,6 +1697,14 @@ gfc_get_symbol_decl (gfc_symbol * sym)
if (sym->ts.type == BT_CHARACTER)
{
if (sym->attr.associate_var
+ && sym->ts.deferred
+ && sym->assoc && sym->assoc->target
+ && ((sym->assoc->target->expr_type == EXPR_VARIABLE
+ && sym->assoc->target->symtree->n.sym->ts.type != BT_CHARACTER)
+ || sym->assoc->target->expr_type == EXPR_FUNCTION))
+ sym->ts.u.cl->backend_decl = NULL_TREE;
+
+ if (sym->attr.associate_var
&& sym->ts.u.cl->backend_decl
&& VAR_P (sym->ts.u.cl->backend_decl))
length = gfc_index_zero_node;
@@ -4626,6 +4636,10 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block)
}
gfc_add_init_cleanup (block, gfc_finish_block (&init), tmp);
+ /* TODO find out why this is necessary to stop double calls to
+ free. Somebody is reusing the expression in 'tmp' because
+ it is being used unititialized. */
+ tmp = NULL_TREE;
}
}
else if (sym->ts.type == BT_CHARACTER && sym->ts.deferred)
diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c
index 8c8569f..4e8bfc5 100644
--- a/gcc/fortran/trans-expr.c
+++ b/gcc/fortran/trans-expr.c
@@ -2861,7 +2861,7 @@ gfc_conv_cst_int_power (gfc_se * se, tree lhs, tree rhs)
HOST_WIDE_INT m;
unsigned HOST_WIDE_INT n;
int sgn;
- wide_int wrhs = rhs;
+ wi::tree_to_wide_ref wrhs = wi::to_wide (rhs);
/* If exponent is too large, we won't expand it anyway, so don't bother
with large integer values. */
@@ -8207,6 +8207,39 @@ pointer_assignment_is_proc_pointer (gfc_expr * expr1, gfc_expr * expr2)
}
+/* Do everything that is needed for a CLASS function expr2. */
+
+static tree
+trans_class_pointer_fcn (stmtblock_t *block, gfc_se *lse, gfc_se *rse,
+ gfc_expr *expr1, gfc_expr *expr2)
+{
+ tree expr1_vptr = NULL_TREE;
+ tree tmp;
+
+ gfc_conv_function_expr (rse, expr2);
+ rse->expr = gfc_evaluate_now (rse->expr, &rse->pre);
+
+ if (expr1->ts.type != BT_CLASS)
+ rse->expr = gfc_class_data_get (rse->expr);
+ else
+ {
+ expr1_vptr = trans_class_vptr_len_assignment (block, expr1,
+ expr2, rse,
+ NULL, NULL);
+ gfc_add_block_to_block (block, &rse->pre);
+ tmp = gfc_create_var (TREE_TYPE (rse->expr), "ptrtemp");
+ gfc_add_modify (&lse->pre, tmp, rse->expr);
+
+ gfc_add_modify (&lse->pre, expr1_vptr,
+ fold_convert (TREE_TYPE (expr1_vptr),
+ gfc_class_vptr_get (tmp)));
+ rse->expr = gfc_class_data_get (tmp);
+ }
+
+ return expr1_vptr;
+}
+
+
tree
gfc_trans_pointer_assign (gfc_code * code)
{
@@ -8224,6 +8257,7 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
stmtblock_t block;
tree desc;
tree tmp;
+ tree expr1_vptr = NULL_TREE;
bool scalar, non_proc_pointer_assign;
gfc_ss *ss;
@@ -8257,7 +8291,10 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
gfc_conv_expr (&lse, expr1);
gfc_init_se (&rse, NULL);
rse.want_pointer = 1;
- gfc_conv_expr (&rse, expr2);
+ if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS)
+ trans_class_pointer_fcn (&block, &lse, &rse, expr1, expr2);
+ else
+ gfc_conv_expr (&rse, expr2);
if (non_proc_pointer_assign && expr1->ts.type == BT_CLASS)
{
@@ -8269,12 +8306,12 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
if (expr1->symtree->n.sym->attr.proc_pointer
&& expr1->symtree->n.sym->attr.dummy)
lse.expr = build_fold_indirect_ref_loc (input_location,
- lse.expr);
+ lse.expr);
if (expr2->symtree && expr2->symtree->n.sym->attr.proc_pointer
&& expr2->symtree->n.sym->attr.dummy)
rse.expr = build_fold_indirect_ref_loc (input_location,
- rse.expr);
+ rse.expr);
gfc_add_block_to_block (&block, &lse.pre);
gfc_add_block_to_block (&block, &rse.pre);
@@ -8320,7 +8357,6 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
{
gfc_ref* remap;
bool rank_remap;
- tree expr1_vptr = NULL_TREE;
tree strlen_lhs;
tree strlen_rhs = NULL_TREE;
@@ -8355,26 +8391,8 @@ gfc_trans_pointer_assignment (gfc_expr * expr1, gfc_expr * expr2)
rse.byref_noassign = 1;
if (expr2->expr_type == EXPR_FUNCTION && expr2->ts.type == BT_CLASS)
- {
- gfc_conv_function_expr (&rse, expr2);
-
- if (expr1->ts.type != BT_CLASS)
- rse.expr = gfc_class_data_get (rse.expr);
- else
- {
- expr1_vptr = trans_class_vptr_len_assignment (&block, expr1,
- expr2, &rse,
- NULL, NULL);
- gfc_add_block_to_block (&block, &rse.pre);
- tmp = gfc_create_var (TREE_TYPE (rse.expr), "ptrtemp");
- gfc_add_modify (&lse.pre, tmp, rse.expr);
-
- gfc_add_modify (&lse.pre, expr1_vptr,
- fold_convert (TREE_TYPE (expr1_vptr),
- gfc_class_vptr_get (tmp)));
- rse.expr = gfc_class_data_get (tmp);
- }
- }
+ expr1_vptr = trans_class_pointer_fcn (&block, &lse, &rse,
+ expr1, expr2);
else if (expr2->expr_type == EXPR_FUNCTION)
{
tree bound[GFC_MAX_DIMENSIONS];
diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c
index 9bc465e..532d3ab 100644
--- a/gcc/fortran/trans-intrinsic.c
+++ b/gcc/fortran/trans-intrinsic.c
@@ -2235,8 +2235,9 @@ trans_this_image (gfc_se * se, gfc_expr *expr)
if (INTEGER_CST_P (dim_arg))
{
- if (wi::ltu_p (dim_arg, 1)
- || wi::gtu_p (dim_arg, GFC_TYPE_ARRAY_CORANK (TREE_TYPE (desc))))
+ if (wi::ltu_p (wi::to_wide (dim_arg), 1)
+ || wi::gtu_p (wi::to_wide (dim_arg),
+ GFC_TYPE_ARRAY_CORANK (TREE_TYPE (desc))))
gfc_error ("%<dim%> argument of %s intrinsic at %L is not a valid "
"dimension index", expr->value.function.isym->name,
&expr->where);
@@ -2657,8 +2658,9 @@ gfc_conv_intrinsic_bound (gfc_se * se, gfc_expr * expr, int upper)
if (INTEGER_CST_P (bound))
{
if (((!as || as->type != AS_ASSUMED_RANK)
- && wi::geu_p (bound, GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc))))
- || wi::gtu_p (bound, GFC_MAX_DIMENSIONS))
+ && wi::geu_p (wi::to_wide (bound),
+ GFC_TYPE_ARRAY_RANK (TREE_TYPE (desc))))
+ || wi::gtu_p (wi::to_wide (bound), GFC_MAX_DIMENSIONS))
gfc_error ("%<dim%> argument of %s intrinsic at %L is not a valid "
"dimension index", upper ? "UBOUND" : "LBOUND",
&expr->where);
@@ -2853,8 +2855,9 @@ conv_intrinsic_cobound (gfc_se * se, gfc_expr * expr)
if (INTEGER_CST_P (bound))
{
- if (wi::ltu_p (bound, 1)
- || wi::gtu_p (bound, GFC_TYPE_ARRAY_CORANK (TREE_TYPE (desc))))
+ if (wi::ltu_p (wi::to_wide (bound), 1)
+ || wi::gtu_p (wi::to_wide (bound),
+ GFC_TYPE_ARRAY_CORANK (TREE_TYPE (desc))))
gfc_error ("%<dim%> argument of %s intrinsic at %L is not a valid "
"dimension index", expr->value.function.isym->name,
&expr->where);
diff --git a/gcc/fortran/trans-io.c b/gcc/fortran/trans-io.c
index 026f9a9..f3e1f3e 100644
--- a/gcc/fortran/trans-io.c
+++ b/gcc/fortran/trans-io.c
@@ -2404,7 +2404,7 @@ transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr,
case BT_CLASS:
if (ts->u.derived->components == NULL)
return;
- if (ts->type == BT_DERIVED || ts->type == BT_CLASS)
+ if (gfc_bt_struct (ts->type) || ts->type == BT_CLASS)
{
gfc_symbol *derived;
gfc_symbol *dtio_sub = NULL;
@@ -2438,7 +2438,7 @@ transfer_expr (gfc_se * se, gfc_typespec * ts, tree addr_expr,
function = iocall[IOCALL_X_DERIVED];
break;
}
- else if (ts->type == BT_DERIVED)
+ else if (gfc_bt_struct (ts->type))
{
/* Recurse into the elements of the derived type. */
expr = gfc_evaluate_now (addr_expr, &se->pre);
diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c
index 925ea63..7a76b8e 100644
--- a/gcc/fortran/trans-stmt.c
+++ b/gcc/fortran/trans-stmt.c
@@ -1533,6 +1533,7 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
bool need_len_assign;
bool whole_array = true;
gfc_ref *ref;
+ symbol_attribute attr;
gcc_assert (sym->assoc);
e = sym->assoc->target;
@@ -1592,6 +1593,17 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
gfc_conv_expr_descriptor (&se, e);
+ if (sym->ts.type == BT_CHARACTER
+ && sym->ts.deferred
+ && !sym->attr.select_type_temporary
+ && VAR_P (sym->ts.u.cl->backend_decl)
+ && se.string_length != sym->ts.u.cl->backend_decl)
+ {
+ gfc_add_modify (&se.pre, sym->ts.u.cl->backend_decl,
+ fold_convert (gfc_charlen_type_node,
+ se.string_length));
+ }
+
/* If we didn't already do the pointer assignment, set associate-name
descriptor to the one generated for the temporary. */
if ((!sym->assoc->variable && !cst_array_ctor)
@@ -1758,8 +1770,35 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
need_len_assign = need_len_assign && sym->ts.type == BT_CHARACTER;
}
- tmp = TREE_TYPE (sym->backend_decl);
- tmp = gfc_build_addr_expr (tmp, se.expr);
+ if (sym->ts.type == BT_CHARACTER
+ && sym->ts.deferred
+ && !sym->attr.select_type_temporary
+ && VAR_P (sym->ts.u.cl->backend_decl)
+ && se.string_length != sym->ts.u.cl->backend_decl)
+ {
+ gfc_add_modify (&se.pre, sym->ts.u.cl->backend_decl,
+ fold_convert (gfc_charlen_type_node,
+ se.string_length));
+ if (e->expr_type == EXPR_FUNCTION)
+ {
+ tmp = gfc_call_free (sym->backend_decl);
+ gfc_add_expr_to_block (&se.post, tmp);
+ }
+ }
+
+ attr = gfc_expr_attr (e);
+ if (sym->ts.type == BT_CHARACTER && e->ts.type == BT_CHARACTER
+ && (attr.allocatable || attr.pointer || attr.dummy))
+ {
+ /* These are pointer types already. */
+ tmp = fold_convert (TREE_TYPE (sym->backend_decl), se.expr);
+ }
+ else
+ {
+ tmp = TREE_TYPE (sym->backend_decl);
+ tmp = gfc_build_addr_expr (tmp, se.expr);
+ }
+
gfc_add_modify (&se.pre, sym->backend_decl, tmp);
gfc_add_init_cleanup (block, gfc_finish_block( &se.pre),
@@ -1784,7 +1823,7 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block)
gfc_init_se (&se, NULL);
if (e->symtree->n.sym->ts.type == BT_CHARACTER)
{
- /* What about deferred strings? */
+ /* Deferred strings are dealt with in the preceeding. */
gcc_assert (!e->symtree->n.sym->ts.deferred);
tmp = e->symtree->n.sym->ts.u.cl->backend_decl;
}
diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c
index b106794..78477a9 100644
--- a/gcc/fortran/trans-types.c
+++ b/gcc/fortran/trans-types.c
@@ -530,7 +530,7 @@ gfc_init_kinds (void)
}
/* Choose the default real kind. Again, we choose 4 when possible. */
- if (flag_default_real)
+ if (flag_default_real_8)
{
if (!saw_r8)
gfc_fatal_error ("REAL(KIND=8) is not available for "
@@ -538,6 +538,22 @@ gfc_init_kinds (void)
gfc_default_real_kind = 8;
}
+ else if (flag_default_real_10)
+ {
+ if (!saw_r10)
+ gfc_fatal_error ("REAL(KIND=10) is not available for "
+ "%<-fdefault-real-10%> option");
+
+ gfc_default_real_kind = 10;
+ }
+ else if (flag_default_real_16)
+ {
+ if (!saw_r16)
+ gfc_fatal_error ("REAL(KIND=16) is not available for "
+ "%<-fdefault-real-16%> option");
+
+ gfc_default_real_kind = 16;
+ }
else if (flag_real4_kind == 8)
{
if (!saw_r8)
@@ -571,14 +587,20 @@ gfc_init_kinds (void)
are specified, we use kind=8, if it's available. If -fdefault-real is
specified without -fdefault-double, we use kind=16, if it's available.
Otherwise we do not change anything. */
- if (flag_default_double && !flag_default_real)
- gfc_fatal_error ("Use of %<-fdefault-double-8%> requires "
- "%<-fdefault-real-8%>");
-
- if (flag_default_real && flag_default_double && saw_r8)
+ if (flag_default_double && saw_r8)
gfc_default_double_kind = 8;
- else if (flag_default_real && saw_r16)
- gfc_default_double_kind = 16;
+ else if (flag_default_real_8 || flag_default_real_10 || flag_default_real_16)
+ {
+ /* Use largest available kind. */
+ if (saw_r16)
+ gfc_default_double_kind = 16;
+ else if (saw_r10)
+ gfc_default_double_kind = 10;
+ else if (saw_r8)
+ gfc_default_double_kind = 8;
+ else
+ gfc_default_double_kind = gfc_default_real_kind;
+ }
else if (flag_real8_kind == 4)
{
if (!saw_r4)
diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c
index 149f482..53bc428 100644
--- a/gcc/fortran/trans.c
+++ b/gcc/fortran/trans.c
@@ -2275,7 +2275,6 @@ gfc_unlikely (tree cond, enum br_predictor predictor)
build_int_cst (integer_type_node,
predictor));
}
- cond = fold_convert (boolean_type_node, cond);
return cond;
}
@@ -2297,7 +2296,6 @@ gfc_likely (tree cond, enum br_predictor predictor)
build_int_cst (integer_type_node,
predictor));
}
- cond = fold_convert (boolean_type_node, cond);
return cond;
}
diff --git a/gcc/function.c b/gcc/function.c
index 3ae5a3a..339419e 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -294,7 +294,7 @@ try_fit_stack_local (HOST_WIDE_INT start, HOST_WIDE_INT length,
/* Calculate how many bytes the start of local variables is off from
stack alignment. */
frame_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
- frame_off = STARTING_FRAME_OFFSET % frame_alignment;
+ frame_off = targetm.starting_frame_offset () % frame_alignment;
frame_phase = frame_off ? frame_alignment - frame_off : 0;
/* Round the frame offset to the specified alignment. */
@@ -499,7 +499,7 @@ assign_stack_local_1 (machine_mode mode, HOST_WIDE_INT size,
addr = plus_constant (Pmode, frame_pointer_rtx,
trunc_int_for_mode
(slot_offset + bigend_correction
- + STARTING_FRAME_OFFSET, Pmode));
+ + targetm.starting_frame_offset (), Pmode));
else
addr = plus_constant (Pmode, virtual_stack_vars_rtx,
trunc_int_for_mode
@@ -1930,7 +1930,7 @@ instantiate_virtual_regs (void)
/* Compute the offsets to use for this function. */
in_arg_offset = FIRST_PARM_OFFSET (current_function_decl);
- var_offset = STARTING_FRAME_OFFSET;
+ var_offset = targetm.starting_frame_offset ();
dynamic_offset = STACK_DYNAMIC_OFFSET (current_function_decl);
out_arg_offset = STACK_POINTER_OFFSET;
#ifdef FRAME_POINTER_CFA_OFFSET
@@ -4049,10 +4049,9 @@ gimplify_parameters (void)
DECL_IGNORED_P (addr) = 0;
local = build_fold_indirect_ref (addr);
- t = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
- t = build_call_expr (t, 2, DECL_SIZE_UNIT (parm),
- size_int (DECL_ALIGN (parm)));
-
+ t = build_alloca_call_expr (DECL_SIZE_UNIT (parm),
+ DECL_ALIGN (parm),
+ max_int_size_in_bytes (type));
/* The call has been built for a variable-sized object. */
CALL_ALLOCA_FOR_VAR_P (t) = 1;
t = fold_convert (ptr_type, t);
@@ -5681,6 +5680,58 @@ get_arg_pointer_save_area (void)
return ret;
}
+
+/* If debugging dumps are requested, dump information about how the
+ target handled -fstack-check=clash for the prologue.
+
+ PROBES describes what if any probes were emitted.
+
+ RESIDUALS indicates if the prologue had any residual allocation
+ (i.e. total allocation was not a multiple of PROBE_INTERVAL). */
+
+void
+dump_stack_clash_frame_info (enum stack_clash_probes probes, bool residuals)
+{
+ if (!dump_file)
+ return;
+
+ switch (probes)
+ {
+ case NO_PROBE_NO_FRAME:
+ fprintf (dump_file,
+ "Stack clash no probe no stack adjustment in prologue.\n");
+ break;
+ case NO_PROBE_SMALL_FRAME:
+ fprintf (dump_file,
+ "Stack clash no probe small stack adjustment in prologue.\n");
+ break;
+ case PROBE_INLINE:
+ fprintf (dump_file, "Stack clash inline probes in prologue.\n");
+ break;
+ case PROBE_LOOP:
+ fprintf (dump_file, "Stack clash probe loop in prologue.\n");
+ break;
+ }
+
+ if (residuals)
+ fprintf (dump_file, "Stack clash residual allocation in prologue.\n");
+ else
+ fprintf (dump_file, "Stack clash no residual allocation in prologue.\n");
+
+ if (frame_pointer_needed)
+ fprintf (dump_file, "Stack clash frame pointer needed.\n");
+ else
+ fprintf (dump_file, "Stack clash no frame pointer needed.\n");
+
+ if (TREE_THIS_VOLATILE (cfun->decl))
+ fprintf (dump_file,
+ "Stack clash noreturn prologue, assuming no implicit"
+ " probes in caller.\n");
+ else
+ fprintf (dump_file,
+ "Stack clash not noreturn prologue.\n");
+}
+
/* Add a list of INSNS to the hash HASHP, possibly allocating HASHP
for the first time. */
diff --git a/gcc/function.h b/gcc/function.h
index 91e0138..76434cd 100644
--- a/gcc/function.h
+++ b/gcc/function.h
@@ -551,6 +551,14 @@ do { \
((TARGET_PTRMEMFUNC_VBIT_LOCATION == ptrmemfunc_vbit_in_pfn) \
? MAX (FUNCTION_BOUNDARY, 2 * BITS_PER_UNIT) : FUNCTION_BOUNDARY)
+enum stack_clash_probes {
+ NO_PROBE_NO_FRAME,
+ NO_PROBE_SMALL_FRAME,
+ PROBE_INLINE,
+ PROBE_LOOP
+};
+
+extern void dump_stack_clash_frame_info (enum stack_clash_probes, bool);
extern void push_function_context (void);
diff --git a/gcc/fwprop.c b/gcc/fwprop.c
index ca99749..b77006b 100644
--- a/gcc/fwprop.c
+++ b/gcc/fwprop.c
@@ -357,8 +357,8 @@ canonicalize_address (rtx x)
{
case ASHIFT:
if (CONST_INT_P (XEXP (x, 1))
- && INTVAL (XEXP (x, 1)) < GET_MODE_BITSIZE (GET_MODE (x))
- && INTVAL (XEXP (x, 1)) >= 0)
+ && INTVAL (XEXP (x, 1)) < GET_MODE_UNIT_BITSIZE (GET_MODE (x))
+ && INTVAL (XEXP (x, 1)) >= 0)
{
HOST_WIDE_INT shift = INTVAL (XEXP (x, 1));
PUT_CODE (x, MULT);
diff --git a/gcc/gcc-ar.c b/gcc/gcc-ar.c
index 78d2fc1..d5d80e0 100644
--- a/gcc/gcc-ar.c
+++ b/gcc/gcc-ar.c
@@ -194,14 +194,6 @@ main (int ac, char **av)
#ifdef CROSS_DIRECTORY_STRUCTURE
real_exe_name = concat (target_machine, "-", PERSONALITY, NULL);
#endif
- /* Do not search original location in the same folder. */
- char *exe_folder = lrealpath (av[0]);
- exe_folder[strlen (exe_folder) - strlen (lbasename (exe_folder))] = '\0';
- char *location = concat (exe_folder, PERSONALITY, NULL);
-
- if (access (location, X_OK) == 0)
- remove_prefix (exe_folder, &path);
-
exe_name = find_a_file (&path, real_exe_name, X_OK);
if (!exe_name)
{
diff --git a/gcc/genmodes.c b/gcc/genmodes.c
index 97ed949..4eb8ee5 100644
--- a/gcc/genmodes.c
+++ b/gcc/genmodes.c
@@ -880,7 +880,7 @@ calc_wider_mode (void)
for (i = 0, m = modes[c]; m; i++, m = m->next)
sortbuf[i] = m;
- qsort (sortbuf, i, sizeof (struct mode_data *), cmp_modes);
+ (qsort) (sortbuf, i, sizeof (struct mode_data *), cmp_modes);
sortbuf[i] = 0;
for (j = 0; j < i; j++)
diff --git a/gcc/genrecog.c b/gcc/genrecog.c
index 902762f..b3d02d7 100644
--- a/gcc/genrecog.c
+++ b/gcc/genrecog.c
@@ -751,6 +751,21 @@ validate_pattern (rtx pattern, md_rtx_info *info, rtx set, int set_code)
error_at (info->loc,
"vec_select parallel with %d elements, expected %d",
XVECLEN (XEXP (pattern, 1), 0), expected);
+ else if (VECTOR_MODE_P (imode))
+ {
+ unsigned int nelems = GET_MODE_NUNITS (imode);
+ int i;
+ for (i = 0; i < expected; ++i)
+ if (CONST_INT_P (XVECEXP (XEXP (pattern, 1), 0, i))
+ && (UINTVAL (XVECEXP (XEXP (pattern, 1), 0, i))
+ >= nelems))
+ error_at (info->loc,
+ "out of bounds selector %u in vec_select, "
+ "expected at most %u",
+ (unsigned)
+ UINTVAL (XVECEXP (XEXP (pattern, 1), 0, i)),
+ nelems - 1);
+ }
}
if (imode != VOIDmode && !VECTOR_MODE_P (imode))
error_at (info->loc, "%smode of first vec_select operand is not a "
diff --git a/gcc/gimple-expr.c b/gcc/gimple-expr.c
index c1771fc..324f101 100644
--- a/gcc/gimple-expr.c
+++ b/gcc/gimple-expr.c
@@ -337,9 +337,8 @@ gimple_decl_printable_name (tree decl, int verbosity)
if (!DECL_NAME (decl))
return NULL;
- if (DECL_ASSEMBLER_NAME_SET_P (decl))
+ if (HAS_DECL_ASSEMBLER_NAME_P (decl) && DECL_ASSEMBLER_NAME_SET_P (decl))
{
- const char *str, *mangled_str;
int dmgl_opts = DMGL_NO_OPTS;
if (verbosity >= 2)
@@ -352,9 +351,10 @@ gimple_decl_printable_name (tree decl, int verbosity)
dmgl_opts |= DMGL_PARAMS;
}
- mangled_str = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- str = cplus_demangle_v3 (mangled_str, dmgl_opts);
- return (str) ? str : mangled_str;
+ const char *mangled_str
+ = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME_RAW (decl));
+ const char *str = cplus_demangle_v3 (mangled_str, dmgl_opts);
+ return str ? str : mangled_str;
}
return IDENTIFIER_POINTER (DECL_NAME (decl));
diff --git a/gcc/gimple-fold.c b/gcc/gimple-fold.c
index b9e0889..cb33c1e 100644
--- a/gcc/gimple-fold.c
+++ b/gcc/gimple-fold.c
@@ -6784,7 +6784,7 @@ gimple_fold_indirect_ref (tree t)
|| DECL_P (TREE_OPERAND (addr, 0)))
return fold_build2 (MEM_REF, type,
addr,
- wide_int_to_tree (ptype, off));
+ wide_int_to_tree (ptype, wi::to_wide (off)));
}
/* *(foo *)fooarrptr => (*fooarrptr)[0] */
diff --git a/gcc/gimple-pretty-print.c b/gcc/gimple-pretty-print.c
index ed8e51c..0da9074 100644
--- a/gcc/gimple-pretty-print.c
+++ b/gcc/gimple-pretty-print.c
@@ -109,7 +109,7 @@ dump_profile (int frequency, profile_count &count)
by xstrdup_for_dump. */
static const char *
-dump_probability (profile_probability probability, profile_count &count)
+dump_probability (profile_probability probability)
{
float minimum = 0.01f;
float fvalue = -1;
@@ -122,13 +122,10 @@ dump_probability (profile_probability probability, profile_count &count)
}
char *buf;
- if (count.initialized_p ())
- buf = xasprintf ("[%.2f%%] [count: %" PRId64 "]", fvalue,
- count.to_gcov_type ());
- else if (probability.initialized_p ())
- buf = xasprintf ("[%.2f%%] [count: INV]", fvalue);
+ if (probability.initialized_p ())
+ buf = xasprintf ("[%.2f%%]", fvalue);
else
- buf = xasprintf ("[INV] [count: INV]");
+ buf = xasprintf ("[INV]");
const char *ret = xstrdup_for_dump (buf);
free (buf);
@@ -141,7 +138,7 @@ dump_probability (profile_probability probability, profile_count &count)
static void
dump_edge_probability (pretty_printer *buffer, edge e)
{
- pp_scalar (buffer, " %s", dump_probability (e->probability, e->count));
+ pp_scalar (buffer, " %s", dump_probability (e->probability));
}
/* Print GIMPLE statement G to FILE using SPC indentation spaces and
diff --git a/gcc/gimple-ssa-isolate-paths.c b/gcc/gimple-ssa-isolate-paths.c
index 807e003..ba5c6a3 100644
--- a/gcc/gimple-ssa-isolate-paths.c
+++ b/gcc/gimple-ssa-isolate-paths.c
@@ -169,7 +169,6 @@ isolate_path (basic_block bb, basic_block duplicate,
/* Update profile only when redirection is really processed. */
bb->frequency += EDGE_FREQUENCY (e);
- bb->count += e->count;
}
/* There may be more than one statement in DUPLICATE which exhibits
diff --git a/gcc/gimple-ssa-sprintf.c b/gcc/gimple-ssa-sprintf.c
index 7899e09..9770df7 100644
--- a/gcc/gimple-ssa-sprintf.c
+++ b/gcc/gimple-ssa-sprintf.c
@@ -583,7 +583,7 @@ get_format_string (tree format, location_t *ploc)
/* For convenience and brevity. */
static bool
- (* const fmtwarn) (const substring_loc &, const source_range *,
+ (* const fmtwarn) (const substring_loc &, location_t,
const char *, int, const char *, ...)
= format_warning_at_substring;
@@ -2418,7 +2418,7 @@ should_warn_p (const pass_sprintf_length::call_info &info,
Return true if a warning has been issued. */
static bool
-maybe_warn (substring_loc &dirloc, source_range *pargrange,
+maybe_warn (substring_loc &dirloc, location_t argloc,
const pass_sprintf_length::call_info &info,
const result_range &avail_range, const result_range &res,
const directive &dir)
@@ -2476,8 +2476,8 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
: G_("%qE writing a terminating nul past the end "
"of the destination")));
- return fmtwarn (dirloc, NULL, NULL, info.warnopt (), fmtstr,
- info.func);
+ return fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (),
+ fmtstr, info.func);
}
if (res.min == res.max)
@@ -2500,7 +2500,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"%wu bytes into a region of size %wu"))
: G_("%<%.*s%> directive writing %wu bytes "
"into a region of size %wu")));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.min, navail);
@@ -2517,7 +2517,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"up to %wu bytes into a region of size %wu"))
: G_("%<%.*s%> directive writing up to %wu bytes "
"into a region of size %wu"));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.max, navail);
@@ -2537,7 +2537,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"likely %wu or more bytes into a region of size %wu"))
: G_("%<%.*s%> directive writing likely %wu or more bytes "
"into a region of size %wu"));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.likely, navail);
@@ -2554,7 +2554,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"between %wu and %wu bytes into a region of size %wu"))
: G_("%<%.*s%> directive writing between %wu and "
"%wu bytes into a region of size %wu"));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.min, res.max, navail);
@@ -2569,7 +2569,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"%wu or more bytes into a region of size %wu"))
: G_("%<%.*s%> directive writing %wu or more bytes "
"into a region of size %wu"));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.min, navail);
@@ -2603,7 +2603,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
: G_("%qE writing a terminating nul past the end "
"of the destination")));
- return fmtwarn (dirloc, NULL, NULL, info.warnopt (), fmtstr,
+ return fmtwarn (dirloc, UNKNOWN_LOCATION, NULL, info.warnopt (), fmtstr,
info.func);
}
@@ -2628,7 +2628,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
: G_("%<%.*s%> directive writing %wu bytes "
"into a region of size between %wu and %wu")));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.min, avail_range.min, avail_range.max);
@@ -2647,7 +2647,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"%wu and %wu"))
: G_("%<%.*s%> directive writing up to %wu bytes "
"into a region of size between %wu and %wu"));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.max, avail_range.min, avail_range.max);
@@ -2669,7 +2669,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"%wu and %wu"))
: G_("%<%.*s%> directive writing likely %wu or more bytes "
"into a region of size between %wu and %wu"));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.likely, avail_range.min, avail_range.max);
@@ -2688,7 +2688,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"between %wu and %wu"))
: G_("%<%.*s%> directive writing between %wu and "
"%wu bytes into a region of size between %wu and %wu"));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.min, res.max, avail_range.min, avail_range.max);
@@ -2705,7 +2705,7 @@ maybe_warn (substring_loc &dirloc, source_range *pargrange,
"%wu and %wu"))
: G_("%<%.*s%> directive writing %wu or more bytes "
"into a region of size between %wu and %wu"));
- return fmtwarn (dirloc, pargrange, NULL,
+ return fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dir.len,
target_to_host (hostdir, sizeof hostdir, dir.beg),
res.min, avail_range.min, avail_range.max);
@@ -2730,17 +2730,11 @@ format_directive (const pass_sprintf_length::call_info &info,
substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format),
offset, start, length);
- /* Also create a location range for the argument if possible.
+ /* Also get the location of the argument if possible.
This doesn't work for integer literals or function calls. */
- source_range argrange;
- source_range *pargrange;
- if (dir.arg && CAN_HAVE_LOCATION_P (dir.arg))
- {
- argrange = EXPR_LOCATION_RANGE (dir.arg);
- pargrange = &argrange;
- }
- else
- pargrange = NULL;
+ location_t argloc = UNKNOWN_LOCATION;
+ if (dir.arg)
+ argloc = EXPR_LOCATION (dir.arg);
/* Bail when there is no function to compute the output length,
or when minimum length checking has been disabled. */
@@ -2797,7 +2791,7 @@ format_directive (const pass_sprintf_length::call_info &info,
if (fmtres.nullp)
{
- fmtwarn (dirloc, pargrange, NULL, info.warnopt (),
+ fmtwarn (dirloc, argloc, NULL, info.warnopt (),
"%<%.*s%> directive argument is null",
dirlen, target_to_host (hostdir, sizeof hostdir, dir.beg));
@@ -2816,7 +2810,7 @@ format_directive (const pass_sprintf_length::call_info &info,
bool warned = res->warned;
if (!warned)
- warned = maybe_warn (dirloc, pargrange, info, avail_range,
+ warned = maybe_warn (dirloc, argloc, info, avail_range,
fmtres.range, dir);
/* Bump up the total maximum if it isn't too big. */
@@ -2862,7 +2856,7 @@ format_directive (const pass_sprintf_length::call_info &info,
(like Glibc does under some conditions). */
if (fmtres.range.min == fmtres.range.max)
- warned = fmtwarn (dirloc, pargrange, NULL,
+ warned = fmtwarn (dirloc, argloc, NULL,
info.warnopt (),
"%<%.*s%> directive output of %wu bytes exceeds "
"minimum required size of 4095",
@@ -2878,7 +2872,7 @@ format_directive (const pass_sprintf_length::call_info &info,
: G_("%<%.*s%> directive output between %wu and %wu "
"bytes exceeds minimum required size of 4095"));
- warned = fmtwarn (dirloc, pargrange, NULL,
+ warned = fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dirlen,
target_to_host (hostdir, sizeof hostdir, dir.beg),
fmtres.range.min, fmtres.range.max);
@@ -2906,7 +2900,7 @@ format_directive (const pass_sprintf_length::call_info &info,
to exceed INT_MAX bytes. */
if (fmtres.range.min == fmtres.range.max)
- warned = fmtwarn (dirloc, pargrange, NULL, info.warnopt (),
+ warned = fmtwarn (dirloc, argloc, NULL, info.warnopt (),
"%<%.*s%> directive output of %wu bytes causes "
"result to exceed %<INT_MAX%>",
dirlen,
@@ -2920,7 +2914,7 @@ format_directive (const pass_sprintf_length::call_info &info,
"bytes causes result to exceed %<INT_MAX%>")
: G_ ("%<%.*s%> directive output between %wu and %wu "
"bytes may cause result to exceed %<INT_MAX%>"));
- warned = fmtwarn (dirloc, pargrange, NULL,
+ warned = fmtwarn (dirloc, argloc, NULL,
info.warnopt (), fmtstr, dirlen,
target_to_host (hostdir, sizeof hostdir, dir.beg),
fmtres.range.min, fmtres.range.max);
@@ -3351,7 +3345,7 @@ parse_directive (pass_sprintf_length::call_info &info,
substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format),
caret, begin, end);
- fmtwarn (dirloc, NULL, NULL,
+ fmtwarn (dirloc, UNKNOWN_LOCATION, NULL,
info.warnopt (), "%<%.*s%> directive width out of range",
dir.len, target_to_host (hostdir, sizeof hostdir, dir.beg));
}
@@ -3385,7 +3379,7 @@ parse_directive (pass_sprintf_length::call_info &info,
substring_loc dirloc (info.fmtloc, TREE_TYPE (info.format),
caret, begin, end);
- fmtwarn (dirloc, NULL, NULL,
+ fmtwarn (dirloc, UNKNOWN_LOCATION, NULL,
info.warnopt (), "%<%.*s%> directive precision out of range",
dir.len, target_to_host (hostdir, sizeof hostdir, dir.beg));
}
diff --git a/gcc/gimple-ssa-store-merging.c b/gcc/gimple-ssa-store-merging.c
index cb76403..bc50bab 100644
--- a/gcc/gimple-ssa-store-merging.c
+++ b/gcc/gimple-ssa-store-merging.c
@@ -357,8 +357,7 @@ encode_tree_to_bitpos (tree expr, unsigned char *ptr, int bitlen, int bitpos,
|| !int_mode_for_size (bitlen, 0).exists ());
if (!sub_byte_op_p)
- return (native_encode_expr (tmp_int, ptr + first_byte, total_bytes, 0)
- != 0);
+ return native_encode_expr (tmp_int, ptr + first_byte, total_bytes) != 0;
/* LITTLE-ENDIAN
We are writing a non byte-sized quantity or at a position that is not
@@ -408,7 +407,7 @@ encode_tree_to_bitpos (tree expr, unsigned char *ptr, int bitlen, int bitpos,
memset (tmpbuf, '\0', byte_size);
/* The store detection code should only have allowed constants that are
accepted by native_encode_expr. */
- if (native_encode_expr (expr, tmpbuf, byte_size - 1, 0) == 0)
+ if (native_encode_expr (expr, tmpbuf, byte_size - 1) == 0)
gcc_unreachable ();
/* The native_encode_expr machinery uses TYPE_MODE to determine how many
@@ -1326,12 +1325,8 @@ lhs_valid_for_store_merging_p (tree lhs)
static bool
rhs_valid_for_store_merging_p (tree rhs)
{
- tree type = TREE_TYPE (rhs);
- if (TREE_CODE_CLASS (TREE_CODE (rhs)) != tcc_constant
- || !can_native_encode_type_p (type))
- return false;
-
- return true;
+ return native_encode_expr (rhs, NULL,
+ GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (rhs)))) != 0;
}
/* Entry point for the pass. Go over each basic block recording chains of
@@ -1357,7 +1352,7 @@ pass_store_merging::execute (function *fun)
if (is_gimple_debug (gsi_stmt (gsi)))
continue;
- if (++num_statements > 2)
+ if (++num_statements >= 2)
break;
}
diff --git a/gcc/gimple-ssa-strength-reduction.c b/gcc/gimple-ssa-strength-reduction.c
index b37ce35..42320ff 100644
--- a/gcc/gimple-ssa-strength-reduction.c
+++ b/gcc/gimple-ssa-strength-reduction.c
@@ -488,7 +488,8 @@ find_phi_def (tree base)
c = base_cand_from_table (base);
- if (!c || c->kind != CAND_PHI)
+ if (!c || c->kind != CAND_PHI
+ || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (gimple_phi_result (c->cand_stmt)))
return 0;
return c->cand_num;
@@ -557,6 +558,11 @@ find_basis_for_base_expr (slsr_cand_t c, tree base_expr)
gimple_bb (one_basis->cand_stmt)))
continue;
+ tree lhs = gimple_assign_lhs (one_basis->cand_stmt);
+ if (lhs && TREE_CODE (lhs) == SSA_NAME
+ && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
+ continue;
+
if (!basis || basis->cand_num < one_basis->cand_num)
basis = one_basis;
}
diff --git a/gcc/gimple-ssa-warn-alloca.c b/gcc/gimple-ssa-warn-alloca.c
index ec95cc6..08c2195 100644
--- a/gcc/gimple-ssa-warn-alloca.c
+++ b/gcc/gimple-ssa-warn-alloca.c
@@ -194,7 +194,8 @@ alloca_call_type_by_arg (tree arg, tree arg_casted, edge e, unsigned max_size)
// degrade into "if (N > Y) alloca(N)".
if (cond_code == GT_EXPR || cond_code == GE_EXPR)
rhs = integer_zero_node;
- return alloca_type_and_limit (ALLOCA_BOUND_MAYBE_LARGE, rhs);
+ return alloca_type_and_limit (ALLOCA_BOUND_MAYBE_LARGE,
+ wi::to_wide (rhs));
}
}
else
@@ -263,7 +264,7 @@ is_max (tree x, wide_int max)
// Analyze the alloca call in STMT and return the alloca type with its
// corresponding limit (if applicable). IS_VLA is set if the alloca
-// call is really a BUILT_IN_ALLOCA_WITH_ALIGN, signifying a VLA.
+// call was created by the gimplifier for a VLA.
//
// If the alloca call may be too large because of a cast from a signed
// type to an unsigned type, set *INVALID_CASTED_TYPE to the
@@ -277,7 +278,8 @@ alloca_call_type (gimple *stmt, bool is_vla, tree *invalid_casted_type)
tree len = gimple_call_arg (stmt, 0);
tree len_casted = NULL;
wide_int min, max;
- struct alloca_type_and_limit ret = alloca_type_and_limit (ALLOCA_UNBOUNDED);
+ edge_iterator ei;
+ edge e;
gcc_assert (!is_vla || (unsigned HOST_WIDE_INT) warn_vla_limit > 0);
gcc_assert (is_vla || (unsigned HOST_WIDE_INT) warn_alloca_limit > 0);
@@ -294,19 +296,22 @@ alloca_call_type (gimple *stmt, bool is_vla, tree *invalid_casted_type)
if (TREE_CODE (len) == INTEGER_CST)
{
if (tree_to_uhwi (len) > max_size)
- return alloca_type_and_limit (ALLOCA_BOUND_DEFINITELY_LARGE, len);
+ return alloca_type_and_limit (ALLOCA_BOUND_DEFINITELY_LARGE,
+ wi::to_wide (len));
if (integer_zerop (len))
return alloca_type_and_limit (ALLOCA_ARG_IS_ZERO);
- ret = alloca_type_and_limit (ALLOCA_OK);
+
+ return alloca_type_and_limit (ALLOCA_OK);
}
+
// Check the range info if available.
- else if (TREE_CODE (len) == SSA_NAME)
+ if (TREE_CODE (len) == SSA_NAME)
{
value_range_type range_type = get_range_info (len, &min, &max);
if (range_type == VR_RANGE)
{
if (wi::leu_p (max, max_size))
- ret = alloca_type_and_limit (ALLOCA_OK);
+ return alloca_type_and_limit (ALLOCA_OK);
else
{
// A cast may have created a range we don't care
@@ -389,52 +394,41 @@ alloca_call_type (gimple *stmt, bool is_vla, tree *invalid_casted_type)
// If we couldn't find anything, try a few heuristics for things we
// can easily determine. Check these misc cases but only accept
// them if all predecessors have a known bound.
- basic_block bb = gimple_bb (stmt);
- if (ret.type == ALLOCA_UNBOUNDED)
+ struct alloca_type_and_limit ret = alloca_type_and_limit (ALLOCA_OK);
+ FOR_EACH_EDGE (e, ei, gimple_bb (stmt)->preds)
{
- ret.type = ALLOCA_OK;
- for (unsigned ix = 0; ix < EDGE_COUNT (bb->preds); ix++)
- {
- gcc_assert (!len_casted || TYPE_UNSIGNED (TREE_TYPE (len_casted)));
- ret = alloca_call_type_by_arg (len, len_casted,
- EDGE_PRED (bb, ix), max_size);
- if (ret.type != ALLOCA_OK)
- break;
- }
+ gcc_assert (!len_casted || TYPE_UNSIGNED (TREE_TYPE (len_casted)));
+ ret = alloca_call_type_by_arg (len, len_casted, e, max_size);
+ if (ret.type != ALLOCA_OK)
+ break;
+ }
+
+ if (ret.type != ALLOCA_OK && tentative_cast_from_signed)
+ ret = alloca_type_and_limit (ALLOCA_CAST_FROM_SIGNED);
+
+ // If we have a declared maximum size, we can take it into account.
+ if (ret.type != ALLOCA_OK
+ && gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX))
+ {
+ tree arg = gimple_call_arg (stmt, 2);
+ if (compare_tree_int (arg, max_size) <= 0)
+ ret = alloca_type_and_limit (ALLOCA_OK);
+ else
+ ret = alloca_type_and_limit (ALLOCA_BOUND_MAYBE_LARGE,
+ wi::to_wide (arg));
}
- if (tentative_cast_from_signed && ret.type != ALLOCA_OK)
- return alloca_type_and_limit (ALLOCA_CAST_FROM_SIGNED);
return ret;
}
-// Return TRUE if the alloca call in STMT is in a loop, otherwise
-// return FALSE. As an exception, ignore alloca calls for VLAs that
-// occur in a loop since those will be cleaned up when they go out of
-// scope.
+// Return TRUE if STMT is in a loop, otherwise return FALSE.
static bool
-in_loop_p (bool is_vla, gimple *stmt)
+in_loop_p (gimple *stmt)
{
basic_block bb = gimple_bb (stmt);
- if (bb->loop_father
- && bb->loop_father->header != ENTRY_BLOCK_PTR_FOR_FN (cfun))
- {
- // Do not warn on VLAs occurring in a loop, since VLAs are
- // guaranteed to be cleaned up when they go out of scope.
- // That is, there is a corresponding __builtin_stack_restore
- // at the end of the scope in which the VLA occurs.
- tree fndecl = gimple_call_fn (stmt);
- while (TREE_CODE (fndecl) == ADDR_EXPR)
- fndecl = TREE_OPERAND (fndecl, 0);
- if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && is_vla
- && DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN)
- return false;
-
- return true;
- }
- return false;
+ return
+ bb->loop_father && bb->loop_father->header != ENTRY_BLOCK_PTR_FOR_FN (cfun);
}
unsigned int
@@ -453,8 +447,8 @@ pass_walloca::execute (function *fun)
continue;
gcc_assert (gimple_call_num_args (stmt) >= 1);
- bool is_vla = gimple_alloca_call_p (stmt)
- && gimple_call_alloca_for_var_p (as_a <gcall *> (stmt));
+ const bool is_vla
+ = gimple_call_alloca_for_var_p (as_a <gcall *> (stmt));
// Strict mode whining for VLAs is handled by the front-end,
// so we can safely ignore this case. Also, ignore VLAs if
@@ -474,9 +468,10 @@ pass_walloca::execute (function *fun)
struct alloca_type_and_limit t
= alloca_call_type (stmt, is_vla, &invalid_casted_type);
- // Even if we think the alloca call is OK, make sure it's
- // not in a loop.
- if (t.type == ALLOCA_OK && in_loop_p (is_vla, stmt))
+ // Even if we think the alloca call is OK, make sure it's not in a
+ // loop, except for a VLA, since VLAs are guaranteed to be cleaned
+ // up when they go out of scope, including in a loop.
+ if (t.type == ALLOCA_OK && !is_vla && in_loop_p (stmt))
t = alloca_type_and_limit (ALLOCA_IN_LOOP);
enum opt_code wcode
@@ -491,7 +486,7 @@ pass_walloca::execute (function *fun)
is_vla ? G_("argument to variable-length array "
"may be too large")
: G_("argument to %<alloca%> may be too large"))
- && t.limit != integer_zero_node)
+ && t.limit != 0)
{
print_decu (t.limit, buff);
inform (loc, G_("limit is %u bytes, but argument "
@@ -504,7 +499,7 @@ pass_walloca::execute (function *fun)
is_vla ? G_("argument to variable-length array "
"is too large")
: G_("argument to %<alloca%> is too large"))
- && t.limit != integer_zero_node)
+ && t.limit != 0)
{
print_decu (t.limit, buff);
inform (loc, G_("limit is %u bytes, but argument is %s"),
diff --git a/gcc/gimple.c b/gcc/gimple.c
index c4e6f81..1f291e1 100644
--- a/gcc/gimple.c
+++ b/gcc/gimple.c
@@ -346,7 +346,7 @@ gimple_build_call_internal_vec (enum internal_fn fn, vec<tree> args)
this fact. */
gcall *
-gimple_build_call_from_tree (tree t)
+gimple_build_call_from_tree (tree t, tree fnptrtype)
{
unsigned i, nargs;
gcall *call;
@@ -369,8 +369,7 @@ gimple_build_call_from_tree (tree t)
gimple_call_set_return_slot_opt (call, CALL_EXPR_RETURN_SLOT_OPT (t));
if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA
- || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN))
+ && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (fndecl)))
gimple_call_set_alloca_for_var (call, CALL_ALLOCA_FOR_VAR_P (t));
else
gimple_call_set_from_thunk (call, CALL_FROM_THUNK_P (t));
@@ -380,6 +379,23 @@ gimple_build_call_from_tree (tree t)
gimple_set_no_warning (call, TREE_NO_WARNING (t));
gimple_call_set_with_bounds (call, CALL_WITH_BOUNDS_P (t));
+ if (fnptrtype)
+ {
+ gimple_call_set_fntype (call, TREE_TYPE (fnptrtype));
+
+ /* Check if it's an indirect CALL and the type has the
+ nocf_check attribute. In that case propagate the information
+ to the gimple CALL insn. */
+ if (!fndecl)
+ {
+ gcc_assert (POINTER_TYPE_P (fnptrtype));
+ tree fntype = TREE_TYPE (fnptrtype);
+
+ if (lookup_attribute ("nocf_check", TYPE_ATTRIBUTES (fntype)))
+ gimple_call_set_nocf_check (call, TRUE);
+ }
+ }
+
return call;
}
@@ -2965,13 +2981,14 @@ preprocess_case_label_vec_for_gimple (vec<tree> labels,
if (CASE_HIGH (labels[i]) != NULL_TREE
&& (CASE_HIGH (widest_label) == NULL_TREE
- || wi::gtu_p (wi::sub (CASE_HIGH (labels[i]),
- CASE_LOW (labels[i])),
- wi::sub (CASE_HIGH (widest_label),
- CASE_LOW (widest_label)))))
+ || (wi::gtu_p
+ (wi::to_wide (CASE_HIGH (labels[i]))
+ - wi::to_wide (CASE_LOW (labels[i])),
+ wi::to_wide (CASE_HIGH (widest_label))
+ - wi::to_wide (CASE_LOW (widest_label))))))
widest_label = labels[i];
- if (wi::add (low, 1) != high)
+ if (wi::to_wide (low) + 1 != wi::to_wide (high))
break;
}
if (i == len)
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 6213c49..334def8 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -148,6 +148,7 @@ enum gf_mask {
GF_CALL_WITH_BOUNDS = 1 << 8,
GF_CALL_MUST_TAIL_CALL = 1 << 9,
GF_CALL_BY_DESCRIPTOR = 1 << 10,
+ GF_CALL_NOCF_CHECK = 1 << 11,
GF_OMP_PARALLEL_COMBINED = 1 << 0,
GF_OMP_PARALLEL_GRID_PHONY = 1 << 1,
GF_OMP_TASK_TASKLOOP = 1 << 0,
@@ -1425,7 +1426,7 @@ gcall *gimple_build_call (tree, unsigned, ...);
gcall *gimple_build_call_valist (tree, unsigned, va_list);
gcall *gimple_build_call_internal (enum internal_fn, unsigned, ...);
gcall *gimple_build_call_internal_vec (enum internal_fn, vec<tree> );
-gcall *gimple_build_call_from_tree (tree);
+gcall *gimple_build_call_from_tree (tree, tree);
gassign *gimple_build_assign (tree, tree CXX_MEM_STAT_INFO);
gassign *gimple_build_assign (tree, enum tree_code,
tree, tree, tree CXX_MEM_STAT_INFO);
@@ -2893,6 +2894,25 @@ gimple_call_set_with_bounds (gimple *gs, bool with_bounds)
}
+/* Return true if call GS is marked as nocf_check. */
+
+static inline bool
+gimple_call_nocf_check_p (const gcall *gs)
+{
+ return (gs->subcode & GF_CALL_NOCF_CHECK) != 0;
+}
+
+/* Mark statement GS as nocf_check call. */
+
+static inline void
+gimple_call_set_nocf_check (gcall *gs, bool nocf_check)
+{
+ if (nocf_check)
+ gs->subcode |= GF_CALL_NOCF_CHECK;
+ else
+ gs->subcode &= ~GF_CALL_NOCF_CHECK;
+}
+
/* Return the target of internal call GS. */
static inline enum internal_fn
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 8b29a71..4c24510 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1574,9 +1574,8 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
SET_DECL_VALUE_EXPR (decl, t);
DECL_HAS_VALUE_EXPR_P (decl) = 1;
- t = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
- t = build_call_expr (t, 2, DECL_SIZE_UNIT (decl),
- size_int (DECL_ALIGN (decl)));
+ t = build_alloca_call_expr (DECL_SIZE_UNIT (decl), DECL_ALIGN (decl),
+ max_int_size_in_bytes (TREE_TYPE (decl)));
/* The call has been built for a variable-sized object. */
CALL_ALLOCA_FOR_VAR_P (t) = 1;
t = fold_convert (ptr_type, t);
@@ -1656,6 +1655,7 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
&& TREE_ADDRESSABLE (decl)
&& !TREE_STATIC (decl)
&& !DECL_HAS_VALUE_EXPR_P (decl)
+ && DECL_ALIGN (decl) <= MAX_SUPPORTED_STACK_ALIGNMENT
&& dbg_cnt (asan_use_after_scope))
{
asan_poisoned_variables->add (decl);
@@ -3173,8 +3173,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL)
switch (DECL_FUNCTION_CODE (fndecl))
{
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
/* If the call has been built for a variable-sized object, then we
want to restore the stack level when the enclosing BIND_EXPR is
exited to reclaim the allocated space; otherwise, we precisely
@@ -3379,8 +3378,7 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
/* The CALL_EXPR in *EXPR_P is already in GIMPLE form, so all we
have to do is replicate it as a GIMPLE_CALL tuple. */
gimple_stmt_iterator gsi;
- call = gimple_build_call_from_tree (*expr_p);
- gimple_call_set_fntype (call, TREE_TYPE (fnptrtype));
+ call = gimple_build_call_from_tree (*expr_p, fnptrtype);
notice_special_calls (call);
if (EXPR_CILK_SPAWN (*expr_p))
gimplify_cilk_detach (pre_p);
@@ -5479,7 +5477,12 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
side as statements and throw away the assignment. Do this after
gimplify_modify_expr_rhs so we handle TARGET_EXPRs of addressable
types properly. */
- if (zero_sized_type (TREE_TYPE (*from_p)) && !want_value)
+ if (zero_sized_type (TREE_TYPE (*from_p))
+ && !want_value
+ /* Don't do this for calls that return addressable types, expand_call
+ relies on those having a lhs. */
+ && !(TREE_ADDRESSABLE (TREE_TYPE (*from_p))
+ && TREE_CODE (*from_p) == CALL_EXPR))
{
gimplify_stmt (from_p, pre_p);
gimplify_stmt (to_p, pre_p);
@@ -5656,8 +5659,7 @@ gimplify_modify_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
CALL_EXPR_ARG (*from_p, 2));
else
{
- call_stmt = gimple_build_call_from_tree (*from_p);
- gimple_call_set_fntype (call_stmt, TREE_TYPE (fnptrtype));
+ call_stmt = gimple_build_call_from_tree (*from_p, fnptrtype);
}
}
notice_special_calls (call_stmt);
@@ -6500,7 +6502,9 @@ gimplify_target_expr (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p)
clobber = build2 (MODIFY_EXPR, TREE_TYPE (temp), temp, clobber);
gimple_push_cleanup (temp, clobber, false, pre_p, true);
}
- if (asan_poisoned_variables && dbg_cnt (asan_use_after_scope))
+ if (asan_poisoned_variables
+ && DECL_ALIGN (temp) <= MAX_SUPPORTED_STACK_ALIGNMENT
+ && dbg_cnt (asan_use_after_scope))
{
tree asan_cleanup = build_asan_poison_call_expr (temp);
if (asan_cleanup)
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index 83138d3..1c0ef93 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,12 @@
+2017-10-11 Tony Reix <tony.reix@atos.net>
+
+ * go-system.h (__STDC_FORMAT_MACROS): Define before including any
+ system header files, as is done in ../system.h.
+
+2017-10-05 Ian Lance Taylor <iant@golang.org>
+
+ * Make-lang.in (GO_OBJS): Add go/names.o.
+
2017-08-30 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in
index b65d347..60fecad 100644
--- a/gcc/go/Make-lang.in
+++ b/gcc/go/Make-lang.in
@@ -68,6 +68,7 @@ GO_OBJS = \
go/import.o \
go/import-archive.o \
go/lex.o \
+ go/names.o \
go/parse.o \
go/runtime.o \
go/statements.o \
diff --git a/gcc/go/go-system.h b/gcc/go/go-system.h
index 9018543..b1c67c3 100644
--- a/gcc/go/go-system.h
+++ b/gcc/go/go-system.h
@@ -22,6 +22,12 @@
#include "config.h"
+/* Define this so that inttypes.h defines the PRI?64 macros even
+ when compiling with a C++ compiler. Define it here so in the
+ event inttypes.h gets pulled in by another header it is already
+ defined. */
+#define __STDC_FORMAT_MACROS
+
// These must be included before the #poison declarations in system.h.
#include <algorithm>
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index f6b5361..8b1846d 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-5fb74cd7192123a9ea06dcae0d5d8d0b3538db8f
+a409ac2c78899e638a014c97891925bec93cb3ad
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc
index a90c527..dea2118 100644
--- a/gcc/go/gofrontend/escape.cc
+++ b/gcc/go/gofrontend/escape.cc
@@ -575,7 +575,7 @@ debug_function_name(Named_object* fn)
// Extract #.
std::string name = Gogo::unpack_hidden_name(fn->name());
- int closure_num = (int)strtol(name.substr(6).c_str(), NULL, 0);
+ int closure_num = Gogo::nested_function_num(fn->name());
closure_num++;
name = Gogo::unpack_hidden_name(enclosing->name());
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 8816232..8337cbe 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -1299,28 +1299,12 @@ Func_descriptor_expression::do_get_backend(Translate_context* context)
return context->backend()->var_expression(this->dvar_, VE_rvalue, loc);
Gogo* gogo = context->gogo();
- std::string var_name;
+ std::string var_name(gogo->function_descriptor_name(no));
bool is_descriptor = false;
if (no->is_function_declaration()
&& !no->func_declaration_value()->asm_name().empty()
&& Linemap::is_predeclared_location(no->location()))
- {
- if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.")
- var_name = no->func_declaration_value()->asm_name() + "_descriptor";
- else
- var_name = no->func_declaration_value()->asm_name() + "$descriptor";
- is_descriptor = true;
- }
- else
- {
- if (no->package() == NULL)
- var_name = gogo->pkgpath_symbol();
- else
- var_name = no->package()->pkgpath_symbol();
- var_name.push_back('.');
- var_name.append(Gogo::unpack_hidden_name(no->name()));
- var_name.append("$descriptor");
- }
+ is_descriptor = true;
Btype* btype = this->type()->get_backend(gogo);
@@ -4348,27 +4332,23 @@ Unary_expression::do_get_backend(Translate_context* context)
}
}
- static unsigned int counter;
- char buf[100];
if (this->is_gc_root_ || this->is_slice_init_)
{
+ std::string var_name;
bool copy_to_heap = false;
if (this->is_gc_root_)
{
// Build a decl for a GC root variable. GC roots are mutable, so
// they cannot be represented as an immutable_struct in the
// backend.
- static unsigned int root_counter;
- snprintf(buf, sizeof buf, "gc%u", root_counter);
- ++root_counter;
+ var_name = gogo->gc_root_name();
}
else
{
// Build a decl for a slice value initializer. An immutable slice
// value initializer may have to be copied to the heap if it
// contains pointers in a non-constant context.
- snprintf(buf, sizeof buf, "C%u", counter);
- ++counter;
+ var_name = gogo->initializer_name();
Array_type* at = this->expr_->type()->array_type();
go_assert(at != NULL);
@@ -4379,12 +4359,12 @@ Unary_expression::do_get_backend(Translate_context* context)
// read-only, because the program is permitted to change it.
copy_to_heap = context->function() != NULL;
}
- std::string asm_name(go_selectively_encode_id(buf));
+ std::string asm_name(go_selectively_encode_id(var_name));
Bvariable* implicit =
- gogo->backend()->implicit_variable(buf, asm_name,
+ gogo->backend()->implicit_variable(var_name, asm_name,
btype, true, copy_to_heap,
false, 0);
- gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
+ gogo->backend()->implicit_variable_set_init(implicit, var_name, btype,
true, copy_to_heap, false,
bexpr);
bexpr = gogo->backend()->var_expression(implicit, VE_rvalue, loc);
@@ -4407,16 +4387,13 @@ Unary_expression::do_get_backend(Translate_context* context)
|| this->expr_->string_expression() != NULL)
&& this->expr_->is_static_initializer())
{
- // Build a decl for a constant constructor.
- snprintf(buf, sizeof buf, "C%u", counter);
- ++counter;
-
- std::string asm_name(go_selectively_encode_id(buf));
+ std::string var_name(gogo->initializer_name());
+ std::string asm_name(go_selectively_encode_id(var_name));
Bvariable* decl =
- gogo->backend()->immutable_struct(buf, asm_name,
+ gogo->backend()->immutable_struct(var_name, asm_name,
true, false, btype, loc);
- gogo->backend()->immutable_struct_set_init(decl, buf, true, false,
- btype, loc, bexpr);
+ gogo->backend()->immutable_struct_set_init(decl, var_name, true,
+ false, btype, loc, bexpr);
bexpr = gogo->backend()->var_expression(decl, VE_rvalue, loc);
}
@@ -15403,10 +15380,9 @@ Interface_mtable_expression::do_get_backend(Translate_context* context)
const Typed_identifier_list* interface_methods = this->itype_->methods();
go_assert(!interface_methods->empty());
- std::string mangled_name = ((this->is_pointer_ ? "__go_pimt__" : "__go_imt_")
- + this->itype_->mangled_name(gogo)
- + "__"
- + this->type_->mangled_name(gogo));
+ std::string mangled_name =
+ gogo->interface_method_table_name(this->itype_, this->type_,
+ this->is_pointer_);
// Set is_public if we are converting a named type to an interface
// type that is defined in the same package as the named type, and
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index adc8e8a..c986963 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -868,32 +868,6 @@ Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
init_stmts.push_back(this->backend()->expression_statement(init_bfn, bcall));
}
-// Get the name to use for the import control function. If there is a
-// global function or variable, then we know that that name must be
-// unique in the link, and we use it as the basis for our name.
-
-const std::string&
-Gogo::get_init_fn_name()
-{
- if (this->init_fn_name_.empty())
- {
- go_assert(this->package_ != NULL);
- if (this->is_main_package())
- {
- // Use a name which the runtime knows.
- this->init_fn_name_ = "__go_init_main";
- }
- else
- {
- std::string s = this->pkgpath_symbol();
- s.append("..import");
- this->init_fn_name_ = s;
- }
- }
-
- return this->init_fn_name_;
-}
-
// Build the decl for the initialization function.
Named_object*
@@ -1774,11 +1748,7 @@ Gogo::start_function(const std::string& name, Function_type* type,
"func init must have no arguments and no return values");
// There can be multiple "init" functions, so give them each a
// different name.
- static int init_count;
- char buf[30];
- snprintf(buf, sizeof buf, ".$init%d", init_count);
- ++init_count;
- nested_name = buf;
+ nested_name = this->init_function_name();
pname = &nested_name;
is_init = true;
}
@@ -1787,22 +1757,15 @@ Gogo::start_function(const std::string& name, Function_type* type,
else
{
// Invent a name for a nested function.
- static int nested_count;
- char buf[30];
- snprintf(buf, sizeof buf, ".$nested%d", nested_count);
- ++nested_count;
- nested_name = buf;
+ nested_name = this->nested_function_name();
pname = &nested_name;
}
Named_object* ret;
if (Gogo::is_sink_name(*pname))
{
- static int sink_count;
- char buf[30];
- snprintf(buf, sizeof buf, ".$sink%d", sink_count);
- ++sink_count;
- ret = Named_object::make_function(buf, NULL, function);
+ std::string sname(this->sink_function_name());
+ ret = Named_object::make_function(sname, NULL, function);
ret->func_value()->set_is_sink();
if (!type->is_method())
@@ -1845,11 +1808,8 @@ Gogo::start_function(const std::string& name, Function_type* type,
{
// Redefinition error. Invent a name to avoid knockon
// errors.
- static int redefinition_count;
- char buf[30];
- snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count);
- ++redefinition_count;
- ret = this->package_->bindings()->add_function(buf, NULL, function);
+ std::string rname(this->redefined_function_name());
+ ret = this->package_->bindings()->add_function(rname, NULL, function);
}
}
else
@@ -2274,47 +2234,6 @@ Gogo::record_interface_type(Interface_type* itype)
this->interface_types_.push_back(itype);
}
-// Return an erroneous name that indicates that an error has already
-// been reported.
-
-std::string
-Gogo::erroneous_name()
-{
- static int erroneous_count;
- char name[50];
- snprintf(name, sizeof name, "$erroneous%d", erroneous_count);
- ++erroneous_count;
- return name;
-}
-
-// Return whether a name is an erroneous name.
-
-bool
-Gogo::is_erroneous_name(const std::string& name)
-{
- return name.compare(0, 10, "$erroneous") == 0;
-}
-
-// Return a name for a thunk object.
-
-std::string
-Gogo::thunk_name()
-{
- static int thunk_count;
- char thunk_name[50];
- snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count);
- ++thunk_count;
- return thunk_name;
-}
-
-// Return whether a function is a thunk.
-
-bool
-Gogo::is_thunk(const Named_object* no)
-{
- return no->name().compare(0, 6, "$thunk") == 0;
-}
-
// Define the global names. We do this only after parsing all the
// input files, because the program might define the global names
// itself.
@@ -4195,10 +4114,10 @@ Build_recover_thunks::function(Named_object* orig_no)
if (orig_fntype->is_varargs())
new_fntype->set_is_varargs();
- std::string name = orig_no->name();
+ Type* rtype = NULL;
if (orig_fntype->is_method())
- name += "$" + orig_fntype->receiver()->type()->mangled_name(gogo);
- name += "$recover";
+ rtype = orig_fntype->receiver()->type();
+ std::string name(gogo->recover_thunk_name(orig_no->name(), rtype));
Named_object *new_no = gogo->start_function(name, new_fntype, false,
location);
Function *new_func = new_no->func_value();
@@ -5424,8 +5343,9 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
{
if (this->fndecl_ == NULL)
{
- std::string asm_name;
bool is_visible = false;
+ bool is_init_fn = false;
+ Type* rtype = NULL;
if (no->package() != NULL)
;
else if (this->enclosing_ != NULL || Gogo::is_thunk(no))
@@ -5436,7 +5356,7 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
else if (no->name() == gogo->get_init_fn_name())
{
is_visible = true;
- asm_name = no->name();
+ is_init_fn = true;
}
else if (Gogo::unpack_hidden_name(no->name()) == "main"
&& gogo->is_main_package())
@@ -5449,36 +5369,29 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
{
if (!this->is_unnamed_type_stub_method_)
is_visible = true;
- std::string pkgpath = gogo->pkgpath_symbol();
- if (this->type_->is_method()
- && Gogo::is_hidden_name(no->name())
- && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
- {
- // This is a method we created for an unexported
- // method of an imported embedded type. We need to
- // use the pkgpath of the imported package to avoid
- // a possible name collision. See bug478 for a test
- // case.
- std::string p = Gogo::hidden_name_pkgpath(no->name());
- pkgpath = gogo->pkgpath_symbol_for_package(p);
- }
-
- asm_name = pkgpath;
- asm_name.append(1, '.');
- asm_name.append(Gogo::unpack_hidden_name(no->name()));
- if (this->type_->is_method())
- {
- asm_name.append(1, '.');
- Type* rtype = this->type_->receiver()->type();
- asm_name.append(rtype->mangled_name(gogo));
- }
+ if (this->type_->is_method())
+ rtype = this->type_->receiver()->type();
}
+ std::string asm_name;
if (!this->asm_name_.empty())
{
asm_name = this->asm_name_;
+
+ // If an assembler name is explicitly specified, there must
+ // be some reason to refer to the symbol from a different
+ // object file.
is_visible = true;
}
+ else if (is_init_fn)
+ {
+ // These names appear in the export data and are used
+ // directly in the assembler code. If we change this here
+ // we need to change Gogo::init_imports.
+ asm_name = no->name();
+ }
+ else
+ asm_name = gogo->function_asm_name(no->name(), NULL, rtype);
// If a function calls the predeclared recover function, we
// can't inline it, because recover behaves differently in a
@@ -5509,10 +5422,6 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no)
if ((this->pragmas_ & GOPRAGMA_NOSPLIT) != 0)
disable_split_stack = true;
- // Encode name if asm_name not already set at this point
- if (asm_name.empty() && go_id_needs_encoding(no->get_id(gogo)))
- asm_name = go_encode_id(no->get_id(gogo));
-
// This should go into a unique section if that has been
// requested elsewhere, or if this is a nointerface function.
// We want to put a nointerface function into a unique section
@@ -5553,30 +5462,12 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
std::string asm_name;
if (this->asm_name_.empty())
- {
- asm_name = (no->package() == NULL
- ? gogo->pkgpath_symbol()
- : no->package()->pkgpath_symbol());
- if (this->fntype_->is_method()
- && Gogo::is_hidden_name(no->name())
- && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath())
- {
- // This is a method created for an unexported method of
- // an imported embedded type. Use the pkgpath of the
- // imported package. This matches code in
- // Function::get_or_make_decl, above.
- std::string p = Gogo::hidden_name_pkgpath(no->name());
- asm_name = gogo->pkgpath_symbol_for_package(p);
- }
- asm_name.append(1, '.');
- asm_name.append(Gogo::unpack_hidden_name(no->name()));
- if (this->fntype_->is_method())
- {
- asm_name.append(1, '.');
- Type* rtype = this->fntype_->receiver()->type();
- asm_name.append(rtype->mangled_name(gogo));
- }
- }
+ {
+ Type* rtype = NULL;
+ if (this->fntype_->is_method())
+ rtype = this->fntype_->receiver()->type();
+ asm_name = gogo->function_asm_name(no->name(), no->package(), rtype);
+ }
else if (go_id_needs_encoding(no->get_id(gogo)))
asm_name = go_encode_id(no->get_id(gogo));
@@ -6815,18 +6706,8 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function,
: gogo->package_name());
var_name.push_back('.');
var_name.append(n);
- std::string asm_name;
- if (Gogo::is_hidden_name(name))
- asm_name = var_name;
- else
- {
- asm_name = package != NULL
- ? package->pkgpath_symbol()
- : gogo->pkgpath_symbol();
- asm_name.push_back('.');
- asm_name.append(n);
- }
- asm_name = go_encode_id(asm_name);
+
+ std::string asm_name(gogo->global_var_asm_name(name, package));
bool is_hidden = Gogo::is_hidden_name(name);
// Hack to export runtime.writeBarrier. FIXME.
@@ -7416,23 +7297,18 @@ Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
go_unreachable();
}
-
// Return the external identifier for this object.
std::string
Named_object::get_id(Gogo* gogo)
{
- go_assert(!this->is_variable() && !this->is_result_variable());
+ go_assert(!this->is_variable()
+ && !this->is_result_variable()
+ && !this->is_type());
std::string decl_name;
if (this->is_function_declaration()
&& !this->func_declaration_value()->asm_name().empty())
decl_name = this->func_declaration_value()->asm_name();
- else if (this->is_type()
- && Linemap::is_predeclared_location(this->type_value()->location()))
- {
- // We don't need the package name for builtin types.
- decl_name = Gogo::unpack_hidden_name(this->name_);
- }
else
{
std::string package_name;
@@ -7466,22 +7342,6 @@ Named_object::get_id(Gogo* gogo)
decl_name.append(fntype->receiver()->type()->mangled_name(gogo));
}
}
- if (this->is_type())
- {
- unsigned int index;
- const Named_object* in_function = this->type_value()->in_function(&index);
- if (in_function != NULL)
- {
- decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
- if (index > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", index);
- decl_name += '$';
- decl_name += buf;
- }
- }
- }
return decl_name;
}
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index a04a1a3..345a15d 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -506,26 +506,6 @@ class Gogo
void
mark_locals_used();
- // Return a name to use for an error case. This should only be used
- // after reporting an error, and is used to avoid useless knockon
- // errors.
- static std::string
- erroneous_name();
-
- // Return whether the name indicates an error.
- static bool
- is_erroneous_name(const std::string&);
-
- // Return a name to use for a thunk function. A thunk function is
- // one we create during the compilation, for a go statement or a
- // defer statement or a method expression.
- static std::string
- thunk_name();
-
- // Return whether an object is a thunk.
- static bool
- is_thunk(const Named_object*);
-
// Note that we've seen an interface type. This is used to build
// all required interface method tables.
void
@@ -781,10 +761,108 @@ class Gogo
Expression*
allocate_memory(Type *type, Location);
+ // Return the assembler name to use for an exported function, a
+ // method, or a function/method declaration.
+ std::string
+ function_asm_name(const std::string& go_name, const Package*,
+ const Type* receiver);
+
+ // Return the name to use for a function descriptor.
+ std::string
+ function_descriptor_name(Named_object*);
+
+ // Return the name to use for a generated stub method.
+ std::string
+ stub_method_name(const std::string& method_name);
+
+ // Return the names of the hash and equality functions for TYPE.
+ void
+ specific_type_function_names(const Type*, const Named_type*,
+ std::string* hash_name,
+ std::string* equal_name);
+
+ // Return the assembler name to use for a global variable.
+ std::string
+ global_var_asm_name(const std::string& go_name, const Package*);
+
+ // Return a name to use for an error case. This should only be used
+ // after reporting an error, and is used to avoid useless knockon
+ // errors.
+ static std::string
+ erroneous_name();
+
+ // Return whether the name indicates an error.
+ static bool
+ is_erroneous_name(const std::string&);
+
+ // Return a name to use for a thunk function. A thunk function is
+ // one we create during the compilation, for a go statement or a
+ // defer statement or a method expression.
+ static std::string
+ thunk_name();
+
+ // Return whether an object is a thunk.
+ static bool
+ is_thunk(const Named_object*);
+
+ // Return the name to use for an init function.
+ std::string
+ init_function_name();
+
+ // Return the name to use for a nested function.
+ static std::string
+ nested_function_name();
+
+ // Return the index of a nested function name.
+ static int
+ nested_function_num(const std::string&);
+
+ // Return the name to use for a sink funciton.
+ std::string
+ sink_function_name();
+
+ // Return the name to use for an (erroneous) redefined function.
+ std::string
+ redefined_function_name();
+
+ // Return the name for use for a recover thunk.
+ std::string
+ recover_thunk_name(const std::string& name, const Type* rtype);
+
+ // Return the name to use for the GC root variable.
+ std::string
+ gc_root_name();
+
+ // Return the name to use for a composite literal or string
+ // initializer.
+ std::string
+ initializer_name();
+
+ // Return the name of the variable used to represent the zero value
+ // of a map.
+ std::string
+ map_zero_value_name();
+
// Get the name of the magic initialization function.
const std::string&
get_init_fn_name();
+ // Return the name for a type descriptor symbol.
+ std::string
+ type_descriptor_name(Type*, Named_type*);
+
+ // Return the assembler name for the GC symbol for a type.
+ std::string
+ gc_symbol_name(Type*);
+
+ // Return the assembler name for a ptrmask variable.
+ std::string
+ ptrmask_symbol_name(const std::string& ptrmask_sym_name);
+
+ // Return the name to use for an interface method table.
+ std::string
+ interface_method_table_name(Interface_type*, Type*, bool is_pointer);
+
private:
// During parsing, we keep a stack of functions. Each function on
// the stack is one that we are currently parsing. For each
diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc
index 20b077f..2a3ea83 100644
--- a/gcc/go/gofrontend/import.cc
+++ b/gcc/go/gofrontend/import.cc
@@ -756,13 +756,6 @@ Import::read_type()
this->require_c_string(" ");
- bool is_alias = false;
- if (this->match_c_string("= "))
- {
- stream->advance(2);
- is_alias = true;
- }
-
// The package name may follow. This is the name of the package in
// the package clause of that package. The type name will include
// the pkgpath, which may be different.
@@ -775,6 +768,13 @@ Import::read_type()
this->require_c_string(" ");
}
+ bool is_alias = false;
+ if (this->match_c_string("= "))
+ {
+ stream->advance(2);
+ is_alias = true;
+ }
+
// Declare the type in the appropriate package. If we haven't seen
// it before, mark it as invisible. We declare it before we read
// the actual definition of the type, since the definition may refer
diff --git a/gcc/go/gofrontend/names.cc b/gcc/go/gofrontend/names.cc
new file mode 100644
index 0000000..20f7c57
--- /dev/null
+++ b/gcc/go/gofrontend/names.cc
@@ -0,0 +1,803 @@
+// names.cc -- Names used by gofrontend generated code.
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-system.h"
+
+#include "gogo.h"
+#include "go-encode-id.h"
+#include "types.h"
+#include "expressions.h"
+
+// This file contains functions that generate names that appear in the
+// assembly code. This is not used for names that appear only in the
+// debug info.
+
+// Return the assembler name to use for an exported function, a
+// method, or a function/method declaration. This is not called if
+// the function has been given an explicit name via a magic //extern
+// or //go:linkname comment. GO_NAME is the name that appears in the
+// Go code. PACKAGE is the package where the function is defined, and
+// is NULL for the package being compiled. For a method, RTYPE is
+// the method's receiver type; for a function, RTYPE is NULL.
+
+std::string
+Gogo::function_asm_name(const std::string& go_name, const Package* package,
+ const Type* rtype)
+{
+ std::string ret = (package == NULL
+ ? this->pkgpath_symbol()
+ : package->pkgpath_symbol());
+
+ if (rtype != NULL
+ && Gogo::is_hidden_name(go_name)
+ && Gogo::hidden_name_pkgpath(go_name) != this->pkgpath())
+ {
+ // This is a method created for an unexported method of an
+ // imported embedded type. Use the pkgpath of the imported
+ // package.
+ std::string p = Gogo::hidden_name_pkgpath(go_name);
+ ret = this->pkgpath_symbol_for_package(p);
+ }
+
+ ret.append(1, '.');
+ ret.append(Gogo::unpack_hidden_name(go_name));
+
+ if (rtype != NULL)
+ {
+ ret.append(1, '.');
+ ret.append(rtype->mangled_name(this));
+ }
+
+ return go_encode_id(ret);
+}
+
+// Return the name to use for a function descriptor. These symbols
+// are globally visible.
+
+std::string
+Gogo::function_descriptor_name(Named_object* no)
+{
+ std::string var_name;
+ if (no->is_function_declaration()
+ && !no->func_declaration_value()->asm_name().empty()
+ && Linemap::is_predeclared_location(no->location()))
+ {
+ if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.")
+ var_name = no->func_declaration_value()->asm_name() + "_descriptor";
+ else
+ var_name = no->func_declaration_value()->asm_name() + "$descriptor";
+ }
+ else
+ {
+ if (no->package() == NULL)
+ var_name = this->pkgpath_symbol();
+ else
+ var_name = no->package()->pkgpath_symbol();
+ var_name.push_back('.');
+ var_name.append(Gogo::unpack_hidden_name(no->name()));
+ var_name.append("$descriptor");
+ }
+ return var_name;
+}
+
+// Return the name to use for a generated stub method. MNAME is the
+// method name. These functions are globally visible. Note that this
+// is the function name that corresponds to the name used for the
+// method in Go source code, if this stub method were written in Go.
+// The assembler name will be generated by Gogo::function_asm_name,
+// and because this is a method that name will include the receiver
+// type.
+
+std::string
+Gogo::stub_method_name(const std::string& mname)
+{
+ return mname + "$stub";
+}
+
+// Return the names of the hash and equality functions for TYPE. If
+// NAME is not NULL it is the name of the type. Set *HASH_NAME and
+// *EQUAL_NAME.
+
+void
+Gogo::specific_type_function_names(const Type* type, const Named_type* name,
+ std::string *hash_name,
+ std::string *equal_name)
+{
+ std::string base_name;
+ if (name == NULL)
+ {
+ // Mangled names can have '.' if they happen to refer to named
+ // types in some way. That's fine if this is simply a named
+ // type, but otherwise it will confuse the code that builds
+ // function identifiers. Remove '.' when necessary.
+ base_name = type->mangled_name(this);
+ size_t i;
+ while ((i = base_name.find('.')) != std::string::npos)
+ base_name[i] = '$';
+ base_name = this->pack_hidden_name(base_name, false);
+ }
+ else
+ {
+ // This name is already hidden or not as appropriate.
+ base_name = name->name();
+ unsigned int index;
+ const Named_object* in_function = name->in_function(&index);
+ if (in_function != NULL)
+ {
+ base_name.append(1, '$');
+ const Typed_identifier* rcvr =
+ in_function->func_value()->type()->receiver();
+ if (rcvr != NULL)
+ {
+ Named_type* rcvr_type = rcvr->type()->deref()->named_type();
+ base_name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
+ base_name.append(1, '$');
+ }
+ base_name.append(Gogo::unpack_hidden_name(in_function->name()));
+ if (index > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", index);
+ base_name += '$';
+ base_name += buf;
+ }
+ }
+ }
+ *hash_name = base_name + "$hash";
+ *equal_name = base_name + "$equal";
+}
+
+// Return the assembler name to use for a global variable. GO_NAME is
+// the name that appears in the Go code. PACKAGE is the package where
+// the variable is defined, and is NULL for the package being
+// compiled.
+
+std::string
+Gogo::global_var_asm_name(const std::string& go_name, const Package* package)
+{
+ std::string ret = (package != NULL
+ ? package->pkgpath_symbol()
+ : this->pkgpath_symbol());
+ ret.push_back('.');
+ ret.append(Gogo::unpack_hidden_name(go_name));
+ return go_encode_id(ret);
+}
+
+// Return an erroneous name that indicates that an error has already
+// been reported.
+
+std::string
+Gogo::erroneous_name()
+{
+ static int erroneous_count;
+ char name[50];
+ snprintf(name, sizeof name, "$erroneous%d", erroneous_count);
+ ++erroneous_count;
+ return name;
+}
+
+// Return whether a name is an erroneous name.
+
+bool
+Gogo::is_erroneous_name(const std::string& name)
+{
+ return name.compare(0, 10, "$erroneous") == 0;
+}
+
+// Return a name for a thunk object.
+
+std::string
+Gogo::thunk_name()
+{
+ static int thunk_count;
+ char thunk_name[50];
+ snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count);
+ ++thunk_count;
+ return thunk_name;
+}
+
+// Return whether a function is a thunk.
+
+bool
+Gogo::is_thunk(const Named_object* no)
+{
+ return no->name().compare(0, 6, "$thunk") == 0;
+}
+
+// Return the name to use for an init function. There can be multiple
+// functions named "init" so each one needs a different name.
+
+std::string
+Gogo::init_function_name()
+{
+ static int init_count;
+ char buf[30];
+ snprintf(buf, sizeof buf, ".$init%d", init_count);
+ ++init_count;
+ return buf;
+}
+
+// Return the name to use for a nested function.
+
+std::string
+Gogo::nested_function_name()
+{
+ static int nested_count;
+ char buf[30];
+ snprintf(buf, sizeof buf, ".$nested%d", nested_count);
+ ++nested_count;
+ return buf;
+}
+
+// Return the index of a nested function name.
+
+int
+Gogo::nested_function_num(const std::string& name)
+{
+ std::string n(Gogo::unpack_hidden_name(name));
+ go_assert(n.compare(0, 8, ".$nested") == 0);
+ return strtol(n.substr(8).c_str(), NULL, 0);
+}
+
+// Return the name to use for a sink function, a function whose name
+// is simply underscore. We don't really need these functions but we
+// do have to generate them for error checking.
+
+std::string
+Gogo::sink_function_name()
+{
+ static int sink_count;
+ char buf[30];
+ snprintf(buf, sizeof buf, ".$sink%d", sink_count);
+ ++sink_count;
+ return buf;
+}
+
+// Return the name to use for a redefined function. These functions
+// are erroneous but we still generate them for further error
+// checking.
+
+std::string
+Gogo::redefined_function_name()
+{
+ static int redefinition_count;
+ char buf[30];
+ snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count);
+ ++redefinition_count;
+ return buf;
+}
+
+// Return the name to use for a recover thunk for the function NAME.
+// If the function is a method, RTYPE is the receiver type.
+
+std::string
+Gogo::recover_thunk_name(const std::string& name, const Type* rtype)
+{
+ std::string ret(name);
+ if (rtype != NULL)
+ {
+ ret.push_back('$');
+ ret.append(rtype->mangled_name(this));
+ }
+ ret.append("$recover");
+ return ret;
+}
+
+// Return the name to use for a GC root variable. The GC root
+// variable is a composite literal that is passed to
+// runtime.registerGCRoots. There is at most one of these variables
+// per compilation.
+
+std::string
+Gogo::gc_root_name()
+{
+ return "gc0";
+}
+
+// Return the name to use for a composite literal or string
+// initializer. This is a local name never referenced outside of this
+// file.
+
+std::string
+Gogo::initializer_name()
+{
+ static unsigned int counter;
+ char buf[30];
+ snprintf(buf, sizeof buf, "C%u", counter);
+ ++counter;
+ return buf;
+}
+
+// Return the name of the variable used to represent the zero value of
+// a map. This is a globally visible common symbol.
+
+std::string
+Gogo::map_zero_value_name()
+{
+ return "go$zerovalue";
+}
+
+// Return the name to use for the import control function.
+
+const std::string&
+Gogo::get_init_fn_name()
+{
+ if (this->init_fn_name_.empty())
+ {
+ go_assert(this->package_ != NULL);
+ if (this->is_main_package())
+ {
+ // Use a name that the runtime knows.
+ this->init_fn_name_ = "__go_init_main";
+ }
+ else
+ {
+ std::string s = this->pkgpath_symbol();
+ s.append("..import");
+ this->init_fn_name_ = s;
+ }
+ }
+
+ return this->init_fn_name_;
+}
+
+// Return a mangled name for a type. These names appear in symbol
+// names in the assembler file for things like type descriptors and
+// methods.
+
+std::string
+Type::mangled_name(Gogo* gogo) const
+{
+ std::string ret;
+
+ // The do_mangled_name virtual function should set RET to the
+ // mangled name. For a composite type it should append a code for
+ // the composition and then call do_mangled_name on the components.
+ this->do_mangled_name(gogo, &ret);
+
+ return ret;
+}
+
+// The mangled name is implemented as a method on each instance of
+// Type.
+
+void
+Error_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ ret->push_back('E');
+}
+
+void
+Void_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ ret->push_back('v');
+}
+
+void
+Boolean_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ ret->push_back('b');
+}
+
+void
+Integer_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ char buf[100];
+ snprintf(buf, sizeof buf, "i%s%s%de",
+ this->is_abstract_ ? "a" : "",
+ this->is_unsigned_ ? "u" : "",
+ this->bits_);
+ ret->append(buf);
+}
+
+void
+Float_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ char buf[100];
+ snprintf(buf, sizeof buf, "f%s%de",
+ this->is_abstract_ ? "a" : "",
+ this->bits_);
+ ret->append(buf);
+}
+
+void
+Complex_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ char buf[100];
+ snprintf(buf, sizeof buf, "c%s%de",
+ this->is_abstract_ ? "a" : "",
+ this->bits_);
+ ret->append(buf);
+}
+
+void
+String_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ ret->push_back('z');
+}
+
+void
+Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ ret->push_back('F');
+
+ if (this->receiver_ != NULL)
+ {
+ ret->push_back('m');
+ this->append_mangled_name(this->receiver_->type(), gogo, ret);
+ }
+
+ const Typed_identifier_list* params = this->parameters();
+ if (params != NULL)
+ {
+ ret->push_back('p');
+ for (Typed_identifier_list::const_iterator p = params->begin();
+ p != params->end();
+ ++p)
+ this->append_mangled_name(p->type(), gogo, ret);
+ if (this->is_varargs_)
+ ret->push_back('V');
+ ret->push_back('e');
+ }
+
+ const Typed_identifier_list* results = this->results();
+ if (results != NULL)
+ {
+ ret->push_back('r');
+ for (Typed_identifier_list::const_iterator p = results->begin();
+ p != results->end();
+ ++p)
+ this->append_mangled_name(p->type(), gogo, ret);
+ ret->push_back('e');
+ }
+
+ ret->push_back('e');
+}
+
+void
+Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ ret->push_back('p');
+ this->append_mangled_name(this->to_type_, gogo, ret);
+}
+
+void
+Nil_type::do_mangled_name(Gogo*, std::string* ret) const
+{
+ ret->push_back('n');
+}
+
+void
+Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ ret->push_back('S');
+
+ const Struct_field_list* fields = this->fields_;
+ if (fields != NULL)
+ {
+ for (Struct_field_list::const_iterator p = fields->begin();
+ p != fields->end();
+ ++p)
+ {
+ if (p->is_anonymous())
+ ret->append("0_");
+ else
+ {
+
+ std::string n(Gogo::mangle_possibly_hidden_name(p->field_name()));
+ char buf[20];
+ snprintf(buf, sizeof buf, "%u_",
+ static_cast<unsigned int>(n.length()));
+ ret->append(buf);
+ ret->append(n);
+ }
+
+ // For an anonymous field with an alias type, the field name
+ // is the alias name.
+ if (p->is_anonymous()
+ && p->type()->named_type() != NULL
+ && p->type()->named_type()->is_alias())
+ p->type()->named_type()->append_mangled_type_name(gogo, true, ret);
+ else
+ this->append_mangled_name(p->type(), gogo, ret);
+ if (p->has_tag())
+ {
+ const std::string& tag(p->tag());
+ std::string out;
+ for (std::string::const_iterator p = tag.begin();
+ p != tag.end();
+ ++p)
+ {
+ if (ISALNUM(*p) || *p == '_')
+ out.push_back(*p);
+ else
+ {
+ char buf[20];
+ snprintf(buf, sizeof buf, ".%x.",
+ static_cast<unsigned int>(*p));
+ out.append(buf);
+ }
+ }
+ char buf[20];
+ snprintf(buf, sizeof buf, "T%u_",
+ static_cast<unsigned int>(out.length()));
+ ret->append(buf);
+ ret->append(out);
+ }
+ }
+ }
+
+ if (this->is_struct_incomparable_)
+ ret->push_back('x');
+
+ ret->push_back('e');
+}
+
+void
+Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ ret->push_back('A');
+ this->append_mangled_name(this->element_type_, gogo, ret);
+ if (this->length_ != NULL)
+ {
+ Numeric_constant nc;
+ if (!this->length_->numeric_constant_value(&nc))
+ {
+ go_assert(saw_errors());
+ return;
+ }
+ mpz_t val;
+ if (!nc.to_int(&val))
+ {
+ go_assert(saw_errors());
+ return;
+ }
+ char *s = mpz_get_str(NULL, 10, val);
+ ret->append(s);
+ free(s);
+ mpz_clear(val);
+ if (this->is_array_incomparable_)
+ ret->push_back('x');
+ }
+ ret->push_back('e');
+}
+
+void
+Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ ret->push_back('M');
+ this->append_mangled_name(this->key_type_, gogo, ret);
+ ret->append("__");
+ this->append_mangled_name(this->val_type_, gogo, ret);
+}
+
+void
+Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ ret->push_back('C');
+ this->append_mangled_name(this->element_type_, gogo, ret);
+ if (this->may_send_)
+ ret->push_back('s');
+ if (this->may_receive_)
+ ret->push_back('r');
+ ret->push_back('e');
+}
+
+void
+Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ go_assert(this->methods_are_finalized_);
+
+ ret->push_back('I');
+
+ const Typed_identifier_list* methods = this->all_methods_;
+ if (methods != NULL && !this->seen_)
+ {
+ this->seen_ = true;
+ for (Typed_identifier_list::const_iterator p = methods->begin();
+ p != methods->end();
+ ++p)
+ {
+ if (!p->name().empty())
+ {
+ std::string n(Gogo::mangle_possibly_hidden_name(p->name()));
+ char buf[20];
+ snprintf(buf, sizeof buf, "%u_",
+ static_cast<unsigned int>(n.length()));
+ ret->append(buf);
+ ret->append(n);
+ }
+ this->append_mangled_name(p->type(), gogo, ret);
+ }
+ this->seen_ = false;
+ }
+
+ ret->push_back('e');
+}
+
+void
+Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ this->append_mangled_type_name(gogo, false, ret);
+}
+
+void
+Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
+{
+ if (this->is_defined())
+ this->append_mangled_name(this->real_type(), gogo, ret);
+ else
+ {
+ const Named_object* no = this->named_object();
+ std::string name;
+ if (no->package() == NULL)
+ name = gogo->pkgpath_symbol();
+ else
+ name = no->package()->pkgpath_symbol();
+ name += '.';
+ name += Gogo::unpack_hidden_name(no->name());
+ char buf[20];
+ snprintf(buf, sizeof buf, "N%u_",
+ static_cast<unsigned int>(name.length()));
+ ret->append(buf);
+ ret->append(name);
+ }
+}
+
+// Append the mangled name for a named type to RET. For an alias we
+// normally use the real name, but if USE_ALIAS is true we use the
+// alias name itself.
+
+void
+Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias,
+ std::string* ret) const
+{
+ if (this->is_error_)
+ return;
+ if (this->is_alias_ && !use_alias)
+ {
+ if (this->seen_alias_)
+ return;
+ this->seen_alias_ = true;
+ this->append_mangled_name(this->type_, gogo, ret);
+ this->seen_alias_ = false;
+ return;
+ }
+ Named_object* no = this->named_object_;
+ std::string name;
+ if (this->is_builtin())
+ go_assert(this->in_function_ == NULL);
+ else
+ {
+ const std::string& pkgpath(no->package() == NULL
+ ? gogo->pkgpath_symbol()
+ : no->package()->pkgpath_symbol());
+ name = pkgpath;
+ name.append(1, '.');
+ if (this->in_function_ != NULL)
+ {
+ const Typed_identifier* rcvr =
+ this->in_function_->func_value()->type()->receiver();
+ if (rcvr != NULL)
+ {
+ Named_type* rcvr_type = rcvr->type()->deref()->named_type();
+ name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
+ name.append(1, '.');
+ }
+ name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
+ name.append(1, '$');
+ if (this->in_function_index_ > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", this->in_function_index_);
+ name.append(buf);
+ name.append(1, '$');
+ }
+ }
+ }
+ name.append(Gogo::unpack_hidden_name(no->name()));
+ char buf[20];
+ snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length()));
+ ret->append(buf);
+ ret->append(name);
+}
+
+// Return the name for the type descriptor symbol for TYPE. This can
+// be a global, common, or local symbol, depending. NT is not NULL if
+// it is the name to use.
+
+std::string
+Gogo::type_descriptor_name(Type* type, Named_type* nt)
+{
+ // The type descriptor symbol for the unsafe.Pointer type is defined
+ // in libgo/runtime/go-unsafe-pointer.c, so just use a reference to
+ // that symbol.
+ if (type->is_unsafe_pointer_type())
+ return "__go_tdn_unsafe.Pointer";
+
+ if (nt == NULL)
+ return "__go_td_" + type->mangled_name(this);
+
+ Named_object* no = nt->named_object();
+ unsigned int index;
+ const Named_object* in_function = nt->in_function(&index);
+ std::string ret = "__go_tdn_";
+ if (nt->is_builtin())
+ go_assert(in_function == NULL);
+ else
+ {
+ const std::string& pkgpath(no->package() == NULL
+ ? this->pkgpath_symbol()
+ : no->package()->pkgpath_symbol());
+ ret.append(pkgpath);
+ ret.append(1, '.');
+ if (in_function != NULL)
+ {
+ const Typed_identifier* rcvr =
+ in_function->func_value()->type()->receiver();
+ if (rcvr != NULL)
+ {
+ Named_type* rcvr_type = rcvr->type()->deref()->named_type();
+ ret.append(Gogo::unpack_hidden_name(rcvr_type->name()));
+ ret.append(1, '.');
+ }
+ ret.append(Gogo::unpack_hidden_name(in_function->name()));
+ ret.append(1, '.');
+ if (index > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", index);
+ ret.append(buf);
+ ret.append(1, '.');
+ }
+ }
+ }
+
+ std::string mname(Gogo::mangle_possibly_hidden_name(no->name()));
+ ret.append(mname);
+
+ return ret;
+}
+
+// Return the name for the GC symbol for a type. This is used to
+// initialize the gcdata field of a type descriptor. This is a local
+// name never referenced outside of this assembly file. (Note that
+// some type descriptors will initialize the gcdata field with a name
+// generated by ptrmask_symbol_name rather than this method.)
+
+std::string
+Gogo::gc_symbol_name(Type* type)
+{
+ return this->type_descriptor_name(type, type->named_type()) + "$gc";
+}
+
+// Return the name for a ptrmask variable. PTRMASK_SYM_NAME is a
+// base64 string encoding the ptrmask (as returned by Ptrmask::symname
+// in types.cc). This name is used to intialize the gcdata field of a
+// type descriptor. These names are globally visible. (Note that
+// some type descriptors will initialize the gcdata field with a name
+// generated by gc_symbol_name rather than this method.)
+
+std::string
+Gogo::ptrmask_symbol_name(const std::string& ptrmask_sym_name)
+{
+ return "runtime.gcbits." + ptrmask_sym_name;
+}
+
+// Return the name to use for an interface method table used for the
+// ordinary type TYPE converted to the interface type ITYPE.
+// IS_POINTER is true if this is for the method set for a pointer
+// receiver.
+
+std::string
+Gogo::interface_method_table_name(Interface_type* itype, Type* type,
+ bool is_pointer)
+{
+ return ((is_pointer ? "__go_pimt__" : "__go_imt_")
+ + itype->mangled_name(this)
+ + "__"
+ + type->mangled_name(this));
+}
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index a00b80a..5b0c84a 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -1257,7 +1257,7 @@ Type::make_type_descriptor_var(Gogo* gogo)
Type* td_type = Type::make_type_descriptor_type();
Btype* td_btype = td_type->get_backend(gogo);
- const char *name = "__go_tdn_unsafe.Pointer";
+ std::string name = gogo->type_descriptor_name(this, nt);
std::string asm_name(go_selectively_encode_id(name));
this->type_descriptor_var_ =
gogo->backend()->immutable_struct_reference(name, asm_name,
@@ -1269,7 +1269,7 @@ Type::make_type_descriptor_var(Gogo* gogo)
return;
}
- std::string var_name = this->type_descriptor_var_name(gogo, nt);
+ std::string var_name = gogo->type_descriptor_name(this, nt);
// Build the contents of the type descriptor.
Expression* initializer = this->do_type_descriptor(gogo, NULL);
@@ -1331,56 +1331,6 @@ Type::make_type_descriptor_var(Gogo* gogo)
binitializer);
}
-// Return the name of the type descriptor variable. If NT is not
-// NULL, use it to get the name. Otherwise this is an unnamed type.
-
-std::string
-Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt)
-{
- if (nt == NULL)
- return "__go_td_" + this->mangled_name(gogo);
-
- Named_object* no = nt->named_object();
- unsigned int index;
- const Named_object* in_function = nt->in_function(&index);
- std::string ret = "__go_tdn_";
- if (nt->is_builtin())
- go_assert(in_function == NULL);
- else
- {
- const std::string& pkgpath(no->package() == NULL
- ? gogo->pkgpath_symbol()
- : no->package()->pkgpath_symbol());
- ret.append(pkgpath);
- ret.append(1, '.');
- if (in_function != NULL)
- {
- const Typed_identifier* rcvr =
- in_function->func_value()->type()->receiver();
- if (rcvr != NULL)
- {
- Named_type* rcvr_type = rcvr->type()->deref()->named_type();
- ret.append(Gogo::unpack_hidden_name(rcvr_type->name()));
- ret.append(1, '.');
- }
- ret.append(Gogo::unpack_hidden_name(in_function->name()));
- ret.append(1, '.');
- if (index > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", index);
- ret.append(buf);
- ret.append(1, '.');
- }
- }
- }
-
- std::string mname(Gogo::mangle_possibly_hidden_name(no->name()));
- ret.append(mname);
-
- return ret;
-}
-
// Return true if this type descriptor is defined in a different
// package. If this returns true it sets *PACKAGE to the package.
@@ -1967,48 +1917,9 @@ Type::specific_type_functions(Gogo* gogo, Named_type* name, int64_t size,
return;
}
- std::string base_name;
- if (name == NULL)
- {
- // Mangled names can have '.' if they happen to refer to named
- // types in some way. That's fine if this is simply a named
- // type, but otherwise it will confuse the code that builds
- // function identifiers. Remove '.' when necessary.
- base_name = this->mangled_name(gogo);
- size_t i;
- while ((i = base_name.find('.')) != std::string::npos)
- base_name[i] = '$';
- base_name = gogo->pack_hidden_name(base_name, false);
- }
- else
- {
- // This name is already hidden or not as appropriate.
- base_name = name->name();
- unsigned int index;
- const Named_object* in_function = name->in_function(&index);
- if (in_function != NULL)
- {
- base_name.append(1, '$');
- const Typed_identifier* rcvr =
- in_function->func_value()->type()->receiver();
- if (rcvr != NULL)
- {
- Named_type* rcvr_type = rcvr->type()->deref()->named_type();
- base_name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
- base_name.append(1, '$');
- }
- base_name.append(Gogo::unpack_hidden_name(in_function->name()));
- if (index > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", index);
- base_name += '$';
- base_name += buf;
- }
- }
- }
- std::string hash_name = base_name + "$hash";
- std::string equal_name = base_name + "$equal";
+ std::string hash_name;
+ std::string equal_name;
+ gogo->specific_type_function_names(this, name, &hash_name, &equal_name);
Location bloc = Linemap::predeclared_location();
@@ -2525,7 +2436,7 @@ Type::make_gc_symbol_var(Gogo* gogo)
return;
}
- std::string sym_name = this->type_descriptor_var_name(gogo, nt) + "$gc";
+ std::string sym_name = gogo->gc_symbol_name(this);
// Build the contents of the gc symbol.
Expression* sym_init = this->gcprog_constructor(gogo, ptrsize, ptrdata);
@@ -2818,7 +2729,8 @@ Type::gc_ptrmask_var(Gogo* gogo, int64_t ptrsize, int64_t ptrdata)
// This can happen in error cases. Just build an empty gcbits.
go_assert(saw_errors());
}
- std::string sym_name = "runtime.gcbits." + ptrmask.symname();
+
+ std::string sym_name = gogo->ptrmask_symbol_name(ptrmask.symname());
Bvariable* bvnull = NULL;
std::pair<GC_gcbits_vars::iterator, bool> ins =
Type::gc_gcbits_vars.insert(std::make_pair(sym_name, bvnull));
@@ -3462,21 +3374,6 @@ Type::reflection(Gogo* gogo) const
return ret;
}
-// Return a mangled name for the type.
-
-std::string
-Type::mangled_name(Gogo* gogo) const
-{
- std::string ret;
-
- // The do_mangled_name virtual function should set RET to the
- // mangled name. For a composite type it should append a code for
- // the composition and then call do_mangled_name on the components.
- this->do_mangled_name(gogo, &ret);
-
- return ret;
-}
-
// Return whether the backend size of the type is known.
bool
@@ -3796,37 +3693,32 @@ Type::import_type(Import* imp)
}
}
-// A type used to indicate a parsing error. This exists to simplify
-// later error detection.
+// Class Error_type.
+
+// Return the backend representation of an Error type.
-class Error_type : public Type
+Btype*
+Error_type::do_get_backend(Gogo* gogo)
{
- public:
- Error_type()
- : Type(TYPE_ERROR)
- { }
+ return gogo->backend()->error_type();
+}
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
+// Return an expression for the type descriptor for an error type.
- Btype*
- do_get_backend(Gogo* gogo)
- { return gogo->backend()->error_type(); }
- Expression*
- do_type_descriptor(Gogo*, Named_type*)
- { return Expression::make_error(Linemap::predeclared_location()); }
+Expression*
+Error_type::do_type_descriptor(Gogo*, Named_type*)
+{
+ return Expression::make_error(Linemap::predeclared_location());
+}
- void
- do_reflection(Gogo*, std::string*) const
- { go_assert(saw_errors()); }
+// We should not be asked for the reflection string for an error type.
- void
- do_mangled_name(Gogo*, std::string* ret) const
- { ret->push_back('E'); }
-};
+void
+Error_type::do_reflection(Gogo*, std::string*) const
+{
+ go_assert(saw_errors());
+}
Type*
Type::make_error_type()
@@ -3835,36 +3727,15 @@ Type::make_error_type()
return &singleton_error_type;
}
-// The void type.
+// Class Void_type.
-class Void_type : public Type
-{
- public:
- Void_type()
- : Type(TYPE_VOID)
- { }
+// Get the backend representation of a void type.
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- Btype*
- do_get_backend(Gogo* gogo)
- { return gogo->backend()->void_type(); }
-
- Expression*
- do_type_descriptor(Gogo*, Named_type*)
- { go_unreachable(); }
-
- void
- do_reflection(Gogo*, std::string*) const
- { }
-
- void
- do_mangled_name(Gogo*, std::string* ret) const
- { ret->push_back('v'); }
-};
+Btype*
+Void_type::do_get_backend(Gogo* gogo)
+{
+ return gogo->backend()->void_type();
+}
Type*
Type::make_void_type()
@@ -3873,36 +3744,15 @@ Type::make_void_type()
return &singleton_void_type;
}
-// The boolean type.
-
-class Boolean_type : public Type
-{
- public:
- Boolean_type()
- : Type(TYPE_BOOLEAN)
- { }
+// Class Boolean_type.
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return true; }
+// Return the backend representation of the boolean type.
- Btype*
- do_get_backend(Gogo* gogo)
- { return gogo->backend()->bool_type(); }
-
- Expression*
- do_type_descriptor(Gogo*, Named_type* name);
-
- // We should not be asked for the reflection string of a basic type.
- void
- do_reflection(Gogo*, std::string* ret) const
- { ret->append("bool"); }
-
- void
- do_mangled_name(Gogo*, std::string* ret) const
- { ret->push_back('b'); }
-};
+Btype*
+Boolean_type::do_get_backend(Gogo* gogo)
+{
+ return gogo->backend()->bool_type();
+}
// Make the type descriptor.
@@ -4069,19 +3919,6 @@ Integer_type::do_reflection(Gogo*, std::string*) const
go_assert(saw_errors());
}
-// Mangled name.
-
-void
-Integer_type::do_mangled_name(Gogo*, std::string* ret) const
-{
- char buf[100];
- snprintf(buf, sizeof buf, "i%s%s%de",
- this->is_abstract_ ? "a" : "",
- this->is_unsigned_ ? "u" : "",
- this->bits_);
- ret->append(buf);
-}
-
// Make an integer type.
Named_type*
@@ -4204,18 +4041,6 @@ Float_type::do_reflection(Gogo*, std::string*) const
go_assert(saw_errors());
}
-// Mangled name.
-
-void
-Float_type::do_mangled_name(Gogo*, std::string* ret) const
-{
- char buf[100];
- snprintf(buf, sizeof buf, "f%s%de",
- this->is_abstract_ ? "a" : "",
- this->bits_);
- ret->append(buf);
-}
-
// Make a floating point type.
Named_type*
@@ -4331,18 +4156,6 @@ Complex_type::do_reflection(Gogo*, std::string*) const
go_assert(saw_errors());
}
-// Mangled name.
-
-void
-Complex_type::do_mangled_name(Gogo*, std::string* ret) const
-{
- char buf[100];
- snprintf(buf, sizeof buf, "c%s%de",
- this->is_abstract_ ? "a" : "",
- this->bits_);
- ret->append(buf);
-}
-
// Make a complex type.
Named_type*
@@ -4428,14 +4241,6 @@ String_type::do_reflection(Gogo*, std::string* ret) const
ret->append("string");
}
-// Mangled name of a string type.
-
-void
-String_type::do_mangled_name(Gogo*, std::string* ret) const
-{
- ret->push_back('z');
-}
-
// Make a string type.
Type*
@@ -5082,46 +4887,6 @@ Function_type::do_reflection(Gogo* gogo, std::string* ret) const
}
}
-// Mangled name.
-
-void
-Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('F');
-
- if (this->receiver_ != NULL)
- {
- ret->push_back('m');
- this->append_mangled_name(this->receiver_->type(), gogo, ret);
- }
-
- const Typed_identifier_list* params = this->parameters();
- if (params != NULL)
- {
- ret->push_back('p');
- for (Typed_identifier_list::const_iterator p = params->begin();
- p != params->end();
- ++p)
- this->append_mangled_name(p->type(), gogo, ret);
- if (this->is_varargs_)
- ret->push_back('V');
- ret->push_back('e');
- }
-
- const Typed_identifier_list* results = this->results();
- if (results != NULL)
- {
- ret->push_back('r');
- for (Typed_identifier_list::const_iterator p = results->begin();
- p != results->end();
- ++p)
- this->append_mangled_name(p->type(), gogo, ret);
- ret->push_back('e');
- }
-
- ret->push_back('e');
-}
-
// Export a function type.
void
@@ -5484,13 +5249,6 @@ Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->to_type_, gogo, ret);
}
-void
-Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('p');
- this->append_mangled_name(this->to_type_, gogo, ret);
-}
-
// Export.
void
@@ -5572,38 +5330,16 @@ Type::finish_pointer_types(Gogo* gogo)
}
}
-// The nil type. We use a special type for nil because it is not the
-// same as any other type. In C term nil has type void*, but there is
-// no such type in Go.
-
-class Nil_type : public Type
-{
- public:
- Nil_type()
- : Type(TYPE_NIL)
- { }
-
- protected:
- bool
- do_compare_is_identity(Gogo*)
- { return false; }
-
- Btype*
- do_get_backend(Gogo* gogo)
- { return gogo->backend()->pointer_type(gogo->backend()->void_type()); }
+// Class Nil_type.
- Expression*
- do_type_descriptor(Gogo*, Named_type*)
- { go_unreachable(); }
+// Get the backend representation of a nil type. FIXME: Is this ever
+// actually called?
- void
- do_reflection(Gogo*, std::string*) const
- { go_unreachable(); }
-
- void
- do_mangled_name(Gogo*, std::string* ret) const
- { ret->push_back('n'); }
-};
+Btype*
+Nil_type::do_get_backend(Gogo* gogo)
+{
+ return gogo->backend()->pointer_type(gogo->backend()->void_type());
+}
// Make the nil type.
@@ -5842,7 +5578,9 @@ Struct_type::do_verify()
Type* t = p->type();
if (p->is_anonymous())
{
- if (t->named_type() != NULL && t->points_to() != NULL)
+ if ((t->named_type() != NULL && t->points_to() != NULL)
+ || (t->named_type() == NULL && t->points_to() != NULL
+ && t->points_to()->points_to() != NULL))
{
go_error_at(p->location(), "embedded type may not be a pointer");
p->set_type(Type::make_error_type());
@@ -6690,74 +6428,6 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->push_back('}');
}
-// Mangled name.
-
-void
-Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('S');
-
- const Struct_field_list* fields = this->fields_;
- if (fields != NULL)
- {
- for (Struct_field_list::const_iterator p = fields->begin();
- p != fields->end();
- ++p)
- {
- if (p->is_anonymous())
- ret->append("0_");
- else
- {
-
- std::string n(Gogo::mangle_possibly_hidden_name(p->field_name()));
- char buf[20];
- snprintf(buf, sizeof buf, "%u_",
- static_cast<unsigned int>(n.length()));
- ret->append(buf);
- ret->append(n);
- }
-
- // For an anonymous field with an alias type, the field name
- // is the alias name.
- if (p->is_anonymous()
- && p->type()->named_type() != NULL
- && p->type()->named_type()->is_alias())
- p->type()->named_type()->append_mangled_type_name(gogo, true, ret);
- else
- this->append_mangled_name(p->type(), gogo, ret);
- if (p->has_tag())
- {
- const std::string& tag(p->tag());
- std::string out;
- for (std::string::const_iterator p = tag.begin();
- p != tag.end();
- ++p)
- {
- if (ISALNUM(*p) || *p == '_')
- out.push_back(*p);
- else
- {
- char buf[20];
- snprintf(buf, sizeof buf, ".%x.",
- static_cast<unsigned int>(*p));
- out.append(buf);
- }
- }
- char buf[20];
- snprintf(buf, sizeof buf, "T%u_",
- static_cast<unsigned int>(out.length()));
- ret->append(buf);
- ret->append(out);
- }
- }
- }
-
- if (this->is_struct_incomparable_)
- ret->push_back('x');
-
- ret->push_back('e');
-}
-
// If the offset of field INDEX in the backend implementation can be
// determined, set *POFFSET to the offset in bytes and return true.
// Otherwise, return false.
@@ -7949,37 +7619,6 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->element_type_, gogo, ret);
}
-// Mangled name.
-
-void
-Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('A');
- this->append_mangled_name(this->element_type_, gogo, ret);
- if (this->length_ != NULL)
- {
- Numeric_constant nc;
- if (!this->length_->numeric_constant_value(&nc))
- {
- go_assert(saw_errors());
- return;
- }
- mpz_t val;
- if (!nc.to_int(&val))
- {
- go_assert(saw_errors());
- return;
- }
- char *s = mpz_get_str(NULL, 10, val);
- ret->append(s);
- free(s);
- mpz_clear(val);
- if (this->is_array_incomparable_)
- ret->push_back('x');
- }
- ret->push_back('e');
-}
-
// Make an array type.
Array_type*
@@ -8035,8 +7674,8 @@ Map_type::fat_zero_value(Gogo* gogo)
Array_type* array_type = Type::make_array_type(uint8_type, size);
array_type->set_is_array_incomparable();
Variable* var = new Variable(array_type, NULL, true, false, false, bloc);
- Map_type::zero_value = Named_object::make_variable("go$zerovalue", NULL,
- var);
+ std::string name = gogo->map_zero_value_name();
+ Map_type::zero_value = Named_object::make_variable(name, NULL, var);
}
Expression* z = Expression::make_var_reference(Map_type::zero_value, bloc);
@@ -8580,17 +8219,6 @@ Map_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->val_type_, gogo, ret);
}
-// Mangled name for a map.
-
-void
-Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('M');
- this->append_mangled_name(this->key_type_, gogo, ret);
- ret->append("__");
- this->append_mangled_name(this->val_type_, gogo, ret);
-}
-
// Export a map type.
void
@@ -8763,20 +8391,6 @@ Channel_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->element_type_, gogo, ret);
}
-// Mangled name.
-
-void
-Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- ret->push_back('C');
- this->append_mangled_name(this->element_type_, gogo, ret);
- if (this->may_send_)
- ret->push_back('s');
- if (this->may_receive_)
- ret->push_back('r');
- ret->push_back('e');
-}
-
// Export.
void
@@ -9700,40 +9314,6 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const
ret->append("}");
}
-// Mangled name.
-
-void
-Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- go_assert(this->methods_are_finalized_);
-
- ret->push_back('I');
-
- const Typed_identifier_list* methods = this->all_methods_;
- if (methods != NULL && !this->seen_)
- {
- this->seen_ = true;
- for (Typed_identifier_list::const_iterator p = methods->begin();
- p != methods->end();
- ++p)
- {
- if (!p->name().empty())
- {
- std::string n(Gogo::mangle_possibly_hidden_name(p->name()));
- char buf[20];
- snprintf(buf, sizeof buf, "%u_",
- static_cast<unsigned int>(n.length()));
- ret->append(buf);
- ret->append(n);
- }
- this->append_mangled_name(p->type(), gogo, ret);
- }
- this->seen_ = false;
- }
-
- ret->push_back('e');
-}
-
// Export.
void
@@ -11176,71 +10756,6 @@ Named_type::append_reflection_type_name(Gogo* gogo, bool use_alias,
ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
}
-// Get the mangled name.
-
-void
-Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- this->append_mangled_type_name(gogo, false, ret);
-}
-
-// Get the mangled name. For an alias we normally get the real name,
-// but if USE_ALIAS is true we use the alias name itself.
-
-void
-Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias,
- std::string* ret) const
-{
- if (this->is_error_)
- return;
- if (this->is_alias_ && !use_alias)
- {
- if (this->seen_alias_)
- return;
- this->seen_alias_ = true;
- this->append_mangled_name(this->type_, gogo, ret);
- this->seen_alias_ = false;
- return;
- }
- Named_object* no = this->named_object_;
- std::string name;
- if (this->is_builtin())
- go_assert(this->in_function_ == NULL);
- else
- {
- const std::string& pkgpath(no->package() == NULL
- ? gogo->pkgpath_symbol()
- : no->package()->pkgpath_symbol());
- name = pkgpath;
- name.append(1, '.');
- if (this->in_function_ != NULL)
- {
- const Typed_identifier* rcvr =
- this->in_function_->func_value()->type()->receiver();
- if (rcvr != NULL)
- {
- Named_type* rcvr_type = rcvr->type()->deref()->named_type();
- name.append(Gogo::unpack_hidden_name(rcvr_type->name()));
- name.append(1, '.');
- }
- name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
- name.append(1, '$');
- if (this->in_function_index_ > 0)
- {
- char buf[30];
- snprintf(buf, sizeof buf, "%u", this->in_function_index_);
- name.append(buf);
- name.append(1, '$');
- }
- }
- }
- name.append(Gogo::unpack_hidden_name(no->name()));
- char buf[20];
- snprintf(buf, sizeof buf, "N%u_", static_cast<unsigned int>(name.length()));
- ret->append(buf);
- ret->append(name);
-}
-
// Export the type. This is called to export a global type.
void
@@ -11621,7 +11136,7 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods,
package = NULL;
else
package = type->named_type()->named_object()->package();
- std::string stub_name = name + "$stub";
+ std::string stub_name = gogo->stub_method_name(name);
Named_object* stub;
if (package != NULL)
stub = Named_object::make_function_declaration(stub_name, package,
@@ -11848,6 +11363,12 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
go_assert(expr->type()->struct_type() == st);
}
ret = st->field_reference(expr, name, location);
+ if (ret == NULL)
+ {
+ go_error_at(location, "type has no field %qs",
+ Gogo::message_name(name).c_str());
+ return Expression::make_error(location);
+ }
}
else if (it != NULL && it->find_method(name) != NULL)
ret = Expression::make_interface_field_reference(expr, name,
@@ -12445,31 +11966,6 @@ Forward_declaration_type::do_reflection(Gogo* gogo, std::string* ret) const
this->append_reflection(this->real_type(), gogo, ret);
}
-// The mangled name.
-
-void
-Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const
-{
- if (this->is_defined())
- this->append_mangled_name(this->real_type(), gogo, ret);
- else
- {
- const Named_object* no = this->named_object();
- std::string name;
- if (no->package() == NULL)
- name = gogo->pkgpath_symbol();
- else
- name = no->package()->pkgpath_symbol();
- name += '.';
- name += Gogo::unpack_hidden_name(no->name());
- char buf[20];
- snprintf(buf, sizeof buf, "N%u_",
- static_cast<unsigned int>(name.length()));
- ret->append(buf);
- ret->append(name);
- }
-}
-
// Export a forward declaration. This can happen when a defined type
// refers to a type which is only declared (and is presumably defined
// in some other file in the same package).
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index f15f08a..a1e3884 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -1213,11 +1213,6 @@ class Type
void
make_gc_symbol_var(Gogo*);
- // Return the name of the type descriptor variable. If NAME is not
- // NULL, it is the name to use.
- std::string
- type_descriptor_var_name(Gogo*, Named_type* name);
-
// Return true if the type descriptor for this type should be
// defined in some other package. If NAME is not NULL, it is the
// name of this type. If this returns true it sets *PACKAGE to the
@@ -1558,6 +1553,92 @@ class Typed_identifier_list
std::vector<Typed_identifier> entries_;
};
+// A type used to indicate a parsing error. This exists to simplify
+// later error detection.
+
+class Error_type : public Type
+{
+ public:
+ Error_type()
+ : Type(TYPE_ERROR)
+ { }
+
+ protected:
+ bool
+ do_compare_is_identity(Gogo*)
+ { return false; }
+
+ Btype*
+ do_get_backend(Gogo* gogo);
+
+ Expression*
+ do_type_descriptor(Gogo*, Named_type*);
+
+ void
+ do_reflection(Gogo*, std::string*) const;
+
+ void
+ do_mangled_name(Gogo*, std::string* ret) const;
+};
+
+// The void type.
+
+class Void_type : public Type
+{
+ public:
+ Void_type()
+ : Type(TYPE_VOID)
+ { }
+
+ protected:
+ bool
+ do_compare_is_identity(Gogo*)
+ { return false; }
+
+ Btype*
+ do_get_backend(Gogo* gogo);
+
+ Expression*
+ do_type_descriptor(Gogo*, Named_type*)
+ { go_unreachable(); }
+
+ void
+ do_reflection(Gogo*, std::string*) const
+ { }
+
+ void
+ do_mangled_name(Gogo*, std::string* ret) const;
+};
+
+// The boolean type.
+
+class Boolean_type : public Type
+{
+ public:
+ Boolean_type()
+ : Type(TYPE_BOOLEAN)
+ { }
+
+ protected:
+ bool
+ do_compare_is_identity(Gogo*)
+ { return true; }
+
+ Btype*
+ do_get_backend(Gogo* gogo);
+
+ Expression*
+ do_type_descriptor(Gogo*, Named_type* name);
+
+ // We should not be asked for the reflection string of a basic type.
+ void
+ do_reflection(Gogo*, std::string* ret) const
+ { ret->append("bool"); }
+
+ void
+ do_mangled_name(Gogo*, std::string* ret) const;
+};
+
// The type of an integer.
class Integer_type : public Type
@@ -2143,6 +2224,37 @@ class Pointer_type : public Type
Type* to_type_;
};
+// The nil type. We use a special type for nil because it is not the
+// same as any other type. In C term nil has type void*, but there is
+// no such type in Go.
+
+class Nil_type : public Type
+{
+ public:
+ Nil_type()
+ : Type(TYPE_NIL)
+ { }
+
+ protected:
+ bool
+ do_compare_is_identity(Gogo*)
+ { return false; }
+
+ Btype*
+ do_get_backend(Gogo* gogo);
+
+ Expression*
+ do_type_descriptor(Gogo*, Named_type*)
+ { go_unreachable(); }
+
+ void
+ do_reflection(Gogo*, std::string*) const
+ { go_unreachable(); }
+
+ void
+ do_mangled_name(Gogo*, std::string* ret) const;
+};
+
// The type of a field in a struct.
class Struct_field
diff --git a/gcc/godump.c b/gcc/godump.c
index 28d81a1..9a9d70f 100644
--- a/gcc/godump.c
+++ b/gcc/godump.c
@@ -1159,7 +1159,7 @@ go_output_typedef (struct godump_container *container, tree decl)
snprintf (buf, sizeof buf, HOST_WIDE_INT_PRINT_UNSIGNED,
tree_to_uhwi (TREE_VALUE (element)));
else
- print_hex (element, buf);
+ print_hex (wi::to_wide (element), buf);
mhval->value = xstrdup (buf);
*slot = mhval;
diff --git a/gcc/graphite-dependences.c b/gcc/graphite-dependences.c
index 4ed9d00..bd3e91b 100644
--- a/gcc/graphite-dependences.c
+++ b/gcc/graphite-dependences.c
@@ -63,20 +63,21 @@ add_pdr_constraints (poly_dr_p pdr, poly_bb_p pbb)
return constrain_domain (x, isl_set_copy (pbb->domain));
}
-/* Returns all the memory reads in SCOP. */
+/* Returns an isl description of all memory operations in SCOP. The memory
+ reads are returned in READS and writes in MUST_WRITES and MAY_WRITES. */
-static isl_union_map *
-scop_get_reads (scop_p scop)
+static void
+scop_get_reads_and_writes (scop_p scop, isl_union_map *&reads,
+ isl_union_map *&must_writes,
+ isl_union_map *&may_writes)
{
int i, j;
poly_bb_p pbb;
poly_dr_p pdr;
- isl_space *space = isl_set_get_space (scop->param_context);
- isl_union_map *res = isl_union_map_empty (space);
FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
{
- FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
+ FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr) {
if (pdr_read_p (pdr))
{
if (dump_file)
@@ -86,33 +87,14 @@ scop_get_reads (scop_p scop)
}
isl_union_map *um
= isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
- res = isl_union_map_union (res, um);
+ reads = isl_union_map_union (reads, um);
if (dump_file)
{
fprintf (dump_file, "Reads depedence graph: ");
- print_isl_union_map (dump_file, res);
+ print_isl_union_map (dump_file, reads);
}
}
- }
-
- return isl_union_map_coalesce (res);
-}
-
-/* Returns all the memory must writes in SCOP. */
-
-static isl_union_map *
-scop_get_must_writes (scop_p scop)
-{
- int i, j;
- poly_bb_p pbb;
- poly_dr_p pdr;
- isl_space *space = isl_set_get_space (scop->param_context);
- isl_union_map *res = isl_union_map_empty (space);
-
- FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
- {
- FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
- if (pdr_write_p (pdr))
+ else if (pdr_write_p (pdr))
{
if (dump_file)
{
@@ -121,33 +103,14 @@ scop_get_must_writes (scop_p scop)
}
isl_union_map *um
= isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
- res = isl_union_map_union (res, um);
+ must_writes = isl_union_map_union (must_writes, um);
if (dump_file)
{
fprintf (dump_file, "Must writes depedence graph: ");
- print_isl_union_map (dump_file, res);
+ print_isl_union_map (dump_file, must_writes);
}
}
- }
-
- return isl_union_map_coalesce (res);
-}
-
-/* Returns all the memory may writes in SCOP. */
-
-static isl_union_map *
-scop_get_may_writes (scop_p scop)
-{
- int i, j;
- poly_bb_p pbb;
- poly_dr_p pdr;
- isl_space *space = isl_set_get_space (scop->param_context);
- isl_union_map *res = isl_union_map_empty (space);
-
- FOR_EACH_VEC_ELT (scop->pbbs, i, pbb)
- {
- FOR_EACH_VEC_ELT (PBB_DRS (pbb), j, pdr)
- if (pdr_may_write_p (pdr))
+ else if (pdr_may_write_p (pdr))
{
if (dump_file)
{
@@ -156,16 +119,15 @@ scop_get_may_writes (scop_p scop)
}
isl_union_map *um
= isl_union_map_from_map (add_pdr_constraints (pdr, pbb));
- res = isl_union_map_union (res, um);
+ may_writes = isl_union_map_union (may_writes, um);
if (dump_file)
{
fprintf (dump_file, "May writes depedence graph: ");
- print_isl_union_map (dump_file, res);
+ print_isl_union_map (dump_file, may_writes);
}
}
+ }
}
-
- return isl_union_map_coalesce (res);
}
/* Helper function used on each MAP of a isl_union_map. Computes the
@@ -300,9 +262,11 @@ scop_get_dependences (scop_p scop)
if (scop->dependence)
return;
- isl_union_map *reads = scop_get_reads (scop);
- isl_union_map *must_writes = scop_get_must_writes (scop);
- isl_union_map *may_writes = scop_get_may_writes (scop);
+ isl_space *space = isl_set_get_space (scop->param_context);
+ isl_union_map *reads = isl_union_map_empty (isl_space_copy (space));
+ isl_union_map *must_writes = isl_union_map_empty (isl_space_copy (space));
+ isl_union_map *may_writes = isl_union_map_empty (space);
+ scop_get_reads_and_writes (scop, reads, must_writes, may_writes);
if (dump_file)
{
diff --git a/gcc/graphite-isl-ast-to-gimple.c b/gcc/graphite-isl-ast-to-gimple.c
index 964d6c9..16570e1 100644
--- a/gcc/graphite-isl-ast-to-gimple.c
+++ b/gcc/graphite-isl-ast-to-gimple.c
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfghooks.h"
#include "tree.h"
#include "gimple.h"
+#include "ssa.h"
#include "params.h"
#include "fold-const.h"
#include "gimple-fold.h"
@@ -54,17 +55,10 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-pretty-print.h"
#include "cfganal.h"
#include "value-prof.h"
+#include "tree-ssa.h"
+#include "tree-vectorizer.h"
#include "graphite.h"
-/* We always try to use signed 128 bit types, but fall back to smaller types
- in case a platform does not provide types of these sizes. In the future we
- should use isl to derive the optimal type for each subexpression. */
-
-static int max_mode_int_precision =
- GET_MODE_PRECISION (int_mode_for_size (MAX_FIXED_MODE_SIZE, 0).require ());
-static int graphite_expression_type_precision = 128 <= max_mode_int_precision ?
- 128 : max_mode_int_precision;
-
struct ast_build_info
{
ast_build_info()
@@ -73,15 +67,6 @@ struct ast_build_info
bool is_parallelizable;
};
-/* Verifies properties that GRAPHITE should maintain during translation. */
-
-static inline void
-graphite_verify (void)
-{
- checking_verify_loop_structure ();
- checking_verify_loop_closed_ssa (true);
-}
-
/* IVS_PARAMS maps isl's scattering and parameter identifiers
to corresponding trees. */
@@ -150,8 +135,7 @@ enum phi_node_kind
class translate_isl_ast_to_gimple
{
public:
- translate_isl_ast_to_gimple (sese_info_p r)
- : region (r), codegen_error (false) { }
+ translate_isl_ast_to_gimple (sese_info_p r);
edge translate_isl_ast (loop_p context_loop, __isl_keep isl_ast_node *node,
edge next_e, ivs_params &ip);
edge translate_isl_ast_node_for (loop_p context_loop,
@@ -184,6 +168,7 @@ class translate_isl_ast_to_gimple
tree gcc_expression_from_isl_ast_expr_id (tree type,
__isl_keep isl_ast_expr *expr_id,
ivs_params &ip);
+ widest_int widest_int_from_isl_expr_int (__isl_keep isl_ast_expr *expr);
tree gcc_expression_from_isl_expr_int (tree type,
__isl_take isl_ast_expr *expr);
tree gcc_expression_from_isl_expr_op (tree type,
@@ -193,66 +178,34 @@ class translate_isl_ast_to_gimple
__isl_keep isl_ast_node *node_for,
loop_p outer, tree type,
tree lb, tree ub, ivs_params &ip);
- edge graphite_create_new_loop_guard (edge entry_edge,
- __isl_keep isl_ast_node *node_for,
- tree *type,
- tree *lb, tree *ub, ivs_params &ip);
edge graphite_create_new_guard (edge entry_edge,
__isl_take isl_ast_expr *if_cond,
ivs_params &ip);
void build_iv_mapping (vec<tree> iv_map, gimple_poly_bb_p gbb,
__isl_keep isl_ast_expr *user_expr, ivs_params &ip,
sese_l &region);
- void translate_pending_phi_nodes (void);
void add_parameters_to_ivs_params (scop_p scop, ivs_params &ip);
__isl_give isl_ast_build *generate_isl_context (scop_p scop);
__isl_give isl_ast_node * scop_to_isl_ast (scop_p scop);
- bool is_valid_rename (tree rename, basic_block def_bb, basic_block use_bb,
- phi_node_kind, tree old_name, basic_block old_bb) const;
- tree get_rename (basic_block new_bb, tree old_name,
- basic_block old_bb, phi_node_kind) const;
tree get_rename_from_scev (tree old_name, gimple_seq *stmts, loop_p loop,
- basic_block new_bb, basic_block old_bb,
vec<tree> iv_map);
- basic_block get_def_bb_for_const (basic_block bb, basic_block old_bb) const;
- tree get_new_name (basic_block new_bb, tree op,
- basic_block old_bb, phi_node_kind) const;
- void collect_all_ssa_names (tree new_expr, vec<tree> *vec_ssa);
- bool copy_loop_phi_args (gphi *old_phi, init_back_edge_pair_t &ibp_old_bb,
- gphi *new_phi, init_back_edge_pair_t &ibp_new_bb,
- bool postpone);
- bool copy_loop_phi_nodes (basic_block bb, basic_block new_bb);
- bool add_close_phis_to_merge_points (gphi *old_phi, gphi *new_phi,
- tree default_value);
- tree add_close_phis_to_outer_loops (tree last_merge_name, edge merge_e,
- gimple *old_close_phi);
- bool copy_loop_close_phi_args (basic_block old_bb, basic_block new_bb,
- vec<tree> iv_map, bool postpone);
- bool copy_loop_close_phi_nodes (basic_block old_bb, basic_block new_bb,
- vec<tree> iv_map);
- bool copy_cond_phi_args (gphi *phi, gphi *new_phi, vec<tree> iv_map,
- bool postpone);
- bool copy_cond_phi_nodes (basic_block bb, basic_block new_bb,
- vec<tree> iv_map);
- bool graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb,
+ void graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb,
vec<tree> iv_map);
edge copy_bb_and_scalar_dependences (basic_block bb, edge next_e,
vec<tree> iv_map);
- edge edge_for_new_close_phis (basic_block bb);
- bool add_phi_arg_for_new_expr (tree old_phi_args[2], tree new_phi_args[2],
- edge old_bb_dominating_edge,
- edge old_bb_non_dominating_edge,
- gphi *phi, gphi *new_phi,
- basic_block new_bb);
- bool rename_uses (gimple *copy, gimple_stmt_iterator *gsi_tgt,
- basic_block old_bb, loop_p loop, vec<tree> iv_map);
void set_rename (tree old_name, tree expr);
- void set_rename_for_each_def (gimple *stmt);
void gsi_insert_earliest (gimple_seq seq);
- tree rename_all_uses (tree new_expr, basic_block new_bb, basic_block old_bb);
bool codegen_error_p () const { return codegen_error; }
+
+ void set_codegen_error ()
+ {
+ codegen_error = true;
+ gcc_assert (! flag_checking
+ || PARAM_VALUE (PARAM_GRAPHITE_ALLOW_CODEGEN_ERRORS));
+ }
+
bool is_constant (tree op) const
{
return TREE_CODE (op) == INTEGER_CST
@@ -271,8 +224,24 @@ private:
/* A vector of all the edges at if_condition merge points. */
auto_vec<edge, 2> merge_points;
+
+ tree graphite_expr_type;
};
+translate_isl_ast_to_gimple::translate_isl_ast_to_gimple (sese_info_p r)
+ : region (r), codegen_error (false)
+{
+ /* We always try to use signed 128 bit types, but fall back to smaller types
+ in case a platform does not provide types of these sizes. In the future we
+ should use isl to derive the optimal type for each subexpression. */
+ int max_mode_int_precision
+ = GET_MODE_PRECISION (int_mode_for_size (MAX_FIXED_MODE_SIZE, 0).require ());
+ int graphite_expr_type_precision
+ = 128 <= max_mode_int_precision ? 128 : max_mode_int_precision;
+ graphite_expr_type
+ = build_nonstandard_integer_type (graphite_expr_type_precision, 0);
+}
+
/* Return the tree variable that corresponds to the given isl ast identifier
expression (an isl_ast_expr of type isl_ast_expr_id).
@@ -295,36 +264,51 @@ gcc_expression_from_isl_ast_expr_id (tree type,
"Could not map isl_id to tree expression");
isl_ast_expr_free (expr_id);
tree t = res->second;
- tree *val = region->parameter_rename_map->get(t);
-
- if (!val)
- val = &t;
- return fold_convert (type, *val);
+ if (useless_type_conversion_p (type, TREE_TYPE (t)))
+ return t;
+ return fold_convert (type, t);
}
-/* Converts an isl_ast_expr_int expression E to a GCC expression tree of
- type TYPE. */
+/* Converts an isl_ast_expr_int expression E to a widest_int.
+ Raises a code generation error when the constant doesn't fit. */
-tree translate_isl_ast_to_gimple::
-gcc_expression_from_isl_expr_int (tree type, __isl_take isl_ast_expr *expr)
+widest_int translate_isl_ast_to_gimple::
+widest_int_from_isl_expr_int (__isl_keep isl_ast_expr *expr)
{
gcc_assert (isl_ast_expr_get_type (expr) == isl_ast_expr_int);
isl_val *val = isl_ast_expr_get_val (expr);
size_t n = isl_val_n_abs_num_chunks (val, sizeof (HOST_WIDE_INT));
HOST_WIDE_INT *chunks = XALLOCAVEC (HOST_WIDE_INT, n);
- tree res;
- if (isl_val_get_abs_num_chunks (val, sizeof (HOST_WIDE_INT), chunks) == -1)
- res = NULL_TREE;
- else
+ if (n > WIDE_INT_MAX_ELTS
+ || isl_val_get_abs_num_chunks (val, sizeof (HOST_WIDE_INT), chunks) == -1)
{
- widest_int wi = widest_int::from_array (chunks, n, true);
- if (isl_val_is_neg (val))
- wi = -wi;
- res = wide_int_to_tree (type, wi);
+ isl_val_free (val);
+ set_codegen_error ();
+ return 0;
}
+ widest_int wi = widest_int::from_array (chunks, n, true);
+ if (isl_val_is_neg (val))
+ wi = -wi;
isl_val_free (val);
+ return wi;
+}
+
+/* Converts an isl_ast_expr_int expression E to a GCC expression tree of
+ type TYPE. Raises a code generation error when the constant doesn't fit. */
+
+tree translate_isl_ast_to_gimple::
+gcc_expression_from_isl_expr_int (tree type, __isl_take isl_ast_expr *expr)
+{
+ widest_int wi = widest_int_from_isl_expr_int (expr);
isl_ast_expr_free (expr);
- return res;
+ if (codegen_error_p ())
+ return NULL_TREE;
+ if (wi::min_precision (wi, TYPE_SIGN (type)) > TYPE_PRECISION (type))
+ {
+ set_codegen_error ();
+ return NULL_TREE;
+ }
+ return wide_int_to_tree (type, wi);
}
/* Converts a binary isl_ast_expr_op expression E to a GCC expression tree of
@@ -333,14 +317,25 @@ gcc_expression_from_isl_expr_int (tree type, __isl_take isl_ast_expr *expr)
tree translate_isl_ast_to_gimple::
binary_op_to_tree (tree type, __isl_take isl_ast_expr *expr, ivs_params &ip)
{
+ enum isl_ast_op_type expr_type = isl_ast_expr_get_op_type (expr);
isl_ast_expr *arg_expr = isl_ast_expr_get_op_arg (expr, 0);
tree tree_lhs_expr = gcc_expression_from_isl_expression (type, arg_expr, ip);
arg_expr = isl_ast_expr_get_op_arg (expr, 1);
- tree tree_rhs_expr = gcc_expression_from_isl_expression (type, arg_expr, ip);
-
- enum isl_ast_op_type expr_type = isl_ast_expr_get_op_type (expr);
isl_ast_expr_free (expr);
+ /* From our constraint generation we may get modulo operations that
+ we cannot represent explicitely but that are no-ops for TYPE.
+ Elide those. */
+ if (expr_type == isl_ast_op_pdiv_r
+ && isl_ast_expr_get_type (arg_expr) == isl_ast_expr_int
+ && (wi::exact_log2 (widest_int_from_isl_expr_int (arg_expr))
+ >= TYPE_PRECISION (type)))
+ {
+ isl_ast_expr_free (arg_expr);
+ return tree_lhs_expr;
+ }
+
+ tree tree_rhs_expr = gcc_expression_from_isl_expression (type, arg_expr, ip);
if (codegen_error_p ())
return NULL_TREE;
@@ -356,44 +351,16 @@ binary_op_to_tree (tree type, __isl_take isl_ast_expr *expr, ivs_params &ip)
return fold_build2 (MULT_EXPR, type, tree_lhs_expr, tree_rhs_expr);
case isl_ast_op_div:
- /* As isl operates on arbitrary precision numbers, we may end up with
- division by 2^64 that is folded to 0. */
- if (integer_zerop (tree_rhs_expr))
- {
- codegen_error = true;
- return NULL_TREE;
- }
return fold_build2 (EXACT_DIV_EXPR, type, tree_lhs_expr, tree_rhs_expr);
case isl_ast_op_pdiv_q:
- /* As isl operates on arbitrary precision numbers, we may end up with
- division by 2^64 that is folded to 0. */
- if (integer_zerop (tree_rhs_expr))
- {
- codegen_error = true;
- return NULL_TREE;
- }
return fold_build2 (TRUNC_DIV_EXPR, type, tree_lhs_expr, tree_rhs_expr);
case isl_ast_op_zdiv_r:
case isl_ast_op_pdiv_r:
- /* As isl operates on arbitrary precision numbers, we may end up with
- division by 2^64 that is folded to 0. */
- if (integer_zerop (tree_rhs_expr))
- {
- codegen_error = true;
- return NULL_TREE;
- }
return fold_build2 (TRUNC_MOD_EXPR, type, tree_lhs_expr, tree_rhs_expr);
case isl_ast_op_fdiv_q:
- /* As isl operates on arbitrary precision numbers, we may end up with
- division by 2^64 that is folded to 0. */
- if (integer_zerop (tree_rhs_expr))
- {
- codegen_error = true;
- return NULL_TREE;
- }
return fold_build2 (FLOOR_DIV_EXPR, type, tree_lhs_expr, tree_rhs_expr);
case isl_ast_op_and:
@@ -731,71 +698,6 @@ get_upper_bound (__isl_keep isl_ast_node *node_for)
return res;
}
-/* All loops generated by create_empty_loop_on_edge have the form of
- a post-test loop:
-
- do
-
- {
- body of the loop;
- } while (lower bound < upper bound);
-
- We create a new if region protecting the loop to be executed, if
- the execution count is zero (lower bound > upper bound). */
-
-edge translate_isl_ast_to_gimple::
-graphite_create_new_loop_guard (edge entry_edge,
- __isl_keep isl_ast_node *node_for, tree *type,
- tree *lb, tree *ub, ivs_params &ip)
-{
- gcc_assert (isl_ast_node_get_type (node_for) == isl_ast_node_for);
- tree cond_expr;
- edge exit_edge;
-
- *type =
- build_nonstandard_integer_type (graphite_expression_type_precision, 0);
- isl_ast_expr *for_init = isl_ast_node_for_get_init (node_for);
- *lb = gcc_expression_from_isl_expression (*type, for_init, ip);
-
- /* To fail code generation, we generate wrong code until we discard it. */
- if (codegen_error_p ())
- *lb = integer_zero_node;
-
- isl_ast_expr *upper_bound = get_upper_bound (node_for);
- *ub = gcc_expression_from_isl_expression (*type, upper_bound, ip);
-
- /* To fail code generation, we generate wrong code until we discard it. */
- if (codegen_error_p ())
- *ub = integer_zero_node;
-
- /* When ub is simply a constant or a parameter, use lb <= ub. */
- if (TREE_CODE (*ub) == INTEGER_CST || TREE_CODE (*ub) == SSA_NAME)
- cond_expr = fold_build2 (LE_EXPR, boolean_type_node, *lb, *ub);
- else
- {
- tree one = (POINTER_TYPE_P (*type)
- ? convert_to_ptrofftype (integer_one_node)
- : fold_convert (*type, integer_one_node));
- /* Adding +1 and using LT_EXPR helps with loop latches that have a
- loop iteration count of "PARAMETER - 1". For PARAMETER == 0 this
- becomes 2^k-1 due to integer overflow, and the condition lb <= ub
- is true, even if we do not want this. However lb < ub + 1 is false,
- as expected. */
- tree ub_one = fold_build2 (POINTER_TYPE_P (*type) ? POINTER_PLUS_EXPR
- : PLUS_EXPR, *type, *ub, one);
-
- cond_expr = fold_build2 (LT_EXPR, boolean_type_node, *lb, ub_one);
- }
-
- if (integer_onep (cond_expr))
- exit_edge = entry_edge;
- else
- exit_edge = create_empty_if_region_on_edge (entry_edge,
- unshare_expr (cond_expr));
-
- return exit_edge;
-}
-
/* Translates an isl_ast_node_for to Gimple. */
edge translate_isl_ast_to_gimple::
@@ -803,26 +705,23 @@ translate_isl_ast_node_for (loop_p context_loop, __isl_keep isl_ast_node *node,
edge next_e, ivs_params &ip)
{
gcc_assert (isl_ast_node_get_type (node) == isl_ast_node_for);
- tree type, lb, ub;
- edge last_e = graphite_create_new_loop_guard (next_e, node, &type,
- &lb, &ub, ip);
-
- if (last_e == next_e)
- {
- /* There was no guard generated. */
- last_e = single_succ_edge (split_edge (last_e));
-
- translate_isl_ast_for_loop (context_loop, node, next_e,
- type, lb, ub, ip);
- return last_e;
- }
+ tree type = graphite_expr_type;
- edge true_e = get_true_edge_from_guard_bb (next_e->dest);
- merge_points.safe_push (last_e);
+ isl_ast_expr *for_init = isl_ast_node_for_get_init (node);
+ tree lb = gcc_expression_from_isl_expression (type, for_init, ip);
+ /* To fail code generation, we generate wrong code until we discard it. */
+ if (codegen_error_p ())
+ lb = integer_zero_node;
- last_e = single_succ_edge (split_edge (last_e));
- translate_isl_ast_for_loop (context_loop, node, true_e, type, lb, ub, ip);
+ isl_ast_expr *upper_bound = get_upper_bound (node);
+ tree ub = gcc_expression_from_isl_expression (type, upper_bound, ip);
+ /* To fail code generation, we generate wrong code until we discard it. */
+ if (codegen_error_p ())
+ ub = integer_zero_node;
+ edge last_e = single_succ_edge (split_edge (next_e));
+ translate_isl_ast_for_loop (context_loop, node, next_e,
+ type, lb, ub, ip);
return last_e;
}
@@ -845,8 +744,7 @@ build_iv_mapping (vec<tree> iv_map, gimple_poly_bb_p gbb,
for (i = 1; i < isl_ast_expr_get_op_n_arg (user_expr); i++)
{
arg_expr = isl_ast_expr_get_op_arg (user_expr, i);
- tree type =
- build_nonstandard_integer_type (graphite_expression_type_precision, 0);
+ tree type = graphite_expr_type;
tree t = gcc_expression_from_isl_expression (type, arg_expr, ip);
/* To fail code generation, we generate wrong code until we discard it. */
@@ -893,13 +791,12 @@ translate_isl_ast_node_user (__isl_keep isl_ast_node *node,
isl_ast_expr_free (user_expr);
basic_block old_bb = GBB_BB (gbb);
- if (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file,
"[codegen] copying from bb_%d on edge (bb_%d, bb_%d)\n",
old_bb->index, next_e->src->index, next_e->dest->index);
print_loops_bb (dump_file, GBB_BB (gbb), 0, 3);
-
}
next_e = copy_bb_and_scalar_dependences (old_bb, next_e, iv_map);
@@ -909,7 +806,7 @@ translate_isl_ast_node_user (__isl_keep isl_ast_node *node,
if (codegen_error_p ())
return NULL;
- if (dump_file)
+ if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "[codegen] (after copy) new basic block\n");
print_loops_bb (dump_file, next_e->src, 0, 3);
@@ -944,8 +841,7 @@ edge translate_isl_ast_to_gimple::
graphite_create_new_guard (edge entry_edge, __isl_take isl_ast_expr *if_cond,
ivs_params &ip)
{
- tree type =
- build_nonstandard_integer_type (graphite_expression_type_precision, 0);
+ tree type = graphite_expr_type;
tree cond_expr = gcc_expression_from_isl_expression (type, if_cond, ip);
/* To fail code generation, we generate wrong code until we discard it. */
@@ -1025,206 +921,6 @@ translate_isl_ast (loop_p context_loop, __isl_keep isl_ast_node *node,
}
}
-/* Return true when BB contains loop close phi nodes. A loop close phi node is
- at the exit of loop which takes one argument that is the last value of the
- variable being used out of the loop. */
-
-static bool
-bb_contains_loop_close_phi_nodes (basic_block bb)
-{
- return single_pred_p (bb)
- && bb->loop_father != single_pred_edge (bb)->src->loop_father;
-}
-
-/* Return true when BB contains loop phi nodes. A loop phi node is the loop
- header containing phi nodes which has one init-edge and one back-edge. */
-
-static bool
-bb_contains_loop_phi_nodes (basic_block bb)
-{
- if (EDGE_COUNT (bb->preds) != 2)
- return false;
-
- unsigned depth = loop_depth (bb->loop_father);
-
- edge preds[2] = { (*bb->preds)[0], (*bb->preds)[1] };
-
- if (depth > loop_depth (preds[0]->src->loop_father)
- || depth > loop_depth (preds[1]->src->loop_father))
- return true;
-
- /* When one of the edges correspond to the same loop father and other
- doesn't. */
- if (bb->loop_father != preds[0]->src->loop_father
- && bb->loop_father == preds[1]->src->loop_father)
- return true;
-
- if (bb->loop_father != preds[1]->src->loop_father
- && bb->loop_father == preds[0]->src->loop_father)
- return true;
-
- return false;
-}
-
-/* Check if USE is defined in a basic block from where the definition of USE can
- propagate from all the paths. FIXME: Verify checks for virtual operands. */
-
-static bool
-is_loop_closed_ssa_use (basic_block bb, tree use)
-{
- if (TREE_CODE (use) != SSA_NAME || virtual_operand_p (use))
- return true;
-
- /* For close-phi nodes def always comes from a loop which has a back-edge. */
- if (bb_contains_loop_close_phi_nodes (bb))
- return true;
-
- gimple *def = SSA_NAME_DEF_STMT (use);
- basic_block def_bb = gimple_bb (def);
- return (!def_bb
- || flow_bb_inside_loop_p (def_bb->loop_father, bb));
-}
-
-/* Return the number of phi nodes in BB. */
-
-static int
-number_of_phi_nodes (basic_block bb)
-{
- int num_phis = 0;
- for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi);
- gsi_next (&psi))
- num_phis++;
- return num_phis;
-}
-
-/* Returns true if BB uses name in one of its PHIs. */
-
-static bool
-phi_uses_name (basic_block bb, tree name)
-{
- for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi);
- gsi_next (&psi))
- {
- gphi *phi = psi.phi ();
- for (unsigned i = 0; i < gimple_phi_num_args (phi); i++)
- {
- tree use_arg = gimple_phi_arg_def (phi, i);
- if (use_arg == name)
- return true;
- }
- }
- return false;
-}
-
-/* Return true if RENAME (defined in BB) is a valid use in NEW_BB. The
- definition should flow into use, and the use should respect the loop-closed
- SSA form. */
-
-bool translate_isl_ast_to_gimple::
-is_valid_rename (tree rename, basic_block def_bb, basic_block use_bb,
- phi_node_kind phi_kind, tree old_name, basic_block old_bb) const
-{
- if (SSA_NAME_IS_DEFAULT_DEF (rename))
- return true;
-
- /* The def of the rename must either dominate the uses or come from a
- back-edge. Also the def must respect the loop closed ssa form. */
- if (!is_loop_closed_ssa_use (use_bb, rename))
- {
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] rename not in loop closed ssa: ");
- print_generic_expr (dump_file, rename);
- fprintf (dump_file, "\n");
- }
- return false;
- }
-
- if (dominated_by_p (CDI_DOMINATORS, use_bb, def_bb))
- return true;
-
- if (bb_contains_loop_phi_nodes (use_bb) && phi_kind == loop_phi)
- {
- /* The loop-header dominates the loop-body. */
- if (!dominated_by_p (CDI_DOMINATORS, def_bb, use_bb))
- return false;
-
- /* RENAME would be used in loop-phi. */
- gcc_assert (number_of_phi_nodes (use_bb));
-
- /* For definitions coming from back edges, we should check that
- old_name is used in a loop PHI node.
- FIXME: Verify if this is true. */
- if (phi_uses_name (old_bb, old_name))
- return true;
- }
- return false;
-}
-
-/* Returns the expression associated to OLD_NAME (which is used in OLD_BB), in
- NEW_BB from RENAME_MAP. PHI_KIND determines the kind of phi node. */
-
-tree translate_isl_ast_to_gimple::
-get_rename (basic_block new_bb, tree old_name, basic_block old_bb,
- phi_node_kind phi_kind) const
-{
- gcc_assert (TREE_CODE (old_name) == SSA_NAME);
- vec <tree> *renames = region->rename_map->get (old_name);
-
- if (!renames || renames->is_empty ())
- return NULL_TREE;
-
- if (1 == renames->length ())
- {
- tree rename = (*renames)[0];
- if (TREE_CODE (rename) == SSA_NAME)
- {
- basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (rename));
- if (is_valid_rename (rename, bb, new_bb, phi_kind, old_name, old_bb)
- && (phi_kind == close_phi
- || ! bb
- || flow_bb_inside_loop_p (bb->loop_father, new_bb)))
- return rename;
- return NULL_TREE;
- }
-
- if (is_constant (rename))
- return rename;
-
- return NULL_TREE;
- }
-
- /* More than one renames corresponding to the old_name. Find the rename for
- which the definition flows into usage at new_bb. */
- int i;
- tree t1 = NULL_TREE, t2;
- basic_block t1_bb = NULL;
- FOR_EACH_VEC_ELT (*renames, i, t2)
- {
- basic_block t2_bb = gimple_bb (SSA_NAME_DEF_STMT (t2));
-
- /* Defined in the same basic block as used. */
- if (t2_bb == new_bb)
- return t2;
-
- /* NEW_BB and T2_BB are in two unrelated if-clauses. */
- if (!dominated_by_p (CDI_DOMINATORS, new_bb, t2_bb))
- continue;
-
- if (!flow_bb_inside_loop_p (t2_bb->loop_father, new_bb))
- continue;
-
- /* Compute the nearest dominator. */
- if (!t1 || dominated_by_p (CDI_DOMINATORS, t2_bb, t1_bb))
- {
- t1_bb = t2_bb;
- t1 = t2;
- }
- }
-
- return t1;
-}
-
/* Register in RENAME_MAP the rename tuple (OLD_NAME, EXPR).
When OLD_NAME and EXPR are the same we assert. */
@@ -1235,32 +931,12 @@ set_rename (tree old_name, tree expr)
{
fprintf (dump_file, "[codegen] setting rename: old_name = ");
print_generic_expr (dump_file, old_name);
- fprintf (dump_file, ", new_name = ");
+ fprintf (dump_file, ", new decl = ");
print_generic_expr (dump_file, expr);
fprintf (dump_file, "\n");
}
-
- if (old_name == expr)
- return;
-
- vec <tree> *renames = region->rename_map->get (old_name);
-
- if (renames)
- renames->safe_push (expr);
- else
- {
- vec<tree> r;
- r.create (2);
- r.safe_push (expr);
- region->rename_map->put (old_name, r);
- }
-
- tree t;
- int i;
- /* For a parameter of a scop we don't want to rename it. */
- FOR_EACH_VEC_ELT (region->params, i, t)
- if (old_name == t)
- region->parameter_rename_map->put(old_name, expr);
+ bool res = region->rename_map->put (old_name, expr);
+ gcc_assert (! res);
}
/* Return an iterator to the instructions comes last in the execution order.
@@ -1372,200 +1048,18 @@ gsi_insert_earliest (gimple_seq seq)
if (dump_file)
{
- fprintf (dump_file, "[codegen] inserting statement: ");
+ fprintf (dump_file, "[codegen] inserting statement in BB %d: ",
+ gimple_bb (use_stmt)->index);
print_gimple_stmt (dump_file, use_stmt, 0, TDF_VOPS | TDF_MEMSYMS);
- print_loops_bb (dump_file, gimple_bb (use_stmt), 0, 3);
}
}
}
-/* Collect all the operands of NEW_EXPR by recursively visiting each
- operand. */
-
-void translate_isl_ast_to_gimple::
-collect_all_ssa_names (tree new_expr, vec<tree> *vec_ssa)
-{
- if (new_expr == NULL_TREE)
- return;
-
- /* Rename all uses in new_expr. */
- if (TREE_CODE (new_expr) == SSA_NAME)
- {
- vec_ssa->safe_push (new_expr);
- return;
- }
-
- /* Iterate over SSA_NAMES in NEW_EXPR. */
- for (int i = 0; i < (TREE_CODE_LENGTH (TREE_CODE (new_expr))); i++)
- {
- tree op = TREE_OPERAND (new_expr, i);
- collect_all_ssa_names (op, vec_ssa);
- }
-}
-
-/* This is abridged version of the function copied from:
- tree.c:substitute_in_expr (tree exp, tree f, tree r). */
-
-static tree
-substitute_ssa_name (tree exp, tree f, tree r)
-{
- enum tree_code code = TREE_CODE (exp);
- tree op0, op1, op2, op3;
- tree new_tree;
-
- /* We handle TREE_LIST and COMPONENT_REF separately. */
- if (code == TREE_LIST)
- {
- op0 = substitute_ssa_name (TREE_CHAIN (exp), f, r);
- op1 = substitute_ssa_name (TREE_VALUE (exp), f, r);
- if (op0 == TREE_CHAIN (exp) && op1 == TREE_VALUE (exp))
- return exp;
-
- return tree_cons (TREE_PURPOSE (exp), op1, op0);
- }
- else if (code == COMPONENT_REF)
- {
- tree inner;
-
- /* If this expression is getting a value from a PLACEHOLDER_EXPR
- and it is the right field, replace it with R. */
- for (inner = TREE_OPERAND (exp, 0);
- REFERENCE_CLASS_P (inner);
- inner = TREE_OPERAND (inner, 0))
- ;
-
- /* The field. */
- op1 = TREE_OPERAND (exp, 1);
-
- if (TREE_CODE (inner) == PLACEHOLDER_EXPR && op1 == f)
- return r;
-
- /* If this expression hasn't been completed let, leave it alone. */
- if (TREE_CODE (inner) == PLACEHOLDER_EXPR && !TREE_TYPE (inner))
- return exp;
-
- op0 = substitute_ssa_name (TREE_OPERAND (exp, 0), f, r);
- if (op0 == TREE_OPERAND (exp, 0))
- return exp;
-
- new_tree
- = fold_build3 (COMPONENT_REF, TREE_TYPE (exp), op0, op1, NULL_TREE);
- }
- else
- switch (TREE_CODE_CLASS (code))
- {
- case tcc_constant:
- return exp;
-
- case tcc_declaration:
- if (exp == f)
- return r;
- else
- return exp;
-
- case tcc_expression:
- if (exp == f)
- return r;
-
- /* Fall through. */
-
- case tcc_exceptional:
- case tcc_unary:
- case tcc_binary:
- case tcc_comparison:
- case tcc_reference:
- switch (TREE_CODE_LENGTH (code))
- {
- case 0:
- if (exp == f)
- return r;
- return exp;
-
- case 1:
- op0 = substitute_ssa_name (TREE_OPERAND (exp, 0), f, r);
- if (op0 == TREE_OPERAND (exp, 0))
- return exp;
-
- new_tree = fold_build1 (code, TREE_TYPE (exp), op0);
- break;
-
- case 2:
- op0 = substitute_ssa_name (TREE_OPERAND (exp, 0), f, r);
- op1 = substitute_ssa_name (TREE_OPERAND (exp, 1), f, r);
-
- if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1))
- return exp;
-
- new_tree = fold_build2 (code, TREE_TYPE (exp), op0, op1);
- break;
-
- case 3:
- op0 = substitute_ssa_name (TREE_OPERAND (exp, 0), f, r);
- op1 = substitute_ssa_name (TREE_OPERAND (exp, 1), f, r);
- op2 = substitute_ssa_name (TREE_OPERAND (exp, 2), f, r);
-
- if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
- && op2 == TREE_OPERAND (exp, 2))
- return exp;
-
- new_tree = fold_build3 (code, TREE_TYPE (exp), op0, op1, op2);
- break;
-
- case 4:
- op0 = substitute_ssa_name (TREE_OPERAND (exp, 0), f, r);
- op1 = substitute_ssa_name (TREE_OPERAND (exp, 1), f, r);
- op2 = substitute_ssa_name (TREE_OPERAND (exp, 2), f, r);
- op3 = substitute_ssa_name (TREE_OPERAND (exp, 3), f, r);
-
- if (op0 == TREE_OPERAND (exp, 0) && op1 == TREE_OPERAND (exp, 1)
- && op2 == TREE_OPERAND (exp, 2)
- && op3 == TREE_OPERAND (exp, 3))
- return exp;
-
- new_tree
- = fold (build4 (code, TREE_TYPE (exp), op0, op1, op2, op3));
- break;
-
- default:
- gcc_unreachable ();
- }
- break;
-
- case tcc_vl_exp:
- default:
- gcc_unreachable ();
- }
-
- TREE_READONLY (new_tree) |= TREE_READONLY (exp);
-
- if (code == INDIRECT_REF || code == ARRAY_REF || code == ARRAY_RANGE_REF)
- TREE_THIS_NOTRAP (new_tree) |= TREE_THIS_NOTRAP (exp);
-
- return new_tree;
-}
-
-/* Rename all the operands of NEW_EXPR by recursively visiting each operand. */
-
-tree translate_isl_ast_to_gimple::
-rename_all_uses (tree new_expr, basic_block new_bb, basic_block old_bb)
-{
- auto_vec<tree, 2> ssa_names;
- collect_all_ssa_names (new_expr, &ssa_names);
- tree t;
- int i;
- FOR_EACH_VEC_ELT (ssa_names, i, t)
- if (tree r = get_rename (new_bb, t, old_bb, unknown_phi))
- new_expr = substitute_ssa_name (new_expr, t, r);
-
- return new_expr;
-}
-
/* For ops which are scev_analyzeable, we can regenerate a new name from its
scalar evolution around LOOP. */
tree translate_isl_ast_to_gimple::
get_rename_from_scev (tree old_name, gimple_seq *stmts, loop_p loop,
- basic_block new_bb, basic_block old_bb,
vec<tree> iv_map)
{
tree scev = scalar_evolution_in_region (region->region, loop, old_name);
@@ -1577,7 +1071,7 @@ get_rename_from_scev (tree old_name, gimple_seq *stmts, loop_p loop,
tree new_expr;
if (chrec_contains_undetermined (scev))
{
- codegen_error = true;
+ set_codegen_error ();
return build_zero_cst (TREE_TYPE (old_name));
}
@@ -1590,915 +1084,15 @@ get_rename_from_scev (tree old_name, gimple_seq *stmts, loop_p loop,
if (chrec_contains_undetermined (new_expr)
|| tree_contains_chrecs (new_expr, NULL))
{
- codegen_error = true;
+ set_codegen_error ();
return build_zero_cst (TREE_TYPE (old_name));
}
- if (TREE_CODE (new_expr) == SSA_NAME)
- {
- basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (new_expr));
- if (bb && !dominated_by_p (CDI_DOMINATORS, new_bb, bb))
- {
- codegen_error = true;
- return build_zero_cst (TREE_TYPE (old_name));
- }
- }
-
- new_expr = rename_all_uses (new_expr, new_bb, old_bb);
-
- /* We check all the operands and all of them should dominate the use at
- new_expr. */
- auto_vec <tree, 2> new_ssa_names;
- collect_all_ssa_names (new_expr, &new_ssa_names);
- int i;
- tree new_ssa_name;
- FOR_EACH_VEC_ELT (new_ssa_names, i, new_ssa_name)
- {
- if (TREE_CODE (new_ssa_name) == SSA_NAME)
- {
- basic_block bb = gimple_bb (SSA_NAME_DEF_STMT (new_ssa_name));
- if (bb && !dominated_by_p (CDI_DOMINATORS, new_bb, bb))
- {
- codegen_error = true;
- return build_zero_cst (TREE_TYPE (old_name));
- }
- }
- }
-
/* Replace the old_name with the new_expr. */
return force_gimple_operand (unshare_expr (new_expr), stmts,
true, NULL_TREE);
}
-/* Renames the scalar uses of the statement COPY, using the
- substitution map RENAME_MAP, inserting the gimplification code at
- GSI_TGT, for the translation REGION, with the original copied
- statement in LOOP, and using the induction variable renaming map
- IV_MAP. Returns true when something has been renamed. */
-
-bool translate_isl_ast_to_gimple::
-rename_uses (gimple *copy, gimple_stmt_iterator *gsi_tgt, basic_block old_bb,
- loop_p loop, vec<tree> iv_map)
-{
- bool changed = false;
-
- if (is_gimple_debug (copy))
- {
- if (gimple_debug_bind_p (copy))
- gimple_debug_bind_reset_value (copy);
- else if (gimple_debug_source_bind_p (copy))
- return false;
- else
- gcc_unreachable ();
-
- return false;
- }
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] renaming uses of stmt: ");
- print_gimple_stmt (dump_file, copy, 0);
- }
-
- use_operand_p use_p;
- ssa_op_iter op_iter;
- FOR_EACH_SSA_USE_OPERAND (use_p, copy, op_iter, SSA_OP_USE)
- {
- tree old_name = USE_FROM_PTR (use_p);
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] renaming old_name = ");
- print_generic_expr (dump_file, old_name);
- fprintf (dump_file, "\n");
- }
-
- if (TREE_CODE (old_name) != SSA_NAME
- || SSA_NAME_IS_DEFAULT_DEF (old_name))
- continue;
-
- changed = true;
- tree new_expr = get_rename (gsi_tgt->bb, old_name,
- old_bb, unknown_phi);
-
- if (new_expr)
- {
- tree type_old_name = TREE_TYPE (old_name);
- tree type_new_expr = TREE_TYPE (new_expr);
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] from rename_map: new_name = ");
- print_generic_expr (dump_file, new_expr);
- fprintf (dump_file, "\n");
- }
-
- if (type_old_name != type_new_expr
- || TREE_CODE (new_expr) != SSA_NAME)
- {
- tree var = create_tmp_var (type_old_name, "var");
-
- if (!useless_type_conversion_p (type_old_name, type_new_expr))
- new_expr = fold_convert (type_old_name, new_expr);
-
- gimple_seq stmts;
- new_expr = force_gimple_operand (new_expr, &stmts, true, var);
- gsi_insert_earliest (stmts);
- }
-
- replace_exp (use_p, new_expr);
- continue;
- }
-
- gimple_seq stmts;
- new_expr = get_rename_from_scev (old_name, &stmts, loop, gimple_bb (copy),
- old_bb, iv_map);
- if (!new_expr || codegen_error_p ())
- return false;
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] not in rename map, scev: ");
- print_generic_expr (dump_file, new_expr);
- fprintf (dump_file, "\n");
- }
-
- gsi_insert_earliest (stmts);
- replace_exp (use_p, new_expr);
-
- if (TREE_CODE (new_expr) == INTEGER_CST
- && is_gimple_assign (copy))
- {
- tree rhs = gimple_assign_rhs1 (copy);
-
- if (TREE_CODE (rhs) == ADDR_EXPR)
- recompute_tree_invariant_for_addr_expr (rhs);
- }
-
- set_rename (old_name, new_expr);
- }
-
- return changed;
-}
-
-/* Returns a basic block that could correspond to where a constant was defined
- in the original code. In the original code OLD_BB had the definition, we
- need to find which basic block out of the copies of old_bb, in the new
- region, should a definition correspond to if it has to reach BB. */
-
-basic_block translate_isl_ast_to_gimple::
-get_def_bb_for_const (basic_block bb, basic_block old_bb) const
-{
- vec <basic_block> *bbs = region->copied_bb_map->get (old_bb);
-
- if (!bbs || bbs->is_empty ())
- return NULL;
-
- if (1 == bbs->length ())
- return (*bbs)[0];
-
- int i;
- basic_block b1 = NULL, b2;
- FOR_EACH_VEC_ELT (*bbs, i, b2)
- {
- if (b2 == bb)
- return bb;
-
- /* BB and B2 are in two unrelated if-clauses. */
- if (!dominated_by_p (CDI_DOMINATORS, bb, b2))
- continue;
-
- /* Compute the nearest dominator. */
- if (!b1 || dominated_by_p (CDI_DOMINATORS, b2, b1))
- b1 = b2;
- }
-
- return b1;
-}
-
-/* Get the new name of OP (from OLD_BB) to be used in NEW_BB. PHI_KIND
- determines the kind of phi node. */
-
-tree translate_isl_ast_to_gimple::
-get_new_name (basic_block new_bb, tree op,
- basic_block old_bb, phi_node_kind phi_kind) const
-{
- /* For constants the names are the same. */
- if (TREE_CODE (op) != SSA_NAME)
- return op;
-
- return get_rename (new_bb, op, old_bb, phi_kind);
-}
-
-/* Return a debug location for OP. */
-
-static location_t
-get_loc (tree op)
-{
- location_t loc = UNKNOWN_LOCATION;
-
- if (TREE_CODE (op) == SSA_NAME)
- loc = gimple_location (SSA_NAME_DEF_STMT (op));
- return loc;
-}
-
-/* Returns the incoming edges of basic_block BB in the pair. The first edge is
- the init edge (from outside the loop) and the second one is the back edge
- from the same loop. */
-
-std::pair<edge, edge>
-get_edges (basic_block bb)
-{
- std::pair<edge, edge> edges;
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, bb->preds)
- if (bb->loop_father != e->src->loop_father)
- edges.first = e;
- else
- edges.second = e;
- return edges;
-}
-
-/* Copy the PHI arguments from OLD_PHI to the NEW_PHI. The arguments to NEW_PHI
- must be found unless they can be POSTPONEd for later. */
-
-bool translate_isl_ast_to_gimple::
-copy_loop_phi_args (gphi *old_phi, init_back_edge_pair_t &ibp_old_bb,
- gphi *new_phi, init_back_edge_pair_t &ibp_new_bb,
- bool postpone)
-{
- gcc_assert (gimple_phi_num_args (old_phi) == gimple_phi_num_args (new_phi));
-
- basic_block new_bb = gimple_bb (new_phi);
- for (unsigned i = 0; i < gimple_phi_num_args (old_phi); i++)
- {
- edge e;
- if (gimple_phi_arg_edge (old_phi, i) == ibp_old_bb.first)
- e = ibp_new_bb.first;
- else
- e = ibp_new_bb.second;
-
- tree old_name = gimple_phi_arg_def (old_phi, i);
- tree new_name = get_new_name (new_bb, old_name,
- gimple_bb (old_phi), loop_phi);
- if (new_name)
- {
- add_phi_arg (new_phi, new_name, e, get_loc (old_name));
- continue;
- }
-
- gimple *old_def_stmt = SSA_NAME_DEF_STMT (old_name);
- if (!old_def_stmt || gimple_code (old_def_stmt) == GIMPLE_NOP)
- /* If the phi arg was a function arg, or wasn't defined, just use the
- old name. */
- add_phi_arg (new_phi, old_name, e, get_loc (old_name));
- else if (postpone)
- {
- /* Postpone code gen for later for those back-edges we don't have the
- names yet. */
- region->incomplete_phis.safe_push (std::make_pair (old_phi, new_phi));
- if (dump_file)
- fprintf (dump_file, "[codegen] postpone loop phi nodes.\n");
- }
- else
- /* Either we should add the arg to phi or, we should postpone. */
- return false;
- }
- return true;
-}
-
-/* Copy loop phi nodes from BB to NEW_BB. */
-
-bool translate_isl_ast_to_gimple::
-copy_loop_phi_nodes (basic_block bb, basic_block new_bb)
-{
- if (dump_file)
- fprintf (dump_file, "[codegen] copying loop phi nodes in bb_%d.\n",
- new_bb->index);
-
- /* Loop phi nodes should have only two arguments. */
- gcc_assert (2 == EDGE_COUNT (bb->preds));
-
- /* First edge is the init edge and second is the back edge. */
- init_back_edge_pair_t ibp_old_bb = get_edges (bb);
-
- /* First edge is the init edge and second is the back edge. */
- init_back_edge_pair_t ibp_new_bb = get_edges (new_bb);
-
- for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi);
- gsi_next (&psi))
- {
- gphi *phi = psi.phi ();
- tree res = gimple_phi_result (phi);
- if (virtual_operand_p (res))
- continue;
- if (is_gimple_reg (res) && scev_analyzable_p (res, region->region))
- continue;
-
- gphi *new_phi = create_phi_node (NULL_TREE, new_bb);
- tree new_res = create_new_def_for (res, new_phi,
- gimple_phi_result_ptr (new_phi));
- set_rename (res, new_res);
- codegen_error = !copy_loop_phi_args (phi, ibp_old_bb, new_phi,
- ibp_new_bb, true);
- update_stmt (new_phi);
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] creating loop-phi node: ");
- print_gimple_stmt (dump_file, new_phi, 0);
- }
- }
-
- return true;
-}
-
-/* Return the init value of PHI, the value coming from outside the loop. */
-
-static tree
-get_loop_init_value (gphi *phi)
-{
-
- loop_p loop = gimple_bb (phi)->loop_father;
-
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, gimple_bb (phi)->preds)
- if (e->src->loop_father != loop)
- return gimple_phi_arg_def (phi, e->dest_idx);
-
- return NULL_TREE;
-}
-
-/* Find the init value (the value which comes from outside the loop), of one of
- the operands of DEF which is defined by a loop phi. */
-
-static tree
-find_init_value (gimple *def)
-{
- if (gimple_code (def) == GIMPLE_PHI)
- return get_loop_init_value (as_a <gphi*> (def));
-
- if (gimple_vuse (def))
- return NULL_TREE;
-
- ssa_op_iter iter;
- use_operand_p use_p;
- FOR_EACH_SSA_USE_OPERAND (use_p, def, iter, SSA_OP_USE)
- {
- tree use = USE_FROM_PTR (use_p);
- if (TREE_CODE (use) == SSA_NAME)
- {
- if (tree res = find_init_value (SSA_NAME_DEF_STMT (use)))
- return res;
- }
- }
-
- return NULL_TREE;
-}
-
-/* Return the init value, the value coming from outside the loop. */
-
-static tree
-find_init_value_close_phi (gphi *phi)
-{
- gcc_assert (gimple_phi_num_args (phi) == 1);
- tree use_arg = gimple_phi_arg_def (phi, 0);
- gimple *def = SSA_NAME_DEF_STMT (use_arg);
- return find_init_value (def);
-}
-
-
-tree translate_isl_ast_to_gimple::
-add_close_phis_to_outer_loops (tree last_merge_name, edge last_e,
- gimple *old_close_phi)
-{
- sese_l &codegen_region = region->if_region->true_region->region;
- gimple *stmt = SSA_NAME_DEF_STMT (last_merge_name);
- basic_block bb = gimple_bb (stmt);
- if (!bb_in_sese_p (bb, codegen_region))
- return last_merge_name;
-
- loop_p loop = bb->loop_father;
- if (!loop_in_sese_p (loop, codegen_region))
- return last_merge_name;
-
- edge e = single_exit (loop);
-
- if (dominated_by_p (CDI_DOMINATORS, e->dest, last_e->src))
- return last_merge_name;
-
- tree old_name = gimple_phi_arg_def (old_close_phi, 0);
- tree old_close_phi_name = gimple_phi_result (old_close_phi);
-
- bb = e->dest;
- if (!bb_contains_loop_close_phi_nodes (bb) || !single_succ_p (bb))
- bb = split_edge (e);
-
- gphi *close_phi = create_phi_node (NULL_TREE, bb);
- tree res = create_new_def_for (last_merge_name, close_phi,
- gimple_phi_result_ptr (close_phi));
- set_rename (old_close_phi_name, res);
- add_phi_arg (close_phi, last_merge_name, e, get_loc (old_name));
- last_merge_name = res;
-
- return add_close_phis_to_outer_loops (last_merge_name, last_e, old_close_phi);
-}
-
-/* Add phi nodes to all merge points of all the diamonds enclosing the loop of
- the close phi node PHI. */
-
-bool translate_isl_ast_to_gimple::
-add_close_phis_to_merge_points (gphi *old_close_phi, gphi *new_close_phi,
- tree default_value)
-{
- sese_l &codegen_region = region->if_region->true_region->region;
- basic_block default_value_bb = get_entry_bb (codegen_region);
- if (SSA_NAME == TREE_CODE (default_value))
- {
- gimple *stmt = SSA_NAME_DEF_STMT (default_value);
- if (!stmt || gimple_code (stmt) == GIMPLE_NOP)
- return false;
- default_value_bb = gimple_bb (stmt);
- }
-
- basic_block new_close_phi_bb = gimple_bb (new_close_phi);
-
- tree old_close_phi_name = gimple_phi_result (old_close_phi);
- tree new_close_phi_name = gimple_phi_result (new_close_phi);
- tree last_merge_name = new_close_phi_name;
- tree old_name = gimple_phi_arg_def (old_close_phi, 0);
-
- int i;
- edge merge_e;
- FOR_EACH_VEC_ELT_REVERSE (merge_points, i, merge_e)
- {
- basic_block new_merge_bb = merge_e->src;
- if (!dominated_by_p (CDI_DOMINATORS, new_merge_bb, default_value_bb))
- continue;
-
- last_merge_name = add_close_phis_to_outer_loops (last_merge_name, merge_e,
- old_close_phi);
-
- gphi *merge_phi = create_phi_node (NULL_TREE, new_merge_bb);
- tree merge_res = create_new_def_for (old_close_phi_name, merge_phi,
- gimple_phi_result_ptr (merge_phi));
- set_rename (old_close_phi_name, merge_res);
-
- edge from_loop = NULL, from_default_value = NULL;
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, new_merge_bb->preds)
- if (dominated_by_p (CDI_DOMINATORS, e->src, new_close_phi_bb))
- from_loop = e;
- else
- from_default_value = e;
-
- /* Because CDI_POST_DOMINATORS are not updated, we only rely on
- CDI_DOMINATORS, which may not handle all cases where new_close_phi_bb
- is contained in another condition. */
- if (!from_default_value || !from_loop)
- return false;
-
- add_phi_arg (merge_phi, last_merge_name, from_loop, get_loc (old_name));
- add_phi_arg (merge_phi, default_value, from_default_value, get_loc (old_name));
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] Adding guard-phi: ");
- print_gimple_stmt (dump_file, merge_phi, 0);
- }
-
- update_stmt (merge_phi);
- last_merge_name = merge_res;
- }
-
- return true;
-}
-
-/* Copy all the loop-close phi args from BB to NEW_BB. */
-
-bool translate_isl_ast_to_gimple::
-copy_loop_close_phi_args (basic_block old_bb, basic_block new_bb,
- vec<tree> iv_map, bool postpone)
-{
- for (gphi_iterator psi = gsi_start_phis (old_bb); !gsi_end_p (psi);
- gsi_next (&psi))
- {
- gphi *old_close_phi = psi.phi ();
- tree res = gimple_phi_result (old_close_phi);
- if (virtual_operand_p (res))
- continue;
-
- gphi *new_close_phi = create_phi_node (NULL_TREE, new_bb);
- tree new_res = create_new_def_for (res, new_close_phi,
- gimple_phi_result_ptr (new_close_phi));
- set_rename (res, new_res);
-
- tree old_name = gimple_phi_arg_def (old_close_phi, 0);
- tree new_name;
- if (is_gimple_reg (res) && scev_analyzable_p (res, region->region))
- {
- gimple_seq stmts;
- new_name = get_rename_from_scev (old_name, &stmts,
- old_bb->loop_father,
- new_bb, old_bb, iv_map);
- if (! codegen_error_p ())
- gsi_insert_earliest (stmts);
- }
- else
- new_name = get_new_name (new_bb, old_name, old_bb, close_phi);
-
- /* Predecessor basic blocks of a loop close phi should have been code
- generated before. FIXME: This is fixable by merging PHIs from inner
- loops as well. See: gfortran.dg/graphite/interchange-3.f90. */
- if (!new_name || codegen_error_p ())
- return false;
-
- add_phi_arg (new_close_phi, new_name, single_pred_edge (new_bb),
- get_loc (old_name));
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] Adding loop close phi: ");
- print_gimple_stmt (dump_file, new_close_phi, 0);
- }
-
- update_stmt (new_close_phi);
-
- /* When there is no loop guard around this codegenerated loop, there is no
- need to collect the close-phi arg. */
- if (merge_points.is_empty ())
- continue;
-
- /* Add a PHI in the succ_new_bb for each close phi of the loop. */
- tree default_value = find_init_value_close_phi (new_close_phi);
-
- /* A close phi must come from a loop-phi having a default value. */
- if (!default_value)
- {
- if (!postpone)
- return false;
-
- region->incomplete_phis.safe_push (std::make_pair (old_close_phi,
- new_close_phi));
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] postpone close phi nodes: ");
- print_gimple_stmt (dump_file, new_close_phi, 0);
- }
- continue;
- }
-
- if (!add_close_phis_to_merge_points (old_close_phi, new_close_phi,
- default_value))
- return false;
- }
-
- return true;
-}
-
-/* Copy loop close phi nodes from BB to NEW_BB. */
-
-bool translate_isl_ast_to_gimple::
-copy_loop_close_phi_nodes (basic_block old_bb, basic_block new_bb,
- vec<tree> iv_map)
-{
- if (dump_file)
- fprintf (dump_file, "[codegen] copying loop close phi nodes in bb_%d.\n",
- new_bb->index);
- /* Loop close phi nodes should have only one argument. */
- gcc_assert (1 == EDGE_COUNT (old_bb->preds));
-
- return copy_loop_close_phi_args (old_bb, new_bb, iv_map, true);
-}
-
-
-/* Add NEW_NAME as the ARGNUM-th arg of NEW_PHI which is in NEW_BB.
- DOMINATING_PRED is the predecessor basic block of OLD_BB which dominates the
- other pred of OLD_BB as well. If no such basic block exists then it is NULL.
- NON_DOMINATING_PRED is a pred which does not dominate OLD_BB, it cannot be
- NULL.
-
- Case1: OLD_BB->preds {BB1, BB2} and BB1 does not dominate BB2 and vice versa.
- In this case DOMINATING_PRED = NULL.
-
- Case2: OLD_BB->preds {BB1, BB2} and BB1 dominates BB2.
-
- Returns true on successful copy of the args, false otherwise. */
-
-bool translate_isl_ast_to_gimple::
-add_phi_arg_for_new_expr (tree old_phi_args[2], tree new_phi_args[2],
- edge old_bb_dominating_edge,
- edge old_bb_non_dominating_edge,
- gphi *phi, gphi *new_phi,
- basic_block new_bb)
-{
- basic_block def_pred[2] = { NULL, NULL };
- int not_found_bb_index = -1;
- for (int i = 0; i < 2; i++)
- {
- /* If the corresponding def_bb could not be found the entry will be
- NULL. */
- if (TREE_CODE (old_phi_args[i]) == INTEGER_CST)
- def_pred[i] = get_def_bb_for_const (new_bb,
- gimple_phi_arg_edge (phi, i)->src);
- else if (new_phi_args[i] && (TREE_CODE (new_phi_args[i]) == SSA_NAME))
- def_pred[i] = gimple_bb (SSA_NAME_DEF_STMT (new_phi_args[i]));
-
- if (!def_pred[i])
- {
- /* When non are available bail out. */
- if (not_found_bb_index != -1)
- return false;
- not_found_bb_index = i;
- }
- }
-
- /* Here we are pattern matching on the structure of CFG w.r.t. old one. */
- if (old_bb_dominating_edge)
- {
- if (not_found_bb_index != -1)
- return false;
-
- basic_block new_pred1 = (*new_bb->preds)[0]->src;
- basic_block new_pred2 = (*new_bb->preds)[1]->src;
- vec <basic_block> *bbs
- = region->copied_bb_map->get (old_bb_non_dominating_edge->src);
-
- /* Could not find a mapping. */
- if (!bbs)
- return false;
-
- basic_block new_pred = NULL;
- basic_block b;
- int i;
- FOR_EACH_VEC_ELT (*bbs, i, b)
- {
- if (dominated_by_p (CDI_DOMINATORS, new_pred1, b))
- {
- /* FIXME: If we have already found new_pred then we have to
- disambiguate, bail out for now. */
- if (new_pred)
- return false;
- new_pred = new_pred1;
- }
- if (dominated_by_p (CDI_DOMINATORS, new_pred2, b))
- {
- /* FIXME: If we have already found new_pred then we have to either
- it dominates both or we have to disambiguate, bail out. */
- if (new_pred)
- return false;
- new_pred = new_pred2;
- }
- }
-
- if (!new_pred)
- return false;
-
- edge new_non_dominating_edge = find_edge (new_pred, new_bb);
- gcc_assert (new_non_dominating_edge);
- /* FIXME: Validate each args just like in loop-phis. */
- /* By the process of elimination we first insert insert phi-edge for
- non-dominating pred which is computed above and then we insert the
- remaining one. */
- int inserted_edge = 0;
- for (; inserted_edge < 2; inserted_edge++)
- {
- edge new_bb_pred_edge = gimple_phi_arg_edge (new_phi, inserted_edge);
- if (new_non_dominating_edge == new_bb_pred_edge)
- {
- add_phi_arg (new_phi, new_phi_args[inserted_edge],
- new_non_dominating_edge,
- get_loc (old_phi_args[inserted_edge]));
- break;
- }
- }
- if (inserted_edge == 2)
- return false;
-
- int edge_dominating = inserted_edge == 0 ? 1 : 0;
-
- edge new_dominating_edge = NULL;
- for (inserted_edge = 0; inserted_edge < 2; inserted_edge++)
- {
- edge e = gimple_phi_arg_edge (new_phi, inserted_edge);
- if (e != new_non_dominating_edge)
- {
- new_dominating_edge = e;
- add_phi_arg (new_phi, new_phi_args[edge_dominating],
- new_dominating_edge,
- get_loc (old_phi_args[inserted_edge]));
- break;
- }
- }
- gcc_assert (new_dominating_edge);
- }
- else
- {
- /* Classic diamond structure: both edges are non-dominating. We need to
- find one unique edge then the other can be found be elimination. If
- any definition (def_pred) dominates both the preds of new_bb then we
- bail out. Entries of def_pred maybe NULL, in that case we must
- uniquely find pred with help of only one entry. */
- edge new_e[2] = { NULL, NULL };
- for (int i = 0; i < 2; i++)
- {
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, new_bb->preds)
- if (def_pred[i]
- && dominated_by_p (CDI_DOMINATORS, e->src, def_pred[i]))
- {
- if (new_e[i])
- /* We do not know how to handle the case when def_pred
- dominates more than a predecessor. */
- return false;
- new_e[i] = e;
- }
- }
-
- gcc_assert (new_e[0] || new_e[1]);
-
- /* Find the other edge by process of elimination. */
- if (not_found_bb_index != -1)
- {
- gcc_assert (!new_e[not_found_bb_index]);
- int found_bb_index = not_found_bb_index == 1 ? 0 : 1;
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, new_bb->preds)
- {
- if (new_e[found_bb_index] == e)
- continue;
- new_e[not_found_bb_index] = e;
- }
- }
-
- /* Add edges to phi args. */
- for (int i = 0; i < 2; i++)
- add_phi_arg (new_phi, new_phi_args[i], new_e[i],
- get_loc (old_phi_args[i]));
- }
-
- return true;
-}
-
-/* Copy the arguments of cond-phi node PHI, to NEW_PHI in the codegenerated
- region. If postpone is true and it isn't possible to copy any arg of PHI,
- the PHI is added to the REGION->INCOMPLETE_PHIS to be codegenerated later.
- Returns false if the copying was unsuccessful. */
-
-bool translate_isl_ast_to_gimple::
-copy_cond_phi_args (gphi *phi, gphi *new_phi, vec<tree> iv_map, bool postpone)
-{
- if (dump_file)
- fprintf (dump_file, "[codegen] copying cond phi args.\n");
- gcc_assert (2 == gimple_phi_num_args (phi));
-
- basic_block new_bb = gimple_bb (new_phi);
- loop_p loop = gimple_bb (phi)->loop_father;
-
- basic_block old_bb = gimple_bb (phi);
- edge old_bb_non_dominating_edge = NULL, old_bb_dominating_edge = NULL;
-
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, old_bb->preds)
- if (!dominated_by_p (CDI_DOMINATORS, old_bb, e->src))
- old_bb_non_dominating_edge = e;
- else
- old_bb_dominating_edge = e;
-
- gcc_assert (!dominated_by_p (CDI_DOMINATORS, old_bb,
- old_bb_non_dominating_edge->src));
-
- tree new_phi_args[2];
- tree old_phi_args[2];
-
- for (unsigned i = 0; i < gimple_phi_num_args (phi); i++)
- {
- tree old_name = gimple_phi_arg_def (phi, i);
- tree new_name = get_new_name (new_bb, old_name, old_bb, cond_phi);
- old_phi_args[i] = old_name;
- if (new_name)
- {
- new_phi_args [i] = new_name;
- continue;
- }
-
- /* If the phi-arg was a parameter. */
- if (vec_find (region->params, old_name) != -1)
- {
- new_phi_args [i] = old_name;
- if (dump_file)
- {
- fprintf (dump_file,
- "[codegen] parameter argument to phi, new_expr: ");
- print_generic_expr (dump_file, new_phi_args[i]);
- fprintf (dump_file, "\n");
- }
- continue;
- }
-
- gimple *old_def_stmt = SSA_NAME_DEF_STMT (old_name);
- if (!old_def_stmt || gimple_code (old_def_stmt) == GIMPLE_NOP)
- /* FIXME: If the phi arg was a function arg, or wasn't defined, just use
- the old name. */
- return false;
-
- if (postpone)
- {
- /* If the phi-arg is scev-analyzeable but only in the first stage. */
- if (is_gimple_reg (old_name)
- && scev_analyzable_p (old_name, region->region))
- {
- gimple_seq stmts;
- tree new_expr = get_rename_from_scev (old_name, &stmts, loop,
- new_bb, old_bb, iv_map);
- if (codegen_error_p ())
- return false;
-
- gcc_assert (new_expr);
- if (dump_file)
- {
- fprintf (dump_file,
- "[codegen] scev analyzeable, new_expr: ");
- print_generic_expr (dump_file, new_expr);
- fprintf (dump_file, "\n");
- }
- gsi_insert_earliest (stmts);
- new_phi_args[i] = new_expr;
- continue;
- }
-
- /* Postpone code gen for later for back-edges. */
- region->incomplete_phis.safe_push (std::make_pair (phi, new_phi));
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] postpone cond phi nodes: ");
- print_gimple_stmt (dump_file, new_phi, 0);
- }
-
- new_phi_args [i] = NULL_TREE;
- continue;
- }
- else
- /* Either we should add the arg to phi or, we should postpone. */
- return false;
- }
-
- /* If none of the args have been determined in the first stage then wait until
- later. */
- if (postpone && !new_phi_args[0] && !new_phi_args[1])
- return true;
-
- return add_phi_arg_for_new_expr (old_phi_args, new_phi_args,
- old_bb_dominating_edge,
- old_bb_non_dominating_edge,
- phi, new_phi, new_bb);
-}
-
-/* Copy cond phi nodes from BB to NEW_BB. A cond-phi node is a basic block
- containing phi nodes coming from two predecessors, and none of them are back
- edges. */
-
-bool translate_isl_ast_to_gimple::
-copy_cond_phi_nodes (basic_block bb, basic_block new_bb, vec<tree> iv_map)
-{
-
- gcc_assert (!bb_contains_loop_close_phi_nodes (bb));
-
- /* TODO: Handle cond phi nodes with more than 2 predecessors. */
- if (EDGE_COUNT (bb->preds) != 2)
- return false;
-
- if (dump_file)
- fprintf (dump_file, "[codegen] copying cond phi nodes in bb_%d.\n",
- new_bb->index);
-
- for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi);
- gsi_next (&psi))
- {
- gphi *phi = psi.phi ();
- tree res = gimple_phi_result (phi);
- if (virtual_operand_p (res))
- continue;
-
- gphi *new_phi = create_phi_node (NULL_TREE, new_bb);
- tree new_res = create_new_def_for (res, new_phi,
- gimple_phi_result_ptr (new_phi));
- set_rename (res, new_res);
-
- if (!copy_cond_phi_args (phi, new_phi, iv_map, true))
- return false;
-
- update_stmt (new_phi);
- }
-
- return true;
-}
/* Return true if STMT should be copied from region to the new code-generated
region. LABELs, CONDITIONS, induction-variables and region parameters need
@@ -2521,37 +1115,13 @@ should_copy_to_new_region (gimple *stmt, sese_info_p region)
&& scev_analyzable_p (lhs, region->region))
return false;
- /* Do not copy parameters that have been generated in the header of the
- scop. */
- if (is_gimple_assign (stmt)
- && (lhs = gimple_assign_lhs (stmt))
- && TREE_CODE (lhs) == SSA_NAME
- && region->parameter_rename_map->get(lhs))
- return false;
-
return true;
}
-/* Create new names for all the definitions created by COPY and add replacement
- mappings for each new name. */
-
-void translate_isl_ast_to_gimple::
-set_rename_for_each_def (gimple *stmt)
-{
- def_operand_p def_p;
- ssa_op_iter op_iter;
- FOR_EACH_SSA_DEF_OPERAND (def_p, stmt, op_iter, SSA_OP_ALL_DEFS)
- {
- tree old_name = DEF_FROM_PTR (def_p);
- tree new_name = create_new_def_for (old_name, stmt, def_p);
- set_rename (old_name, new_name);
- }
-}
-
/* Duplicates the statements of basic block BB into basic block NEW_BB
and compute the new induction variables according to the IV_MAP. */
-bool translate_isl_ast_to_gimple::
+void translate_isl_ast_to_gimple::
graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb,
vec<tree> iv_map)
{
@@ -2568,96 +1138,71 @@ graphite_copy_stmts_from_block (basic_block bb, basic_block new_bb,
/* Create a new copy of STMT and duplicate STMT's virtual
operands. */
gimple *copy = gimple_copy (stmt);
- gsi_insert_after (&gsi_tgt, copy, GSI_NEW_STMT);
- if (dump_file)
+ /* Rather than not copying debug stmts we reset them.
+ ??? Where we can rewrite uses without inserting new
+ stmts we could simply do that. */
+ if (is_gimple_debug (copy))
{
- fprintf (dump_file, "[codegen] inserting statement: ");
- print_gimple_stmt (dump_file, copy, 0);
+ if (gimple_debug_bind_p (copy))
+ gimple_debug_bind_reset_value (copy);
+ else if (gimple_debug_source_bind_p (copy))
+ ;
+ else
+ gcc_unreachable ();
}
maybe_duplicate_eh_stmt (copy, stmt);
gimple_duplicate_stmt_histograms (cfun, copy, cfun, stmt);
/* Crete new names for each def in the copied stmt. */
- set_rename_for_each_def (copy);
-
- loop_p loop = bb->loop_father;
- if (rename_uses (copy, &gsi_tgt, bb, loop, iv_map))
+ def_operand_p def_p;
+ ssa_op_iter op_iter;
+ FOR_EACH_SSA_DEF_OPERAND (def_p, copy, op_iter, SSA_OP_ALL_DEFS)
{
- fold_stmt_inplace (&gsi_tgt);
- gcc_assert (gsi_stmt (gsi_tgt) == copy);
+ tree old_name = DEF_FROM_PTR (def_p);
+ create_new_def_for (old_name, copy, def_p);
}
- if (codegen_error_p ())
- return false;
+ gsi_insert_after (&gsi_tgt, copy, GSI_NEW_STMT);
+ if (dump_file)
+ {
+ fprintf (dump_file, "[codegen] inserting statement: ");
+ print_gimple_stmt (dump_file, copy, 0);
+ }
- /* For each SSA_NAME in the parameter_rename_map rename their usage. */
+ /* For each SCEV analyzable SSA_NAME, rename their usage. */
ssa_op_iter iter;
use_operand_p use_p;
if (!is_gimple_debug (copy))
- FOR_EACH_SSA_USE_OPERAND (use_p, copy, iter, SSA_OP_USE)
- {
- tree old_name = USE_FROM_PTR (use_p);
-
- if (TREE_CODE (old_name) != SSA_NAME
- || SSA_NAME_IS_DEFAULT_DEF (old_name))
- continue;
+ {
+ bool changed = false;
+ FOR_EACH_SSA_USE_OPERAND (use_p, copy, iter, SSA_OP_USE)
+ {
+ tree old_name = USE_FROM_PTR (use_p);
- tree *new_expr = region->parameter_rename_map->get (old_name);
- if (!new_expr)
- continue;
+ if (TREE_CODE (old_name) != SSA_NAME
+ || SSA_NAME_IS_DEFAULT_DEF (old_name)
+ || ! scev_analyzable_p (old_name, region->region))
+ continue;
- replace_exp (use_p, *new_expr);
- }
+ gimple_seq stmts = NULL;
+ tree new_name = get_rename_from_scev (old_name, &stmts,
+ bb->loop_father, iv_map);
+ if (! codegen_error_p ())
+ gsi_insert_earliest (stmts);
+ replace_exp (use_p, new_name);
+ changed = true;
+ }
+ if (changed)
+ fold_stmt_inplace (&gsi_tgt);
+ }
update_stmt (copy);
}
-
- return true;
}
-/* Given a basic block containing close-phi it returns the new basic block where
- to insert a copy of the close-phi nodes. All the uses in close phis should
- come from a single loop otherwise it returns NULL. */
-
-edge translate_isl_ast_to_gimple::
-edge_for_new_close_phis (basic_block bb)
-{
- /* Make sure that NEW_BB is the new_loop->exit->dest. We find the definition
- of close phi in the original code and then find the mapping of basic block
- defining that variable. If there are multiple close-phis and they are
- defined in different loops (in the original or in the new code) because of
- loop splitting, then we bail out. */
- loop_p new_loop = NULL;
- for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi);
- gsi_next (&psi))
- {
- gphi *phi = psi.phi ();
- tree name = gimple_phi_arg_def (phi, 0);
- basic_block old_loop_bb = gimple_bb (SSA_NAME_DEF_STMT (name));
-
- vec <basic_block> *bbs = region->copied_bb_map->get (old_loop_bb);
- if (!bbs || bbs->length () != 1)
- /* This is one of the places which shows preserving original structure
- is not always possible, as we may need to insert close PHI for a loop
- where the latch does not have any mapping, or the mapping is
- ambiguous. */
- return NULL;
-
- if (!new_loop)
- new_loop = (*bbs)[0]->loop_father;
- else if (new_loop != (*bbs)[0]->loop_father)
- return NULL;
- }
-
- if (!new_loop)
- return NULL;
-
- return single_exit (new_loop);
-}
-
/* Copies BB and includes in the copied BB all the statements that can
be reached following the use-def chains from the memory accesses,
and returns the next edge following this new block. */
@@ -2665,189 +1210,93 @@ edge_for_new_close_phis (basic_block bb)
edge translate_isl_ast_to_gimple::
copy_bb_and_scalar_dependences (basic_block bb, edge next_e, vec<tree> iv_map)
{
- int num_phis = number_of_phi_nodes (bb);
-
- if (region->copied_bb_map->get (bb))
- {
- /* FIXME: we should be able to handle phi nodes with args coming from
- outside the region. */
- if (num_phis)
- {
- codegen_error = true;
- return NULL;
- }
- }
-
- basic_block new_bb = NULL;
- if (bb_contains_loop_close_phi_nodes (bb))
+ basic_block new_bb = split_edge (next_e);
+ gimple_stmt_iterator gsi_tgt = gsi_last_bb (new_bb);
+ for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi);
+ gsi_next (&psi))
{
- if (dump_file)
- fprintf (dump_file, "[codegen] bb_%d contains close phi nodes.\n",
- bb->index);
+ gphi *phi = psi.phi ();
+ tree res = gimple_phi_result (phi);
+ if (virtual_operand_p (res)
+ || scev_analyzable_p (res, region->region))
+ continue;
- edge e = edge_for_new_close_phis (bb);
- if (!e)
+ tree new_phi_def;
+ tree *rename = region->rename_map->get (res);
+ if (! rename)
{
- codegen_error = true;
- return NULL;
+ new_phi_def = create_tmp_reg (TREE_TYPE (res));
+ set_rename (res, new_phi_def);
}
+ else
+ new_phi_def = *rename;
- basic_block phi_bb = e->dest;
-
- if (!bb_contains_loop_close_phi_nodes (phi_bb) || !single_succ_p (phi_bb))
- phi_bb = split_edge (e);
-
- gcc_assert (single_pred_edge (phi_bb)->src->loop_father
- != single_pred_edge (phi_bb)->dest->loop_father);
+ gassign *ass = gimple_build_assign (NULL_TREE, new_phi_def);
+ create_new_def_for (res, ass, NULL);
+ gsi_insert_after (&gsi_tgt, ass, GSI_NEW_STMT);
+ }
- if (!copy_loop_close_phi_nodes (bb, phi_bb, iv_map))
- {
- codegen_error = true;
- return NULL;
- }
+ graphite_copy_stmts_from_block (bb, new_bb, iv_map);
- if (e == next_e)
- new_bb = phi_bb;
- else
- new_bb = split_edge (next_e);
- }
- else
+ /* Insert out-of SSA copies on the original BB outgoing edges. */
+ gsi_tgt = gsi_last_bb (new_bb);
+ basic_block bb_for_succs = bb;
+ if (bb_for_succs == bb_for_succs->loop_father->latch
+ && bb_in_sese_p (bb_for_succs, region->region)
+ && sese_trivially_empty_bb_p (bb_for_succs))
+ bb_for_succs = NULL;
+ while (bb_for_succs)
{
- new_bb = split_edge (next_e);
- if (num_phis > 0 && bb_contains_loop_phi_nodes (bb))
+ basic_block latch = NULL;
+ edge_iterator ei;
+ edge e;
+ FOR_EACH_EDGE (e, ei, bb_for_succs->succs)
{
- basic_block phi_bb = next_e->dest->loop_father->header;
-
- /* At this point we are unable to codegenerate by still preserving the SSA
- structure because maybe the loop is completely unrolled and the PHIs
- and cross-bb scalar dependencies are untrackable w.r.t. the original
- code. See gfortran.dg/graphite/pr29832.f90. */
- if (EDGE_COUNT (bb->preds) != EDGE_COUNT (phi_bb->preds))
+ for (gphi_iterator psi = gsi_start_phis (e->dest); !gsi_end_p (psi);
+ gsi_next (&psi))
{
- codegen_error = true;
- return NULL;
- }
-
- /* In case isl did some loop peeling, like this:
-
- S_8(0);
- for (int c1 = 1; c1 <= 5; c1 += 1) {
- S_8(c1);
- }
- S_8(6);
-
- there should be no loop-phi nodes in S_8(0).
-
- FIXME: We need to reason about dynamic instances of S_8, i.e., the
- values of all scalar variables: for the moment we instantiate only
- SCEV analyzable expressions on the iteration domain, and we need to
- extend that to reductions that cannot be analyzed by SCEV. */
- if (!bb_in_sese_p (phi_bb, region->if_region->true_region->region))
- {
- codegen_error = true;
- return NULL;
- }
-
- if (dump_file)
- fprintf (dump_file, "[codegen] bb_%d contains loop phi nodes.\n",
- bb->index);
- if (!copy_loop_phi_nodes (bb, phi_bb))
- {
- codegen_error = true;
- return NULL;
- }
- }
- else if (num_phis > 0)
- {
- if (dump_file)
- fprintf (dump_file, "[codegen] bb_%d contains cond phi nodes.\n",
- bb->index);
-
- basic_block phi_bb = single_pred (new_bb);
- loop_p loop_father = new_bb->loop_father;
+ gphi *phi = psi.phi ();
+ tree res = gimple_phi_result (phi);
+ if (virtual_operand_p (res)
+ || scev_analyzable_p (res, region->region))
+ continue;
- /* Move back until we find the block with two predecessors. */
- while (single_pred_p (phi_bb))
- phi_bb = single_pred_edge (phi_bb)->src;
+ tree new_phi_def;
+ tree *rename = region->rename_map->get (res);
+ if (! rename)
+ {
+ new_phi_def = create_tmp_reg (TREE_TYPE (res));
+ set_rename (res, new_phi_def);
+ }
+ else
+ new_phi_def = *rename;
- /* If a corresponding merge-point was not found, then abort codegen. */
- if (phi_bb->loop_father != loop_father
- || !bb_in_sese_p (phi_bb, region->if_region->true_region->region)
- || !copy_cond_phi_nodes (bb, phi_bb, iv_map))
- {
- codegen_error = true;
- return NULL;
+ tree arg = PHI_ARG_DEF_FROM_EDGE (phi, e);
+ if (TREE_CODE (arg) == SSA_NAME
+ && scev_analyzable_p (arg, region->region))
+ {
+ gimple_seq stmts = NULL;
+ tree new_name = get_rename_from_scev (arg, &stmts,
+ bb->loop_father,
+ iv_map);
+ if (! codegen_error_p ())
+ gsi_insert_earliest (stmts);
+ arg = new_name;
+ }
+ gassign *ass = gimple_build_assign (new_phi_def, arg);
+ gsi_insert_after (&gsi_tgt, ass, GSI_NEW_STMT);
}
+ if (e->dest == bb_for_succs->loop_father->latch
+ && bb_in_sese_p (e->dest, region->region)
+ && sese_trivially_empty_bb_p (e->dest))
+ latch = e->dest;
}
- }
-
- if (dump_file)
- fprintf (dump_file, "[codegen] copying from bb_%d to bb_%d.\n",
- bb->index, new_bb->index);
-
- vec <basic_block> *copied_bbs = region->copied_bb_map->get (bb);
- if (copied_bbs)
- copied_bbs->safe_push (new_bb);
- else
- {
- vec<basic_block> bbs;
- bbs.create (2);
- bbs.safe_push (new_bb);
- region->copied_bb_map->put (bb, bbs);
- }
-
- if (!graphite_copy_stmts_from_block (bb, new_bb, iv_map))
- {
- codegen_error = true;
- return NULL;
+ bb_for_succs = latch;
}
return single_succ_edge (new_bb);
}
-/* Patch the missing arguments of the phi nodes. */
-
-void translate_isl_ast_to_gimple::
-translate_pending_phi_nodes ()
-{
- int i;
- phi_rename *rename;
- FOR_EACH_VEC_ELT (region->incomplete_phis, i, rename)
- {
- gphi *old_phi = rename->first;
- gphi *new_phi = rename->second;
- basic_block old_bb = gimple_bb (old_phi);
- basic_block new_bb = gimple_bb (new_phi);
-
- /* First edge is the init edge and second is the back edge. */
- init_back_edge_pair_t ibp_old_bb = get_edges (old_bb);
- init_back_edge_pair_t ibp_new_bb = get_edges (new_bb);
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] translating pending old-phi: ");
- print_gimple_stmt (dump_file, old_phi, 0);
- }
-
- auto_vec <tree, 1> iv_map;
- if (bb_contains_loop_phi_nodes (new_bb))
- codegen_error = !copy_loop_phi_args (old_phi, ibp_old_bb, new_phi,
- ibp_new_bb, false);
- else if (bb_contains_loop_close_phi_nodes (new_bb))
- codegen_error = !copy_loop_close_phi_args (old_bb, new_bb, iv_map, false);
- else
- codegen_error = !copy_cond_phi_args (old_phi, new_phi, iv_map, false);
-
- if (dump_file)
- {
- fprintf (dump_file, "[codegen] to new-phi: ");
- print_gimple_stmt (dump_file, new_phi, 0);
- }
- if (codegen_error_p ())
- return;
- }
-}
-
/* Add isl's parameter identifiers and corresponding trees to ivs_params. */
void translate_isl_ast_to_gimple::
@@ -2855,13 +1304,14 @@ add_parameters_to_ivs_params (scop_p scop, ivs_params &ip)
{
sese_info_p region = scop->scop_info;
unsigned nb_parameters = isl_set_dim (scop->param_context, isl_dim_param);
- gcc_assert (nb_parameters == region->params.length ());
+ gcc_assert (nb_parameters == sese_nb_params (region));
unsigned i;
- for (i = 0; i < nb_parameters; i++)
+ tree param;
+ FOR_EACH_VEC_ELT (region->params, i, param)
{
isl_id *tmp_id = isl_set_get_dim_id (scop->param_context,
isl_dim_param, i);
- ip[tmp_id] = region->params[i];
+ ip[tmp_id] = param;
}
}
@@ -2897,6 +1347,13 @@ ast_build_before_for (__isl_keep isl_ast_build *build, void *user)
__isl_give isl_ast_node *translate_isl_ast_to_gimple::
scop_to_isl_ast (scop_p scop)
{
+ int old_err = isl_options_get_on_error (scop->isl_context);
+ int old_max_operations = isl_ctx_get_max_operations (scop->isl_context);
+ int max_operations = PARAM_VALUE (PARAM_MAX_ISL_OPERATIONS);
+ if (max_operations)
+ isl_ctx_set_max_operations (scop->isl_context, max_operations);
+ isl_options_set_on_error (scop->isl_context, ISL_ON_ERROR_CONTINUE);
+
gcc_assert (scop->transformed_schedule);
/* Set the separate option to reduce control flow overhead. */
@@ -2915,70 +1372,56 @@ scop_to_isl_ast (scop_p scop)
isl_ast_node *ast_isl = isl_ast_build_node_from_schedule
(context_isl, schedule);
isl_ast_build_free (context_isl);
+
+ isl_options_set_on_error (scop->isl_context, old_err);
+ isl_ctx_reset_operations (scop->isl_context);
+ isl_ctx_set_max_operations (scop->isl_context, old_max_operations);
+ if (isl_ctx_last_error (scop->isl_context) != isl_error_none)
+ {
+ location_t loc = find_loop_location
+ (scop->scop_info->region.entry->dest->loop_father);
+ if (isl_ctx_last_error (scop->isl_context) == isl_error_quota)
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
+ "loop nest not optimized, AST generation timed out "
+ "after %d operations [--param max-isl-operations]\n",
+ max_operations);
+ else
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
+ "loop nest not optimized, ISL AST generation "
+ "signalled an error\n");
+ isl_ast_node_free (ast_isl);
+ return NULL;
+ }
+
return ast_isl;
}
-/* Copy def from sese REGION to the newly created TO_REGION. TR is defined by
- DEF_STMT. GSI points to entry basic block of the TO_REGION. */
+/* Generate out-of-SSA copies for the entry edge FALSE_ENTRY/TRUE_ENTRY
+ in REGION. */
static void
-copy_def (tree tr, gimple *def_stmt, sese_info_p region, sese_info_p to_region,
- gimple_stmt_iterator *gsi)
+generate_entry_out_of_ssa_copies (edge false_entry,
+ edge true_entry,
+ sese_info_p region)
{
- if (!defined_in_sese_p (tr, region->region))
- return;
-
- ssa_op_iter iter;
- use_operand_p use_p;
- FOR_EACH_SSA_USE_OPERAND (use_p, def_stmt, iter, SSA_OP_USE)
+ gimple_stmt_iterator gsi_tgt = gsi_start_bb (true_entry->dest);
+ for (gphi_iterator psi = gsi_start_phis (false_entry->dest);
+ !gsi_end_p (psi); gsi_next (&psi))
{
- tree use_tr = USE_FROM_PTR (use_p);
-
- /* Do not copy parameters that have been generated in the header of the
- scop. */
- if (region->parameter_rename_map->get(use_tr))
+ gphi *phi = psi.phi ();
+ tree res = gimple_phi_result (phi);
+ if (virtual_operand_p (res))
continue;
-
- gimple *def_of_use = SSA_NAME_DEF_STMT (use_tr);
- if (!def_of_use)
+ /* When there's no out-of-SSA var registered do not bother
+ to create one. */
+ tree *rename = region->rename_map->get (res);
+ if (! rename)
continue;
-
- copy_def (use_tr, def_of_use, region, to_region, gsi);
- }
-
- gimple *copy = gimple_copy (def_stmt);
- gsi_insert_after (gsi, copy, GSI_NEW_STMT);
-
- /* Create new names for all the definitions created by COPY and
- add replacement mappings for each new name. */
- def_operand_p def_p;
- ssa_op_iter op_iter;
- FOR_EACH_SSA_DEF_OPERAND (def_p, copy, op_iter, SSA_OP_ALL_DEFS)
- {
- tree old_name = DEF_FROM_PTR (def_p);
- tree new_name = create_new_def_for (old_name, copy, def_p);
- region->parameter_rename_map->put(old_name, new_name);
- }
-
- update_stmt (copy);
-}
-
-static void
-copy_internal_parameters (sese_info_p region, sese_info_p to_region)
-{
- /* For all the parameters which definitino is in the if_region->false_region,
- insert code on true_region (if_region->true_region->entry). */
-
- int i;
- tree tr;
- gimple_stmt_iterator gsi = gsi_start_bb(to_region->region.entry->dest);
-
- FOR_EACH_VEC_ELT (region->params, i, tr)
- {
- // If def is not in region.
- gimple *def_stmt = SSA_NAME_DEF_STMT (tr);
- if (def_stmt)
- copy_def (tr, def_stmt, region, to_region, &gsi);
+ tree new_phi_def = *rename;
+ gassign *ass = gimple_build_assign (new_phi_def,
+ PHI_ARG_DEF_FROM_EDGE (phi,
+ false_entry));
+ gsi_insert_after (&gsi_tgt, ass, GSI_NEW_STMT);
}
}
@@ -2998,6 +1441,12 @@ graphite_regenerate_ast_isl (scop_p scop)
timevar_push (TV_GRAPHITE_CODE_GEN);
t.add_parameters_to_ivs_params (scop, ip);
root_node = t.scop_to_isl_ast (scop);
+ if (! root_node)
+ {
+ ivs_params_clear (ip);
+ timevar_pop (TV_GRAPHITE_CODE_GEN);
+ return false;
+ }
if (dump_file && (dump_flags & TDF_DETAILS))
{
@@ -3012,18 +1461,10 @@ graphite_regenerate_ast_isl (scop_p scop)
print_isl_ast (dump_file, root_node);
}
- recompute_all_dominators ();
- graphite_verify ();
-
if_region = move_sese_in_condition (region);
region->if_region = if_region;
- recompute_all_dominators ();
loop_p context_loop = region->region.entry->src->loop_father;
-
- /* Copy all the parameters which are defined in the region. */
- copy_internal_parameters(if_region->false_region, if_region->true_region);
-
edge e = single_succ_edge (if_region->true_region->region.entry->dest);
basic_block bb = split_edge (e);
@@ -3031,43 +1472,47 @@ graphite_regenerate_ast_isl (scop_p scop)
region->if_region->true_region->region.exit = single_succ_edge (bb);
t.translate_isl_ast (context_loop, root_node, e, ip);
- if (t.codegen_error_p ())
- {
+ if (! t.codegen_error_p ())
+ {
+ generate_entry_out_of_ssa_copies (if_region->false_region->region.entry,
+ if_region->true_region->region.entry,
+ region);
+ sese_insert_phis_for_liveouts (region,
+ if_region->region->region.exit->src,
+ if_region->false_region->region.exit,
+ if_region->true_region->region.exit);
if (dump_file)
- fprintf (dump_file, "codegen error: "
- "reverting back to the original code.\n");
- set_ifsese_condition (if_region, integer_zero_node);
+ fprintf (dump_file, "[codegen] isl AST to Gimple succeeded.\n");
}
- else
- {
- t.translate_pending_phi_nodes ();
- if (!t.codegen_error_p ())
- {
- sese_insert_phis_for_liveouts (region,
- if_region->region->region.exit->src,
- if_region->false_region->region.exit,
- if_region->true_region->region.exit);
- mark_virtual_operands_for_renaming (cfun);
- update_ssa (TODO_update_ssa);
-
- graphite_verify ();
- scev_reset ();
- recompute_all_dominators ();
- graphite_verify ();
-
- if (dump_file)
- fprintf (dump_file, "[codegen] isl AST to Gimple succeeded.\n");
- }
- else
- {
- if (dump_file)
- fprintf (dump_file, "[codegen] unsuccessful in translating"
- " pending phis, reverting back to the original code.\n");
- set_ifsese_condition (if_region, integer_zero_node);
- }
+ if (t.codegen_error_p ())
+ {
+ location_t loc = find_loop_location
+ (scop->scop_info->region.entry->dest->loop_father);
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
+ "loop nest not optimized, code generation error\n");
+
+ /* Remove the unreachable region. */
+ remove_edge_and_dominated_blocks (if_region->true_region->region.entry);
+ basic_block ifb = if_region->false_region->region.entry->src;
+ gimple_stmt_iterator gsi = gsi_last_bb (ifb);
+ gsi_remove (&gsi, true);
+ if_region->false_region->region.entry->flags &= ~EDGE_FALSE_VALUE;
+ if_region->false_region->region.entry->flags |= EDGE_FALLTHRU;
+ /* remove_edge_and_dominated_blocks marks loops for removal but
+ doesn't actually remove them (fix that...). */
+ loop_p loop;
+ FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+ if (! loop->header)
+ delete_loop (loop);
}
+ /* We are delaying SSA update to after code-generating all SCOPs.
+ This is because we analyzed DRs and parameters on the unmodified
+ IL and thus rely on SSA update to pick up new dominating definitions
+ from for example SESE liveout PHIs. This is also for efficiency
+ as SSA update does work depending on the size of the function. */
+
free (if_region->true_region);
free (if_region->region);
free (if_region);
@@ -3076,19 +1521,6 @@ graphite_regenerate_ast_isl (scop_p scop)
isl_ast_node_free (root_node);
timevar_pop (TV_GRAPHITE_CODE_GEN);
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- loop_p loop;
- int num_no_dependency = 0;
-
- FOR_EACH_LOOP (loop, 0)
- if (loop->can_be_parallel)
- num_no_dependency++;
-
- fprintf (dump_file, "%d loops carried no dependency.\n",
- num_no_dependency);
- }
-
return !t.codegen_error_p ();
}
diff --git a/gcc/graphite-optimize-isl.c b/gcc/graphite-optimize-isl.c
index 467503e..e1b9606 100644
--- a/gcc/graphite-optimize-isl.c
+++ b/gcc/graphite-optimize-isl.c
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-data-ref.h"
#include "params.h"
#include "dumpfile.h"
+#include "tree-vectorizer.h"
#include "graphite.h"
@@ -63,7 +64,10 @@ get_schedule_for_node_st (__isl_take isl_schedule_node *node, void *user)
if (type != isl_schedule_node_leaf)
return node;
- if (dims <= 1 || !isl_schedule_node_band_get_permutable (node))
+ long tile_size = PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE);
+ if (dims <= 1
+ || tile_size == 0
+ || !isl_schedule_node_band_get_permutable (node))
{
if (dump_file && dump_flags)
fprintf (dump_file, "not tiled\n");
@@ -73,7 +77,6 @@ get_schedule_for_node_st (__isl_take isl_schedule_node *node, void *user)
/* Tile loops. */
space = isl_schedule_node_band_get_space (node);
isl_multi_val *sizes = isl_multi_val_zero (space);
- long tile_size = PARAM_VALUE (PARAM_LOOP_BLOCK_TILE_SIZE);
isl_ctx *ctx = isl_schedule_node_get_ctx (node);
for (unsigned i = 0; i < dims; i++)
@@ -110,6 +113,7 @@ scop_get_domains (scop_p scop)
static bool
optimize_isl (scop_p scop)
{
+ int old_err = isl_options_get_on_error (scop->isl_context);
int old_max_operations = isl_ctx_get_max_operations (scop->isl_context);
int max_operations = PARAM_VALUE (PARAM_MAX_ISL_OPERATIONS);
if (max_operations)
@@ -149,16 +153,23 @@ optimize_isl (scop_p scop)
scop->transformed_schedule =
isl_schedule_map_schedule_node_bottom_up (scop->transformed_schedule,
get_schedule_for_node_st, NULL);
- isl_options_set_on_error (scop->isl_context, ISL_ON_ERROR_ABORT);
+ isl_options_set_on_error (scop->isl_context, old_err);
isl_ctx_reset_operations (scop->isl_context);
isl_ctx_set_max_operations (scop->isl_context, old_max_operations);
if (!scop->transformed_schedule
- || isl_ctx_last_error (scop->isl_context) == isl_error_quota)
+ || isl_ctx_last_error (scop->isl_context) != isl_error_none)
{
- if (dump_file && dump_flags)
- fprintf (dump_file, "isl timed out --param max-isl-operations=%d\n",
- max_operations);
+ location_t loc = find_loop_location
+ (scop->scop_info->region.entry->dest->loop_father);
+ if (isl_ctx_last_error (scop->isl_context) == isl_error_quota)
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
+ "loop nest not optimized, optimization timed out "
+ "after %d operations [--param max-isl-operations]\n",
+ max_operations);
+ else
+ dump_printf_loc (MSG_MISSED_OPTIMIZATION, loc,
+ "loop nest not optimized, ISL signalled an error\n");
return false;
}
@@ -171,15 +182,16 @@ optimize_isl (scop_p scop)
if (same_schedule)
{
+ location_t loc = find_loop_location
+ (scop->scop_info->region.entry->dest->loop_father);
+ dump_printf_loc (MSG_NOTE, loc,
+ "loop nest not optimized, optimized schedule is "
+ "identical to original schedule\n");
if (dump_file)
- {
- fprintf (dump_file, "[scheduler] isl optimized schedule is "
- "identical to the original schedule.\n");
- print_schedule_ast (dump_file, scop->original_schedule, scop);
- }
+ print_schedule_ast (dump_file, scop->original_schedule, scop);
isl_schedule_free (scop->transformed_schedule);
scop->transformed_schedule = isl_schedule_copy (scop->original_schedule);
- return false;
+ return flag_graphite_identity || flag_loop_parallelize_all;
}
return true;
diff --git a/gcc/graphite-scop-detection.c b/gcc/graphite-scop-detection.c
index 3ed6afd..c236556 100644
--- a/gcc/graphite-scop-detection.c
+++ b/gcc/graphite-scop-detection.c
@@ -48,6 +48,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-pass.h"
#include "tree-ssa-propagate.h"
#include "gimple-pretty-print.h"
+#include "cfganal.h"
#include "graphite.h"
class debug_printer
@@ -253,223 +254,6 @@ dot_cfg ()
scops.release ();
}
-/* Return true if BB is empty, contains only DEBUG_INSNs. */
-
-static bool
-trivially_empty_bb_p (basic_block bb)
-{
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- if (gimple_code (gsi_stmt (gsi)) != GIMPLE_DEBUG)
- return false;
-
- return true;
-}
-
-/* Returns true when P1 and P2 are close phis with the same
- argument. */
-
-static inline bool
-same_close_phi_node (gphi *p1, gphi *p2)
-{
- return (types_compatible_p (TREE_TYPE (gimple_phi_result (p1)),
- TREE_TYPE (gimple_phi_result (p2)))
- && operand_equal_p (gimple_phi_arg_def (p1, 0),
- gimple_phi_arg_def (p2, 0), 0));
-}
-
-static void make_close_phi_nodes_unique (basic_block bb);
-
-/* Remove the close phi node at GSI and replace its rhs with the rhs
- of PHI. */
-
-static void
-remove_duplicate_close_phi (gphi *phi, gphi_iterator *gsi)
-{
- gimple *use_stmt;
- use_operand_p use_p;
- imm_use_iterator imm_iter;
- tree res = gimple_phi_result (phi);
- tree def = gimple_phi_result (gsi->phi ());
-
- gcc_assert (same_close_phi_node (phi, gsi->phi ()));
-
- FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, def)
- {
- FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
- SET_USE (use_p, res);
-
- update_stmt (use_stmt);
-
- /* It is possible that we just created a duplicate close-phi
- for an already-processed containing loop. Check for this
- case and clean it up. */
- if (gimple_code (use_stmt) == GIMPLE_PHI
- && gimple_phi_num_args (use_stmt) == 1)
- make_close_phi_nodes_unique (gimple_bb (use_stmt));
- }
-
- remove_phi_node (gsi, true);
-}
-
-/* Removes all the close phi duplicates from BB. */
-
-static void
-make_close_phi_nodes_unique (basic_block bb)
-{
- gphi_iterator psi;
-
- for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
- {
- gphi_iterator gsi = psi;
- gphi *phi = psi.phi ();
-
- /* At this point, PHI should be a close phi in normal form. */
- gcc_assert (gimple_phi_num_args (phi) == 1);
-
- /* Iterate over the next phis and remove duplicates. */
- gsi_next (&gsi);
- while (!gsi_end_p (gsi))
- if (same_close_phi_node (phi, gsi.phi ()))
- remove_duplicate_close_phi (phi, &gsi);
- else
- gsi_next (&gsi);
- }
-}
-
-/* Return true when NAME is defined in LOOP. */
-
-static bool
-defined_in_loop_p (tree name, loop_p loop)
-{
- gcc_assert (TREE_CODE (name) == SSA_NAME);
- return loop == loop_containing_stmt (SSA_NAME_DEF_STMT (name));
-}
-
-/* Transforms LOOP to the canonical loop closed SSA form. */
-
-static void
-canonicalize_loop_closed_ssa (loop_p loop)
-{
- edge e = single_exit (loop);
- basic_block bb;
-
- if (!e || e->flags & EDGE_ABNORMAL)
- return;
-
- bb = e->dest;
-
- if (single_pred_p (bb))
- {
- e = split_block_after_labels (bb);
- DEBUG_PRINT (dp << "Splitting bb_" << bb->index << ".\n");
- make_close_phi_nodes_unique (e->src);
- }
- else
- {
- gphi_iterator psi;
- basic_block close = split_edge (e);
-
- e = single_succ_edge (close);
- DEBUG_PRINT (dp << "Splitting edge (" << e->src->index << ","
- << e->dest->index << ")\n");
-
- for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
- {
- gphi *phi = psi.phi ();
- unsigned i;
-
- for (i = 0; i < gimple_phi_num_args (phi); i++)
- if (gimple_phi_arg_edge (phi, i) == e)
- {
- tree res, arg = gimple_phi_arg_def (phi, i);
- use_operand_p use_p;
- gphi *close_phi;
-
- /* Only add close phi nodes for SSA_NAMEs defined in LOOP. */
- if (TREE_CODE (arg) != SSA_NAME
- || !defined_in_loop_p (arg, loop))
- continue;
-
- close_phi = create_phi_node (NULL_TREE, close);
- res = create_new_def_for (arg, close_phi,
- gimple_phi_result_ptr (close_phi));
- add_phi_arg (close_phi, arg,
- gimple_phi_arg_edge (close_phi, 0),
- UNKNOWN_LOCATION);
- use_p = gimple_phi_arg_imm_use_ptr (phi, i);
- replace_exp (use_p, res);
- update_stmt (phi);
- }
- }
-
- make_close_phi_nodes_unique (close);
- }
-
- /* The code above does not properly handle changes in the post dominance
- information (yet). */
- recompute_all_dominators ();
-}
-
-/* Converts the current loop closed SSA form to a canonical form
- expected by the Graphite code generation.
-
- The loop closed SSA form has the following invariant: a variable
- defined in a loop that is used outside the loop appears only in the
- phi nodes in the destination of the loop exit. These phi nodes are
- called close phi nodes.
-
- The canonical loop closed SSA form contains the extra invariants:
-
- - when the loop contains only one exit, the close phi nodes contain
- only one argument. That implies that the basic block that contains
- the close phi nodes has only one predecessor, that is a basic block
- in the loop.
-
- - the basic block containing the close phi nodes does not contain
- other statements.
-
- - there exist only one phi node per definition in the loop.
-*/
-
-static void
-canonicalize_loop_closed_ssa_form (void)
-{
- checking_verify_loop_closed_ssa (true);
-
- loop_p loop;
- FOR_EACH_LOOP (loop, 0)
- canonicalize_loop_closed_ssa (loop);
-
- rewrite_into_loop_closed_ssa (NULL, TODO_update_ssa);
- update_ssa (TODO_update_ssa);
-
- checking_verify_loop_closed_ssa (true);
-}
-
-/* Can all ivs be represented by a signed integer?
- As isl might generate negative values in its expressions, signed loop ivs
- are required in the backend. */
-
-static bool
-loop_ivs_can_be_represented (loop_p loop)
-{
- unsigned type_long_long = TYPE_PRECISION (long_long_integer_type_node);
- for (gphi_iterator psi = gsi_start_phis (loop->header); !gsi_end_p (psi);
- gsi_next (&psi))
- {
- gphi *phi = psi.phi ();
- tree res = PHI_RESULT (phi);
- tree type = TREE_TYPE (res);
-
- if (TYPE_UNSIGNED (type) && TYPE_PRECISION (type) >= type_long_long)
- return false;
- }
-
- return true;
-}
-
/* Returns a COND_EXPR statement when BB has a single predecessor, the
edge between BB and its predecessor is not a loop exit edge, and
the last statement of the single predecessor is a COND_EXPR. */
@@ -542,17 +326,7 @@ public:
/* Build scop outer->inner if possible. */
- sese_l build_scop_depth (sese_l s, loop_p loop);
-
- /* If loop and loop->next are valid scops, try to merge them. */
-
- sese_l build_scop_breadth (sese_l s1, loop_p loop);
-
- /* Return true when LOOP is a valid scop, that is a Static Control Part, a
- region of code that can be represented in the polyhedral model. SCOP
- defines the region we analyse. */
-
- bool loop_is_valid_in_scop (loop_p loop, sese_l scop) const;
+ void build_scop_depth (loop_p loop);
/* Return true when BEGIN is the preheader edge of a loop with a single exit
END. */
@@ -578,22 +352,7 @@ public:
void remove_intersecting_scops (sese_l s1);
- /* Return true when the body of LOOP has statements that can be represented
- as a valid scop. */
-
- bool loop_body_is_valid_scop (loop_p loop, sese_l scop) const;
-
- /* Return true when BB contains a harmful operation for a scop: that
- can be a function call with side effects, the induction variables
- are not linear with respect to SCOP, etc. The current open
- scop should end before this statement. */
-
- bool harmful_stmt_in_bb (sese_l scop, basic_block bb) const;
-
- /* Return true when a statement in SCOP cannot be represented by Graphite.
- The assumptions are that L1 dominates L2, and SCOP->entry dominates L1.
- Limit the number of bbs between adjacent loops to
- PARAM_SCOP_MAX_NUM_BBS_BETWEEN_LOOPS. */
+ /* Return true when a statement in SCOP cannot be represented by Graphite. */
bool harmful_loop_in_region (sese_l scop) const;
@@ -622,7 +381,7 @@ public:
Something like "i * n" or "n * m" is not allowed. */
- static bool graphite_can_represent_scev (tree scev);
+ static bool graphite_can_represent_scev (sese_l scop, tree scev);
/* Return true when EXPR can be represented in the polyhedral model.
@@ -647,19 +406,12 @@ public:
FIXME: For the moment, graphite cannot be used on loops that iterate using
induction variables that wrap. */
- static bool can_represent_loop_1 (loop_p loop, sese_l scop);
-
- /* Return true when all the loops within LOOP can be represented by
- Graphite. */
-
static bool can_represent_loop (loop_p loop, sese_l scop);
/* Returns the number of pbbs that are in loops contained in SCOP. */
static int nb_pbbs_in_loops (scop_p scop);
- static bool graphite_can_represent_stmt (sese_l, gimple *, basic_block);
-
private:
vec<sese_l> scops;
};
@@ -674,14 +426,19 @@ scop_detection::get_sese (loop_p loop)
if (!loop)
return invalid_sese;
- if (!loops_state_satisfies_p (LOOPS_HAVE_PREHEADERS))
- return invalid_sese;
+ edge scop_begin = loop_preheader_edge (loop);
edge scop_end = single_exit (loop);
- if (!scop_end)
+ if (!scop_end || (scop_end->flags & EDGE_COMPLEX))
return invalid_sese;
- edge scop_begin = loop_preheader_edge (loop);
- sese_l s (scop_begin, scop_end);
- return s;
+ /* Include the BB with the loop-closed SSA PHI nodes.
+ canonicalize_loop_closed_ssa makes sure that is in proper shape. */
+ if (! single_pred_p (scop_end->dest)
+ || ! single_succ_p (scop_end->dest)
+ || ! sese_trivially_empty_bb_p (scop_end->dest))
+ gcc_unreachable ();
+ scop_end = single_succ_edge (scop_end->dest);
+
+ return sese_l (scop_begin, scop_end);
}
/* Return the closest dominator with a single entry edge. */
@@ -848,30 +605,6 @@ scop_detection::merge_sese (sese_l first, sese_l second) const
return invalid_sese;
}
- /* FIXME: We should remove this piece of code once
- canonicalize_loop_closed_ssa has been removed, because that function
- adds a BB with single exit. */
- if (!trivially_empty_bb_p (get_exit_bb (combined)))
- {
- /* Find the first empty succ (with single exit) of combined.exit. */
- basic_block imm_succ = combined.exit->dest;
- if (single_succ_p (imm_succ)
- && single_pred_p (imm_succ)
- && trivially_empty_bb_p (imm_succ))
- combined.exit = single_succ_edge (imm_succ);
- else
- {
- DEBUG_PRINT (dp << "[scop-detection-fail] Discarding SCoP because "
- << "no single exit (empty succ) for sese exit";
- print_sese (dump_file, combined));
- return invalid_sese;
- }
- }
-
- /* Analyze all the BBs in new sese. */
- if (harmful_loop_in_region (combined))
- return invalid_sese;
-
DEBUG_PRINT (dp << "[merged-sese] s1: "; print_sese (dump_file, combined));
return combined;
@@ -879,71 +612,40 @@ scop_detection::merge_sese (sese_l first, sese_l second) const
/* Build scop outer->inner if possible. */
-sese_l
-scop_detection::build_scop_depth (sese_l s, loop_p loop)
-{
- if (!loop)
- return s;
-
- DEBUG_PRINT (dp << "[Depth loop_" << loop->num << "]\n");
- s = build_scop_depth (s, loop->inner);
-
- sese_l s2 = merge_sese (s, get_sese (loop));
- if (!s2)
- {
- /* s might be a valid scop, so return it and start analyzing from the
- adjacent loop. */
- build_scop_depth (invalid_sese, loop->next);
- return s;
- }
-
- if (!loop_is_valid_in_scop (loop, s2))
- return build_scop_depth (invalid_sese, loop->next);
-
- return build_scop_breadth (s2, loop);
-}
-
-/* If loop and loop->next are valid scops, try to merge them. */
-
-sese_l
-scop_detection::build_scop_breadth (sese_l s1, loop_p loop)
+void
+scop_detection::build_scop_depth (loop_p loop)
{
- if (!loop)
- return s1;
- DEBUG_PRINT (dp << "[Breadth loop_" << loop->num << "]\n");
- gcc_assert (s1);
-
- loop_p l = loop;
- sese_l s2 = build_scop_depth (invalid_sese, l->next);
- if (!s2)
+ sese_l s = invalid_sese;
+ loop = loop->inner;
+ while (loop)
{
- if (s1)
- add_scop (s1);
- return s1;
- }
-
- sese_l combined = merge_sese (s1, s2);
-
- /* Combining adjacent loops may add unrelated loops into the
- region so we have to check all sub-loops of the outer loop
- that are in the combined region. */
- if (combined)
- for (l = loop_outer (loop)->inner; l; l = l->next)
- if (bb_in_sese_p (l->header, combined)
- && ! loop_is_valid_in_scop (l, combined))
+ sese_l next = get_sese (loop);
+ if (! next
+ || harmful_loop_in_region (next))
{
- combined = invalid_sese;
- break;
+ if (s)
+ add_scop (s);
+ build_scop_depth (loop);
+ s = invalid_sese;
}
-
- if (combined)
- s1 = combined;
- else
- add_scop (s2);
-
- if (s1)
- add_scop (s1);
- return s1;
+ else if (! s)
+ s = next;
+ else
+ {
+ sese_l combined = merge_sese (s, next);
+ if (! combined
+ || harmful_loop_in_region (combined))
+ {
+ add_scop (s);
+ s = next;
+ }
+ else
+ s = combined;
+ }
+ loop = loop->next;
+ }
+ if (s)
+ add_scop (s);
}
/* Returns true when Graphite can represent LOOP in SCOP.
@@ -951,7 +653,7 @@ scop_detection::build_scop_breadth (sese_l s1, loop_p loop)
induction variables that wrap. */
bool
-scop_detection::can_represent_loop_1 (loop_p loop, sese_l scop)
+scop_detection::can_represent_loop (loop_p loop, sese_l scop)
{
tree niter;
struct tree_niter_desc niter_desc;
@@ -967,53 +669,6 @@ scop_detection::can_represent_loop_1 (loop_p loop, sese_l scop)
&& graphite_can_represent_expr (scop, loop, niter);
}
-/* Return true when all the loops within LOOP can be represented by
- Graphite. */
-
-bool
-scop_detection::can_represent_loop (loop_p loop, sese_l scop)
-{
- if (!can_represent_loop_1 (loop, scop))
- return false;
- for (loop_p inner = loop->inner; inner; inner = inner->next)
- if (!can_represent_loop (inner, scop))
- return false;
- return true;
-}
-
-/* Return true when LOOP is a valid scop, that is a Static Control Part, a
- region of code that can be represented in the polyhedral model. SCOP
- defines the region we analyse. */
-
-bool
-scop_detection::loop_is_valid_in_scop (loop_p loop, sese_l scop) const
-{
- if (!scop)
- return false;
-
- if (!optimize_loop_nest_for_speed_p (loop))
- {
- DEBUG_PRINT (dp << "[scop-detection-fail] loop_"
- << loop->num << " is not on a hot path.\n");
- return false;
- }
-
- if (!can_represent_loop (loop, scop))
- {
- DEBUG_PRINT (dp << "[scop-detection-fail] cannot represent loop_"
- << loop->num << "\n");
- return false;
- }
-
- if (loop_body_is_valid_scop (loop, scop))
- {
- DEBUG_PRINT (dp << "[valid-scop] loop_" << loop->num
- << " is a valid scop.\n");
- return true;
- }
- return false;
-}
-
/* Return true when BEGIN is the preheader edge of a loop with a single exit
END. */
@@ -1027,7 +682,8 @@ scop_detection::region_has_one_loop (sese_l s)
return false;
/* Otherwise, check whether we have adjacent loops. */
- return begin->dest->loop_father == end->src->loop_father;
+ return (single_pred_p (end->src)
+ && begin->dest->loop_father == single_pred (end->src)->loop_father);
}
/* Add to SCOPS a scop starting at SCOP_BEGIN and ending at SCOP_END. */
@@ -1064,10 +720,7 @@ scop_detection::add_scop (sese_l s)
DEBUG_PRINT (dp << "[scop-detection] Adding SCoP: "; print_sese (dump_file, s));
}
-/* Return true when a statement in SCOP cannot be represented by Graphite.
- The assumptions are that L1 dominates L2, and SCOP->entry dominates L1.
- Limit the number of bbs between adjacent loops to
- PARAM_SCOP_MAX_NUM_BBS_BETWEEN_LOOPS. */
+/* Return true when a statement in SCOP cannot be represented by Graphite. */
bool
scop_detection::harmful_loop_in_region (sese_l scop) const
@@ -1108,14 +761,12 @@ scop_detection::harmful_loop_in_region (sese_l scop) const
loop_p loop = bb->loop_father;
if (loop_in_sese_p (loop, scop))
bitmap_set_bit (loops, loop->num);
- else
- {
- /* We only check for harmful statements in basic blocks not part of
- any loop fully contained in the scop: other bbs are checked below
- in loop_is_valid_in_scop. */
- if (harmful_stmt_in_bb (scop, bb))
- return true;
- }
+
+ /* Check for harmful statements in basic blocks part of the region. */
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bb);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ if (!stmt_simple_for_scop_p (scop, gsi_stmt (gsi), bb))
+ return true;
if (bb != exit_bb)
for (basic_block dom = first_dom_son (CDI_DOMINATORS, bb);
@@ -1133,8 +784,34 @@ scop_detection::harmful_loop_in_region (sese_l scop) const
loop_p loop = (*current_loops->larray)[j];
gcc_assert (loop->num == (int) j);
- if (!loop_is_valid_in_scop (loop, scop))
- return true;
+ /* Check if the loop nests are to be optimized for speed. */
+ if (! loop->inner
+ && ! optimize_loop_for_speed_p (loop))
+ {
+ DEBUG_PRINT (dp << "[scop-detection-fail] loop_"
+ << loop->num << " is not on a hot path.\n");
+ return true;
+ }
+
+ if (! can_represent_loop (loop, scop))
+ {
+ DEBUG_PRINT (dp << "[scop-detection-fail] cannot represent loop_"
+ << loop->num << "\n");
+ return true;
+ }
+
+ /* Check if all loop nests have at least one data reference.
+ ??? This check is expensive and loops premature at this point.
+ If important to retain we can pre-compute this for all innermost
+ loops and reject those when we build a SESE region for a loop
+ during SESE discovery. */
+ if (! loop->inner
+ && ! loop_nest_has_data_refs (loop))
+ {
+ DEBUG_PRINT (dp << "[scop-detection-fail] loop_" << loop->num
+ << "does not have any data reference.\n");
+ return true;
+ }
}
return false;
@@ -1257,32 +934,24 @@ scop_detection::graphite_can_represent_init (tree e)
Something like "i * n" or "n * m" is not allowed. */
bool
-scop_detection::graphite_can_represent_scev (tree scev)
+scop_detection::graphite_can_represent_scev (sese_l scop, tree scev)
{
if (chrec_contains_undetermined (scev))
return false;
- /* We disable the handling of pointer types, because it’s currently not
- supported by Graphite with the isl AST generator. SSA_NAME nodes are
- the only nodes, which are disabled in case they are pointers to object
- types, but this can be changed. */
-
- if (POINTER_TYPE_P (TREE_TYPE (scev)) && TREE_CODE (scev) == SSA_NAME)
- return false;
-
switch (TREE_CODE (scev))
{
case NEGATE_EXPR:
case BIT_NOT_EXPR:
CASE_CONVERT:
case NON_LVALUE_EXPR:
- return graphite_can_represent_scev (TREE_OPERAND (scev, 0));
+ return graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0));
case PLUS_EXPR:
case POINTER_PLUS_EXPR:
case MINUS_EXPR:
- return graphite_can_represent_scev (TREE_OPERAND (scev, 0))
- && graphite_can_represent_scev (TREE_OPERAND (scev, 1));
+ return graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0))
+ && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 1));
case MULT_EXPR:
return !CONVERT_EXPR_CODE_P (TREE_CODE (TREE_OPERAND (scev, 0)))
@@ -1290,18 +959,20 @@ scop_detection::graphite_can_represent_scev (tree scev)
&& !(chrec_contains_symbols (TREE_OPERAND (scev, 0))
&& chrec_contains_symbols (TREE_OPERAND (scev, 1)))
&& graphite_can_represent_init (scev)
- && graphite_can_represent_scev (TREE_OPERAND (scev, 0))
- && graphite_can_represent_scev (TREE_OPERAND (scev, 1));
+ && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 0))
+ && graphite_can_represent_scev (scop, TREE_OPERAND (scev, 1));
case POLYNOMIAL_CHREC:
/* Check for constant strides. With a non constant stride of
'n' we would have a value of 'iv * n'. Also check that the
initial value can represented: for example 'n * m' cannot be
represented. */
+ gcc_assert (loop_in_sese_p (get_loop (cfun,
+ CHREC_VARIABLE (scev)), scop));
if (!evolution_function_right_is_integer_cst (scev)
|| !graphite_can_represent_init (scev))
return false;
- return graphite_can_represent_scev (CHREC_LEFT (scev));
+ return graphite_can_represent_scev (scop, CHREC_LEFT (scev));
default:
break;
@@ -1325,7 +996,7 @@ scop_detection::graphite_can_represent_expr (sese_l scop, loop_p loop,
tree expr)
{
tree scev = scalar_evolution_in_region (scop, loop, expr);
- return graphite_can_represent_scev (scev);
+ return graphite_can_represent_scev (scop, scev);
}
/* Return true if the data references of STMT can be represented by Graphite.
@@ -1334,10 +1005,10 @@ scop_detection::graphite_can_represent_expr (sese_l scop, loop_p loop,
bool
scop_detection::stmt_has_simple_data_refs_p (sese_l scop, gimple *stmt)
{
- loop_p nest = outermost_loop_in_sese (scop, gimple_bb (stmt));
+ edge nest = scop.entry;;
loop_p loop = loop_containing_stmt (stmt);
if (!loop_in_sese_p (loop, scop))
- loop = nest;
+ loop = NULL;
auto_vec<data_reference_p> drs;
if (! graphite_find_data_references_in_stmt (nest, loop, stmt, &drs))
@@ -1348,7 +1019,7 @@ scop_detection::stmt_has_simple_data_refs_p (sese_l scop, gimple *stmt)
FOR_EACH_VEC_ELT (drs, j, dr)
{
for (unsigned i = 0; i < DR_NUM_DIMENSIONS (dr); ++i)
- if (! graphite_can_represent_scev (DR_ACCESS_FN (dr, i)))
+ if (! graphite_can_represent_scev (scop, DR_ACCESS_FN (dr, i)))
return false;
}
@@ -1375,14 +1046,32 @@ stmt_has_side_effects (gimple *stmt)
return false;
}
-/* Returns true if STMT can be represented in polyhedral model. LABEL,
- simple COND stmts, pure calls, and assignments can be repesented. */
+/* Return true only when STMT is simple enough for being handled by Graphite.
+ This depends on SCOP, as the parameters are initialized relatively to
+ this basic block, the linear functions are initialized based on the outermost
+ loop containing STMT inside the SCOP. BB is the place where we try to
+ evaluate the STMT. */
bool
-scop_detection::graphite_can_represent_stmt (sese_l scop, gimple *stmt,
- basic_block bb)
+scop_detection::stmt_simple_for_scop_p (sese_l scop, gimple *stmt,
+ basic_block bb) const
{
- loop_p loop = bb->loop_father;
+ gcc_assert (scop);
+
+ if (is_gimple_debug (stmt))
+ return true;
+
+ if (stmt_has_side_effects (stmt))
+ return false;
+
+ if (!stmt_has_simple_data_refs_p (scop, stmt))
+ {
+ DEBUG_PRINT (dp << "[scop-detection-fail] "
+ << "Graphite cannot handle data-refs in stmt:\n";
+ print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS|TDF_MEMSYMS););
+ return false;
+ }
+
switch (gimple_code (stmt))
{
case GIMPLE_LABEL:
@@ -1408,12 +1097,13 @@ scop_detection::graphite_can_represent_stmt (sese_l scop, gimple *stmt,
return false;
}
+ loop_p loop = bb->loop_father;
for (unsigned i = 0; i < 2; ++i)
{
tree op = gimple_op (stmt, i);
if (!graphite_can_represent_expr (scop, loop, op)
/* We can only constrain on integer type. */
- || (TREE_CODE (TREE_TYPE (op)) != INTEGER_TYPE))
+ || ! INTEGRAL_TYPE_P (TREE_TYPE (op)))
{
DEBUG_PRINT (dp << "[scop-detection-fail] "
<< "Graphite cannot represent stmt:\n";
@@ -1440,99 +1130,6 @@ scop_detection::graphite_can_represent_stmt (sese_l scop, gimple *stmt,
}
}
-/* Return true only when STMT is simple enough for being handled by Graphite.
- This depends on SCOP, as the parameters are initialized relatively to
- this basic block, the linear functions are initialized based on the outermost
- loop containing STMT inside the SCOP. BB is the place where we try to
- evaluate the STMT. */
-
-bool
-scop_detection::stmt_simple_for_scop_p (sese_l scop, gimple *stmt,
- basic_block bb) const
-{
- gcc_assert (scop);
-
- if (is_gimple_debug (stmt))
- return true;
-
- if (stmt_has_side_effects (stmt))
- return false;
-
- if (!stmt_has_simple_data_refs_p (scop, stmt))
- {
- DEBUG_PRINT (dp << "[scop-detection-fail] "
- << "Graphite cannot handle data-refs in stmt:\n";
- print_gimple_stmt (dump_file, stmt, 0, TDF_VOPS|TDF_MEMSYMS););
- return false;
- }
-
- return graphite_can_represent_stmt (scop, stmt, bb);
-}
-
-/* Return true when BB contains a harmful operation for a scop: that
- can be a function call with side effects, the induction variables
- are not linear with respect to SCOP, etc. The current open
- scop should end before this statement. */
-
-bool
-scop_detection::harmful_stmt_in_bb (sese_l scop, basic_block bb) const
-{
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- if (!stmt_simple_for_scop_p (scop, gsi_stmt (gsi), bb))
- return true;
-
- return false;
-}
-
-/* Return true when the body of LOOP has statements that can be represented as a
- valid scop. */
-
-bool
-scop_detection::loop_body_is_valid_scop (loop_p loop, sese_l scop) const
-{
- if (!loop_ivs_can_be_represented (loop))
- {
- DEBUG_PRINT (dp << "[scop-detection-fail] loop_" << loop->num
- << "IV cannot be represented.\n");
- return false;
- }
-
- if (!loop_nest_has_data_refs (loop))
- {
- DEBUG_PRINT (dp << "[scop-detection-fail] loop_" << loop->num
- << "does not have any data reference.\n");
- return false;
- }
-
- basic_block *bbs = get_loop_body (loop);
- for (unsigned i = 0; i < loop->num_nodes; i++)
- {
- basic_block bb = bbs[i];
-
- if (harmful_stmt_in_bb (scop, bb))
- {
- free (bbs);
- return false;
- }
- }
- free (bbs);
-
- if (loop->inner)
- {
- loop = loop->inner;
- while (loop)
- {
- if (!loop_body_is_valid_scop (loop, scop))
- return false;
- loop = loop->next;
- }
- }
-
- return true;
-}
-
/* Returns the number of pbbs that are in loops contained in SCOP. */
int
@@ -1549,49 +1146,23 @@ scop_detection::nb_pbbs_in_loops (scop_p scop)
return res;
}
-/* When parameter NAME is in REGION, returns its index in SESE_PARAMS.
- Otherwise returns -1. */
+/* Assigns the parameter NAME an index in REGION. */
-static inline int
-parameter_index_in_region_1 (tree name, sese_info_p region)
+static void
+assign_parameter_index_in_region (tree name, sese_info_p region)
{
+ gcc_assert (TREE_CODE (name) == SSA_NAME
+ && INTEGRAL_TYPE_P (TREE_TYPE (name))
+ && ! defined_in_sese_p (name, region->region));
+
int i;
tree p;
-
- gcc_assert (TREE_CODE (name) == SSA_NAME);
-
FOR_EACH_VEC_ELT (region->params, i, p)
if (p == name)
- return i;
-
- return -1;
-}
-
-/* When the parameter NAME is in REGION, returns its index in
- SESE_PARAMS. Otherwise this function inserts NAME in SESE_PARAMS
- and returns the index of NAME. */
-
-static int
-parameter_index_in_region (tree name, sese_info_p region)
-{
- int i;
-
- gcc_assert (TREE_CODE (name) == SSA_NAME);
-
- /* Cannot constrain on anything else than INTEGER_TYPE parameters. */
- if (TREE_CODE (TREE_TYPE (name)) != INTEGER_TYPE)
- return -1;
-
- if (!invariant_in_sese_p_rec (name, region->region, NULL))
- return -1;
-
- i = parameter_index_in_region_1 (name, region);
- if (i != -1)
- return i;
+ return;
i = region->params.length ();
region->params.safe_push (name);
- return i;
}
/* In the context of sese S, scan the expression E and translate it to
@@ -1633,7 +1204,7 @@ scan_tree_for_params (sese_info_p s, tree e)
break;
case SSA_NAME:
- parameter_index_in_region (e, s);
+ assign_parameter_index_in_region (e, s);
break;
case INTEGER_CST:
@@ -1677,7 +1248,7 @@ find_params_in_bb (sese_info_p region, gimple_poly_bb_p gbb)
}
}
-/* Record the parameters used in the SCOP. A variable is a parameter
+/* Record the parameters used in the SCOP BBs. A variable is a parameter
in a scop if it does not vary during the execution of that scop. */
static void
@@ -1685,19 +1256,8 @@ find_scop_parameters (scop_p scop)
{
unsigned i;
sese_info_p region = scop->scop_info;
- struct loop *loop;
-
- /* Find the parameters used in the loop bounds. */
- FOR_EACH_VEC_ELT (region->loop_nest, i, loop)
- {
- tree nb_iters = number_of_latch_executions (loop);
-
- if (!chrec_contains_symbols (nb_iters))
- continue;
- nb_iters = scalar_evolution_in_region (region->region, loop, nb_iters);
- scan_tree_for_params (region, nb_iters);
- }
+ /* Parameters used in loop bounds are processed during gather_bbs. */
/* Find the parameters used in data accesses. */
poly_bb_p pbb;
@@ -1708,33 +1268,51 @@ find_scop_parameters (scop_p scop)
scop_set_nb_params (scop, nbp);
}
+static void
+add_write (vec<tree> *writes, tree def)
+{
+ writes->safe_push (def);
+ DEBUG_PRINT (dp << "Adding scalar write: ";
+ print_generic_expr (dump_file, def);
+ dp << "\nFrom stmt: ";
+ print_gimple_stmt (dump_file,
+ SSA_NAME_DEF_STMT (def), 0));
+}
+
+static void
+add_read (vec<scalar_use> *reads, tree use, gimple *use_stmt)
+{
+ DEBUG_PRINT (dp << "Adding scalar read: ";
+ print_generic_expr (dump_file, use);
+ dp << "\nFrom stmt: ";
+ print_gimple_stmt (dump_file, use_stmt, 0));
+ reads->safe_push (std::make_pair (use_stmt, use));
+}
+
+
/* Record DEF if it is used in other bbs different than DEF_BB in the SCOP. */
static void
build_cross_bb_scalars_def (scop_p scop, tree def, basic_block def_bb,
vec<tree> *writes)
{
- if (!def || !is_gimple_reg (def))
+ if (!is_gimple_reg (def))
return;
- /* Do not gather scalar variables that can be analyzed by SCEV as they can be
- generated out of the induction variables. */
- if (scev_analyzable_p (def, scop->scop_info->region))
- return;
+ bool scev_analyzable = scev_analyzable_p (def, scop->scop_info->region);
gimple *use_stmt;
imm_use_iterator imm_iter;
FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, def)
- if ((def_bb != gimple_bb (use_stmt) && !is_gimple_debug (use_stmt))
- /* PHIs have their effect at "BBs" on the edges. See PR79622. */
- || gimple_code (SSA_NAME_DEF_STMT (def)) == GIMPLE_PHI)
+ /* Do not gather scalar variables that can be analyzed by SCEV as they can
+ be generated out of the induction variables. */
+ if ((! scev_analyzable
+ /* But gather SESE liveouts as we otherwise fail to rewrite their
+ exit PHIs. */
+ || ! bb_in_sese_p (gimple_bb (use_stmt), scop->scop_info->region))
+ && (def_bb != gimple_bb (use_stmt) && !is_gimple_debug (use_stmt)))
{
- writes->safe_push (def);
- DEBUG_PRINT (dp << "Adding scalar write: ";
- print_generic_expr (dump_file, def);
- dp << "\nFrom stmt: ";
- print_gimple_stmt (dump_file,
- SSA_NAME_DEF_STMT (def), 0));
+ add_write (writes, def);
/* This is required by the FOR_EACH_IMM_USE_STMT when we want to break
before all the uses have been visited. */
BREAK_FROM_IMM_USE_STMT (imm_iter);
@@ -1748,7 +1326,6 @@ static void
build_cross_bb_scalars_use (scop_p scop, tree use, gimple *use_stmt,
vec<scalar_use> *reads)
{
- gcc_assert (use);
if (!is_gimple_reg (use))
return;
@@ -1758,46 +1335,8 @@ build_cross_bb_scalars_use (scop_p scop, tree use, gimple *use_stmt,
return;
gimple *def_stmt = SSA_NAME_DEF_STMT (use);
- if (gimple_bb (def_stmt) != gimple_bb (use_stmt)
- /* PHIs have their effect at "BBs" on the edges. See PR79622. */
- || gimple_code (def_stmt) == GIMPLE_PHI)
- {
- DEBUG_PRINT (dp << "Adding scalar read: ";
- print_generic_expr (dump_file, use);
- dp << "\nFrom stmt: ";
- print_gimple_stmt (dump_file, use_stmt, 0));
- reads->safe_push (std::make_pair (use_stmt, use));
- }
-}
-
-/* Record all scalar variables that are defined and used in different BBs of the
- SCOP. */
-
-static void
-graphite_find_cross_bb_scalar_vars (scop_p scop, gimple *stmt,
- vec<scalar_use> *reads, vec<tree> *writes)
-{
- tree def;
-
- if (gimple_code (stmt) == GIMPLE_ASSIGN)
- def = gimple_assign_lhs (stmt);
- else if (gimple_code (stmt) == GIMPLE_CALL)
- def = gimple_call_lhs (stmt);
- else if (gimple_code (stmt) == GIMPLE_PHI)
- def = gimple_phi_result (stmt);
- else
- return;
-
-
- build_cross_bb_scalars_def (scop, def, gimple_bb (stmt), writes);
-
- ssa_op_iter iter;
- use_operand_p use_p;
- FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
- {
- tree use = USE_FROM_PTR (use_p);
- build_cross_bb_scalars_use (scop, use, stmt, reads);
- }
+ if (gimple_bb (def_stmt) != gimple_bb (use_stmt))
+ add_read (reads, use, use_stmt);
}
/* Generates a polyhedral black box only if the bb contains interesting
@@ -1811,11 +1350,10 @@ try_generate_gimple_bb (scop_p scop, basic_block bb)
vec<scalar_use> reads = vNULL;
sese_l region = scop->scop_info->region;
- loop_p nest = outermost_loop_in_sese (region, bb);
-
+ edge nest = region.entry;
loop_p loop = bb->loop_father;
if (!loop_in_sese_p (loop, region))
- loop = nest;
+ loop = NULL;
for (gimple_stmt_iterator gsi = gsi_start_bb (bb); !gsi_end_p (gsi);
gsi_next (&gsi))
@@ -1825,13 +1363,89 @@ try_generate_gimple_bb (scop_p scop, basic_block bb)
continue;
graphite_find_data_references_in_stmt (nest, loop, stmt, &drs);
- graphite_find_cross_bb_scalar_vars (scop, stmt, &reads, &writes);
+
+ tree def = gimple_get_lhs (stmt);
+ if (def)
+ build_cross_bb_scalars_def (scop, def, gimple_bb (stmt), &writes);
+
+ ssa_op_iter iter;
+ tree use;
+ FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
+ build_cross_bb_scalars_use (scop, use, stmt, &reads);
}
+ /* Handle defs and uses in PHIs. Those need special treatment given
+ that we have to present ISL with sth that looks like we've rewritten
+ the IL out-of-SSA. */
for (gphi_iterator psi = gsi_start_phis (bb); !gsi_end_p (psi);
gsi_next (&psi))
- if (!virtual_operand_p (gimple_phi_result (psi.phi ())))
- graphite_find_cross_bb_scalar_vars (scop, psi.phi (), &reads, &writes);
+ {
+ gphi *phi = psi.phi ();
+ tree res = gimple_phi_result (phi);
+ if (virtual_operand_p (res)
+ || scev_analyzable_p (res, scop->scop_info->region))
+ continue;
+ /* To simulate out-of-SSA the block containing the PHI node has
+ reads of the PHI destination. And to preserve SSA dependences
+ we also write to it (the out-of-SSA decl and the SSA result
+ are coalesced for dependence purposes which is good enough). */
+ add_read (&reads, res, phi);
+ add_write (&writes, res);
+ }
+ basic_block bb_for_succs = bb;
+ if (bb_for_succs == bb_for_succs->loop_father->latch
+ && bb_in_sese_p (bb_for_succs, scop->scop_info->region)
+ && sese_trivially_empty_bb_p (bb_for_succs))
+ bb_for_succs = NULL;
+ while (bb_for_succs)
+ {
+ basic_block latch = NULL;
+ edge_iterator ei;
+ edge e;
+ FOR_EACH_EDGE (e, ei, bb_for_succs->succs)
+ {
+ for (gphi_iterator psi = gsi_start_phis (e->dest); !gsi_end_p (psi);
+ gsi_next (&psi))
+ {
+ gphi *phi = psi.phi ();
+ tree res = gimple_phi_result (phi);
+ if (virtual_operand_p (res))
+ continue;
+ /* To simulate out-of-SSA the predecessor of edges into PHI nodes
+ has a copy from the PHI argument to the PHI destination. */
+ if (! scev_analyzable_p (res, scop->scop_info->region))
+ add_write (&writes, res);
+ tree use = PHI_ARG_DEF_FROM_EDGE (phi, e);
+ if (TREE_CODE (use) == SSA_NAME
+ && ! SSA_NAME_IS_DEFAULT_DEF (use)
+ && gimple_bb (SSA_NAME_DEF_STMT (use)) != bb_for_succs
+ && ! scev_analyzable_p (use, scop->scop_info->region))
+ add_read (&reads, use, phi);
+ }
+ if (e->dest == bb_for_succs->loop_father->latch
+ && bb_in_sese_p (e->dest, scop->scop_info->region)
+ && sese_trivially_empty_bb_p (e->dest))
+ latch = e->dest;
+ }
+ /* Handle empty latch block PHIs here, otherwise we confuse ISL
+ with extra conditional code where it then peels off the last
+ iteration just because of that. It would be simplest if we
+ just didn't force simple latches (thus remove the forwarder). */
+ bb_for_succs = latch;
+ }
+
+ /* For the region exit block add reads for all live-out vars. */
+ if (bb == scop->scop_info->region.exit->src)
+ {
+ sese_build_liveouts (scop->scop_info);
+ unsigned i;
+ bitmap_iterator bi;
+ EXECUTE_IF_SET_IN_BITMAP (scop->scop_info->liveout, 0, i, bi)
+ {
+ tree use = ssa_name (i);
+ add_read (&reads, use, NULL);
+ }
+ }
if (drs.is_empty () && writes.is_empty () && reads.is_empty ())
return NULL;
@@ -1875,7 +1489,8 @@ build_alias_set (scop_p scop)
for (i = 0; i < num_vertices; i++)
all_vertices[i] = i;
- graphds_dfs (g, all_vertices, num_vertices, NULL, true, NULL);
+ scop->max_alias_set
+ = graphds_dfs (g, all_vertices, num_vertices, NULL, true, NULL) + 1;
free (all_vertices);
for (i = 0; i < g->n_vertices; i++)
@@ -1889,7 +1504,7 @@ build_alias_set (scop_p scop)
class gather_bbs : public dom_walker
{
public:
- gather_bbs (cdi_direction, scop_p);
+ gather_bbs (cdi_direction, scop_p, int *);
virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block);
@@ -1899,31 +1514,9 @@ private:
scop_p scop;
};
}
-gather_bbs::gather_bbs (cdi_direction direction, scop_p scop)
- : dom_walker (direction), scop (scop)
-{
-}
-
-/* Record in execution order the loops fully contained in the region. */
-
-static void
-record_loop_in_sese (basic_block bb, sese_info_p region)
+gather_bbs::gather_bbs (cdi_direction direction, scop_p scop, int *bb_to_rpo)
+ : dom_walker (direction, false, bb_to_rpo), scop (scop)
{
- loop_p father = bb->loop_father;
- if (loop_in_sese_p (father, region->region))
- {
- bool found = false;
- loop_p loop0;
- int j;
- FOR_EACH_VEC_ELT (region->loop_nest, j, loop0)
- if (father == loop0)
- {
- found = true;
- break;
- }
- if (!found)
- region->loop_nest.safe_push (father);
- }
}
/* Call-back for dom_walk executed before visiting the dominated
@@ -1934,9 +1527,22 @@ gather_bbs::before_dom_children (basic_block bb)
{
sese_info_p region = scop->scop_info;
if (!bb_in_sese_p (bb, region->region))
- return NULL;
+ return dom_walker::STOP;
- record_loop_in_sese (bb, region);
+ /* For loops fully contained in the region record parameters in the
+ loop bounds. */
+ loop_p loop = bb->loop_father;
+ if (loop->header == bb
+ && loop_in_sese_p (loop, region->region))
+ {
+ tree nb_iters = number_of_latch_executions (loop);
+ if (chrec_contains_symbols (nb_iters))
+ {
+ nb_iters = scalar_evolution_in_region (region->region,
+ loop, nb_iters);
+ scan_tree_for_params (region, nb_iters);
+ }
+ }
gcond *stmt = single_pred_cond_non_loop_exit (bb);
@@ -2048,13 +1654,20 @@ build_scops (vec<scop_p> *scops)
if (dump_file)
dp.set_dump_file (dump_file);
- canonicalize_loop_closed_ssa_form ();
-
scop_detection sb;
- sb.build_scop_depth (scop_detection::invalid_sese, current_loops->tree_root);
+ sb.build_scop_depth (current_loops->tree_root);
/* Now create scops from the lightweight SESEs. */
vec<sese_l> scops_l = sb.get_scops ();
+
+ /* Domwalk needs a bb to RPO mapping. Compute it once here. */
+ int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (cfun));
+ int postorder_num = pre_and_rev_post_order_compute (NULL, postorder, true);
+ int *bb_to_rpo = XNEWVEC (int, last_basic_block_for_fn (cfun));
+ for (int i = 0; i < postorder_num; ++i)
+ bb_to_rpo[postorder[i]] = i;
+ free (postorder);
+
int i;
sese_l *s;
FOR_EACH_VEC_ELT (scops_l, i, s)
@@ -2062,7 +1675,7 @@ build_scops (vec<scop_p> *scops)
scop_p scop = new_scop (s->entry, s->exit);
/* Record all basic blocks and their conditions in REGION. */
- gather_bbs (CDI_DOMINATORS, scop).walk (s->entry->dest);
+ gather_bbs (CDI_DOMINATORS, scop, bb_to_rpo).walk (s->entry->dest);
/* domwalk does not fulfil our code-generations constraints on the
order of pbb which is to produce sth like execution order, delaying
@@ -2092,7 +1705,8 @@ build_scops (vec<scop_p> *scops)
}
unsigned max_arrays = PARAM_VALUE (PARAM_GRAPHITE_MAX_ARRAYS_PER_SCOP);
- if (scop->drs.length () >= max_arrays)
+ if (max_arrays > 0
+ && scop->drs.length () >= max_arrays)
{
DEBUG_PRINT (dp << "[scop-detection-fail] too many data references: "
<< scop->drs.length ()
@@ -2104,8 +1718,8 @@ build_scops (vec<scop_p> *scops)
find_scop_parameters (scop);
graphite_dim_t max_dim = PARAM_VALUE (PARAM_GRAPHITE_MAX_NB_SCOP_PARAMS);
-
- if (scop_nb_params (scop) > max_dim)
+ if (max_dim > 0
+ && scop_nb_params (scop) > max_dim)
{
DEBUG_PRINT (dp << "[scop-detection-fail] too many parameters: "
<< scop_nb_params (scop)
@@ -2118,6 +1732,7 @@ build_scops (vec<scop_p> *scops)
scops->safe_push (scop);
}
+ free (bb_to_rpo);
DEBUG_PRINT (dp << "number of SCoPs: " << (scops ? scops->length () : 0););
}
diff --git a/gcc/graphite-sese-to-poly.c b/gcc/graphite-sese-to-poly.c
index 6e64f13..248c34a 100644
--- a/gcc/graphite-sese-to-poly.c
+++ b/gcc/graphite-sese-to-poly.c
@@ -63,7 +63,7 @@ along with GCC; see the file COPYING3. If not see
static inline void
tree_int_to_gmp (tree t, mpz_t res)
{
- wi::to_mpz (t, res, TYPE_SIGN (TREE_TYPE (t)));
+ wi::to_mpz (wi::to_wide (t), res, TYPE_SIGN (TREE_TYPE (t)));
}
/* Return an isl identifier for the polyhedral basic block PBB. */
@@ -142,11 +142,8 @@ isl_id_for_dr (scop_p s)
/* Extract an affine expression from the ssa_name E. */
static isl_pw_aff *
-extract_affine_name (scop_p s, tree e, __isl_take isl_space *space)
+extract_affine_name (int dimension, __isl_take isl_space *space)
{
- isl_id *id = isl_id_for_ssa_name (s, e);
- int dimension = isl_space_find_dim_by_id (space, isl_dim_param, id);
- isl_id_free (id);
isl_set *dom = isl_set_universe (isl_space_copy (space));
isl_aff *aff = isl_aff_zero_on_domain (isl_local_space_from_space (space));
aff = isl_aff_add_coefficient_si (aff, isl_dim_param, dimension, 1);
@@ -211,17 +208,13 @@ wrap (isl_pw_aff *pwaff, unsigned width)
Otherwise returns -1. */
static inline int
-parameter_index_in_region_1 (tree name, sese_info_p region)
+parameter_index_in_region (tree name, sese_info_p region)
{
int i;
tree p;
-
- gcc_assert (TREE_CODE (name) == SSA_NAME);
-
FOR_EACH_VEC_ELT (region->params, i, p)
if (p == name)
return i;
-
return -1;
}
@@ -237,6 +230,7 @@ extract_affine (scop_p s, tree e, __isl_take isl_space *space)
return NULL;
}
+ tree type = TREE_TYPE (e);
switch (TREE_CODE (e))
{
case POLYNOMIAL_CHREC:
@@ -247,8 +241,22 @@ extract_affine (scop_p s, tree e, __isl_take isl_space *space)
res = extract_affine_mul (s, e, space);
break;
- case PLUS_EXPR:
case POINTER_PLUS_EXPR:
+ {
+ lhs = extract_affine (s, TREE_OPERAND (e, 0), isl_space_copy (space));
+ /* The RHS of a pointer-plus expression is to be interpreted
+ as signed value. Try to look through a sign-changing conversion
+ first. */
+ tree tem = TREE_OPERAND (e, 1);
+ STRIP_NOPS (tem);
+ rhs = extract_affine (s, tem, space);
+ if (TYPE_UNSIGNED (TREE_TYPE (tem)))
+ rhs = wrap (rhs, TYPE_PRECISION (type) - 1);
+ res = isl_pw_aff_add (lhs, rhs);
+ break;
+ }
+
+ case PLUS_EXPR:
lhs = extract_affine (s, TREE_OPERAND (e, 0), isl_space_copy (space));
rhs = extract_affine (s, TREE_OPERAND (e, 1), space);
res = isl_pw_aff_add (lhs, rhs);
@@ -260,18 +268,26 @@ extract_affine (scop_p s, tree e, __isl_take isl_space *space)
res = isl_pw_aff_sub (lhs, rhs);
break;
- case NEGATE_EXPR:
case BIT_NOT_EXPR:
+ lhs = extract_affine (s, integer_minus_one_node, isl_space_copy (space));
+ rhs = extract_affine (s, TREE_OPERAND (e, 0), space);
+ res = isl_pw_aff_sub (lhs, rhs);
+ break;
+
+ case NEGATE_EXPR:
lhs = extract_affine (s, TREE_OPERAND (e, 0), isl_space_copy (space));
rhs = extract_affine (s, integer_minus_one_node, space);
res = isl_pw_aff_mul (lhs, rhs);
break;
case SSA_NAME:
- gcc_assert (-1 != parameter_index_in_region_1 (e, s->scop_info)
- || defined_in_sese_p (e, s->scop_info->region));
- res = extract_affine_name (s, e, space);
- break;
+ {
+ gcc_assert (! defined_in_sese_p (e, s->scop_info->region));
+ int dim = parameter_index_in_region (e, s->scop_info);
+ gcc_assert (dim != -1);
+ res = extract_affine_name (dim, space);
+ break;
+ }
case INTEGER_CST:
res = extract_affine_int (e, space);
@@ -279,6 +295,19 @@ extract_affine (scop_p s, tree e, __isl_take isl_space *space)
return res;
CASE_CONVERT:
+ {
+ tree itype = TREE_TYPE (TREE_OPERAND (e, 0));
+ res = extract_affine (s, TREE_OPERAND (e, 0), space);
+ /* Signed values, even if overflow is undefined, get modulo-reduced.
+ But only if not all values of the old type fit in the new. */
+ if (! TYPE_UNSIGNED (type)
+ && ((TYPE_UNSIGNED (TREE_TYPE (TREE_OPERAND (e, 0)))
+ && TYPE_PRECISION (type) <= TYPE_PRECISION (itype))
+ || TYPE_PRECISION (type) < TYPE_PRECISION (itype)))
+ res = wrap (res, TYPE_PRECISION (type) - 1);
+ break;
+ }
+
case NON_LVALUE_EXPR:
res = extract_affine (s, TREE_OPERAND (e, 0), space);
break;
@@ -288,7 +317,6 @@ extract_affine (scop_p s, tree e, __isl_take isl_space *space)
break;
}
- tree type = TREE_TYPE (e);
if (TYPE_UNSIGNED (type))
res = wrap (res, TYPE_PRECISION (type));
@@ -399,54 +427,40 @@ add_conditions_to_domain (poly_bb_p pbb)
of P. */
static void
-add_param_constraints (scop_p scop, graphite_dim_t p)
+add_param_constraints (scop_p scop, graphite_dim_t p, tree parameter)
{
- tree parameter = scop->scop_info->params[p];
tree type = TREE_TYPE (parameter);
- tree lb = NULL_TREE;
- tree ub = NULL_TREE;
+ wide_int min, max;
- if (POINTER_TYPE_P (type) || !TYPE_MIN_VALUE (type))
- lb = lower_bound_in_type (type, type);
- else
- lb = TYPE_MIN_VALUE (type);
+ gcc_assert (INTEGRAL_TYPE_P (type) || POINTER_TYPE_P (type));
- if (POINTER_TYPE_P (type) || !TYPE_MAX_VALUE (type))
- ub = upper_bound_in_type (type, type);
+ if (INTEGRAL_TYPE_P (type)
+ && get_range_info (parameter, &min, &max) == VR_RANGE)
+ ;
else
- ub = TYPE_MAX_VALUE (type);
-
- if (lb)
{
- isl_space *space = isl_set_get_space (scop->param_context);
- isl_constraint *c;
- isl_val *v;
-
- c = isl_inequality_alloc (isl_local_space_from_space (space));
- v = isl_val_int_from_wi (scop->isl_context, wi::to_widest (lb));
- v = isl_val_neg (v);
- c = isl_constraint_set_constant_val (c, v);
- c = isl_constraint_set_coefficient_si (c, isl_dim_param, p, 1);
-
- scop->param_context = isl_set_coalesce
- (isl_set_add_constraint (scop->param_context, c));
+ min = wi::min_value (TYPE_PRECISION (type), TYPE_SIGN (type));
+ max = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
}
- if (ub)
- {
- isl_space *space = isl_set_get_space (scop->param_context);
- isl_constraint *c;
- isl_val *v;
-
- c = isl_inequality_alloc (isl_local_space_from_space (space));
-
- v = isl_val_int_from_wi (scop->isl_context, wi::to_widest (ub));
- c = isl_constraint_set_constant_val (c, v);
- c = isl_constraint_set_coefficient_si (c, isl_dim_param, p, -1);
-
- scop->param_context = isl_set_coalesce
- (isl_set_add_constraint (scop->param_context, c));
- }
+ isl_space *space = isl_set_get_space (scop->param_context);
+ isl_constraint *c = isl_inequality_alloc (isl_local_space_from_space (space));
+ isl_val *v = isl_val_int_from_wi (scop->isl_context,
+ widest_int::from (min, TYPE_SIGN (type)));
+ v = isl_val_neg (v);
+ c = isl_constraint_set_constant_val (c, v);
+ c = isl_constraint_set_coefficient_si (c, isl_dim_param, p, 1);
+ scop->param_context = isl_set_coalesce
+ (isl_set_add_constraint (scop->param_context, c));
+
+ space = isl_set_get_space (scop->param_context);
+ c = isl_inequality_alloc (isl_local_space_from_space (space));
+ v = isl_val_int_from_wi (scop->isl_context,
+ widest_int::from (max, TYPE_SIGN (type)));
+ c = isl_constraint_set_constant_val (c, v);
+ c = isl_constraint_set_coefficient_si (c, isl_dim_param, p, -1);
+ scop->param_context = isl_set_coalesce
+ (isl_set_add_constraint (scop->param_context, c));
}
/* Add a constrain to the ACCESSES polyhedron for the alias set of
@@ -466,25 +480,6 @@ pdr_add_alias_set (isl_map *acc, dr_info &dri)
return isl_map_add_constraint (acc, c);
}
-/* Add a constrain to the ACCESSES polyhedron for the alias set of
- data reference DR. ACCESSP_NB_DIMS is the dimension of the
- ACCESSES polyhedron, DOM_NB_DIMS is the dimension of the iteration
- domain. */
-
-static isl_map *
-add_scalar_version_numbers (isl_map *acc, tree var)
-{
- isl_constraint *c = isl_equality_alloc
- (isl_local_space_from_space (isl_map_get_space (acc)));
- int max_arrays = PARAM_VALUE (PARAM_GRAPHITE_MAX_ARRAYS_PER_SCOP);
- /* Each scalar variables has a unique alias set number starting from
- max_arrays. */
- c = isl_constraint_set_constant_si (c, -max_arrays - SSA_NAME_VERSION (var));
- c = isl_constraint_set_coefficient_si (c, isl_dim_out, 0, 1);
-
- return isl_map_add_constraint (acc, c);
-}
-
/* Assign the affine expression INDEX to the output dimension POS of
MAP and return the result. */
@@ -659,13 +654,21 @@ static void
build_poly_sr_1 (poly_bb_p pbb, gimple *stmt, tree var, enum poly_dr_type kind,
isl_map *acc, isl_set *subscript_sizes)
{
- int max_arrays = PARAM_VALUE (PARAM_GRAPHITE_MAX_ARRAYS_PER_SCOP);
+ scop_p scop = PBB_SCOP (pbb);
/* Each scalar variables has a unique alias set number starting from
- max_arrays. */
+ the maximum alias set assigned to a dr. */
+ int alias_set = scop->max_alias_set + SSA_NAME_VERSION (var);
subscript_sizes = isl_set_fix_si (subscript_sizes, isl_dim_set, 0,
- max_arrays + SSA_NAME_VERSION (var));
+ alias_set);
+
+ /* Add a constrain to the ACCESSES polyhedron for the alias set of
+ data reference DR. */
+ isl_constraint *c
+ = isl_equality_alloc (isl_local_space_from_space (isl_map_get_space (acc)));
+ c = isl_constraint_set_constant_si (c, -alias_set);
+ c = isl_constraint_set_coefficient_si (c, isl_dim_out, 0, 1);
- new_poly_dr (pbb, stmt, kind, add_scalar_version_numbers (acc, var),
+ new_poly_dr (pbb, stmt, kind, isl_map_add_constraint (acc, c),
subscript_sizes);
}
@@ -909,9 +912,8 @@ build_scop_context (scop_p scop)
scop->param_context = isl_set_universe (space);
- graphite_dim_t p;
- for (p = 0; p < nbp; p++)
- add_param_constraints (scop, p);
+ FOR_EACH_VEC_ELT (region->params, i, e)
+ add_param_constraints (scop, i, e);
}
/* Return true when loop A is nested in loop B. */
@@ -1030,8 +1032,6 @@ outer_projection_mupa (__isl_take isl_union_set *set, int n)
return isl_multi_union_pw_aff_from_union_pw_multi_aff (data.res);
}
-static bool schedule_error;
-
/* Embed SCHEDULE in the constraints of the LOOP domain. */
static isl_schedule *
@@ -1046,11 +1046,9 @@ add_loop_schedule (__isl_take isl_schedule *schedule, loop_p loop,
return empty < 0 ? isl_schedule_free (schedule) : schedule;
isl_union_set *domain = isl_schedule_get_domain (schedule);
- /* We cannot apply an empty domain to pbbs in this loop so fail.
- ??? Somehow drop pbbs in the loop instead. */
+ /* We cannot apply an empty domain to pbbs in this loop so return early. */
if (isl_union_set_is_empty (domain))
{
- schedule_error = true;
isl_union_set_free (domain);
return schedule;
}
@@ -1177,11 +1175,9 @@ build_schedule_loop_nest (scop_p scop, int *index, loop_p context_loop)
/* Build the schedule of the SCOP. */
-static bool
+static void
build_original_schedule (scop_p scop)
{
- schedule_error = false;
-
int i = 0;
int n = scop->pbbs.length ();
while (i < n)
@@ -1196,22 +1192,11 @@ build_original_schedule (scop_p scop)
scop->original_schedule = add_in_sequence (scop->original_schedule, s);
}
- if (schedule_error)
- {
- if (dump_file)
- fprintf (dump_file, "[sese-to-poly] failed to build "
- "original schedule\n");
- return false;
- }
-
if (dump_file)
{
fprintf (dump_file, "[sese-to-poly] original schedule:\n");
print_isl_schedule (dump_file, scop->original_schedule);
}
- if (!scop->original_schedule)
- return false;
- return true;
}
/* Builds the polyhedral representation for a SESE region. */
@@ -1219,6 +1204,9 @@ build_original_schedule (scop_p scop)
bool
build_poly_scop (scop_p scop)
{
+ int old_err = isl_options_get_on_error (scop->isl_context);
+ isl_options_set_on_error (scop->isl_context, ISL_ON_ERROR_CONTINUE);
+
build_scop_context (scop);
unsigned i = 0;
@@ -1228,6 +1216,14 @@ build_poly_scop (scop_p scop)
build_scop_drs (scop);
build_original_schedule (scop);
- return true;
+
+ enum isl_error err = isl_ctx_last_error (scop->isl_context);
+ isl_ctx_reset_error (scop->isl_context);
+ isl_options_set_on_error (scop->isl_context, old_err);
+ if (err != isl_error_none)
+ dump_printf (MSG_MISSED_OPTIMIZATION,
+ "ISL error while building poly scop\n");
+
+ return err == isl_error_none;
}
#endif /* HAVE_isl */
diff --git a/gcc/graphite.c b/gcc/graphite.c
index af336da..22d8330 100644
--- a/gcc/graphite.c
+++ b/gcc/graphite.c
@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfghooks.h"
#include "tree.h"
#include "gimple.h"
+#include "ssa.h"
#include "fold-const.h"
#include "gimple-iterator.h"
#include "tree-cfg.h"
@@ -53,6 +54,9 @@ along with GCC; see the file COPYING3. If not see
#include "tree-parloops.h"
#include "tree-cfgcleanup.h"
#include "tree-vectorizer.h"
+#include "tree-ssa-loop-manip.h"
+#include "tree-ssa.h"
+#include "tree-into-ssa.h"
#include "graphite.h"
/* Print global statistics to FILE. */
@@ -107,7 +111,7 @@ print_global_statistics (FILE* file)
fprintf (file, "LOOPS:%ld, ", n_loops);
fprintf (file, "CONDITIONS:%ld, ", n_conditions);
fprintf (file, "STMTS:%ld)\n", n_stmts);
- fprintf (file, "\nGlobal profiling statistics (");
+ fprintf (file, "Global profiling statistics (");
fprintf (file, "BBS:");
n_p_bbs.dump (file);
fprintf (file, ", LOOPS:");
@@ -116,7 +120,7 @@ print_global_statistics (FILE* file)
n_p_conditions.dump (file);
fprintf (file, ", STMTS:");
n_p_stmts.dump (file);
- fprintf (file, ")\n");
+ fprintf (file, ")\n\n");
}
/* Print statistics for SCOP to FILE. */
@@ -181,7 +185,7 @@ print_graphite_scop_statistics (FILE* file, scop_p scop)
fprintf (file, "LOOPS:%ld, ", n_loops);
fprintf (file, "CONDITIONS:%ld, ", n_conditions);
fprintf (file, "STMTS:%ld)\n", n_stmts);
- fprintf (file, "\nSCoP profiling statistics (");
+ fprintf (file, "SCoP profiling statistics (");
fprintf (file, "BBS:");
n_p_bbs.dump (file);
fprintf (file, ", LOOPS:");
@@ -190,7 +194,7 @@ print_graphite_scop_statistics (FILE* file, scop_p scop)
n_p_conditions.dump (file);
fprintf (file, ", STMTS:");
n_p_stmts.dump (file);
- fprintf (file, ")\n");
+ fprintf (file, ")\n\n");
}
/* Print statistics for SCOPS to FILE. */
@@ -199,99 +203,126 @@ static void
print_graphite_statistics (FILE* file, vec<scop_p> scops)
{
int i;
-
scop_p scop;
FOR_EACH_VEC_ELT (scops, i, scop)
print_graphite_scop_statistics (file, scop);
-
- /* Print the loop structure. */
- print_loops (file, 2);
- print_loops (file, 3);
}
-/* Initialize graphite: when there are no loops returns false. */
+/* Deletes all scops in SCOPS. */
-static bool
-graphite_initialize (isl_ctx *ctx)
+static void
+free_scops (vec<scop_p> scops)
{
- int min_loops = PARAM_VALUE (PARAM_GRAPHITE_MIN_LOOPS_PER_FUNCTION);
- int max_bbs = PARAM_VALUE (PARAM_GRAPHITE_MAX_BBS_PER_FUNCTION);
- int nbbs = n_basic_blocks_for_fn (cfun);
- int nloops = number_of_loops (cfun);
-
- if (nloops <= min_loops
- /* FIXME: This limit on the number of basic blocks of a function
- should be removed when the SCOP detection is faster. */
- || (nbbs > max_bbs))
- {
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- if (nloops <= min_loops)
- fprintf (dump_file, "\nFunction does not have enough loops: "
- "PARAM_GRAPHITE_MIN_LOOPS_PER_FUNCTION = %d.\n",
- min_loops);
+ int i;
+ scop_p scop;
- else if (nbbs > max_bbs)
- fprintf (dump_file, "\nFunction has too many basic blocks: "
- "PARAM_GRAPHITE_MAX_BBS_PER_FUNCTION = %d.\n", max_bbs);
+ FOR_EACH_VEC_ELT (scops, i, scop)
+ free_scop (scop);
- fprintf (dump_file, "\nnumber of SCoPs: 0\n");
- print_global_statistics (dump_file);
- }
+ scops.release ();
+}
- isl_ctx_free (ctx);
- return false;
- }
+/* Transforms LOOP to the canonical loop closed SSA form. */
+
+static void
+canonicalize_loop_closed_ssa (loop_p loop)
+{
+ edge e = single_exit (loop);
+ basic_block bb;
+ gphi_iterator psi;
+
+ if (!e || (e->flags & EDGE_COMPLEX))
+ return;
- scev_reset ();
- recompute_all_dominators ();
- initialize_original_copy_tables ();
+ bb = e->dest;
- if (dump_file && dump_flags)
+ /* Make the loop-close PHI node BB contain only PHIs and have a
+ single predecessor. */
+ if (single_pred_p (bb))
{
- dump_function_to_file (current_function_decl, dump_file, dump_flags);
- print_loops (dump_file, 3);
+ e = split_block_after_labels (bb);
+ bb = e->src;
+ }
+ else
+ {
+ basic_block close = split_edge (e);
+ e = single_succ_edge (close);
+ for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
+ {
+ gphi *phi = psi.phi ();
+ use_operand_p use_p = PHI_ARG_DEF_PTR_FROM_EDGE (phi, e);
+ tree arg = USE_FROM_PTR (use_p);
+
+ /* Only add close phi nodes for SSA_NAMEs defined in LOOP. */
+ if (TREE_CODE (arg) != SSA_NAME
+ || SSA_NAME_IS_DEFAULT_DEF (arg)
+ || ! flow_bb_inside_loop_p (loop,
+ gimple_bb (SSA_NAME_DEF_STMT (arg))))
+ continue;
+
+ tree res = copy_ssa_name (arg);
+ gphi *close_phi = create_phi_node (res, close);
+ add_phi_arg (close_phi, arg, gimple_phi_arg_edge (close_phi, 0),
+ UNKNOWN_LOCATION);
+ SET_USE (use_p, res);
+ }
+ bb = close;
}
- return true;
+ /* Eliminate duplicates. This relies on processing loops from
+ innermost to outer. */
+ for (psi = gsi_start_phis (bb); !gsi_end_p (psi); gsi_next (&psi))
+ {
+ gphi_iterator gsi = psi;
+ gphi *phi = psi.phi ();
+
+ /* At this point, PHI should be a close phi in normal form. */
+ gcc_assert (gimple_phi_num_args (phi) == 1);
+
+ /* Iterate over the next phis and remove duplicates. */
+ gsi_next (&gsi);
+ while (!gsi_end_p (gsi))
+ if (gimple_phi_arg_def (phi, 0) == gimple_phi_arg_def (gsi.phi (), 0))
+ {
+ replace_uses_by (gimple_phi_result (gsi.phi ()),
+ gimple_phi_result (phi));
+ remove_phi_node (&gsi, true);
+ }
+ else
+ gsi_next (&gsi);
+ }
}
-/* Finalize graphite: perform CFG cleanup when NEED_CFG_CLEANUP_P is
- true. */
+/* Converts the current loop closed SSA form to a canonical form
+ expected by the Graphite code generation.
-static void
-graphite_finalize (bool need_cfg_cleanup_p)
-{
- free_dominance_info (CDI_POST_DOMINATORS);
- if (need_cfg_cleanup_p)
- {
- free_dominance_info (CDI_DOMINATORS);
- scev_reset ();
- cleanup_tree_cfg ();
- profile_status_for_fn (cfun) = PROFILE_ABSENT;
- release_recorded_exits (cfun);
- tree_estimate_probability (false);
- }
+ The loop closed SSA form has the following invariant: a variable
+ defined in a loop that is used outside the loop appears only in the
+ phi nodes in the destination of the loop exit. These phi nodes are
+ called close phi nodes.
- free_original_copy_tables ();
+ The canonical loop closed SSA form contains the extra invariants:
- if (dump_file && dump_flags)
- print_loops (dump_file, 3);
-}
+ - when the loop contains only one exit, the close phi nodes contain
+ only one argument. That implies that the basic block that contains
+ the close phi nodes has only one predecessor, that is a basic block
+ in the loop.
-/* Deletes all scops in SCOPS. */
+ - the basic block containing the close phi nodes does not contain
+ other statements.
+
+ - there exist only one phi node per definition in the loop.
+*/
static void
-free_scops (vec<scop_p> scops)
+canonicalize_loop_closed_ssa_form (void)
{
- int i;
- scop_p scop;
+ loop_p loop;
+ FOR_EACH_LOOP (loop, LI_FROM_INNERMOST)
+ canonicalize_loop_closed_ssa (loop);
- FOR_EACH_VEC_ELT (scops, i, scop)
- free_scop (scop);
-
- scops.release ();
+ checking_verify_loop_closed_ssa (true);
}
isl_ctx *the_isl_ctx;
@@ -304,7 +335,7 @@ graphite_transform_loops (void)
{
int i;
scop_p scop;
- bool need_cfg_cleanup_p = false;
+ bool changed = false;
vec<scop_p> scops = vNULL;
isl_ctx *ctx;
@@ -313,13 +344,25 @@ graphite_transform_loops (void)
if (parallelized_function_p (cfun->decl))
return;
+ calculate_dominance_info (CDI_DOMINATORS);
+
ctx = isl_ctx_alloc ();
isl_options_set_on_error (ctx, ISL_ON_ERROR_ABORT);
- if (!graphite_initialize (ctx))
- return;
-
the_isl_ctx = ctx;
+
+ sort_sibling_loops (cfun);
+ canonicalize_loop_closed_ssa_form ();
+
+ /* Print the loop structure. */
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ print_loops (dump_file, 2);
+ print_loops (dump_file, 3);
+ }
+
+ calculate_dominance_info (CDI_POST_DOMINATORS);
build_scops (&scops);
+ free_dominance_info (CDI_POST_DOMINATORS);
if (dump_file && (dump_flags & TDF_DETAILS))
{
@@ -337,23 +380,51 @@ graphite_transform_loops (void)
if (!apply_poly_transforms (scop))
continue;
- need_cfg_cleanup_p = true;
- /* When code generation is not successful, do not continue
- generating code for the next scops: the IR has to be cleaned up
- and could be in an inconsistent state. */
- if (!graphite_regenerate_ast_isl (scop))
- break;
-
- location_t loc = find_loop_location
- (scop->scop_info->region.entry->dest->loop_father);
- dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
- "loop nest optimized\n");
+ changed = true;
+ if (graphite_regenerate_ast_isl (scop))
+ {
+ location_t loc = find_loop_location
+ (scops[i]->scop_info->region.entry->dest->loop_father);
+ dump_printf_loc (MSG_OPTIMIZED_LOCATIONS, loc,
+ "loop nest optimized\n");
+ }
}
+ if (changed)
+ {
+ mark_virtual_operands_for_renaming (cfun);
+ update_ssa (TODO_update_ssa);
+ checking_verify_ssa (true, true);
+ rewrite_into_loop_closed_ssa (NULL, 0);
+ scev_reset ();
+ checking_verify_loop_structure ();
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ loop_p loop;
+ int num_no_dependency = 0;
+
+ FOR_EACH_LOOP (loop, 0)
+ if (loop->can_be_parallel)
+ num_no_dependency++;
+
+ fprintf (dump_file, "%d loops carried no dependency.\n",
+ num_no_dependency);
+ }
+
free_scops (scops);
- graphite_finalize (need_cfg_cleanup_p);
the_isl_ctx = NULL;
isl_ctx_free (ctx);
+
+ if (changed)
+ {
+ cleanup_tree_cfg ();
+ profile_status_for_fn (cfun) = PROFILE_ABSENT;
+ release_recorded_exits (cfun);
+ tree_estimate_probability (false);
+ }
+
}
#else /* If isl is not available: #ifndef HAVE_isl. */
diff --git a/gcc/graphite.h b/gcc/graphite.h
index d22c4f2..79793ee 100644
--- a/gcc/graphite.h
+++ b/gcc/graphite.h
@@ -379,6 +379,9 @@ struct scop
/* Number of parameters in SCoP. */
graphite_dim_t nb_params;
+ /* The maximum alias set as assigned to drs by build_alias_sets. */
+ unsigned max_alias_set;
+
/* All the basic blocks in this scop that contain memory references
and that will be represented as statements in the polyhedral
representation. */
diff --git a/gcc/haifa-sched.c b/gcc/haifa-sched.c
index af0ed27..4b906a3 100644
--- a/gcc/haifa-sched.c
+++ b/gcc/haifa-sched.c
@@ -225,7 +225,7 @@ struct common_sched_info_def *common_sched_info;
#define FEEDS_BACKTRACK_INSN(INSN) (HID (INSN)->feeds_backtrack_insn)
#define SHADOW_P(INSN) (HID (INSN)->shadow_p)
#define MUST_RECOMPUTE_SPEC_P(INSN) (HID (INSN)->must_recompute_spec)
-/* Cached cost of the instruction. Use insn_cost to get cost of the
+/* Cached cost of the instruction. Use insn_sched_cost to get cost of the
insn. -1 here means that the field is not initialized. */
#define INSN_COST(INSN) (HID (INSN)->cost)
@@ -1383,7 +1383,7 @@ static rtx_insn *nonscheduled_insns_begin;
This is the number of cycles between instruction issue and
instruction results. */
int
-insn_cost (rtx_insn *insn)
+insn_sched_cost (rtx_insn *insn)
{
int cost;
@@ -1470,7 +1470,7 @@ dep_cost_1 (dep_t link, dw_t dw)
{
enum reg_note dep_type = DEP_TYPE (link);
- cost = insn_cost (insn);
+ cost = insn_sched_cost (insn);
if (INSN_CODE (insn) >= 0)
{
@@ -1608,11 +1608,11 @@ priority (rtx_insn *insn)
INSN_FUSION_PRIORITY (insn) = this_fusion_priority;
}
else if (dep_list_size (insn, SD_LIST_FORW) == 0)
- /* ??? We should set INSN_PRIORITY to insn_cost when and insn has
- some forward deps but all of them are ignored by
+ /* ??? We should set INSN_PRIORITY to insn_sched_cost when and insn
+ has some forward deps but all of them are ignored by
contributes_to_priority hook. At the moment we set priority of
such insn to 0. */
- this_priority = insn_cost (insn);
+ this_priority = insn_sched_cost (insn);
else
{
rtx_insn *prev_first, *twin;
@@ -1683,7 +1683,7 @@ priority (rtx_insn *insn)
{
gcc_assert (this_priority == -1);
- this_priority = insn_cost (insn);
+ this_priority = insn_sched_cost (insn);
}
INSN_PRIORITY (insn) = this_priority;
@@ -5568,9 +5568,7 @@ autopref_multipass_init (const rtx_insn *insn, int write)
gcc_assert (data->status == AUTOPREF_MULTIPASS_DATA_UNINITIALIZED);
data->base = NULL_RTX;
- data->min_offset = 0;
- data->max_offset = 0;
- data->multi_mem_insn_p = false;
+ data->offset = 0;
/* Set insn entry initialized, but not relevant for auto-prefetcher. */
data->status = AUTOPREF_MULTIPASS_DATA_IRRELEVANT;
@@ -5585,10 +5583,9 @@ autopref_multipass_init (const rtx_insn *insn, int write)
{
int n_elems = XVECLEN (pat, 0);
- int i = 0;
- rtx prev_base = NULL_RTX;
- int min_offset = 0;
- int max_offset = 0;
+ int i, offset;
+ rtx base, prev_base = NULL_RTX;
+ int min_offset = INT_MAX;
for (i = 0; i < n_elems; i++)
{
@@ -5596,38 +5593,23 @@ autopref_multipass_init (const rtx_insn *insn, int write)
if (GET_CODE (set) != SET)
return;
- rtx base = NULL_RTX;
- int offset = 0;
if (!analyze_set_insn_for_autopref (set, write, &base, &offset))
return;
- if (i == 0)
- {
- prev_base = base;
- min_offset = offset;
- max_offset = offset;
- }
/* Ensure that all memory operations in the PARALLEL use the same
base register. */
- else if (REGNO (base) != REGNO (prev_base))
+ if (i > 0 && REGNO (base) != REGNO (prev_base))
return;
- else
- {
- min_offset = MIN (min_offset, offset);
- max_offset = MAX (max_offset, offset);
- }
+ prev_base = base;
+ min_offset = MIN (min_offset, offset);
}
- /* If we reached here then we have a valid PARALLEL of multiple memory
- ops with prev_base as the base and min_offset and max_offset
- containing the offsets range. */
+ /* If we reached here then we have a valid PARALLEL of multiple memory ops
+ with prev_base as the base and min_offset containing the offset. */
gcc_assert (prev_base);
data->base = prev_base;
- data->min_offset = min_offset;
- data->max_offset = max_offset;
- data->multi_mem_insn_p = true;
+ data->offset = min_offset;
data->status = AUTOPREF_MULTIPASS_DATA_NORMAL;
-
return;
}
@@ -5637,7 +5619,7 @@ autopref_multipass_init (const rtx_insn *insn, int write)
return;
if (!analyze_set_insn_for_autopref (set, write, &data->base,
- &data->min_offset))
+ &data->offset))
return;
/* This insn is relevant for the auto-prefetcher.
@@ -5646,68 +5628,12 @@ autopref_multipass_init (const rtx_insn *insn, int write)
data->status = AUTOPREF_MULTIPASS_DATA_NORMAL;
}
-
-/* Helper for autopref_rank_for_schedule. Given the data of two
- insns relevant to the auto-prefetcher modelling code DATA1 and DATA2
- return their comparison result. Return 0 if there is no sensible
- ranking order for the two insns. */
-
-static int
-autopref_rank_data (autopref_multipass_data_t data1,
- autopref_multipass_data_t data2)
-{
- /* Simple case when both insns are simple single memory ops. */
- if (!data1->multi_mem_insn_p && !data2->multi_mem_insn_p)
- return data1->min_offset - data2->min_offset;
-
- /* Two load/store multiple insns. Return 0 if the offset ranges
- overlap and the difference between the minimum offsets otherwise. */
- else if (data1->multi_mem_insn_p && data2->multi_mem_insn_p)
- {
- int min1 = data1->min_offset;
- int max1 = data1->max_offset;
- int min2 = data2->min_offset;
- int max2 = data2->max_offset;
-
- if (max1 < min2 || min1 > max2)
- return min1 - min2;
- else
- return 0;
- }
-
- /* The other two cases is a pair of a load/store multiple and
- a simple memory op. Return 0 if the single op's offset is within the
- range of the multi-op insn and the difference between the single offset
- and the minimum offset of the multi-set insn otherwise. */
- else if (data1->multi_mem_insn_p && !data2->multi_mem_insn_p)
- {
- int max1 = data1->max_offset;
- int min1 = data1->min_offset;
-
- if (data2->min_offset >= min1
- && data2->min_offset <= max1)
- return 0;
- else
- return min1 - data2->min_offset;
- }
- else
- {
- int max2 = data2->max_offset;
- int min2 = data2->min_offset;
-
- if (data1->min_offset >= min2
- && data1->min_offset <= max2)
- return 0;
- else
- return data1->min_offset - min2;
- }
-}
-
/* Helper function for rank_for_schedule sorting. */
static int
autopref_rank_for_schedule (const rtx_insn *insn1, const rtx_insn *insn2)
{
- for (int write = 0; write < 2; ++write)
+ int r = 0;
+ for (int write = 0; write < 2 && !r; ++write)
{
autopref_multipass_data_t data1
= &INSN_AUTOPREF_MULTIPASS_DATA (insn1)[write];
@@ -5716,21 +5642,20 @@ autopref_rank_for_schedule (const rtx_insn *insn1, const rtx_insn *insn2)
if (data1->status == AUTOPREF_MULTIPASS_DATA_UNINITIALIZED)
autopref_multipass_init (insn1, write);
- if (data1->status == AUTOPREF_MULTIPASS_DATA_IRRELEVANT)
- continue;
if (data2->status == AUTOPREF_MULTIPASS_DATA_UNINITIALIZED)
autopref_multipass_init (insn2, write);
- if (data2->status == AUTOPREF_MULTIPASS_DATA_IRRELEVANT)
- continue;
- if (!rtx_equal_p (data1->base, data2->base))
- continue;
+ int irrel1 = data1->status == AUTOPREF_MULTIPASS_DATA_IRRELEVANT;
+ int irrel2 = data2->status == AUTOPREF_MULTIPASS_DATA_IRRELEVANT;
- return autopref_rank_data (data1, data2);
+ if (!irrel1 && !irrel2)
+ r = data1->offset - data2->offset;
+ else
+ r = irrel2 - irrel1;
}
- return 0;
+ return r;
}
/* True if header of debug dump was printed. */
@@ -5753,7 +5678,7 @@ autopref_multipass_dfa_lookahead_guard_1 (const rtx_insn *insn1,
return 0;
if (rtx_equal_p (data1->base, data2->base)
- && autopref_rank_data (data1, data2) > 0)
+ && data1->offset > data2->offset)
{
if (sched_verbose >= 2)
{
@@ -6302,7 +6227,7 @@ prune_ready_list (state_t temp_state, bool first_cycle_insn_p,
{
int i, pass;
bool sched_group_found = false;
- int min_cost_group = 1;
+ int min_cost_group = 0;
if (sched_fusion)
return;
@@ -6318,8 +6243,8 @@ prune_ready_list (state_t temp_state, bool first_cycle_insn_p,
}
/* Make two passes if there's a SCHED_GROUP_P insn; make sure to handle
- such an insn first and note its cost, then schedule all other insns
- for one cycle later. */
+ such an insn first and note its cost. If at least one SCHED_GROUP_P insn
+ gets queued, then all other insns get queued for one cycle later. */
for (pass = sched_group_found ? 0 : 1; pass < 2; )
{
int n = ready.n_ready;
@@ -6332,7 +6257,8 @@ prune_ready_list (state_t temp_state, bool first_cycle_insn_p,
if (DEBUG_INSN_P (insn))
continue;
- if (sched_group_found && !SCHED_GROUP_P (insn))
+ if (sched_group_found && !SCHED_GROUP_P (insn)
+ && ((pass == 0) || (min_cost_group >= 1)))
{
if (pass == 0)
continue;
@@ -8309,11 +8235,9 @@ sched_create_recovery_edges (basic_block first_bb, basic_block rec,
'todo_spec' variable in create_check_block_twin and
in sel-sched.c `check_ds' in create_speculation_check. */
e->probability = profile_probability::very_unlikely ();
- e->count = first_bb->count.apply_probability (e->probability);
- rec->count = e->count;
+ rec->count = e->count ();
rec->frequency = EDGE_FREQUENCY (e);
e2->probability = e->probability.invert ();
- e2->count = first_bb->count - e2->count;
rtx_code_label *label = block_label (second_bb);
rtx_jump_insn *jump = emit_jump_insn_after (targetm.gen_jump (label),
diff --git a/gcc/hooks.c b/gcc/hooks.c
index d383926..61ff890 100644
--- a/gcc/hooks.c
+++ b/gcc/hooks.c
@@ -259,6 +259,12 @@ hook_uint_void_0 (void)
return 0;
}
+HOST_WIDE_INT
+hook_hwi_void_0 (void)
+{
+ return 0;
+}
+
void
hook_void_tree (tree)
{
diff --git a/gcc/hooks.h b/gcc/hooks.h
index 711d0e2..8dbfd78 100644
--- a/gcc/hooks.h
+++ b/gcc/hooks.h
@@ -98,6 +98,8 @@ extern int hook_int_rtx_bool_0 (rtx, bool);
extern int hook_int_rtx_mode_as_bool_0 (rtx, machine_mode, addr_space_t,
bool);
+extern HOST_WIDE_INT hook_hwi_void_0 (void);
+
extern tree hook_tree_const_tree_null (const_tree);
extern tree hook_tree_void_null (void);
diff --git a/gcc/hsa-common.h b/gcc/hsa-common.h
index 810624e..3075163 100644
--- a/gcc/hsa-common.h
+++ b/gcc/hsa-common.h
@@ -157,6 +157,9 @@ public:
/* Convert an operand to a destination type DTYPE and attach insns
to HBB if needed. */
hsa_op_with_type *get_in_type (BrigType16_t dtype, hsa_bb *hbb);
+ /* If this operand has integer type smaller than 32 bits, extend it to 32
+ bits, adding instructions to HBB if needed. */
+ hsa_op_with_type *extend_int_to_32bit (hsa_bb *hbb);
protected:
hsa_op_with_type (BrigKind16_t k, BrigType16_t t);
diff --git a/gcc/hsa-gen.c b/gcc/hsa-gen.c
index 6e054c0..a2cb8b2 100644
--- a/gcc/hsa-gen.c
+++ b/gcc/hsa-gen.c
@@ -564,6 +564,19 @@ get_integer_type_by_bytes (unsigned size, bool sign)
return 0;
}
+/* If T points to an integral type smaller than 32 bits, change it to a 32bit
+ equivalent and return the result. Otherwise just return the result. */
+
+static BrigType16_t
+hsa_extend_inttype_to_32bit (BrigType16_t t)
+{
+ if (t == BRIG_TYPE_U8 || t == BRIG_TYPE_U16)
+ return BRIG_TYPE_U32;
+ else if (t == BRIG_TYPE_S8 || t == BRIG_TYPE_S16)
+ return BRIG_TYPE_S32;
+ return t;
+}
+
/* Return HSA type for tree TYPE, which has to fit into BrigType16_t. Pointers
are assumed to use flat addressing. If min32int is true, always expand
integer types to one that has at least 32 bits. */
@@ -580,8 +593,13 @@ hsa_type_for_scalar_tree_type (const_tree type, bool min32int)
if (POINTER_TYPE_P (type))
return hsa_get_segment_addr_type (BRIG_SEGMENT_FLAT);
- if (TREE_CODE (type) == VECTOR_TYPE || TREE_CODE (type) == COMPLEX_TYPE)
+ if (TREE_CODE (type) == VECTOR_TYPE)
base = TREE_TYPE (type);
+ else if (TREE_CODE (type) == COMPLEX_TYPE)
+ {
+ base = TREE_TYPE (type);
+ min32int = true;
+ }
else
base = type;
@@ -652,14 +670,9 @@ hsa_type_for_scalar_tree_type (const_tree type, bool min32int)
}
if (min32int)
- {
- /* Registers/immediate operands can only be 32bit or more except for
- f16. */
- if (res == BRIG_TYPE_U8 || res == BRIG_TYPE_U16)
- res = BRIG_TYPE_U32;
- else if (res == BRIG_TYPE_S8 || res == BRIG_TYPE_S16)
- res = BRIG_TYPE_S32;
- }
+ /* Registers/immediate operands can only be 32bit or more except for
+ f16. */
+ res = hsa_extend_inttype_to_32bit (res);
if (TREE_CODE (type) == COMPLEX_TYPE)
{
@@ -1009,6 +1022,16 @@ hsa_get_string_cst_symbol (tree string_cst)
return sym;
}
+/* Make the type of a MOV instruction larger if mandated by HSAIL rules. */
+
+static void
+hsa_fixup_mov_insn_type (hsa_insn_basic *insn)
+{
+ insn->m_type = hsa_extend_inttype_to_32bit (insn->m_type);
+ if (insn->m_type == BRIG_TYPE_B8 || insn->m_type == BRIG_TYPE_B16)
+ insn->m_type = BRIG_TYPE_B32;
+}
+
/* Constructor of the ancestor of all operands. K is BRIG kind that identified
what the operator is. */
@@ -1050,9 +1073,11 @@ hsa_op_with_type::get_in_type (BrigType16_t dtype, hsa_bb *hbb)
else
{
dest = new hsa_op_reg (m_type);
- hbb->append_insn (new hsa_insn_basic (2, BRIG_OPCODE_MOV,
- dest->m_type, dest, this));
+ hsa_insn_basic *mov = new hsa_insn_basic (2, BRIG_OPCODE_MOV,
+ dest->m_type, dest, this);
+ hsa_fixup_mov_insn_type (mov);
+ hbb->append_insn (mov);
/* We cannot simply for instance: 'mov_u32 $_3, 48 (s32)' because
type of the operand must be same as type of the instruction. */
dest->m_type = dtype;
@@ -1061,6 +1086,20 @@ hsa_op_with_type::get_in_type (BrigType16_t dtype, hsa_bb *hbb)
return dest;
}
+/* If this operand has integer type smaller than 32 bits, extend it to 32 bits,
+ adding instructions to HBB if needed. */
+
+hsa_op_with_type *
+hsa_op_with_type::extend_int_to_32bit (hsa_bb *hbb)
+{
+ if (m_type == BRIG_TYPE_U8 || m_type == BRIG_TYPE_U16)
+ return get_in_type (BRIG_TYPE_U32, hbb);
+ else if (m_type == BRIG_TYPE_S8 || m_type == BRIG_TYPE_S16)
+ return get_in_type (BRIG_TYPE_S32, hbb);
+ else
+ return this;
+}
+
/* Constructor of class representing HSA immediate values. TREE_VAL is the
tree representation of the immediate value. If min32int is true,
always expand integer types to one that has at least 32 bits. */
@@ -1292,7 +1331,7 @@ hsa_function_representation::reg_for_gimple_ssa (tree ssa)
return m_ssa_map[SSA_NAME_VERSION (ssa)];
hreg = new hsa_op_reg (hsa_type_for_scalar_tree_type (TREE_TYPE (ssa),
- true));
+ false));
hreg->m_gimple_ssa = ssa;
m_ssa_map[SSA_NAME_VERSION (ssa)] = hreg;
@@ -1799,7 +1838,7 @@ gen_address_calculation (tree exp, hsa_bb *hbb, BrigType16_t addrtype)
case INTEGER_CST:
{
- hsa_op_immed *imm = new hsa_op_immed (exp);
+ hsa_op_immed *imm = new hsa_op_immed (exp);
if (addrtype != imm->m_type)
imm->m_type = addrtype;
return imm;
@@ -1957,8 +1996,10 @@ gen_hsa_addr (tree ref, hsa_bb *hbb, HOST_WIDE_INT *output_bitsize = NULL,
case SSA_NAME:
{
addrtype = hsa_get_segment_addr_type (BRIG_SEGMENT_PRIVATE);
- symbol = hsa_cfun->create_hsa_temporary (flat_addrtype);
- hsa_op_reg *r = hsa_cfun->reg_for_gimple_ssa (ref);
+ hsa_op_with_type *r = hsa_cfun->reg_for_gimple_ssa (ref);
+ if (r->m_type == BRIG_TYPE_B1)
+ r = r->get_in_type (BRIG_TYPE_U32, hbb);
+ symbol = hsa_cfun->create_hsa_temporary (r->m_type);
hbb->append_insn (new hsa_insn_mem (BRIG_OPCODE_ST, r->m_type,
r, new hsa_op_address (symbol)));
@@ -2247,13 +2288,18 @@ hsa_build_append_simple_mov (hsa_op_reg *dest, hsa_op_base *src, hsa_bb *hbb)
rules like when dealing with memory. */
BrigType16_t tp = mem_type_for_type (dest->m_type);
hsa_insn_basic *insn = new hsa_insn_basic (2, BRIG_OPCODE_MOV, tp, dest, src);
+ hsa_fixup_mov_insn_type (insn);
+ unsigned dest_size = hsa_type_bit_size (dest->m_type);
if (hsa_op_reg *sreg = dyn_cast <hsa_op_reg *> (src))
- gcc_assert (hsa_type_bit_size (dest->m_type)
- == hsa_type_bit_size (sreg->m_type));
+ gcc_assert (dest_size == hsa_type_bit_size (sreg->m_type));
else
- gcc_assert (hsa_type_bit_size (dest->m_type)
- == hsa_type_bit_size (as_a <hsa_op_immed *> (src)->m_type));
-
+ {
+ unsigned imm_size
+ = hsa_type_bit_size (as_a <hsa_op_immed *> (src)->m_type);
+ gcc_assert ((dest_size == imm_size)
+ /* Eventually < 32bit registers will be promoted to 32bit. */
+ || (dest_size < 32 && imm_size == 32));
+ }
hbb->append_insn (insn);
}
@@ -2268,13 +2314,15 @@ gen_hsa_insns_for_bitfield (hsa_op_reg *dest, hsa_op_reg *value_reg,
HOST_WIDE_INT bitsize, HOST_WIDE_INT bitpos,
hsa_bb *hbb)
{
- unsigned type_bitsize = hsa_type_bit_size (dest->m_type);
+ unsigned type_bitsize
+ = hsa_type_bit_size (hsa_extend_inttype_to_32bit (dest->m_type));
unsigned left_shift = type_bitsize - (bitsize + bitpos);
unsigned right_shift = left_shift + bitpos;
if (left_shift)
{
- hsa_op_reg *value_reg_2 = new hsa_op_reg (dest->m_type);
+ hsa_op_reg *value_reg_2
+ = new hsa_op_reg (hsa_extend_inttype_to_32bit (dest->m_type));
hsa_op_immed *c = new hsa_op_immed (left_shift, BRIG_TYPE_U32);
hsa_insn_basic *lshift
@@ -2288,7 +2336,8 @@ gen_hsa_insns_for_bitfield (hsa_op_reg *dest, hsa_op_reg *value_reg,
if (right_shift)
{
- hsa_op_reg *value_reg_2 = new hsa_op_reg (dest->m_type);
+ hsa_op_reg *value_reg_2
+ = new hsa_op_reg (hsa_extend_inttype_to_32bit (dest->m_type));
hsa_op_immed *c = new hsa_op_immed (right_shift, BRIG_TYPE_U32);
hsa_insn_basic *rshift
@@ -2301,8 +2350,10 @@ gen_hsa_insns_for_bitfield (hsa_op_reg *dest, hsa_op_reg *value_reg,
}
hsa_insn_basic *assignment
- = new hsa_insn_basic (2, BRIG_OPCODE_MOV, dest->m_type, dest, value_reg);
+ = new hsa_insn_basic (2, BRIG_OPCODE_MOV, dest->m_type, NULL, value_reg);
+ hsa_fixup_mov_insn_type (assignment);
hbb->append_insn (assignment);
+ assignment->set_output_in_type (dest, 0, hbb);
}
@@ -2318,8 +2369,10 @@ gen_hsa_insns_for_bitfield_load (hsa_op_reg *dest, hsa_op_address *addr,
hsa_bb *hbb, BrigAlignment8_t align)
{
hsa_op_reg *value_reg = new hsa_op_reg (dest->m_type);
- hsa_insn_mem *mem = new hsa_insn_mem (BRIG_OPCODE_LD, dest->m_type, value_reg,
- addr);
+ hsa_insn_mem *mem
+ = new hsa_insn_mem (BRIG_OPCODE_LD,
+ hsa_extend_inttype_to_32bit (dest->m_type),
+ value_reg, addr);
mem->set_align (align);
hbb->append_insn (mem);
gen_hsa_insns_for_bitfield (dest, value_reg, bitsize, bitpos, hbb);
@@ -2446,9 +2499,10 @@ gen_hsa_insns_for_load (hsa_op_reg *dest, tree rhs, tree type, hsa_bb *hbb)
real_reg : imag_reg;
hsa_insn_basic *insn = new hsa_insn_basic (2, BRIG_OPCODE_MOV,
- dest->m_type, dest, source);
-
+ dest->m_type, NULL, source);
+ hsa_fixup_mov_insn_type (insn);
hbb->append_insn (insn);
+ insn->set_output_in_type (dest, 0, hbb);
}
else if (TREE_CODE (rhs) == BIT_FIELD_REF
&& TREE_CODE (TREE_OPERAND (rhs, 0)) == SSA_NAME)
@@ -2584,6 +2638,7 @@ gen_hsa_insns_for_store (tree lhs, hsa_op_base *src, hsa_bb *hbb)
hsa_insn_basic *basic = new hsa_insn_basic (2, BRIG_OPCODE_MOV, mem_type,
new_value_reg, src);
+ hsa_fixup_mov_insn_type (basic);
hbb->append_insn (basic);
if (bitpos)
@@ -2954,8 +3009,10 @@ gen_hsa_cmp_insn_from_gimple (enum tree_code code, tree lhs, tree rhs,
? (BrigType16_t) BRIG_TYPE_B1 : dest->m_type;
hsa_insn_cmp *cmp = new hsa_insn_cmp (compare, dest_type);
- cmp->set_op (1, hsa_reg_or_immed_for_gimple_op (lhs, hbb));
- cmp->set_op (2, hsa_reg_or_immed_for_gimple_op (rhs, hbb));
+ hsa_op_with_type *op1 = hsa_reg_or_immed_for_gimple_op (lhs, hbb);
+ cmp->set_op (1, op1->extend_int_to_32bit (hbb));
+ hsa_op_with_type *op2 = hsa_reg_or_immed_for_gimple_op (rhs, hbb);
+ cmp->set_op (2, op2->extend_int_to_32bit (hbb));
hbb->append_insn (cmp);
cmp->set_output_in_type (dest, 0, hbb);
@@ -2973,8 +3030,14 @@ gen_hsa_unary_operation (BrigOpcode opcode, hsa_op_reg *dest,
hsa_insn_basic *insn;
if (opcode == BRIG_OPCODE_MOV && hsa_needs_cvt (dest->m_type, op1->m_type))
- insn = new hsa_insn_cvt (dest, op1);
- else if (opcode == BRIG_OPCODE_FIRSTBIT || opcode == BRIG_OPCODE_LASTBIT)
+ {
+ insn = new hsa_insn_cvt (dest, op1);
+ hbb->append_insn (insn);
+ return;
+ }
+
+ op1 = op1->extend_int_to_32bit (hbb);
+ if (opcode == BRIG_OPCODE_FIRSTBIT || opcode == BRIG_OPCODE_LASTBIT)
{
BrigType16_t srctype = hsa_type_integer_p (op1->m_type) ? op1->m_type
: hsa_unsigned_type_for_type (op1->m_type);
@@ -2983,9 +3046,12 @@ gen_hsa_unary_operation (BrigOpcode opcode, hsa_op_reg *dest,
}
else
{
- insn = new hsa_insn_basic (2, opcode, dest->m_type, dest, op1);
+ BrigType16_t optype = hsa_extend_inttype_to_32bit (dest->m_type);
+ insn = new hsa_insn_basic (2, opcode, optype, NULL, op1);
- if (opcode == BRIG_OPCODE_ABS || opcode == BRIG_OPCODE_NEG)
+ if (opcode == BRIG_OPCODE_MOV)
+ hsa_fixup_mov_insn_type (insn);
+ else if (opcode == BRIG_OPCODE_ABS || opcode == BRIG_OPCODE_NEG)
{
/* ABS and NEG only exist in _s form :-/ */
if (insn->m_type == BRIG_TYPE_U32)
@@ -2996,9 +3062,7 @@ gen_hsa_unary_operation (BrigOpcode opcode, hsa_op_reg *dest,
}
hbb->append_insn (insn);
-
- if (opcode == BRIG_OPCODE_FIRSTBIT || opcode == BRIG_OPCODE_LASTBIT)
- insn->set_output_in_type (dest, 0, hbb);
+ insn->set_output_in_type (dest, 0, hbb);
}
/* Generate a binary instruction with OPCODE and append it to a basic block
@@ -3007,10 +3071,15 @@ gen_hsa_unary_operation (BrigOpcode opcode, hsa_op_reg *dest,
static void
gen_hsa_binary_operation (int opcode, hsa_op_reg *dest,
- hsa_op_base *op1, hsa_op_base *op2, hsa_bb *hbb)
+ hsa_op_with_type *op1, hsa_op_with_type *op2,
+ hsa_bb *hbb)
{
gcc_checking_assert (dest);
+ BrigType16_t optype = hsa_extend_inttype_to_32bit (dest->m_type);
+ op1 = op1->extend_int_to_32bit (hbb);
+ op2 = op2->extend_int_to_32bit (hbb);
+
if ((opcode == BRIG_OPCODE_SHL || opcode == BRIG_OPCODE_SHR)
&& is_a <hsa_op_immed *> (op2))
{
@@ -3026,9 +3095,10 @@ gen_hsa_binary_operation (int opcode, hsa_op_reg *dest,
i->set_type (hsa_unsigned_type_for_type (i->m_type));
}
- hsa_insn_basic *insn = new hsa_insn_basic (3, opcode, dest->m_type, dest,
+ hsa_insn_basic *insn = new hsa_insn_basic (3, opcode, optype, NULL,
op1, op2);
hbb->append_insn (insn);
+ insn->set_output_in_type (dest, 0, hbb);
}
/* Generate HSA instructions for a single assignment. HBB is the basic block
@@ -3150,6 +3220,7 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb)
else if (TREE_CODE (rhs2) == SSA_NAME)
{
hsa_op_reg *s = hsa_cfun->reg_for_gimple_ssa (rhs2);
+ s = as_a <hsa_op_reg *> (s->extend_int_to_32bit (hbb));
hsa_op_reg *d = new hsa_op_reg (s->m_type);
hsa_op_immed *size_imm = new hsa_op_immed (bitsize, BRIG_TYPE_U32);
@@ -3253,8 +3324,11 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb)
hsa_op_with_type *op2 = hsa_reg_or_immed_for_gimple_op (rhs2, hbb);
hsa_op_with_type *op3 = hsa_reg_or_immed_for_gimple_op (rhs3, hbb);
+ op2 = op2->extend_int_to_32bit (hbb);
+ op3 = op3->extend_int_to_32bit (hbb);
- BrigType16_t utype = hsa_unsigned_type_for_type (dest->m_type);
+ BrigType16_t type = hsa_extend_inttype_to_32bit (dest->m_type);
+ BrigType16_t utype = hsa_unsigned_type_for_type (type);
if (is_a <hsa_op_immed *> (op2))
op2->m_type = utype;
if (is_a <hsa_op_immed *> (op3))
@@ -3262,10 +3336,11 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb)
hsa_insn_basic *insn
= new hsa_insn_basic (4, BRIG_OPCODE_CMOV,
- hsa_bittype_for_type (dest->m_type),
- dest, ctrl, op2, op3);
+ hsa_bittype_for_type (type),
+ NULL, ctrl, op2, op3);
hbb->append_insn (insn);
+ insn->set_output_in_type (dest, 0, hbb);
return;
}
case COMPLEX_EXPR:
@@ -3273,7 +3348,9 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb)
hsa_op_reg *dest
= hsa_cfun->reg_for_gimple_ssa (gimple_assign_lhs (assign));
hsa_op_with_type *rhs1_reg = hsa_reg_or_immed_for_gimple_op (rhs1, hbb);
+ rhs1_reg = rhs1_reg->extend_int_to_32bit (hbb);
hsa_op_with_type *rhs2_reg = hsa_reg_or_immed_for_gimple_op (rhs2, hbb);
+ rhs2_reg = rhs2_reg->extend_int_to_32bit (hbb);
if (hsa_seen_error ())
return;
@@ -3298,11 +3375,10 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb)
}
- hsa_op_reg *dest = hsa_cfun->reg_for_gimple_ssa (gimple_assign_lhs (assign));
-
+ hsa_op_reg *dest = hsa_cfun->reg_for_gimple_ssa (lhs);
hsa_op_with_type *op1 = hsa_reg_or_immed_for_gimple_op (rhs1, hbb);
- hsa_op_with_type *op2 = rhs2 != NULL_TREE ?
- hsa_reg_or_immed_for_gimple_op (rhs2, hbb) : NULL;
+ hsa_op_with_type *op2
+ = rhs2 ? hsa_reg_or_immed_for_gimple_op (rhs2, hbb) : NULL;
if (hsa_seen_error ())
return;
@@ -3312,6 +3388,7 @@ gen_hsa_insns_for_operation_assignment (gimple *assign, hsa_bb *hbb)
case GIMPLE_TERNARY_RHS:
{
hsa_op_with_type *op3 = hsa_reg_or_immed_for_gimple_op (rhs3, hbb);
+ op3 = op3->extend_int_to_32bit (hbb);
hsa_insn_basic *insn = new hsa_insn_basic (4, opcode, dest->m_type, dest,
op1, op2, op3);
hbb->append_insn (insn);
@@ -3407,14 +3484,15 @@ gen_hsa_insns_for_switch_stmt (gswitch *s, hsa_bb *hbb)
tree highest = get_switch_high (s);
hsa_op_reg *index = hsa_cfun->reg_for_gimple_ssa (index_tree);
+ index = as_a <hsa_op_reg *> (index->extend_int_to_32bit (hbb));
hsa_op_reg *cmp1_reg = new hsa_op_reg (BRIG_TYPE_B1);
- hsa_op_immed *cmp1_immed = new hsa_op_immed (lowest);
+ hsa_op_immed *cmp1_immed = new hsa_op_immed (lowest, true);
hbb->append_insn (new hsa_insn_cmp (BRIG_COMPARE_GE, cmp1_reg->m_type,
cmp1_reg, index, cmp1_immed));
hsa_op_reg *cmp2_reg = new hsa_op_reg (BRIG_TYPE_B1);
- hsa_op_immed *cmp2_immed = new hsa_op_immed (highest);
+ hsa_op_immed *cmp2_immed = new hsa_op_immed (highest, true);
hbb->append_insn (new hsa_insn_cmp (BRIG_COMPARE_LE, cmp2_reg->m_type,
cmp2_reg, index, cmp2_immed));
@@ -3444,7 +3522,7 @@ gen_hsa_insns_for_switch_stmt (gswitch *s, hsa_bb *hbb)
hsa_op_reg *sub_index = new hsa_op_reg (index->m_type);
hbb->append_insn (new hsa_insn_basic (3, BRIG_OPCODE_SUB, sub_index->m_type,
sub_index, index,
- new hsa_op_immed (lowest)));
+ new hsa_op_immed (lowest, true)));
hsa_op_base *tmp = sub_index->get_in_type (BRIG_TYPE_U64, hbb);
sub_index = as_a <hsa_op_reg *> (tmp);
@@ -3760,7 +3838,6 @@ void
hsa_insn_basic::set_output_in_type (hsa_op_reg *dest, unsigned op_index,
hsa_bb *hbb)
{
- hsa_insn_basic *insn;
gcc_checking_assert (op_output_p (op_index));
if (dest->m_type == m_type)
@@ -3769,15 +3846,28 @@ hsa_insn_basic::set_output_in_type (hsa_op_reg *dest, unsigned op_index,
return;
}
- hsa_op_reg *tmp = new hsa_op_reg (m_type);
- set_op (op_index, tmp);
-
+ hsa_insn_basic *insn;
+ hsa_op_reg *tmp;
if (hsa_needs_cvt (dest->m_type, m_type))
- insn = new hsa_insn_cvt (dest, tmp);
+ {
+ tmp = new hsa_op_reg (m_type);
+ insn = new hsa_insn_cvt (dest, tmp);
+ }
+ else if (hsa_type_bit_size (dest->m_type) == hsa_type_bit_size (m_type))
+ {
+ /* When output, HSA registers do not really have types, only sizes, so if
+ the sizes match, we can use the register directly. */
+ set_op (op_index, dest);
+ return;
+ }
else
- insn = new hsa_insn_basic (2, BRIG_OPCODE_MOV, dest->m_type,
- dest, tmp->get_in_type (dest->m_type, hbb));
-
+ {
+ tmp = new hsa_op_reg (m_type);
+ insn = new hsa_insn_basic (2, BRIG_OPCODE_MOV, dest->m_type,
+ dest, tmp->get_in_type (dest->m_type, hbb));
+ hsa_fixup_mov_insn_type (insn);
+ }
+ set_op (op_index, tmp);
hbb->append_insn (insn);
}
@@ -4148,12 +4238,11 @@ gen_hsa_alloca (gcall *call, hsa_bb *hbb)
built_in_function fn = DECL_FUNCTION_CODE (gimple_call_fndecl (call));
- gcc_checking_assert (fn == BUILT_IN_ALLOCA
- || fn == BUILT_IN_ALLOCA_WITH_ALIGN);
+ gcc_checking_assert (ALLOCA_FUNCTION_CODE_P (fn));
unsigned bit_alignment = 0;
- if (fn == BUILT_IN_ALLOCA_WITH_ALIGN)
+ if (fn != BUILT_IN_ALLOCA)
{
tree alignment_tree = gimple_call_arg (call, 1);
if (TREE_CODE (alignment_tree) != INTEGER_CST)
@@ -4200,6 +4289,7 @@ gen_hsa_clrsb (gcall *call, hsa_bb *hbb)
hsa_op_reg *dest = hsa_cfun->reg_for_gimple_ssa (lhs);
tree rhs1 = gimple_call_arg (call, 0);
hsa_op_with_type *arg = hsa_reg_or_immed_for_gimple_op (rhs1, hbb);
+ arg->extend_int_to_32bit (hbb);
BrigType16_t bittype = hsa_bittype_for_type (arg->m_type);
unsigned bitsize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (rhs1)));
@@ -4272,6 +4362,7 @@ gen_hsa_ffs (gcall *call, hsa_bb *hbb)
tree rhs1 = gimple_call_arg (call, 0);
hsa_op_with_type *arg = hsa_reg_or_immed_for_gimple_op (rhs1, hbb);
+ arg = arg->extend_int_to_32bit (hbb);
hsa_op_reg *tmp = new hsa_op_reg (BRIG_TYPE_U32);
hsa_insn_srctype *insn = new hsa_insn_srctype (2, BRIG_OPCODE_LASTBIT,
@@ -4361,7 +4452,9 @@ gen_hsa_divmod (gcall *call, hsa_bb *hbb)
tree rhs1 = gimple_call_arg (call, 1);
hsa_op_with_type *arg0 = hsa_reg_or_immed_for_gimple_op (rhs0, hbb);
+ arg0 = arg0->extend_int_to_32bit (hbb);
hsa_op_with_type *arg1 = hsa_reg_or_immed_for_gimple_op (rhs1, hbb);
+ arg1 = arg1->extend_int_to_32bit (hbb);
hsa_op_reg *dest0 = new hsa_op_reg (arg0->m_type);
hsa_op_reg *dest1 = new hsa_op_reg (arg1->m_type);
@@ -4374,11 +4467,13 @@ gen_hsa_divmod (gcall *call, hsa_bb *hbb)
hbb->append_insn (insn);
hsa_op_reg *dest = hsa_cfun->reg_for_gimple_ssa (lhs);
+ BrigType16_t dst_type = hsa_extend_inttype_to_32bit (dest->m_type);
BrigType16_t src_type = hsa_bittype_for_type (dest0->m_type);
- insn = new hsa_insn_packed (3, BRIG_OPCODE_COMBINE, dest->m_type,
- src_type, dest, dest0, dest1);
+ insn = new hsa_insn_packed (3, BRIG_OPCODE_COMBINE, dst_type,
+ src_type, NULL, dest0, dest1);
hbb->append_insn (insn);
+ insn->set_output_in_type (dest, 0, hbb);
}
/* Set VALUE to a shadow kernel debug argument and append a new instruction
@@ -4936,8 +5031,8 @@ gen_hsa_atomic_for_builtin (bool ret_orig, enum BrigAtomicOperation acode,
tgt = addr;
}
- hsa_op_base *op = hsa_reg_or_immed_for_gimple_op (gimple_call_arg (stmt, 1),
- hbb);
+ hsa_op_with_type *op
+ = hsa_reg_or_immed_for_gimple_op (gimple_call_arg (stmt, 1), hbb);
if (lhs)
{
atominsn->set_op (0, dest);
@@ -5560,8 +5655,7 @@ gen_hsa_insns_for_call (gimple *stmt, hsa_bb *hbb)
break;
}
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
{
gen_hsa_alloca (call, hbb);
break;
@@ -6175,7 +6269,7 @@ convert_switch_statements (void)
tree label = gimple_switch_label (s, i);
basic_block label_bb = label_to_block_fn (func, CASE_LABEL (label));
edge e = find_edge (bb, label_bb);
- edge_counts.safe_push (e->count);
+ edge_counts.safe_push (e->count ());
edge_probabilities.safe_push (e->probability);
gphi_iterator phi_gsi;
@@ -6265,7 +6359,6 @@ convert_switch_statements (void)
if (prob_sum.initialized_p ())
new_edge->probability = edge_probabilities[i] / prob_sum;
- new_edge->count = edge_counts[i];
new_edges.safe_push (new_edge);
if (i < labels - 1)
@@ -6281,9 +6374,6 @@ convert_switch_statements (void)
edge next_edge = make_edge (cur_bb, next_bb, EDGE_FALSE_VALUE);
next_edge->probability = new_edge->probability.invert ();
- next_edge->count = edge_counts[0]
- + sum_slice <profile_count> (edge_counts, i, labels,
- profile_count::zero ());
next_bb->frequency = EDGE_FREQUENCY (next_edge);
cur_bb = next_bb;
}
@@ -6292,7 +6382,6 @@ convert_switch_statements (void)
{
edge e = make_edge (cur_bb, default_label_bb, EDGE_FALSE_VALUE);
e->probability = new_edge->probability.invert ();
- e->count = edge_counts[0];
new_edges.safe_insert (0, e);
}
}
diff --git a/gcc/ifcvt.c b/gcc/ifcvt.c
index e1b163c..72bab82 100644
--- a/gcc/ifcvt.c
+++ b/gcc/ifcvt.c
@@ -121,7 +121,7 @@ count_bb_insns (const_basic_block bb)
return count;
}
-/* Determine whether the total insn_rtx_cost on non-jump insns in
+/* Determine whether the total insn_cost on non-jump insns in
basic block BB is less than MAX_COST. This function returns
false if the cost of any instruction could not be estimated.
@@ -140,7 +140,7 @@ cheap_bb_rtx_cost_p (const_basic_block bb,
: REG_BR_PROB_BASE;
/* Set scale to REG_BR_PROB_BASE to void the identical scaling
- applied to insn_rtx_cost when optimizing for size. Only do
+ applied to insn_cost when optimizing for size. Only do
this after combine because if-conversion might interfere with
passes before combine.
@@ -163,7 +163,7 @@ cheap_bb_rtx_cost_p (const_basic_block bb,
{
if (NONJUMP_INSN_P (insn))
{
- int cost = insn_rtx_cost (PATTERN (insn), speed) * REG_BR_PROB_BASE;
+ int cost = insn_cost (insn, speed) * REG_BR_PROB_BASE;
if (cost == 0)
return false;
@@ -3021,7 +3021,7 @@ bb_valid_for_noce_process_p (basic_block test_bb, rtx cond,
if (first_insn == last_insn)
{
*simple_p = noce_operand_ok (SET_DEST (first_set));
- *cost += insn_rtx_cost (first_set, speed_p);
+ *cost += pattern_cost (first_set, speed_p);
return *simple_p;
}
@@ -3037,7 +3037,7 @@ bb_valid_for_noce_process_p (basic_block test_bb, rtx cond,
/* The regs that are live out of test_bb. */
bitmap test_bb_live_out = df_get_live_out (test_bb);
- int potential_cost = insn_rtx_cost (last_set, speed_p);
+ int potential_cost = pattern_cost (last_set, speed_p);
rtx_insn *insn;
FOR_BB_INSNS (test_bb, insn)
{
@@ -3057,7 +3057,7 @@ bb_valid_for_noce_process_p (basic_block test_bb, rtx cond,
|| reg_overlap_mentioned_p (SET_DEST (sset), cond))
goto free_bitmap_and_fail;
- potential_cost += insn_rtx_cost (sset, speed_p);
+ potential_cost += pattern_cost (sset, speed_p);
bitmap_set_bit (test_bb_temps, REGNO (SET_DEST (sset)));
}
}
@@ -5283,8 +5283,6 @@ dead_or_predicable (basic_block test_bb, basic_block merge_bb,
redirect_edge_succ (BRANCH_EDGE (test_bb), new_dest);
if (reversep)
{
- std::swap (BRANCH_EDGE (test_bb)->count,
- FALLTHRU_EDGE (test_bb)->count);
std::swap (BRANCH_EDGE (test_bb)->probability,
FALLTHRU_EDGE (test_bb)->probability);
update_br_prob_note (test_bb);
diff --git a/gcc/inchash.h b/gcc/inchash.h
index 6af1dad..73930c2 100644
--- a/gcc/inchash.h
+++ b/gcc/inchash.h
@@ -58,11 +58,20 @@ class hash
}
/* Add HOST_WIDE_INT value V. */
- void add_wide_int (HOST_WIDE_INT v)
+ void add_hwi (HOST_WIDE_INT v)
{
val = iterative_hash_host_wide_int (v, val);
}
+ /* Add wide_int-based value V. */
+ template<typename T>
+ void add_wide_int (const generic_wide_int<T> &x)
+ {
+ add_int (x.get_len ());
+ for (unsigned i = 0; i < x.get_len (); i++)
+ add_hwi (x.elt (i));
+ }
+
/* Hash in pointer PTR. */
void add_ptr (const void *ptr)
{
diff --git a/gcc/incpath.c b/gcc/incpath.c
index 47942e2..a2ee69f 100644
--- a/gcc/incpath.c
+++ b/gcc/incpath.c
@@ -46,7 +46,7 @@
static const char dir_separator_str[] = { DIR_SEPARATOR, 0 };
-static void add_env_var_paths (const char *, int);
+static void add_env_var_paths (const char *, incpath_kind);
static void add_standard_paths (const char *, const char *, const char *, int);
static void free_path (struct cpp_dir *, int);
static void merge_include_chains (const char *, cpp_reader *, int);
@@ -56,8 +56,9 @@ static struct cpp_dir *remove_duplicates (cpp_reader *, struct cpp_dir *,
struct cpp_dir *, int);
/* Include chains heads and tails. */
-static struct cpp_dir *heads[4];
-static struct cpp_dir *tails[4];
+static struct cpp_dir *heads[INC_MAX];
+static struct cpp_dir *tails[INC_MAX];
+
static bool quote_ignores_source_dir;
enum { REASON_QUIET = 0, REASON_NOENT, REASON_DUP, REASON_DUP_SYS };
@@ -92,7 +93,7 @@ free_path (struct cpp_dir *path, int reason)
/* Read ENV_VAR for a PATH_SEPARATOR-separated list of file names; and
append all the names to the search path CHAIN. */
static void
-add_env_var_paths (const char *env_var, int chain)
+add_env_var_paths (const char *env_var, incpath_kind chain)
{
char *p, *q, *path;
@@ -116,7 +117,7 @@ add_env_var_paths (const char *env_var, int chain)
path[q - p] = '\0';
}
- add_path (path, chain, chain == SYSTEM, false);
+ add_path (path, chain, chain == INC_SYSTEM, false);
}
}
@@ -159,7 +160,7 @@ add_standard_paths (const char *sysroot, const char *iprefix,
str = reconcat (str, str, dir_separator_str,
imultiarch, NULL);
}
- add_path (str, SYSTEM, p->cxx_aware, false);
+ add_path (str, INC_SYSTEM, p->cxx_aware, false);
}
}
}
@@ -225,7 +226,7 @@ add_standard_paths (const char *sysroot, const char *iprefix,
str = reconcat (str, str, dir_separator_str, imultiarch, NULL);
}
- add_path (str, SYSTEM, p->cxx_aware, false);
+ add_path (str, INC_SYSTEM, p->cxx_aware, false);
}
}
}
@@ -349,29 +350,32 @@ merge_include_chains (const char *sysroot, cpp_reader *pfile, int verbose)
/* Add the sysroot to user-supplied paths starting with "=". */
if (sysroot)
{
- add_sysroot_to_chain (sysroot, QUOTE);
- add_sysroot_to_chain (sysroot, BRACKET);
- add_sysroot_to_chain (sysroot, SYSTEM);
- add_sysroot_to_chain (sysroot, AFTER);
+ add_sysroot_to_chain (sysroot, INC_QUOTE);
+ add_sysroot_to_chain (sysroot, INC_BRACKET);
+ add_sysroot_to_chain (sysroot, INC_SYSTEM);
+ add_sysroot_to_chain (sysroot, INC_AFTER);
}
/* Join the SYSTEM and AFTER chains. Remove duplicates in the
resulting SYSTEM chain. */
- if (heads[SYSTEM])
- tails[SYSTEM]->next = heads[AFTER];
+ if (heads[INC_SYSTEM])
+ tails[INC_SYSTEM]->next = heads[INC_AFTER];
else
- heads[SYSTEM] = heads[AFTER];
- heads[SYSTEM] = remove_duplicates (pfile, heads[SYSTEM], 0, 0, verbose);
+ heads[INC_SYSTEM] = heads[INC_AFTER];
+ heads[INC_SYSTEM]
+ = remove_duplicates (pfile, heads[INC_SYSTEM], 0, 0, verbose);
/* Remove duplicates from BRACKET that are in itself or SYSTEM, and
join it to SYSTEM. */
- heads[BRACKET] = remove_duplicates (pfile, heads[BRACKET], heads[SYSTEM],
- heads[SYSTEM], verbose);
+ heads[INC_BRACKET]
+ = remove_duplicates (pfile, heads[INC_BRACKET], heads[INC_SYSTEM],
+ heads[INC_SYSTEM], verbose);
/* Remove duplicates from QUOTE that are in itself or SYSTEM, and
join it to BRACKET. */
- heads[QUOTE] = remove_duplicates (pfile, heads[QUOTE], heads[SYSTEM],
- heads[BRACKET], verbose);
+ heads[INC_QUOTE]
+ = remove_duplicates (pfile, heads[INC_QUOTE], heads[INC_SYSTEM],
+ heads[INC_BRACKET], verbose);
/* If verbose, print the list of dirs to search. */
if (verbose)
@@ -379,9 +383,9 @@ merge_include_chains (const char *sysroot, cpp_reader *pfile, int verbose)
struct cpp_dir *p;
fprintf (stderr, _("#include \"...\" search starts here:\n"));
- for (p = heads[QUOTE];; p = p->next)
+ for (p = heads[INC_QUOTE];; p = p->next)
{
- if (p == heads[BRACKET])
+ if (p == heads[INC_BRACKET])
fprintf (stderr, _("#include <...> search starts here:\n"));
if (!p)
break;
@@ -398,14 +402,14 @@ merge_include_chains (const char *sysroot, cpp_reader *pfile, int verbose)
void
split_quote_chain (void)
{
- if (heads[QUOTE])
- free_path (heads[QUOTE], REASON_QUIET);
- if (tails[QUOTE])
- free_path (tails[QUOTE], REASON_QUIET);
- heads[QUOTE] = heads[BRACKET];
- tails[QUOTE] = tails[BRACKET];
- heads[BRACKET] = NULL;
- tails[BRACKET] = NULL;
+ if (heads[INC_QUOTE])
+ free_path (heads[INC_QUOTE], REASON_QUIET);
+ if (tails[INC_QUOTE])
+ free_path (tails[INC_QUOTE], REASON_QUIET);
+ heads[INC_QUOTE] = heads[INC_BRACKET];
+ tails[INC_QUOTE] = tails[INC_BRACKET];
+ heads[INC_BRACKET] = NULL;
+ tails[INC_BRACKET] = NULL;
/* This is NOT redundant. */
quote_ignores_source_dir = true;
}
@@ -413,7 +417,7 @@ split_quote_chain (void)
/* Add P to the chain specified by CHAIN. */
void
-add_cpp_dir_path (cpp_dir *p, int chain)
+add_cpp_dir_path (cpp_dir *p, incpath_kind chain)
{
if (tails[chain])
tails[chain]->next = p;
@@ -425,7 +429,7 @@ add_cpp_dir_path (cpp_dir *p, int chain)
/* Add PATH to the include chain CHAIN. PATH must be malloc-ed and
NUL-terminated. */
void
-add_path (char *path, int chain, int cxx_aware, bool user_supplied_p)
+add_path (char *path, incpath_kind chain, int cxx_aware, bool user_supplied_p)
{
cpp_dir *p;
@@ -450,7 +454,7 @@ add_path (char *path, int chain, int cxx_aware, bool user_supplied_p)
#ifndef INO_T_EQ
p->canonical_name = lrealpath (path);
#endif
- if (chain == SYSTEM || chain == AFTER)
+ if (chain == INC_SYSTEM || chain == INC_AFTER)
p->sysp = 1 + !cxx_aware;
else
p->sysp = 0;
@@ -480,8 +484,8 @@ register_include_chains (cpp_reader *pfile, const char *sysroot,
/* CPATH and language-dependent environment variables may add to the
include chain. */
- add_env_var_paths ("CPATH", BRACKET);
- add_env_var_paths (lang_env_vars[idx], SYSTEM);
+ add_env_var_paths ("CPATH", INC_BRACKET);
+ add_env_var_paths (lang_env_vars[idx], INC_SYSTEM);
target_c_incpath.extra_pre_includes (sysroot, iprefix, stdinc);
@@ -493,14 +497,14 @@ register_include_chains (cpp_reader *pfile, const char *sysroot,
merge_include_chains (sysroot, pfile, verbose);
- cpp_set_include_chains (pfile, heads[QUOTE], heads[BRACKET],
+ cpp_set_include_chains (pfile, heads[INC_QUOTE], heads[INC_BRACKET],
quote_ignores_source_dir);
}
/* Return the current chain of cpp dirs. */
struct cpp_dir *
-get_added_cpp_dirs (int chain)
+get_added_cpp_dirs (incpath_kind chain)
{
return heads[chain];
}
diff --git a/gcc/incpath.h b/gcc/incpath.h
index 39a29cd..32c3dce 100644
--- a/gcc/incpath.h
+++ b/gcc/incpath.h
@@ -18,13 +18,22 @@
#ifndef GCC_INCPATH_H
#define GCC_INCPATH_H
+/* Various fragments of include path. */
+enum incpath_kind {
+ INC_QUOTE = 0, /* include "foo" */
+ INC_BRACKET, /* include <foo> */
+ INC_SYSTEM, /* sysinclude */
+ INC_AFTER, /* post-sysinclude. */
+ INC_MAX
+};
+
extern void split_quote_chain (void);
-extern void add_path (char *, int, int, bool);
+extern void add_path (char *, incpath_kind, int, bool);
extern void register_include_chains (cpp_reader *, const char *,
const char *, const char *,
int, int, int);
-extern void add_cpp_dir_path (struct cpp_dir *, int);
-extern struct cpp_dir *get_added_cpp_dirs (int);
+extern void add_cpp_dir_path (struct cpp_dir *, incpath_kind);
+extern struct cpp_dir *get_added_cpp_dirs (incpath_kind);
struct target_c_incpath_s {
/* Do extra includes processing. STDINC is false iff -nostdinc was given. */
@@ -34,6 +43,4 @@ struct target_c_incpath_s {
extern struct target_c_incpath_s target_c_incpath;
-enum { QUOTE = 0, BRACKET, SYSTEM, AFTER };
-
#endif /* GCC_INCPATH_H */
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 051f787..94873c2 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -485,7 +485,7 @@ get_min_precision (tree arg, signop sign)
p = wi::min_precision (w, sign);
}
else
- p = wi::min_precision (arg, sign);
+ p = wi::min_precision (wi::to_wide (arg), sign);
return MIN (p, prec);
}
while (CONVERT_EXPR_P (arg)
@@ -1770,8 +1770,8 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
}
/* At this point hipart{0,1} are both in [-1, 0]. If they are
- the same, overflow happened if res is negative, if they are
- different, overflow happened if res is positive. */
+ the same, overflow happened if res is non-positive, if they
+ are different, overflow happened if res is positive. */
if (op0_sign != 1 && op1_sign != 1 && op0_sign != op1_sign)
emit_jump (hipart_different);
else if (op0_sign == 1 || op1_sign == 1)
@@ -1779,7 +1779,7 @@ expand_mul_overflow (location_t loc, tree lhs, tree arg0, tree arg1,
NULL_RTX, NULL, hipart_different,
profile_probability::even ());
- do_compare_rtx_and_jump (res, const0_rtx, LT, false, mode,
+ do_compare_rtx_and_jump (res, const0_rtx, LE, false, mode,
NULL_RTX, NULL, do_error,
profile_probability::very_unlikely ());
emit_jump (done_label);
@@ -2606,7 +2606,15 @@ expand_direct_optab_fn (internal_fn fn, gcall *stmt, direct_optab optab,
tree lhs = gimple_call_lhs (stmt);
tree lhs_type = TREE_TYPE (lhs);
rtx lhs_rtx = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
- create_output_operand (&ops[0], lhs_rtx, insn_data[icode].operand[0].mode);
+
+ /* Do not assign directly to a promoted subreg, since there is no
+ guarantee that the instruction will leave the upper bits of the
+ register in the state required by SUBREG_PROMOTED_SIGN. */
+ rtx dest = lhs_rtx;
+ if (GET_CODE (dest) == SUBREG && SUBREG_PROMOTED_VAR_P (dest))
+ dest = NULL_RTX;
+
+ create_output_operand (&ops[0], dest, insn_data[icode].operand[0].mode);
for (unsigned int i = 0; i < nargs; ++i)
{
diff --git a/gcc/ipa-cp.c b/gcc/ipa-cp.c
index 6b3d8d7..d23c1d8 100644
--- a/gcc/ipa-cp.c
+++ b/gcc/ipa-cp.c
@@ -4971,8 +4971,8 @@ ipcp_store_vr_results (void)
{
vr.known = true;
vr.type = plats->m_value_range.m_vr.type;
- vr.min = plats->m_value_range.m_vr.min;
- vr.max = plats->m_value_range.m_vr.max;
+ vr.min = wi::to_wide (plats->m_value_range.m_vr.min);
+ vr.max = wi::to_wide (plats->m_value_range.m_vr.max);
}
else
{
diff --git a/gcc/ipa-devirt.c b/gcc/ipa-devirt.c
index f0aecfb..f03c7f0 100644
--- a/gcc/ipa-devirt.c
+++ b/gcc/ipa-devirt.c
@@ -373,7 +373,7 @@ hash_odr_vtable (const_tree t)
v = TREE_OPERAND (TREE_OPERAND (v, 0), 0);
}
- hstate.add_wide_int (IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (v)));
+ hstate.add_hwi (IDENTIFIER_HASH_VALUE (DECL_ASSEMBLER_NAME (v)));
return hstate.end ();
}
@@ -2625,14 +2625,14 @@ polymorphic_call_target_hasher::hash (const polymorphic_call_target_d *odr_query
{
inchash::hash hstate (odr_query->otr_token);
- hstate.add_wide_int (odr_query->type->id);
+ hstate.add_hwi (odr_query->type->id);
hstate.merge_hash (TYPE_UID (odr_query->context.outer_type));
- hstate.add_wide_int (odr_query->context.offset);
+ hstate.add_hwi (odr_query->context.offset);
if (odr_query->context.speculative_outer_type)
{
hstate.merge_hash (TYPE_UID (odr_query->context.speculative_outer_type));
- hstate.add_wide_int (odr_query->context.speculative_offset);
+ hstate.add_hwi (odr_query->context.speculative_offset);
}
hstate.add_flag (odr_query->speculative);
hstate.add_flag (odr_query->context.maybe_in_construction);
diff --git a/gcc/ipa-icf.c b/gcc/ipa-icf.c
index 4d152ce..3f6f432 100644
--- a/gcc/ipa-icf.c
+++ b/gcc/ipa-icf.c
@@ -286,11 +286,11 @@ sem_function::get_hash (void)
/* Add common features of declaration itself. */
if (DECL_FUNCTION_SPECIFIC_TARGET (decl))
- hstate.add_wide_int
+ hstate.add_hwi
(cl_target_option_hash
(TREE_TARGET_OPTION (DECL_FUNCTION_SPECIFIC_TARGET (decl))));
if (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))
- hstate.add_wide_int
+ hstate.add_hwi
(cl_optimization_hash
(TREE_OPTIMIZATION (DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl))));
hstate.add_flag (DECL_CXX_CONSTRUCTOR_P (decl));
@@ -1422,6 +1422,7 @@ sem_function::init (void)
}
}
+ hstate.commit_flag ();
gcode_hash = hstate.end ();
bb_sizes.safe_push (nondbg_stmt_count);
@@ -1437,8 +1438,8 @@ sem_function::init (void)
{
cfg_checksum = 0;
inchash::hash hstate;
- hstate.add_wide_int (cnode->thunk.fixed_offset);
- hstate.add_wide_int (cnode->thunk.virtual_value);
+ hstate.add_hwi (cnode->thunk.fixed_offset);
+ hstate.add_hwi (cnode->thunk.virtual_value);
hstate.add_flag (cnode->thunk.this_adjusting);
hstate.add_flag (cnode->thunk.virtual_offset_p);
hstate.add_flag (cnode->thunk.add_pointer_bounds_args);
@@ -1485,7 +1486,7 @@ sem_item::add_expr (const_tree exp, inchash::hash &hstate)
unsigned HOST_WIDE_INT idx;
tree value;
- hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
+ hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
FOR_EACH_CONSTRUCTOR_VALUE (CONSTRUCTOR_ELTS (exp), idx, value)
if (value)
@@ -1500,7 +1501,7 @@ sem_item::add_expr (const_tree exp, inchash::hash &hstate)
case VAR_DECL:
case CONST_DECL:
case PARM_DECL:
- hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
+ hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
break;
case MEM_REF:
case POINTER_PLUS_EXPR:
@@ -1518,7 +1519,7 @@ sem_item::add_expr (const_tree exp, inchash::hash &hstate)
}
break;
CASE_CONVERT:
- hstate.add_wide_int (int_size_in_bytes (TREE_TYPE (exp)));
+ hstate.add_hwi (int_size_in_bytes (TREE_TYPE (exp)));
return add_expr (TREE_OPERAND (exp, 0), hstate);
default:
break;
@@ -1589,11 +1590,11 @@ sem_item::add_type (const_tree type, inchash::hash &hstate)
hstate2.add_int (nf);
hash = hstate2.end ();
- hstate.add_wide_int (hash);
+ hstate.add_hwi (hash);
optimizer->m_type_hash_cache.put (type, hash);
}
else
- hstate.add_wide_int (*val);
+ hstate.add_hwi (*val);
}
}
@@ -1644,6 +1645,11 @@ sem_function::hash_stmt (gimple *stmt, inchash::hash &hstate)
if (gimple_op (stmt, i))
add_type (TREE_TYPE (gimple_op (stmt, i)), hstate);
}
+ /* Consider nocf_check attribute in hash as it affects code
+ generation. */
+ if (code == GIMPLE_CALL
+ && flag_cf_protection & CF_BRANCH)
+ hstate.add_flag (gimple_call_nocf_check_p (as_a <gcall *> (stmt)));
default:
break;
}
@@ -2108,7 +2114,7 @@ sem_variable::get_hash (void)
hstate.add_int (456346417);
if (DECL_SIZE (decl) && tree_fits_shwi_p (DECL_SIZE (decl)))
- hstate.add_wide_int (tree_to_shwi (DECL_SIZE (decl)));
+ hstate.add_hwi (tree_to_shwi (DECL_SIZE (decl)));
add_expr (ctor, hstate);
set_hash (hstate.end ());
@@ -2720,7 +2726,7 @@ sem_item_optimizer::update_hash_by_addr_refs ()
if (TYPE_NAME (class_type)
&& DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (class_type)))
- hstate.add_wide_int
+ hstate.add_hwi
(IDENTIFIER_HASH_VALUE
(DECL_ASSEMBLER_NAME (TYPE_NAME (class_type))));
diff --git a/gcc/ipa-inline-transform.c b/gcc/ipa-inline-transform.c
index dc224f7..1e7fafa 100644
--- a/gcc/ipa-inline-transform.c
+++ b/gcc/ipa-inline-transform.c
@@ -692,14 +692,7 @@ inline_transform (struct cgraph_node *node)
basic_block bb;
FOR_ALL_BB_FN (bb, cfun)
- {
- bb->count = bb->count.apply_scale (num, den);
-
- edge e;
- edge_iterator ei;
- FOR_EACH_EDGE (e, ei, bb->succs)
- e->count = e->count.apply_scale (num, den);
- }
+ bb->count = bb->count.apply_scale (num, den);
ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = node->count;
}
todo = optimize_inline_calls (current_function_decl);
diff --git a/gcc/ipa-polymorphic-call.c b/gcc/ipa-polymorphic-call.c
index 9ac5153..1c5aca4 100644
--- a/gcc/ipa-polymorphic-call.c
+++ b/gcc/ipa-polymorphic-call.c
@@ -967,8 +967,9 @@ ipa_polymorphic_call_context::ipa_polymorphic_call_context (tree fndecl,
else if (TREE_CODE (base_pointer) == POINTER_PLUS_EXPR
&& TREE_CODE (TREE_OPERAND (base_pointer, 1)) == INTEGER_CST)
{
- offset_int o = offset_int::from (TREE_OPERAND (base_pointer, 1),
- SIGNED);
+ offset_int o
+ = offset_int::from (wi::to_wide (TREE_OPERAND (base_pointer, 1)),
+ SIGNED);
o *= BITS_PER_UNIT;
o += offset;
if (!wi::fits_shwi_p (o))
diff --git a/gcc/ipa-prop.c b/gcc/ipa-prop.c
index 51f6221..a687f7c 100644
--- a/gcc/ipa-prop.c
+++ b/gcc/ipa-prop.c
@@ -397,9 +397,9 @@ ipa_print_node_jump_functions_for_edge (FILE *f, struct cgraph_edge *cs)
fprintf (f, " VR ");
fprintf (f, "%s[",
(jump_func->m_vr->type == VR_ANTI_RANGE) ? "~" : "");
- print_decs (jump_func->m_vr->min, f);
+ print_decs (wi::to_wide (jump_func->m_vr->min), f);
fprintf (f, ", ");
- print_decs (jump_func->m_vr->max, f);
+ print_decs (wi::to_wide (jump_func->m_vr->max), f);
fprintf (f, "]\n");
}
else
@@ -1931,9 +1931,9 @@ ipa_compute_jump_functions_for_edge (struct ipa_func_body_info *fbi,
unsigned align;
get_pointer_alignment_1 (arg, &align, &bitpos);
- widest_int mask
- = wi::mask<widest_int>(TYPE_PRECISION (TREE_TYPE (arg)), false)
- .and_not (align / BITS_PER_UNIT - 1);
+ widest_int mask = wi::bit_and_not
+ (wi::mask<widest_int> (TYPE_PRECISION (TREE_TYPE (arg)), false),
+ align / BITS_PER_UNIT - 1);
widest_int value = bitpos / BITS_PER_UNIT;
ipa_set_jfunc_bits (jfunc, value, mask);
}
@@ -4373,7 +4373,8 @@ ipa_modify_call_arguments (struct cgraph_edge *cs, gcall *stmt,
if (TYPE_ALIGN (type) > align)
align = TYPE_ALIGN (type);
}
- misalign += (offset_int::from (off, SIGNED).to_short_addr ()
+ misalign += (offset_int::from (wi::to_wide (off),
+ SIGNED).to_short_addr ()
* BITS_PER_UNIT);
misalign = misalign & (align - 1);
if (misalign != 0)
diff --git a/gcc/ipa-pure-const.c b/gcc/ipa-pure-const.c
index dac8f0d..3c06e2d 100644
--- a/gcc/ipa-pure-const.c
+++ b/gcc/ipa-pure-const.c
@@ -156,7 +156,8 @@ private:
static bool
function_always_visible_to_compiler_p (tree decl)
{
- return (!TREE_PUBLIC (decl) || DECL_DECLARED_INLINE_P (decl));
+ return (!TREE_PUBLIC (decl) || DECL_DECLARED_INLINE_P (decl)
+ || DECL_COMDAT (decl));
}
/* Emit suggestion about attribute ATTRIB_NAME for DECL. KNOWN_FINITE
@@ -232,6 +233,21 @@ warn_function_noreturn (tree decl)
true, warned_about, "noreturn");
}
+void
+warn_function_cold (tree decl)
+{
+ tree original_decl = decl;
+
+ cgraph_node *node = cgraph_node::get (decl);
+ if (node->instrumentation_clone)
+ decl = node->instrumented_version->decl;
+
+ static hash_set<tree> *warned_about;
+ warned_about
+ = suggest_attribute (OPT_Wsuggest_attribute_cold, original_decl,
+ true, warned_about, "cold");
+}
+
/* Return true if we have a function state for NODE. */
static inline bool
@@ -502,8 +518,7 @@ special_builtin_state (enum pure_const_state_e *state, bool *looping,
{
case BUILT_IN_RETURN:
case BUILT_IN_UNREACHABLE:
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
case BUILT_IN_STACK_SAVE:
case BUILT_IN_STACK_RESTORE:
case BUILT_IN_EH_POINTER:
@@ -1788,6 +1803,7 @@ pass_local_pure_const::execute (function *fun)
node = cgraph_node::get (current_function_decl);
skip = skip_function_for_local_pure_const (node);
+
if (!warn_suggest_attribute_const
&& !warn_suggest_attribute_pure
&& skip)
diff --git a/gcc/ipa-split.c b/gcc/ipa-split.c
index e3759d6..f2d1478 100644
--- a/gcc/ipa-split.c
+++ b/gcc/ipa-split.c
@@ -1285,7 +1285,6 @@ split_function (basic_block return_bb, struct split_point *split_point,
FOR_EACH_EDGE (e, ei, return_bb->preds)
if (bitmap_bit_p (split_point->split_bbs, e->src->index))
{
- new_return_bb->count += e->count;
new_return_bb->frequency += EDGE_FREQUENCY (e);
redirect_edge_and_branch (e, new_return_bb);
redirected = true;
diff --git a/gcc/ipa-utils.c b/gcc/ipa-utils.c
index 708710d..a27e406 100644
--- a/gcc/ipa-utils.c
+++ b/gcc/ipa-utils.c
@@ -524,20 +524,28 @@ ipa_merge_profiles (struct cgraph_node *dst,
unsigned int i;
dstbb = BASIC_BLOCK_FOR_FN (dstcfun, srcbb->index);
- if (dstbb->count.initialized_p ())
- dstbb->count += srcbb->count;
- else
- dstbb->count = srcbb->count;
- for (i = 0; i < EDGE_COUNT (srcbb->succs); i++)
+ if (!dstbb->count.initialized_p ())
{
- edge srce = EDGE_SUCC (srcbb, i);
- edge dste = EDGE_SUCC (dstbb, i);
- if (dstbb->count.initialized_p ())
- dste->count += srce->count;
- else
- dste->count = srce->count;
- if (dstbb->count > 0 && dste->count.initialized_p ())
- dste->probability = dste->count.probability_in (dstbb->count);
+ dstbb->count = srcbb->count;
+ for (i = 0; i < EDGE_COUNT (srcbb->succs); i++)
+ {
+ edge srce = EDGE_SUCC (srcbb, i);
+ edge dste = EDGE_SUCC (dstbb, i);
+ if (srce->probability.initialized_p ())
+ dste->probability = srce->probability;
+ }
+ }
+ else if (srcbb->count.initialized_p ())
+ {
+ for (i = 0; i < EDGE_COUNT (srcbb->succs); i++)
+ {
+ edge srce = EDGE_SUCC (srcbb, i);
+ edge dste = EDGE_SUCC (dstbb, i);
+ dste->probability =
+ dste->probability * dstbb->count.probability_in (dstbb->count + srcbb->count)
+ + srce->probability * srcbb->count.probability_in (dstbb->count + srcbb->count);
+ }
+ dstbb->count += srcbb->count;
}
}
push_cfun (dstcfun);
diff --git a/gcc/ipa-utils.h b/gcc/ipa-utils.h
index f061c84c..2affbd6 100644
--- a/gcc/ipa-utils.h
+++ b/gcc/ipa-utils.h
@@ -217,11 +217,11 @@ type_in_anonymous_namespace_p (const_tree t)
{
/* C++ FE uses magic <anon> as assembler names of anonymous types.
verify that this match with type_in_anonymous_namespace_p. */
- gcc_checking_assert (!in_lto_p || !DECL_ASSEMBLER_NAME_SET_P (t)
- || !strcmp
- ("<anon>",
- IDENTIFIER_POINTER
- (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))));
+ gcc_checking_assert (!in_lto_p
+ || !DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t))
+ || !strcmp ("<anon>",
+ IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))));
return true;
}
return false;
@@ -245,14 +245,13 @@ odr_type_p (const_tree t)
if (type_in_anonymous_namespace_p (t))
return true;
- if (TYPE_NAME (t) && TREE_CODE (TYPE_NAME (t)) == TYPE_DECL
- && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))
+ if (TYPE_NAME (t) && DECL_ASSEMBLER_NAME_SET_P (TYPE_NAME (t)))
{
/* C++ FE uses magic <anon> as assembler names of anonymous types.
verify that this match with type_in_anonymous_namespace_p. */
gcc_checking_assert (strcmp ("<anon>",
- IDENTIFIER_POINTER
- (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))));
+ IDENTIFIER_POINTER
+ (DECL_ASSEMBLER_NAME (TYPE_NAME (t)))));
return true;
}
return false;
diff --git a/gcc/ira-color.c b/gcc/ira-color.c
index 22fdb88..31a4a80 100644
--- a/gcc/ira-color.c
+++ b/gcc/ira-color.c
@@ -3005,14 +3005,13 @@ allocno_priority_compare_func (const void *v1p, const void *v2p)
{
ira_allocno_t a1 = *(const ira_allocno_t *) v1p;
ira_allocno_t a2 = *(const ira_allocno_t *) v2p;
- int pri1, pri2;
+ int pri1, pri2, diff;
/* Assign hard reg to static chain pointer pseudo first when
non-local goto is used. */
- if (non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a1)))
- return 1;
- else if (non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a2)))
- return -1;
+ if ((diff = (non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a2))
+ - non_spilled_static_chain_regno_p (ALLOCNO_REGNO (a1)))) != 0)
+ return diff;
pri1 = allocno_priorities[ALLOCNO_NUM (a1)];
pri2 = allocno_priorities[ALLOCNO_NUM (a2)];
if (pri2 != pri1)
diff --git a/gcc/ira-costs.c b/gcc/ira-costs.c
index 714bdbd..0bd0778 100644
--- a/gcc/ira-costs.c
+++ b/gcc/ira-costs.c
@@ -1471,7 +1471,10 @@ scan_one_insn (rtx_insn *insn)
&& targetm.legitimate_constant_p (GET_MODE (SET_DEST (set)),
XEXP (note, 0))
&& REG_N_SETS (REGNO (SET_DEST (set))) == 1))
- && general_operand (SET_SRC (set), GET_MODE (SET_SRC (set))))
+ && general_operand (SET_SRC (set), GET_MODE (SET_SRC (set)))
+ /* LRA does not use equiv with a symbol for PIC code. */
+ && (! ira_use_lra_p || ! pic_offset_table_rtx
+ || ! contains_symbol_ref_p (XEXP (note, 0))))
{
enum reg_class cl = GENERAL_REGS;
rtx reg = SET_DEST (set);
diff --git a/gcc/ira.c b/gcc/ira.c
index 046ce3b..8c93d3d 100644
--- a/gcc/ira.c
+++ b/gcc/ira.c
@@ -4400,6 +4400,12 @@ rtx_moveable_p (rtx *loc, enum op_type type)
for a reason. */
return false;
+ case ASM_OPERANDS:
+ /* The same is true for volatile asm: it has unknown side effects, it
+ cannot be moved at will. */
+ if (MEM_VOLATILE_P (x))
+ return false;
+
default:
break;
}
diff --git a/gcc/jit/ChangeLog b/gcc/jit/ChangeLog
index 63d8b06..24df990 100644
--- a/gcc/jit/ChangeLog
+++ b/gcc/jit/ChangeLog
@@ -1,3 +1,110 @@
+2017-10-04 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/cp/topics/expressions.rst (Vector expressions): New
+ section.
+ * docs/topics/compatibility.rst (LIBGCCJIT_ABI_10): New ABI tag.
+ * docs/topics/expressions.rst (Vector expressions): New section.
+ * docs/topics/types.rst (gcc_jit_type_get_vector): Add link to
+ gcc_jit_context_new_rvalue_from_vector.
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+ * jit-common.h (gcc::jit:recording::vector_type): New forward
+ decl.
+ * jit-playback.c
+ (gcc::jit::playback::context::new_rvalue_from_vector): New method.
+ * jit-playback.h
+ (gcc::jit::playback::context::new_rvalue_from_vector): New method.
+ * jit-recording.c: In namespace gcc::jit::
+ (class comma_separated_string): New class.
+ (comma_separated_string::comma_separated_string): New ctor,
+ adapted from recording::call::make_debug_string.
+ (comma_separated_string::~comma_separated_string): New dtor.
+ In namespace gcc::jit::recording::
+ (context::new_rvalue_from_vector): New method.
+ (type::get_vector): Update for renaming of memento_of_get_vector.
+ (class memento_of_get_vector): Rename to...
+ (class vector_type): ..this.
+ (memento_of_new_rvalue_from_vector::memento_of_new_rvalue_from_vector):
+ New ctor.
+ (memento_of_new_rvalue_from_vector::replay_into): New method.
+ (memento_of_new_rvalue_from_vector::visit_children): New method.
+ (memento_of_new_rvalue_from_vector::make_debug_string): New
+ method.
+ (memento_of_new_rvalue_from_vector::write_reproducer): New method.
+ (call::make_debug_string): Split out arg-printing code into ctor
+ for comma_separated_string.
+ * jit-recording.h: In namespace gcc::jit::recording::
+ (context::new_rvalue_from_vector): New method.
+ (type::dyn_cast_vector_type): New virtual function.
+ (class memento_of_get_vector): Rename to...
+ (class vector_type): ...this.
+ (vector_type::unqualified): Remove this vfunc override in favor
+ of...
+ (vector_type::get_element_type): ...this new method.
+ (vector_type::get_num_units): New method.
+ (vector_type::dyn_cast_vector_type): New vfunc override.
+ (class memento_of_new_rvalue_from_vector): New class.
+ * libgccjit++.h (gccjit::context::new_rvalue): Add overload for
+ vector of rvalue.
+ * libgccjit.c (gcc_jit_context_new_binary_op): Strip off type
+ qualifications when checking that both operands have same type.
+ (gcc_jit_context_new_rvalue_from_vector): New API entrypoint.
+ * libgccjit.h
+ (LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector): New
+ macro.
+ (gcc_jit_context_new_rvalue_from_vector): New API entrypoint.
+ * libgccjit.map (LIBGCCJIT_ABI_10): New ABI tag.
+
+2017-09-28 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/topics/expressions.rst (Function calls): Add link to
+ gcc_jit_context_new_function_ptr_type.
+ (Function pointers): Convert to cross-references to
+ function-pointers.rst, moving material there.
+ * docs/topics/function-pointers.rst: New page.
+ * docs/topics/index.rst: Add function-pointers.rst.
+ * docs/topics/types.rst (Function pointer types): New section.
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+
+2017-09-28 David Malcolm <dmalcolm@redhat.com>
+
+ * jit-recording.c
+ (gcc::jit::recording::function_type::is_same_type_as): New function.
+ * jit-recording.h: In namespace gcc::jit::recording::
+ (type::accepts_writes_from): Use is_same_type_as rather than pointer
+ equality.
+ (type::is_same_type_as): New virtual function.
+ (function_type::is_same_type_as): New override.
+
+2017-09-27 David Malcolm <dmalcolm@redhat.com>
+
+ * docs/cp/topics/expressions.rst (Function pointers): New section.
+ * docs/topics/compatibility.rst (LIBGCCJIT_ABI_9): New tag.
+ * docs/topics/expressions.rst (Function pointers): New section.
+ * docs/_build/texinfo/libgccjit.texi: Regenerate.
+ * jit-common.h (class gcc::jit::recording::function_pointer): New
+ forward decl.
+ * jit-playback.c (gcc::jit::playback::function::get_address): New
+ method.
+ * jit-playback.h (gcc::jit::playback::function::get_address): New
+ method decl.
+ * jit-recording.c: Within namespace gcc::jit::recording...
+ (function::function): Initialize new field "m_fn_ptr_type".
+ (function::get_address): New method.
+ (function_pointer::replay_into): New method.
+ (function_pointer::visit_children): New method.
+ (function_pointer::make_debug_string): New method.
+ (function_pointer::write_reproducer): New method.
+ * jit-recording.h: Within namespace gcc::jit::recording...
+ (function::get_address): New method.
+ (function): Add field "m_fn_ptr_type".
+ (class function_pointer): New subclass of rvalue.
+ * libgccjit++.h (gccjit::function::get_address): New method.
+ * libgccjit.c (gcc_jit_function_get_address): New function.
+ * libgccjit.h (LIBGCCJIT_HAVE_gcc_jit_function_get_address): New
+ macro.
+ (gcc_jit_function_get_address): New API entrypoint.
+ * libgccjit.map (LIBGCCJIT_ABI_9): New tag.
+
2017-09-14 David Malcolm <dmalcolm@redhat.com>
PR jit/82174
diff --git a/gcc/jit/docs/_build/texinfo/libgccjit.texi b/gcc/jit/docs/_build/texinfo/libgccjit.texi
index 7e9a7d5..344c93e 100644
--- a/gcc/jit/docs/_build/texinfo/libgccjit.texi
+++ b/gcc/jit/docs/_build/texinfo/libgccjit.texi
@@ -19,7 +19,7 @@
@copying
@quotation
-libgccjit 8.0.0 (experimental 20170809), August 09, 2017
+libgccjit 8.0.0 (experimental 20171004), October 04, 2017
David Malcolm
@@ -166,6 +166,7 @@ Topic Reference
* Types::
* Expressions::
* Creating and using functions::
+* Function pointers: Function pointers<2>.
* Source Locations::
* Compiling a context::
* ABI and API compatibility::
@@ -192,6 +193,7 @@ Types
* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
* Vector types::
* Structures and unions::
+* Function pointer types::
Expressions
@@ -202,10 +204,12 @@ Expressions
Rvalues
* Simple expressions::
+* Vector expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
+* Function pointers::
* Type-coercion::
Lvalues
@@ -243,6 +247,8 @@ ABI symbol tags
* LIBGCCJIT_ABI_6::
* LIBGCCJIT_ABI_7::
* LIBGCCJIT_ABI_8::
+* LIBGCCJIT_ABI_9::
+* LIBGCCJIT_ABI_10::
Performance
@@ -331,10 +337,12 @@ Expressions
Rvalues
* Simple expressions: Simple expressions<2>.
+* Vector expressions: Vector expressions<2>.
* Unary Operations: Unary Operations<2>.
* Binary Operations: Binary Operations<2>.
* Comparisons: Comparisons<2>.
* Function calls: Function calls<2>.
+* Function pointers: Function pointers<3>.
* Type-coercion: Type-coercion<2>.
Lvalues
@@ -4861,6 +4869,7 @@ and to a dynamic library. See the documentation of
* Types::
* Expressions::
* Creating and using functions::
+* Function pointers: Function pointers<2>.
* Source Locations::
* Compiling a context::
* ABI and API compatibility::
@@ -4887,6 +4896,7 @@ Types
* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
* Vector types::
* Structures and unions::
+* Function pointer types::
Expressions
@@ -4897,10 +4907,12 @@ Expressions
Rvalues
* Simple expressions::
+* Vector expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
+* Function pointers::
* Type-coercion::
Lvalues
@@ -4938,6 +4950,8 @@ ABI symbol tags
* LIBGCCJIT_ABI_6::
* LIBGCCJIT_ABI_7::
* LIBGCCJIT_ABI_8::
+* LIBGCCJIT_ABI_9::
+* LIBGCCJIT_ABI_10::
Performance
@@ -5799,6 +5813,7 @@ by creating structures (see below).
* Pointers@comma{} const@comma{} and volatile: Pointers const and volatile.
* Vector types::
* Structures and unions::
+* Function pointer types::
@end menu
@@ -6121,29 +6136,32 @@ for its presence using
@end example
@noindent
+
+Vector rvalues can be generated using
+@pxref{85,,gcc_jit_context_new_rvalue_from_vector()}.
@end deffn
-@node Structures and unions,,Vector types,Types
-@anchor{topics/types structures-and-unions}@anchor{85}
+@node Structures and unions,Function pointer types,Vector types,Types
+@anchor{topics/types structures-and-unions}@anchor{86}
@subsection Structures and unions
@geindex gcc_jit_struct (C type)
-@anchor{topics/types gcc_jit_struct}@anchor{86}
+@anchor{topics/types gcc_jit_struct}@anchor{87}
@deffn {C Type} gcc_jit_struct
@end deffn
A compound type analagous to a C @cite{struct}.
@geindex gcc_jit_field (C type)
-@anchor{topics/types gcc_jit_field}@anchor{87}
+@anchor{topics/types gcc_jit_field}@anchor{88}
@deffn {C Type} gcc_jit_field
@end deffn
-A field within a @pxref{86,,gcc_jit_struct}.
+A field within a @pxref{87,,gcc_jit_struct}.
-You can model C @cite{struct} types by creating @pxref{86,,gcc_jit_struct *} and
-@pxref{87,,gcc_jit_field} instances, in either order:
+You can model C @cite{struct} types by creating @pxref{87,,gcc_jit_struct *} and
+@pxref{88,,gcc_jit_field} instances, in either order:
@itemize *
@@ -6200,7 +6218,7 @@ gcc_jit_struct_set_fields (node, NULL, 2, fields);
@end itemize
@geindex gcc_jit_context_new_field (C function)
-@anchor{topics/types gcc_jit_context_new_field}@anchor{88}
+@anchor{topics/types gcc_jit_context_new_field}@anchor{89}
@deffn {C Function} gcc_jit_field * gcc_jit_context_new_field (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*type, const char@w{ }*name)
Construct a new field, with the given type and name.
@@ -6211,14 +6229,14 @@ buffer.
@end deffn
@geindex gcc_jit_field_as_object (C function)
-@anchor{topics/types gcc_jit_field_as_object}@anchor{89}
+@anchor{topics/types gcc_jit_field_as_object}@anchor{8a}
@deffn {C Function} gcc_jit_object * gcc_jit_field_as_object (gcc_jit_field@w{ }*field)
Upcast from field to object.
@end deffn
@geindex gcc_jit_context_new_struct_type (C function)
-@anchor{topics/types gcc_jit_context_new_struct_type}@anchor{8a}
+@anchor{topics/types gcc_jit_context_new_struct_type}@anchor{8b}
@deffn {C Function} gcc_jit_struct *gcc_jit_context_new_struct_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
@quotation
@@ -6232,13 +6250,13 @@ on-stack buffer.
@end deffn
@geindex gcc_jit_context_new_opaque_struct (C function)
-@anchor{topics/types gcc_jit_context_new_opaque_struct}@anchor{8b}
+@anchor{topics/types gcc_jit_context_new_opaque_struct}@anchor{8c}
@deffn {C Function} gcc_jit_struct * gcc_jit_context_new_opaque_struct (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name)
Construct a new struct type, with the given name, but without
specifying the fields. The fields can be omitted (in which case the
size of the struct is not known), or later specified using
-@pxref{8c,,gcc_jit_struct_set_fields()}.
+@pxref{8d,,gcc_jit_struct_set_fields()}.
The parameter @code{name} must be non-NULL. The call takes a copy of
the underlying string, so it is valid to pass in a pointer to an
@@ -6246,14 +6264,14 @@ on-stack buffer.
@end deffn
@geindex gcc_jit_struct_as_type (C function)
-@anchor{topics/types gcc_jit_struct_as_type}@anchor{8d}
+@anchor{topics/types gcc_jit_struct_as_type}@anchor{8e}
@deffn {C Function} gcc_jit_type * gcc_jit_struct_as_type (gcc_jit_struct@w{ }*struct_type)
Upcast from struct to type.
@end deffn
@geindex gcc_jit_struct_set_fields (C function)
-@anchor{topics/types gcc_jit_struct_set_fields}@anchor{8c}
+@anchor{topics/types gcc_jit_struct_set_fields}@anchor{8d}
@deffn {C Function} void gcc_jit_struct_set_fields (gcc_jit_struct@w{ }*struct_type, gcc_jit_location@w{ }*loc, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
Populate the fields of a formerly-opaque struct type.
@@ -6262,7 +6280,7 @@ This can only be called once on a given struct type.
@end deffn
@geindex gcc_jit_context_new_union_type (C function)
-@anchor{topics/types gcc_jit_context_new_union_type}@anchor{8e}
+@anchor{topics/types gcc_jit_context_new_union_type}@anchor{8f}
@deffn {C Function} gcc_jit_type * gcc_jit_context_new_union_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, const char@w{ }*name, int@w{ }num_fields, gcc_jit_field@w{ }**fields)
Construct a new union type, with the given name and fields.
@@ -6352,6 +6370,14 @@ create_code (gcc_jit_context *ctxt, void *user_data)
@noindent
@end deffn
+@node Function pointer types,,Structures and unions,Types
+@anchor{topics/types function-pointer-types}@anchor{90}
+@subsection Function pointer types
+
+
+Function pointer types can be created using
+@pxref{91,,gcc_jit_context_new_function_ptr_type()}.
+
@c Copyright (C) 2014-2017 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@@ -6370,7 +6396,7 @@ create_code (gcc_jit_context *ctxt, void *user_data)
@c <http://www.gnu.org/licenses/>.
@node Expressions,Creating and using functions,Types,Topic Reference
-@anchor{topics/expressions expressions}@anchor{8f}@anchor{topics/expressions doc}@anchor{90}
+@anchor{topics/expressions expressions}@anchor{92}@anchor{topics/expressions doc}@anchor{93}
@section Expressions
@@ -6382,10 +6408,12 @@ create_code (gcc_jit_context *ctxt, void *user_data)
Rvalues
* Simple expressions::
+* Vector expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
+* Function pointers::
* Type-coercion::
Lvalues
@@ -6396,7 +6424,7 @@ Lvalues
@node Rvalues,Lvalues,,Expressions
-@anchor{topics/expressions rvalues}@anchor{91}
+@anchor{topics/expressions rvalues}@anchor{94}
@subsection Rvalues
@@ -6450,7 +6478,7 @@ Every rvalue has an associated type, and the API will check to ensure
that types match up correctly (otherwise the context will emit an error).
@geindex gcc_jit_rvalue_get_type (C function)
-@anchor{topics/expressions gcc_jit_rvalue_get_type}@anchor{92}
+@anchor{topics/expressions gcc_jit_rvalue_get_type}@anchor{95}
@deffn {C Function} gcc_jit_type *gcc_jit_rvalue_get_type (gcc_jit_rvalue@w{ }*rvalue)
Get the type of this rvalue.
@@ -6465,16 +6493,18 @@ Upcast the given rvalue to be an object.
@menu
* Simple expressions::
+* Vector expressions::
* Unary Operations::
* Binary Operations::
* Comparisons::
* Function calls::
+* Function pointers::
* Type-coercion::
@end menu
-@node Simple expressions,Unary Operations,,Rvalues
-@anchor{topics/expressions simple-expressions}@anchor{93}
+@node Simple expressions,Vector expressions,,Rvalues
+@anchor{topics/expressions simple-expressions}@anchor{96}
@subsubsection Simple expressions
@@ -6487,7 +6517,7 @@ the given constant @code{int} value.
@end deffn
@geindex gcc_jit_context_new_rvalue_from_long (C function)
-@anchor{topics/expressions gcc_jit_context_new_rvalue_from_long}@anchor{94}
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_long}@anchor{97}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_long (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*numeric_type, long@w{ }value)
Given a numeric type (integer or floating point), build an rvalue for
@@ -6531,14 +6561,14 @@ the given constant @code{double} value.
@end deffn
@geindex gcc_jit_context_new_rvalue_from_ptr (C function)
-@anchor{topics/expressions gcc_jit_context_new_rvalue_from_ptr}@anchor{95}
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_ptr}@anchor{98}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_ptr (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*pointer_type, void@w{ }*value)
Given a pointer type, build an rvalue for the given address.
@end deffn
@geindex gcc_jit_context_null (C function)
-@anchor{topics/expressions gcc_jit_context_null}@anchor{96}
+@anchor{topics/expressions gcc_jit_context_null}@anchor{99}
@deffn {C Function} gcc_jit_rvalue *gcc_jit_context_null (gcc_jit_context@w{ }*ctxt, gcc_jit_type@w{ }*pointer_type)
Given a pointer type, build an rvalue for @code{NULL}. Essentially this
@@ -6552,7 +6582,7 @@ gcc_jit_context_new_rvalue_from_ptr (ctxt, pointer_type, NULL)
@end deffn
@geindex gcc_jit_context_new_string_literal (C function)
-@anchor{topics/expressions gcc_jit_context_new_string_literal}@anchor{97}
+@anchor{topics/expressions gcc_jit_context_new_string_literal}@anchor{9a}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_string_literal (gcc_jit_context@w{ }*ctxt, const char@w{ }*value)
Generate an rvalue for the given NIL-terminated string, of type
@@ -6563,20 +6593,46 @@ underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
@end deffn
-@node Unary Operations,Binary Operations,Simple expressions,Rvalues
-@anchor{topics/expressions unary-operations}@anchor{98}
+@node Vector expressions,Unary Operations,Simple expressions,Rvalues
+@anchor{topics/expressions vector-expressions}@anchor{9b}
+@subsubsection Vector expressions
+
+
+@geindex gcc_jit_context_new_rvalue_from_vector (C function)
+@anchor{topics/expressions gcc_jit_context_new_rvalue_from_vector}@anchor{85}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_rvalue_from_vector (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*vec_type, size_t@w{ }num_elements, gcc_jit_rvalue@w{ }**elements)
+
+Build a vector rvalue from an array of elements.
+
+"vec_type" should be a vector type, created using
+@pxref{83,,gcc_jit_type_get_vector()}.
+
+"num_elements" should match that of the vector type.
+
+This entrypoint was added in @pxref{9c,,LIBGCCJIT_ABI_10}; you can test for
+its presence using
+
+@example
+#ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
+@end example
+
+@noindent
+@end deffn
+
+@node Unary Operations,Binary Operations,Vector expressions,Rvalues
+@anchor{topics/expressions unary-operations}@anchor{9d}
@subsubsection Unary Operations
@geindex gcc_jit_context_new_unary_op (C function)
-@anchor{topics/expressions gcc_jit_context_new_unary_op}@anchor{99}
+@anchor{topics/expressions gcc_jit_context_new_unary_op}@anchor{9e}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_unary_op (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_unary_op@w{ }op, gcc_jit_type@w{ }*result_type, gcc_jit_rvalue@w{ }*rvalue)
Build a unary operation out of an input rvalue.
@end deffn
@geindex gcc_jit_unary_op (C type)
-@anchor{topics/expressions gcc_jit_unary_op}@anchor{9a}
+@anchor{topics/expressions gcc_jit_unary_op}@anchor{9f}
@deffn {C Type} enum gcc_jit_unary_op
@end deffn
@@ -6594,7 +6650,7 @@ C equivalent
@item
-@pxref{9b,,GCC_JIT_UNARY_OP_MINUS}
+@pxref{a0,,GCC_JIT_UNARY_OP_MINUS}
@tab
@@ -6602,7 +6658,7 @@ C equivalent
@item
-@pxref{9c,,GCC_JIT_UNARY_OP_BITWISE_NEGATE}
+@pxref{a1,,GCC_JIT_UNARY_OP_BITWISE_NEGATE}
@tab
@@ -6610,7 +6666,7 @@ C equivalent
@item
-@pxref{9d,,GCC_JIT_UNARY_OP_LOGICAL_NEGATE}
+@pxref{a2,,GCC_JIT_UNARY_OP_LOGICAL_NEGATE}
@tab
@@ -6618,7 +6674,7 @@ C equivalent
@item
-@pxref{9e,,GCC_JIT_UNARY_OP_ABS}
+@pxref{a3,,GCC_JIT_UNARY_OP_ABS}
@tab
@@ -6628,7 +6684,7 @@ C equivalent
@geindex GCC_JIT_UNARY_OP_MINUS (C macro)
-@anchor{topics/expressions GCC_JIT_UNARY_OP_MINUS}@anchor{9b}
+@anchor{topics/expressions GCC_JIT_UNARY_OP_MINUS}@anchor{a0}
@deffn {C Macro} GCC_JIT_UNARY_OP_MINUS
Negate an arithmetic value; analogous to:
@@ -6643,7 +6699,7 @@ in C.
@end deffn
@geindex GCC_JIT_UNARY_OP_BITWISE_NEGATE (C macro)
-@anchor{topics/expressions GCC_JIT_UNARY_OP_BITWISE_NEGATE}@anchor{9c}
+@anchor{topics/expressions GCC_JIT_UNARY_OP_BITWISE_NEGATE}@anchor{a1}
@deffn {C Macro} GCC_JIT_UNARY_OP_BITWISE_NEGATE
Bitwise negation of an integer value (one's complement); analogous
@@ -6659,7 +6715,7 @@ in C.
@end deffn
@geindex GCC_JIT_UNARY_OP_LOGICAL_NEGATE (C macro)
-@anchor{topics/expressions GCC_JIT_UNARY_OP_LOGICAL_NEGATE}@anchor{9d}
+@anchor{topics/expressions GCC_JIT_UNARY_OP_LOGICAL_NEGATE}@anchor{a2}
@deffn {C Macro} GCC_JIT_UNARY_OP_LOGICAL_NEGATE
Logical negation of an arithmetic or pointer value; analogous to:
@@ -6674,7 +6730,7 @@ in C.
@end deffn
@geindex GCC_JIT_UNARY_OP_ABS (C macro)
-@anchor{topics/expressions GCC_JIT_UNARY_OP_ABS}@anchor{9e}
+@anchor{topics/expressions GCC_JIT_UNARY_OP_ABS}@anchor{a3}
@deffn {C Macro} GCC_JIT_UNARY_OP_ABS
Absolute value of an arithmetic expression; analogous to:
@@ -6689,7 +6745,7 @@ in C.
@end deffn
@node Binary Operations,Comparisons,Unary Operations,Rvalues
-@anchor{topics/expressions binary-operations}@anchor{9f}
+@anchor{topics/expressions binary-operations}@anchor{a4}
@subsubsection Binary Operations
@@ -6701,7 +6757,7 @@ Build a binary operation out of two constituent rvalues.
@end deffn
@geindex gcc_jit_binary_op (C type)
-@anchor{topics/expressions gcc_jit_binary_op}@anchor{a0}
+@anchor{topics/expressions gcc_jit_binary_op}@anchor{a5}
@deffn {C Type} enum gcc_jit_binary_op
@end deffn
@@ -6719,7 +6775,7 @@ C equivalent
@item
-@pxref{a1,,GCC_JIT_BINARY_OP_PLUS}
+@pxref{a6,,GCC_JIT_BINARY_OP_PLUS}
@tab
@@ -6727,7 +6783,7 @@ C equivalent
@item
-@pxref{a2,,GCC_JIT_BINARY_OP_MINUS}
+@pxref{a7,,GCC_JIT_BINARY_OP_MINUS}
@tab
@@ -6735,7 +6791,7 @@ C equivalent
@item
-@pxref{a3,,GCC_JIT_BINARY_OP_MULT}
+@pxref{a8,,GCC_JIT_BINARY_OP_MULT}
@tab
@@ -6743,7 +6799,7 @@ C equivalent
@item
-@pxref{a4,,GCC_JIT_BINARY_OP_DIVIDE}
+@pxref{a9,,GCC_JIT_BINARY_OP_DIVIDE}
@tab
@@ -6751,7 +6807,7 @@ C equivalent
@item
-@pxref{a5,,GCC_JIT_BINARY_OP_MODULO}
+@pxref{aa,,GCC_JIT_BINARY_OP_MODULO}
@tab
@@ -6759,7 +6815,7 @@ C equivalent
@item
-@pxref{a6,,GCC_JIT_BINARY_OP_BITWISE_AND}
+@pxref{ab,,GCC_JIT_BINARY_OP_BITWISE_AND}
@tab
@@ -6767,7 +6823,7 @@ C equivalent
@item
-@pxref{a7,,GCC_JIT_BINARY_OP_BITWISE_XOR}
+@pxref{ac,,GCC_JIT_BINARY_OP_BITWISE_XOR}
@tab
@@ -6775,7 +6831,7 @@ C equivalent
@item
-@pxref{a8,,GCC_JIT_BINARY_OP_BITWISE_OR}
+@pxref{ad,,GCC_JIT_BINARY_OP_BITWISE_OR}
@tab
@@ -6783,7 +6839,7 @@ C equivalent
@item
-@pxref{a9,,GCC_JIT_BINARY_OP_LOGICAL_AND}
+@pxref{ae,,GCC_JIT_BINARY_OP_LOGICAL_AND}
@tab
@@ -6791,7 +6847,7 @@ C equivalent
@item
-@pxref{aa,,GCC_JIT_BINARY_OP_LOGICAL_OR}
+@pxref{af,,GCC_JIT_BINARY_OP_LOGICAL_OR}
@tab
@@ -6799,7 +6855,7 @@ C equivalent
@item
-@pxref{ab,,GCC_JIT_BINARY_OP_LSHIFT}
+@pxref{b0,,GCC_JIT_BINARY_OP_LSHIFT}
@tab
@@ -6807,7 +6863,7 @@ C equivalent
@item
-@pxref{ac,,GCC_JIT_BINARY_OP_RSHIFT}
+@pxref{b1,,GCC_JIT_BINARY_OP_RSHIFT}
@tab
@@ -6817,7 +6873,7 @@ C equivalent
@geindex GCC_JIT_BINARY_OP_PLUS (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_PLUS}@anchor{a1}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_PLUS}@anchor{a6}
@deffn {C Macro} GCC_JIT_BINARY_OP_PLUS
Addition of arithmetic values; analogous to:
@@ -6830,11 +6886,11 @@ Addition of arithmetic values; analogous to:
in C.
-For pointer addition, use @pxref{ad,,gcc_jit_context_new_array_access()}.
+For pointer addition, use @pxref{b2,,gcc_jit_context_new_array_access()}.
@end deffn
@geindex GCC_JIT_BINARY_OP_MINUS (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_MINUS}@anchor{a2}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_MINUS}@anchor{a7}
@deffn {C Macro} GCC_JIT_BINARY_OP_MINUS
Subtraction of arithmetic values; analogous to:
@@ -6849,7 +6905,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_MULT (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_MULT}@anchor{a3}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_MULT}@anchor{a8}
@deffn {C Macro} GCC_JIT_BINARY_OP_MULT
Multiplication of a pair of arithmetic values; analogous to:
@@ -6864,7 +6920,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_DIVIDE (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_DIVIDE}@anchor{a4}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_DIVIDE}@anchor{a9}
@deffn {C Macro} GCC_JIT_BINARY_OP_DIVIDE
Quotient of division of arithmetic values; analogous to:
@@ -6883,7 +6939,7 @@ a floating-point result type indicates floating-point division.
@end deffn
@geindex GCC_JIT_BINARY_OP_MODULO (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_MODULO}@anchor{a5}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_MODULO}@anchor{aa}
@deffn {C Macro} GCC_JIT_BINARY_OP_MODULO
Remainder of division of arithmetic values; analogous to:
@@ -6898,7 +6954,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_AND (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_AND}@anchor{a6}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_AND}@anchor{ab}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_AND
Bitwise AND; analogous to:
@@ -6913,7 +6969,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_XOR (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_XOR}@anchor{a7}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_XOR}@anchor{ac}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_XOR
Bitwise exclusive OR; analogous to:
@@ -6928,7 +6984,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_BITWISE_OR (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_OR}@anchor{a8}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_BITWISE_OR}@anchor{ad}
@deffn {C Macro} GCC_JIT_BINARY_OP_BITWISE_OR
Bitwise inclusive OR; analogous to:
@@ -6943,7 +6999,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LOGICAL_AND (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_AND}@anchor{a9}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_AND}@anchor{ae}
@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_AND
Logical AND; analogous to:
@@ -6958,7 +7014,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LOGICAL_OR (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_OR}@anchor{aa}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LOGICAL_OR}@anchor{af}
@deffn {C Macro} GCC_JIT_BINARY_OP_LOGICAL_OR
Logical OR; analogous to:
@@ -6973,7 +7029,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_LSHIFT (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_LSHIFT}@anchor{ab}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_LSHIFT}@anchor{b0}
@deffn {C Macro} GCC_JIT_BINARY_OP_LSHIFT
Left shift; analogous to:
@@ -6988,7 +7044,7 @@ in C.
@end deffn
@geindex GCC_JIT_BINARY_OP_RSHIFT (C macro)
-@anchor{topics/expressions GCC_JIT_BINARY_OP_RSHIFT}@anchor{ac}
+@anchor{topics/expressions GCC_JIT_BINARY_OP_RSHIFT}@anchor{b1}
@deffn {C Macro} GCC_JIT_BINARY_OP_RSHIFT
Right shift; analogous to:
@@ -7003,7 +7059,7 @@ in C.
@end deffn
@node Comparisons,Function calls,Binary Operations,Rvalues
-@anchor{topics/expressions comparisons}@anchor{ae}
+@anchor{topics/expressions comparisons}@anchor{b3}
@subsubsection Comparisons
@@ -7015,7 +7071,7 @@ Build a boolean rvalue out of the comparison of two other rvalues.
@end deffn
@geindex gcc_jit_comparison (C type)
-@anchor{topics/expressions gcc_jit_comparison}@anchor{af}
+@anchor{topics/expressions gcc_jit_comparison}@anchor{b4}
@deffn {C Type} enum gcc_jit_comparison
@end deffn
@@ -7080,13 +7136,13 @@ C equivalent
@end multitable
-@node Function calls,Type-coercion,Comparisons,Rvalues
-@anchor{topics/expressions function-calls}@anchor{b0}
+@node Function calls,Function pointers,Comparisons,Rvalues
+@anchor{topics/expressions function-calls}@anchor{b5}
@subsubsection Function calls
@geindex gcc_jit_context_new_call (C function)
-@anchor{topics/expressions gcc_jit_context_new_call}@anchor{b1}
+@anchor{topics/expressions gcc_jit_context_new_call}@anchor{b6}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_call (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_function@w{ }*func, int@w{ }numargs, gcc_jit_rvalue@w{ }**args)
Given a function and the given table of argument rvalues, construct a
@@ -7094,7 +7150,7 @@ call to the function, with the result as an rvalue.
@cartouche
@quotation Note
-@pxref{b1,,gcc_jit_context_new_call()} merely builds a
+@pxref{b6,,gcc_jit_context_new_call()} merely builds a
@pxref{13,,gcc_jit_rvalue} i.e. an expression that can be evaluated,
perhaps as part of a more complicated expression.
The call @emph{won't} happen unless you add a statement to a function
@@ -7102,7 +7158,7 @@ that evaluates the expression.
For example, if you want to call a function and discard the result
(or to call a function with @code{void} return type), use
-@pxref{b2,,gcc_jit_block_add_eval()}:
+@pxref{b7,,gcc_jit_block_add_eval()}:
@example
/* Add "(void)printf (arg0, arg1);". */
@@ -7121,27 +7177,28 @@ gcc_jit_block_add_eval (
@end deffn
@geindex gcc_jit_context_new_call_through_ptr (C function)
-@anchor{topics/expressions gcc_jit_context_new_call_through_ptr}@anchor{b3}
+@anchor{topics/expressions gcc_jit_context_new_call_through_ptr}@anchor{b8}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_call_through_ptr (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*fn_ptr, int@w{ }numargs, gcc_jit_rvalue@w{ }**args)
-Given an rvalue of function pointer type, and the given table of
+Given an rvalue of function pointer type (e.g. from
+@pxref{91,,gcc_jit_context_new_function_ptr_type()}), and the given table of
argument rvalues, construct a call to the function pointer, with the
result as an rvalue.
@cartouche
@quotation Note
-The same caveat as for @pxref{b1,,gcc_jit_context_new_call()} applies.
+The same caveat as for @pxref{b6,,gcc_jit_context_new_call()} applies.
@end quotation
@end cartouche
@end deffn
@geindex gcc_jit_rvalue_set_bool_require_tail_call (C function)
-@anchor{topics/expressions gcc_jit_rvalue_set_bool_require_tail_call}@anchor{b4}
+@anchor{topics/expressions gcc_jit_rvalue_set_bool_require_tail_call}@anchor{b9}
@deffn {C Function} void gcc_jit_rvalue_set_bool_require_tail_call (gcc_jit_rvalue@w{ }*call, int@w{ }require_tail_call)
Given an @pxref{13,,gcc_jit_rvalue *} for a call created through
-@pxref{b1,,gcc_jit_context_new_call()} or
-@pxref{b3,,gcc_jit_context_new_call_through_ptr()}, mark/clear the
+@pxref{b6,,gcc_jit_context_new_call()} or
+@pxref{b8,,gcc_jit_context_new_call_through_ptr()}, mark/clear the
call as needing tail-call optimization. The optimizer will
attempt to optimize the call into a jump instruction; if it is
unable to do do, an error will be emitted.
@@ -7153,7 +7210,7 @@ languages), in which every function "returns" by calling a
guaranteed to be implemented as a jump, otherwise the program
could consume an arbitrary amount of stack space as it executed.
-This entrypoint was added in @pxref{b5,,LIBGCCJIT_ABI_6}; you can test for
+This entrypoint was added in @pxref{ba,,LIBGCCJIT_ABI_6}; you can test for
its presence using
@example
@@ -7163,13 +7220,37 @@ its presence using
@noindent
@end deffn
-@node Type-coercion,,Function calls,Rvalues
-@anchor{topics/expressions type-coercion}@anchor{b6}
+@node Function pointers,Type-coercion,Function calls,Rvalues
+@anchor{topics/expressions function-pointers}@anchor{bb}
+@subsubsection Function pointers
+
+
+Function pointers can be obtained:
+
+@quotation
+
+
+@itemize *
+
+@item
+from a @pxref{29,,gcc_jit_function} using
+@pxref{bc,,gcc_jit_function_get_address()}, or
+
+@item
+from an existing function using
+@pxref{98,,gcc_jit_context_new_rvalue_from_ptr()},
+using a function pointer type obtained using
+@pxref{91,,gcc_jit_context_new_function_ptr_type()}.
+@end itemize
+@end quotation
+
+@node Type-coercion,,Function pointers,Rvalues
+@anchor{topics/expressions type-coercion}@anchor{bd}
@subsubsection Type-coercion
@geindex gcc_jit_context_new_cast (C function)
-@anchor{topics/expressions gcc_jit_context_new_cast}@anchor{b7}
+@anchor{topics/expressions gcc_jit_context_new_cast}@anchor{be}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_context_new_cast (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue, gcc_jit_type@w{ }*type)
Given an rvalue of T, construct another rvalue of another type.
@@ -7194,7 +7275,7 @@ P* <-> Q*, for pointer types P and Q
@end deffn
@node Lvalues,Working with pointers structs and unions,Rvalues,Expressions
-@anchor{topics/expressions lvalues}@anchor{b8}
+@anchor{topics/expressions lvalues}@anchor{bf}
@subsection Lvalues
@@ -7208,21 +7289,21 @@ a storage area (such as a variable). It is also usable as an rvalue,
where the rvalue is computed by reading from the storage area.
@geindex gcc_jit_lvalue_as_object (C function)
-@anchor{topics/expressions gcc_jit_lvalue_as_object}@anchor{b9}
+@anchor{topics/expressions gcc_jit_lvalue_as_object}@anchor{c0}
@deffn {C Function} gcc_jit_object * gcc_jit_lvalue_as_object (gcc_jit_lvalue@w{ }*lvalue)
Upcast an lvalue to be an object.
@end deffn
@geindex gcc_jit_lvalue_as_rvalue (C function)
-@anchor{topics/expressions gcc_jit_lvalue_as_rvalue}@anchor{ba}
+@anchor{topics/expressions gcc_jit_lvalue_as_rvalue}@anchor{c1}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_lvalue_as_rvalue (gcc_jit_lvalue@w{ }*lvalue)
Upcast an lvalue to be an rvalue.
@end deffn
@geindex gcc_jit_lvalue_get_address (C function)
-@anchor{topics/expressions gcc_jit_lvalue_get_address}@anchor{bb}
+@anchor{topics/expressions gcc_jit_lvalue_get_address}@anchor{c2}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_lvalue_get_address (gcc_jit_lvalue@w{ }*lvalue, gcc_jit_location@w{ }*loc)
Take the address of an lvalue; analogous to:
@@ -7242,12 +7323,12 @@ in C.
@end menu
@node Global variables,,,Lvalues
-@anchor{topics/expressions global-variables}@anchor{bc}
+@anchor{topics/expressions global-variables}@anchor{c3}
@subsubsection Global variables
@geindex gcc_jit_context_new_global (C function)
-@anchor{topics/expressions gcc_jit_context_new_global}@anchor{bd}
+@anchor{topics/expressions gcc_jit_context_new_global}@anchor{c4}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_context_new_global (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, enum gcc_jit_global_kind@w{ }kind, gcc_jit_type@w{ }*type, const char@w{ }*name)
Add a new global variable of the given type and name to the context.
@@ -7260,22 +7341,22 @@ The "kind" parameter determines the visibility of the "global" outside
of the @pxref{16,,gcc_jit_result}:
@geindex gcc_jit_global_kind (C type)
-@anchor{topics/expressions gcc_jit_global_kind}@anchor{be}
+@anchor{topics/expressions gcc_jit_global_kind}@anchor{c5}
@deffn {C Type} enum gcc_jit_global_kind
@end deffn
@geindex GCC_JIT_GLOBAL_EXPORTED (C macro)
-@anchor{topics/expressions GCC_JIT_GLOBAL_EXPORTED}@anchor{bf}
+@anchor{topics/expressions GCC_JIT_GLOBAL_EXPORTED}@anchor{c6}
@deffn {C Macro} GCC_JIT_GLOBAL_EXPORTED
Global is defined by the client code and is visible
by name outside of this JIT context via
-@pxref{c0,,gcc_jit_result_get_global()} (and this value is required for
+@pxref{c7,,gcc_jit_result_get_global()} (and this value is required for
the global to be accessible via that entrypoint).
@end deffn
@geindex GCC_JIT_GLOBAL_INTERNAL (C macro)
-@anchor{topics/expressions GCC_JIT_GLOBAL_INTERNAL}@anchor{c1}
+@anchor{topics/expressions GCC_JIT_GLOBAL_INTERNAL}@anchor{c8}
@deffn {C Macro} GCC_JIT_GLOBAL_INTERNAL
Global is defined by the client code, but is invisible
@@ -7285,7 +7366,7 @@ context and within child contexts.
@end deffn
@geindex GCC_JIT_GLOBAL_IMPORTED (C macro)
-@anchor{topics/expressions GCC_JIT_GLOBAL_IMPORTED}@anchor{c2}
+@anchor{topics/expressions GCC_JIT_GLOBAL_IMPORTED}@anchor{c9}
@deffn {C Macro} GCC_JIT_GLOBAL_IMPORTED
Global is not defined by the client code; we're merely
@@ -7295,12 +7376,12 @@ header file.
@end deffn
@node Working with pointers structs and unions,,Lvalues,Expressions
-@anchor{topics/expressions working-with-pointers-structs-and-unions}@anchor{c3}
+@anchor{topics/expressions working-with-pointers-structs-and-unions}@anchor{ca}
@subsection Working with pointers, structs and unions
@geindex gcc_jit_rvalue_dereference (C function)
-@anchor{topics/expressions gcc_jit_rvalue_dereference}@anchor{c4}
+@anchor{topics/expressions gcc_jit_rvalue_dereference}@anchor{cb}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_rvalue_dereference (gcc_jit_rvalue@w{ }*rvalue, gcc_jit_location@w{ }*loc)
Given an rvalue of pointer type @code{T *}, dereferencing the pointer,
@@ -7318,7 +7399,7 @@ in C.
Field access is provided separately for both lvalues and rvalues.
@geindex gcc_jit_lvalue_access_field (C function)
-@anchor{topics/expressions gcc_jit_lvalue_access_field}@anchor{c5}
+@anchor{topics/expressions gcc_jit_lvalue_access_field}@anchor{cc}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_lvalue_access_field (gcc_jit_lvalue@w{ }*struct_, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
Given an lvalue of struct or union type, access the given field,
@@ -7334,7 +7415,7 @@ in C.
@end deffn
@geindex gcc_jit_rvalue_access_field (C function)
-@anchor{topics/expressions gcc_jit_rvalue_access_field}@anchor{c6}
+@anchor{topics/expressions gcc_jit_rvalue_access_field}@anchor{cd}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_rvalue_access_field (gcc_jit_rvalue@w{ }*struct_, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
Given an rvalue of struct or union type, access the given field
@@ -7350,7 +7431,7 @@ in C.
@end deffn
@geindex gcc_jit_rvalue_dereference_field (C function)
-@anchor{topics/expressions gcc_jit_rvalue_dereference_field}@anchor{c7}
+@anchor{topics/expressions gcc_jit_rvalue_dereference_field}@anchor{ce}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_rvalue_dereference_field (gcc_jit_rvalue@w{ }*ptr, gcc_jit_location@w{ }*loc, gcc_jit_field@w{ }*field)
Given an rvalue of pointer type @code{T *} where T is of struct or union
@@ -7366,7 +7447,7 @@ in C, itself equivalent to @code{(*EXPR).FIELD}.
@end deffn
@geindex gcc_jit_context_new_array_access (C function)
-@anchor{topics/expressions gcc_jit_context_new_array_access}@anchor{ad}
+@anchor{topics/expressions gcc_jit_context_new_array_access}@anchor{b2}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_context_new_array_access (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*ptr, gcc_jit_rvalue@w{ }*index)
Given an rvalue of pointer type @code{T *}, get at the element @cite{T} at
@@ -7400,8 +7481,8 @@ in C (or, indeed, to @code{PTR + INDEX}).
@c along with this program. If not, see
@c <http://www.gnu.org/licenses/>.
-@node Creating and using functions,Source Locations,Expressions,Topic Reference
-@anchor{topics/functions doc}@anchor{c8}@anchor{topics/functions creating-and-using-functions}@anchor{c9}
+@node Creating and using functions,Function pointers<2>,Expressions,Topic Reference
+@anchor{topics/functions doc}@anchor{cf}@anchor{topics/functions creating-and-using-functions}@anchor{d0}
@section Creating and using functions
@@ -7414,7 +7495,7 @@ in C (or, indeed, to @code{PTR + INDEX}).
@end menu
@node Params,Functions,,Creating and using functions
-@anchor{topics/functions params}@anchor{ca}
+@anchor{topics/functions params}@anchor{d1}
@subsection Params
@@ -7441,28 +7522,28 @@ Parameters are lvalues, and thus are also rvalues (and objects), so the
following upcasts are available:
@geindex gcc_jit_param_as_lvalue (C function)
-@anchor{topics/functions gcc_jit_param_as_lvalue}@anchor{cb}
+@anchor{topics/functions gcc_jit_param_as_lvalue}@anchor{d2}
@deffn {C Function} gcc_jit_lvalue * gcc_jit_param_as_lvalue (gcc_jit_param@w{ }*param)
Upcasting from param to lvalue.
@end deffn
@geindex gcc_jit_param_as_rvalue (C function)
-@anchor{topics/functions gcc_jit_param_as_rvalue}@anchor{cc}
+@anchor{topics/functions gcc_jit_param_as_rvalue}@anchor{d3}
@deffn {C Function} gcc_jit_rvalue * gcc_jit_param_as_rvalue (gcc_jit_param@w{ }*param)
Upcasting from param to rvalue.
@end deffn
@geindex gcc_jit_param_as_object (C function)
-@anchor{topics/functions gcc_jit_param_as_object}@anchor{cd}
+@anchor{topics/functions gcc_jit_param_as_object}@anchor{d4}
@deffn {C Function} gcc_jit_object * gcc_jit_param_as_object (gcc_jit_param@w{ }*param)
Upcasting from param to object.
@end deffn
@node Functions,Blocks,Params,Creating and using functions
-@anchor{topics/functions functions}@anchor{ce}
+@anchor{topics/functions functions}@anchor{d5}
@subsection Functions
@@ -7481,7 +7562,7 @@ creating ourselves, or one that we're referencing.
Create a gcc_jit_function with the given name and parameters.
@geindex gcc_jit_function_kind (C type)
-@anchor{topics/functions gcc_jit_function_kind}@anchor{cf}
+@anchor{topics/functions gcc_jit_function_kind}@anchor{d6}
@deffn {C Type} enum gcc_jit_function_kind
@end deffn
@@ -7491,7 +7572,7 @@ values:
@quotation
@geindex GCC_JIT_FUNCTION_EXPORTED (C macro)
-@anchor{topics/functions GCC_JIT_FUNCTION_EXPORTED}@anchor{d0}
+@anchor{topics/functions GCC_JIT_FUNCTION_EXPORTED}@anchor{d7}
@deffn {C Macro} GCC_JIT_FUNCTION_EXPORTED
Function is defined by the client code and visible
@@ -7503,7 +7584,7 @@ for this function from a @pxref{16,,gcc_jit_result} via
@end deffn
@geindex GCC_JIT_FUNCTION_INTERNAL (C macro)
-@anchor{topics/functions GCC_JIT_FUNCTION_INTERNAL}@anchor{d1}
+@anchor{topics/functions GCC_JIT_FUNCTION_INTERNAL}@anchor{d8}
@deffn {C Macro} GCC_JIT_FUNCTION_INTERNAL
Function is defined by the client code, but is invisible
@@ -7511,7 +7592,7 @@ outside of the JIT. Analogous to a "static" function.
@end deffn
@geindex GCC_JIT_FUNCTION_IMPORTED (C macro)
-@anchor{topics/functions GCC_JIT_FUNCTION_IMPORTED}@anchor{d2}
+@anchor{topics/functions GCC_JIT_FUNCTION_IMPORTED}@anchor{d9}
@deffn {C Macro} GCC_JIT_FUNCTION_IMPORTED
Function is not defined by the client code; we're merely
@@ -7520,7 +7601,7 @@ header file.
@end deffn
@geindex GCC_JIT_FUNCTION_ALWAYS_INLINE (C macro)
-@anchor{topics/functions GCC_JIT_FUNCTION_ALWAYS_INLINE}@anchor{d3}
+@anchor{topics/functions GCC_JIT_FUNCTION_ALWAYS_INLINE}@anchor{da}
@deffn {C Macro} GCC_JIT_FUNCTION_ALWAYS_INLINE
Function is only ever inlined into other functions, and is
@@ -7541,19 +7622,19 @@ buffer.
@end deffn
@geindex gcc_jit_context_get_builtin_function (C function)
-@anchor{topics/functions gcc_jit_context_get_builtin_function}@anchor{d4}
+@anchor{topics/functions gcc_jit_context_get_builtin_function}@anchor{db}
@deffn {C Function} gcc_jit_function *gcc_jit_context_get_builtin_function (gcc_jit_context@w{ }*ctxt, const char@w{ }*name)
@end deffn
@geindex gcc_jit_function_as_object (C function)
-@anchor{topics/functions gcc_jit_function_as_object}@anchor{d5}
+@anchor{topics/functions gcc_jit_function_as_object}@anchor{dc}
@deffn {C Function} gcc_jit_object * gcc_jit_function_as_object (gcc_jit_function@w{ }*func)
Upcasting from function to object.
@end deffn
@geindex gcc_jit_function_get_param (C function)
-@anchor{topics/functions gcc_jit_function_get_param}@anchor{d6}
+@anchor{topics/functions gcc_jit_function_get_param}@anchor{dd}
@deffn {C Function} gcc_jit_param * gcc_jit_function_get_param (gcc_jit_function@w{ }*func, int@w{ }index)
Get the param of the given index (0-based).
@@ -7579,7 +7660,7 @@ buffer.
@end deffn
@node Blocks,Statements,Functions,Creating and using functions
-@anchor{topics/functions blocks}@anchor{d7}
+@anchor{topics/functions blocks}@anchor{de}
@subsection Blocks
@@ -7603,7 +7684,7 @@ one function.
@end deffn
@geindex gcc_jit_function_new_block (C function)
-@anchor{topics/functions gcc_jit_function_new_block}@anchor{d8}
+@anchor{topics/functions gcc_jit_function_new_block}@anchor{df}
@deffn {C Function} gcc_jit_block * gcc_jit_function_new_block (gcc_jit_function@w{ }*func, const char@w{ }*name)
Create a basic block of the given name. The name may be NULL, but
@@ -7625,26 +7706,26 @@ for (pc = 0; pc < fn->fn_num_ops; pc++)
@end deffn
@geindex gcc_jit_block_as_object (C function)
-@anchor{topics/functions gcc_jit_block_as_object}@anchor{d9}
+@anchor{topics/functions gcc_jit_block_as_object}@anchor{e0}
@deffn {C Function} gcc_jit_object * gcc_jit_block_as_object (gcc_jit_block@w{ }*block)
Upcast from block to object.
@end deffn
@geindex gcc_jit_block_get_function (C function)
-@anchor{topics/functions gcc_jit_block_get_function}@anchor{da}
+@anchor{topics/functions gcc_jit_block_get_function}@anchor{e1}
@deffn {C Function} gcc_jit_function * gcc_jit_block_get_function (gcc_jit_block@w{ }*block)
Which function is this block within?
@end deffn
@node Statements,,Blocks,Creating and using functions
-@anchor{topics/functions statements}@anchor{db}
+@anchor{topics/functions statements}@anchor{e2}
@subsection Statements
@geindex gcc_jit_block_add_eval (C function)
-@anchor{topics/functions gcc_jit_block_add_eval}@anchor{b2}
+@anchor{topics/functions gcc_jit_block_add_eval}@anchor{b7}
@deffn {C Function} void gcc_jit_block_add_eval (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue)
Add evaluation of an rvalue, discarding the result
@@ -7753,7 +7834,7 @@ block, boolval, on_true, and on_false must be non-NULL.
@end deffn
@geindex gcc_jit_block_end_with_jump (C function)
-@anchor{topics/functions gcc_jit_block_end_with_jump}@anchor{dc}
+@anchor{topics/functions gcc_jit_block_end_with_jump}@anchor{e3}
@deffn {C Function} void gcc_jit_block_end_with_jump (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_block@w{ }*target)
Terminate a block by adding a jump to the given target block.
@@ -7768,7 +7849,7 @@ goto target;
@end deffn
@geindex gcc_jit_block_end_with_return (C function)
-@anchor{topics/functions gcc_jit_block_end_with_return}@anchor{dd}
+@anchor{topics/functions gcc_jit_block_end_with_return}@anchor{e4}
@deffn {C Function} void gcc_jit_block_end_with_return (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*rvalue)
Terminate a block by adding evaluation of an rvalue, returning the value.
@@ -7783,7 +7864,7 @@ return expression;
@end deffn
@geindex gcc_jit_block_end_with_void_return (C function)
-@anchor{topics/functions gcc_jit_block_end_with_void_return}@anchor{de}
+@anchor{topics/functions gcc_jit_block_end_with_void_return}@anchor{e5}
@deffn {C Function} void gcc_jit_block_end_with_void_return (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc)
Terminate a block by adding a valueless return, for use within a function
@@ -7799,7 +7880,7 @@ return;
@end deffn
@geindex gcc_jit_block_end_with_switch (C function)
-@anchor{topics/functions gcc_jit_block_end_with_switch}@anchor{df}
+@anchor{topics/functions gcc_jit_block_end_with_switch}@anchor{e6}
@deffn {C Function} void gcc_jit_block_end_with_switch (gcc_jit_block@w{ }*block, gcc_jit_location@w{ }*loc, gcc_jit_rvalue@w{ }*expr, gcc_jit_block@w{ }*default_block, int@w{ }num_cases, gcc_jit_case@w{ }**cases)
Terminate a block by adding evalation of an rvalue, then performing
@@ -7847,17 +7928,17 @@ The API entrypoints relating to switch statements and cases:
@itemize *
@item
-@pxref{df,,gcc_jit_block_end_with_switch()}
+@pxref{e6,,gcc_jit_block_end_with_switch()}
@item
-@pxref{e0,,gcc_jit_case_as_object()}
+@pxref{e7,,gcc_jit_case_as_object()}
@item
-@pxref{e1,,gcc_jit_context_new_case()}
+@pxref{e8,,gcc_jit_context_new_case()}
@end itemize
@end quotation
-were added in @pxref{e2,,LIBGCCJIT_ABI_3}; you can test for their presence
+were added in @pxref{e9,,LIBGCCJIT_ABI_3}; you can test for their presence
using
@example
@@ -7867,20 +7948,20 @@ using
@noindent
@geindex gcc_jit_case (C type)
-@anchor{topics/functions gcc_jit_case}@anchor{e3}
+@anchor{topics/functions gcc_jit_case}@anchor{ea}
@deffn {C Type} gcc_jit_case
@end deffn
A @cite{gcc_jit_case} represents a case within a switch statement, and
is created within a particular @pxref{8,,gcc_jit_context} using
-@pxref{e1,,gcc_jit_context_new_case()}.
+@pxref{e8,,gcc_jit_context_new_case()}.
Each case expresses a multivalued range of integer values. You
can express single-valued cases by passing in the same value for
both @cite{min_value} and @cite{max_value}.
@geindex gcc_jit_context_new_case (C function)
-@anchor{topics/functions gcc_jit_context_new_case}@anchor{e1}
+@anchor{topics/functions gcc_jit_context_new_case}@anchor{e8}
@deffn {C Function} gcc_jit_case * gcc_jit_context_new_case (gcc_jit_context@w{ }*ctxt, gcc_jit_rvalue@w{ }*min_value, gcc_jit_rvalue@w{ }*max_value, gcc_jit_block@w{ }*dest_block)
Create a new gcc_jit_case instance for use in a switch statement.
@@ -7892,7 +7973,7 @@ statement.
@end deffn
@geindex gcc_jit_case_as_object (C function)
-@anchor{topics/functions gcc_jit_case_as_object}@anchor{e0}
+@anchor{topics/functions gcc_jit_case_as_object}@anchor{e7}
@deffn {C Function} gcc_jit_object * gcc_jit_case_as_object (gcc_jit_case@w{ }*case_)
Upcast from a case to an object.
@@ -8009,6 +8090,89 @@ create_code (gcc_jit_context *ctxt, void *user_data)
@end quotation
@end deffn
+@c Copyright (C) 2017 Free Software Foundation, Inc.
+@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
+@c
+@c This is free software: you can redistribute it and/or modify it
+@c under the terms of the GNU General Public License as published by
+@c the Free Software Foundation, either version 3 of the License, or
+@c (at your option) any later version.
+@c
+@c This program is distributed in the hope that it will be useful, but
+@c WITHOUT ANY WARRANTY; without even the implied warranty of
+@c MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+@c General Public License for more details.
+@c
+@c You should have received a copy of the GNU General Public License
+@c along with this program. If not, see
+@c <http://www.gnu.org/licenses/>.
+
+@node Function pointers<2>,Source Locations,Creating and using functions,Topic Reference
+@anchor{topics/function-pointers doc}@anchor{eb}@anchor{topics/function-pointers function-pointers}@anchor{ec}
+@section Function pointers
+
+
+You can generate calls that use a function pointer via
+@pxref{b8,,gcc_jit_context_new_call_through_ptr()}.
+
+To do requires a @pxref{13,,gcc_jit_rvalue} of the correct function pointer type.
+
+Function pointers for a @pxref{29,,gcc_jit_function} can be obtained
+via @pxref{bc,,gcc_jit_function_get_address()}.
+
+@geindex gcc_jit_function_get_address (C function)
+@anchor{topics/function-pointers gcc_jit_function_get_address}@anchor{bc}
+@deffn {C Function} gcc_jit_rvalue * gcc_jit_function_get_address (gcc_jit_function@w{ }*fn, gcc_jit_location@w{ }*loc)
+
+Get the address of a function as an rvalue, of function pointer
+type.
+
+This entrypoint was added in @pxref{ed,,LIBGCCJIT_ABI_9}; you can test
+for its presence using
+
+@example
+#ifdef LIBGCCJIT_HAVE_gcc_jit_function_get_address
+@end example
+
+@noindent
+@end deffn
+
+Alternatively, given an existing function, you can obtain a pointer
+to it in @pxref{13,,gcc_jit_rvalue} form using
+@pxref{98,,gcc_jit_context_new_rvalue_from_ptr()}, using a function pointer
+type obtained using @pxref{91,,gcc_jit_context_new_function_ptr_type()}.
+
+Here's an example of creating a function pointer type corresponding to C's
+@code{void (*) (int, int, int)}:
+
+@example
+gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+/* Build the function ptr type. */
+gcc_jit_type *param_types[3];
+param_types[0] = int_type;
+param_types[1] = int_type;
+param_types[2] = int_type;
+
+gcc_jit_type *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 3, param_types, 0);
+@end example
+
+@noindent
+
+@geindex gcc_jit_context_new_function_ptr_type (C function)
+@anchor{topics/function-pointers gcc_jit_context_new_function_ptr_type}@anchor{91}
+@deffn {C Function} gcc_jit_type * gcc_jit_context_new_function_ptr_type (gcc_jit_context@w{ }*ctxt, gcc_jit_location@w{ }*loc, gcc_jit_type@w{ }*return_type, int@w{ }num_params, gcc_jit_type@w{ }**param_types, int@w{ }is_variadic)
+
+Generate a @pxref{a,,gcc_jit_type} for a function pointer with the
+given return type and parameters.
+@end deffn
+
@c Copyright (C) 2014-2017 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@@ -8026,8 +8190,8 @@ create_code (gcc_jit_context *ctxt, void *user_data)
@c along with this program. If not, see
@c <http://www.gnu.org/licenses/>.
-@node Source Locations,Compiling a context,Creating and using functions,Topic Reference
-@anchor{topics/locations source-locations}@anchor{e4}@anchor{topics/locations doc}@anchor{e5}
+@node Source Locations,Compiling a context,Function pointers<2>,Topic Reference
+@anchor{topics/locations source-locations}@anchor{ee}@anchor{topics/locations doc}@anchor{ef}
@section Source Locations
@@ -8077,7 +8241,7 @@ on-stack buffer.
@end menu
@node Faking it,,,Source Locations
-@anchor{topics/locations faking-it}@anchor{e6}
+@anchor{topics/locations faking-it}@anchor{f0}
@subsection Faking it
@@ -8115,7 +8279,7 @@ file, giving you @emph{something} you can step through in the debugger.
@c <http://www.gnu.org/licenses/>.
@node Compiling a context,ABI and API compatibility,Source Locations,Topic Reference
-@anchor{topics/compilation compiling-a-context}@anchor{e7}@anchor{topics/compilation doc}@anchor{e8}
+@anchor{topics/compilation compiling-a-context}@anchor{f1}@anchor{topics/compilation doc}@anchor{f2}
@section Compiling a context
@@ -8134,7 +8298,7 @@ prevent any future compilation of that context.
@end menu
@node In-memory compilation,Ahead-of-time compilation,,Compiling a context
-@anchor{topics/compilation in-memory-compilation}@anchor{e9}
+@anchor{topics/compilation in-memory-compilation}@anchor{f3}
@subsection In-memory compilation
@@ -8169,7 +8333,7 @@ Functions are looked up by name. For this to succeed, a function
with a name matching @cite{funcname} must have been created on
@cite{result}'s context (or a parent context) via a call to
@pxref{11,,gcc_jit_context_new_function()} with @cite{kind}
-@pxref{d0,,GCC_JIT_FUNCTION_EXPORTED}:
+@pxref{d7,,GCC_JIT_FUNCTION_EXPORTED}:
@example
gcc_jit_context_new_function (ctxt,
@@ -8199,7 +8363,7 @@ to a segmentation fault.
@end deffn
@geindex gcc_jit_result_get_global (C function)
-@anchor{topics/compilation gcc_jit_result_get_global}@anchor{c0}
+@anchor{topics/compilation gcc_jit_result_get_global}@anchor{c7}
@deffn {C Function} void * gcc_jit_result_get_global (gcc_jit_result@w{ }*result, const char@w{ }*name)
Locate a given global within the built machine code.
@@ -8207,8 +8371,8 @@ Locate a given global within the built machine code.
Globals are looked up by name. For this to succeed, a global
with a name matching @cite{name} must have been created on
@cite{result}'s context (or a parent context) via a call to
-@pxref{bd,,gcc_jit_context_new_global()} with @cite{kind}
-@pxref{bf,,GCC_JIT_GLOBAL_EXPORTED}.
+@pxref{c4,,gcc_jit_context_new_global()} with @cite{kind}
+@pxref{c6,,GCC_JIT_GLOBAL_EXPORTED}.
If the global is found, the result will need to be cast to a
pointer of the correct type before it can be called.
@@ -8256,11 +8420,11 @@ Once we're done with the code, this unloads the built .so file.
This cleans up the result; after calling this, it's no longer
valid to use the result, or any code or globals that were obtained
by calling @pxref{17,,gcc_jit_result_get_code()} or
-@pxref{c0,,gcc_jit_result_get_global()} on it.
+@pxref{c7,,gcc_jit_result_get_global()} on it.
@end deffn
@node Ahead-of-time compilation,,In-memory compilation,Compiling a context
-@anchor{topics/compilation ahead-of-time-compilation}@anchor{ea}
+@anchor{topics/compilation ahead-of-time-compilation}@anchor{f4}
@subsection Ahead-of-time compilation
@@ -8289,7 +8453,7 @@ suffix of the output file when determining what to do.
@end cartouche
@geindex gcc_jit_output_kind (C type)
-@anchor{topics/compilation gcc_jit_output_kind}@anchor{eb}
+@anchor{topics/compilation gcc_jit_output_kind}@anchor{f5}
@deffn {C Type} enum gcc_jit_output_kind
@end deffn
@@ -8307,7 +8471,7 @@ Typical suffix
@item
-@pxref{ec,,GCC_JIT_OUTPUT_KIND_ASSEMBLER}
+@pxref{f6,,GCC_JIT_OUTPUT_KIND_ASSEMBLER}
@tab
@@ -8315,7 +8479,7 @@ Typical suffix
@item
-@pxref{ed,,GCC_JIT_OUTPUT_KIND_OBJECT_FILE}
+@pxref{f7,,GCC_JIT_OUTPUT_KIND_OBJECT_FILE}
@tab
@@ -8323,7 +8487,7 @@ Typical suffix
@item
-@pxref{ee,,GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY}
+@pxref{f8,,GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY}
@tab
@@ -8331,7 +8495,7 @@ Typical suffix
@item
-@pxref{ef,,GCC_JIT_OUTPUT_KIND_EXECUTABLE}
+@pxref{f9,,GCC_JIT_OUTPUT_KIND_EXECUTABLE}
@tab
@@ -8341,21 +8505,21 @@ None, or .exe
@geindex GCC_JIT_OUTPUT_KIND_ASSEMBLER (C macro)
-@anchor{topics/compilation GCC_JIT_OUTPUT_KIND_ASSEMBLER}@anchor{ec}
+@anchor{topics/compilation GCC_JIT_OUTPUT_KIND_ASSEMBLER}@anchor{f6}
@deffn {C Macro} GCC_JIT_OUTPUT_KIND_ASSEMBLER
Compile the context to an assembler file.
@end deffn
@geindex GCC_JIT_OUTPUT_KIND_OBJECT_FILE (C macro)
-@anchor{topics/compilation GCC_JIT_OUTPUT_KIND_OBJECT_FILE}@anchor{ed}
+@anchor{topics/compilation GCC_JIT_OUTPUT_KIND_OBJECT_FILE}@anchor{f7}
@deffn {C Macro} GCC_JIT_OUTPUT_KIND_OBJECT_FILE
Compile the context to an object file.
@end deffn
@geindex GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY (C macro)
-@anchor{topics/compilation GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY}@anchor{ee}
+@anchor{topics/compilation GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY}@anchor{f8}
@deffn {C Macro} GCC_JIT_OUTPUT_KIND_DYNAMIC_LIBRARY
Compile the context to a dynamic library.
@@ -8365,7 +8529,7 @@ against.
@end deffn
@geindex GCC_JIT_OUTPUT_KIND_EXECUTABLE (C macro)
-@anchor{topics/compilation GCC_JIT_OUTPUT_KIND_EXECUTABLE}@anchor{ef}
+@anchor{topics/compilation GCC_JIT_OUTPUT_KIND_EXECUTABLE}@anchor{f9}
@deffn {C Macro} GCC_JIT_OUTPUT_KIND_EXECUTABLE
Compile the context to an executable.
@@ -8392,7 +8556,7 @@ against.
@c <http://www.gnu.org/licenses/>.
@node ABI and API compatibility,Performance,Compiling a context,Topic Reference
-@anchor{topics/compatibility abi-and-api-compatibility}@anchor{f0}@anchor{topics/compatibility doc}@anchor{f1}
+@anchor{topics/compatibility abi-and-api-compatibility}@anchor{fa}@anchor{topics/compatibility doc}@anchor{fb}
@section ABI and API compatibility
@@ -8459,12 +8623,14 @@ ABI symbol tags
* LIBGCCJIT_ABI_6::
* LIBGCCJIT_ABI_7::
* LIBGCCJIT_ABI_8::
+* LIBGCCJIT_ABI_9::
+* LIBGCCJIT_ABI_10::
@end menu
@node ABI symbol tags,,,ABI and API compatibility
-@anchor{topics/compatibility abi-symbol-tags}@anchor{f2}
+@anchor{topics/compatibility abi-symbol-tags}@anchor{fc}
@subsection ABI symbol tags
@@ -8482,11 +8648,13 @@ Newer releases use the following tags.
* LIBGCCJIT_ABI_6::
* LIBGCCJIT_ABI_7::
* LIBGCCJIT_ABI_8::
+* LIBGCCJIT_ABI_9::
+* LIBGCCJIT_ABI_10::
@end menu
@node LIBGCCJIT_ABI_0,LIBGCCJIT_ABI_1,,ABI symbol tags
-@anchor{topics/compatibility libgccjit-abi-0}@anchor{f3}@anchor{topics/compatibility id1}@anchor{f4}
+@anchor{topics/compatibility libgccjit-abi-0}@anchor{fd}@anchor{topics/compatibility id1}@anchor{fe}
@subsubsection @code{LIBGCCJIT_ABI_0}
@@ -8498,7 +8666,7 @@ continue to work, with this being handled transparently by the linker
(see this post@footnote{https://gcc.gnu.org/ml/gcc-patches/2015-06/msg02126.html})
@node LIBGCCJIT_ABI_1,LIBGCCJIT_ABI_2,LIBGCCJIT_ABI_0,ABI symbol tags
-@anchor{topics/compatibility libgccjit-abi-1}@anchor{73}@anchor{topics/compatibility id2}@anchor{f5}
+@anchor{topics/compatibility libgccjit-abi-1}@anchor{73}@anchor{topics/compatibility id2}@anchor{ff}
@subsubsection @code{LIBGCCJIT_ABI_1}
@@ -8506,7 +8674,7 @@ continue to work, with this being handled transparently by the linker
@pxref{72,,gcc_jit_context_add_command_line_option()}
@node LIBGCCJIT_ABI_2,LIBGCCJIT_ABI_3,LIBGCCJIT_ABI_1,ABI symbol tags
-@anchor{topics/compatibility libgccjit-abi-2}@anchor{6c}@anchor{topics/compatibility id3}@anchor{f6}
+@anchor{topics/compatibility libgccjit-abi-2}@anchor{6c}@anchor{topics/compatibility id3}@anchor{100}
@subsubsection @code{LIBGCCJIT_ABI_2}
@@ -8514,7 +8682,7 @@ continue to work, with this being handled transparently by the linker
@pxref{6b,,gcc_jit_context_set_bool_allow_unreachable_blocks()}
@node LIBGCCJIT_ABI_3,LIBGCCJIT_ABI_4,LIBGCCJIT_ABI_2,ABI symbol tags
-@anchor{topics/compatibility libgccjit-abi-3}@anchor{e2}@anchor{topics/compatibility id4}@anchor{f7}
+@anchor{topics/compatibility libgccjit-abi-3}@anchor{e9}@anchor{topics/compatibility id4}@anchor{101}
@subsubsection @code{LIBGCCJIT_ABI_3}
@@ -8527,18 +8695,18 @@ entrypoints:
@itemize *
@item
-@pxref{df,,gcc_jit_block_end_with_switch()}
+@pxref{e6,,gcc_jit_block_end_with_switch()}
@item
-@pxref{e0,,gcc_jit_case_as_object()}
+@pxref{e7,,gcc_jit_case_as_object()}
@item
-@pxref{e1,,gcc_jit_context_new_case()}
+@pxref{e8,,gcc_jit_context_new_case()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_4,LIBGCCJIT_ABI_5,LIBGCCJIT_ABI_3,ABI symbol tags
-@anchor{topics/compatibility id5}@anchor{f8}@anchor{topics/compatibility libgccjit-abi-4}@anchor{f9}
+@anchor{topics/compatibility id5}@anchor{102}@anchor{topics/compatibility libgccjit-abi-4}@anchor{103}
@subsubsection @code{LIBGCCJIT_ABI_4}
@@ -8551,30 +8719,30 @@ entrypoints:
@itemize *
@item
-@pxref{fa,,gcc_jit_context_get_timer()}
+@pxref{104,,gcc_jit_context_get_timer()}
@item
-@pxref{fb,,gcc_jit_context_set_timer()}
+@pxref{105,,gcc_jit_context_set_timer()}
@item
-@pxref{fc,,gcc_jit_timer_new()}
+@pxref{106,,gcc_jit_timer_new()}
@item
-@pxref{fd,,gcc_jit_timer_release()}
+@pxref{107,,gcc_jit_timer_release()}
@item
-@pxref{fe,,gcc_jit_timer_push()}
+@pxref{108,,gcc_jit_timer_push()}
@item
-@pxref{ff,,gcc_jit_timer_pop()}
+@pxref{109,,gcc_jit_timer_pop()}
@item
-@pxref{100,,gcc_jit_timer_print()}
+@pxref{10a,,gcc_jit_timer_print()}
@end itemize
@end quotation
@node LIBGCCJIT_ABI_5,LIBGCCJIT_ABI_6,LIBGCCJIT_ABI_4,ABI symbol tags
-@anchor{topics/compatibility id6}@anchor{101}@anchor{topics/compatibility libgccjit-abi-5}@anchor{6e}
+@anchor{topics/compatibility id6}@anchor{10b}@anchor{topics/compatibility libgccjit-abi-5}@anchor{6e}
@subsubsection @code{LIBGCCJIT_ABI_5}
@@ -8582,29 +8750,45 @@ entrypoints:
@pxref{6d,,gcc_jit_context_set_bool_use_external_driver()}
@node LIBGCCJIT_ABI_6,LIBGCCJIT_ABI_7,LIBGCCJIT_ABI_5,ABI symbol tags
-@anchor{topics/compatibility id7}@anchor{102}@anchor{topics/compatibility libgccjit-abi-6}@anchor{b5}
+@anchor{topics/compatibility id7}@anchor{10c}@anchor{topics/compatibility libgccjit-abi-6}@anchor{ba}
@subsubsection @code{LIBGCCJIT_ABI_6}
@code{LIBGCCJIT_ABI_6} covers the addition of
-@pxref{b4,,gcc_jit_rvalue_set_bool_require_tail_call()}
+@pxref{b9,,gcc_jit_rvalue_set_bool_require_tail_call()}
@node LIBGCCJIT_ABI_7,LIBGCCJIT_ABI_8,LIBGCCJIT_ABI_6,ABI symbol tags
-@anchor{topics/compatibility libgccjit-abi-7}@anchor{81}@anchor{topics/compatibility id8}@anchor{103}
+@anchor{topics/compatibility libgccjit-abi-7}@anchor{81}@anchor{topics/compatibility id8}@anchor{10d}
@subsubsection @code{LIBGCCJIT_ABI_7}
@code{LIBGCCJIT_ABI_7} covers the addition of
@pxref{80,,gcc_jit_type_get_aligned()}
-@node LIBGCCJIT_ABI_8,,LIBGCCJIT_ABI_7,ABI symbol tags
-@anchor{topics/compatibility libgccjit-abi-8}@anchor{84}@anchor{topics/compatibility id9}@anchor{104}
+@node LIBGCCJIT_ABI_8,LIBGCCJIT_ABI_9,LIBGCCJIT_ABI_7,ABI symbol tags
+@anchor{topics/compatibility libgccjit-abi-8}@anchor{84}@anchor{topics/compatibility id9}@anchor{10e}
@subsubsection @code{LIBGCCJIT_ABI_8}
@code{LIBGCCJIT_ABI_8} covers the addition of
@pxref{83,,gcc_jit_type_get_vector()}
+@node LIBGCCJIT_ABI_9,LIBGCCJIT_ABI_10,LIBGCCJIT_ABI_8,ABI symbol tags
+@anchor{topics/compatibility id10}@anchor{10f}@anchor{topics/compatibility libgccjit-abi-9}@anchor{ed}
+@subsubsection @code{LIBGCCJIT_ABI_9}
+
+
+@code{LIBGCCJIT_ABI_9} covers the addition of
+@pxref{bc,,gcc_jit_function_get_address()}
+
+@node LIBGCCJIT_ABI_10,,LIBGCCJIT_ABI_9,ABI symbol tags
+@anchor{topics/compatibility id11}@anchor{110}@anchor{topics/compatibility libgccjit-abi-10}@anchor{9c}
+@subsubsection @code{LIBGCCJIT_ABI_10}
+
+
+@code{LIBGCCJIT_ABI_10} covers the addition of
+@pxref{85,,gcc_jit_context_new_rvalue_from_vector()}
+
@c Copyright (C) 2015-2017 Free Software Foundation, Inc.
@c Originally contributed by David Malcolm <dmalcolm@redhat.com>
@c
@@ -8623,7 +8807,7 @@ entrypoints:
@c <http://www.gnu.org/licenses/>.
@node Performance,,ABI and API compatibility,Topic Reference
-@anchor{topics/performance performance}@anchor{105}@anchor{topics/performance doc}@anchor{106}
+@anchor{topics/performance performance}@anchor{111}@anchor{topics/performance doc}@anchor{112}
@section Performance
@@ -8633,14 +8817,14 @@ entrypoints:
@end menu
@node The timing API,,,Performance
-@anchor{topics/performance the-timing-api}@anchor{107}
+@anchor{topics/performance the-timing-api}@anchor{113}
@subsection The timing API
As of GCC 6, libgccjit exposes a timing API, for printing reports on
how long was spent in different parts of code.
-You can create a @pxref{108,,gcc_jit_timer} instance, which will
+You can create a @pxref{114,,gcc_jit_timer} instance, which will
measure time spent since its creation. The timer maintains a stack
of "timer items": as control flow moves through your code, you can push
and pop named items relating to your code onto the stack, and the timer
@@ -8742,7 +8926,7 @@ Client items:
The exact format is intended to be human-readable, and is subject to change.
@geindex LIBGCCJIT_HAVE_TIMING_API (C macro)
-@anchor{topics/performance LIBGCCJIT_HAVE_TIMING_API}@anchor{109}
+@anchor{topics/performance LIBGCCJIT_HAVE_TIMING_API}@anchor{115}
@deffn {C Macro} LIBGCCJIT_HAVE_TIMING_API
The timer API was added to libgccjit in GCC 6.
@@ -8761,15 +8945,15 @@ gcc_jit_context_set_timer (ctxt, t);
@end deffn
@geindex gcc_jit_timer (C type)
-@anchor{topics/performance gcc_jit_timer}@anchor{108}
+@anchor{topics/performance gcc_jit_timer}@anchor{114}
@deffn {C Type} gcc_jit_timer
@end deffn
@geindex gcc_jit_timer_new (C function)
-@anchor{topics/performance gcc_jit_timer_new}@anchor{fc}
+@anchor{topics/performance gcc_jit_timer_new}@anchor{106}
@deffn {C Function} gcc_jit_timer * gcc_jit_timer_new (void)
-Create a @pxref{108,,gcc_jit_timer} instance, and start timing:
+Create a @pxref{114,,gcc_jit_timer} instance, and start timing:
@example
gcc_jit_timer *t = gcc_jit_timer_new ();
@@ -8777,7 +8961,7 @@ gcc_jit_timer *t = gcc_jit_timer_new ();
@noindent
-This API entrypoint was added in @pxref{f9,,LIBGCCJIT_ABI_4}; you can test
+This API entrypoint was added in @pxref{103,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
@@ -8788,10 +8972,10 @@ for its presence using
@end deffn
@geindex gcc_jit_timer_release (C function)
-@anchor{topics/performance gcc_jit_timer_release}@anchor{fd}
+@anchor{topics/performance gcc_jit_timer_release}@anchor{107}
@deffn {C Function} void gcc_jit_timer_release (gcc_jit_timer@w{ }*timer)
-Release a @pxref{108,,gcc_jit_timer} instance:
+Release a @pxref{114,,gcc_jit_timer} instance:
@example
gcc_jit_timer_release (t);
@@ -8801,7 +8985,7 @@ gcc_jit_timer_release (t);
This should be called exactly once on a timer.
-This API entrypoint was added in @pxref{f9,,LIBGCCJIT_ABI_4}; you can test
+This API entrypoint was added in @pxref{103,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
@@ -8812,10 +8996,10 @@ for its presence using
@end deffn
@geindex gcc_jit_context_set_timer (C function)
-@anchor{topics/performance gcc_jit_context_set_timer}@anchor{fb}
+@anchor{topics/performance gcc_jit_context_set_timer}@anchor{105}
@deffn {C Function} void gcc_jit_context_set_timer (gcc_jit_context@w{ }*ctxt, gcc_jit_timer@w{ }*timer)
-Associate a @pxref{108,,gcc_jit_timer} instance with a context:
+Associate a @pxref{114,,gcc_jit_timer} instance with a context:
@example
gcc_jit_context_set_timer (ctxt, t);
@@ -8830,7 +9014,7 @@ Timers have no locking, so if you have a multithreaded program, you
must provide your own locks if more than one thread could be working
with the same timer via timer-associated contexts.
-This API entrypoint was added in @pxref{f9,,LIBGCCJIT_ABI_4}; you can test
+This API entrypoint was added in @pxref{103,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
@@ -8841,12 +9025,12 @@ for its presence using
@end deffn
@geindex gcc_jit_context_get_timer (C function)
-@anchor{topics/performance gcc_jit_context_get_timer}@anchor{fa}
+@anchor{topics/performance gcc_jit_context_get_timer}@anchor{104}
@deffn {C Function} gcc_jit_timer *gcc_jit_context_get_timer (gcc_jit_context@w{ }*ctxt)
Get the timer associated with a context (if any).
-This API entrypoint was added in @pxref{f9,,LIBGCCJIT_ABI_4}; you can test
+This API entrypoint was added in @pxref{103,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
@@ -8857,7 +9041,7 @@ for its presence using
@end deffn
@geindex gcc_jit_timer_push (C function)
-@anchor{topics/performance gcc_jit_timer_push}@anchor{fe}
+@anchor{topics/performance gcc_jit_timer_push}@anchor{108}
@deffn {C Function} void gcc_jit_timer_push (gcc_jit_timer@w{ }*timer, const char@w{ }*item_name)
Push the given item onto the timer's stack:
@@ -8870,7 +9054,7 @@ gcc_jit_timer_pop (t, "running code");
@noindent
-This API entrypoint was added in @pxref{f9,,LIBGCCJIT_ABI_4}; you can test
+This API entrypoint was added in @pxref{103,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
@@ -8881,7 +9065,7 @@ for its presence using
@end deffn
@geindex gcc_jit_timer_pop (C function)
-@anchor{topics/performance gcc_jit_timer_pop}@anchor{ff}
+@anchor{topics/performance gcc_jit_timer_pop}@anchor{109}
@deffn {C Function} void gcc_jit_timer_pop (gcc_jit_timer@w{ }*timer, const char@w{ }*item_name)
Pop the top item from the timer's stack.
@@ -8889,7 +9073,7 @@ Pop the top item from the timer's stack.
If "item_name" is provided, it must match that of the top item.
Alternatively, @code{NULL} can be passed in, to suppress checking.
-This API entrypoint was added in @pxref{f9,,LIBGCCJIT_ABI_4}; you can test
+This API entrypoint was added in @pxref{103,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
@@ -8900,13 +9084,13 @@ for its presence using
@end deffn
@geindex gcc_jit_timer_print (C function)
-@anchor{topics/performance gcc_jit_timer_print}@anchor{100}
+@anchor{topics/performance gcc_jit_timer_print}@anchor{10a}
@deffn {C Function} void gcc_jit_timer_print (gcc_jit_timer@w{ }*timer, FILE@w{ }*f_out)
Print timing information to the given stream about activity since
the timer was started.
-This API entrypoint was added in @pxref{f9,,LIBGCCJIT_ABI_4}; you can test
+This API entrypoint was added in @pxref{103,,LIBGCCJIT_ABI_4}; you can test
for its presence using
@example
@@ -8934,7 +9118,7 @@ for its presence using
@c <http://www.gnu.org/licenses/>.
@node C++ bindings for libgccjit,Internals,Topic Reference,Top
-@anchor{cp/index c-bindings-for-libgccjit}@anchor{10a}@anchor{cp/index doc}@anchor{10b}
+@anchor{cp/index c-bindings-for-libgccjit}@anchor{116}@anchor{cp/index doc}@anchor{117}
@chapter C++ bindings for libgccjit
@@ -9053,10 +9237,12 @@ Expressions
Rvalues
* Simple expressions: Simple expressions<2>.
+* Vector expressions: Vector expressions<2>.
* Unary Operations: Unary Operations<2>.
* Binary Operations: Binary Operations<2>.
* Comparisons: Comparisons<2>.
* Function calls: Function calls<2>.
+* Function pointers: Function pointers<3>.
* Type-coercion: Type-coercion<2>.
Lvalues
@@ -9083,7 +9269,7 @@ Compiling a context
@node Tutorial<2>,Topic Reference<2>,,C++ bindings for libgccjit
-@anchor{cp/intro/index doc}@anchor{10c}@anchor{cp/intro/index tutorial}@anchor{10d}
+@anchor{cp/intro/index doc}@anchor{118}@anchor{cp/intro/index tutorial}@anchor{119}
@section Tutorial
@@ -9113,7 +9299,7 @@ Compiling a context
@end menu
@node Tutorial part 1 "Hello world"<2>,Tutorial part 2 Creating a trivial machine code function<2>,,Tutorial<2>
-@anchor{cp/intro/tutorial01 doc}@anchor{10e}@anchor{cp/intro/tutorial01 tutorial-part-1-hello-world}@anchor{10f}
+@anchor{cp/intro/tutorial01 doc}@anchor{11a}@anchor{cp/intro/tutorial01 tutorial-part-1-hello-world}@anchor{11b}
@subsection Tutorial part 1: "Hello world"
@@ -9283,7 +9469,7 @@ hello world
@c <http://www.gnu.org/licenses/>.
@node Tutorial part 2 Creating a trivial machine code function<2>,Tutorial part 3 Loops and variables<2>,Tutorial part 1 "Hello world"<2>,Tutorial<2>
-@anchor{cp/intro/tutorial02 doc}@anchor{110}@anchor{cp/intro/tutorial02 tutorial-part-2-creating-a-trivial-machine-code-function}@anchor{111}
+@anchor{cp/intro/tutorial02 doc}@anchor{11c}@anchor{cp/intro/tutorial02 tutorial-part-2-creating-a-trivial-machine-code-function}@anchor{11d}
@subsection Tutorial part 2: Creating a trivial machine code function
@@ -9312,7 +9498,7 @@ All state associated with compilation is associated with a
@code{gccjit::context}, which is a thin C++ wrapper around the C API's
@pxref{8,,gcc_jit_context *}.
-Create one using @pxref{112,,gccjit;;context;;acquire()}:
+Create one using @pxref{11e,,gccjit;;context;;acquire()}:
@example
gccjit::context ctxt;
@@ -9325,7 +9511,7 @@ The JIT library has a system of types. It is statically-typed: every
expression is of a specific type, fixed at compile-time. In our example,
all of the expressions are of the C @cite{int} type, so let's obtain this from
the context, as a @code{gccjit::type}, using
-@pxref{113,,gccjit;;context;;get_type()}:
+@pxref{11f,,gccjit;;context;;get_type()}:
@example
gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
@@ -9338,7 +9524,7 @@ entity in the API is associated with a @code{gccjit::context}.
Memory management is easy: all such "contextual" objects are automatically
cleaned up for you when the context is released, using
-@pxref{114,,gccjit;;context;;release()}:
+@pxref{120,,gccjit;;context;;release()}:
@example
ctxt.release ();
@@ -9371,7 +9557,7 @@ The C++ class hierarchy within the @code{gccjit} namespace looks like this:
One thing you can do with a @code{gccjit::object} is
to ask it for a human-readable description as a @code{std::string}, using
-@pxref{115,,gccjit;;object;;get_debug_string()}:
+@pxref{121,,gccjit;;object;;get_debug_string()}:
@example
printf ("obj: %s\n", obj.get_debug_string ().c_str ());
@@ -9391,7 +9577,7 @@ This is invaluable when debugging.
Let's create the function. To do so, we first need to construct
its single parameter, specifying its type and giving it a name,
-using @pxref{116,,gccjit;;context;;new_param()}:
+using @pxref{122,,gccjit;;context;;new_param()}:
@example
gccjit::param param_i = ctxt.new_param (int_type, "i");
@@ -9440,7 +9626,7 @@ gccjit::block block = func.new_block ();
Our basic block is relatively simple: it immediately terminates by
returning the value of an expression.
-We can build the expression using @pxref{117,,gccjit;;context;;new_binary_op()}:
+We can build the expression using @pxref{123,,gccjit;;context;;new_binary_op()}:
@example
gccjit::rvalue expr =
@@ -9453,7 +9639,7 @@ gccjit::rvalue expr =
A @code{gccjit::rvalue} is another example of a
@code{gccjit::object} subclass. As before, we can print it with
-@pxref{115,,gccjit;;object;;get_debug_string()}.
+@pxref{121,,gccjit;;object;;get_debug_string()}.
@example
printf ("expr: %s\n", expr.get_debug_string ().c_str ());
@@ -9490,7 +9676,7 @@ block.end_with_return (expr);
@noindent
OK, we've populated the context. We can now compile it using
-@pxref{118,,gccjit;;context;;compile()}:
+@pxref{124,,gccjit;;context;;compile()}:
@example
gcc_jit_result *result;
@@ -9540,12 +9726,12 @@ result: 25
@end menu
@node Options<3>,Full example<3>,,Tutorial part 2 Creating a trivial machine code function<2>
-@anchor{cp/intro/tutorial02 options}@anchor{119}
+@anchor{cp/intro/tutorial02 options}@anchor{125}
@subsubsection Options
To get more information on what's going on, you can set debugging flags
-on the context using @pxref{11a,,gccjit;;context;;set_bool_option()}.
+on the context using @pxref{126,,gccjit;;context;;set_bool_option()}.
@c (I'm deliberately not mentioning
@c :c:macro:`GCC_JIT_BOOL_OPTION_DUMP_INITIAL_TREE` here since I think
@@ -9617,7 +9803,7 @@ square:
By default, no optimizations are performed, the equivalent of GCC's
@cite{-O0} option. We can turn things up to e.g. @cite{-O3} by calling
-@pxref{11b,,gccjit;;context;;set_int_option()} with
+@pxref{127,,gccjit;;context;;set_int_option()} with
@pxref{1f,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
@example
@@ -9651,7 +9837,7 @@ square:
Naturally this has only a small effect on such a trivial function.
@node Full example<3>,,Options<3>,Tutorial part 2 Creating a trivial machine code function<2>
-@anchor{cp/intro/tutorial02 full-example}@anchor{11c}
+@anchor{cp/intro/tutorial02 full-example}@anchor{128}
@subsubsection Full example
@@ -9794,7 +9980,7 @@ result: 25
@c <http://www.gnu.org/licenses/>.
@node Tutorial part 3 Loops and variables<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>,Tutorial part 2 Creating a trivial machine code function<2>,Tutorial<2>
-@anchor{cp/intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{11d}@anchor{cp/intro/tutorial03 doc}@anchor{11e}
+@anchor{cp/intro/tutorial03 tutorial-part-3-loops-and-variables}@anchor{129}@anchor{cp/intro/tutorial03 doc}@anchor{12a}
@subsection Tutorial part 3: Loops and variables
@@ -9918,7 +10104,7 @@ gccjit::function func =
@end menu
@node Expressions lvalues and rvalues<2>,Control flow<2>,,Tutorial part 3 Loops and variables<2>
-@anchor{cp/intro/tutorial03 expressions-lvalues-and-rvalues}@anchor{11f}
+@anchor{cp/intro/tutorial03 expressions-lvalues-and-rvalues}@anchor{12b}
@subsubsection Expressions: lvalues and rvalues
@@ -9991,7 +10177,7 @@ body of a function.
Our new example has a new kind of expression: we have two local
variables. We create them by calling
-@pxref{120,,gccjit;;function;;new_local()}, supplying a type and a name:
+@pxref{12c,,gccjit;;function;;new_local()}, supplying a type and a name:
@example
/* Build locals: */
@@ -10017,7 +10203,7 @@ Instead, having added the local to the function, we have to separately add
an assignment of @cite{0} to @cite{local_i} at the beginning of the function.
@node Control flow<2>,Visualizing the control flow graph<2>,Expressions lvalues and rvalues<2>,Tutorial part 3 Loops and variables<2>
-@anchor{cp/intro/tutorial03 control-flow}@anchor{121}
+@anchor{cp/intro/tutorial03 control-flow}@anchor{12d}
@subsubsection Control flow
@@ -10056,8 +10242,8 @@ We now populate each block with statements.
The entry block @cite{b_initial} consists of initializations followed by a jump
to the conditional. We assign @cite{0} to @cite{i} and to @cite{sum}, using
-@pxref{122,,gccjit;;block;;add_assignment()} to add
-an assignment statement, and using @pxref{123,,gccjit;;context;;zero()} to get
+@pxref{12e,,gccjit;;block;;add_assignment()} to add
+an assignment statement, and using @pxref{12f,,gccjit;;context;;zero()} to get
the constant value @cite{0} for the relevant type for the right-hand side of
the assignment:
@@ -10084,7 +10270,7 @@ C example. It contains a single statement: a conditional, which jumps to
one of two destination blocks depending on a boolean
@code{gccjit::rvalue}, in this case the comparison of @cite{i} and @cite{n}.
-We could build the comparison using @pxref{124,,gccjit;;context;;new_comparison()}:
+We could build the comparison using @pxref{130,,gccjit;;context;;new_comparison()}:
@example
gccjit::rvalue guard =
@@ -10095,7 +10281,7 @@ gccjit::rvalue guard =
@noindent
and can then use this to add @cite{b_loop_cond}'s sole statement, via
-@pxref{125,,gccjit;;block;;end_with_conditional()}:
+@pxref{131,,gccjit;;block;;end_with_conditional()}:
@example
b_loop_cond.end_with_conditional (guard,
@@ -10129,7 +10315,7 @@ Next, we populate the body of the loop.
The C statement @cite{sum += i * i;} is an assignment operation, where an
lvalue is modified "in-place". We use
-@pxref{126,,gccjit;;block;;add_assignment_op()} to handle these operations:
+@pxref{132,,gccjit;;block;;add_assignment_op()} to handle these operations:
@example
/* sum += i * i */
@@ -10157,7 +10343,7 @@ b_loop_body.add_assignment_op (i,
@cartouche
@quotation Note
For numeric constants other than 0 or 1, we could use
-@pxref{127,,gccjit;;context;;new_rvalue()}, which has overloads
+@pxref{133,,gccjit;;context;;new_rvalue()}, which has overloads
for both @code{int} and @code{double}.
@end quotation
@end cartouche
@@ -10233,12 +10419,12 @@ result: 285
@noindent
@node Visualizing the control flow graph<2>,Full example<4>,Control flow<2>,Tutorial part 3 Loops and variables<2>
-@anchor{cp/intro/tutorial03 visualizing-the-control-flow-graph}@anchor{128}
+@anchor{cp/intro/tutorial03 visualizing-the-control-flow-graph}@anchor{134}
@subsubsection Visualizing the control flow graph
You can see the control flow graph of a function using
-@pxref{129,,gccjit;;function;;dump_to_dot()}:
+@pxref{135,,gccjit;;function;;dump_to_dot()}:
@example
func.dump_to_dot ("/tmp/sum-of-squares.dot");
@@ -10272,7 +10458,7 @@ install it with @cite{yum install python-xdot}):
@end quotation
@node Full example<4>,,Visualizing the control flow graph<2>,Tutorial part 3 Loops and variables<2>
-@anchor{cp/intro/tutorial03 full-example}@anchor{12a}
+@anchor{cp/intro/tutorial03 full-example}@anchor{136}
@subsubsection Full example
@@ -10455,7 +10641,7 @@ loop_test returned: 285
@c <http://www.gnu.org/licenses/>.
@node Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>,,Tutorial part 3 Loops and variables<2>,Tutorial<2>
-@anchor{cp/intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{12b}@anchor{cp/intro/tutorial04 doc}@anchor{12c}
+@anchor{cp/intro/tutorial04 tutorial-part-4-adding-jit-compilation-to-a-toy-interpreter}@anchor{137}@anchor{cp/intro/tutorial04 doc}@anchor{138}
@subsection Tutorial part 4: Adding JIT-compilation to a toy interpreter
@@ -10477,7 +10663,7 @@ to it.
@end menu
@node Our toy interpreter<2>,Compiling to machine code<2>,,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 our-toy-interpreter}@anchor{12d}
+@anchor{cp/intro/tutorial04 our-toy-interpreter}@anchor{139}
@subsubsection Our toy interpreter
@@ -10885,7 +11071,7 @@ toyvm_function::interpret (int arg, FILE *trace)
@end quotation
@node Compiling to machine code<2>,Setting things up<2>,Our toy interpreter<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 compiling-to-machine-code}@anchor{12e}
+@anchor{cp/intro/tutorial04 compiling-to-machine-code}@anchor{13a}
@subsubsection Compiling to machine code
@@ -10965,7 +11151,7 @@ This means our compiler has the following state:
@end quotation
@node Setting things up<2>,Populating the function<2>,Compiling to machine code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 setting-things-up}@anchor{12f}
+@anchor{cp/intro/tutorial04 setting-things-up}@anchor{13b}
@subsubsection Setting things up
@@ -11133,7 +11319,7 @@ We create the locals within the function.
@end quotation
@node Populating the function<2>,Verifying the control flow graph<2>,Setting things up<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 populating-the-function}@anchor{130}
+@anchor{cp/intro/tutorial04 populating-the-function}@anchor{13c}
@subsubsection Populating the function
@@ -11261,7 +11447,7 @@ stack into @code{y} instead erroneously assigned it to @code{x}, leaving @code{y
uninitialized.
To track this kind of thing down, we can use
-@pxref{131,,gccjit;;block;;add_comment()} to add descriptive comments
+@pxref{13d,,gccjit;;block;;add_comment()} to add descriptive comments
to the internal representation. This is invaluable when looking through
the generated IR for, say @code{factorial}:
@@ -11410,14 +11596,14 @@ to the next block.
This is analogous to simply incrementing the program counter.
@node Verifying the control flow graph<2>,Compiling the context<2>,Populating the function<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 verifying-the-control-flow-graph}@anchor{132}
+@anchor{cp/intro/tutorial04 verifying-the-control-flow-graph}@anchor{13e}
@subsubsection Verifying the control flow graph
Having finished looping over the blocks, the context is complete.
As before, we can verify that the control flow and statements are sane by
-using @pxref{129,,gccjit;;function;;dump_to_dot()}:
+using @pxref{135,,gccjit;;function;;dump_to_dot()}:
@example
fn.dump_to_dot ("/tmp/factorial.dot");
@@ -11441,7 +11627,7 @@ errors in our compiler.
@end quotation
@node Compiling the context<2>,Single-stepping through the generated code<2>,Verifying the control flow graph<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 compiling-the-context}@anchor{133}
+@anchor{cp/intro/tutorial04 compiling-the-context}@anchor{13f}
@subsubsection Compiling the context
@@ -11498,7 +11684,7 @@ private:
@end quotation
@node Single-stepping through the generated code<2>,Examining the generated code<2>,Compiling the context<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 single-stepping-through-the-generated-code}@anchor{134}
+@anchor{cp/intro/tutorial04 single-stepping-through-the-generated-code}@anchor{140}
@subsubsection Single-stepping through the generated code
@@ -11512,14 +11698,14 @@ It's possible to debug the generated code. To do this we need to both:
@item
Set up source code locations for our statements, so that we can
meaningfully step through the code. We did this above by
-calling @pxref{135,,gccjit;;context;;new_location()} and using the
+calling @pxref{141,,gccjit;;context;;new_location()} and using the
results.
@item
Enable the generation of debugging information, by setting
@pxref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
@code{gccjit::context} via
-@pxref{11a,,gccjit;;context;;set_bool_option()}:
+@pxref{126,,gccjit;;context;;set_bool_option()}:
@example
ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO, 1);
@@ -11591,14 +11777,14 @@ optimization level in a regular compiler.
@end cartouche
@node Examining the generated code<2>,Putting it all together<2>,Single-stepping through the generated code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 examining-the-generated-code}@anchor{136}
+@anchor{cp/intro/tutorial04 examining-the-generated-code}@anchor{142}
@subsubsection Examining the generated code
How good is the optimized code?
We can turn up optimizations, by calling
-@pxref{11b,,gccjit;;context;;set_int_option()} with
+@pxref{127,,gccjit;;context;;set_int_option()} with
@pxref{1f,,GCC_JIT_INT_OPTION_OPTIMIZATION_LEVEL}:
@example
@@ -11780,7 +11966,7 @@ Note that the stack pushing and popping have been eliminated, as has the
recursive call (in favor of an iteration).
@node Putting it all together<2>,Behind the curtain How does our code get optimized?<2>,Examining the generated code<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 putting-it-all-together}@anchor{137}
+@anchor{cp/intro/tutorial04 putting-it-all-together}@anchor{143}
@subsubsection Putting it all together
@@ -11813,7 +11999,7 @@ compiler result: 55
@noindent
@node Behind the curtain How does our code get optimized?<2>,,Putting it all together<2>,Tutorial part 4 Adding JIT-compilation to a toy interpreter<2>
-@anchor{cp/intro/tutorial04 behind-the-curtain-how-does-our-code-get-optimized}@anchor{138}
+@anchor{cp/intro/tutorial04 behind-the-curtain-how-does-our-code-get-optimized}@anchor{144}
@subsubsection Behind the curtain: How does our code get optimized?
@@ -12014,7 +12200,7 @@ representation: @code{initial}, @code{instr4} and @code{instr9}.
@end menu
@node Optimizing away stack manipulation<2>,Elimination of tail recursion<2>,,Behind the curtain How does our code get optimized?<2>
-@anchor{cp/intro/tutorial04 optimizing-away-stack-manipulation}@anchor{139}
+@anchor{cp/intro/tutorial04 optimizing-away-stack-manipulation}@anchor{145}
@subsubsection Optimizing away stack manipulation
@@ -12294,7 +12480,7 @@ instr9:
@noindent
@node Elimination of tail recursion<2>,,Optimizing away stack manipulation<2>,Behind the curtain How does our code get optimized?<2>
-@anchor{cp/intro/tutorial04 elimination-of-tail-recursion}@anchor{13a}
+@anchor{cp/intro/tutorial04 elimination-of-tail-recursion}@anchor{146}
@subsubsection Elimination of tail recursion
@@ -12381,7 +12567,7 @@ instr9:
@c <http://www.gnu.org/licenses/>.
@node Topic Reference<2>,,Tutorial<2>,C++ bindings for libgccjit
-@anchor{cp/topics/index doc}@anchor{13b}@anchor{cp/topics/index topic-reference}@anchor{13c}
+@anchor{cp/topics/index doc}@anchor{147}@anchor{cp/topics/index topic-reference}@anchor{148}
@section Topic Reference
@@ -12442,10 +12628,12 @@ Expressions
Rvalues
* Simple expressions: Simple expressions<2>.
+* Vector expressions: Vector expressions<2>.
* Unary Operations: Unary Operations<2>.
* Binary Operations: Binary Operations<2>.
* Comparisons: Comparisons<2>.
* Function calls: Function calls<2>.
+* Function pointers: Function pointers<3>.
* Type-coercion: Type-coercion<2>.
Lvalues
@@ -12472,22 +12660,22 @@ Compiling a context
@node Compilation contexts<2>,Objects<2>,,Topic Reference<2>
-@anchor{cp/topics/contexts compilation-contexts}@anchor{13d}@anchor{cp/topics/contexts doc}@anchor{13e}
+@anchor{cp/topics/contexts compilation-contexts}@anchor{149}@anchor{cp/topics/contexts doc}@anchor{14a}
@subsection Compilation contexts
@geindex gccjit;;context (C++ class)
-@anchor{cp/topics/contexts gccjit context}@anchor{13f}
+@anchor{cp/topics/contexts gccjit context}@anchor{14b}
@deffn {C++ Class} gccjit::context
@end deffn
-The top-level of the C++ API is the @pxref{13f,,gccjit;;context} type.
+The top-level of the C++ API is the @pxref{14b,,gccjit;;context} type.
-A @pxref{13f,,gccjit;;context} instance encapsulates the state of a
+A @pxref{14b,,gccjit;;context} instance encapsulates the state of a
compilation.
You can set up options on it, and add types, functions and code.
-Invoking @pxref{118,,gccjit;;context;;compile()} on it gives you a
+Invoking @pxref{124,,gccjit;;context;;compile()} on it gives you a
@pxref{16,,gcc_jit_result *}.
It is a thin wrapper around the C API's @pxref{8,,gcc_jit_context *}.
@@ -12502,7 +12690,7 @@ It is a thin wrapper around the C API's @pxref{8,,gcc_jit_context *}.
@end menu
@node Lifetime-management<2>,Thread-safety<2>,,Compilation contexts<2>
-@anchor{cp/topics/contexts lifetime-management}@anchor{140}
+@anchor{cp/topics/contexts lifetime-management}@anchor{14c}
@subsubsection Lifetime-management
@@ -12511,16 +12699,16 @@ have their lifetime bounded by the context they are created within, and
cleanup of such objects is done for you when the context is released.
@geindex gccjit;;context;;acquire (C++ function)
-@anchor{cp/topics/contexts gccjit context acquire}@anchor{112}
+@anchor{cp/topics/contexts gccjit context acquire}@anchor{11e}
@deffn {C++ Function} gccjit::context gccjit::context::acquire ()
-This function acquires a new @pxref{13f,,gccjit;;context} instance,
+This function acquires a new @pxref{14b,,gccjit;;context} instance,
which is independent of any others that may be present within this
process.
@end deffn
@geindex gccjit;;context;;release (C++ function)
-@anchor{cp/topics/contexts gccjit context release}@anchor{114}
+@anchor{cp/topics/contexts gccjit context release}@anchor{120}
@deffn {C++ Function} void gccjit::context::release ()
This function releases all resources associated with the given context.
@@ -12539,7 +12727,7 @@ ctxt.release ();
@end deffn
@geindex gccjit;;context;;new_child_context (C++ function)
-@anchor{cp/topics/contexts gccjit context new_child_context}@anchor{141}
+@anchor{cp/topics/contexts gccjit context new_child_context}@anchor{14d}
@deffn {C++ Function} gccjit::context gccjit::context::new_child_context ()
Given an existing JIT context, create a child context.
@@ -12571,16 +12759,16 @@ there will likely be a performance hit for such nesting.
@end deffn
@node Thread-safety<2>,Error-handling<3>,Lifetime-management<2>,Compilation contexts<2>
-@anchor{cp/topics/contexts thread-safety}@anchor{142}
+@anchor{cp/topics/contexts thread-safety}@anchor{14e}
@subsubsection Thread-safety
-Instances of @pxref{13f,,gccjit;;context} created via
-@pxref{112,,gccjit;;context;;acquire()} are independent from each other:
+Instances of @pxref{14b,,gccjit;;context} created via
+@pxref{11e,,gccjit;;context;;acquire()} are independent from each other:
only one thread may use a given context at once, but multiple threads
could each have their own contexts without needing locks.
-Contexts created via @pxref{141,,gccjit;;context;;new_child_context()} are
+Contexts created via @pxref{14d,,gccjit;;context;;new_child_context()} are
related to their parent context. They can be partitioned by their
ultimate ancestor into independent "family trees". Only one thread
within a process may use a given "family tree" of such contexts at once,
@@ -12588,7 +12776,7 @@ and if you're using multiple threads you should provide your own locking
around entire such context partitions.
@node Error-handling<3>,Debugging<2>,Thread-safety<2>,Compilation contexts<2>
-@anchor{cp/topics/contexts error-handling}@anchor{143}
+@anchor{cp/topics/contexts error-handling}@anchor{14f}
@subsubsection Error-handling
@@ -12601,10 +12789,10 @@ NULL. You don't have to check everywhere for NULL results, since the
API gracefully handles a NULL being passed in for any argument.
Errors are printed on stderr and can be queried using
-@pxref{144,,gccjit;;context;;get_first_error()}.
+@pxref{150,,gccjit;;context;;get_first_error()}.
@geindex gccjit;;context;;get_first_error (C++ function)
-@anchor{cp/topics/contexts gccjit context get_first_error__gccjit contextP}@anchor{144}
+@anchor{cp/topics/contexts gccjit context get_first_error__gccjit contextP}@anchor{150}
@deffn {C++ Function} const char* gccjit::context::get_first_error (gccjit::context* ctxt)
Returns the first error message that occurred on the context.
@@ -12616,18 +12804,18 @@ If no errors occurred, this will be NULL.
@end deffn
@node Debugging<2>,Options<4>,Error-handling<3>,Compilation contexts<2>
-@anchor{cp/topics/contexts debugging}@anchor{145}
+@anchor{cp/topics/contexts debugging}@anchor{151}
@subsubsection Debugging
@geindex gccjit;;context;;dump_to_file (C++ function)
-@anchor{cp/topics/contexts gccjit context dump_to_file__ssCR i}@anchor{146}
+@anchor{cp/topics/contexts gccjit context dump_to_file__ssCR i}@anchor{152}
@deffn {C++ Function} void gccjit::context::dump_to_file (const std::string& path, int update_locations)
To help with debugging: dump a C-like representation to the given path,
describing what's been set up on the context.
-If "update_locations" is true, then also set up @pxref{147,,gccjit;;location}
+If "update_locations" is true, then also set up @pxref{153,,gccjit;;location}
information throughout the context, pointing at the dump file as if it
were a source file. This may be of use in conjunction with
@code{GCCJIT::BOOL_OPTION_DEBUGINFO} to allow stepping through the
@@ -12635,7 +12823,7 @@ code in a debugger.
@end deffn
@geindex gccjit;;context;;dump_reproducer_to_file (C++ function)
-@anchor{cp/topics/contexts gccjit context dump_reproducer_to_file__gcc_jit_contextP cCP}@anchor{148}
+@anchor{cp/topics/contexts gccjit context dump_reproducer_to_file__gcc_jit_contextP cCP}@anchor{154}
@deffn {C++ Function} void gccjit::context::dump_reproducer_to_file (gcc_jit_context* ctxt, const char* path)
This is a thin wrapper around the C API
@@ -12647,7 +12835,7 @@ for seeing what the C++ bindings are doing at the C level.
@end deffn
@node Options<4>,,Debugging<2>,Compilation contexts<2>
-@anchor{cp/topics/contexts options}@anchor{149}
+@anchor{cp/topics/contexts options}@anchor{155}
@subsubsection Options
@@ -12660,12 +12848,12 @@ for seeing what the C++ bindings are doing at the C level.
@end menu
@node String Options<2>,Boolean options<2>,,Options<4>
-@anchor{cp/topics/contexts string-options}@anchor{14a}
+@anchor{cp/topics/contexts string-options}@anchor{156}
@subsubsection String Options
@geindex gccjit;;context;;set_str_option (C++ function)
-@anchor{cp/topics/contexts gccjit context set_str_option__enum cCP}@anchor{14b}
+@anchor{cp/topics/contexts gccjit context set_str_option__enum cCP}@anchor{157}
@deffn {C++ Function} void gccjit::context::set_str_option (enum gcc_jit_str_option, const char* value)
Set a string option of the context.
@@ -12676,12 +12864,12 @@ meaning.
@end deffn
@node Boolean options<2>,Integer options<2>,String Options<2>,Options<4>
-@anchor{cp/topics/contexts boolean-options}@anchor{14c}
+@anchor{cp/topics/contexts boolean-options}@anchor{158}
@subsubsection Boolean options
@geindex gccjit;;context;;set_bool_option (C++ function)
-@anchor{cp/topics/contexts gccjit context set_bool_option__enum i}@anchor{11a}
+@anchor{cp/topics/contexts gccjit context set_bool_option__enum i}@anchor{126}
@deffn {C++ Function} void gccjit::context::set_bool_option (enum gcc_jit_bool_option, int value)
Set a boolean option of the context.
@@ -12692,7 +12880,7 @@ meaning.
@end deffn
@geindex gccjit;;context;;set_bool_allow_unreachable_blocks (C++ function)
-@anchor{cp/topics/contexts gccjit context set_bool_allow_unreachable_blocks__i}@anchor{14d}
+@anchor{cp/topics/contexts gccjit context set_bool_allow_unreachable_blocks__i}@anchor{159}
@deffn {C++ Function} void gccjit::context::set_bool_allow_unreachable_blocks (int bool_value)
By default, libgccjit will issue an error about unreachable blocks
@@ -12713,7 +12901,7 @@ its presence using
@end deffn
@geindex gccjit;;context;;set_bool_use_external_driver (C++ function)
-@anchor{cp/topics/contexts gccjit context set_bool_use_external_driver__i}@anchor{14e}
+@anchor{cp/topics/contexts gccjit context set_bool_use_external_driver__i}@anchor{15a}
@deffn {C++ Function} void gccjit::context::set_bool_use_external_driver (int bool_value)
libgccjit internally generates assembler, and uses "driver" code
@@ -12737,12 +12925,12 @@ its presence using
@end deffn
@node Integer options<2>,Additional command-line options<2>,Boolean options<2>,Options<4>
-@anchor{cp/topics/contexts integer-options}@anchor{14f}
+@anchor{cp/topics/contexts integer-options}@anchor{15b}
@subsubsection Integer options
@geindex gccjit;;context;;set_int_option (C++ function)
-@anchor{cp/topics/contexts gccjit context set_int_option__enum i}@anchor{11b}
+@anchor{cp/topics/contexts gccjit context set_int_option__enum i}@anchor{127}
@deffn {C++ Function} void gccjit::context::set_int_option (enum gcc_jit_int_option, int value)
Set an integer option of the context.
@@ -12753,12 +12941,12 @@ meaning.
@end deffn
@node Additional command-line options<2>,,Integer options<2>,Options<4>
-@anchor{cp/topics/contexts additional-command-line-options}@anchor{150}
+@anchor{cp/topics/contexts additional-command-line-options}@anchor{15c}
@subsubsection Additional command-line options
@geindex gccjit;;context;;add_command_line_option (C++ function)
-@anchor{cp/topics/contexts gccjit context add_command_line_option__cCP}@anchor{151}
+@anchor{cp/topics/contexts gccjit context add_command_line_option__cCP}@anchor{15d}
@deffn {C++ Function} void gccjit::context::add_command_line_option (const char* optname)
Add an arbitrary gcc command-line option to the context for use
@@ -12795,18 +12983,18 @@ its presence using
@c <http://www.gnu.org/licenses/>.
@node Objects<2>,Types<2>,Compilation contexts<2>,Topic Reference<2>
-@anchor{cp/topics/objects objects}@anchor{152}@anchor{cp/topics/objects doc}@anchor{153}
+@anchor{cp/topics/objects objects}@anchor{15e}@anchor{cp/topics/objects doc}@anchor{15f}
@subsection Objects
@geindex gccjit;;object (C++ class)
-@anchor{cp/topics/objects gccjit object}@anchor{154}
+@anchor{cp/topics/objects gccjit object}@anchor{160}
@deffn {C++ Class} gccjit::object
@end deffn
Almost every entity in the API (with the exception of
-@pxref{13f,,gccjit;;context} and @pxref{16,,gcc_jit_result *}) is a
-"contextual" object, a @pxref{154,,gccjit;;object}.
+@pxref{14b,,gccjit;;context} and @pxref{16,,gcc_jit_result *}) is a
+"contextual" object, a @pxref{160,,gccjit;;object}.
A JIT object:
@@ -12816,7 +13004,7 @@ A JIT object:
@itemize *
@item
-is associated with a @pxref{13f,,gccjit;;context}.
+is associated with a @pxref{14b,,gccjit;;context}.
@item
is automatically cleaned up for you when its context is released so
@@ -12843,17 +13031,17 @@ The C++ class hierarchy within the @code{gccjit} namespace looks like this:
@noindent
-The @pxref{154,,gccjit;;object} base class has the following operations:
+The @pxref{160,,gccjit;;object} base class has the following operations:
@geindex gccjit;;object;;get_context (C++ function)
-@anchor{cp/topics/objects gccjit object get_contextC}@anchor{155}
+@anchor{cp/topics/objects gccjit object get_contextC}@anchor{161}
@deffn {C++ Function} gccjit::context gccjit::object::get_context () const
Which context is the obj within?
@end deffn
@geindex gccjit;;object;;get_debug_string (C++ function)
-@anchor{cp/topics/objects gccjit object get_debug_stringC}@anchor{115}
+@anchor{cp/topics/objects gccjit object get_debug_stringC}@anchor{121}
@deffn {C++ Function} std::string gccjit::object::get_debug_string () const
Generate a human-readable description for the given object.
@@ -12893,16 +13081,16 @@ obj: 4.0 * (float)i
@c <http://www.gnu.org/licenses/>.
@node Types<2>,Expressions<2>,Objects<2>,Topic Reference<2>
-@anchor{cp/topics/types doc}@anchor{156}@anchor{cp/topics/types types}@anchor{157}
+@anchor{cp/topics/types doc}@anchor{162}@anchor{cp/topics/types types}@anchor{163}
@subsection Types
@geindex gccjit;;type (C++ class)
-@anchor{cp/topics/types gccjit type}@anchor{158}
+@anchor{cp/topics/types gccjit type}@anchor{164}
@deffn {C++ Class} gccjit::type
gccjit::type represents a type within the library. It is a subclass
-of @pxref{154,,gccjit;;object}.
+of @pxref{160,,gccjit;;object}.
@end deffn
Types can be created in several ways:
@@ -12912,7 +13100,7 @@ Types can be created in several ways:
@item
fundamental types can be accessed using
-@pxref{113,,gccjit;;context;;get_type()}:
+@pxref{11f,,gccjit;;context;;get_type()}:
@example
gccjit::type int_type = ctxt.get_type (GCC_JIT_TYPE_INT);
@@ -12932,7 +13120,7 @@ See @pxref{b,,gcc_jit_context_get_type()} for the available types.
@item
derived types can be accessed by using functions such as
-@pxref{159,,gccjit;;type;;get_pointer()} and @pxref{15a,,gccjit;;type;;get_const()}:
+@pxref{165,,gccjit;;type;;get_pointer()} and @pxref{166,,gccjit;;type;;get_const()}:
@example
gccjit::type const_int_star = int_type.get_const ().get_pointer ();
@@ -12954,12 +13142,12 @@ by creating structures (see below).
@end menu
@node Standard types<2>,Pointers const and volatile<2>,,Types<2>
-@anchor{cp/topics/types standard-types}@anchor{15b}
+@anchor{cp/topics/types standard-types}@anchor{167}
@subsubsection Standard types
@geindex gccjit;;context;;get_type (C++ function)
-@anchor{cp/topics/types gccjit context get_type__enum}@anchor{113}
+@anchor{cp/topics/types gccjit context get_type__enum}@anchor{11f}
@deffn {C++ Function} gccjit::type gccjit::context::get_type (enum gcc_jit_types)
Access a specific type. This is a thin wrapper around
@@ -12967,14 +13155,14 @@ Access a specific type. This is a thin wrapper around
@end deffn
@geindex gccjit;;context;;get_int_type (C++ function)
-@anchor{cp/topics/types gccjit context get_int_type__s i}@anchor{15c}
+@anchor{cp/topics/types gccjit context get_int_type__s i}@anchor{168}
@deffn {C++ Function} gccjit::type gccjit::context::get_int_type (size_t num_bytes, int is_signed)
Access the integer type of the given size.
@end deffn
@geindex gccjit;;context;;get_int_type<T> (C++ function)
-@anchor{cp/topics/types gccjit context get_int_type T}@anchor{15d}
+@anchor{cp/topics/types gccjit context get_int_type T}@anchor{169}
@deffn {C++ Function} gccjit::type gccjit::context::get_int_type<T> ()
Access the given integer type. For example, you could map the
@@ -12988,33 +13176,33 @@ gccjit::type t = ctxt.get_int_type <unsigned short> ();
@end deffn
@node Pointers const and volatile<2>,Vector types<2>,Standard types<2>,Types<2>
-@anchor{cp/topics/types pointers-const-and-volatile}@anchor{15e}
+@anchor{cp/topics/types pointers-const-and-volatile}@anchor{16a}
@subsubsection Pointers, @cite{const}, and @cite{volatile}
@geindex gccjit;;type;;get_pointer (C++ function)
-@anchor{cp/topics/types gccjit type get_pointer}@anchor{159}
+@anchor{cp/topics/types gccjit type get_pointer}@anchor{165}
@deffn {C++ Function} gccjit::type gccjit::type::get_pointer ()
Given type "T", get type "T*".
@end deffn
@geindex gccjit;;type;;get_const (C++ function)
-@anchor{cp/topics/types gccjit type get_const}@anchor{15a}
+@anchor{cp/topics/types gccjit type get_const}@anchor{166}
@deffn {C++ Function} gccjit::type gccjit::type::get_const ()
Given type "T", get type "const T".
@end deffn
@geindex gccjit;;type;;get_volatile (C++ function)
-@anchor{cp/topics/types gccjit type get_volatile}@anchor{15f}
+@anchor{cp/topics/types gccjit type get_volatile}@anchor{16b}
@deffn {C++ Function} gccjit::type gccjit::type::get_volatile ()
Given type "T", get type "volatile T".
@end deffn
@geindex gccjit;;type;;get_aligned (C++ function)
-@anchor{cp/topics/types gccjit type get_aligned__s}@anchor{160}
+@anchor{cp/topics/types gccjit type get_aligned__s}@anchor{16c}
@deffn {C++ Function} gccjit::type gccjit::type::get_aligned (size_t alignment_in_bytes)
Given type "T", get type:
@@ -13029,7 +13217,7 @@ The alignment must be a power of two.
@end deffn
@geindex gccjit;;context;;new_array_type (C++ function)
-@anchor{cp/topics/types gccjit context new_array_type__gccjit type i gccjit location}@anchor{161}
+@anchor{cp/topics/types gccjit context new_array_type__gccjit type i gccjit location}@anchor{16d}
@deffn {C++ Function} gccjit::type gccjit::context::new_array_type (gccjit::type element_type, int num_elements, gccjit::location loc)
Given type "T", get type "T[N]" (for a constant N).
@@ -13037,12 +13225,12 @@ Param "loc" is optional.
@end deffn
@node Vector types<2>,Structures and unions<2>,Pointers const and volatile<2>,Types<2>
-@anchor{cp/topics/types vector-types}@anchor{162}
+@anchor{cp/topics/types vector-types}@anchor{16e}
@subsubsection Vector types
@geindex gccjit;;type;;get_vector (C++ function)
-@anchor{cp/topics/types gccjit type get_vector__s}@anchor{163}
+@anchor{cp/topics/types gccjit type get_vector__s}@anchor{16f}
@deffn {C++ Function} gccjit::type gccjit::type::get_vector (size_t num_units)
Given type "T", get type:
@@ -13057,31 +13245,31 @@ T must be integral or floating point; num_units must be a power of two.
@end deffn
@node Structures and unions<2>,,Vector types<2>,Types<2>
-@anchor{cp/topics/types structures-and-unions}@anchor{164}
+@anchor{cp/topics/types structures-and-unions}@anchor{170}
@subsubsection Structures and unions
@geindex gccjit;;struct_ (C++ class)
-@anchor{cp/topics/types gccjit struct_}@anchor{165}
+@anchor{cp/topics/types gccjit struct_}@anchor{171}
@deffn {C++ Class} gccjit::struct_
@end deffn
A compound type analagous to a C @cite{struct}.
-@pxref{165,,gccjit;;struct_} is a subclass of @pxref{158,,gccjit;;type} (and thus
-of @pxref{154,,gccjit;;object} in turn).
+@pxref{171,,gccjit;;struct_} is a subclass of @pxref{164,,gccjit;;type} (and thus
+of @pxref{160,,gccjit;;object} in turn).
@geindex gccjit;;field (C++ class)
-@anchor{cp/topics/types gccjit field}@anchor{166}
+@anchor{cp/topics/types gccjit field}@anchor{172}
@deffn {C++ Class} gccjit::field
@end deffn
-A field within a @pxref{165,,gccjit;;struct_}.
+A field within a @pxref{171,,gccjit;;struct_}.
-@pxref{166,,gccjit;;field} is a subclass of @pxref{154,,gccjit;;object}.
+@pxref{172,,gccjit;;field} is a subclass of @pxref{160,,gccjit;;object}.
-You can model C @cite{struct} types by creating @pxref{165,,gccjit;;struct_} and
-@pxref{166,,gccjit;;field} instances, in either order:
+You can model C @cite{struct} types by creating @pxref{171,,gccjit;;struct_} and
+@pxref{172,,gccjit;;field} instances, in either order:
@itemize *
@@ -13137,14 +13325,14 @@ node.set_fields (fields);
@c FIXME: the above API doesn't seem to exist yet
@geindex gccjit;;context;;new_field (C++ function)
-@anchor{cp/topics/types gccjit context new_field__gccjit type cCP gccjit location}@anchor{167}
+@anchor{cp/topics/types gccjit context new_field__gccjit type cCP gccjit location}@anchor{173}
@deffn {C++ Function} gccjit::field gccjit::context::new_field (gccjit::type type, const char* name, gccjit::location loc)
Construct a new field, with the given type and name.
@end deffn
@geindex gccjit;;context;;new_struct_type (C++ function)
-@anchor{cp/topics/types gccjit context new_struct_type__ssCR std vector field R gccjit location}@anchor{168}
+@anchor{cp/topics/types gccjit context new_struct_type__ssCR std vector field R gccjit location}@anchor{174}
@deffn {C++ Function} gccjit::struct_ gccjit::context::new_struct_type (const std::string& name, std::vector<field>& fields, gccjit::location loc)
@quotation
@@ -13154,13 +13342,13 @@ Construct a new struct type, with the given name and fields.
@end deffn
@geindex gccjit;;context;;new_opaque_struct (C++ function)
-@anchor{cp/topics/types gccjit context new_opaque_struct__ssCR gccjit location}@anchor{169}
+@anchor{cp/topics/types gccjit context new_opaque_struct__ssCR gccjit location}@anchor{175}
@deffn {C++ Function} gccjit::struct_ gccjit::context::new_opaque_struct (const std::string& name, gccjit::location loc)
Construct a new struct type, with the given name, but without
specifying the fields. The fields can be omitted (in which case the
size of the struct is not known), or later specified using
-@pxref{8c,,gcc_jit_struct_set_fields()}.
+@pxref{8d,,gcc_jit_struct_set_fields()}.
@end deffn
@c Copyright (C) 2014-2017 Free Software Foundation, Inc.
@@ -13181,7 +13369,7 @@ size of the struct is not known), or later specified using
@c <http://www.gnu.org/licenses/>.
@node Expressions<2>,Creating and using functions<2>,Types<2>,Topic Reference<2>
-@anchor{cp/topics/expressions expressions}@anchor{16a}@anchor{cp/topics/expressions doc}@anchor{16b}
+@anchor{cp/topics/expressions expressions}@anchor{176}@anchor{cp/topics/expressions doc}@anchor{177}
@subsection Expressions
@@ -13193,10 +13381,12 @@ size of the struct is not known), or later specified using
Rvalues
* Simple expressions: Simple expressions<2>.
+* Vector expressions: Vector expressions<2>.
* Unary Operations: Unary Operations<2>.
* Binary Operations: Binary Operations<2>.
* Comparisons: Comparisons<2>.
* Function calls: Function calls<2>.
+* Function pointers: Function pointers<3>.
* Type-coercion: Type-coercion<2>.
Lvalues
@@ -13207,17 +13397,17 @@ Lvalues
@node Rvalues<2>,Lvalues<2>,,Expressions<2>
-@anchor{cp/topics/expressions rvalues}@anchor{16c}
+@anchor{cp/topics/expressions rvalues}@anchor{178}
@subsubsection Rvalues
@geindex gccjit;;rvalue (C++ class)
-@anchor{cp/topics/expressions gccjit rvalue}@anchor{16d}
+@anchor{cp/topics/expressions gccjit rvalue}@anchor{179}
@deffn {C++ Class} gccjit::rvalue
@end deffn
-A @pxref{16d,,gccjit;;rvalue} is an expression that can be computed. It is a
-subclass of @pxref{154,,gccjit;;object}, and is a thin wrapper around
+A @pxref{179,,gccjit;;rvalue} is an expression that can be computed. It is a
+subclass of @pxref{160,,gccjit;;object}, and is a thin wrapper around
@pxref{13,,gcc_jit_rvalue *} from the C API.
It can be simple, e.g.:
@@ -13263,7 +13453,7 @@ Every rvalue has an associated type, and the API will check to ensure
that types match up correctly (otherwise the context will emit an error).
@geindex gccjit;;rvalue;;get_type (C++ function)
-@anchor{cp/topics/expressions gccjit rvalue get_type}@anchor{16e}
+@anchor{cp/topics/expressions gccjit rvalue get_type}@anchor{17a}
@deffn {C++ Function} gccjit::type gccjit::rvalue::get_type ()
Get the type of this rvalue.
@@ -13271,21 +13461,23 @@ Get the type of this rvalue.
@menu
* Simple expressions: Simple expressions<2>.
+* Vector expressions: Vector expressions<2>.
* Unary Operations: Unary Operations<2>.
* Binary Operations: Binary Operations<2>.
* Comparisons: Comparisons<2>.
* Function calls: Function calls<2>.
+* Function pointers: Function pointers<3>.
* Type-coercion: Type-coercion<2>.
@end menu
-@node Simple expressions<2>,Unary Operations<2>,,Rvalues<2>
-@anchor{cp/topics/expressions simple-expressions}@anchor{16f}
+@node Simple expressions<2>,Vector expressions<2>,,Rvalues<2>
+@anchor{cp/topics/expressions simple-expressions}@anchor{17b}
@subsubsection Simple expressions
@geindex gccjit;;context;;new_rvalue (C++ function)
-@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type iC}@anchor{127}
+@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type iC}@anchor{133}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_rvalue (gccjit::type numeric_type, int value) const
Given a numeric type (integer or floating point), build an rvalue for
@@ -13293,7 +13485,7 @@ the given constant @code{int} value.
@end deffn
@geindex gccjit;;context;;new_rvalue (C++ function)
-@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type lC}@anchor{170}
+@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type lC}@anchor{17c}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_rvalue (gccjit::type numeric_type, long value) const
Given a numeric type (integer or floating point), build an rvalue for
@@ -13301,7 +13493,7 @@ the given constant @code{long} value.
@end deffn
@geindex gccjit;;context;;zero (C++ function)
-@anchor{cp/topics/expressions gccjit context zero__gccjit typeC}@anchor{123}
+@anchor{cp/topics/expressions gccjit context zero__gccjit typeC}@anchor{12f}
@deffn {C++ Function} gccjit::rvalue gccjit::context::zero (gccjit::type numeric_type) const
Given a numeric type (integer or floating point), get the rvalue for
@@ -13315,7 +13507,7 @@ ctxt.new_rvalue (numeric_type, 0)
@end deffn
@geindex gccjit;;context;;one (C++ function)
-@anchor{cp/topics/expressions gccjit context one__gccjit typeC}@anchor{171}
+@anchor{cp/topics/expressions gccjit context one__gccjit typeC}@anchor{17d}
@deffn {C++ Function} gccjit::rvalue gccjit::context::one (gccjit::type numeric_type) const
Given a numeric type (integer or floating point), get the rvalue for
@@ -13329,7 +13521,7 @@ ctxt.new_rvalue (numeric_type, 1)
@end deffn
@geindex gccjit;;context;;new_rvalue (C++ function)
-@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type doubleC}@anchor{172}
+@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type doubleC}@anchor{17e}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_rvalue (gccjit::type numeric_type, double value) const
Given a numeric type (integer or floating point), build an rvalue for
@@ -13337,27 +13529,42 @@ the given constant @code{double} value.
@end deffn
@geindex gccjit;;context;;new_rvalue (C++ function)
-@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type voidPC}@anchor{173}
+@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type voidPC}@anchor{17f}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_rvalue (gccjit::type pointer_type, void* value) const
Given a pointer type, build an rvalue for the given address.
@end deffn
@geindex gccjit;;context;;new_rvalue (C++ function)
-@anchor{cp/topics/expressions gccjit context new_rvalue__ssCRC}@anchor{174}
+@anchor{cp/topics/expressions gccjit context new_rvalue__ssCRC}@anchor{180}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_rvalue (const std::string& value) const
Generate an rvalue of type @code{GCC_JIT_TYPE_CONST_CHAR_PTR} for
the given string. This is akin to a string literal.
@end deffn
-@node Unary Operations<2>,Binary Operations<2>,Simple expressions<2>,Rvalues<2>
-@anchor{cp/topics/expressions unary-operations}@anchor{175}
+@node Vector expressions<2>,Unary Operations<2>,Simple expressions<2>,Rvalues<2>
+@anchor{cp/topics/expressions vector-expressions}@anchor{181}
+@subsubsection Vector expressions
+
+
+@geindex gccjit;;context;;new_rvalue (C++ function)
+@anchor{cp/topics/expressions gccjit context new_rvalue__gccjit type std vector gccjit rvalue C}@anchor{182}
+@deffn {C++ Function} gccjit::rvalue gccjit::context::new_rvalue (gccjit::type vector_type, std::vector<gccjit::rvalue> elements) const
+
+Given a vector type, and a vector of scalar rvalue elements, generate a
+vector rvalue.
+
+The number of elements needs to match that of the vector type.
+@end deffn
+
+@node Unary Operations<2>,Binary Operations<2>,Vector expressions<2>,Rvalues<2>
+@anchor{cp/topics/expressions unary-operations}@anchor{183}
@subsubsection Unary Operations
@geindex gccjit;;context;;new_unary_op (C++ function)
-@anchor{cp/topics/expressions gccjit context new_unary_op__enum gccjit type gccjit rvalue gccjit location}@anchor{176}
+@anchor{cp/topics/expressions gccjit context new_unary_op__enum gccjit type gccjit rvalue gccjit location}@anchor{184}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_unary_op (enum gcc_jit_unary_op, gccjit::type result_type, gccjit::rvalue rvalue, gccjit::location loc)
Build a unary operation out of an input rvalue.
@@ -13365,7 +13572,7 @@ Build a unary operation out of an input rvalue.
Parameter @code{loc} is optional.
This is a thin wrapper around the C API's
-@pxref{99,,gcc_jit_context_new_unary_op()} and the available unary
+@pxref{9e,,gcc_jit_context_new_unary_op()} and the available unary
operations are documented there.
@end deffn
@@ -13373,7 +13580,7 @@ There are shorter ways to spell the various specific kinds of unary
operation:
@geindex gccjit;;context;;new_minus (C++ function)
-@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit location}@anchor{177}
+@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit location}@anchor{185}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_minus (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc)
Negate an arithmetic value; for example:
@@ -13394,7 +13601,7 @@ builds the equivalent of this C expression:
@end deffn
@geindex new_bitwise_negate (C++ function)
-@anchor{cp/topics/expressions new_bitwise_negate__gccjit type gccjit rvalue gccjit location}@anchor{178}
+@anchor{cp/topics/expressions new_bitwise_negate__gccjit type gccjit rvalue gccjit location}@anchor{186}
@deffn {C++ Function} gccjit::rvalue new_bitwise_negate (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc)
Bitwise negation of an integer value (one's complement); for example:
@@ -13415,7 +13622,7 @@ builds the equivalent of this C expression:
@end deffn
@geindex new_logical_negate (C++ function)
-@anchor{cp/topics/expressions new_logical_negate__gccjit type gccjit rvalue gccjit location}@anchor{179}
+@anchor{cp/topics/expressions new_logical_negate__gccjit type gccjit rvalue gccjit location}@anchor{187}
@deffn {C++ Function} gccjit::rvalue new_logical_negate (gccjit::type result_type, gccjit::rvalue a, gccjit::location loc)
Logical negation of an arithmetic or pointer value; for example:
@@ -13438,7 +13645,7 @@ builds the equivalent of this C expression:
The most concise way to spell them is with overloaded operators:
@geindex operator- (C++ function)
-@anchor{cp/topics/expressions sub-operator__gccjit rvalue}@anchor{17a}
+@anchor{cp/topics/expressions sub-operator__gccjit rvalue}@anchor{188}
@deffn {C++ Function} gccjit::rvalue operator- (gccjit::rvalue a)
@example
@@ -13449,7 +13656,7 @@ gccjit::rvalue negpi = -pi;
@end deffn
@geindex operator~ (C++ function)
-@anchor{cp/topics/expressions inv-operator__gccjit rvalue}@anchor{17b}
+@anchor{cp/topics/expressions inv-operator__gccjit rvalue}@anchor{189}
@deffn {C++ Function} gccjit::rvalue operator~ (gccjit::rvalue a)
@example
@@ -13460,7 +13667,7 @@ gccjit::rvalue mask = ~a;
@end deffn
@geindex operator! (C++ function)
-@anchor{cp/topics/expressions not-operator__gccjit rvalue}@anchor{17c}
+@anchor{cp/topics/expressions not-operator__gccjit rvalue}@anchor{18a}
@deffn {C++ Function} gccjit::rvalue operator! (gccjit::rvalue a)
@example
@@ -13471,12 +13678,12 @@ gccjit::rvalue guard = !cond;
@end deffn
@node Binary Operations<2>,Comparisons<2>,Unary Operations<2>,Rvalues<2>
-@anchor{cp/topics/expressions binary-operations}@anchor{17d}
+@anchor{cp/topics/expressions binary-operations}@anchor{18b}
@subsubsection Binary Operations
@geindex gccjit;;context;;new_binary_op (C++ function)
-@anchor{cp/topics/expressions gccjit context new_binary_op__enum gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{117}
+@anchor{cp/topics/expressions gccjit context new_binary_op__enum gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{123}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_binary_op (enum gcc_jit_binary_op, gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
Build a binary operation out of two constituent rvalues.
@@ -13492,59 +13699,59 @@ There are shorter ways to spell the various specific kinds of binary
operation:
@geindex gccjit;;context;;new_plus (C++ function)
-@anchor{cp/topics/expressions gccjit context new_plus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{17e}
+@anchor{cp/topics/expressions gccjit context new_plus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{18c}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_plus (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_minus (C++ function)
-@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{17f}
+@anchor{cp/topics/expressions gccjit context new_minus__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{18d}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_minus (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_mult (C++ function)
-@anchor{cp/topics/expressions gccjit context new_mult__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{180}
+@anchor{cp/topics/expressions gccjit context new_mult__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{18e}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_mult (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_divide (C++ function)
-@anchor{cp/topics/expressions gccjit context new_divide__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{181}
+@anchor{cp/topics/expressions gccjit context new_divide__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{18f}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_divide (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_modulo (C++ function)
-@anchor{cp/topics/expressions gccjit context new_modulo__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{182}
+@anchor{cp/topics/expressions gccjit context new_modulo__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{190}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_modulo (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_bitwise_and (C++ function)
-@anchor{cp/topics/expressions gccjit context new_bitwise_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{183}
+@anchor{cp/topics/expressions gccjit context new_bitwise_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{191}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_bitwise_and (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_bitwise_xor (C++ function)
-@anchor{cp/topics/expressions gccjit context new_bitwise_xor__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{184}
+@anchor{cp/topics/expressions gccjit context new_bitwise_xor__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{192}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_bitwise_xor (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_bitwise_or (C++ function)
-@anchor{cp/topics/expressions gccjit context new_bitwise_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{185}
+@anchor{cp/topics/expressions gccjit context new_bitwise_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{193}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_bitwise_or (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_logical_and (C++ function)
-@anchor{cp/topics/expressions gccjit context new_logical_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{186}
+@anchor{cp/topics/expressions gccjit context new_logical_and__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{194}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_logical_and (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_logical_or (C++ function)
-@anchor{cp/topics/expressions gccjit context new_logical_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{187}
+@anchor{cp/topics/expressions gccjit context new_logical_or__gccjit type gccjit rvalue gccjit rvalue gccjit location}@anchor{195}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_logical_or (gccjit::type result_type, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
The most concise way to spell them is with overloaded operators:
@geindex operator+ (C++ function)
-@anchor{cp/topics/expressions add-operator__gccjit rvalue gccjit rvalue}@anchor{188}
+@anchor{cp/topics/expressions add-operator__gccjit rvalue gccjit rvalue}@anchor{196}
@deffn {C++ Function} gccjit::rvalue operator+ (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13555,7 +13762,7 @@ gccjit::rvalue sum = a + b;
@end deffn
@geindex operator- (C++ function)
-@anchor{cp/topics/expressions sub-operator__gccjit rvalue gccjit rvalue}@anchor{189}
+@anchor{cp/topics/expressions sub-operator__gccjit rvalue gccjit rvalue}@anchor{197}
@deffn {C++ Function} gccjit::rvalue operator- (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13566,7 +13773,7 @@ gccjit::rvalue diff = a - b;
@end deffn
@geindex operator* (C++ function)
-@anchor{cp/topics/expressions mul-operator__gccjit rvalue gccjit rvalue}@anchor{18a}
+@anchor{cp/topics/expressions mul-operator__gccjit rvalue gccjit rvalue}@anchor{198}
@deffn {C++ Function} gccjit::rvalue operator* (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13577,7 +13784,7 @@ gccjit::rvalue prod = a * b;
@end deffn
@geindex operator/ (C++ function)
-@anchor{cp/topics/expressions div-operator__gccjit rvalue gccjit rvalue}@anchor{18b}
+@anchor{cp/topics/expressions div-operator__gccjit rvalue gccjit rvalue}@anchor{199}
@deffn {C++ Function} gccjit::rvalue operator/ (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13588,7 +13795,7 @@ gccjit::rvalue result = a / b;
@end deffn
@geindex operator% (C++ function)
-@anchor{cp/topics/expressions mod-operator__gccjit rvalue gccjit rvalue}@anchor{18c}
+@anchor{cp/topics/expressions mod-operator__gccjit rvalue gccjit rvalue}@anchor{19a}
@deffn {C++ Function} gccjit::rvalue operator% (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13599,7 +13806,7 @@ gccjit::rvalue mod = a % b;
@end deffn
@geindex operator& (C++ function)
-@anchor{cp/topics/expressions and-operator__gccjit rvalue gccjit rvalue}@anchor{18d}
+@anchor{cp/topics/expressions and-operator__gccjit rvalue gccjit rvalue}@anchor{19b}
@deffn {C++ Function} gccjit::rvalue operator& (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13610,7 +13817,7 @@ gccjit::rvalue x = a & b;
@end deffn
@geindex operator^ (C++ function)
-@anchor{cp/topics/expressions xor-operator__gccjit rvalue gccjit rvalue}@anchor{18e}
+@anchor{cp/topics/expressions xor-operator__gccjit rvalue gccjit rvalue}@anchor{19c}
@deffn {C++ Function} gccjit::rvalue operator^ (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13621,7 +13828,7 @@ gccjit::rvalue x = a ^ b;
@end deffn
@geindex operator| (C++ function)
-@anchor{cp/topics/expressions or-operator__gccjit rvalue gccjit rvalue}@anchor{18f}
+@anchor{cp/topics/expressions or-operator__gccjit rvalue gccjit rvalue}@anchor{19d}
@deffn {C++ Function} gccjit::rvalue operator| (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13632,7 +13839,7 @@ gccjit::rvalue x = a | b;
@end deffn
@geindex operator&& (C++ function)
-@anchor{cp/topics/expressions sand-operator__gccjit rvalue gccjit rvalue}@anchor{190}
+@anchor{cp/topics/expressions sand-operator__gccjit rvalue gccjit rvalue}@anchor{19e}
@deffn {C++ Function} gccjit::rvalue operator&& (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13643,7 +13850,7 @@ gccjit::rvalue cond = a && b;
@end deffn
@geindex operator|| (C++ function)
-@anchor{cp/topics/expressions sor-operator__gccjit rvalue gccjit rvalue}@anchor{191}
+@anchor{cp/topics/expressions sor-operator__gccjit rvalue gccjit rvalue}@anchor{19f}
@deffn {C++ Function} gccjit::rvalue operator|| (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13666,12 +13873,12 @@ gccjit::rvalue discriminant = (b * b) - (four * a * c);
@end quotation
@node Comparisons<2>,Function calls<2>,Binary Operations<2>,Rvalues<2>
-@anchor{cp/topics/expressions comparisons}@anchor{192}
+@anchor{cp/topics/expressions comparisons}@anchor{1a0}
@subsubsection Comparisons
@geindex gccjit;;context;;new_comparison (C++ function)
-@anchor{cp/topics/expressions gccjit context new_comparison__enum gccjit rvalue gccjit rvalue gccjit location}@anchor{124}
+@anchor{cp/topics/expressions gccjit context new_comparison__enum gccjit rvalue gccjit rvalue gccjit location}@anchor{130}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_comparison (enum gcc_jit_comparison, gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
Build a boolean rvalue out of the comparison of two other rvalues.
@@ -13687,39 +13894,39 @@ There are shorter ways to spell the various specific kinds of binary
operation:
@geindex gccjit;;context;;new_eq (C++ function)
-@anchor{cp/topics/expressions gccjit context new_eq__gccjit rvalue gccjit rvalue gccjit location}@anchor{193}
+@anchor{cp/topics/expressions gccjit context new_eq__gccjit rvalue gccjit rvalue gccjit location}@anchor{1a1}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_eq (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_ne (C++ function)
-@anchor{cp/topics/expressions gccjit context new_ne__gccjit rvalue gccjit rvalue gccjit location}@anchor{194}
+@anchor{cp/topics/expressions gccjit context new_ne__gccjit rvalue gccjit rvalue gccjit location}@anchor{1a2}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_ne (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_lt (C++ function)
-@anchor{cp/topics/expressions gccjit context new_lt__gccjit rvalue gccjit rvalue gccjit location}@anchor{195}
+@anchor{cp/topics/expressions gccjit context new_lt__gccjit rvalue gccjit rvalue gccjit location}@anchor{1a3}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_lt (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_le (C++ function)
-@anchor{cp/topics/expressions gccjit context new_le__gccjit rvalue gccjit rvalue gccjit location}@anchor{196}
+@anchor{cp/topics/expressions gccjit context new_le__gccjit rvalue gccjit rvalue gccjit location}@anchor{1a4}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_le (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_gt (C++ function)
-@anchor{cp/topics/expressions gccjit context new_gt__gccjit rvalue gccjit rvalue gccjit location}@anchor{197}
+@anchor{cp/topics/expressions gccjit context new_gt__gccjit rvalue gccjit rvalue gccjit location}@anchor{1a5}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_gt (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
@geindex gccjit;;context;;new_ge (C++ function)
-@anchor{cp/topics/expressions gccjit context new_ge__gccjit rvalue gccjit rvalue gccjit location}@anchor{198}
+@anchor{cp/topics/expressions gccjit context new_ge__gccjit rvalue gccjit rvalue gccjit location}@anchor{1a6}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_ge (gccjit::rvalue a, gccjit::rvalue b, gccjit::location loc)
@end deffn
The most concise way to spell them is with overloaded operators:
@geindex operator== (C++ function)
-@anchor{cp/topics/expressions eq-operator__gccjit rvalue gccjit rvalue}@anchor{199}
+@anchor{cp/topics/expressions eq-operator__gccjit rvalue gccjit rvalue}@anchor{1a7}
@deffn {C++ Function} gccjit::rvalue operator== (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13730,7 +13937,7 @@ gccjit::rvalue cond = (a == ctxt.zero (t_int));
@end deffn
@geindex operator!= (C++ function)
-@anchor{cp/topics/expressions neq-operator__gccjit rvalue gccjit rvalue}@anchor{19a}
+@anchor{cp/topics/expressions neq-operator__gccjit rvalue gccjit rvalue}@anchor{1a8}
@deffn {C++ Function} gccjit::rvalue operator!= (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13741,7 +13948,7 @@ gccjit::rvalue cond = (i != j);
@end deffn
@geindex operator< (C++ function)
-@anchor{cp/topics/expressions lt-operator__gccjit rvalue gccjit rvalue}@anchor{19b}
+@anchor{cp/topics/expressions lt-operator__gccjit rvalue gccjit rvalue}@anchor{1a9}
@deffn {C++ Function} gccjit::rvalue operator< (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13752,7 +13959,7 @@ gccjit::rvalue cond = i < n;
@end deffn
@geindex operator<= (C++ function)
-@anchor{cp/topics/expressions lte-operator__gccjit rvalue gccjit rvalue}@anchor{19c}
+@anchor{cp/topics/expressions lte-operator__gccjit rvalue gccjit rvalue}@anchor{1aa}
@deffn {C++ Function} gccjit::rvalue operator<= (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13763,7 +13970,7 @@ gccjit::rvalue cond = i <= n;
@end deffn
@geindex operator> (C++ function)
-@anchor{cp/topics/expressions gt-operator__gccjit rvalue gccjit rvalue}@anchor{19d}
+@anchor{cp/topics/expressions gt-operator__gccjit rvalue gccjit rvalue}@anchor{1ab}
@deffn {C++ Function} gccjit::rvalue operator> (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13774,7 +13981,7 @@ gccjit::rvalue cond = (ch > limit);
@end deffn
@geindex operator>= (C++ function)
-@anchor{cp/topics/expressions gte-operator__gccjit rvalue gccjit rvalue}@anchor{19e}
+@anchor{cp/topics/expressions gte-operator__gccjit rvalue gccjit rvalue}@anchor{1ac}
@deffn {C++ Function} gccjit::rvalue operator>= (gccjit::rvalue a, gccjit::rvalue b)
@example
@@ -13786,13 +13993,13 @@ gccjit::rvalue cond = (score >= ctxt.new_rvalue (t_int, 100));
@c TODO: beyond this point
-@node Function calls<2>,Type-coercion<2>,Comparisons<2>,Rvalues<2>
-@anchor{cp/topics/expressions function-calls}@anchor{19f}
+@node Function calls<2>,Function pointers<3>,Comparisons<2>,Rvalues<2>
+@anchor{cp/topics/expressions function-calls}@anchor{1ad}
@subsubsection Function calls
@geindex gcc_jit_context_new_call (C++ function)
-@anchor{cp/topics/expressions gcc_jit_context_new_call__gcc_jit_contextP gcc_jit_locationP gcc_jit_functionP i gcc_jit_rvaluePP}@anchor{1a0}
+@anchor{cp/topics/expressions gcc_jit_context_new_call__gcc_jit_contextP gcc_jit_locationP gcc_jit_functionP i gcc_jit_rvaluePP}@anchor{1ae}
@deffn {C++ Function} gcc_jit_rvalue* gcc_jit_context_new_call (gcc_jit_context* ctxt, gcc_jit_location* loc, gcc_jit_function* func, int numargs, gcc_jit_rvalue** args)
Given a function and the given table of argument rvalues, construct a
@@ -13801,14 +14008,14 @@ call to the function, with the result as an rvalue.
@cartouche
@quotation Note
@code{gccjit::context::new_call()} merely builds a
-@pxref{16d,,gccjit;;rvalue} i.e. an expression that can be evaluated,
+@pxref{179,,gccjit;;rvalue} i.e. an expression that can be evaluated,
perhaps as part of a more complicated expression.
The call @emph{won't} happen unless you add a statement to a function
that evaluates the expression.
For example, if you want to call a function and discard the result
(or to call a function with @code{void} return type), use
-@pxref{1a1,,gccjit;;block;;add_eval()}:
+@pxref{1af,,gccjit;;block;;add_eval()}:
@example
/* Add "(void)printf (arg0, arg1);". */
@@ -13820,13 +14027,26 @@ block.add_eval (ctxt.new_call (printf_func, arg0, arg1));
@end cartouche
@end deffn
-@node Type-coercion<2>,,Function calls<2>,Rvalues<2>
-@anchor{cp/topics/expressions type-coercion}@anchor{1a2}
+@node Function pointers<3>,Type-coercion<2>,Function calls<2>,Rvalues<2>
+@anchor{cp/topics/expressions function-pointers}@anchor{1b0}
+@subsubsection Function pointers
+
+
+@geindex gccjit;;function;;get_address (C++ function)
+@anchor{cp/topics/expressions gccjit function get_address__gccjit location}@anchor{1b1}
+@deffn {C++ Function} gccjit::rvalue gccjit::function::get_address (gccjit::location loc)
+
+Get the address of a function as an rvalue, of function pointer
+type.
+@end deffn
+
+@node Type-coercion<2>,,Function pointers<3>,Rvalues<2>
+@anchor{cp/topics/expressions type-coercion}@anchor{1b2}
@subsubsection Type-coercion
@geindex gccjit;;context;;new_cast (C++ function)
-@anchor{cp/topics/expressions gccjit context new_cast__gccjit rvalue gccjit type gccjit location}@anchor{1a3}
+@anchor{cp/topics/expressions gccjit context new_cast__gccjit rvalue gccjit type gccjit location}@anchor{1b3}
@deffn {C++ Function} gccjit::rvalue gccjit::context::new_cast (gccjit::rvalue rvalue, gccjit::type type, gccjit::location loc)
Given an rvalue of T, construct another rvalue of another type.
@@ -13851,24 +14071,24 @@ P* <-> Q*, for pointer types P and Q
@end deffn
@node Lvalues<2>,Working with pointers structs and unions<2>,Rvalues<2>,Expressions<2>
-@anchor{cp/topics/expressions lvalues}@anchor{1a4}
+@anchor{cp/topics/expressions lvalues}@anchor{1b4}
@subsubsection Lvalues
@geindex gccjit;;lvalue (C++ class)
-@anchor{cp/topics/expressions gccjit lvalue}@anchor{1a5}
+@anchor{cp/topics/expressions gccjit lvalue}@anchor{1b5}
@deffn {C++ Class} gccjit::lvalue
@end deffn
An lvalue is something that can of the @emph{left}-hand side of an assignment:
a storage area (such as a variable). It is a subclass of
-@pxref{16d,,gccjit;;rvalue}, where the rvalue is computed by reading from the
+@pxref{179,,gccjit;;rvalue}, where the rvalue is computed by reading from the
storage area.
It iss a thin wrapper around @pxref{24,,gcc_jit_lvalue *} from the C API.
@geindex gccjit;;lvalue;;get_address (C++ function)
-@anchor{cp/topics/expressions gccjit lvalue get_address__gccjit location}@anchor{1a6}
+@anchor{cp/topics/expressions gccjit lvalue get_address__gccjit location}@anchor{1b6}
@deffn {C++ Function} gccjit::rvalue gccjit::lvalue::get_address (gccjit::location loc)
Take the address of an lvalue; analogous to:
@@ -13890,27 +14110,27 @@ Parameter "loc" is optional.
@end menu
@node Global variables<2>,,,Lvalues<2>
-@anchor{cp/topics/expressions global-variables}@anchor{1a7}
+@anchor{cp/topics/expressions global-variables}@anchor{1b7}
@subsubsection Global variables
@geindex gccjit;;context;;new_global (C++ function)
-@anchor{cp/topics/expressions gccjit context new_global__enum gccjit type cCP gccjit location}@anchor{1a8}
+@anchor{cp/topics/expressions gccjit context new_global__enum gccjit type cCP gccjit location}@anchor{1b8}
@deffn {C++ Function} gccjit::lvalue gccjit::context::new_global (enum gcc_jit_global_kind, gccjit::type type, const char* name, gccjit::location loc)
Add a new global variable of the given type and name to the context.
-This is a thin wrapper around @pxref{bd,,gcc_jit_context_new_global()} from
+This is a thin wrapper around @pxref{c4,,gcc_jit_context_new_global()} from
the C API; the "kind" parameter has the same meaning as there.
@end deffn
@node Working with pointers structs and unions<2>,,Lvalues<2>,Expressions<2>
-@anchor{cp/topics/expressions working-with-pointers-structs-and-unions}@anchor{1a9}
+@anchor{cp/topics/expressions working-with-pointers-structs-and-unions}@anchor{1b9}
@subsubsection Working with pointers, structs and unions
@geindex gccjit;;rvalue;;dereference (C++ function)
-@anchor{cp/topics/expressions gccjit rvalue dereference__gccjit location}@anchor{1aa}
+@anchor{cp/topics/expressions gccjit rvalue dereference__gccjit location}@anchor{1ba}
@deffn {C++ Function} gccjit::lvalue gccjit::rvalue::dereference (gccjit::location loc)
Given an rvalue of pointer type @code{T *}, dereferencing the pointer,
@@ -13931,7 +14151,7 @@ If you don't need to specify the location, this can also be expressed using
an overloaded operator:
@geindex gccjit;;rvalue;;operator* (C++ function)
-@anchor{cp/topics/expressions gccjit rvalue mul-operator}@anchor{1ab}
+@anchor{cp/topics/expressions gccjit rvalue mul-operator}@anchor{1bb}
@deffn {C++ Function} gccjit::lvalue gccjit::rvalue::operator* ()
@example
@@ -13944,7 +14164,7 @@ gccjit::lvalue content = *ptr;
Field access is provided separately for both lvalues and rvalues:
@geindex gccjit;;lvalue;;access_field (C++ function)
-@anchor{cp/topics/expressions gccjit lvalue access_field__gccjit field gccjit location}@anchor{1ac}
+@anchor{cp/topics/expressions gccjit lvalue access_field__gccjit field gccjit location}@anchor{1bc}
@deffn {C++ Function} gccjit::lvalue gccjit::lvalue::access_field (gccjit::field field, gccjit::location loc)
Given an lvalue of struct or union type, access the given field,
@@ -13960,7 +14180,7 @@ in C.
@end deffn
@geindex gccjit;;rvalue;;access_field (C++ function)
-@anchor{cp/topics/expressions gccjit rvalue access_field__gccjit field gccjit location}@anchor{1ad}
+@anchor{cp/topics/expressions gccjit rvalue access_field__gccjit field gccjit location}@anchor{1bd}
@deffn {C++ Function} gccjit::rvalue gccjit::rvalue::access_field (gccjit::field field, gccjit::location loc)
Given an rvalue of struct or union type, access the given field
@@ -13976,7 +14196,7 @@ in C.
@end deffn
@geindex gccjit;;rvalue;;dereference_field (C++ function)
-@anchor{cp/topics/expressions gccjit rvalue dereference_field__gccjit field gccjit location}@anchor{1ae}
+@anchor{cp/topics/expressions gccjit rvalue dereference_field__gccjit field gccjit location}@anchor{1be}
@deffn {C++ Function} gccjit::lvalue gccjit::rvalue::dereference_field (gccjit::field field, gccjit::location loc)
Given an rvalue of pointer type @code{T *} where T is of struct or union
@@ -13992,7 +14212,7 @@ in C, itself equivalent to @code{(*EXPR).FIELD}.
@end deffn
@geindex gccjit;;context;;new_array_access (C++ function)
-@anchor{cp/topics/expressions gccjit context new_array_access__gccjit rvalue gccjit rvalue gccjit location}@anchor{1af}
+@anchor{cp/topics/expressions gccjit context new_array_access__gccjit rvalue gccjit rvalue gccjit location}@anchor{1bf}
@deffn {C++ Function} gccjit::lvalue gccjit::context::new_array_access (gccjit::rvalue ptr, gccjit::rvalue index, gccjit::location loc)
Given an rvalue of pointer type @code{T *}, get at the element @cite{T} at
@@ -14011,7 +14231,7 @@ in C (or, indeed, to @code{PTR + INDEX}).
Parameter "loc" is optional.
@end deffn
-For array accesses where you don't need to specify a @pxref{147,,gccjit;;location},
+For array accesses where you don't need to specify a @pxref{153,,gccjit;;location},
two overloaded operators are available:
@quotation
@@ -14051,7 +14271,7 @@ gccjit::lvalue element = array[0];
@c <http://www.gnu.org/licenses/>.
@node Creating and using functions<2>,Source Locations<2>,Expressions<2>,Topic Reference<2>
-@anchor{cp/topics/functions doc}@anchor{1b0}@anchor{cp/topics/functions creating-and-using-functions}@anchor{1b1}
+@anchor{cp/topics/functions doc}@anchor{1c0}@anchor{cp/topics/functions creating-and-using-functions}@anchor{1c1}
@subsection Creating and using functions
@@ -14064,36 +14284,36 @@ gccjit::lvalue element = array[0];
@end menu
@node Params<2>,Functions<2>,,Creating and using functions<2>
-@anchor{cp/topics/functions params}@anchor{1b2}
+@anchor{cp/topics/functions params}@anchor{1c2}
@subsubsection Params
@geindex gccjit;;param (C++ class)
-@anchor{cp/topics/functions gccjit param}@anchor{1b3}
+@anchor{cp/topics/functions gccjit param}@anchor{1c3}
@deffn {C++ Class} gccjit::param
A @cite{gccjit::param} represents a parameter to a function.
@end deffn
@geindex gccjit;;context;;new_param (C++ function)
-@anchor{cp/topics/functions gccjit context new_param__gccjit type cCP gccjit location}@anchor{116}
+@anchor{cp/topics/functions gccjit context new_param__gccjit type cCP gccjit location}@anchor{122}
@deffn {C++ Function} gccjit::param gccjit::context::new_param (gccjit::type type, const char* name, gccjit::location loc)
In preparation for creating a function, create a new parameter of the
given type and name.
@end deffn
-@pxref{1b3,,gccjit;;param} is a subclass of @pxref{1a5,,gccjit;;lvalue} (and thus
-of @pxref{16d,,gccjit;;rvalue} and @pxref{154,,gccjit;;object}). It is a thin
+@pxref{1c3,,gccjit;;param} is a subclass of @pxref{1b5,,gccjit;;lvalue} (and thus
+of @pxref{179,,gccjit;;rvalue} and @pxref{160,,gccjit;;object}). It is a thin
wrapper around the C API's @pxref{25,,gcc_jit_param *}.
@node Functions<2>,Blocks<2>,Params<2>,Creating and using functions<2>
-@anchor{cp/topics/functions functions}@anchor{1b4}
+@anchor{cp/topics/functions functions}@anchor{1c4}
@subsubsection Functions
@geindex gccjit;;function (C++ class)
-@anchor{cp/topics/functions gccjit function}@anchor{1b5}
+@anchor{cp/topics/functions gccjit function}@anchor{1c5}
@deffn {C++ Class} gccjit::function
A @cite{gccjit::function} represents a function - either one that we're
@@ -14101,7 +14321,7 @@ creating ourselves, or one that we're referencing.
@end deffn
@geindex gccjit;;context;;new_function (C++ function)
-@anchor{cp/topics/functions gccjit context new_function__enum gccjit type cCP std vector param R i gccjit location}@anchor{1b6}
+@anchor{cp/topics/functions gccjit context new_function__enum gccjit type cCP std vector param R i gccjit location}@anchor{1c6}
@deffn {C++ Function} gccjit::function gccjit::context::new_function (enum gcc_jit_function_kind, gccjit::type return_type, const char* name, std::vector<param>& params, int is_variadic, gccjit::location loc)
Create a gcc_jit_function with the given name and parameters.
@@ -14112,29 +14332,29 @@ This is a wrapper around the C API's @pxref{11,,gcc_jit_context_new_function()}.
@end deffn
@geindex gccjit;;context;;get_builtin_function (C++ function)
-@anchor{cp/topics/functions gccjit context get_builtin_function__cCP}@anchor{1b7}
+@anchor{cp/topics/functions gccjit context get_builtin_function__cCP}@anchor{1c7}
@deffn {C++ Function} gccjit::function gccjit::context::get_builtin_function (const char* name)
This is a wrapper around the C API's
-@pxref{d4,,gcc_jit_context_get_builtin_function()}.
+@pxref{db,,gcc_jit_context_get_builtin_function()}.
@end deffn
@geindex gccjit;;function;;get_param (C++ function)
-@anchor{cp/topics/functions gccjit function get_param__iC}@anchor{1b8}
+@anchor{cp/topics/functions gccjit function get_param__iC}@anchor{1c8}
@deffn {C++ Function} gccjit::param gccjit::function::get_param (int index) const
Get the param of the given index (0-based).
@end deffn
@geindex gccjit;;function;;dump_to_dot (C++ function)
-@anchor{cp/topics/functions gccjit function dump_to_dot__cCP}@anchor{129}
+@anchor{cp/topics/functions gccjit function dump_to_dot__cCP}@anchor{135}
@deffn {C++ Function} void gccjit::function::dump_to_dot (const char* path)
Emit the function in graphviz format to the given path.
@end deffn
@geindex gccjit;;function;;new_local (C++ function)
-@anchor{cp/topics/functions gccjit function new_local__gccjit type cCP gccjit location}@anchor{120}
+@anchor{cp/topics/functions gccjit function new_local__gccjit type cCP gccjit location}@anchor{12c}
@deffn {C++ Function} gccjit::lvalue gccjit::function::new_local (gccjit::type type, const char* name, gccjit::location loc)
Create a new local variable within the function, of the given type and
@@ -14142,19 +14362,19 @@ name.
@end deffn
@node Blocks<2>,Statements<2>,Functions<2>,Creating and using functions<2>
-@anchor{cp/topics/functions blocks}@anchor{1b9}
+@anchor{cp/topics/functions blocks}@anchor{1c9}
@subsubsection Blocks
@geindex gccjit;;block (C++ class)
-@anchor{cp/topics/functions gccjit block}@anchor{1ba}
+@anchor{cp/topics/functions gccjit block}@anchor{1ca}
@deffn {C++ Class} gccjit::block
A @cite{gccjit::block} represents a basic block within a function i.e. a
sequence of statements with a single entry point and a single exit
point.
-@pxref{1ba,,gccjit;;block} is a subclass of @pxref{154,,gccjit;;object}.
+@pxref{1ca,,gccjit;;block} is a subclass of @pxref{160,,gccjit;;object}.
The first basic block that you create within a function will
be the entrypoint.
@@ -14168,7 +14388,7 @@ one function.
@end deffn
@geindex gccjit;;function;;new_block (C++ function)
-@anchor{cp/topics/functions gccjit function new_block__cCP}@anchor{1bb}
+@anchor{cp/topics/functions gccjit function new_block__cCP}@anchor{1cb}
@deffn {C++ Function} gccjit::block gccjit::function::new_block (const char* name)
Create a basic block of the given name. The name may be NULL, but
@@ -14178,12 +14398,12 @@ messages.
@end deffn
@node Statements<2>,,Blocks<2>,Creating and using functions<2>
-@anchor{cp/topics/functions statements}@anchor{1bc}
+@anchor{cp/topics/functions statements}@anchor{1cc}
@subsubsection Statements
@geindex gccjit;;block;;add_eval (C++ function)
-@anchor{cp/topics/functions gccjit block add_eval__gccjit rvalue gccjit location}@anchor{1a1}
+@anchor{cp/topics/functions gccjit block add_eval__gccjit rvalue gccjit location}@anchor{1af}
@deffn {C++ Function} void gccjit::block::add_eval (gccjit::rvalue rvalue, gccjit::location loc)
Add evaluation of an rvalue, discarding the result
@@ -14199,7 +14419,7 @@ This is equivalent to this C code:
@end deffn
@geindex gccjit;;block;;add_assignment (C++ function)
-@anchor{cp/topics/functions gccjit block add_assignment__gccjit lvalue gccjit rvalue gccjit location}@anchor{122}
+@anchor{cp/topics/functions gccjit block add_assignment__gccjit lvalue gccjit rvalue gccjit location}@anchor{12e}
@deffn {C++ Function} void gccjit::block::add_assignment (gccjit::lvalue lvalue, gccjit::rvalue rvalue, gccjit::location loc)
Add evaluation of an rvalue, assigning the result to the given
@@ -14215,7 +14435,7 @@ lvalue = rvalue;
@end deffn
@geindex gccjit;;block;;add_assignment_op (C++ function)
-@anchor{cp/topics/functions gccjit block add_assignment_op__gccjit lvalue enum gccjit rvalue gccjit location}@anchor{126}
+@anchor{cp/topics/functions gccjit block add_assignment_op__gccjit lvalue enum gccjit rvalue gccjit location}@anchor{132}
@deffn {C++ Function} void gccjit::block::add_assignment_op (gccjit::lvalue lvalue, enum gcc_jit_binary_op, gccjit::rvalue rvalue, gccjit::location loc)
Add evaluation of an rvalue, using the result to modify an
@@ -14245,7 +14465,7 @@ loop_body.add_assignment_op (
@end deffn
@geindex gccjit;;block;;add_comment (C++ function)
-@anchor{cp/topics/functions gccjit block add_comment__cCP gccjit location}@anchor{131}
+@anchor{cp/topics/functions gccjit block add_comment__cCP gccjit location}@anchor{13d}
@deffn {C++ Function} void gccjit::block::add_comment (const char* text, gccjit::location loc)
Add a no-op textual comment to the internal representation of the
@@ -14259,7 +14479,7 @@ Parameter "loc" is optional.
@end deffn
@geindex gccjit;;block;;end_with_conditional (C++ function)
-@anchor{cp/topics/functions gccjit block end_with_conditional__gccjit rvalue gccjit block gccjit block gccjit location}@anchor{125}
+@anchor{cp/topics/functions gccjit block end_with_conditional__gccjit rvalue gccjit block gccjit block gccjit location}@anchor{131}
@deffn {C++ Function} void gccjit::block::end_with_conditional (gccjit::rvalue boolval, gccjit::block on_true, gccjit::block on_false, gccjit::location loc)
Terminate a block by adding evaluation of an rvalue, branching on the
@@ -14280,7 +14500,7 @@ block, boolval, on_true, and on_false must be non-NULL.
@end deffn
@geindex gccjit;;block;;end_with_jump (C++ function)
-@anchor{cp/topics/functions gccjit block end_with_jump__gccjit block gccjit location}@anchor{1bd}
+@anchor{cp/topics/functions gccjit block end_with_jump__gccjit block gccjit location}@anchor{1cd}
@deffn {C++ Function} void gccjit::block::end_with_jump (gccjit::block target, gccjit::location loc)
Terminate a block by adding a jump to the given target block.
@@ -14295,7 +14515,7 @@ goto target;
@end deffn
@geindex gccjit;;block;;end_with_return (C++ function)
-@anchor{cp/topics/functions gccjit block end_with_return__gccjit rvalue gccjit location}@anchor{1be}
+@anchor{cp/topics/functions gccjit block end_with_return__gccjit rvalue gccjit location}@anchor{1ce}
@deffn {C++ Function} void gccjit::block::end_with_return (gccjit::rvalue rvalue, gccjit::location loc)
Terminate a block.
@@ -14329,7 +14549,7 @@ return;
@end deffn
@geindex gccjit;;block;;end_with_switch (C++ function)
-@anchor{cp/topics/functions gccjit block end_with_switch__gccjit rvalue gccjit block std vector gccjit case_ gccjit location}@anchor{1bf}
+@anchor{cp/topics/functions gccjit block end_with_switch__gccjit rvalue gccjit block std vector gccjit case_ gccjit location}@anchor{1cf}
@deffn {C++ Function} void gccjit::block::end_with_switch (gccjit::rvalue expr, gccjit::block default_block, std::vector<gccjit::case_> cases, gccjit::location loc)
Terminate a block by adding evalation of an rvalue, then performing
@@ -14372,14 +14592,14 @@ The API entrypoints relating to switch statements and cases:
@itemize *
@item
-@pxref{1bf,,gccjit;;block;;end_with_switch()}
+@pxref{1cf,,gccjit;;block;;end_with_switch()}
@item
-@pxref{1c0,,gccjit;;context;;new_case()}
+@pxref{1d0,,gccjit;;context;;new_case()}
@end itemize
@end quotation
-were added in @pxref{e2,,LIBGCCJIT_ABI_3}; you can test for their presence
+were added in @pxref{e9,,LIBGCCJIT_ABI_3}; you can test for their presence
using
@example
@@ -14389,21 +14609,21 @@ using
@noindent
@geindex gccjit;;block;;end_with_switch;;gccjit;;case_ (C++ class)
-@anchor{cp/topics/functions gccjit block end_with_switch gccjit case_}@anchor{1c1}
+@anchor{cp/topics/functions gccjit block end_with_switch gccjit case_}@anchor{1d1}
@deffn {C++ Class} gccjit::case_
@end deffn
A @cite{gccjit::case_} represents a case within a switch statement, and
-is created within a particular @pxref{13f,,gccjit;;context} using
-@pxref{1c0,,gccjit;;context;;new_case()}. It is a subclass of
-@pxref{154,,gccjit;;object}.
+is created within a particular @pxref{14b,,gccjit;;context} using
+@pxref{1d0,,gccjit;;context;;new_case()}. It is a subclass of
+@pxref{160,,gccjit;;object}.
Each case expresses a multivalued range of integer values. You
can express single-valued cases by passing in the same value for
both @cite{min_value} and @cite{max_value}.
@geindex gccjit;;block;;end_with_switch;;gccjit;;context;;new_case (C++ function)
-@anchor{cp/topics/functions gccjit block end_with_switch gccjit context new_case__gccjit rvalue gccjit rvalue gccjit block}@anchor{1c0}
+@anchor{cp/topics/functions gccjit block end_with_switch gccjit context new_case__gccjit rvalue gccjit rvalue gccjit block}@anchor{1d0}
@deffn {C++ Function} gccjit::case_* gccjit::context::new_case (gccjit::rvalue min_value, gccjit::rvalue max_value, gccjit::block dest_block)
Create a new gccjit::case for use in a switch statement.
@@ -14514,12 +14734,12 @@ create_code (gcc_jit_context *c_ctxt, void *user_data)
@c <http://www.gnu.org/licenses/>.
@node Source Locations<2>,Compiling a context<2>,Creating and using functions<2>,Topic Reference<2>
-@anchor{cp/topics/locations source-locations}@anchor{1c2}@anchor{cp/topics/locations doc}@anchor{1c3}
+@anchor{cp/topics/locations source-locations}@anchor{1d2}@anchor{cp/topics/locations doc}@anchor{1d3}
@subsection Source Locations
@geindex gccjit;;location (C++ class)
-@anchor{cp/topics/locations gccjit location}@anchor{147}
+@anchor{cp/topics/locations gccjit location}@anchor{153}
@deffn {C++ Class} gccjit::location
A @cite{gccjit::location} encapsulates a source code location, so that
@@ -14530,10 +14750,10 @@ single-step through your language.
@cite{gccjit::location} instances are optional: you can always omit them
from any C++ API entrypoint accepting one.
-You can construct them using @pxref{135,,gccjit;;context;;new_location()}.
+You can construct them using @pxref{141,,gccjit;;context;;new_location()}.
You need to enable @pxref{42,,GCC_JIT_BOOL_OPTION_DEBUGINFO} on the
-@pxref{13f,,gccjit;;context} for these locations to actually be usable by
+@pxref{14b,,gccjit;;context} for these locations to actually be usable by
the debugger:
@example
@@ -14544,7 +14764,7 @@ ctxt.set_bool_option (GCC_JIT_BOOL_OPTION_DEBUGINFO, 1);
@end deffn
@geindex gccjit;;context;;new_location (C++ function)
-@anchor{cp/topics/locations gccjit context new_location__cCP i i}@anchor{135}
+@anchor{cp/topics/locations gccjit context new_location__cCP i i}@anchor{141}
@deffn {C++ Function} gccjit::location gccjit::context::new_location (const char* filename, int line, int column)
Create a @cite{gccjit::location} instance representing the given source
@@ -14557,13 +14777,13 @@ location.
@end menu
@node Faking it<2>,,,Source Locations<2>
-@anchor{cp/topics/locations faking-it}@anchor{1c4}
+@anchor{cp/topics/locations faking-it}@anchor{1d4}
@subsubsection Faking it
If you don't have source code for your internal representation, but need
to debug, you can generate a C-like representation of the functions in
-your context using @pxref{146,,gccjit;;context;;dump_to_file()}:
+your context using @pxref{152,,gccjit;;context;;dump_to_file()}:
@example
ctxt.dump_to_file ("/tmp/something.c",
@@ -14595,13 +14815,13 @@ file, giving you @emph{something} you can step through in the debugger.
@c <http://www.gnu.org/licenses/>.
@node Compiling a context<2>,,Source Locations<2>,Topic Reference<2>
-@anchor{cp/topics/compilation compiling-a-context}@anchor{1c5}@anchor{cp/topics/compilation doc}@anchor{1c6}
+@anchor{cp/topics/compilation compiling-a-context}@anchor{1d5}@anchor{cp/topics/compilation doc}@anchor{1d6}
@subsection Compiling a context
-Once populated, a @pxref{13f,,gccjit;;context} can be compiled to
-machine code, either in-memory via @pxref{118,,gccjit;;context;;compile()} or
-to disk via @pxref{1c7,,gccjit;;context;;compile_to_file()}.
+Once populated, a @pxref{14b,,gccjit;;context} can be compiled to
+machine code, either in-memory via @pxref{124,,gccjit;;context;;compile()} or
+to disk via @pxref{1d7,,gccjit;;context;;compile_to_file()}.
You can compile a context multiple times (using either form of
compilation), although any errors that occur on the context will
@@ -14614,12 +14834,12 @@ prevent any future compilation of that context.
@end menu
@node In-memory compilation<2>,Ahead-of-time compilation<2>,,Compiling a context<2>
-@anchor{cp/topics/compilation in-memory-compilation}@anchor{1c8}
+@anchor{cp/topics/compilation in-memory-compilation}@anchor{1d8}
@subsubsection In-memory compilation
@geindex gccjit;;context;;compile (C++ function)
-@anchor{cp/topics/compilation gccjit context compile}@anchor{118}
+@anchor{cp/topics/compilation gccjit context compile}@anchor{124}
@deffn {C++ Function} gcc_jit_result* gccjit::context::compile ()
This calls into GCC and builds the code, returning a
@@ -14630,19 +14850,19 @@ This is a thin wrapper around the
@end deffn
@node Ahead-of-time compilation<2>,,In-memory compilation<2>,Compiling a context<2>
-@anchor{cp/topics/compilation ahead-of-time-compilation}@anchor{1c9}
+@anchor{cp/topics/compilation ahead-of-time-compilation}@anchor{1d9}
@subsubsection Ahead-of-time compilation
Although libgccjit is primarily aimed at just-in-time compilation, it
can also be used for implementing more traditional ahead-of-time
-compilers, via the @pxref{1c7,,gccjit;;context;;compile_to_file()} method.
+compilers, via the @pxref{1d7,,gccjit;;context;;compile_to_file()} method.
@geindex gccjit;;context;;compile_to_file (C++ function)
-@anchor{cp/topics/compilation gccjit context compile_to_file__enum cCP}@anchor{1c7}
+@anchor{cp/topics/compilation gccjit context compile_to_file__enum cCP}@anchor{1d7}
@deffn {C++ Function} void gccjit::context::compile_to_file (enum gcc_jit_output_kind, const char* output_path)
-Compile the @pxref{13f,,gccjit;;context} to a file of the given
+Compile the @pxref{14b,,gccjit;;context} to a file of the given
kind.
This is a thin wrapper around the
@@ -14667,7 +14887,7 @@ This is a thin wrapper around the
@c <http://www.gnu.org/licenses/>.
@node Internals,Indices and tables,C++ bindings for libgccjit,Top
-@anchor{internals/index internals}@anchor{1ca}@anchor{internals/index doc}@anchor{1cb}
+@anchor{internals/index internals}@anchor{1da}@anchor{internals/index doc}@anchor{1db}
@chapter Internals
@@ -14683,7 +14903,7 @@ This is a thin wrapper around the
@end menu
@node Working on the JIT library,Running the test suite,,Internals
-@anchor{internals/index working-on-the-jit-library}@anchor{1cc}
+@anchor{internals/index working-on-the-jit-library}@anchor{1dc}
@section Working on the JIT library
@@ -14720,7 +14940,7 @@ gcc/libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV),
Here's what those configuration options mean:
@geindex command line option; --enable-host-shared
-@anchor{internals/index cmdoption--enable-host-shared}@anchor{1cd}
+@anchor{internals/index cmdoption--enable-host-shared}@anchor{1dd}
@deffn {Option} --enable-host-shared
Configuring with this option means that the compiler is built as
@@ -14729,7 +14949,7 @@ but it necessary for a shared library.
@end deffn
@geindex command line option; --enable-languages=jit@comma{}c++
-@anchor{internals/index cmdoption--enable-languages}@anchor{1ce}
+@anchor{internals/index cmdoption--enable-languages}@anchor{1de}
@deffn {Option} --enable-languages=jit,c++
This specifies which frontends to build. The JIT library looks like
@@ -14748,7 +14968,7 @@ c++: error trying to exec 'cc1plus': execvp: No such file or directory
@end deffn
@geindex command line option; --disable-bootstrap
-@anchor{internals/index cmdoption--disable-bootstrap}@anchor{1cf}
+@anchor{internals/index cmdoption--disable-bootstrap}@anchor{1df}
@deffn {Option} --disable-bootstrap
For hacking on the "jit" subdirectory, performing a full
@@ -14758,7 +14978,7 @@ the compiler can still bootstrap itself.
@end deffn
@geindex command line option; --enable-checking=release
-@anchor{internals/index cmdoption--enable-checking}@anchor{1d0}
+@anchor{internals/index cmdoption--enable-checking}@anchor{1e0}
@deffn {Option} --enable-checking=release
The compile can perform extensive self-checking as it runs, useful when
@@ -14769,7 +14989,7 @@ disable this self-checking.
@end deffn
@node Running the test suite,Environment variables,Working on the JIT library,Internals
-@anchor{internals/index running-the-test-suite}@anchor{1d1}
+@anchor{internals/index running-the-test-suite}@anchor{1e1}
@section Running the test suite
@@ -14832,7 +15052,7 @@ and once a test has been compiled, you can debug it directly:
@end menu
@node Running under valgrind,,,Running the test suite
-@anchor{internals/index running-under-valgrind}@anchor{1d2}
+@anchor{internals/index running-under-valgrind}@anchor{1e2}
@subsection Running under valgrind
@@ -14880,7 +15100,7 @@ When running under valgrind, it's best to have configured gcc with
various known false positives.
@node Environment variables,Packaging notes,Running the test suite,Internals
-@anchor{internals/index environment-variables}@anchor{1d3}
+@anchor{internals/index environment-variables}@anchor{1e3}
@section Environment variables
@@ -14888,7 +15108,7 @@ When running client code against a locally-built libgccjit, three
environment variables need to be set up:
@geindex environment variable; LD_LIBRARY_PATH
-@anchor{internals/index envvar-LD_LIBRARY_PATH}@anchor{1d4}
+@anchor{internals/index envvar-LD_LIBRARY_PATH}@anchor{1e4}
@deffn {Environment Variable} LD_LIBRARY_PATH
@quotation
@@ -14910,7 +15130,7 @@ libgccjit.so.0.0.1: ELF 64-bit LSB shared object, x86-64, version 1 (GNU/Linux),
@end deffn
@geindex environment variable; PATH
-@anchor{internals/index envvar-PATH}@anchor{1d5}
+@anchor{internals/index envvar-PATH}@anchor{1e5}
@deffn {Environment Variable} PATH
The library uses a driver executable for converting from .s assembler
@@ -14929,7 +15149,7 @@ of development.
@end deffn
@geindex environment variable; LIBRARY_PATH
-@anchor{internals/index envvar-LIBRARY_PATH}@anchor{1d6}
+@anchor{internals/index envvar-LIBRARY_PATH}@anchor{1e6}
@deffn {Environment Variable} LIBRARY_PATH
The driver executable invokes the linker, and the latter needs to locate
@@ -14965,11 +15185,11 @@ hello world
@noindent
@node Packaging notes,Overview of code structure,Environment variables,Internals
-@anchor{internals/index packaging-notes}@anchor{1d7}
+@anchor{internals/index packaging-notes}@anchor{1e7}
@section Packaging notes
-The configure-time option @pxref{1cd,,--enable-host-shared} is needed when
+The configure-time option @pxref{1dd,,--enable-host-shared} is needed when
building the jit in order to get position-independent code. This will
slow down the regular compiler by a few percent. Hence when packaging gcc
with libgccjit, please configure and build twice:
@@ -14980,10 +15200,10 @@ with libgccjit, please configure and build twice:
@itemize *
@item
-once without @pxref{1cd,,--enable-host-shared} for most languages, and
+once without @pxref{1dd,,--enable-host-shared} for most languages, and
@item
-once with @pxref{1cd,,--enable-host-shared} for the jit
+once with @pxref{1dd,,--enable-host-shared} for the jit
@end itemize
@end quotation
@@ -15027,7 +15247,7 @@ popd
@noindent
@node Overview of code structure,Design notes,Packaging notes,Internals
-@anchor{internals/index overview-of-code-structure}@anchor{1d8}
+@anchor{internals/index overview-of-code-structure}@anchor{1e8}
@section Overview of code structure
@@ -15060,6 +15280,7 @@ The gcc::jit::recording classes (within @code{jit-recording.c} and
class compound_type;
class struct_;
class union_;
+ class vector_type;
class field;
class fields;
class function;
@@ -15070,6 +15291,7 @@ The gcc::jit::recording classes (within @code{jit-recording.c} and
class global;
class param;
class base_call;
+ class function_pointer;
class statement;
class case_;
@@ -15503,7 +15725,7 @@ JIT: gcc::jit::logger::~logger()
@noindent
@node Design notes,Submitting patches,Overview of code structure,Internals
-@anchor{internals/index design-notes}@anchor{1d9}
+@anchor{internals/index design-notes}@anchor{1e9}
@section Design notes
@@ -15516,7 +15738,7 @@ close as possible to the error; failing that, a good place is within
@code{recording::context::validate ()} in jit-recording.c.
@node Submitting patches,,Design notes,Internals
-@anchor{internals/index submitting-patches}@anchor{1da}
+@anchor{internals/index submitting-patches}@anchor{1ea}
@section Submitting patches
@@ -15650,7 +15872,7 @@ large and inconsequential (e.g. anchor renumbering), rather like generated
committing to svn.
@node Indices and tables,Index,Internals,Top
-@anchor{index indices-and-tables}@anchor{1db}
+@anchor{index indices-and-tables}@anchor{1eb}
@unnumbered Indices and tables
diff --git a/gcc/jit/docs/cp/topics/expressions.rst b/gcc/jit/docs/cp/topics/expressions.rst
index 2f317fff..b0081f6 100644
--- a/gcc/jit/docs/cp/topics/expressions.rst
+++ b/gcc/jit/docs/cp/topics/expressions.rst
@@ -105,6 +105,17 @@ Simple expressions
Generate an rvalue of type :c:data:`GCC_JIT_TYPE_CONST_CHAR_PTR` for
the given string. This is akin to a string literal.
+Vector expressions
+******************
+
+.. function:: gccjit::rvalue \
+ gccjit::context::new_rvalue (gccjit::type vector_type, \
+ std::vector<gccjit::rvalue> elements) const
+
+ Given a vector type, and a vector of scalar rvalue elements, generate a
+ vector rvalue.
+
+ The number of elements needs to match that of the vector type.
Unary Operations
****************
@@ -459,6 +470,15 @@ Function calls
/* Add "(void)printf (arg0, arg1);". */
block.add_eval (ctxt.new_call (printf_func, arg0, arg1));
+Function pointers
+*****************
+
+.. function:: gccjit::rvalue \
+ gccjit::function::get_address (gccjit::location loc)
+
+ Get the address of a function as an rvalue, of function pointer
+ type.
+
Type-coercion
*************
diff --git a/gcc/jit/docs/topics/compatibility.rst b/gcc/jit/docs/topics/compatibility.rst
index 1d5fbc2..84d342b 100644
--- a/gcc/jit/docs/topics/compatibility.rst
+++ b/gcc/jit/docs/topics/compatibility.rst
@@ -156,3 +156,18 @@ entrypoints:
-------------------
``LIBGCCJIT_ABI_8`` covers the addition of
:func:`gcc_jit_type_get_vector`
+
+.. _LIBGCCJIT_ABI_9:
+
+``LIBGCCJIT_ABI_9``
+-------------------
+``LIBGCCJIT_ABI_9`` covers the addition of
+:func:`gcc_jit_function_get_address`
+
+.. _LIBGCCJIT_ABI_10:
+
+``LIBGCCJIT_ABI_10``
+--------------------
+
+``LIBGCCJIT_ABI_10`` covers the addition of
+:func:`gcc_jit_context_new_rvalue_from_vector`
diff --git a/gcc/jit/docs/topics/expressions.rst b/gcc/jit/docs/topics/expressions.rst
index 2534699..e6e09dd 100644
--- a/gcc/jit/docs/topics/expressions.rst
+++ b/gcc/jit/docs/topics/expressions.rst
@@ -126,6 +126,30 @@ Simple expressions
underlying string, so it is valid to pass in a pointer to an on-stack
buffer.
+Vector expressions
+******************
+
+.. function:: gcc_jit_rvalue * \
+ gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt, \
+ gcc_jit_location *loc, \
+ gcc_jit_type *vec_type, \
+ size_t num_elements, \
+ gcc_jit_rvalue **elements)
+
+ Build a vector rvalue from an array of elements.
+
+ "vec_type" should be a vector type, created using
+ :func:`gcc_jit_type_get_vector`.
+
+ "num_elements" should match that of the vector type.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_10`; you can test for
+ its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
+
Unary Operations
****************
@@ -416,7 +440,8 @@ Function calls
int numargs, \
gcc_jit_rvalue **args)
- Given an rvalue of function pointer type, and the given table of
+ Given an rvalue of function pointer type (e.g. from
+ :c:func:`gcc_jit_context_new_function_ptr_type`), and the given table of
argument rvalues, construct a call to the function pointer, with the
result as an rvalue.
@@ -449,6 +474,19 @@ Function calls
#ifdef LIBGCCJIT_HAVE_gcc_jit_rvalue_set_bool_require_tail_call
+Function pointers
+*****************
+
+Function pointers can be obtained:
+
+ * from a :c:type:`gcc_jit_function` using
+ :c:func:`gcc_jit_function_get_address`, or
+
+ * from an existing function using
+ :c:func:`gcc_jit_context_new_rvalue_from_ptr`,
+ using a function pointer type obtained using
+ :c:func:`gcc_jit_context_new_function_ptr_type`.
+
Type-coercion
*************
diff --git a/gcc/jit/docs/topics/function-pointers.rst b/gcc/jit/docs/topics/function-pointers.rst
new file mode 100644
index 0000000..b5b9d1b
--- /dev/null
+++ b/gcc/jit/docs/topics/function-pointers.rst
@@ -0,0 +1,80 @@
+.. Copyright (C) 2017 Free Software Foundation, Inc.
+ Originally contributed by David Malcolm <dmalcolm@redhat.com>
+
+ This is free software: you can 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, see
+ <http://www.gnu.org/licenses/>.
+
+.. default-domain:: c
+
+Function pointers
+=================
+
+You can generate calls that use a function pointer via
+:c:func:`gcc_jit_context_new_call_through_ptr`.
+
+To do requires a :c:type:`gcc_jit_rvalue` of the correct function pointer type.
+
+Function pointers for a :c:type:`gcc_jit_function` can be obtained
+via :c:func:`gcc_jit_function_get_address`.
+
+.. function:: gcc_jit_rvalue *\
+ gcc_jit_function_get_address (gcc_jit_function *fn,\
+ gcc_jit_location *loc)
+
+ Get the address of a function as an rvalue, of function pointer
+ type.
+
+ This entrypoint was added in :ref:`LIBGCCJIT_ABI_9`; you can test
+ for its presence using
+
+ .. code-block:: c
+
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_function_get_address
+
+Alternatively, given an existing function, you can obtain a pointer
+to it in :c:type:`gcc_jit_rvalue` form using
+:c:func:`gcc_jit_context_new_rvalue_from_ptr`, using a function pointer
+type obtained using :c:func:`gcc_jit_context_new_function_ptr_type`.
+
+Here's an example of creating a function pointer type corresponding to C's
+:c:type:`void (*) (int, int, int)`:
+
+.. code-block:: c
+
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Build the function ptr type. */
+ gcc_jit_type *param_types[3];
+ param_types[0] = int_type;
+ param_types[1] = int_type;
+ param_types[2] = int_type;
+
+ gcc_jit_type *fn_ptr_type =
+ gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 3, param_types, 0);
+
+.. function:: gcc_jit_type *\
+ gcc_jit_context_new_function_ptr_type (gcc_jit_context *ctxt,\
+ gcc_jit_location *loc,\
+ gcc_jit_type *return_type,\
+ int num_params,\
+ gcc_jit_type **param_types,\
+ int is_variadic)
+
+ Generate a :c:type:`gcc_jit_type` for a function pointer with the
+ given return type and parameters.
diff --git a/gcc/jit/docs/topics/index.rst b/gcc/jit/docs/topics/index.rst
index 890f21c..a912a6d 100644
--- a/gcc/jit/docs/topics/index.rst
+++ b/gcc/jit/docs/topics/index.rst
@@ -26,6 +26,7 @@ Topic Reference
types.rst
expressions.rst
functions.rst
+ function-pointers.rst
locations.rst
compilation.rst
compatibility.rst
diff --git a/gcc/jit/docs/topics/types.rst b/gcc/jit/docs/topics/types.rst
index c279222..a9ab9b3 100644
--- a/gcc/jit/docs/topics/types.rst
+++ b/gcc/jit/docs/topics/types.rst
@@ -177,6 +177,9 @@ Vector types
#ifdef LIBGCCJIT_HAVE_gcc_jit_type_get_vector
+ Vector rvalues can be generated using
+ :func:`gcc_jit_context_new_rvalue_from_vector`.
+
Structures and unions
---------------------
@@ -309,3 +312,9 @@ You can model C `struct` types by creating :c:type:`gcc_jit_struct *` and
:start-after: /* Quote from here in docs/topics/types.rst. */
:end-before: /* Quote up to here in docs/topics/types.rst. */
:language: c
+
+Function pointer types
+----------------------
+
+Function pointer types can be created using
+:c:func:`gcc_jit_context_new_function_ptr_type`.
diff --git a/gcc/jit/jit-common.h b/gcc/jit/jit-common.h
index 1fc558c..daf94a0 100644
--- a/gcc/jit/jit-common.h
+++ b/gcc/jit/jit-common.h
@@ -117,6 +117,7 @@ namespace recording {
class compound_type;
class struct_;
class union_;
+ class vector_type;
class field;
class fields;
class function;
@@ -127,6 +128,7 @@ namespace recording {
class global;
class param;
class base_call;
+ class function_pointer;
class statement;
class case_;
diff --git a/gcc/jit/jit-playback.c b/gcc/jit/jit-playback.c
index 19b6fe2..95126c9 100644
--- a/gcc/jit/jit-playback.c
+++ b/gcc/jit/jit-playback.c
@@ -629,6 +629,22 @@ new_string_literal (const char *value)
return new rvalue (this, t_addr);
}
+/* Construct a playback::rvalue instance (wrapping a tree) for a
+ vector. */
+
+playback::rvalue *
+playback::context::new_rvalue_from_vector (location *,
+ type *type,
+ const auto_vec<rvalue *> &elements)
+{
+ vec<constructor_elt, va_gc> *v;
+ vec_alloc (v, elements.length ());
+ for (unsigned i = 0; i < elements.length (); ++i)
+ CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, elements[i]->as_tree ());
+ tree t_ctor = build_constructor (type->as_tree (), v);
+ return new rvalue (this, t_ctor);
+}
+
/* Coerce a tree expression into a boolean tree expression. */
tree
@@ -1356,6 +1372,20 @@ new_block (const char *name)
return result;
}
+/* Construct a playback::rvalue instance wrapping an ADDR_EXPR for
+ this playback::function. */
+
+playback::rvalue *
+playback::function::get_address (location *loc)
+{
+ tree t_fndecl = as_fndecl ();
+ tree t_fntype = TREE_TYPE (t_fndecl);
+ tree t_fnptr = build1 (ADDR_EXPR, build_pointer_type (t_fntype), t_fndecl);
+ if (loc)
+ m_ctxt->set_tree_location (t_fnptr, loc);
+ return new rvalue (m_ctxt, t_fnptr);
+}
+
/* Build a statement list for the function as a whole out of the
lists of statements for the individual blocks, building labels
for each block. */
diff --git a/gcc/jit/jit-playback.h b/gcc/jit/jit-playback.h
index 7dc7315..b45f6d5 100644
--- a/gcc/jit/jit-playback.h
+++ b/gcc/jit/jit-playback.h
@@ -114,6 +114,11 @@ public:
new_string_literal (const char *value);
rvalue *
+ new_rvalue_from_vector (location *loc,
+ type *type,
+ const auto_vec<rvalue *> &elements);
+
+ rvalue *
new_unary_op (location *loc,
enum gcc_jit_unary_op op,
type *result_type,
@@ -443,6 +448,9 @@ public:
block*
new_block (const char *name);
+ rvalue *
+ get_address (location *loc);
+
void
build_stmt_list ();
diff --git a/gcc/jit/jit-recording.c b/gcc/jit/jit-recording.c
index 0e7f46e0..bd8f116 100644
--- a/gcc/jit/jit-recording.c
+++ b/gcc/jit/jit-recording.c
@@ -447,6 +447,62 @@ reproducer::xstrdup_printf (const char *fmt, ...)
return result;
}
+/* A helper class for implementing make_debug_string, for building
+ a temporary string from a vec of rvalues. */
+
+class comma_separated_string
+{
+ public:
+ comma_separated_string (const auto_vec<recording::rvalue *> &rvalues,
+ enum recording::precedence prec);
+ ~comma_separated_string ();
+
+ const char *as_char_ptr () const { return m_buf; }
+
+ private:
+ char *m_buf;
+};
+
+/* comma_separated_string's ctor
+ Build m_buf. */
+
+comma_separated_string::comma_separated_string
+ (const auto_vec<recording::rvalue *> &rvalues,
+ enum recording::precedence prec)
+: m_buf (NULL)
+{
+ /* Calculate length of said buffer. */
+ size_t sz = 1; /* nil terminator */
+ for (unsigned i = 0; i< rvalues.length (); i++)
+ {
+ sz += strlen (rvalues[i]->get_debug_string_parens (prec));
+ sz += 2; /* ", " separator */
+ }
+
+ /* Now allocate and populate the buffer. */
+ m_buf = new char[sz];
+ size_t len = 0;
+
+ for (unsigned i = 0; i< rvalues.length (); i++)
+ {
+ strcpy (m_buf + len, rvalues[i]->get_debug_string_parens (prec));
+ len += strlen (rvalues[i]->get_debug_string_parens (prec));
+ if (i + 1 < rvalues.length ())
+ {
+ strcpy (m_buf + len, ", ");
+ len += 2;
+ }
+ }
+ m_buf[len] = '\0';
+}
+
+/* comma_separated_string's dtor. */
+
+comma_separated_string::~comma_separated_string ()
+{
+ delete[] m_buf;
+}
+
/**********************************************************************
Recording.
**********************************************************************/
@@ -1001,6 +1057,23 @@ recording::context::new_string_literal (const char *value)
return result;
}
+/* Create a recording::memento_of_new_rvalue_from_vector instance and add it
+ to this context's list of mementos.
+
+ Implements the post-error-checking part of
+ gcc_jit_context_new_rvalue_from_vector. */
+
+recording::rvalue *
+recording::context::new_rvalue_from_vector (location *loc,
+ vector_type *type,
+ rvalue **elements)
+{
+ recording::rvalue *result
+ = new memento_of_new_rvalue_from_vector (this, loc, type, elements);
+ record (result);
+ return result;
+}
+
/* Create a recording::unary_op instance and add it to this context's
list of mementos.
@@ -2035,7 +2108,7 @@ recording::type *
recording::type::get_vector (size_t num_units)
{
recording::type *result
- = new memento_of_get_vector (this, num_units);
+ = new vector_type (this, num_units);
m_ctxt->record (result);
return result;
}
@@ -2523,13 +2596,13 @@ recording::memento_of_get_aligned::write_reproducer (reproducer &r)
m_alignment_in_bytes);
}
-/* The implementation of class gcc::jit::recording::memento_of_get_vector. */
+/* The implementation of class gcc::jit::recording::vector_type. */
/* Implementation of pure virtual hook recording::memento::replay_into
- for recording::memento_of_get_vector. */
+ for recording::vector_type. */
void
-recording::memento_of_get_vector::replay_into (replayer *)
+recording::vector_type::replay_into (replayer *)
{
set_playback_obj
(m_other_type->playback_type ()->get_vector (m_num_units));
@@ -2539,7 +2612,7 @@ recording::memento_of_get_vector::replay_into (replayer *)
results of get_vector. */
recording::string *
-recording::memento_of_get_vector::make_debug_string ()
+recording::vector_type::make_debug_string ()
{
return string::from_printf
(m_ctxt,
@@ -2549,11 +2622,10 @@ recording::memento_of_get_vector::make_debug_string ()
m_num_units);
}
-/* Implementation of recording::memento::write_reproducer for volatile
- types. */
+/* Implementation of recording::memento::write_reproducer for vector types. */
void
-recording::memento_of_get_vector::write_reproducer (reproducer &r)
+recording::vector_type::write_reproducer (reproducer &r)
{
const char *id = r.make_identifier (this, "type");
r.write (" gcc_jit_type *%s =\n"
@@ -2643,6 +2715,53 @@ recording::function_type::dereference ()
return NULL;
}
+/* Implementation of virtual hook recording::type::is_same_type_as for
+ recording::function_type.
+
+ We override this to avoid requiring identity of function pointer types,
+ so that if client code has obtained the same signature in
+ different ways (e.g. via gcc_jit_context_new_function_ptr_type
+ vs gcc_jit_function_get_address), the different function_type
+ instances are treated as compatible.
+
+ We can't use type::accepts_writes_from for this as we need a stronger
+ notion of "sameness": if we have a fn_ptr type that has args that are
+ themselves fn_ptr types, then those args still need to match exactly.
+
+ Alternatively, we could consolidate attempts to create identical
+ function_type instances so that pointer equality works, but that runs
+ into issues about the lifetimes of the cache (w.r.t. nested contexts). */
+
+bool
+recording::function_type::is_same_type_as (type *other)
+{
+ gcc_assert (other);
+
+ function_type *other_fn_type = other->dyn_cast_function_type ();
+ if (!other_fn_type)
+ return false;
+
+ /* Everything must match. */
+
+ if (!m_return_type->is_same_type_as (other_fn_type->m_return_type))
+ return false;
+
+ if (m_param_types.length () != other_fn_type->m_param_types.length ())
+ return false;
+
+ unsigned i;
+ type *param_type;
+ FOR_EACH_VEC_ELT (m_param_types, i, param_type)
+ if (!param_type->is_same_type_as (other_fn_type->m_param_types[i]))
+ return false;
+
+ if (m_is_variadic != other_fn_type->m_is_variadic)
+ return false;
+
+ /* Passed all tests. */
+ return true;
+}
+
/* Implementation of pure virtual hook recording::memento::replay_into
for recording::function_type. */
@@ -3452,7 +3571,8 @@ recording::function::function (context *ctxt,
m_is_variadic (is_variadic),
m_builtin_id (builtin_id),
m_locals (),
- m_blocks ()
+ m_blocks (),
+ m_fn_ptr_type (NULL)
{
for (int i = 0; i< num_params; i++)
{
@@ -3725,6 +3845,35 @@ recording::function::dump_to_dot (const char *path)
fclose (fp);
}
+/* Implements the post-error-checking part of
+ gcc_jit_function_get_address. */
+
+recording::rvalue *
+recording::function::get_address (recording::location *loc)
+{
+ /* Lazily create and cache the function pointer type. */
+ if (!m_fn_ptr_type)
+ {
+ /* Make a recording::function_type for this function. */
+ auto_vec <recording::type *> param_types (m_params.length ());
+ unsigned i;
+ recording::param *param;
+ FOR_EACH_VEC_ELT (m_params, i, param)
+ param_types.safe_push (param->get_type ());
+ recording::function_type *fn_type
+ = m_ctxt->new_function_type (m_return_type,
+ m_params.length (),
+ param_types.address (),
+ m_is_variadic);
+ m_fn_ptr_type = fn_type->get_pointer ();
+ }
+ gcc_assert (m_fn_ptr_type);
+
+ rvalue *result = new function_pointer (get_context (), loc, this, m_fn_ptr_type);
+ m_ctxt->record (result);
+ return result;
+}
+
/* Implementation of recording::memento::make_debug_string for
functions. */
@@ -4492,6 +4641,96 @@ recording::memento_of_new_string_literal::write_reproducer (reproducer &r)
m_value->get_debug_string ());
}
+/* The implementation of class
+ gcc::jit::recording::memento_of_new_rvalue_from_vector. */
+
+/* The constructor for
+ gcc::jit::recording::memento_of_new_rvalue_from_vector. */
+
+recording::memento_of_new_rvalue_from_vector::
+memento_of_new_rvalue_from_vector (context *ctxt,
+ location *loc,
+ vector_type *type,
+ rvalue **elements)
+: rvalue (ctxt, loc, type),
+ m_vector_type (type),
+ m_elements ()
+{
+ for (unsigned i = 0; i < type->get_num_units (); i++)
+ m_elements.safe_push (elements[i]);
+}
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::memento_of_new_rvalue_from_vector. */
+
+void
+recording::memento_of_new_rvalue_from_vector::replay_into (replayer *r)
+{
+ auto_vec<playback::rvalue *> playback_elements;
+ playback_elements.create (m_elements.length ());
+ for (unsigned i = 0; i< m_elements.length (); i++)
+ playback_elements.safe_push (m_elements[i]->playback_rvalue ());
+
+ set_playback_obj (r->new_rvalue_from_vector (playback_location (r, m_loc),
+ m_type->playback_type (),
+ playback_elements));
+}
+
+/* Implementation of pure virtual hook recording::rvalue::visit_children
+ for recording::memento_of_new_rvalue_from_vector. */
+
+void
+recording::memento_of_new_rvalue_from_vector::visit_children (rvalue_visitor *v)
+{
+ for (unsigned i = 0; i< m_elements.length (); i++)
+ v->visit (m_elements[i]);
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ vectors. */
+
+recording::string *
+recording::memento_of_new_rvalue_from_vector::make_debug_string ()
+{
+ comma_separated_string elements (m_elements, get_precedence ());
+
+ /* Now build a string. */
+ string *result = string::from_printf (m_ctxt,
+ "{%s}",
+ elements.as_char_ptr ());
+
+ return result;
+
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ vectors. */
+
+void
+recording::memento_of_new_rvalue_from_vector::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "vector");
+ const char *elements_id = r.make_tmp_identifier ("elements_for_", this);
+ r.write (" gcc_jit_rvalue *%s[%i] = {\n",
+ elements_id,
+ m_elements.length ());
+ for (unsigned i = 0; i< m_elements.length (); i++)
+ r.write (" %s,\n", r.get_identifier_as_rvalue (m_elements[i]));
+ r.write (" };\n");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_context_new_rvalue_from_vector (%s, /* gcc_jit_context *ctxt */\n"
+ " %s, /* gcc_jit_location *loc */\n"
+ " %s, /* gcc_jit_type *vec_type */\n"
+ " %i, /* size_t num_elements */ \n"
+ " %s); /* gcc_jit_rvalue **elements*/\n",
+ id,
+ r.get_identifier (get_context ()),
+ r.get_identifier (m_loc),
+ r.get_identifier (m_vector_type),
+ m_elements.length (),
+ elements_id);
+}
+
/* The implementation of class gcc::jit::recording::unary_op. */
/* Implementation of pure virtual hook recording::memento::replay_into
@@ -4905,39 +5144,14 @@ recording::call::visit_children (rvalue_visitor *v)
recording::string *
recording::call::make_debug_string ()
{
- enum precedence prec = get_precedence ();
/* First, build a buffer for the arguments. */
- /* Calculate length of said buffer. */
- size_t sz = 1; /* nil terminator */
- for (unsigned i = 0; i< m_args.length (); i++)
- {
- sz += strlen (m_args[i]->get_debug_string_parens (prec));
- sz += 2; /* ", " separator */
- }
-
- /* Now allocate and populate the buffer. */
- char *argbuf = new char[sz];
- size_t len = 0;
-
- for (unsigned i = 0; i< m_args.length (); i++)
- {
- strcpy (argbuf + len, m_args[i]->get_debug_string_parens (prec));
- len += strlen (m_args[i]->get_debug_string_parens (prec));
- if (i + 1 < m_args.length ())
- {
- strcpy (argbuf + len, ", ");
- len += 2;
- }
- }
- argbuf[len] = '\0';
+ comma_separated_string args (m_args, get_precedence ());
/* ...and use it to get the string for the call as a whole. */
string *result = string::from_printf (m_ctxt,
"%s (%s)",
m_func->get_debug_string (),
- argbuf);
-
- delete[] argbuf;
+ args.as_char_ptr ());
return result;
}
@@ -5400,6 +5614,51 @@ recording::get_address_of_lvalue::write_reproducer (reproducer &r)
r.get_identifier (m_loc));
}
+/* The implementation of class gcc::jit::recording::function_pointer. */
+
+/* Implementation of pure virtual hook recording::memento::replay_into
+ for recording::function_pointer. */
+
+void
+recording::function_pointer::replay_into (replayer *r)
+{
+ set_playback_obj (
+ m_fn->playback_function ()->
+ get_address (playback_location (r, m_loc)));
+}
+
+void
+recording::function_pointer::visit_children (rvalue_visitor *)
+{
+ /* Empty. */
+}
+
+/* Implementation of recording::memento::make_debug_string for
+ getting the address of an lvalue. */
+
+recording::string *
+recording::function_pointer::make_debug_string ()
+{
+ return string::from_printf (m_ctxt,
+ "%s",
+ m_fn->get_debug_string ());
+}
+
+/* Implementation of recording::memento::write_reproducer for
+ function_pointer. */
+
+void
+recording::function_pointer::write_reproducer (reproducer &r)
+{
+ const char *id = r.make_identifier (this, "address_of");
+ r.write (" gcc_jit_rvalue *%s =\n"
+ " gcc_jit_function_get_address (%s, /* gcc_jit_function *fn */\n"
+ " %s); /* gcc_jit_location *loc */\n",
+ id,
+ r.get_identifier (m_fn),
+ r.get_identifier (m_loc));
+}
+
/* The implementation of class gcc::jit::recording::local. */
/* Implementation of pure virtual hook recording::memento::replay_into
diff --git a/gcc/jit/jit-recording.h b/gcc/jit/jit-recording.h
index 248765d..6a3fd5d 100644
--- a/gcc/jit/jit-recording.h
+++ b/gcc/jit/jit-recording.h
@@ -149,6 +149,11 @@ public:
new_string_literal (const char *value);
rvalue *
+ new_rvalue_from_vector (location *loc,
+ vector_type *type,
+ rvalue **elements);
+
+ rvalue *
new_unary_op (location *loc,
enum gcc_jit_unary_op op,
type *result_type,
@@ -486,12 +491,18 @@ public:
virtual function_type *dyn_cast_function_type () { return NULL; }
virtual function_type *as_a_function_type() { gcc_unreachable (); return NULL; }
virtual struct_ *dyn_cast_struct () { return NULL; }
+ virtual vector_type *dyn_cast_vector_type () { return NULL; }
/* Is it typesafe to copy to this type from rtype? */
virtual bool accepts_writes_from (type *rtype)
{
gcc_assert (rtype);
- return this->unqualified () == rtype->unqualified ();
+ return this->unqualified ()->is_same_type_as (rtype->unqualified ());
+ }
+
+ virtual bool is_same_type_as (type *other)
+ {
+ return this == other;
}
/* Strip off "const" etc */
@@ -685,15 +696,18 @@ private:
};
/* Result of "gcc_jit_type_get_vector". */
-class memento_of_get_vector : public decorated_type
+class vector_type : public decorated_type
{
public:
- memento_of_get_vector (type *other_type, size_t num_units)
+ vector_type (type *other_type, size_t num_units)
: decorated_type (other_type),
m_num_units (num_units) {}
- /* Strip off the alignment, giving the underlying type. */
- type *unqualified () FINAL OVERRIDE { return m_other_type; }
+ size_t get_num_units () const { return m_num_units; }
+
+ vector_type *dyn_cast_vector_type () FINAL OVERRIDE { return this; }
+
+ type *get_element_type () { return m_other_type; }
void replay_into (replayer *) FINAL OVERRIDE;
@@ -751,6 +765,8 @@ public:
function_type *dyn_cast_function_type () FINAL OVERRIDE { return this; }
function_type *as_a_function_type () FINAL OVERRIDE { return this; }
+ bool is_same_type_as (type *other) FINAL OVERRIDE;
+
bool is_int () const FINAL OVERRIDE { return false; }
bool is_float () const FINAL OVERRIDE { return false; }
bool is_bool () const FINAL OVERRIDE { return false; }
@@ -1145,6 +1161,8 @@ public:
void dump_to_dot (const char *path);
+ rvalue *get_address (location *loc);
+
private:
string * make_debug_string () FINAL OVERRIDE;
void write_reproducer (reproducer &r) FINAL OVERRIDE;
@@ -1159,6 +1177,7 @@ private:
enum built_in_function m_builtin_id;
auto_vec<local *> m_locals;
auto_vec<block *> m_blocks;
+ type *m_fn_ptr_type;
};
class block : public memento
@@ -1348,6 +1367,31 @@ private:
string *m_value;
};
+class memento_of_new_rvalue_from_vector : public rvalue
+{
+public:
+ memento_of_new_rvalue_from_vector (context *ctxt,
+ location *loc,
+ vector_type *type,
+ rvalue **elements);
+
+ void replay_into (replayer *r) FINAL OVERRIDE;
+
+ void visit_children (rvalue_visitor *) FINAL OVERRIDE;
+
+private:
+ string * make_debug_string () FINAL OVERRIDE;
+ void write_reproducer (reproducer &r) FINAL OVERRIDE;
+ enum precedence get_precedence () const FINAL OVERRIDE
+ {
+ return PRECEDENCE_PRIMARY;
+ }
+
+private:
+ vector_type *m_vector_type;
+ auto_vec<rvalue *> m_elements;
+};
+
class unary_op : public rvalue
{
public:
@@ -1699,6 +1743,32 @@ private:
lvalue *m_lvalue;
};
+class function_pointer : public rvalue
+{
+public:
+ function_pointer (context *ctxt,
+ location *loc,
+ function *fn,
+ type *type)
+ : rvalue (ctxt, loc, type),
+ m_fn (fn) {}
+
+ void replay_into (replayer *r) FINAL OVERRIDE;
+
+ void visit_children (rvalue_visitor *v) FINAL OVERRIDE;
+
+private:
+ string * make_debug_string () FINAL OVERRIDE;
+ void write_reproducer (reproducer &r) FINAL OVERRIDE;
+ enum precedence get_precedence () const FINAL OVERRIDE
+ {
+ return PRECEDENCE_UNARY;
+ }
+
+private:
+ function *m_fn;
+};
+
class local : public lvalue
{
public:
diff --git a/gcc/jit/libgccjit++.h b/gcc/jit/libgccjit++.h
index a83ccf6..9e3c179 100644
--- a/gcc/jit/libgccjit++.h
+++ b/gcc/jit/libgccjit++.h
@@ -187,6 +187,8 @@ namespace gccjit
rvalue new_rvalue (type pointer_type,
void *value) const;
rvalue new_rvalue (const std::string &value) const;
+ rvalue new_rvalue (type vector_type,
+ std::vector<rvalue> elements) const;
/* Generic unary operations... */
rvalue new_unary_op (enum gcc_jit_unary_op op,
@@ -368,6 +370,8 @@ namespace gccjit
const std::string &name,
location loc = location ());
+ rvalue get_address (location loc = location ());
+
/* A series of overloaded operator () with various numbers of arguments
for a very terse way of creating a call to this function. The call
is created within the same context as the function itself, which may
@@ -895,6 +899,26 @@ context::new_rvalue (const std::string &value) const
}
inline rvalue
+context::new_rvalue (type vector_type,
+ std::vector<rvalue> elements) const
+{
+ /* Treat std::vector as an array, relying on it not being resized: */
+ rvalue *as_array_of_wrappers = &elements[0];
+
+ /* Treat the array as being of the underlying pointers, relying on
+ the wrapper type being such a pointer internally. */
+ gcc_jit_rvalue **as_array_of_ptrs =
+ reinterpret_cast<gcc_jit_rvalue **> (as_array_of_wrappers);
+
+ return rvalue (
+ gcc_jit_context_new_rvalue_from_vector (m_inner_ctxt,
+ NULL,
+ vector_type.get_inner_type (),
+ elements.size (),
+ as_array_of_ptrs));
+}
+
+inline rvalue
context::new_unary_op (enum gcc_jit_unary_op op,
type result_type,
rvalue a,
@@ -1392,6 +1416,13 @@ function::new_local (type type_,
name.c_str ()));
}
+inline rvalue
+function::get_address (location loc)
+{
+ return rvalue (gcc_jit_function_get_address (get_inner_function (),
+ loc.get_inner_location ()));
+}
+
inline function
block::get_function () const
{
diff --git a/gcc/jit/libgccjit.c b/gcc/jit/libgccjit.c
index 6e352c6..c00acbf 100644
--- a/gcc/jit/libgccjit.c
+++ b/gcc/jit/libgccjit.c
@@ -1335,7 +1335,7 @@ gcc_jit_context_new_binary_op (gcc_jit_context *ctxt,
RETURN_NULL_IF_FAIL (a, ctxt, loc, "NULL a");
RETURN_NULL_IF_FAIL (b, ctxt, loc, "NULL b");
RETURN_NULL_IF_FAIL_PRINTF4 (
- a->get_type () == b->get_type (),
+ a->get_type ()->unqualified () == b->get_type ()->unqualified (),
ctxt, loc,
"mismatching types for binary op:"
" a: %s (type: %s) b: %s (type: %s)",
@@ -3022,3 +3022,81 @@ gcc_jit_type_get_vector (gcc_jit_type *type, size_t num_units)
return (gcc_jit_type *)type->get_vector (num_units);
}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::function::get_address method, in
+ jit-recording.c. */
+
+gcc_jit_rvalue *
+gcc_jit_function_get_address (gcc_jit_function *fn,
+ gcc_jit_location *loc)
+{
+ RETURN_NULL_IF_FAIL (fn, NULL, NULL, "NULL function");
+
+ gcc::jit::recording::context *ctxt = fn->m_ctxt;
+
+ JIT_LOG_FUNC (ctxt->get_logger ());
+ /* LOC can be NULL. */
+
+ return (gcc_jit_rvalue *)fn->get_address (loc);
+}
+
+/* Public entrypoint. See description in libgccjit.h.
+
+ After error-checking, the real work is done by the
+ gcc::jit::recording::context::new_rvalue_from_vector method, in
+ jit-recording.c. */
+
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_type *vec_type,
+ size_t num_elements,
+ gcc_jit_rvalue **elements)
+{
+ RETURN_NULL_IF_FAIL (ctxt, NULL, loc, "NULL ctxt");
+ JIT_LOG_FUNC (ctxt->get_logger ());
+
+ /* LOC can be NULL. */
+ RETURN_NULL_IF_FAIL (vec_type, ctxt, loc, "NULL vec_type");
+
+ /* "vec_type" must be a vector type. */
+ gcc::jit::recording::vector_type *as_vec_type
+ = vec_type->dyn_cast_vector_type ();
+ RETURN_NULL_IF_FAIL_PRINTF1 (as_vec_type, ctxt, loc,
+ "%s is not a vector type",
+ vec_type->get_debug_string ());
+
+ /* "num_elements" must match. */
+ RETURN_NULL_IF_FAIL_PRINTF1 (
+ num_elements == as_vec_type->get_num_units (), ctxt, loc,
+ "num_elements != %zi", as_vec_type->get_num_units ());
+
+ /* "elements must be non-NULL. */
+ RETURN_NULL_IF_FAIL (elements, ctxt, loc, "NULL elements");
+
+ /* Each of "elements" must be non-NULL and of the correct type. */
+ gcc::jit::recording::type *element_type
+ = as_vec_type->get_element_type ();
+ for (size_t i = 0; i < num_elements; i++)
+ {
+ RETURN_NULL_IF_FAIL_PRINTF1 (
+ elements[i], ctxt, loc, "NULL elements[%zi]", i);
+ RETURN_NULL_IF_FAIL_PRINTF4 (
+ compatible_types (element_type,
+ elements[i]->get_type ()),
+ ctxt, loc,
+ "mismatching type for element[%zi] (expected type: %s): %s (type: %s)",
+ i,
+ element_type->get_debug_string (),
+ elements[i]->get_debug_string (),
+ elements[i]->get_type ()->get_debug_string ());
+ }
+
+ return (gcc_jit_rvalue *)ctxt->new_rvalue_from_vector
+ (loc,
+ as_vec_type,
+ (gcc::jit::recording::rvalue **)elements);
+}
diff --git a/gcc/jit/libgccjit.h b/gcc/jit/libgccjit.h
index b863b07..f955eb2 100644
--- a/gcc/jit/libgccjit.h
+++ b/gcc/jit/libgccjit.h
@@ -1418,6 +1418,38 @@ gcc_jit_type_get_aligned (gcc_jit_type *type,
extern gcc_jit_type *
gcc_jit_type_get_vector (gcc_jit_type *type, size_t num_units);
+
+#define LIBGCCJIT_HAVE_gcc_jit_function_get_address
+
+/* Get the address of a function as an rvalue, of function pointer
+ type.
+
+ This API entrypoint was added in LIBGCCJIT_ABI_9; you can test for its
+ presence using
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_function_get_address
+*/
+extern gcc_jit_rvalue *
+gcc_jit_function_get_address (gcc_jit_function *fn,
+ gcc_jit_location *loc);
+
+
+#define LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
+
+/* Build a vector rvalue from an array of elements.
+
+ "vec_type" should be a vector type, created using gcc_jit_type_get_vector.
+
+ This API entrypoint was added in LIBGCCJIT_ABI_10; you can test for its
+ presence using
+ #ifdef LIBGCCJIT_HAVE_gcc_jit_context_new_rvalue_from_vector
+*/
+extern gcc_jit_rvalue *
+gcc_jit_context_new_rvalue_from_vector (gcc_jit_context *ctxt,
+ gcc_jit_location *loc,
+ gcc_jit_type *vec_type,
+ size_t num_elements,
+ gcc_jit_rvalue **elements);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */
diff --git a/gcc/jit/libgccjit.map b/gcc/jit/libgccjit.map
index 08760e3..03f65fd 100644
--- a/gcc/jit/libgccjit.map
+++ b/gcc/jit/libgccjit.map
@@ -160,3 +160,13 @@ LIBGCCJIT_ABI_8 {
global:
gcc_jit_type_get_vector;
} LIBGCCJIT_ABI_7;
+
+LIBGCCJIT_ABI_9 {
+ global:
+ gcc_jit_function_get_address;
+} LIBGCCJIT_ABI_8;
+
+LIBGCCJIT_ABI_10 {
+ global:
+ gcc_jit_context_new_rvalue_from_vector;
+} LIBGCCJIT_ABI_9;
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index c54b790..9b3212b 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -266,8 +266,8 @@ lhd_gimplify_expr (tree *expr_p ATTRIBUTE_UNUSED,
}
/* lang_hooks.tree_size: Determine the size of a tree with code C,
- which is a language-specific tree code in category tcc_constant or
- tcc_exceptional. The default expects never to be called. */
+ which is a language-specific tree code in category tcc_constant,
+ tcc_exceptional or tcc_type. The default expects never to be called. */
size_t
lhd_tree_size (enum tree_code c ATTRIBUTE_UNUSED)
{
diff --git a/gcc/langhooks.h b/gcc/langhooks.h
index b0c9829..d1288f1 100644
--- a/gcc/langhooks.h
+++ b/gcc/langhooks.h
@@ -307,10 +307,10 @@ struct lang_hooks
/* Remove any parts of the tree that are used only by the FE. */
void (*free_lang_data) (tree);
- /* Determines the size of any language-specific tcc_constant or
- tcc_exceptional nodes. Since it is called from make_node, the
- only information available is the tree code. Expected to die
- on unrecognized codes. */
+ /* Determines the size of any language-specific tcc_constant,
+ tcc_exceptional or tcc_type nodes. Since it is called from
+ make_node, the only information available is the tree code.
+ Expected to die on unrecognized codes. */
size_t (*tree_size) (enum tree_code);
/* Return the language mask used for converting argv into a sequence
diff --git a/gcc/loop-doloop.c b/gcc/loop-doloop.c
index 5769d9d..421b355 100644
--- a/gcc/loop-doloop.c
+++ b/gcc/loop-doloop.c
@@ -393,9 +393,7 @@ add_test (rtx cond, edge *e, basic_block dest)
edge e2 = make_edge (bb, dest, (*e)->flags & ~EDGE_FALLTHRU);
e2->probability = prob;
- e2->count = e2->src->count.apply_probability (prob);
(*e)->probability = prob.invert ();
- (*e)->count = (*e)->count.apply_probability (prob);
update_br_prob_note (e2->src);
return true;
}
diff --git a/gcc/loop-unroll.c b/gcc/loop-unroll.c
index 8cf305b..816302b 100644
--- a/gcc/loop-unroll.c
+++ b/gcc/loop-unroll.c
@@ -977,7 +977,6 @@ unroll_loop_runtime_iterations (struct loop *loop)
iter_count = new_count = swtch->count.apply_scale (1, max_unroll + 1);
swtch->frequency = new_freq;
swtch->count = new_count;
- single_succ_edge (swtch)->count = new_count;
for (i = 0; i < n_peel; i++)
{
@@ -999,7 +998,6 @@ unroll_loop_runtime_iterations (struct loop *loop)
/* Add in frequency/count of edge from switch block. */
preheader->frequency += iter_freq;
preheader->count += iter_count;
- single_succ_edge (preheader)->count = preheader->count;
branch_code = compare_and_jump_seq (copy_rtx (niter), GEN_INT (j), EQ,
block_label (preheader), p,
NULL);
@@ -1011,14 +1009,12 @@ unroll_loop_runtime_iterations (struct loop *loop)
swtch = split_edge_and_insert (single_pred_edge (swtch), branch_code);
set_immediate_dominator (CDI_DOMINATORS, preheader, swtch);
single_succ_edge (swtch)->probability = p.invert ();
- single_succ_edge (swtch)->count = new_count;
new_freq += iter_freq;
new_count += iter_count;
swtch->frequency = new_freq;
swtch->count = new_count;
e = make_edge (swtch, preheader,
single_succ_edge (swtch)->flags & EDGE_IRREDUCIBLE_LOOP);
- e->count = iter_count;
e->probability = p;
}
@@ -1035,7 +1031,6 @@ unroll_loop_runtime_iterations (struct loop *loop)
/* Add in frequency/count of edge from switch block. */
preheader->frequency += iter_freq;
preheader->count += iter_count;
- single_succ_edge (preheader)->count = preheader->count;
branch_code = compare_and_jump_seq (copy_rtx (niter), const0_rtx, EQ,
block_label (preheader), p,
NULL);
@@ -1044,10 +1039,8 @@ unroll_loop_runtime_iterations (struct loop *loop)
swtch = split_edge_and_insert (single_succ_edge (swtch), branch_code);
set_immediate_dominator (CDI_DOMINATORS, preheader, swtch);
single_succ_edge (swtch)->probability = p.invert ();
- single_succ_edge (swtch)->count -= iter_count;
e = make_edge (swtch, preheader,
single_succ_edge (swtch)->flags & EDGE_IRREDUCIBLE_LOOP);
- e->count = iter_count;
e->probability = p;
}
@@ -1731,7 +1724,8 @@ split_iv (struct iv_to_split *ivts, rtx_insn *insn, unsigned delta)
else
{
incr = simplify_gen_binary (MULT, mode,
- ivts->step, gen_int_mode (delta, mode));
+ copy_rtx (ivts->step),
+ gen_int_mode (delta, mode));
expr = simplify_gen_binary (PLUS, GET_MODE (ivts->base_var),
ivts->base_var, incr);
}
diff --git a/gcc/lra-constraints.c b/gcc/lra-constraints.c
index d90bde2..6163d7d 100644
--- a/gcc/lra-constraints.c
+++ b/gcc/lra-constraints.c
@@ -4271,7 +4271,13 @@ curr_insn_transform (bool check_only_p)
}
else if (curr_static_id->operand[i].type == OP_IN
&& (curr_static_id->operand[goal_alt_matched[i][0]].type
- == OP_OUT))
+ == OP_OUT
+ || (curr_static_id->operand[goal_alt_matched[i][0]].type
+ == OP_INOUT
+ && (operands_match_p
+ (*curr_id->operand_loc[i],
+ *curr_id->operand_loc[goal_alt_matched[i][0]],
+ -1)))))
{
/* generate reloads for input and matched outputs. */
match_inputs[0] = i;
@@ -4282,9 +4288,14 @@ curr_insn_transform (bool check_only_p)
[goal_alt_number * n_operands + goal_alt_matched[i][0]]
.earlyclobber);
}
- else if (curr_static_id->operand[i].type == OP_OUT
+ else if ((curr_static_id->operand[i].type == OP_OUT
+ || (curr_static_id->operand[i].type == OP_INOUT
+ && (operands_match_p
+ (*curr_id->operand_loc[i],
+ *curr_id->operand_loc[goal_alt_matched[i][0]],
+ -1))))
&& (curr_static_id->operand[goal_alt_matched[i][0]].type
- == OP_IN))
+ == OP_IN))
/* Generate reloads for output and matched inputs. */
match_reload (i, goal_alt_matched[i], outputs, goal_alt[i], &before,
&after, curr_static_id->operand_alternative
@@ -6219,6 +6230,7 @@ inherit_in_ebb (rtx_insn *head, rtx_insn *tail)
&& ((cheap = XEXP (cheap, 0)), true)
&& (regno = REGNO (cheap)) >= FIRST_PSEUDO_REGISTER
&& (hard_regno = reg_renumber[regno]) >= 0
+ && usage_insns[regno].check == curr_usage_insns_check
/* If there are pending saves/restores, the
optimization is not worth. */
&& usage_insns[regno].calls_num == calls_num - 1
diff --git a/gcc/lra-lives.c b/gcc/lra-lives.c
index 4648eca..df7e253 100644
--- a/gcc/lra-lives.c
+++ b/gcc/lra-lives.c
@@ -220,6 +220,9 @@ lra_intersected_live_ranges_p (lra_live_range_t r1, lra_live_range_t r2)
return false;
}
+/* The corresponding bitmaps of BB currently being processed. */
+static bitmap bb_killed_pseudos, bb_gen_pseudos;
+
/* The function processing birth of hard register REGNO. It updates
living hard regs, START_LIVING, and conflict hard regs for living
pseudos. Conflict hard regs for the pic pseudo is not updated if
@@ -243,6 +246,8 @@ make_hard_regno_born (int regno, bool check_pic_pseudo_p ATTRIBUTE_UNUSED)
|| i != REGNO (pic_offset_table_rtx))
#endif
SET_HARD_REG_BIT (lra_reg_info[i].conflict_hard_regs, regno);
+ if (fixed_regs[regno])
+ bitmap_set_bit (bb_gen_pseudos, regno);
}
/* Process the death of hard register REGNO. This updates
@@ -255,6 +260,11 @@ make_hard_regno_dead (int regno)
return;
sparseset_set_bit (start_dying, regno);
CLEAR_HARD_REG_BIT (hard_regs_live, regno);
+ if (fixed_regs[regno])
+ {
+ bitmap_clear_bit (bb_gen_pseudos, regno);
+ bitmap_set_bit (bb_killed_pseudos, regno);
+ }
}
/* Mark pseudo REGNO as living at program point POINT, update conflicting
@@ -299,9 +309,6 @@ mark_pseudo_dead (int regno, int point)
}
}
-/* The corresponding bitmaps of BB currently being processed. */
-static bitmap bb_killed_pseudos, bb_gen_pseudos;
-
/* Mark register REGNO (pseudo or hard register) in MODE as live at
program point POINT. Update BB_GEN_PSEUDOS.
Return TRUE if the liveness tracking sets were modified, or FALSE
diff --git a/gcc/lra-spills.c b/gcc/lra-spills.c
index ab33dd4..5997b1e 100644
--- a/gcc/lra-spills.c
+++ b/gcc/lra-spills.c
@@ -153,9 +153,7 @@ assign_mem_slot (int i)
/* On a big endian machine, the "address" of the slot is the address
of the low part that fits its inherent mode. */
- if (BYTES_BIG_ENDIAN && inherent_size < total_size)
- adjust += (total_size - inherent_size);
-
+ adjust += subreg_size_lowpart_offset (inherent_size, total_size);
x = adjust_address_nv (x, GET_MODE (regno_reg_rtx[i]), adjust);
/* Set all of the memory attributes as appropriate for a spill. */
diff --git a/gcc/lra.c b/gcc/lra.c
index a473777..3122f2c 100644
--- a/gcc/lra.c
+++ b/gcc/lra.c
@@ -820,7 +820,8 @@ collect_non_operand_hard_regs (rtx *x, lra_insn_recog_data_t data,
const char *fmt = GET_RTX_FORMAT (code);
for (i = 0; i < data->insn_static_data->n_operands; i++)
- if (x == data->operand_loc[i])
+ if (! data->insn_static_data->operand[i].is_operator
+ && x == data->operand_loc[i])
/* It is an operand loc. Stop here. */
return list;
for (i = 0; i < data->insn_static_data->n_dups; i++)
diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c
index 51d9a7b..ea6f92b 100644
--- a/gcc/lto-streamer-in.c
+++ b/gcc/lto-streamer-in.c
@@ -715,8 +715,7 @@ make_new_block (struct function *fn, unsigned int index)
static void
input_cfg (struct lto_input_block *ib, struct data_in *data_in,
- struct function *fn,
- int count_materialization_scale)
+ struct function *fn)
{
unsigned int bb_count;
basic_block p_bb;
@@ -756,13 +755,10 @@ input_cfg (struct lto_input_block *ib, struct data_in *data_in,
unsigned int edge_flags;
basic_block dest;
profile_probability probability;
- profile_count count;
edge e;
dest_index = streamer_read_uhwi (ib);
probability = profile_probability::stream_in (ib);
- count = profile_count::stream_in (ib).apply_scale
- (count_materialization_scale, REG_BR_PROB_BASE);
edge_flags = streamer_read_uhwi (ib);
dest = BASIC_BLOCK_FOR_FN (fn, dest_index);
@@ -772,7 +768,6 @@ input_cfg (struct lto_input_block *ib, struct data_in *data_in,
e = make_edge (bb, dest, edge_flags);
e->probability = probability;
- e->count = count;
}
index = streamer_read_hwi (ib);
@@ -1070,7 +1065,7 @@ input_function (tree fn_decl, struct data_in *data_in,
if (!node)
node = cgraph_node::create (fn_decl);
input_struct_function_base (fn, data_in, ib);
- input_cfg (ib_cfg, data_in, fn, node->count_materialization_scale);
+ input_cfg (ib_cfg, data_in, fn);
/* Read all the SSA names. */
input_ssa_names (ib, data_in, fn);
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index 944502b..554f9cc 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -1028,13 +1028,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
hstate.commit_flag ();
if (CODE_CONTAINS_STRUCT (code, TS_INT_CST))
- {
- int i;
- hstate.add_wide_int (TREE_INT_CST_NUNITS (t));
- hstate.add_wide_int (TREE_INT_CST_EXT_NUNITS (t));
- for (i = 0; i < TREE_INT_CST_NUNITS (t); i++)
- hstate.add_wide_int (TREE_INT_CST_ELT (t, i));
- }
+ hstate.add_wide_int (wi::to_widest (t));
if (CODE_CONTAINS_STRUCT (code, TS_REAL_CST))
{
@@ -1058,7 +1052,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
if (CODE_CONTAINS_STRUCT (code, TS_DECL_COMMON))
{
- hstate.add_wide_int (DECL_MODE (t));
+ hstate.add_hwi (DECL_MODE (t));
hstate.add_flag (DECL_NONLOCAL (t));
hstate.add_flag (DECL_VIRTUAL_P (t));
hstate.add_flag (DECL_IGNORED_P (t));
@@ -1151,7 +1145,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
if (CODE_CONTAINS_STRUCT (code, TS_TYPE_COMMON))
{
- hstate.add_wide_int (TYPE_MODE (t));
+ hstate.add_hwi (TYPE_MODE (t));
hstate.add_flag (TYPE_STRING_FLAG (t));
/* TYPE_NO_FORCE_BLK is private to stor-layout and need
no streaming. */
@@ -1181,10 +1175,10 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
if (CODE_CONTAINS_STRUCT (code, TS_TARGET_OPTION)
/* We don't stream these when passing things to a different target. */
&& !lto_stream_offload_p)
- hstate.add_wide_int (cl_target_option_hash (TREE_TARGET_OPTION (t)));
+ hstate.add_hwi (cl_target_option_hash (TREE_TARGET_OPTION (t)));
if (CODE_CONTAINS_STRUCT (code, TS_OPTIMIZATION))
- hstate.add_wide_int (cl_optimization_hash (TREE_OPTIMIZATION (t)));
+ hstate.add_hwi (cl_optimization_hash (TREE_OPTIMIZATION (t)));
if (CODE_CONTAINS_STRUCT (code, TS_IDENTIFIER))
hstate.merge_hash (IDENTIFIER_HASH_VALUE (t));
@@ -1312,7 +1306,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
if (CODE_CONTAINS_STRUCT (code, TS_EXP))
{
- hstate.add_wide_int (TREE_OPERAND_LENGTH (t));
+ hstate.add_hwi (TREE_OPERAND_LENGTH (t));
for (int i = 0; i < TREE_OPERAND_LENGTH (t); ++i)
visit (TREE_OPERAND (t, i));
}
@@ -1336,7 +1330,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
{
unsigned i;
tree index, value;
- hstate.add_wide_int (CONSTRUCTOR_NELTS (t));
+ hstate.add_hwi (CONSTRUCTOR_NELTS (t));
FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (t), i, index, value)
{
visit (index);
@@ -1349,7 +1343,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
int i;
HOST_WIDE_INT val;
- hstate.add_wide_int (OMP_CLAUSE_CODE (t));
+ hstate.add_hwi (OMP_CLAUSE_CODE (t));
switch (OMP_CLAUSE_CODE (t))
{
case OMP_CLAUSE_DEFAULT:
@@ -1374,7 +1368,7 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
val = 0;
break;
}
- hstate.add_wide_int (val);
+ hstate.add_hwi (val);
for (i = 0; i < omp_clause_num_ops[OMP_CLAUSE_CODE (t)]; i++)
visit (OMP_CLAUSE_OPERAND (t, i));
visit (OMP_CLAUSE_CHAIN (t));
@@ -1883,7 +1877,6 @@ output_cfg (struct output_block *ob, struct function *fn)
{
streamer_write_uhwi (ob, e->dest->index);
e->probability.stream_out (ob);
- e->count.stream_out (ob);
streamer_write_uhwi (ob, e->flags);
}
}
diff --git a/gcc/lto/ChangeLog b/gcc/lto/ChangeLog
index 1911e84..173cde6 100644
--- a/gcc/lto/ChangeLog
+++ b/gcc/lto/ChangeLog
@@ -1,3 +1,18 @@
+2017-10-13 Jan Hubicka <hubicka@ucw.cz>
+
+ * lto-lang.c (lto_post_options): Clean shlib flag when not doing PIC.
+
+2017-10-11 Nathan Sidwell <nathan@acm.org>
+
+ * lto.c (mentions_vars_p_decl_with_vis): Use
+ DECL_ASSEMBLER_NAME_RAW.
+ (lto_fixup_prevailing_decls): Likewise.
+
+2017-10-10 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * lto.c (compare_tree_sccs_1): Use wi::to_wide when
+ operating on trees as wide_ints.
+
2017-08-30 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c
index eaf7933..88f2970 100644
--- a/gcc/lto/lto-lang.c
+++ b/gcc/lto/lto-lang.c
@@ -854,11 +854,13 @@ lto_post_options (const char **pfilename ATTRIBUTE_UNUSED)
flag_pie is 2. */
flag_pie = MAX (flag_pie, flag_pic);
flag_pic = flag_pie;
+ flag_shlib = 0;
break;
case LTO_LINKER_OUTPUT_EXEC: /* Normal executable */
flag_pic = 0;
flag_pie = 0;
+ flag_shlib = 0;
break;
case LTO_LINKER_OUTPUT_UNKNOWN:
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 182607b..63ba73c 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -591,7 +591,7 @@ mentions_vars_p_decl_with_vis (tree t)
return true;
/* Accessor macro has side-effects, use field-name here. */
- CHECK_NO_VAR (t->decl_with_vis.assembler_name);
+ CHECK_NO_VAR (DECL_ASSEMBLER_NAME_RAW (t));
return false;
}
@@ -1039,7 +1039,7 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
if (CODE_CONTAINS_STRUCT (code, TS_INT_CST))
{
- if (!wi::eq_p (t1, t2))
+ if (wi::to_wide (t1) != wi::to_wide (t2))
return false;
}
@@ -2557,7 +2557,7 @@ lto_fixup_prevailing_decls (tree t)
}
if (CODE_CONTAINS_STRUCT (code, TS_DECL_WITH_VIS))
{
- LTO_NO_PREVAIL (t->decl_with_vis.assembler_name);
+ LTO_NO_PREVAIL (DECL_ASSEMBLER_NAME_RAW (t));
}
if (CODE_CONTAINS_STRUCT (code, TS_DECL_NON_COMMON))
{
diff --git a/gcc/match.pd b/gcc/match.pd
index e9017e4..f2c4373 100644
--- a/gcc/match.pd
+++ b/gcc/match.pd
@@ -276,7 +276,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(div (div @0 INTEGER_CST@1) INTEGER_CST@2)
(with {
bool overflow_p;
- wide_int mul = wi::mul (@1, @2, TYPE_SIGN (type), &overflow_p);
+ wide_int mul = wi::mul (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (type), &overflow_p);
}
(if (!overflow_p)
(div @0 { wide_int_to_tree (type, mul); })
@@ -290,7 +291,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(mult (mult @0 INTEGER_CST@1) INTEGER_CST@2)
(with {
bool overflow_p;
- wide_int mul = wi::mul (@1, @2, TYPE_SIGN (type), &overflow_p);
+ wide_int mul = wi::mul (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (type), &overflow_p);
}
/* Skip folding on overflow: the only special case is @1 * @2 == -INT_MIN,
otherwise undefined overflow implies that @0 must be zero. */
@@ -358,10 +360,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(div (convert? (bit_and @0 INTEGER_CST@1)) INTEGER_CST@2)
(if (integer_pow2p (@2)
&& tree_int_cst_sgn (@2) > 0
- && wi::add (@2, @1) == 0
- && tree_nop_conversion_p (type, TREE_TYPE (@0)))
- (rshift (convert @0) { build_int_cst (integer_type_node,
- wi::exact_log2 (@2)); }))))
+ && tree_nop_conversion_p (type, TREE_TYPE (@0))
+ && wi::to_wide (@2) + wi::to_wide (@1) == 0)
+ (rshift (convert @0)
+ { build_int_cst (integer_type_node,
+ wi::exact_log2 (wi::to_wide (@2))); }))))
/* If ARG1 is a constant, we can convert this to a multiply by the
reciprocal. This does not have the same rounding properties,
@@ -414,7 +417,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(mod (mult @0 INTEGER_CST@1) INTEGER_CST@2)
(if (ANY_INTEGRAL_TYPE_P (type)
&& TYPE_OVERFLOW_UNDEFINED (type)
- && wi::multiple_of_p (@1, @2, TYPE_SIGN (type)))
+ && wi::multiple_of_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (type)))
{ build_zero_cst (type); })))
/* X % -C is the same as X % C. */
@@ -422,7 +426,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(trunc_mod @0 INTEGER_CST@1)
(if (TYPE_SIGN (type) == SIGNED
&& !TREE_OVERFLOW (@1)
- && wi::neg_p (@1)
+ && wi::neg_p (wi::to_wide (@1))
&& !TYPE_OVERFLOW_TRAPS (type)
/* Avoid this transformation if C is INT_MIN, i.e. C == -C. */
&& !sign_bit_p (@1, @1))
@@ -438,7 +442,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
/* Avoid this transformation if X might be INT_MIN or
Y might be -1, because we would then change valid
INT_MIN % -(-1) into invalid INT_MIN % -1. */
- && (expr_not_equal_to (@0, TYPE_MIN_VALUE (type))
+ && (expr_not_equal_to (@0, wi::to_wide (TYPE_MIN_VALUE (type)))
|| expr_not_equal_to (@1, wi::minus_one (TYPE_PRECISION
(TREE_TYPE (@1))))))
(trunc_mod @0 (convert @1))))
@@ -471,7 +475,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(trunc_div (mult @0 integer_pow2p@1) @1)
(if (TYPE_UNSIGNED (TREE_TYPE (@0)))
(bit_and @0 { wide_int_to_tree
- (type, wi::mask (TYPE_PRECISION (type) - wi::exact_log2 (@1),
+ (type, wi::mask (TYPE_PRECISION (type)
+ - wi::exact_log2 (wi::to_wide (@1)),
false, TYPE_PRECISION (type))); })))
/* Simplify (unsigned t / 2) * 2 -> unsigned t & ~1. */
@@ -505,7 +510,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(for pows (POWI)
(simplify
(pows (op @0) INTEGER_CST@1)
- (if (wi::bit_and (@1, 1) == 0)
+ (if ((wi::to_wide (@1) & 1) == 0)
(pows @0 @1))))
/* Strip negate and abs from both operands of hypot. */
(for hypots (HYPOT)
@@ -546,7 +551,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
copysigns (COPYSIGN)
(simplify
(pows (copysigns @0 @2) INTEGER_CST@1)
- (if (wi::bit_and (@1, 1) == 0)
+ (if ((wi::to_wide (@1) & 1) == 0)
(pows @0 @1))))
(for hypots (HYPOT)
@@ -630,17 +635,26 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (TYPE_UNSIGNED (type))
(bit_and @0 (bit_not (lshift { build_all_ones_cst (type); } @1)))))
-/* PR35691: Transform
- (x == 0 & y == 0) -> (x | typeof(x)(y)) == 0.
- (x != 0 | y != 0) -> (x | typeof(x)(y)) != 0. */
(for bitop (bit_and bit_ior)
cmp (eq ne)
+ /* PR35691: Transform
+ (x == 0 & y == 0) -> (x | typeof(x)(y)) == 0.
+ (x != 0 | y != 0) -> (x | typeof(x)(y)) != 0. */
(simplify
(bitop (cmp @0 integer_zerop@2) (cmp @1 integer_zerop))
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && INTEGRAL_TYPE_P (TREE_TYPE (@1))
- && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)))
- (cmp (bit_ior @0 (convert @1)) @2))))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)))
+ (cmp (bit_ior @0 (convert @1)) @2)))
+ /* Transform:
+ (x == -1 & y == -1) -> (x & typeof(x)(y)) == -1.
+ (x != -1 | y != -1) -> (x & typeof(x)(y)) != -1. */
+ (simplify
+ (bitop (cmp @0 integer_all_onesp@2) (cmp @1 integer_all_onesp))
+ (if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && INTEGRAL_TYPE_P (TREE_TYPE (@1))
+ && TYPE_PRECISION (TREE_TYPE (@0)) == TYPE_PRECISION (TREE_TYPE (@1)))
+ (cmp (bit_and @0 (convert @1)) @2))))
/* Fold (A & ~B) - (A & B) into (A ^ B) - B. */
(simplify
@@ -648,7 +662,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(minus (bit_xor @0 @1) @1))
(simplify
(minus (bit_and:s @0 INTEGER_CST@2) (bit_and:s @0 INTEGER_CST@1))
- (if (wi::bit_not (@2) == @1)
+ (if (~wi::to_wide (@2) == wi::to_wide (@1))
(minus (bit_xor @0 @1) @1)))
/* Fold (A & B) - (A & ~B) into B - (A ^ B). */
@@ -663,7 +677,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(bit_xor @0 @1))
(simplify
(op:c (bit_and @0 INTEGER_CST@2) (bit_and (bit_not @0) INTEGER_CST@1))
- (if (wi::bit_not (@2) == @1)
+ (if (~wi::to_wide (@2) == wi::to_wide (@1))
(bit_xor @0 @1))))
/* PR53979: Transform ((a ^ b) | a) -> (a | b) */
@@ -676,7 +690,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(bit_and (bit_not SSA_NAME@0) INTEGER_CST@1)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && (get_nonzero_bits (@0) & wi::bit_not (@1)) == 0)
+ && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0)
(bit_xor @0 @1)))
#endif
@@ -741,7 +755,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(bit_and SSA_NAME@0 INTEGER_CST@1)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
- && (get_nonzero_bits (@0) & wi::bit_not (@1)) == 0)
+ && wi::bit_and_not (get_nonzero_bits (@0), wi::to_wide (@1)) == 0)
@0))
#endif
@@ -842,7 +856,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(convert2? (bit_and@5 @2 INTEGER_CST@3)))
(if (tree_nop_conversion_p (type, TREE_TYPE (@0))
&& tree_nop_conversion_p (type, TREE_TYPE (@2))
- && wi::bit_and (@1, @3) == 0)
+ && (wi::to_wide (@1) & wi::to_wide (@3)) == 0)
(bit_ior (convert @4) (convert @5)))))
/* (X | Y) ^ X -> Y & ~ X*/
@@ -1141,7 +1155,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (tree_expr_nonnegative_p (@1) && tree_expr_nonzero_p (@1))
(cmp @0 @2)
(if (TREE_CODE (@1) == INTEGER_CST
- && wi::neg_p (@1, TYPE_SIGN (TREE_TYPE (@1))))
+ && wi::neg_p (wi::to_wide (@1), TYPE_SIGN (TREE_TYPE (@1))))
(cmp @2 @0))))))
/* (X - 1U) <= INT_MAX-1U into (int) X > 0. */
@@ -1152,8 +1166,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& TYPE_UNSIGNED (TREE_TYPE (@0))
&& TYPE_PRECISION (TREE_TYPE (@0)) > 1
- && wi::eq_p (@2, wi::max_value (TYPE_PRECISION (TREE_TYPE (@0)),
- SIGNED) - 1))
+ && (wi::to_wide (@2)
+ == wi::max_value (TYPE_PRECISION (TREE_TYPE (@0)), SIGNED) - 1))
(with { tree stype = signed_type_for (TREE_TYPE (@0)); }
(icmp (convert:stype @0) { build_int_cst (stype, 0); })))))
@@ -1161,7 +1175,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(for cmp (simple_comparison)
(simplify
(cmp (exact_div @0 INTEGER_CST@2) (exact_div @1 @2))
- (if (wi::gt_p(@2, 0, TYPE_SIGN (TREE_TYPE (@2))))
+ (if (wi::gt_p (wi::to_wide (@2), 0, TYPE_SIGN (TREE_TYPE (@2))))
(cmp @0 @1))))
/* X / C1 op C2 into a simple range test. */
@@ -1266,6 +1280,56 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
|| TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
(op @1 @0))))
+/* X + Y < Y is the same as X < 0 when there is no overflow. */
+(for op (lt le gt ge)
+ (simplify
+ (op:c (plus:c@2 @0 @1) @1)
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+ && (CONSTANT_CLASS_P (@0) || single_use (@2)))
+ (op @0 { build_zero_cst (TREE_TYPE (@0)); }))))
+/* For equality, this is also true with wrapping overflow. */
+(for op (eq ne)
+ (simplify
+ (op:c (nop_convert@3 (plus:c@2 @0 (convert1? @1))) (convert2? @1))
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+ || TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
+ && (CONSTANT_CLASS_P (@0) || (single_use (@2) && single_use (@3)))
+ && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@2))
+ && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@1)))
+ (op @0 { build_zero_cst (TREE_TYPE (@0)); })))
+ (simplify
+ (op:c (nop_convert@3 (pointer_plus@2 (convert1? @0) @1)) (convert2? @0))
+ (if (tree_nop_conversion_p (TREE_TYPE (@2), TREE_TYPE (@0))
+ && tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@0))
+ && (CONSTANT_CLASS_P (@1) || (single_use (@2) && single_use (@3))))
+ (op @1 { build_zero_cst (TREE_TYPE (@1)); }))))
+
+/* X - Y < X is the same as Y > 0 when there is no overflow.
+ For equality, this is also true with wrapping overflow. */
+(for op (simple_comparison)
+ (simplify
+ (op:c @0 (minus@2 @0 @1))
+ (if (ANY_INTEGRAL_TYPE_P (TREE_TYPE (@0))
+ && (TYPE_OVERFLOW_UNDEFINED (TREE_TYPE (@0))
+ || ((op == EQ_EXPR || op == NE_EXPR)
+ && TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))))
+ && (CONSTANT_CLASS_P (@1) || single_use (@2)))
+ (op @1 { build_zero_cst (TREE_TYPE (@1)); }))))
+
+/* Transform:
+ * (X / Y) == 0 -> X < Y if X, Y are unsigned.
+ * (X / Y) != 0 -> X >= Y, if X, Y are unsigned.
+ */
+(for cmp (eq ne)
+ ocmp (lt ge)
+ (simplify
+ (cmp (trunc_div @0 @1) integer_zerop)
+ (if (TYPE_UNSIGNED (TREE_TYPE (@0))
+ && (VECTOR_TYPE_P (type) || !VECTOR_TYPE_P (TREE_TYPE (@0))))
+ (ocmp @0 @1))))
+
/* X == C - X can never be true if C is odd. */
(for cmp (eq ne)
(simplify
@@ -1297,7 +1361,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(for cmp (eq ne)
(simplify
(cmp:c (with_possible_nonzero_bits2 @0) (with_certain_nonzero_bits2 @1))
- (if ((~get_nonzero_bits (@0) & @1) != 0)
+ (if (wi::bit_and_not (wi::to_wide (@1), get_nonzero_bits (@0)) != 0)
{ constant_boolean_node (cmp == NE_EXPR, type); })))
/* ((X inner_op C0) outer_op C1)
@@ -1329,18 +1393,18 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
if (inner_op == BIT_XOR_EXPR)
{
- C0 = wi::bit_and_not (@0, @1);
- cst_emit = wi::bit_or (C0, @1);
+ C0 = wi::bit_and_not (wi::to_wide (@0), wi::to_wide (@1));
+ cst_emit = C0 | wi::to_wide (@1);
}
else
{
- C0 = @0;
- cst_emit = wi::bit_xor (@0, @1);
+ C0 = wi::to_wide (@0);
+ cst_emit = C0 ^ wi::to_wide (@1);
}
}
- (if (!fail && wi::bit_and (C0, zero_mask_not) == 0)
+ (if (!fail && (C0 & zero_mask_not) == 0)
(outer_op @2 { wide_int_to_tree (type, cst_emit); })
- (if (!fail && wi::bit_and (@1, zero_mask_not) == 0)
+ (if (!fail && (wi::to_wide (@1) & zero_mask_not) == 0)
(inner_op @2 { wide_int_to_tree (type, cst_emit); }))))))
/* Associate (p +p off1) +p off2 as (p +p (off1 + off2)). */
@@ -1373,7 +1437,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
... = ptr & ~algn; */
(simplify
(pointer_plus @0 (negate (bit_and (convert @0) INTEGER_CST@1)))
- (with { tree algn = wide_int_to_tree (TREE_TYPE (@0), wi::bit_not (@1)); }
+ (with { tree algn = wide_int_to_tree (TREE_TYPE (@0), ~wi::to_wide (@1)); }
(bit_and @0 { algn; })))
/* Try folding difference of addresses. */
@@ -1403,8 +1467,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
unsigned HOST_WIDE_INT bitpos;
get_pointer_alignment_1 (@0, &align, &bitpos);
}
- (if (wi::ltu_p (@1, align / BITS_PER_UNIT))
- { wide_int_to_tree (type, wi::bit_and (@1, bitpos / BITS_PER_UNIT)); }))))
+ (if (wi::ltu_p (wi::to_wide (@1), align / BITS_PER_UNIT))
+ { wide_int_to_tree (type, (wi::to_wide (@1)
+ & (bitpos / BITS_PER_UNIT))); }))))
/* We can't reassociate at all for saturating types. */
@@ -1514,8 +1579,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(inner_op @0 { cst; } )
/* X+INT_MAX+1 is X-INT_MIN. */
(if (INTEGRAL_TYPE_P (type) && cst
- && wi::eq_p (cst, wi::min_value (type)))
- (neg_inner_op @0 { wide_int_to_tree (type, cst); })
+ && wi::to_wide (cst) == wi::min_value (type))
+ (neg_inner_op @0 { wide_int_to_tree (type, wi::to_wide (cst)); })
/* Last resort, use some unsigned type. */
(with { tree utype = unsigned_type_for (type); }
(view_convert (inner_op
@@ -1767,16 +1832,20 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(for cmp (eq ne)
(simplify
(cmp (min @0 INTEGER_CST@1) INTEGER_CST@2)
- (if (wi::lt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0))))
+ (if (wi::lt_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (TREE_TYPE (@0))))
{ constant_boolean_node (cmp == NE_EXPR, type); }
- (if (wi::gt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0))))
+ (if (wi::gt_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (TREE_TYPE (@0))))
(cmp @0 @2)))))
(for cmp (eq ne)
(simplify
(cmp (max @0 INTEGER_CST@1) INTEGER_CST@2)
- (if (wi::gt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0))))
+ (if (wi::gt_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (TREE_TYPE (@0))))
{ constant_boolean_node (cmp == NE_EXPR, type); }
- (if (wi::lt_p (@1, @2, TYPE_SIGN (TREE_TYPE (@0))))
+ (if (wi::lt_p (wi::to_wide (@1), wi::to_wide (@2),
+ TYPE_SIGN (TREE_TYPE (@0))))
(cmp @0 @2)))))
/* MIN (X, C1) < C2 -> X < C2 || C1 < C2 */
(for minmax (min min max max min min max max )
@@ -1803,7 +1872,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
/* Optimize (x >> c) << c into x & (-1<<c). */
(simplify
(lshift (rshift @0 INTEGER_CST@1) @1)
- (if (wi::ltu_p (@1, element_precision (type)))
+ (if (wi::ltu_p (wi::to_wide (@1), element_precision (type)))
(bit_and @0 (lshift { build_minus_one_cst (type); } @1))))
/* Optimize (x << c) >> c into x & ((unsigned)-1 >> c) for unsigned
@@ -1811,7 +1880,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(rshift (lshift @0 INTEGER_CST@1) @1)
(if (TYPE_UNSIGNED (type)
- && (wi::ltu_p (@1, element_precision (type))))
+ && (wi::ltu_p (wi::to_wide (@1), element_precision (type))))
(bit_and @0 (rshift { build_minus_one_cst (type); } @1))))
(for shiftrotate (lrotate rrotate lshift rshift)
@@ -1858,11 +1927,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(op (op @0 INTEGER_CST@1) INTEGER_CST@2)
(with { unsigned int prec = element_precision (type); }
- (if (wi::ge_p (@1, 0, TYPE_SIGN (TREE_TYPE (@1)))
- && wi::lt_p (@1, prec, TYPE_SIGN (TREE_TYPE (@1)))
- && wi::ge_p (@2, 0, TYPE_SIGN (TREE_TYPE (@2)))
- && wi::lt_p (@2, prec, TYPE_SIGN (TREE_TYPE (@2))))
- (with { unsigned int low = wi::add (@1, @2).to_uhwi (); }
+ (if (wi::ge_p (wi::to_wide (@1), 0, TYPE_SIGN (TREE_TYPE (@1)))
+ && wi::lt_p (wi::to_wide (@1), prec, TYPE_SIGN (TREE_TYPE (@1)))
+ && wi::ge_p (wi::to_wide (@2), 0, TYPE_SIGN (TREE_TYPE (@2)))
+ && wi::lt_p (wi::to_wide (@2), prec, TYPE_SIGN (TREE_TYPE (@2))))
+ (with { unsigned int low = (tree_to_uhwi (@1)
+ + tree_to_uhwi (@2)); }
/* Deal with a OP (c1 + c2) being undefined but (a OP c1) OP c2
being well defined. */
(if (low >= prec)
@@ -1888,13 +1958,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(for cmp (ne eq)
(simplify
(cmp (lshift INTEGER_CST@0 @1) INTEGER_CST@2)
- (with { int cand = wi::ctz (@2) - wi::ctz (@0); }
+ (with { int cand = wi::ctz (wi::to_wide (@2)) - wi::ctz (wi::to_wide (@0)); }
(if (cand < 0
|| (!integer_zerop (@2)
- && wi::ne_p (wi::lshift (@0, cand), @2)))
+ && wi::lshift (wi::to_wide (@0), cand) != wi::to_wide (@2)))
{ constant_boolean_node (cmp == NE_EXPR, type); }
(if (!integer_zerop (@2)
- && wi::eq_p (wi::lshift (@0, cand), @2))
+ && wi::lshift (wi::to_wide (@0), cand) == wi::to_wide (@2))
(cmp @1 { build_int_cst (TREE_TYPE (@1), cand); }))))))
/* Fold (X << C1) & C2 into (X << C1) & (C2 | ((1 << C1) - 1))
@@ -2432,7 +2502,10 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
{
bool overflow = false;
enum tree_code code, cmp_code = cmp;
- wide_int real_c1, c1 = @1, c2 = @2, c3 = @3;
+ wide_int real_c1;
+ wide_int c1 = wi::to_wide (@1);
+ wide_int c2 = wi::to_wide (@2);
+ wide_int c3 = wi::to_wide (@3);
signop sgn = TYPE_SIGN (from_type);
/* Handle special case A), given x of unsigned type:
@@ -2570,13 +2643,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(cmp @0 INTEGER_CST@1)
(if (tree_int_cst_sgn (@1) == -1)
- (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::add (@1, 1)); }))))
+ (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))))
(for cmp (ge lt)
acmp (gt le)
(simplify
(cmp @0 INTEGER_CST@1)
(if (tree_int_cst_sgn (@1) == 1)
- (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::sub (@1, 1)); }))))
+ (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))))
/* We can simplify a logical negation of a comparison to the
@@ -2940,7 +3013,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
else
real_trunc (&icst, fmt, cst);
- bool cst_int_p = real_identical (&icst, cst);
+ bool cst_int_p = !real_isnan (cst) && real_identical (&icst, cst);
bool overflow_p = false;
wide_int icst_val
@@ -2976,13 +3049,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(cmp (exact_div @0 @1) INTEGER_CST@2)
(if (!integer_zerop (@1))
- (if (wi::eq_p (@2, 0))
+ (if (wi::to_wide (@2) == 0)
(cmp @0 @2)
(if (TREE_CODE (@1) == INTEGER_CST)
(with
{
bool ovf;
- wide_int prod = wi::mul (@2, @1, TYPE_SIGN (TREE_TYPE (@1)), &ovf);
+ wide_int prod = wi::mul (wi::to_wide (@2), wi::to_wide (@1),
+ TYPE_SIGN (TREE_TYPE (@1)), &ovf);
}
(if (ovf)
{ constant_boolean_node (cmp == NE_EXPR, type); }
@@ -2990,14 +3064,16 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(for cmp (lt le gt ge)
(simplify
(cmp (exact_div @0 INTEGER_CST@1) INTEGER_CST@2)
- (if (wi::gt_p (@1, 0, TYPE_SIGN (TREE_TYPE (@1))))
+ (if (wi::gt_p (wi::to_wide (@1), 0, TYPE_SIGN (TREE_TYPE (@1))))
(with
{
bool ovf;
- wide_int prod = wi::mul (@2, @1, TYPE_SIGN (TREE_TYPE (@1)), &ovf);
+ wide_int prod = wi::mul (wi::to_wide (@2), wi::to_wide (@1),
+ TYPE_SIGN (TREE_TYPE (@1)), &ovf);
}
(if (ovf)
- { constant_boolean_node (wi::lt_p (@2, 0, TYPE_SIGN (TREE_TYPE (@2)))
+ { constant_boolean_node (wi::lt_p (wi::to_wide (@2), 0,
+ TYPE_SIGN (TREE_TYPE (@2)))
!= (cmp == LT_EXPR || cmp == LE_EXPR), type); }
(cmp @0 { wide_int_to_tree (TREE_TYPE (@0), prod); }))))))
@@ -3087,7 +3163,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(op (abs @0) zerop@1)
(op @0 @1)))
-/* From fold_sign_changed_comparison and fold_widened_comparison. */
+/* From fold_sign_changed_comparison and fold_widened_comparison.
+ FIXME: the lack of symmetry is disturbing. */
(for cmp (simple_comparison)
(simplify
(cmp (convert@0 @00) (convert?@1 @10))
@@ -3100,11 +3177,11 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
&& single_use (@0))
(if (TYPE_PRECISION (TREE_TYPE (@00)) == TYPE_PRECISION (TREE_TYPE (@0))
&& (TREE_CODE (@10) == INTEGER_CST
- || (@1 != @10 && types_match (TREE_TYPE (@10), TREE_TYPE (@00))))
+ || @1 != @10)
&& (TYPE_UNSIGNED (TREE_TYPE (@00)) == TYPE_UNSIGNED (TREE_TYPE (@0))
|| cmp == NE_EXPR
|| cmp == EQ_EXPR)
- && (POINTER_TYPE_P (TREE_TYPE (@00)) == POINTER_TYPE_P (TREE_TYPE (@0))))
+ && !POINTER_TYPE_P (TREE_TYPE (@00)))
/* ??? The special-casing of INTEGER_CST conversion was in the original
code and here to avoid a spurious overflow flag on the resulting
constant which fold_convert produces. */
@@ -3169,7 +3246,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(simplify
(cmp (convert?@3 (bit_ior @0 INTEGER_CST@1)) INTEGER_CST@2)
(if (tree_nop_conversion_p (TREE_TYPE (@3), TREE_TYPE (@0))
- && wi::bit_and_not (@1, @2) != 0)
+ && wi::bit_and_not (wi::to_wide (@1), wi::to_wide (@2)) != 0)
{ constant_boolean_node (cmp == NE_EXPR, type); }))
/* (X ^ Y) == 0 becomes X == Y, and (X ^ Y) != 0 becomes X != Y. */
@@ -3209,7 +3286,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(ne (bit_and @0 integer_pow2p@1) integer_zerop)
integer_pow2p@2 integer_zerop)
(with {
- int shift = wi::exact_log2 (@2) - wi::exact_log2 (@1);
+ int shift = (wi::exact_log2 (wi::to_wide (@2))
+ - wi::exact_log2 (wi::to_wide (@1)));
}
(if (shift > 0)
(bit_and
@@ -3226,7 +3304,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(if (INTEGRAL_TYPE_P (TREE_TYPE (@0))
&& type_has_mode_precision_p (TREE_TYPE (@0))
&& element_precision (@2) >= element_precision (@0)
- && wi::only_sign_bit_p (@1, element_precision (@0)))
+ && wi::only_sign_bit_p (wi::to_wide (@1), element_precision (@0)))
(with { tree stype = signed_type_for (TREE_TYPE (@0)); }
(ncmp (convert:stype @0) { build_zero_cst (stype); })))))
@@ -3238,7 +3316,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
integer_pow2p@1 integer_zerop)
(if (!TYPE_UNSIGNED (TREE_TYPE (@0)))
(with {
- int shift = element_precision (@0) - wi::exact_log2 (@1) - 1;
+ int shift = element_precision (@0) - wi::exact_log2 (wi::to_wide (@1)) - 1;
}
(if (shift >= 0)
(bit_and
@@ -3359,7 +3437,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
wide_int min = wi::min_value (arg1_type);
}
(switch
- (if (wi::eq_p (@1, max))
+ (if (wi::to_wide (@1) == max)
(switch
(if (cmp == GT_EXPR)
{ constant_boolean_node (false, type); })
@@ -3369,7 +3447,7 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
{ constant_boolean_node (true, type); })
(if (cmp == LT_EXPR)
(ne @2 @1))))
- (if (wi::eq_p (@1, min))
+ (if (wi::to_wide (@1) == min)
(switch
(if (cmp == LT_EXPR)
{ constant_boolean_node (false, type); })
@@ -3379,19 +3457,19 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
{ constant_boolean_node (true, type); })
(if (cmp == GT_EXPR)
(ne @2 @1))))
- (if (wi::eq_p (@1, max - 1))
+ (if (wi::to_wide (@1) == max - 1)
(switch
(if (cmp == GT_EXPR)
- (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::add (@1, 1)); }))
+ (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))
(if (cmp == LE_EXPR)
- (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::add (@1, 1)); }))))
- (if (wi::eq_p (@1, min + 1))
+ (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))))
+ (if (wi::to_wide (@1) == min + 1)
(switch
(if (cmp == GE_EXPR)
- (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::sub (@1, 1)); }))
+ (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))
(if (cmp == LT_EXPR)
- (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::sub (@1, 1)); }))))
- (if (wi::eq_p (@1, signed_max)
+ (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))))
+ (if (wi::to_wide (@1) == signed_max
&& TYPE_UNSIGNED (arg1_type)
/* We will flip the signedness of the comparison operator
associated with the mode of @1, so the sign bit is
@@ -3447,10 +3525,12 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(cmp:c (plus@2 @0 INTEGER_CST@1) @0)
(if (TYPE_UNSIGNED (TREE_TYPE (@0))
&& TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0))
- && wi::ne_p (@1, 0)
+ && wi::to_wide (@1) != 0
&& single_use (@2))
- (out @0 { wide_int_to_tree (TREE_TYPE (@0), wi::max_value
- (TYPE_PRECISION (TREE_TYPE (@0)), UNSIGNED) - @1); }))))
+ (with { unsigned int prec = TYPE_PRECISION (TREE_TYPE (@0)); }
+ (out @0 { wide_int_to_tree (TREE_TYPE (@0),
+ wi::max_value (prec, UNSIGNED)
+ - wi::to_wide (@1)); })))))
/* To detect overflow in unsigned A - B, A < B is simpler than A - B > A.
However, the detection logic for SUB_OVERFLOW in tree-ssa-math-opts.c
@@ -4012,13 +4092,13 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
(POWI @0 INTEGER_CST@1)
(switch
/* powi(x,0) -> 1. */
- (if (wi::eq_p (@1, 0))
+ (if (wi::to_wide (@1) == 0)
{ build_real (type, dconst1); })
/* powi(x,1) -> x. */
- (if (wi::eq_p (@1, 1))
+ (if (wi::to_wide (@1) == 1)
@0)
/* powi(x,-1) -> 1/x. */
- (if (wi::eq_p (@1, -1))
+ (if (wi::to_wide (@1) == -1)
(rdiv { build_real (type, dconst1); } @0))))
/* Narrowing of arithmetic and logical operations.
@@ -4083,8 +4163,9 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
&& types_match (@0, @1)
&& (tree_int_cst_min_precision (@4, TYPE_SIGN (TREE_TYPE (@0)))
<= TYPE_PRECISION (TREE_TYPE (@0)))
- && (wi::bit_and (@4, wi::mask (TYPE_PRECISION (TREE_TYPE (@0)),
- true, TYPE_PRECISION (type))) == 0))
+ && (wi::to_wide (@4)
+ & wi::mask (TYPE_PRECISION (TREE_TYPE (@0)),
+ true, TYPE_PRECISION (type))) == 0)
(if (TYPE_OVERFLOW_WRAPS (TREE_TYPE (@0)))
(with { tree ntype = TREE_TYPE (@0); }
(convert (bit_and (op @0 @1) (convert:ntype @4))))
@@ -4144,7 +4225,8 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
WARN_STRICT_OVERFLOW_CONDITIONAL);
bool less = cmp == LE_EXPR || cmp == LT_EXPR;
/* wi::ges_p (@2, 0) should be sufficient for a signed type. */
- bool ovf_high = wi::lt_p (@1, 0, TYPE_SIGN (TREE_TYPE (@1)))
+ bool ovf_high = wi::lt_p (wi::to_wide (@1), 0,
+ TYPE_SIGN (TREE_TYPE (@1)))
!= (op == MINUS_EXPR);
constant_boolean_node (less == ovf_high, type);
}
@@ -4270,10 +4352,14 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
isize = tree_to_uhwi (TYPE_SIZE (TREE_TYPE (@1)));
}
(switch
- (if (wi::leu_p (@ipos, @rpos)
- && wi::leu_p (wi::add (@rpos, @rsize), wi::add (@ipos, isize)))
+ (if (wi::leu_p (wi::to_wide (@ipos), wi::to_wide (@rpos))
+ && wi::leu_p (wi::to_wide (@rpos) + wi::to_wide (@rsize),
+ wi::to_wide (@ipos) + isize))
(BIT_FIELD_REF @1 @rsize { wide_int_to_tree (bitsizetype,
- wi::sub (@rpos, @ipos)); }))
- (if (wi::geu_p (@ipos, wi::add (@rpos, @rsize))
- || wi::geu_p (@rpos, wi::add (@ipos, isize)))
+ wi::to_wide (@rpos)
+ - wi::to_wide (@ipos)); }))
+ (if (wi::geu_p (wi::to_wide (@ipos),
+ wi::to_wide (@rpos) + wi::to_wide (@rsize))
+ || wi::geu_p (wi::to_wide (@rpos),
+ wi::to_wide (@ipos) + isize))
(BIT_FIELD_REF @0 @rsize @rpos)))))
diff --git a/gcc/modulo-sched.c b/gcc/modulo-sched.c
index f85011e..71b2a61 100644
--- a/gcc/modulo-sched.c
+++ b/gcc/modulo-sched.c
@@ -1422,15 +1422,15 @@ sms_schedule (void)
get_ebb_head_tail (bb, bb, &head, &tail);
latch_edge = loop_latch_edge (loop);
gcc_assert (single_exit (loop));
- if (single_exit (loop)->count > profile_count::zero ())
- trip_count = latch_edge->count.to_gcov_type ()
- / single_exit (loop)->count.to_gcov_type ();
+ if (single_exit (loop)->count () > profile_count::zero ())
+ trip_count = latch_edge->count ().to_gcov_type ()
+ / single_exit (loop)->count ().to_gcov_type ();
/* Perform SMS only on loops that their average count is above threshold. */
- if ( latch_edge->count > profile_count::zero ()
- && (latch_edge->count
- < single_exit (loop)->count.apply_scale
+ if ( latch_edge->count () > profile_count::zero ()
+ && (latch_edge->count()
+ < single_exit (loop)->count ().apply_scale
(SMS_LOOP_AVERAGE_COUNT_THRESHOLD, 1)))
{
if (dump_file)
@@ -1552,9 +1552,9 @@ sms_schedule (void)
latch_edge = loop_latch_edge (loop);
gcc_assert (single_exit (loop));
- if (single_exit (loop)->count > profile_count::zero ())
- trip_count = latch_edge->count.to_gcov_type ()
- / single_exit (loop)->count.to_gcov_type ();
+ if (single_exit (loop)->count ()> profile_count::zero ())
+ trip_count = latch_edge->count ().to_gcov_type ()
+ / single_exit (loop)->count ().to_gcov_type ();
if (dump_file)
{
diff --git a/gcc/objc/ChangeLog b/gcc/objc/ChangeLog
index d592949..a387814 100644
--- a/gcc/objc/ChangeLog
+++ b/gcc/objc/ChangeLog
@@ -1,3 +1,17 @@
+2017-10-17 Nathan Sidwell <nathan@acm.org>
+
+ * objc-act.c (objc_common_tree_size): Return size of TYPE nodes.
+
+2017-10-10 Richard Sandiford <richard.sandiford@linaro.org>
+
+ * objc-act.c (objc_decl_method_attributes): Use wi::to_wide when
+ operating on trees as wide_ints.
+
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ * objc-act.c (check_ivars, gen_declaration): For OBJCPLUS look at
+ DECL_BIT_FIELD_REPRESENTATIVE rather than DECL_INITIAL.
+
2017-08-30 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
diff --git a/gcc/objc/objc-act.c b/gcc/objc/objc-act.c
index 5f70961..765192c 100644
--- a/gcc/objc/objc-act.c
+++ b/gcc/objc/objc-act.c
@@ -4602,8 +4602,14 @@ check_ivars (tree inter, tree imp)
t1 = TREE_TYPE (intdecls); t2 = TREE_TYPE (impdecls);
if (!comptypes (t1, t2)
+#ifdef OBJCPLUS
+ || !tree_int_cst_equal (DECL_BIT_FIELD_REPRESENTATIVE (intdecls),
+ DECL_BIT_FIELD_REPRESENTATIVE (impdecls))
+#else
|| !tree_int_cst_equal (DECL_INITIAL (intdecls),
- DECL_INITIAL (impdecls)))
+ DECL_INITIAL (impdecls))
+#endif
+ )
{
if (DECL_NAME (intdecls) == DECL_NAME (impdecls))
{
@@ -4894,10 +4900,10 @@ objc_decl_method_attributes (tree *node, tree attributes, int flags)
number = TREE_VALUE (second_argument);
if (number
&& TREE_CODE (number) == INTEGER_CST
- && !wi::eq_p (number, 0))
+ && wi::to_wide (number) != 0)
TREE_VALUE (second_argument)
= wide_int_to_tree (TREE_TYPE (number),
- wi::add (number, 2));
+ wi::to_wide (number) + 2);
/* This is the third argument, the "first-to-check",
which specifies the index of the first argument to
@@ -4907,10 +4913,10 @@ objc_decl_method_attributes (tree *node, tree attributes, int flags)
number = TREE_VALUE (third_argument);
if (number
&& TREE_CODE (number) == INTEGER_CST
- && !wi::eq_p (number, 0))
+ && wi::to_wide (number) != 0)
TREE_VALUE (third_argument)
= wide_int_to_tree (TREE_TYPE (number),
- wi::add (number, 2));
+ wi::to_wide (number) + 2);
}
filtered_attributes = chainon (filtered_attributes,
new_attribute);
@@ -4943,10 +4949,10 @@ objc_decl_method_attributes (tree *node, tree attributes, int flags)
/* Get the value of the argument and add 2. */
tree number = TREE_VALUE (argument);
if (number && TREE_CODE (number) == INTEGER_CST
- && !wi::eq_p (number, 0))
+ && wi::to_wide (number) != 0)
TREE_VALUE (argument)
= wide_int_to_tree (TREE_TYPE (number),
- wi::add (number, 2));
+ wi::to_wide (number) + 2);
argument = TREE_CHAIN (argument);
}
@@ -8895,10 +8901,14 @@ gen_declaration (tree decl)
strcat (errbuf, IDENTIFIER_POINTER (DECL_NAME (decl)));
}
- if (DECL_INITIAL (decl)
- && TREE_CODE (DECL_INITIAL (decl)) == INTEGER_CST)
+#ifdef OBJCPLUS
+ tree w = DECL_BIT_FIELD_REPRESENTATIVE (decl);
+#else
+ tree w = DECL_INITIAL (decl);
+#endif
+ if (w && TREE_CODE (w) == INTEGER_CST)
sprintf (errbuf + strlen (errbuf), ": " HOST_WIDE_INT_PRINT_DEC,
- TREE_INT_CST_LOW (DECL_INITIAL (decl)));
+ TREE_INT_CST_LOW (w));
}
return errbuf;
@@ -10108,11 +10118,14 @@ objc_common_tree_size (enum tree_code code)
case CLASS_METHOD_DECL:
case INSTANCE_METHOD_DECL:
case KEYWORD_DECL:
- case PROPERTY_DECL:
- return sizeof (struct tree_decl_non_common);
+ case PROPERTY_DECL: return sizeof (tree_decl_non_common);
+ case CLASS_INTERFACE_TYPE:
+ case CLASS_IMPLEMENTATION_TYPE:
+ case CATEGORY_INTERFACE_TYPE:
+ case CATEGORY_IMPLEMENTATION_TYPE:
+ case PROTOCOL_INTERFACE_TYPE: return sizeof (tree_type_non_common);
default:
gcc_unreachable ();
-
}
}
diff --git a/gcc/omp-expand.c b/gcc/omp-expand.c
index 4bdcf19..0f45563 100644
--- a/gcc/omp-expand.c
+++ b/gcc/omp-expand.c
@@ -499,6 +499,42 @@ parallel_needs_hsa_kernel_p (struct omp_region *region)
return false;
}
+/* Change DECL_CONTEXT of CHILD_FNDECL to that of the parent function.
+ Add CHILD_FNDECL to decl chain of the supercontext of the block
+ ENTRY_BLOCK - this is the block which originally contained the
+ code from which CHILD_FNDECL was created.
+
+ Together, these actions ensure that the debug info for the outlined
+ function will be emitted with the correct lexical scope. */
+
+static void
+adjust_context_and_scope (tree entry_block, tree child_fndecl)
+{
+ if (entry_block != NULL_TREE && TREE_CODE (entry_block) == BLOCK)
+ {
+ tree b = BLOCK_SUPERCONTEXT (entry_block);
+
+ if (TREE_CODE (b) == BLOCK)
+ {
+ tree parent_fndecl;
+
+ /* Follow supercontext chain until the parent fndecl
+ is found. */
+ for (parent_fndecl = BLOCK_SUPERCONTEXT (b);
+ TREE_CODE (parent_fndecl) == BLOCK;
+ parent_fndecl = BLOCK_SUPERCONTEXT (parent_fndecl))
+ ;
+
+ gcc_assert (TREE_CODE (parent_fndecl) == FUNCTION_DECL);
+
+ DECL_CONTEXT (child_fndecl) = parent_fndecl;
+
+ DECL_CHAIN (child_fndecl) = BLOCK_VARS (b);
+ BLOCK_VARS (b) = child_fndecl;
+ }
+ }
+}
+
/* Build the function calls to GOMP_parallel_start etc to actually
generate the parallel operation. REGION is the parallel region
being expanded. BB is the block where to insert the code. WS_ARGS
@@ -668,6 +704,8 @@ expand_parallel_call (struct omp_region *region, basic_block bb,
tree child_fndecl = gimple_omp_parallel_child_fn (entry_stmt);
t2 = build_fold_addr_expr (child_fndecl);
+ adjust_context_and_scope (gimple_block (entry_stmt), child_fndecl);
+
vec_alloc (args, 4 + vec_safe_length (ws_args));
args->quick_push (t2);
args->quick_push (t1);
diff --git a/gcc/omp-low.c b/gcc/omp-low.c
index 8ed8f7c..afa758b 100644
--- a/gcc/omp-low.c
+++ b/gcc/omp-low.c
@@ -1626,6 +1626,14 @@ create_omp_child_function (omp_context *ctx, bool task_copy)
DECL_CONTEXT (decl) = NULL_TREE;
DECL_INITIAL (decl) = make_node (BLOCK);
BLOCK_SUPERCONTEXT (DECL_INITIAL (decl)) = decl;
+ DECL_ATTRIBUTES (decl) = DECL_ATTRIBUTES (current_function_decl);
+ DECL_FUNCTION_SPECIFIC_OPTIMIZATION (decl)
+ = DECL_FUNCTION_SPECIFIC_OPTIMIZATION (current_function_decl);
+ DECL_FUNCTION_SPECIFIC_TARGET (decl)
+ = DECL_FUNCTION_SPECIFIC_TARGET (current_function_decl);
+ DECL_FUNCTION_VERSIONED (decl)
+ = DECL_FUNCTION_VERSIONED (current_function_decl);
+
if (omp_maybe_offloaded_ctx (ctx))
{
cgraph_node::get_create (decl)->offloadable = 1;
@@ -3073,7 +3081,7 @@ scan_omp_1_op (tree *tp, int *walk_subtrees, void *data)
if (tem != TREE_TYPE (t))
{
if (TREE_CODE (t) == INTEGER_CST)
- *tp = wide_int_to_tree (tem, t);
+ *tp = wide_int_to_tree (tem, wi::to_wide (t));
else
TREE_TYPE (t) = tem;
}
@@ -6364,14 +6372,14 @@ lower_omp_ordered_clauses (gimple_stmt_iterator *gsi_p, gomp_ordered *ord_stmt,
tree itype = TREE_TYPE (TREE_VALUE (vec));
if (POINTER_TYPE_P (itype))
itype = sizetype;
- wide_int offset = wide_int::from (TREE_PURPOSE (vec),
+ wide_int offset = wide_int::from (wi::to_wide (TREE_PURPOSE (vec)),
TYPE_PRECISION (itype),
TYPE_SIGN (itype));
/* Ignore invalid offsets that are not multiples of the step. */
- if (!wi::multiple_of_p
- (wi::abs (offset), wi::abs ((wide_int) fd.loops[i].step),
- UNSIGNED))
+ if (!wi::multiple_of_p (wi::abs (offset),
+ wi::abs (wi::to_wide (fd.loops[i].step)),
+ UNSIGNED))
{
warning_at (OMP_CLAUSE_LOCATION (c), 0,
"ignoring sink clause with offset that is not "
diff --git a/gcc/optabs-query.c b/gcc/optabs-query.c
index ced6f57..204ca60 100644
--- a/gcc/optabs-query.c
+++ b/gcc/optabs-query.c
@@ -367,7 +367,7 @@ can_vec_perm_p (machine_mode mode, bool variable, vec_perm_indices *sel)
if (direct_optab_handler (vec_perm_const_optab, mode) != CODE_FOR_nothing
&& (sel == NULL
|| targetm.vectorize.vec_perm_const_ok == NULL
- || targetm.vectorize.vec_perm_const_ok (mode, &(*sel)[0])))
+ || targetm.vectorize.vec_perm_const_ok (mode, *sel)))
return true;
}
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 67dfa58..15ca315 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -138,8 +138,8 @@ add_equal_note (rtx_insn *insns, rtx target, enum rtx_code code, rtx op0, rtx op
if (GET_MODE (op0) != VOIDmode && GET_MODE (target) != GET_MODE (op0))
{
note = gen_rtx_fmt_e (code, GET_MODE (op0), copy_rtx (op0));
- if (GET_MODE_SIZE (GET_MODE (op0))
- > GET_MODE_SIZE (GET_MODE (target)))
+ if (GET_MODE_UNIT_SIZE (GET_MODE (op0))
+ > GET_MODE_UNIT_SIZE (GET_MODE (target)))
note = simplify_gen_unary (TRUNCATE, GET_MODE (target),
note, GET_MODE (op0));
else
@@ -173,12 +173,12 @@ widened_mode (machine_mode to_mode, rtx op0, rtx op1)
if (m0 == VOIDmode && m1 == VOIDmode)
return to_mode;
- else if (m0 == VOIDmode || GET_MODE_SIZE (m0) < GET_MODE_SIZE (m1))
+ else if (m0 == VOIDmode || GET_MODE_UNIT_SIZE (m0) < GET_MODE_UNIT_SIZE (m1))
result = m1;
else
result = m0;
- if (GET_MODE_SIZE (result) > GET_MODE_SIZE (to_mode))
+ if (GET_MODE_UNIT_SIZE (result) > GET_MODE_UNIT_SIZE (to_mode))
return to_mode;
return result;
@@ -2977,9 +2977,9 @@ expand_unop (machine_mode mode, optab unoptab, rtx op0, rtx target,
else
{
eq_value = gen_rtx_fmt_e (optab_to_code (unoptab), mode, op0);
- if (GET_MODE_SIZE (outmode) < GET_MODE_SIZE (mode))
+ if (GET_MODE_UNIT_SIZE (outmode) < GET_MODE_UNIT_SIZE (mode))
eq_value = simplify_gen_unary (TRUNCATE, outmode, eq_value, mode);
- else if (GET_MODE_SIZE (outmode) > GET_MODE_SIZE (mode))
+ else if (GET_MODE_UNIT_SIZE (outmode) > GET_MODE_UNIT_SIZE (mode))
eq_value = simplify_gen_unary (ZERO_EXTEND,
outmode, eq_value, mode);
}
@@ -4655,7 +4655,8 @@ expand_float (rtx to, rtx from, int unsignedp)
int doing_unsigned = unsignedp;
if (fmode != GET_MODE (to)
- && significand_size (fmode) < GET_MODE_PRECISION (GET_MODE (from)))
+ && (significand_size (fmode)
+ < GET_MODE_UNIT_PRECISION (GET_MODE (from))))
continue;
icode = can_float_p (fmode, imode, unsignedp);
@@ -6273,10 +6274,10 @@ expand_atomic_compare_and_swap (rtx *ptarget_bool, rtx *ptarget_oval,
return true;
}
-/* Generate asm volatile("" : : : "memory") as the memory barrier. */
+/* Generate asm volatile("" : : : "memory") as the memory blockage. */
static void
-expand_asm_memory_barrier (void)
+expand_asm_memory_blockage (void)
{
rtx asm_op, clob;
@@ -6292,6 +6293,17 @@ expand_asm_memory_barrier (void)
emit_insn (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, asm_op, clob)));
}
+/* Do not propagate memory accesses across this point. */
+
+static void
+expand_memory_blockage (void)
+{
+ if (targetm.have_memory_blockage ())
+ emit_insn (targetm.gen_memory_blockage ());
+ else
+ expand_asm_memory_blockage ();
+}
+
/* This routine will either emit the mem_thread_fence pattern or issue a
sync_synchronize to generate a fence for memory model MEMMODEL. */
@@ -6303,14 +6315,14 @@ expand_mem_thread_fence (enum memmodel model)
if (targetm.have_mem_thread_fence ())
{
emit_insn (targetm.gen_mem_thread_fence (GEN_INT (model)));
- expand_asm_memory_barrier ();
+ expand_memory_blockage ();
}
else if (targetm.have_memory_barrier ())
emit_insn (targetm.gen_memory_barrier ());
else if (synchronize_libfunc != NULL_RTX)
emit_library_call (synchronize_libfunc, LCT_NORMAL, VOIDmode);
else
- expand_asm_memory_barrier ();
+ expand_memory_blockage ();
}
/* Emit a signal fence with given memory model. */
@@ -6321,7 +6333,7 @@ expand_mem_signal_fence (enum memmodel model)
/* No machine barrier is required to implement a signal fence, but
a compiler memory barrier must be issued, except for relaxed MM. */
if (!is_mm_relaxed (model))
- expand_asm_memory_barrier ();
+ expand_memory_blockage ();
}
/* This function expands the atomic load operation:
@@ -6343,7 +6355,7 @@ expand_atomic_load (rtx target, rtx mem, enum memmodel model)
struct expand_operand ops[3];
rtx_insn *last = get_last_insn ();
if (is_mm_seq_cst (model))
- expand_asm_memory_barrier ();
+ expand_memory_blockage ();
create_output_operand (&ops[0], target, mode);
create_fixed_operand (&ops[1], mem);
@@ -6351,7 +6363,7 @@ expand_atomic_load (rtx target, rtx mem, enum memmodel model)
if (maybe_expand_insn (icode, 3, ops))
{
if (!is_mm_relaxed (model))
- expand_asm_memory_barrier ();
+ expand_memory_blockage ();
return ops[0].value;
}
delete_insns_since (last);
@@ -6401,14 +6413,14 @@ expand_atomic_store (rtx mem, rtx val, enum memmodel model, bool use_release)
{
rtx_insn *last = get_last_insn ();
if (!is_mm_relaxed (model))
- expand_asm_memory_barrier ();
+ expand_memory_blockage ();
create_fixed_operand (&ops[0], mem);
create_input_operand (&ops[1], val, mode);
create_integer_operand (&ops[2], model);
if (maybe_expand_insn (icode, 3, ops))
{
if (is_mm_seq_cst (model))
- expand_asm_memory_barrier ();
+ expand_memory_blockage ();
return const0_rtx;
}
delete_insns_since (last);
diff --git a/gcc/optc-gen.awk b/gcc/optc-gen.awk
index 3cb0005..295bae1 100644
--- a/gcc/optc-gen.awk
+++ b/gcc/optc-gen.awk
@@ -328,7 +328,7 @@ for (i = 0; i < n_opts; i++) {
alias_data = "NULL, NULL, N_OPTS"
if (flag_set_p("Enum.*", flags[i])) {
if (!flag_set_p("RejectNegative", flags[i]) \
- && opts[i] ~ "^[Wfm]")
+ && opts[i] ~ "^[Wfgm]")
print "#error Enum allowing negative form"
}
} else {
@@ -370,7 +370,7 @@ for (i = 0; i < n_opts; i++) {
if (flag_set_p("RejectNegative", flags[i]))
idx = -1;
else {
- if (opts[i] ~ "^[Wfm]")
+ if (opts[i] ~ "^[Wfgm]")
idx = indices[opts[i]];
else
idx = -1;
diff --git a/gcc/optc-save-gen.awk b/gcc/optc-save-gen.awk
index fc58210..7e73435 100644
--- a/gcc/optc-save-gen.awk
+++ b/gcc/optc-save-gen.awk
@@ -678,7 +678,7 @@ for (i = 0; i < n_target_array; i++) {
}
for (i = 0; i < n_target_val; i++) {
name = var_target_val[i]
- print " hstate.add_wide_int (ptr->" name");";
+ print " hstate.add_hwi (ptr->" name");";
}
print " return hstate.end ();";
print "}";
@@ -766,7 +766,7 @@ for (i = 0; i < n_opt_val; i++) {
if (!var_opt_hash[i])
continue;
name = var_opt_val[i]
- print " hstate.add_wide_int (ptr->" name");";
+ print " hstate.add_hwi (ptr->" name");";
}
print " return hstate.end ();";
print "}";
diff --git a/gcc/opts-common.c b/gcc/opts-common.c
index d756814..e78ab88 100644
--- a/gcc/opts-common.c
+++ b/gcc/opts-common.c
@@ -28,6 +28,24 @@ along with GCC; see the file COPYING3. If not see
static void prune_options (struct cl_decoded_option **, unsigned int *);
+/* An option that is undocumented, that takes a joined argument, and
+ that doesn't fit any of the classes of uses (language/common,
+ driver, target) is assumed to be a prefix used to catch
+ e.g. negated options, and stop them from being further shortened to
+ a prefix that could use the negated option as an argument. For
+ example, we want -gno-statement-frontiers to be taken as a negation
+ of -gstatement-frontiers, but without catching the gno- prefix and
+ signaling it's to be used for option remapping, it would end up
+ backtracked to g with no-statemnet-frontiers as the debug level. */
+
+static bool
+remapping_prefix_p (const struct cl_option *opt)
+{
+ return opt->flags & CL_UNDOCUMENTED
+ && opt->flags & CL_JOINED
+ && !(opt->flags & (CL_DRIVER | CL_TARGET | CL_COMMON | CL_LANG_ALL));
+}
+
/* Perform a binary search to find which option the command-line INPUT
matches. Returns its index in the option array, and
OPT_SPECIAL_unknown on failure.
@@ -98,6 +116,9 @@ find_opt (const char *input, unsigned int lang_mask)
if (opt->flags & lang_mask)
return mn;
+ if (remapping_prefix_p (opt))
+ return OPT_SPECIAL_unknown;
+
/* If we haven't remembered a prior match, remember this
one. Any prior match is necessarily better. */
if (match_wrong_lang == OPT_SPECIAL_unknown)
@@ -286,7 +307,8 @@ generate_canonical_option (size_t opt_index, const char *arg, int value,
if (value == 0
&& !option->cl_reject_negative
- && (opt_text[1] == 'W' || opt_text[1] == 'f' || opt_text[1] == 'm'))
+ && (opt_text[1] == 'W' || opt_text[1] == 'f'
+ || opt_text[1] == 'g' || opt_text[1] == 'm'))
{
char *t = XOBNEWVEC (&opts_obstack, char, option->opt_len + 5);
t[0] = '-';
@@ -349,6 +371,7 @@ static const struct option_map option_map[] =
{
{ "-Wno-", NULL, "-W", false, true },
{ "-fno-", NULL, "-f", false, true },
+ { "-gno-", NULL, "-g", false, true },
{ "-mno-", NULL, "-m", false, true },
{ "--debug=", NULL, "-g", false, false },
{ "--machine-", NULL, "-m", true, false },
@@ -394,6 +417,8 @@ add_misspelling_candidates (auto_vec<char *> *candidates,
gcc_assert (candidates);
gcc_assert (option);
gcc_assert (opt_text);
+ if (remapping_prefix_p (option))
+ return;
candidates->safe_push (xstrdup (opt_text + 1));
for (unsigned i = 0; i < ARRAY_SIZE (option_map); i++)
{
diff --git a/gcc/opts.c b/gcc/opts.c
index 5aa5d06..ee95c84 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1521,6 +1521,7 @@ const struct sanitizer_opts_s sanitizer_opts[] =
SANITIZER_OPT (object-size, SANITIZE_OBJECT_SIZE, true),
SANITIZER_OPT (vptr, SANITIZE_VPTR, true),
SANITIZER_OPT (pointer-overflow, SANITIZE_POINTER_OVERFLOW, true),
+ SANITIZER_OPT (builtin, SANITIZE_BUILTIN, true),
SANITIZER_OPT (all, ~0U, true),
#undef SANITIZER_OPT
{ NULL, 0U, 0UL, false }
@@ -1700,11 +1701,10 @@ parse_sanitizer_options (const char *p, location_t loc, int scode,
}
/* Parse string values of no_sanitize attribute passed in VALUE.
- Values are separated with comma. Wrong argument is stored to
- WRONG_ARGUMENT variable. */
+ Values are separated with comma. */
unsigned int
-parse_no_sanitize_attribute (char *value, char **wrong_argument)
+parse_no_sanitize_attribute (char *value)
{
unsigned int flags = 0;
unsigned int i;
@@ -1722,7 +1722,8 @@ parse_no_sanitize_attribute (char *value, char **wrong_argument)
}
if (sanitizer_opts[i].name == NULL)
- *wrong_argument = q;
+ warning (OPT_Wattributes,
+ "%<%s%> attribute directive ignored", q);
q = strtok (NULL, ",");
}
diff --git a/gcc/opts.h b/gcc/opts.h
index 2774e2c..1093861 100644
--- a/gcc/opts.h
+++ b/gcc/opts.h
@@ -390,7 +390,7 @@ extern void handle_common_deferred_options (void);
unsigned int parse_sanitizer_options (const char *, location_t, int,
unsigned int, int, bool);
-unsigned int parse_no_sanitize_attribute (char *value, char **wrong_argument);
+unsigned int parse_no_sanitize_attribute (char *value);
extern bool common_handle_option (struct gcc_options *opts,
struct gcc_options *opts_set,
const struct cl_decoded_option *decoded,
diff --git a/gcc/params.def b/gcc/params.def
index 805302b..8881f4c 100644
--- a/gcc/params.def
+++ b/gcc/params.def
@@ -213,6 +213,16 @@ DEFPARAM(PARAM_STACK_FRAME_GROWTH,
"Maximal stack frame growth due to inlining (in percent).",
1000, 0, 0)
+DEFPARAM(PARAM_STACK_CLASH_PROTECTION_GUARD_SIZE,
+ "stack-clash-protection-guard-size",
+ "Size of the stack guard expressed as a power of two.",
+ 12, 12, 30)
+
+DEFPARAM(PARAM_STACK_CLASH_PROTECTION_PROBE_INTERVAL,
+ "stack-clash-protection-probe-interval",
+ "Interval in which to probe the stack expressed as a power of two.",
+ 12, 10, 16)
+
/* The GCSE optimization will be disabled if it would require
significantly more memory than this value. */
DEFPARAM(PARAM_MAX_GCSE_MEMORY,
@@ -863,14 +873,7 @@ DEFPARAM (PARAM_LOOP_BLOCK_TILE_SIZE,
DEFPARAM (PARAM_GRAPHITE_MAX_NB_SCOP_PARAMS,
"graphite-max-nb-scop-params",
"maximum number of parameters in a SCoP.",
- 7, 0, 0)
-
-/* Maximal number of basic blocks in the functions analyzed by Graphite. */
-
-DEFPARAM (PARAM_GRAPHITE_MAX_BBS_PER_FUNCTION,
- "graphite-max-bbs-per-function",
- "maximum number of basic blocks per function to be analyzed by Graphite.",
- 100, 0, 0)
+ 10, 0, 0)
/* Maximal number of array references in a scop. */
@@ -879,18 +882,17 @@ DEFPARAM (PARAM_GRAPHITE_MAX_ARRAYS_PER_SCOP,
"maximum number of arrays per scop.",
100, 0, 0)
-/* Maximal number of basic blocks in the functions analyzed by Graphite. */
-
-DEFPARAM (PARAM_GRAPHITE_MIN_LOOPS_PER_FUNCTION,
- "graphite-min-loops-per-function",
- "minimal number of loops per function to be analyzed by Graphite.",
- 2, 0, 0)
-
DEFPARAM (PARAM_MAX_ISL_OPERATIONS,
"max-isl-operations",
"maximum number of isl operations, 0 means unlimited",
350000, 0, 0)
+/* For testsuite purposes allow to check for codegen error handling. */
+DEFPARAM (PARAM_GRAPHITE_ALLOW_CODEGEN_ERRORS,
+ "graphite-allow-codegen-errors",
+ "whether codegen errors should be ICEs when -fchecking.",
+ 0, 0, 1)
+
/* Avoid data dependence analysis on very large loops. */
DEFPARAM (PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS,
"loop-max-datarefs-for-datadeps",
diff --git a/gcc/passes.c b/gcc/passes.c
index 2c9add8..65568e0 100644
--- a/gcc/passes.c
+++ b/gcc/passes.c
@@ -197,7 +197,9 @@ rest_of_decl_compilation (tree decl,
/* Can't defer this, because it needs to happen before any
later function definitions are processed. */
- if (DECL_ASSEMBLER_NAME_SET_P (decl) && DECL_REGISTER (decl))
+ if (HAS_DECL_ASSEMBLER_NAME_P (decl)
+ && DECL_ASSEMBLER_NAME_SET_P (decl)
+ && DECL_REGISTER (decl))
make_decl_rtl (decl);
/* Forward declarations for nested functions are not "external",
diff --git a/gcc/postreload-gcse.c b/gcc/postreload-gcse.c
index a1dcac2..15fdb7e 100644
--- a/gcc/postreload-gcse.c
+++ b/gcc/postreload-gcse.c
@@ -1108,14 +1108,14 @@ eliminate_partially_redundant_load (basic_block bb, rtx_insn *insn,
avail_insn = NULL;
}
- if (EDGE_CRITICAL_P (pred) && pred->count.initialized_p ())
- critical_count += pred->count;
+ if (EDGE_CRITICAL_P (pred) && pred->count ().initialized_p ())
+ critical_count += pred->count ();
if (avail_insn != NULL_RTX)
{
npred_ok++;
- if (pred->count.initialized_p ())
- ok_count = ok_count + pred->count;
+ if (pred->count ().initialized_p ())
+ ok_count = ok_count + pred->count ();
if (! set_noop_p (PATTERN (gen_move_insn (copy_rtx (dest),
copy_rtx (avail_reg)))))
{
@@ -1139,8 +1139,8 @@ eliminate_partially_redundant_load (basic_block bb, rtx_insn *insn,
/* Adding a load on a critical edge will cause a split. */
if (EDGE_CRITICAL_P (pred))
critical_edge_split = true;
- if (pred->count.initialized_p ())
- not_ok_count = not_ok_count + pred->count;
+ if (pred->count ().initialized_p ())
+ not_ok_count = not_ok_count + pred->count ();
unoccr = (struct unoccr *) obstack_alloc (&unoccr_obstack,
sizeof (struct unoccr));
unoccr->insn = NULL;
diff --git a/gcc/predict.c b/gcc/predict.c
index 80c2c19..0a85d0b 100644
--- a/gcc/predict.c
+++ b/gcc/predict.c
@@ -203,7 +203,7 @@ maybe_hot_bb_p (struct function *fun, const_basic_block bb)
bool
maybe_hot_edge_p (edge e)
{
- if (!maybe_hot_count_p (cfun, e->count))
+ if (!maybe_hot_count_p (cfun, e->count ()))
return false;
return maybe_hot_frequency_p (cfun, EDGE_FREQUENCY (e));
}
@@ -247,7 +247,7 @@ probably_never_executed_bb_p (struct function *fun, const_basic_block bb)
static bool
unlikely_executed_edge_p (edge e)
{
- return (e->count == profile_count::zero ()
+ return (e->count () == profile_count::zero ()
|| e->probability == profile_probability::never ())
|| (e->flags & (EDGE_EH | EDGE_FAKE));
}
@@ -259,7 +259,7 @@ probably_never_executed_edge_p (struct function *fun, edge e)
{
if (unlikely_executed_edge_p (e))
return true;
- return probably_never_executed (fun, e->count, EDGE_FREQUENCY (e));
+ return probably_never_executed (fun, e->count (), EDGE_FREQUENCY (e));
}
/* Return true when current function should always be optimized for size. */
@@ -746,8 +746,8 @@ dump_prediction (FILE *file, enum br_predictor predictor, int probability,
if (e)
{
fprintf (file, " hit ");
- e->count.dump (file);
- fprintf (file, " (%.1f%%)", e->count.to_gcov_type() * 100.0
+ e->count ().dump (file);
+ fprintf (file, " (%.1f%%)", e->count ().to_gcov_type() * 100.0
/ bb->count.to_gcov_type ());
}
}
@@ -3199,21 +3199,14 @@ drop_profile (struct cgraph_node *node, profile_count call_count)
FOR_ALL_BB_FN (bb, fn)
{
bb->count = profile_count::uninitialized ();
-
- edge_iterator ei;
- edge e;
- FOR_EACH_EDGE (e, ei, bb->preds)
- e->count = profile_count::uninitialized ();
}
struct cgraph_edge *e;
for (e = node->callees; e; e = e->next_caller)
{
- e->count = profile_count::uninitialized ();
e->frequency = compute_call_stmt_bb_frequency (e->caller->decl,
gimple_bb (e->call_stmt));
}
- node->count = profile_count::uninitialized ();
profile_status_for_fn (fn)
= (flag_guess_branch_prob ? PROFILE_GUESSED : PROFILE_ABSENT);
@@ -3396,7 +3389,7 @@ propagate_unlikely_bbs_forward (void)
{
bb = worklist.pop ();
FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->count == profile_count::zero ())
+ if (!(e->count () == profile_count::zero ())
&& !(e->dest->count == profile_count::zero ())
&& !e->dest->aux)
{
@@ -3417,8 +3410,6 @@ propagate_unlikely_bbs_forward (void)
bb->index);
bb->count = profile_count::zero ();
bb->frequency = 0;
- FOR_EACH_EDGE (e, ei, bb->succs)
- e->count = profile_count::zero ();
}
else
bb->aux = NULL;
@@ -3450,20 +3441,16 @@ determine_unlikely_bbs ()
}
if (bb->count == profile_count::zero ())
- {
- bb->frequency = 0;
- FOR_EACH_EDGE (e, ei, bb->preds)
- e->count = profile_count::zero ();
- }
+ bb->frequency = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->count == profile_count::zero ())
+ if (!(e->probability == profile_probability::never ())
&& unlikely_executed_edge_p (e))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "Edge %i->%i is locally unlikely\n",
bb->index, e->dest->index);
- e->count = profile_count::zero ();
+ e->probability = profile_probability::never ();
}
gcc_checking_assert (!bb->aux);
@@ -3477,7 +3464,8 @@ determine_unlikely_bbs ()
{
nsuccs[bb->index] = 0;
FOR_EACH_EDGE (e, ei, bb->succs)
- if (!(e->count == profile_count::zero ()))
+ if (!(e->probability == profile_probability::never ())
+ && !(e->dest->count == profile_count::zero ()))
nsuccs[bb->index]++;
if (!nsuccs[bb->index])
worklist.safe_push (bb);
@@ -3511,9 +3499,9 @@ determine_unlikely_bbs ()
bb->count = profile_count::zero ();
bb->frequency = 0;
FOR_EACH_EDGE (e, ei, bb->preds)
- if (!(e->count == profile_count::zero ()))
+ if (!(e->probability == profile_probability::never ()))
{
- e->count = profile_count::zero ();
+ e->probability = profile_probability::never ();
if (!(e->src->count == profile_count::zero ()))
{
nsuccs[e->src->index]--;
@@ -3613,7 +3601,10 @@ compute_function_frequency (void)
if (ENTRY_BLOCK_PTR_FOR_FN (cfun)->count == profile_count::zero ()
|| lookup_attribute ("cold", DECL_ATTRIBUTES (current_function_decl))
!= NULL)
- node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
+ {
+ node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
+ warn_function_cold (current_function_decl);
+ }
else if (lookup_attribute ("hot", DECL_ATTRIBUTES (current_function_decl))
!= NULL)
node->frequency = NODE_FREQUENCY_HOT;
@@ -3632,7 +3623,10 @@ compute_function_frequency (void)
Ipa-profile pass will drop functions only called from unlikely
functions to unlikely and that is most of what we care about. */
if (!cfun->after_inlining)
- node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
+ {
+ node->frequency = NODE_FREQUENCY_UNLIKELY_EXECUTED;
+ warn_function_cold (current_function_decl);
+ }
FOR_EACH_BB_FN (bb, cfun)
{
if (maybe_hot_bb_p (cfun, bb))
@@ -3922,8 +3916,6 @@ force_edge_cold (edge e, bool impossible)
profile_probability prob_sum = profile_probability::never ();
edge_iterator ei;
edge e2;
- profile_count old_count = e->count;
- profile_probability old_probability = e->probability;
bool uninitialized_exit = false;
profile_probability goal = (impossible ? profile_probability::never ()
@@ -3931,13 +3923,13 @@ force_edge_cold (edge e, bool impossible)
/* If edge is already improbably or cold, just return. */
if (e->probability <= goal
- && (!impossible || e->count == profile_count::zero ()))
+ && (!impossible || e->count () == profile_count::zero ()))
return;
FOR_EACH_EDGE (e2, ei, e->src->succs)
if (e2 != e)
{
- if (e2->count.initialized_p ())
- count_sum += e2->count;
+ if (e2->count ().initialized_p ())
+ count_sum += e2->count ();
else
uninitialized_exit = true;
if (e2->probability.initialized_p ())
@@ -3950,13 +3942,6 @@ force_edge_cold (edge e, bool impossible)
{
if (!(e->probability < goal))
e->probability = goal;
- if (impossible)
- e->count = profile_count::zero ();
- else if (old_probability > profile_probability::never ())
- e->count = e->count.apply_probability (e->probability
- / old_probability);
- else
- e->count = e->count.apply_scale (1, REG_BR_PROB_BASE);
profile_probability prob_comp = prob_sum / e->probability.invert ();
@@ -3965,12 +3950,9 @@ force_edge_cold (edge e, bool impossible)
"probability to other edges.\n",
e->src->index, e->dest->index,
impossible ? "impossible" : "cold");
- profile_count count_sum2 = count_sum + old_count - e->count;
FOR_EACH_EDGE (e2, ei, e->src->succs)
if (e2 != e)
{
- if (count_sum > 0)
- e2->count.apply_scale (count_sum2, count_sum);
e2->probability /= prob_comp;
}
if (current_ir_type () != IR_GIMPLE
@@ -4021,7 +4003,6 @@ force_edge_cold (edge e, bool impossible)
fprintf (dump_file,
"Making bb %i impossible and dropping count to 0.\n",
e->src->index);
- e->count = profile_count::zero ();
e->src->count = profile_count::zero ();
FOR_EACH_EDGE (e2, ei, e->src->preds)
force_edge_cold (e2, impossible);
@@ -4044,10 +4025,10 @@ force_edge_cold (edge e, bool impossible)
impossible ? "impossible" : "cold");
e->src->frequency = MIN (e->src->frequency, impossible ? 0 : 1);
if (impossible)
- e->src->count = e->count = profile_count::zero ();
+ e->src->count = profile_count::zero ();
else
- e->src->count = e->count = e->count.apply_scale (e->src->frequency,
- old_frequency);
+ e->src->count = e->count ().apply_scale (e->src->frequency,
+ old_frequency);
force_edge_cold (single_pred_edge (e->src), impossible);
}
else if (dump_file && (dump_flags & TDF_DETAILS)
diff --git a/gcc/predict.h b/gcc/predict.h
index 9b8b140..1b73ae2 100644
--- a/gcc/predict.h
+++ b/gcc/predict.h
@@ -102,4 +102,7 @@ extern void propagate_unlikely_bbs_forward (void);
extern void add_reg_br_prob_note (rtx_insn *, profile_probability);
+/* In ipa-pure-const.c */
+extern void warn_function_cold (tree);
+
#endif /* GCC_PREDICT_H */
diff --git a/gcc/pretty-print.c b/gcc/pretty-print.c
index 7340cd4..e66d898 100644
--- a/gcc/pretty-print.c
+++ b/gcc/pretty-print.c
@@ -30,6 +30,666 @@ along with GCC; see the file COPYING3. If not see
#include <iconv.h>
#endif
+#ifdef __MINGW32__
+
+/* Replacement for fputs() that handles ANSI escape codes on Windows NT.
+ Contributed by: Liu Hao (lh_mouse at 126 dot com)
+
+ XXX: This file is compiled into libcommon.a that will be self-contained.
+ It looks like that these functions can be put nowhere else. */
+
+#include <io.h>
+#define WIN32_LEAN_AND_MEAN 1
+#include <windows.h>
+
+/* Write all bytes in [s,s+n) into the specified stream.
+ Errors are ignored. */
+static void
+write_all (HANDLE h, const char *s, size_t n)
+{
+ size_t rem = n;
+ DWORD step;
+
+ while (rem != 0)
+ {
+ if (rem <= UINT_MAX)
+ step = rem;
+ else
+ step = UINT_MAX;
+ if (!WriteFile (h, s + n - rem, step, &step, NULL))
+ break;
+ rem -= step;
+ }
+}
+
+/* Find the beginning of an escape sequence.
+ There are two cases:
+ 1. If the sequence begins with an ESC character (0x1B) and a second
+ character X in [0x40,0x5F], returns X and stores a pointer to
+ the third character into *head.
+ 2. If the sequence begins with a character X in [0x80,0x9F], returns
+ (X-0x40) and stores a pointer to the second character into *head.
+ Stores the number of ESC character(s) in *prefix_len.
+ Returns 0 if no such sequence can be found. */
+static int
+find_esc_head (int *prefix_len, const char **head, const char *str)
+{
+ int c;
+ const char *r = str;
+ int escaped = 0;
+
+ for (;;)
+ {
+ c = (unsigned char) *r;
+ if (c == 0)
+ {
+ /* Not found. */
+ return 0;
+ }
+ if (escaped && 0x40 <= c && c <= 0x5F)
+ {
+ /* Found (case 1). */
+ *prefix_len = 2;
+ *head = r + 1;
+ return c;
+ }
+ if (0x80 <= c && c <= 0x9F)
+ {
+ /* Found (case 2). */
+ *prefix_len = 1;
+ *head = r + 1;
+ return c - 0x40;
+ }
+ ++r;
+ escaped = c == 0x1B;
+ }
+}
+
+/* Find the terminator of an escape sequence.
+ str should be the value stored in *head by a previous successful
+ call to find_esc_head().
+ Returns 0 if no such sequence can be found. */
+static int
+find_esc_terminator (const char **term, const char *str)
+{
+ int c;
+ const char *r = str;
+
+ for (;;)
+ {
+ c = (unsigned char) *r;
+ if (c == 0)
+ {
+ /* Not found. */
+ return 0;
+ }
+ if (0x40 <= c && c <= 0x7E)
+ {
+ /* Found. */
+ *term = r;
+ return c;
+ }
+ ++r;
+ }
+}
+
+/* Handle a sequence of codes. Sequences that are invalid, reserved,
+ unrecognized or unimplemented are ignored silently.
+ There isn't much we can do because of lameness of Windows consoles. */
+static void
+eat_esc_sequence (HANDLE h, int esc_code,
+ const char *esc_head, const char *esc_term)
+{
+ /* Numbers in an escape sequence cannot be negative, because
+ a minus sign in the middle of it would have terminated it. */
+ long n1, n2;
+ char *eptr, *delim;
+ CONSOLE_SCREEN_BUFFER_INFO sb;
+ COORD cr;
+ /* ED and EL parameters. */
+ DWORD cnt, step;
+ long rows;
+ /* SGR parameters. */
+ WORD attrib_add, attrib_rm;
+ const char *param;
+
+ switch (MAKEWORD (esc_code, *esc_term))
+ {
+ /* ESC [ n1 'A'
+ Move the cursor up by n1 characters. */
+ case MAKEWORD ('[', 'A'):
+ if (esc_head == esc_term)
+ n1 = 1;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ cr = sb.dwCursorPosition;
+ /* Stop at the topmost boundary. */
+ if (cr.Y > n1)
+ cr.Y -= n1;
+ else
+ cr.Y = 0;
+ SetConsoleCursorPosition (h, cr);
+ }
+ break;
+
+ /* ESC [ n1 'B'
+ Move the cursor down by n1 characters. */
+ case MAKEWORD ('[', 'B'):
+ if (esc_head == esc_term)
+ n1 = 1;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ cr = sb.dwCursorPosition;
+ /* Stop at the bottommost boundary. */
+ if (sb.dwSize.Y - cr.Y > n1)
+ cr.Y += n1;
+ else
+ cr.Y = sb.dwSize.Y;
+ SetConsoleCursorPosition (h, cr);
+ }
+ break;
+
+ /* ESC [ n1 'C'
+ Move the cursor right by n1 characters. */
+ case MAKEWORD ('[', 'C'):
+ if (esc_head == esc_term)
+ n1 = 1;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ cr = sb.dwCursorPosition;
+ /* Stop at the rightmost boundary. */
+ if (sb.dwSize.X - cr.X > n1)
+ cr.X += n1;
+ else
+ cr.X = sb.dwSize.X;
+ SetConsoleCursorPosition (h, cr);
+ }
+ break;
+
+ /* ESC [ n1 'D'
+ Move the cursor left by n1 characters. */
+ case MAKEWORD ('[', 'D'):
+ if (esc_head == esc_term)
+ n1 = 1;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ cr = sb.dwCursorPosition;
+ /* Stop at the leftmost boundary. */
+ if (cr.X > n1)
+ cr.X -= n1;
+ else
+ cr.X = 0;
+ SetConsoleCursorPosition (h, cr);
+ }
+ break;
+
+ /* ESC [ n1 'E'
+ Move the cursor to the beginning of the n1-th line downwards. */
+ case MAKEWORD ('[', 'E'):
+ if (esc_head == esc_term)
+ n1 = 1;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ cr = sb.dwCursorPosition;
+ cr.X = 0;
+ /* Stop at the bottommost boundary. */
+ if (sb.dwSize.Y - cr.Y > n1)
+ cr.Y += n1;
+ else
+ cr.Y = sb.dwSize.Y;
+ SetConsoleCursorPosition (h, cr);
+ }
+ break;
+
+ /* ESC [ n1 'F'
+ Move the cursor to the beginning of the n1-th line upwards. */
+ case MAKEWORD ('[', 'F'):
+ if (esc_head == esc_term)
+ n1 = 1;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ cr = sb.dwCursorPosition;
+ cr.X = 0;
+ /* Stop at the topmost boundary. */
+ if (cr.Y > n1)
+ cr.Y -= n1;
+ else
+ cr.Y = 0;
+ SetConsoleCursorPosition (h, cr);
+ }
+ break;
+
+ /* ESC [ n1 'G'
+ Move the cursor to the (1-based) n1-th column. */
+ case MAKEWORD ('[', 'G'):
+ if (esc_head == esc_term)
+ n1 = 1;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ cr = sb.dwCursorPosition;
+ n1 -= 1;
+ /* Stop at the leftmost or rightmost boundary. */
+ if (n1 < 0)
+ cr.X = 0;
+ else if (n1 > sb.dwSize.X)
+ cr.X = sb.dwSize.X;
+ else
+ cr.X = n1;
+ SetConsoleCursorPosition (h, cr);
+ }
+ break;
+
+ /* ESC [ n1 ';' n2 'H'
+ ESC [ n1 ';' n2 'f'
+ Move the cursor to the (1-based) n1-th row and
+ (also 1-based) n2-th column. */
+ case MAKEWORD ('[', 'H'):
+ case MAKEWORD ('[', 'f'):
+ if (esc_head == esc_term)
+ {
+ /* Both parameters are omitted and set to 1 by default. */
+ n1 = 1;
+ n2 = 1;
+ }
+ else if (!(delim = (char *) memchr (esc_head, ';',
+ esc_term - esc_head)))
+ {
+ /* Only the first parameter is given. The second one is
+ set to 1 by default. */
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ n2 = 1;
+ }
+ else
+ {
+ /* Both parameters are given. The first one shall be
+ terminated by the semicolon. */
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != delim)
+ break;
+ n2 = strtol (delim + 1, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ cr = sb.dwCursorPosition;
+ n1 -= 1;
+ n2 -= 1;
+ /* The cursor position shall be relative to the view coord of
+ the console window, which is usually smaller than the actual
+ buffer. FWIW, the 'appropriate' solution will be shrinking
+ the buffer to match the size of the console window,
+ destroying scrollback in the process. */
+ n1 += sb.srWindow.Top;
+ n2 += sb.srWindow.Left;
+ /* Stop at the topmost or bottommost boundary. */
+ if (n1 < 0)
+ cr.Y = 0;
+ else if (n1 > sb.dwSize.Y)
+ cr.Y = sb.dwSize.Y;
+ else
+ cr.Y = n1;
+ /* Stop at the leftmost or rightmost boundary. */
+ if (n2 < 0)
+ cr.X = 0;
+ else if (n2 > sb.dwSize.X)
+ cr.X = sb.dwSize.X;
+ else
+ cr.X = n2;
+ SetConsoleCursorPosition (h, cr);
+ }
+ break;
+
+ /* ESC [ n1 'J'
+ Erase display. */
+ case MAKEWORD ('[', 'J'):
+ if (esc_head == esc_term)
+ /* This is one of the very few codes whose parameters have
+ a default value of zero. */
+ n1 = 0;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ /* The cursor is not necessarily in the console window, which
+ makes the behavior of this code harder to define. */
+ switch (n1)
+ {
+ case 0:
+ /* If the cursor is in or above the window, erase from
+ it to the bottom of the window; otherwise, do nothing. */
+ cr = sb.dwCursorPosition;
+ cnt = sb.dwSize.X - sb.dwCursorPosition.X;
+ rows = sb.srWindow.Bottom - sb.dwCursorPosition.Y;
+ break;
+ case 1:
+ /* If the cursor is in or under the window, erase from
+ it to the top of the window; otherwise, do nothing. */
+ cr.X = 0;
+ cr.Y = sb.srWindow.Top;
+ cnt = sb.dwCursorPosition.X + 1;
+ rows = sb.dwCursorPosition.Y - sb.srWindow.Top;
+ break;
+ case 2:
+ /* Erase the entire window. */
+ cr.X = sb.srWindow.Left;
+ cr.Y = sb.srWindow.Top;
+ cnt = 0;
+ rows = sb.srWindow.Bottom - sb.srWindow.Top + 1;
+ break;
+ default:
+ /* Erase the entire buffer. */
+ cr.X = 0;
+ cr.Y = 0;
+ cnt = 0;
+ rows = sb.dwSize.Y;
+ break;
+ }
+ if (rows < 0)
+ break;
+ cnt += rows * sb.dwSize.X;
+ FillConsoleOutputCharacterW (h, L' ', cnt, cr, &step);
+ FillConsoleOutputAttribute (h, sb.wAttributes, cnt, cr, &step);
+ }
+ break;
+
+ /* ESC [ n1 'K'
+ Erase line. */
+ case MAKEWORD ('[', 'K'):
+ if (esc_head == esc_term)
+ /* This is one of the very few codes whose parameters have
+ a default value of zero. */
+ n1 = 0;
+ else
+ {
+ n1 = strtol (esc_head, &eptr, 10);
+ if (eptr != esc_term)
+ break;
+ }
+
+ if (GetConsoleScreenBufferInfo (h, &sb))
+ {
+ switch (n1)
+ {
+ case 0:
+ /* Erase from the cursor to the end. */
+ cr = sb.dwCursorPosition;
+ cnt = sb.dwSize.X - sb.dwCursorPosition.X;
+ break;
+ case 1:
+ /* Erase from the cursor to the beginning. */
+ cr = sb.dwCursorPosition;
+ cr.X = 0;
+ cnt = sb.dwCursorPosition.X + 1;
+ break;
+ default:
+ /* Erase the entire line. */
+ cr = sb.dwCursorPosition;
+ cr.X = 0;
+ cnt = sb.dwSize.X;
+ break;
+ }
+ FillConsoleOutputCharacterW (h, L' ', cnt, cr, &step);
+ FillConsoleOutputAttribute (h, sb.wAttributes, cnt, cr, &step);
+ }
+ break;
+
+ /* ESC [ n1 ';' n2 'm'
+ Set SGR parameters. Zero or more parameters will follow. */
+ case MAKEWORD ('[', 'm'):
+ attrib_add = 0;
+ attrib_rm = 0;
+ if (esc_head == esc_term)
+ {
+ /* When no parameter is given, reset the console. */
+ attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
+ | FOREGROUND_BLUE);
+ attrib_rm = -1; /* Removes everything. */
+ goto sgr_set_it;
+ }
+ param = esc_head;
+ do
+ {
+ /* Parse a parameter. */
+ n1 = strtol (param, &eptr, 10);
+ if (*eptr != ';' && eptr != esc_term)
+ goto sgr_set_it;
+
+ switch (n1)
+ {
+ case 0:
+ /* Reset. */
+ attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
+ | FOREGROUND_BLUE);
+ attrib_rm = -1; /* Removes everything. */
+ break;
+ case 1:
+ /* Bold. */
+ attrib_add |= FOREGROUND_INTENSITY;
+ break;
+ case 4:
+ /* Underline. */
+ attrib_add |= COMMON_LVB_UNDERSCORE;
+ break;
+ case 5:
+ /* Blink. */
+ /* XXX: It is not BLINKING at all! */
+ attrib_add |= BACKGROUND_INTENSITY;
+ break;
+ case 7:
+ /* Reverse. */
+ attrib_add |= COMMON_LVB_REVERSE_VIDEO;
+ break;
+ case 22:
+ /* No bold. */
+ attrib_add &= ~FOREGROUND_INTENSITY;
+ attrib_rm |= FOREGROUND_INTENSITY;
+ break;
+ case 24:
+ /* No underline. */
+ attrib_add &= ~COMMON_LVB_UNDERSCORE;
+ attrib_rm |= COMMON_LVB_UNDERSCORE;
+ break;
+ case 25:
+ /* No blink. */
+ /* XXX: It is not BLINKING at all! */
+ attrib_add &= ~BACKGROUND_INTENSITY;
+ attrib_rm |= BACKGROUND_INTENSITY;
+ break;
+ case 27:
+ /* No reverse. */
+ attrib_add &= ~COMMON_LVB_REVERSE_VIDEO;
+ attrib_rm |= COMMON_LVB_REVERSE_VIDEO;
+ break;
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ /* Foreground color. */
+ attrib_add &= ~(FOREGROUND_RED | FOREGROUND_GREEN
+ | FOREGROUND_BLUE);
+ n1 -= 30;
+ if (n1 & 1)
+ attrib_add |= FOREGROUND_RED;
+ if (n1 & 2)
+ attrib_add |= FOREGROUND_GREEN;
+ if (n1 & 4)
+ attrib_add |= FOREGROUND_BLUE;
+ attrib_rm |= (FOREGROUND_RED | FOREGROUND_GREEN
+ | FOREGROUND_BLUE);
+ break;
+ case 38:
+ /* Reserved for extended foreground color.
+ Don't know how to handle parameters remaining.
+ Bail out. */
+ goto sgr_set_it;
+ case 39:
+ /* Reset foreground color. */
+ /* Set to grey. */
+ attrib_add |= (FOREGROUND_RED | FOREGROUND_GREEN
+ | FOREGROUND_BLUE);
+ attrib_rm |= (FOREGROUND_RED | FOREGROUND_GREEN
+ | FOREGROUND_BLUE);
+ break;
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ /* Background color. */
+ attrib_add &= ~(BACKGROUND_RED | BACKGROUND_GREEN
+ | BACKGROUND_BLUE);
+ n1 -= 40;
+ if (n1 & 1)
+ attrib_add |= BACKGROUND_RED;
+ if (n1 & 2)
+ attrib_add |= BACKGROUND_GREEN;
+ if (n1 & 4)
+ attrib_add |= BACKGROUND_BLUE;
+ attrib_rm |= (BACKGROUND_RED | BACKGROUND_GREEN
+ | BACKGROUND_BLUE);
+ break;
+ case 48:
+ /* Reserved for extended background color.
+ Don't know how to handle parameters remaining.
+ Bail out. */
+ goto sgr_set_it;
+ case 49:
+ /* Reset background color. */
+ /* Set to black. */
+ attrib_add &= ~(BACKGROUND_RED | BACKGROUND_GREEN
+ | BACKGROUND_BLUE);
+ attrib_rm |= (BACKGROUND_RED | BACKGROUND_GREEN
+ | BACKGROUND_BLUE);
+ break;
+ }
+
+ /* Prepare the next parameter. */
+ param = eptr + 1;
+ }
+ while (param != esc_term);
+
+sgr_set_it:
+ /* 0xFFFF removes everything. If it is not the case,
+ care must be taken to preserve old attributes. */
+ if (attrib_rm != 0xFFFF && GetConsoleScreenBufferInfo (h, &sb))
+ {
+ attrib_add |= sb.wAttributes & ~attrib_rm;
+ }
+ SetConsoleTextAttribute (h, attrib_add);
+ break;
+ }
+}
+
+int
+mingw_ansi_fputs (const char *str, FILE *fp)
+{
+ const char *read = str;
+ HANDLE h;
+ DWORD mode;
+ int esc_code, prefix_len;
+ const char *esc_head, *esc_term;
+
+ h = (HANDLE) _get_osfhandle (_fileno (fp));
+ if (h == INVALID_HANDLE_VALUE)
+ return EOF;
+
+ /* Don't mess up stdio functions with Windows APIs. */
+ fflush (fp);
+
+ if (GetConsoleMode (h, &mode))
+ /* If it is a console, translate ANSI escape codes as needed. */
+ for (;;)
+ {
+ if ((esc_code = find_esc_head (&prefix_len, &esc_head, read)) == 0)
+ {
+ /* Write all remaining characters, then exit. */
+ write_all (h, read, strlen (read));
+ break;
+ }
+ if (find_esc_terminator (&esc_term, esc_head) == 0)
+ /* Ignore incomplete escape sequences at the moment.
+ FIXME: The escape state shall be cached for further calls
+ to this function. */
+ break;
+ write_all (h, read, esc_head - prefix_len - read);
+ eat_esc_sequence (h, esc_code, esc_head, esc_term);
+ read = esc_term + 1;
+ }
+ else
+ /* If it is not a console, write everything as-is. */
+ write_all (h, read, strlen (read));
+
+ _close ((intptr_t) h);
+ return 1;
+}
+
+#endif /* __MINGW32__ */
+
static void pp_quoted_string (pretty_printer *, const char *, size_t = -1);
/* Overwrite the given location/range within this text_info's rich_location.
@@ -140,7 +800,11 @@ void
pp_write_text_to_stream (pretty_printer *pp)
{
const char *text = pp_formatted_text (pp);
+#ifdef __MINGW32__
+ mingw_ansi_fputs (text, pp_buffer (pp)->stream);
+#else
fputs (text, pp_buffer (pp)->stream);
+#endif
pp_clear_output_area (pp);
}
diff --git a/gcc/print-rtl.c b/gcc/print-rtl.c
index 79ec463..28d9986 100644
--- a/gcc/print-rtl.c
+++ b/gcc/print-rtl.c
@@ -1792,11 +1792,11 @@ print_insn (pretty_printer *pp, const rtx_insn *x, int verbose)
case DEBUG_INSN:
{
const char *name = "?";
+ char idbuf[32];
if (DECL_P (INSN_VAR_LOCATION_DECL (x)))
{
tree id = DECL_NAME (INSN_VAR_LOCATION_DECL (x));
- char idbuf[32];
if (id)
name = IDENTIFIER_POINTER (id);
else if (TREE_CODE (INSN_VAR_LOCATION_DECL (x))
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index 9497cb4..d534c76 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -118,7 +118,7 @@ print_node_brief (FILE *file, const char *prefix, const_tree node, int indent)
fprintf (file, " overflow");
fprintf (file, " ");
- print_dec (node, file, TYPE_SIGN (TREE_TYPE (node)));
+ print_dec (wi::to_wide (node), file, TYPE_SIGN (TREE_TYPE (node)));
}
if (TREE_CODE (node) == REAL_CST)
{
@@ -721,7 +721,7 @@ print_node (FILE *file, const char *prefix, tree node, int indent,
fprintf (file, " overflow");
fprintf (file, " ");
- print_dec (node, file, TYPE_SIGN (TREE_TYPE (node)));
+ print_dec (wi::to_wide (node), file, TYPE_SIGN (TREE_TYPE (node)));
break;
case REAL_CST:
diff --git a/gcc/profile-count.c b/gcc/profile-count.c
index 4d22428..44ceaed 100644
--- a/gcc/profile-count.c
+++ b/gcc/profile-count.c
@@ -30,6 +30,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple.h"
#include "data-streamer.h"
#include "cgraph.h"
+#include "wide-int.h"
/* Dump THIS to F. */
@@ -146,12 +147,12 @@ profile_probability::differs_from_p (profile_probability other) const
{
if (!initialized_p () || !other.initialized_p ())
return false;
- if ((uint64_t)m_val - (uint64_t)other.m_val < 10
- || (uint64_t)other.m_val - (uint64_t)m_val < 10)
+ if ((uint64_t)m_val - (uint64_t)other.m_val < max_probability / 1000
+ || (uint64_t)other.m_val - (uint64_t)max_probability < 1000)
return false;
if (!other.m_val)
return true;
- int64_t ratio = m_val * 100 / other.m_val;
+ int64_t ratio = (int64_t)m_val * 100 / other.m_val;
return ratio < 99 || ratio > 101;
}
@@ -194,3 +195,21 @@ profile_probability::stream_out (struct lto_output_stream *ob)
streamer_write_uhwi_stream (ob, m_val);
streamer_write_uhwi_stream (ob, m_quality);
}
+
+/* Compute RES=(a*b + c/2)/c capping and return false if overflow happened. */
+
+bool
+slow_safe_scale_64bit (uint64_t a, uint64_t b, uint64_t c, uint64_t *res)
+{
+ FIXED_WIDE_INT (128) tmp = a;
+ bool overflow;
+ tmp = wi::udiv_floor (wi::umul (tmp, b, &overflow) + (c / 2), c);
+ gcc_checking_assert (!overflow);
+ if (wi::fits_uhwi_p (tmp))
+ {
+ *res = tmp.to_uhwi ();
+ return true;
+ }
+ *res = (uint64_t) -1;
+ return false;
+}
diff --git a/gcc/profile-count.h b/gcc/profile-count.h
index 8fd22b8..4546e199 100644
--- a/gcc/profile-count.h
+++ b/gcc/profile-count.h
@@ -43,6 +43,38 @@ enum profile_quality {
#define RDIV(X,Y) (((X) + (Y) / 2) / (Y))
+bool slow_safe_scale_64bit (uint64_t a, uint64_t b, uint64_t c, uint64_t *res);
+
+/* Compute RES=(a*b + c/2)/c capping and return false if overflow happened. */
+
+inline bool
+safe_scale_64bit (uint64_t a, uint64_t b, uint64_t c, uint64_t *res)
+{
+#if (GCC_VERSION >= 5000)
+ uint64_t tmp;
+ if (!__builtin_mul_overflow (a, b, &tmp)
+ && !__builtin_add_overflow (tmp, c/2, &tmp))
+ {
+ *res = tmp / c;
+ return true;
+ }
+ if (c == 1)
+ {
+ *res = (uint64_t) -1;
+ return false;
+ }
+#else
+ if (a < ((uint64_t)1 << 31)
+ && b < ((uint64_t)1 << 31)
+ && c < ((uint64_t)1 << 31))
+ {
+ *res = (a * b + (c / 2)) / c;
+ return true;
+ }
+#endif
+ return slow_safe_scale_64bit (a, b, c, res);
+}
+
/* Data type to hold probabilities. It implements fixed point arithmetics
with capping so probability is always in range [0,1] and scaling requiring
values greater than 1 needs to be represented otherwise.
@@ -82,12 +114,12 @@ enum profile_quality {
class GTY((user)) profile_probability
{
- /* For now use values in range 0...REG_BR_PROB_BASE. Later we can use full
- precision of 30 bits available. */
-
static const int n_bits = 30;
- static const uint32_t max_probability = REG_BR_PROB_BASE;
- static const uint32_t uninitialized_probability = ((uint32_t) 1 << n_bits) - 1;
+ /* We can technically use ((uint32_t) 1 << (n_bits - 1)) - 2 but that
+ will lead to harder multiplication sequences. */
+ static const uint32_t max_probability = (uint32_t) 1 << (n_bits - 2);
+ static const uint32_t uninitialized_probability
+ = ((uint32_t) 1 << (n_bits - 1)) - 1;
uint32_t m_val : 30;
enum profile_quality m_quality : 2;
@@ -171,7 +203,7 @@ public:
/* Return true if value can be trusted. */
bool reliable_p () const
{
- return initialized_p ();
+ return m_quality >= profile_adjusted;
}
/* Conversion from and to REG_BR_PROB_BASE integer fixpoint arithmetics.
@@ -180,14 +212,14 @@ public:
{
profile_probability ret;
gcc_checking_assert (v >= 0 && v <= REG_BR_PROB_BASE);
- ret.m_val = RDIV (v * max_probability, REG_BR_PROB_BASE);
+ ret.m_val = RDIV (v * (uint64_t) max_probability, REG_BR_PROB_BASE);
ret.m_quality = profile_guessed;
return ret;
}
int to_reg_br_prob_base () const
{
gcc_checking_assert (initialized_p ());
- return RDIV (m_val * REG_BR_PROB_BASE, max_probability);
+ return RDIV (m_val * (uint64_t) REG_BR_PROB_BASE, max_probability);
}
/* Conversion to and from RTL representation of profile probabilities. */
@@ -216,7 +248,12 @@ public:
if (val1 > val2)
ret.m_val = max_probability;
else
- ret.m_val = RDIV (val1 * max_probability, val2);
+ {
+ uint64_t tmp;
+ safe_scale_64bit (val1, max_probability, val2, &tmp);
+ gcc_checking_assert (tmp <= max_probability);
+ ret.m_val = tmp;
+ }
ret.m_quality = profile_precise;
return ret;
}
@@ -413,8 +450,9 @@ public:
if (!initialized_p ())
return profile_probability::uninitialized ();
profile_probability ret;
- ret.m_val = MIN (RDIV (m_val * num, den),
- max_probability);
+ uint64_t tmp;
+ safe_scale_64bit (m_val, num, den, &tmp);
+ ret.m_val = MIN (tmp, max_probability);
ret.m_quality = MIN (m_quality, profile_adjusted);
return ret;
}
@@ -452,7 +490,7 @@ public:
if (m_val == uninitialized_probability)
return m_quality == profile_guessed;
else
- return m_val <= REG_BR_PROB_BASE;
+ return m_val <= max_probability;
}
/* Comparsions are three-state and conservative. False is returned if
@@ -535,11 +573,6 @@ class GTY(()) profile_count
uint64_t m_val : n_bits;
enum profile_quality m_quality : 2;
-
- /* Assume numbers smaller than this to multiply. This is set to make
- testsuite pass, in future we may implement precise multiplication in higer
- rangers. */
- static const uint64_t max_safe_multiplier = 131072;
public:
/* Used for counters which are expected to be never executed. */
@@ -595,7 +628,7 @@ public:
/* Return true if value can be trusted. */
bool reliable_p () const
{
- return initialized_p ();
+ return m_quality >= profile_adjusted;
}
/* When merging basic blocks, the two different profile counts are unified.
@@ -756,8 +789,10 @@ public:
if (!initialized_p ())
return profile_count::uninitialized ();
profile_count ret;
- ret.m_val = RDIV (m_val * prob.m_val,
- profile_probability::max_probability);
+ uint64_t tmp;
+ safe_scale_64bit (m_val, prob.m_val, profile_probability::max_probability,
+ &tmp);
+ ret.m_val = tmp;
ret.m_quality = MIN (m_quality, prob.m_quality);
return ret;
}
@@ -769,11 +804,11 @@ public:
if (!initialized_p ())
return profile_count::uninitialized ();
profile_count ret;
+ uint64_t tmp;
+
gcc_checking_assert (num >= 0 && den > 0);
- /* FIXME: shrink wrapping violates this sanity check. */
- gcc_checking_assert ((num <= REG_BR_PROB_BASE
- || den <= REG_BR_PROB_BASE) || 1);
- ret.m_val = RDIV (m_val * num, den);
+ safe_scale_64bit (m_val, num, den, &tmp);
+ ret.m_val = MIN (tmp, max_count);
ret.m_quality = MIN (m_quality, profile_adjusted);
return ret;
}
@@ -790,12 +825,9 @@ public:
return *this;
profile_count ret;
- /* Take care for overflows! */
- if (num.m_val < max_safe_multiplier || m_val < max_safe_multiplier)
- ret.m_val = RDIV (m_val * num.m_val, den.m_val);
- else
- ret.m_val = RDIV (m_val * RDIV (num.m_val * max_safe_multiplier,
- den.m_val), max_safe_multiplier);
+ uint64_t val;
+ safe_scale_64bit (m_val, num.m_val, den.m_val, &val);
+ ret.m_val = MIN (val, max_count);
ret.m_quality = MIN (m_quality, profile_adjusted);
return ret;
}
diff --git a/gcc/profile.c b/gcc/profile.c
index 6d40241..95dd578 100644
--- a/gcc/profile.c
+++ b/gcc/profile.c
@@ -831,12 +831,7 @@ compute_branch_probabilities (unsigned cfg_checksum, unsigned lineno_checksum)
FOR_ALL_BB_FN (bb, cfun)
{
- edge e;
- edge_iterator ei;
-
bb->count = profile_count::from_gcov_type (bb_gcov_count (bb));
- FOR_EACH_EDGE (e, ei, bb->succs)
- e->count = profile_count::from_gcov_type (edge_gcov_count (e));
}
bb_gcov_counts.release ();
delete edge_gcov_counts;
diff --git a/gcc/recog.c b/gcc/recog.c
index cfce029..4f11c57 100644
--- a/gcc/recog.c
+++ b/gcc/recog.c
@@ -408,6 +408,7 @@ verify_changes (int num)
&& REG_P (changes[i].old)
&& asm_noperands (PATTERN (object)) > 0
&& REG_EXPR (changes[i].old) != NULL_TREE
+ && HAS_DECL_ASSEMBLER_NAME_P (REG_EXPR (changes[i].old))
&& DECL_ASSEMBLER_NAME_SET_P (REG_EXPR (changes[i].old))
&& DECL_REGISTER (REG_EXPR (changes[i].old)))
{
@@ -3380,6 +3381,7 @@ peep2_attempt (basic_block bb, rtx_insn *insn, int match_len, rtx_insn *attempt)
case REG_NORETURN:
case REG_SETJMP:
case REG_TM:
+ case REG_CALL_NOCF_CHECK:
add_reg_note (new_insn, REG_NOTE_KIND (note),
XEXP (note, 0));
break;
@@ -3861,7 +3863,7 @@ const pass_data pass_data_split_all_insns =
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
0, /* properties_required */
- 0, /* properties_provided */
+ PROP_rtl_split_insns, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
0, /* todo_flags_finish */
diff --git a/gcc/ree.c b/gcc/ree.c
index 19225d5..811de5a 100644
--- a/gcc/ree.c
+++ b/gcc/ree.c
@@ -269,7 +269,7 @@ update_reg_equal_equiv_notes (rtx_insn *insn, machine_mode new_mode,
/* Update equivalency constants. Recall that RTL constants are
sign-extended. */
if (GET_CODE (orig_src) == CONST_INT
- && HOST_BITS_PER_WIDE_INT >= GET_MODE_BITSIZE (new_mode))
+ && HWI_COMPUTABLE_MODE_P (new_mode))
{
if (INTVAL (orig_src) >= 0 || code == SIGN_EXTEND)
/* Nothing needed. */;
@@ -337,7 +337,7 @@ combine_set_extension (ext_cand *cand, rtx_insn *curr_insn, rtx *orig_set)
/* Merge constants by directly moving the constant into the register under
some conditions. Recall that RTL constants are sign-extended. */
if (GET_CODE (orig_src) == CONST_INT
- && HOST_BITS_PER_WIDE_INT >= GET_MODE_BITSIZE (cand->mode))
+ && HWI_COMPUTABLE_MODE_P (cand->mode))
{
if (INTVAL (orig_src) >= 0 || cand->code == SIGN_EXTEND)
new_set = gen_rtx_SET (new_reg, orig_src);
@@ -428,7 +428,8 @@ transform_ifelse (ext_cand *cand, rtx_insn *def_insn)
srcreg2 = XEXP (SET_SRC (set_insn), 2);
/* If the conditional move already has the right or wider mode,
there is nothing to do. */
- if (GET_MODE_SIZE (GET_MODE (dstreg)) >= GET_MODE_SIZE (cand->mode))
+ if (GET_MODE_UNIT_SIZE (GET_MODE (dstreg))
+ >= GET_MODE_UNIT_SIZE (cand->mode))
return true;
map_srcreg = gen_rtx_REG (cand->mode, REGNO (srcreg));
@@ -718,8 +719,8 @@ merge_def_and_ext (ext_cand *cand, rtx_insn *def_insn, ext_state *state)
&& state->modified[INSN_UID (def_insn)].mode
== ext_src_mode)))
{
- if (GET_MODE_SIZE (GET_MODE (SET_DEST (*sub_rtx)))
- >= GET_MODE_SIZE (cand->mode))
+ if (GET_MODE_UNIT_SIZE (GET_MODE (SET_DEST (*sub_rtx)))
+ >= GET_MODE_UNIT_SIZE (cand->mode))
return true;
/* If def_insn is already scheduled to be deleted, don't attempt
to modify it. */
@@ -926,7 +927,8 @@ combine_reaching_defs (ext_cand *cand, const_rtx set_pat, ext_state *state)
|| (set = single_set (cand->insn)) == NULL_RTX)
return false;
mode = GET_MODE (SET_DEST (set));
- gcc_assert (GET_MODE_SIZE (mode) >= GET_MODE_SIZE (cand->mode));
+ gcc_assert (GET_MODE_UNIT_SIZE (mode)
+ >= GET_MODE_UNIT_SIZE (cand->mode));
cand->mode = mode;
}
diff --git a/gcc/reg-notes.def b/gcc/reg-notes.def
index 943eff4..d83fc45 100644
--- a/gcc/reg-notes.def
+++ b/gcc/reg-notes.def
@@ -224,7 +224,18 @@ REG_NOTE (ARGS_SIZE)
pseudo reg. */
REG_NOTE (RETURNED)
+/* Indicates the instruction is a stack check probe that should not
+ be combined with other stack adjustments. */
+REG_NOTE (STACK_CHECK)
+
/* Used to mark a call with the function decl called by the call.
The decl might not be available in the call due to splitting of the call
insn. This note is a SYMBOL_REF. */
REG_NOTE (CALL_DECL)
+
+/* Indicate that a call should not be verified for control-flow consistency.
+ The target address of the call is assumed as a valid address and no check
+ to validate a branch to the target address is needed. The call is marked
+ when a called function has a 'notrack' attribute. This note is used by the
+ compiler when the option -fcf-protection=branch is specified. */
+REG_NOTE (CALL_NOCF_CHECK)
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index f238106..62f7d7b 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -262,7 +262,7 @@ static bool move_for_stack_reg (rtx_insn *, stack_ptr, rtx);
static bool move_nan_for_stack_reg (rtx_insn *, stack_ptr, rtx);
static int swap_rtx_condition_1 (rtx);
static int swap_rtx_condition (rtx_insn *);
-static void compare_for_stack_reg (rtx_insn *, stack_ptr, rtx);
+static void compare_for_stack_reg (rtx_insn *, stack_ptr, rtx, bool);
static bool subst_stack_regs_pat (rtx_insn *, stack_ptr, rtx);
static void subst_asm_stack_regs (rtx_insn *, stack_ptr);
static bool subst_stack_regs (rtx_insn *, stack_ptr);
@@ -1325,7 +1325,8 @@ swap_rtx_condition (rtx_insn *insn)
set up. */
static void
-compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
+compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack,
+ rtx pat_src, bool can_pop_second_op)
{
rtx *src1, *src2;
rtx src1_note, src2_note;
@@ -1366,8 +1367,18 @@ compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
if (src1_note)
{
- pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
- replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+ if (*src2 == CONST0_RTX (GET_MODE (*src2)))
+ {
+ /* This is `ftst' insn that can't pop register. */
+ remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src1_note, 0)));
+ emit_pop_insn (insn, regstack, XEXP (src1_note, 0),
+ EMIT_AFTER);
+ }
+ else
+ {
+ pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
+ replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+ }
}
/* If the second operand dies, handle that. But if the operands are
@@ -1384,7 +1395,7 @@ compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
at top (FIRST_STACK_REG) now. */
if (get_hard_regnum (regstack, XEXP (src2_note, 0)) == FIRST_STACK_REG
- && src1_note)
+ && src1_note && can_pop_second_op)
{
pop_stack (regstack, REGNO (XEXP (src2_note, 0)));
replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
@@ -1550,7 +1561,9 @@ subst_stack_regs_pat (rtx_insn *insn, stack_ptr regstack, rtx pat)
switch (GET_CODE (pat_src))
{
case COMPARE:
- compare_for_stack_reg (insn, regstack, pat_src);
+ /* `fcomi' insn can't pop two regs. */
+ compare_for_stack_reg (insn, regstack, pat_src,
+ REGNO (*dest) != FLAGS_REG);
break;
case CALL:
@@ -1970,7 +1983,7 @@ subst_stack_regs_pat (rtx_insn *insn, stack_ptr regstack, rtx pat)
pat_src = XVECEXP (pat_src, 0, 0);
gcc_assert (GET_CODE (pat_src) == COMPARE);
- compare_for_stack_reg (insn, regstack, pat_src);
+ compare_for_stack_reg (insn, regstack, pat_src, true);
break;
default:
@@ -2948,9 +2961,9 @@ better_edge (edge e1, edge e2)
if (EDGE_FREQUENCY (e1) < EDGE_FREQUENCY (e2))
return e2;
- if (e1->count > e2->count)
+ if (e1->count () > e2->count ())
return e1;
- if (e1->count < e2->count)
+ if (e1->count () < e2->count ())
return e2;
/* Prefer critical edges to minimize inserting compensation code on
diff --git a/gcc/regcprop.c b/gcc/regcprop.c
index 73e945d..b80019b 100644
--- a/gcc/regcprop.c
+++ b/gcc/regcprop.c
@@ -345,8 +345,7 @@ copy_value (rtx dest, rtx src, struct value_data *vd)
We can't properly represent the latter case in our tables, so don't
record anything then. */
else if (sn < hard_regno_nregs (sr, vd->e[sr].mode)
- && (GET_MODE_SIZE (vd->e[sr].mode) > UNITS_PER_WORD
- ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
+ && subreg_lowpart_offset (GET_MODE (dest), vd->e[sr].mode) != 0)
return;
/* If SRC had been assigned a mode narrower than the copy, we can't
@@ -408,13 +407,9 @@ maybe_mode_change (machine_mode orig_mode, machine_mode copy_mode,
int use_nregs = hard_regno_nregs (copy_regno, new_mode);
int copy_offset
= GET_MODE_SIZE (copy_mode) / copy_nregs * (copy_nregs - use_nregs);
- int offset
- = GET_MODE_SIZE (orig_mode) - GET_MODE_SIZE (new_mode) - copy_offset;
- int byteoffset = offset % UNITS_PER_WORD;
- int wordoffset = offset - byteoffset;
-
- offset = ((WORDS_BIG_ENDIAN ? wordoffset : 0)
- + (BYTES_BIG_ENDIAN ? byteoffset : 0));
+ unsigned int offset
+ = subreg_size_lowpart_offset (GET_MODE_SIZE (new_mode) + copy_offset,
+ GET_MODE_SIZE (orig_mode));
regno += subreg_regno_offset (regno, orig_mode, offset, new_mode);
if (targetm.hard_regno_mode_ok (regno, new_mode))
return gen_raw_REG (new_mode, regno);
@@ -871,8 +866,7 @@ copyprop_hardreg_forward_1 (basic_block bb, struct value_data *vd)
/* And likewise, if we are narrowing on big endian the transformation
is also invalid. */
if (REG_NREGS (src) < hard_regno_nregs (regno, vd->e[regno].mode)
- && (GET_MODE_SIZE (vd->e[regno].mode) > UNITS_PER_WORD
- ? WORDS_BIG_ENDIAN : BYTES_BIG_ENDIAN))
+ && subreg_lowpart_offset (mode, vd->e[regno].mode) != 0)
goto no_move_special_case;
}
diff --git a/gcc/reload1.c b/gcc/reload1.c
index 5e200b9..e2ee2fe 100644
--- a/gcc/reload1.c
+++ b/gcc/reload1.c
@@ -963,7 +963,7 @@ reload (rtx_insn *first, int global)
then repeat the elimination bookkeeping. We don't
realign when there is no stack, as that will cause a
stack frame when none is needed should
- STARTING_FRAME_OFFSET not be already aligned to
+ TARGET_STARTING_FRAME_OFFSET not be already aligned to
STACK_BOUNDARY. */
assign_stack_local (BLKmode, 0, crtl->stack_alignment_needed);
}
@@ -2251,8 +2251,7 @@ alter_reg (int i, int from_reg, bool dont_share_p)
/* On a big endian machine, the "address" of the slot
is the address of the low part that fits its inherent mode. */
- if (BYTES_BIG_ENDIAN && inherent_size < total_size)
- adjust += (total_size - inherent_size);
+ adjust += subreg_size_lowpart_offset (inherent_size, total_size);
/* If we have any adjustment to make, or if the stack slot is the
wrong mode, make a new stack slot. */
diff --git a/gcc/rtl.h b/gcc/rtl.h
index a450a04..f854550 100644
--- a/gcc/rtl.h
+++ b/gcc/rtl.h
@@ -2722,6 +2722,7 @@ get_full_set_src_cost (rtx x, machine_mode mode, struct full_rtx_costs *c)
/* In explow.c */
extern HOST_WIDE_INT trunc_int_for_mode (HOST_WIDE_INT, machine_mode);
extern rtx plus_constant (machine_mode, rtx, HOST_WIDE_INT, bool = false);
+extern HOST_WIDE_INT get_stack_check_protect (void);
/* In rtl.c */
extern rtx rtx_alloc (RTX_CODE CXX_MEM_STAT_INFO);
@@ -3202,7 +3203,8 @@ extern int loc_mentioned_in_p (rtx *, const_rtx);
extern rtx_insn *find_first_parameter_load (rtx_insn *, rtx_insn *);
extern bool keep_with_call_p (const rtx_insn *);
extern bool label_is_jump_target_p (const_rtx, const rtx_insn *);
-extern int insn_rtx_cost (rtx, bool);
+extern int pattern_cost (rtx, bool);
+extern int insn_cost (rtx_insn *, bool);
extern unsigned seq_cost (const rtx_insn *, bool);
/* Given an insn and condition, return a canonical description of
diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c
index b28325e..560bfd4 100644
--- a/gcc/rtlanal.c
+++ b/gcc/rtlanal.c
@@ -551,12 +551,12 @@ rtx_addr_can_trap_p_1 (const_rtx x, HOST_WIDE_INT offset, HOST_WIDE_INT size,
{
if (FRAME_GROWS_DOWNWARD)
{
- high_bound = STARTING_FRAME_OFFSET;
+ high_bound = targetm.starting_frame_offset ();
low_bound = high_bound - get_frame_size ();
}
else
{
- low_bound = STARTING_FRAME_OFFSET;
+ low_bound = targetm.starting_frame_offset ();
high_bound = low_bound + get_frame_size ();
}
}
@@ -5269,11 +5269,11 @@ num_sign_bit_copies1 (const_rtx x, scalar_int_mode mode, const_rtx known_x,
? 1 : bitwidth - floor_log2 (nonzero) - 1;
}
-/* Calculate the rtx_cost of a single instruction. A return value of
+/* Calculate the rtx_cost of a single instruction pattern. A return value of
zero indicates an instruction pattern without a known cost. */
int
-insn_rtx_cost (rtx pat, bool speed)
+pattern_cost (rtx pat, bool speed)
{
int i, cost;
rtx set;
@@ -5323,6 +5323,18 @@ insn_rtx_cost (rtx pat, bool speed)
return cost > 0 ? cost : COSTS_N_INSNS (1);
}
+/* Calculate the cost of a single instruction. A return value of zero
+ indicates an instruction pattern without a known cost. */
+
+int
+insn_cost (rtx_insn *insn, bool speed)
+{
+ if (targetm.insn_cost)
+ return targetm.insn_cost (insn, speed);
+
+ return pattern_cost (PATTERN (insn), speed);
+}
+
/* Returns estimate on cost of computing SEQ. */
unsigned
@@ -5798,7 +5810,7 @@ low_bitmask_len (machine_mode mode, unsigned HOST_WIDE_INT m)
{
if (mode != VOIDmode)
{
- if (GET_MODE_PRECISION (mode) > HOST_BITS_PER_WIDE_INT)
+ if (!HWI_COMPUTABLE_MODE_P (mode))
return -1;
m &= GET_MODE_MASK (mode);
}
diff --git a/gcc/rtlhooks.c b/gcc/rtlhooks.c
index 4d04ebd..d20815e 100644
--- a/gcc/rtlhooks.c
+++ b/gcc/rtlhooks.c
@@ -59,8 +59,6 @@ gen_lowpart_general (machine_mode mode, rtx x)
}
else
{
- int offset = 0;
-
/* The only additional case we can do is MEM. */
gcc_assert (MEM_P (x));
@@ -72,16 +70,7 @@ gen_lowpart_general (machine_mode mode, rtx x)
&& !reload_completed)
return gen_lowpart_general (mode, force_reg (xmode, x));
- if (WORDS_BIG_ENDIAN)
- offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
-
- if (BYTES_BIG_ENDIAN)
- /* Adjust the address so that the address-after-the-data
- is unchanged. */
- offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-
+ HOST_WIDE_INT offset = byte_lowpart_offset (mode, GET_MODE (x));
return adjust_address (x, mode, offset);
}
}
@@ -126,19 +115,8 @@ gen_lowpart_if_possible (machine_mode mode, rtx x)
else if (MEM_P (x))
{
/* This is the only other case we handle. */
- int offset = 0;
- rtx new_rtx;
-
- if (WORDS_BIG_ENDIAN)
- offset = (MAX (GET_MODE_SIZE (GET_MODE (x)), UNITS_PER_WORD)
- - MAX (GET_MODE_SIZE (mode), UNITS_PER_WORD));
- if (BYTES_BIG_ENDIAN)
- /* Adjust the address so that the address-after-the-data is
- unchanged. */
- offset -= (MIN (UNITS_PER_WORD, GET_MODE_SIZE (mode))
- - MIN (UNITS_PER_WORD, GET_MODE_SIZE (GET_MODE (x))));
-
- new_rtx = adjust_address_nv (x, mode, offset);
+ HOST_WIDE_INT offset = byte_lowpart_offset (mode, GET_MODE (x));
+ rtx new_rtx = adjust_address_nv (x, mode, offset);
if (! memory_address_addr_space_p (mode, XEXP (new_rtx, 0),
MEM_ADDR_SPACE (x)))
return 0;
diff --git a/gcc/sanitizer.def b/gcc/sanitizer.def
index 9d963f0..00e7ae0 100644
--- a/gcc/sanitizer.def
+++ b/gcc/sanitizer.def
@@ -424,8 +424,8 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE,
"__ubsan_handle_vla_bound_not_positive",
BT_FN_VOID_PTR_PTR,
ATTR_COLD_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH,
- "__ubsan_handle_type_mismatch",
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1,
+ "__ubsan_handle_type_mismatch_v1",
BT_FN_VOID_PTR_PTR,
ATTR_COLD_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW,
@@ -464,8 +464,8 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT,
"__ubsan_handle_vla_bound_not_positive_abort",
BT_FN_VOID_PTR_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT,
- "__ubsan_handle_type_mismatch_abort",
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT,
+ "__ubsan_handle_type_mismatch_v1_abort",
BT_FN_VOID_PTR_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT,
@@ -516,12 +516,20 @@ DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT,
"__ubsan_handle_nonnull_arg_abort",
BT_FN_VOID_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN,
- "__ubsan_handle_nonnull_return",
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1,
+ "__ubsan_handle_nonnull_return_v1",
+ BT_FN_VOID_PTR_PTR,
+ ATTR_COLD_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT,
+ "__ubsan_handle_nonnull_return_v1_abort",
+ BT_FN_VOID_PTR_PTR,
+ ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN,
+ "__ubsan_handle_invalid_builtin",
BT_FN_VOID_PTR,
ATTR_COLD_NOTHROW_LEAF_LIST)
-DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT,
- "__ubsan_handle_nonnull_return_abort",
+DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT,
+ "__ubsan_handle_invalid_builtin_abort",
BT_FN_VOID_PTR,
ATTR_COLD_NORETURN_NOTHROW_LEAF_LIST)
DEF_SANITIZER_BUILTIN(BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS,
diff --git a/gcc/sanopt.c b/gcc/sanopt.c
index d17c7db..997bcfd 100644
--- a/gcc/sanopt.c
+++ b/gcc/sanopt.c
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see
#include "cfghooks.h"
#include "tree-dfa.h"
#include "tree-ssa.h"
+#include "varasm.h"
/* This is used to carry information about basic blocks. It is
attached to the AUX field of the standard CFG block. */
@@ -105,7 +106,7 @@ struct sanopt_tree_triplet_hash : typed_noop_remove <sanopt_tree_triplet>
typedef sanopt_tree_triplet value_type;
typedef sanopt_tree_triplet compare_type;
- static inline hashval_t
+ static hashval_t
hash (const sanopt_tree_triplet &ref)
{
inchash::hash hstate (0);
@@ -115,7 +116,7 @@ struct sanopt_tree_triplet_hash : typed_noop_remove <sanopt_tree_triplet>
return hstate.end ();
}
- static inline bool
+ static bool
equal (const sanopt_tree_triplet &ref1, const sanopt_tree_triplet &ref2)
{
return operand_equal_p (ref1.t1, ref2.t1, 0)
@@ -123,31 +124,86 @@ struct sanopt_tree_triplet_hash : typed_noop_remove <sanopt_tree_triplet>
&& operand_equal_p (ref1.t3, ref2.t3, 0);
}
- static inline void
+ static void
mark_deleted (sanopt_tree_triplet &ref)
{
ref.t1 = reinterpret_cast<tree> (1);
}
- static inline void
+ static void
mark_empty (sanopt_tree_triplet &ref)
{
ref.t1 = NULL;
}
- static inline bool
+ static bool
is_deleted (const sanopt_tree_triplet &ref)
{
- return ref.t1 == (void *) 1;
+ return ref.t1 == reinterpret_cast<tree> (1);
}
- static inline bool
+ static bool
is_empty (const sanopt_tree_triplet &ref)
{
return ref.t1 == NULL;
}
};
+/* Tree couple for ptr_check_map. */
+struct sanopt_tree_couple
+{
+ tree ptr;
+ bool pos_p;
+};
+
+/* Traits class for tree triplet hash maps below. */
+
+struct sanopt_tree_couple_hash : typed_noop_remove <sanopt_tree_couple>
+{
+ typedef sanopt_tree_couple value_type;
+ typedef sanopt_tree_couple compare_type;
+
+ static hashval_t
+ hash (const sanopt_tree_couple &ref)
+ {
+ inchash::hash hstate (0);
+ inchash::add_expr (ref.ptr, hstate);
+ hstate.add_int (ref.pos_p);
+ return hstate.end ();
+ }
+
+ static bool
+ equal (const sanopt_tree_couple &ref1, const sanopt_tree_couple &ref2)
+ {
+ return operand_equal_p (ref1.ptr, ref2.ptr, 0)
+ && ref1.pos_p == ref2.pos_p;
+ }
+
+ static void
+ mark_deleted (sanopt_tree_couple &ref)
+ {
+ ref.ptr = reinterpret_cast<tree> (1);
+ }
+
+ static void
+ mark_empty (sanopt_tree_couple &ref)
+ {
+ ref.ptr = NULL;
+ }
+
+ static bool
+ is_deleted (const sanopt_tree_couple &ref)
+ {
+ return ref.ptr == reinterpret_cast<tree> (1);
+ }
+
+ static bool
+ is_empty (const sanopt_tree_couple &ref)
+ {
+ return ref.ptr == NULL;
+ }
+};
+
/* This is used to carry various hash maps and variables used
in sanopt_optimize_walker. */
@@ -166,6 +222,10 @@ struct sanopt_ctx
that virtual table pointer. */
hash_map<sanopt_tree_triplet_hash, auto_vec<gimple *> > vptr_check_map;
+ /* This map maps a couple (tree and boolean) to a vector of UBSAN_PTR
+ call statements that check that pointer overflow. */
+ hash_map<sanopt_tree_couple_hash, auto_vec<gimple *> > ptr_check_map;
+
/* Number of IFN_ASAN_CHECK statements. */
int asan_num_accesses;
@@ -344,6 +404,179 @@ maybe_optimize_ubsan_null_ifn (struct sanopt_ctx *ctx, gimple *stmt)
return remove;
}
+/* Return true when pointer PTR for a given CUR_OFFSET is already sanitized
+ in a given sanitization context CTX. */
+
+static bool
+has_dominating_ubsan_ptr_check (sanopt_ctx *ctx, tree ptr,
+ offset_int &cur_offset)
+{
+ bool pos_p = !wi::neg_p (cur_offset);
+ sanopt_tree_couple couple;
+ couple.ptr = ptr;
+ couple.pos_p = pos_p;
+
+ auto_vec<gimple *> &v = ctx->ptr_check_map.get_or_insert (couple);
+ gimple *g = maybe_get_dominating_check (v);
+ if (!g)
+ return false;
+
+ /* We already have recorded a UBSAN_PTR check for this pointer. Perhaps we
+ can drop this one. But only if this check doesn't specify larger offset.
+ */
+ tree offset = gimple_call_arg (g, 1);
+ gcc_assert (TREE_CODE (offset) == INTEGER_CST);
+ offset_int ooffset = wi::sext (wi::to_offset (offset), POINTER_SIZE);
+
+ if (pos_p)
+ {
+ if (wi::les_p (cur_offset, ooffset))
+ return true;
+ }
+ else if (!pos_p && wi::les_p (ooffset, cur_offset))
+ return true;
+
+ return false;
+}
+
+/* Record UBSAN_PTR check of given context CTX. Register pointer PTR on
+ a given OFFSET that it's handled by GIMPLE STMT. */
+
+static void
+record_ubsan_ptr_check_stmt (sanopt_ctx *ctx, gimple *stmt, tree ptr,
+ const offset_int &offset)
+{
+ sanopt_tree_couple couple;
+ couple.ptr = ptr;
+ couple.pos_p = !wi::neg_p (offset);
+
+ auto_vec<gimple *> &v = ctx->ptr_check_map.get_or_insert (couple);
+ v.safe_push (stmt);
+}
+
+/* Optimize away redundant UBSAN_PTR calls. */
+
+static bool
+maybe_optimize_ubsan_ptr_ifn (sanopt_ctx *ctx, gimple *stmt)
+{
+ HOST_WIDE_INT bitsize, bitpos;
+ machine_mode mode;
+ int volatilep = 0, reversep, unsignedp = 0;
+ tree offset;
+
+ gcc_assert (gimple_call_num_args (stmt) == 2);
+ tree ptr = gimple_call_arg (stmt, 0);
+ tree off = gimple_call_arg (stmt, 1);
+
+ if (TREE_CODE (off) != INTEGER_CST)
+ return false;
+
+ if (integer_zerop (off))
+ return true;
+
+ offset_int cur_offset = wi::sext (wi::to_offset (off), POINTER_SIZE);
+ if (has_dominating_ubsan_ptr_check (ctx, ptr, cur_offset))
+ return true;
+
+ tree base = ptr;
+ if (TREE_CODE (base) == ADDR_EXPR)
+ {
+ base = TREE_OPERAND (base, 0);
+
+ base = get_inner_reference (base, &bitsize, &bitpos, &offset, &mode,
+ &unsignedp, &reversep, &volatilep);
+ if (offset == NULL_TREE && DECL_P (base))
+ {
+ gcc_assert (!DECL_REGISTER (base));
+ offset_int expr_offset = bitpos / BITS_PER_UNIT;
+ offset_int total_offset = expr_offset + cur_offset;
+ if (total_offset != wi::sext (total_offset, POINTER_SIZE))
+ {
+ record_ubsan_ptr_check_stmt (ctx, stmt, ptr, cur_offset);
+ return false;
+ }
+
+ /* If BASE is a fixed size automatic variable or
+ global variable defined in the current TU, we don't have
+ to instrument anything if offset is within address
+ of the variable. */
+ if ((VAR_P (base)
+ || TREE_CODE (base) == PARM_DECL
+ || TREE_CODE (base) == RESULT_DECL)
+ && DECL_SIZE_UNIT (base)
+ && TREE_CODE (DECL_SIZE_UNIT (base)) == INTEGER_CST
+ && (!is_global_var (base) || decl_binds_to_current_def_p (base)))
+ {
+ offset_int base_size = wi::to_offset (DECL_SIZE_UNIT (base));
+ if (bitpos >= 0
+ && wi::les_p (total_offset, base_size))
+ {
+ if (!wi::neg_p (total_offset)
+ && wi::les_p (total_offset, base_size))
+ return true;
+ }
+ }
+
+ /* Following expression: UBSAN_PTR (&MEM_REF[ptr + x], y) can be
+ handled as follows:
+
+ 1) sign (x) == sign (y), then check for dominating check of (x + y)
+ 2) sign (x) != sign (y), then first check if we have a dominating
+ check for ptr + x. If so, then we have 2 situations:
+ a) sign (x) == sign (x + y), here we are done, example:
+ UBSAN_PTR (&MEM_REF[ptr + 100], -50)
+ b) check for dominating check of ptr + x + y.
+ */
+
+ bool sign_cur_offset = !wi::neg_p (cur_offset);
+ bool sign_expr_offset = bitpos >= 0;
+
+ tree base_addr
+ = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (base)), base);
+
+ bool add = false;
+ if (sign_cur_offset == sign_expr_offset)
+ {
+ if (has_dominating_ubsan_ptr_check (ctx, base_addr, total_offset))
+ return true;
+ else
+ add = true;
+ }
+ else
+ {
+ if (!has_dominating_ubsan_ptr_check (ctx, base_addr, expr_offset))
+ ; /* Don't record base_addr + expr_offset, it's not a guarding
+ check. */
+ else
+ {
+ bool sign_total_offset = !wi::neg_p (total_offset);
+ if (sign_expr_offset == sign_total_offset)
+ return true;
+ else
+ {
+ if (has_dominating_ubsan_ptr_check (ctx, base_addr,
+ total_offset))
+ return true;
+ else
+ add = true;
+ }
+ }
+ }
+
+ /* Record a new dominating check for base_addr + total_offset. */
+ if (add && !operand_equal_p (base, base_addr, 0))
+ record_ubsan_ptr_check_stmt (ctx, stmt, base_addr,
+ total_offset);
+ }
+ }
+
+ /* For this PTR we don't have any UBSAN_PTR stmts recorded, so there's
+ nothing to optimize yet. */
+ record_ubsan_ptr_check_stmt (ctx, stmt, ptr, cur_offset);
+
+ return false;
+}
+
/* Optimize away redundant UBSAN_VPTR calls. The second argument
is the value loaded from the virtual table, so rely on FRE to find out
when we can actually optimize. */
@@ -586,6 +819,9 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
case IFN_UBSAN_VPTR:
remove = maybe_optimize_ubsan_vptr_ifn (ctx, stmt);
break;
+ case IFN_UBSAN_PTR:
+ remove = maybe_optimize_ubsan_ptr_ifn (ctx, stmt);
+ break;
case IFN_ASAN_CHECK:
if (asan_check_optimize)
remove = maybe_optimize_asan_check_ifn (ctx, stmt);
@@ -604,15 +840,22 @@ sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
/* Drop this check. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "Optimizing out\n ");
+ fprintf (dump_file, "Optimizing out: ");
print_gimple_stmt (dump_file, stmt, 0, dump_flags);
- fprintf (dump_file, "\n");
}
unlink_stmt_vdef (stmt);
gsi_remove (&gsi, true);
}
else
- gsi_next (&gsi);
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Leaving: ");
+ print_gimple_stmt (dump_file, stmt, 0, dump_flags);
+ }
+
+ gsi_next (&gsi);
+ }
}
if (asan_check_optimize)
@@ -1008,7 +1251,7 @@ pass_sanopt::execute (function *fun)
if (optimize
&& (flag_sanitize
& (SANITIZE_NULL | SANITIZE_ALIGNMENT
- | SANITIZE_ADDRESS | SANITIZE_VPTR)))
+ | SANITIZE_ADDRESS | SANITIZE_VPTR | SANITIZE_POINTER_OVERFLOW)))
asan_num_accesses = sanopt_optimize (fun, &contains_asan_mark);
else if (flag_sanitize & SANITIZE_ADDRESS)
{
@@ -1103,9 +1346,8 @@ pass_sanopt::execute (function *fun)
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "Expanded\n ");
+ fprintf (dump_file, "Expanded: ");
print_gimple_stmt (dump_file, stmt, 0, dump_flags);
- fprintf (dump_file, "\n");
}
if (!no_next)
diff --git a/gcc/sbitmap.c b/gcc/sbitmap.c
index c065d13..df933f6 100644
--- a/gcc/sbitmap.c
+++ b/gcc/sbitmap.c
@@ -21,6 +21,7 @@ along with GCC; see the file COPYING3. If not see
#include "system.h"
#include "coretypes.h"
#include "sbitmap.h"
+#include "selftest.h"
typedef SBITMAP_ELT_TYPE *sbitmap_ptr;
typedef const SBITMAP_ELT_TYPE *const_sbitmap_ptr;
@@ -179,6 +180,8 @@ sbitmap_vector_alloc (unsigned int n_vecs, unsigned int n_elms)
void
bitmap_copy (sbitmap dst, const_sbitmap src)
{
+ gcc_checking_assert (src->size <= dst->size);
+
memcpy (dst->elms, src->elms, sizeof (SBITMAP_ELT_TYPE) * dst->size);
}
@@ -186,6 +189,8 @@ bitmap_copy (sbitmap dst, const_sbitmap src)
int
bitmap_equal_p (const_sbitmap a, const_sbitmap b)
{
+ bitmap_check_sizes (a, b);
+
return !memcmp (a->elms, b->elms, sizeof (SBITMAP_ELT_TYPE) * a->size);
}
@@ -210,6 +215,8 @@ bitmap_clear_range (sbitmap bmap, unsigned int start, unsigned int count)
if (count == 0)
return;
+ bitmap_check_index (bmap, start + count - 1);
+
unsigned int start_word = start / SBITMAP_ELT_BITS;
unsigned int start_bitno = start % SBITMAP_ELT_BITS;
@@ -266,6 +273,8 @@ bitmap_set_range (sbitmap bmap, unsigned int start, unsigned int count)
if (count == 0)
return;
+ bitmap_check_index (bmap, start + count - 1);
+
unsigned int start_word = start / SBITMAP_ELT_BITS;
unsigned int start_bitno = start % SBITMAP_ELT_BITS;
@@ -316,6 +325,55 @@ bitmap_set_range (sbitmap bmap, unsigned int start, unsigned int count)
bmap->elms[start_word] |= mask;
}
+/* Return TRUE if any bit between START and END inclusive is set within
+ the simple bitmap BMAP. Return FALSE otherwise. */
+
+bool
+bitmap_bit_in_range_p (const_sbitmap bmap, unsigned int start, unsigned int end)
+{
+ gcc_checking_assert (start <= end);
+ bitmap_check_index (bmap, end);
+
+ unsigned int start_word = start / SBITMAP_ELT_BITS;
+ unsigned int start_bitno = start % SBITMAP_ELT_BITS;
+
+ unsigned int end_word = end / SBITMAP_ELT_BITS;
+ unsigned int end_bitno = end % SBITMAP_ELT_BITS;
+
+ /* Check beginning of first word if different from zero. */
+ if (start_bitno != 0)
+ {
+ SBITMAP_ELT_TYPE high_mask = ~(SBITMAP_ELT_TYPE)0;
+ if (start_word == end_word && end_bitno + 1 < SBITMAP_ELT_BITS)
+ high_mask = ((SBITMAP_ELT_TYPE)1 << (end_bitno + 1)) - 1;
+
+ SBITMAP_ELT_TYPE low_mask = ((SBITMAP_ELT_TYPE)1 << start_bitno) - 1;
+ SBITMAP_ELT_TYPE mask = high_mask - low_mask;
+ if (bmap->elms[start_word] & mask)
+ return true;
+ start_word++;
+ }
+
+ if (start_word > end_word)
+ return false;
+
+ /* Now test words at a time until we hit a partial word. */
+ unsigned int nwords = (end_word - start_word);
+ while (nwords)
+ {
+ if (bmap->elms[start_word])
+ return true;
+ start_word++;
+ nwords--;
+ }
+
+ /* Now handle residuals in the last word. */
+ SBITMAP_ELT_TYPE mask = ~(SBITMAP_ELT_TYPE)0;
+ if (end_bitno + 1 < SBITMAP_ELT_BITS)
+ mask = ((SBITMAP_ELT_TYPE)1 << (end_bitno + 1)) - 1;
+ return (bmap->elms[start_word] & mask) != 0;
+}
+
#if GCC_VERSION < 3400
/* Table of number of set bits in a character, indexed by value of char. */
static const unsigned char popcount_table[] =
@@ -419,6 +477,9 @@ bitmap_vector_ones (sbitmap *bmap, unsigned int n_vecs)
bool
bitmap_ior_and_compl (sbitmap dst, const_sbitmap a, const_sbitmap b, const_sbitmap c)
{
+ bitmap_check_sizes (a, b);
+ bitmap_check_sizes (b, c);
+
unsigned int i, n = dst->size;
sbitmap_ptr dstp = dst->elms;
const_sbitmap_ptr ap = a->elms;
@@ -441,6 +502,8 @@ bitmap_ior_and_compl (sbitmap dst, const_sbitmap a, const_sbitmap b, const_sbitm
void
bitmap_not (sbitmap dst, const_sbitmap src)
{
+ bitmap_check_sizes (src, dst);
+
unsigned int i, n = dst->size;
sbitmap_ptr dstp = dst->elms;
const_sbitmap_ptr srcp = src->elms;
@@ -462,6 +525,9 @@ bitmap_not (sbitmap dst, const_sbitmap src)
void
bitmap_and_compl (sbitmap dst, const_sbitmap a, const_sbitmap b)
{
+ bitmap_check_sizes (a, b);
+ bitmap_check_sizes (b, dst);
+
unsigned int i, dst_size = dst->size;
unsigned int min_size = dst->size;
sbitmap_ptr dstp = dst->elms;
@@ -489,6 +555,8 @@ bitmap_and_compl (sbitmap dst, const_sbitmap a, const_sbitmap b)
bool
bitmap_intersect_p (const_sbitmap a, const_sbitmap b)
{
+ bitmap_check_sizes (a, b);
+
const_sbitmap_ptr ap = a->elms;
const_sbitmap_ptr bp = b->elms;
unsigned int i, n;
@@ -507,6 +575,9 @@ bitmap_intersect_p (const_sbitmap a, const_sbitmap b)
bool
bitmap_and (sbitmap dst, const_sbitmap a, const_sbitmap b)
{
+ bitmap_check_sizes (a, b);
+ bitmap_check_sizes (b, dst);
+
unsigned int i, n = dst->size;
sbitmap_ptr dstp = dst->elms;
const_sbitmap_ptr ap = a->elms;
@@ -529,6 +600,9 @@ bitmap_and (sbitmap dst, const_sbitmap a, const_sbitmap b)
bool
bitmap_xor (sbitmap dst, const_sbitmap a, const_sbitmap b)
{
+ bitmap_check_sizes (a, b);
+ bitmap_check_sizes (b, dst);
+
unsigned int i, n = dst->size;
sbitmap_ptr dstp = dst->elms;
const_sbitmap_ptr ap = a->elms;
@@ -551,6 +625,9 @@ bitmap_xor (sbitmap dst, const_sbitmap a, const_sbitmap b)
bool
bitmap_ior (sbitmap dst, const_sbitmap a, const_sbitmap b)
{
+ bitmap_check_sizes (a, b);
+ bitmap_check_sizes (b, dst);
+
unsigned int i, n = dst->size;
sbitmap_ptr dstp = dst->elms;
const_sbitmap_ptr ap = a->elms;
@@ -572,6 +649,8 @@ bitmap_ior (sbitmap dst, const_sbitmap a, const_sbitmap b)
bool
bitmap_subset_p (const_sbitmap a, const_sbitmap b)
{
+ bitmap_check_sizes (a, b);
+
unsigned int i, n = a->size;
const_sbitmap_ptr ap, bp;
@@ -588,6 +667,10 @@ bitmap_subset_p (const_sbitmap a, const_sbitmap b)
bool
bitmap_or_and (sbitmap dst, const_sbitmap a, const_sbitmap b, const_sbitmap c)
{
+ bitmap_check_sizes (a, b);
+ bitmap_check_sizes (b, c);
+ bitmap_check_sizes (c, dst);
+
unsigned int i, n = dst->size;
sbitmap_ptr dstp = dst->elms;
const_sbitmap_ptr ap = a->elms;
@@ -611,6 +694,10 @@ bitmap_or_and (sbitmap dst, const_sbitmap a, const_sbitmap b, const_sbitmap c)
bool
bitmap_and_or (sbitmap dst, const_sbitmap a, const_sbitmap b, const_sbitmap c)
{
+ bitmap_check_sizes (a, b);
+ bitmap_check_sizes (b, c);
+ bitmap_check_sizes (c, dst);
+
unsigned int i, n = dst->size;
sbitmap_ptr dstp = dst->elms;
const_sbitmap_ptr ap = a->elms;
@@ -768,3 +855,146 @@ dump_bitmap_vector (FILE *file, const char *title, const char *subtitle,
fprintf (file, "\n");
}
+
+#if CHECKING_P
+
+namespace selftest {
+
+/* Selftests for sbitmaps. */
+
+/* Checking function that uses both bitmap_bit_in_range_p and
+ loop of bitmap_bit_p and verifies consistent results. */
+
+static bool
+bitmap_bit_in_range_p_checking (sbitmap s, unsigned int start,
+ unsigned end)
+{
+ bool r1 = bitmap_bit_in_range_p (s, start, end);
+ bool r2 = false;
+
+ for (unsigned int i = start; i <= end; i++)
+ if (bitmap_bit_p (s, i))
+ {
+ r2 = true;
+ break;
+ }
+
+ ASSERT_EQ (r1, r2);
+ return r1;
+}
+
+/* Verify bitmap_set_range functions for sbitmap. */
+
+static void
+test_set_range ()
+{
+ sbitmap s = sbitmap_alloc (16);
+ bitmap_clear (s);
+
+ bitmap_set_range (s, 0, 1);
+ ASSERT_TRUE (bitmap_bit_in_range_p_checking (s, 0, 0));
+ ASSERT_FALSE (bitmap_bit_in_range_p_checking (s, 1, 15));
+ bitmap_set_range (s, 15, 1);
+ ASSERT_FALSE (bitmap_bit_in_range_p_checking (s, 1, 14));
+ ASSERT_TRUE (bitmap_bit_in_range_p_checking (s, 15, 15));
+
+ s = sbitmap_alloc (1024);
+ bitmap_clear (s);
+ bitmap_set_range (s, 512, 1);
+ ASSERT_FALSE (bitmap_bit_in_range_p_checking (s, 0, 511));
+ ASSERT_FALSE (bitmap_bit_in_range_p_checking (s, 513, 1023));
+ ASSERT_TRUE (bitmap_bit_in_range_p_checking (s, 512, 512));
+ ASSERT_TRUE (bitmap_bit_in_range_p_checking (s, 508, 512));
+ ASSERT_TRUE (bitmap_bit_in_range_p_checking (s, 508, 513));
+ ASSERT_FALSE (bitmap_bit_in_range_p_checking (s, 508, 511));
+
+ bitmap_clear (s);
+ bitmap_set_range (s, 512, 64);
+ ASSERT_FALSE (bitmap_bit_in_range_p_checking (s, 0, 511));
+ ASSERT_FALSE (bitmap_bit_in_range_p_checking (s, 512 + 64, 1023));
+ ASSERT_TRUE (bitmap_bit_in_range_p_checking (s, 512, 512));
+ ASSERT_TRUE (bitmap_bit_in_range_p_checking (s, 512 + 63, 512 + 63));
+}
+
+/* Verify bitmap_bit_in_range_p functions for sbitmap. */
+
+static void
+test_bit_in_range ()
+{
+ sbitmap s = sbitmap_alloc (1024);
+ bitmap_clear (s);
+
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 512, 1023));
+ bitmap_set_bit (s, 100);
+
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 512, 1023));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 0, 99));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 101, 1023));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 1, 100));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 64, 100));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 100, 100));
+ ASSERT_TRUE (bitmap_bit_p (s, 100));
+
+ s = sbitmap_alloc (64);
+ bitmap_clear (s);
+ bitmap_set_bit (s, 63);
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 0, 63));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 1, 63));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 63, 63));
+ ASSERT_TRUE (bitmap_bit_p (s, 63));
+
+ s = sbitmap_alloc (1024);
+ bitmap_clear (s);
+ bitmap_set_bit (s, 128);
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 0, 127));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 129, 1023));
+
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 0, 128));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 1, 128));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 128, 255));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 128, 254));
+ ASSERT_TRUE (bitmap_bit_p (s, 128));
+
+ bitmap_clear (s);
+ bitmap_set_bit (s, 8);
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 0, 8));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 0, 12));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 0, 63));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 0, 127));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 0, 512));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 8, 8));
+ ASSERT_TRUE (bitmap_bit_p (s, 8));
+
+ bitmap_clear (s);
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 0, 0));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 0, 8));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 0, 63));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 1, 63));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 0, 256));
+
+ bitmap_set_bit (s, 0);
+ bitmap_set_bit (s, 16);
+ bitmap_set_bit (s, 32);
+ bitmap_set_bit (s, 48);
+ bitmap_set_bit (s, 64);
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 0, 0));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 1, 16));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 48, 63));
+ ASSERT_TRUE (bitmap_bit_in_range_p (s, 64, 64));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 1, 15));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 17, 31));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 49, 63));
+ ASSERT_FALSE (bitmap_bit_in_range_p (s, 65, 1023));
+}
+
+/* Run all of the selftests within this file. */
+
+void
+sbitmap_c_tests ()
+{
+ test_set_range ();
+ test_bit_in_range ();
+}
+
+} // namespace selftest
+#endif /* CHECKING_P */
diff --git a/gcc/sbitmap.h b/gcc/sbitmap.h
index ce4d27d..a5ff068 100644
--- a/gcc/sbitmap.h
+++ b/gcc/sbitmap.h
@@ -51,6 +51,7 @@ along with GCC; see the file COPYING3. If not see
* set_difference : bitmap_and_compl
* set_disjuction : (not implemented)
* set_compare : bitmap_equal_p
+ * bit_in_range_p : bitmap_bit_in_range_p
Some operations on 3 sets that occur frequently in data flow problems
are also implemented:
@@ -95,10 +96,29 @@ struct simple_bitmap_def
/* Return the number of bits in BITMAP. */
#define SBITMAP_SIZE(BITMAP) ((BITMAP)->n_bits)
+/* Verify that access at INDEX in bitmap MAP is valid. */
+
+static inline void
+bitmap_check_index (const_sbitmap map, int index)
+{
+ gcc_checking_assert (index >= 0);
+ gcc_checking_assert ((unsigned int)index < map->n_bits);
+}
+
+/* Verify that bitmaps A and B have same size. */
+
+static inline void
+bitmap_check_sizes (const_sbitmap a, const_sbitmap b)
+{
+ gcc_checking_assert (a->n_bits == b->n_bits);
+}
+
/* Test if bit number bitno in the bitmap is set. */
static inline SBITMAP_ELT_TYPE
bitmap_bit_p (const_sbitmap map, int bitno)
{
+ bitmap_check_index (map, bitno);
+
size_t i = bitno / SBITMAP_ELT_BITS;
unsigned int s = bitno % SBITMAP_ELT_BITS;
return (map->elms[i] >> s) & (SBITMAP_ELT_TYPE) 1;
@@ -109,6 +129,8 @@ bitmap_bit_p (const_sbitmap map, int bitno)
static inline void
bitmap_set_bit (sbitmap map, int bitno)
{
+ bitmap_check_index (map, bitno);
+
map->elms[bitno / SBITMAP_ELT_BITS]
|= (SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS;
}
@@ -118,6 +140,8 @@ bitmap_set_bit (sbitmap map, int bitno)
static inline void
bitmap_clear_bit (sbitmap map, int bitno)
{
+ bitmap_check_index (map, bitno);
+
map->elms[bitno / SBITMAP_ELT_BITS]
&= ~((SBITMAP_ELT_TYPE) 1 << (bitno) % SBITMAP_ELT_BITS);
}
@@ -147,6 +171,8 @@ static inline void
bmp_iter_set_init (sbitmap_iterator *i, const_sbitmap bmp,
unsigned int min, unsigned *bit_no ATTRIBUTE_UNUSED)
{
+ bitmap_check_index (bmp, min);
+
i->word_num = min / (unsigned int) SBITMAP_ELT_BITS;
i->bit_num = min;
i->size = bmp->size;
@@ -253,6 +279,7 @@ extern bool bitmap_and (sbitmap, const_sbitmap, const_sbitmap);
extern bool bitmap_ior (sbitmap, const_sbitmap, const_sbitmap);
extern bool bitmap_xor (sbitmap, const_sbitmap, const_sbitmap);
extern bool bitmap_subset_p (const_sbitmap, const_sbitmap);
+extern bool bitmap_bit_in_range_p (const_sbitmap, unsigned int, unsigned int);
extern int bitmap_first_set_bit (const_sbitmap);
extern int bitmap_last_set_bit (const_sbitmap);
diff --git a/gcc/sched-deps.c b/gcc/sched-deps.c
index e7c4b87..a64e4e1 100644
--- a/gcc/sched-deps.c
+++ b/gcc/sched-deps.c
@@ -4714,6 +4714,11 @@ parse_add_or_inc (struct mem_inc_info *mii, rtx_insn *insn, bool before_mem)
if (RTX_FRAME_RELATED_P (insn) || !pat)
return false;
+ /* Do not allow breaking data dependencies for insns that are marked
+ with REG_STACK_CHECK. */
+ if (find_reg_note (insn, REG_STACK_CHECK, NULL))
+ return false;
+
/* Result must be single reg. */
if (!REG_P (SET_DEST (pat)))
return false;
diff --git a/gcc/sched-int.h b/gcc/sched-int.h
index 624d892..6832589 100644
--- a/gcc/sched-int.h
+++ b/gcc/sched-int.h
@@ -819,15 +819,8 @@ struct autopref_multipass_data_
/* Base part of memory address. */
rtx base;
- /* Memory offsets from the base. For single simple sets
- only min_offset is valid. For multi-set insns min_offset
- and max_offset record the minimum and maximum offsets from the same
- base among the sets inside the PARALLEL. */
- int min_offset;
- int max_offset;
-
- /* True if this is a load/store-multiple instruction. */
- bool multi_mem_insn_p;
+ /* Memory offsets from the base. */
+ int offset;
/* Entry status. */
enum autopref_multipass_data_status status;
@@ -1403,7 +1396,7 @@ extern void get_ebb_head_tail (basic_block, basic_block,
rtx_insn **, rtx_insn **);
extern int no_real_insns_p (const rtx_insn *, const rtx_insn *);
-extern int insn_cost (rtx_insn *);
+extern int insn_sched_cost (rtx_insn *);
extern int dep_cost_1 (dep_t, dw_t);
extern int dep_cost (dep_t);
extern int set_priorities (rtx_insn *, rtx_insn *);
diff --git a/gcc/sched-rgn.c b/gcc/sched-rgn.c
index 492094e..ba5b47c 100644
--- a/gcc/sched-rgn.c
+++ b/gcc/sched-rgn.c
@@ -2837,8 +2837,8 @@ void debug_dependencies (rtx_insn *head, rtx_insn *tail)
: INSN_PRIORITY (insn))
: INSN_PRIORITY (insn)),
(sel_sched_p () ? (sched_emulate_haifa_p ? -1
- : insn_cost (insn))
- : insn_cost (insn)));
+ : insn_sched_cost (insn))
+ : insn_sched_cost (insn)));
if (recog_memoized (insn) < 0)
fprintf (sched_dump, "nothing");
diff --git a/gcc/sel-sched-ir.c b/gcc/sel-sched-ir.c
index fa88259..c0e835f 100644
--- a/gcc/sel-sched-ir.c
+++ b/gcc/sel-sched-ir.c
@@ -1324,7 +1324,7 @@ sel_insn_rtx_cost (rtx_insn *insn)
}
/* Return the cost of the VI.
- !!! FIXME: Unify with haifa-sched.c: insn_cost (). */
+ !!! FIXME: Unify with haifa-sched.c: insn_sched_cost (). */
int
sel_vinsn_cost (vinsn_t vi)
{
diff --git a/gcc/selftest-run-tests.c b/gcc/selftest-run-tests.c
index 30e476d..11bf0cc 100644
--- a/gcc/selftest-run-tests.c
+++ b/gcc/selftest-run-tests.c
@@ -56,6 +56,7 @@ selftest::run_tests ()
/* Low-level data structures. */
bitmap_c_tests ();
+ sbitmap_c_tests ();
et_forest_c_tests ();
hash_map_tests_c_tests ();
hash_set_tests_c_tests ();
@@ -66,6 +67,7 @@ selftest::run_tests ()
sreal_c_tests ();
fibonacci_heap_c_tests ();
typed_splay_tree_c_tests ();
+ unique_ptr_tests_cc_tests ();
/* Mid-level data structures. */
input_c_tests ();
diff --git a/gcc/selftest.h b/gcc/selftest.h
index 0572fef..6478922 100644
--- a/gcc/selftest.h
+++ b/gcc/selftest.h
@@ -171,6 +171,7 @@ extern const char *path_to_selftest_files;
/* Declarations for specific families of tests (by source file), in
alphabetical order. */
extern void bitmap_c_tests ();
+extern void sbitmap_c_tests ();
extern void diagnostic_c_tests ();
extern void diagnostic_show_locus_c_tests ();
extern void edit_context_c_tests ();
@@ -194,6 +195,7 @@ extern void store_merging_c_tests ();
extern void typed_splay_tree_c_tests ();
extern void tree_c_tests ();
extern void tree_cfg_c_tests ();
+extern void unique_ptr_tests_cc_tests ();
extern void vec_c_tests ();
extern void wide_int_cc_tests ();
extern void predict_c_tests ();
diff --git a/gcc/sese.c b/gcc/sese.c
index 3279ead..89cddf0 100644
--- a/gcc/sese.c
+++ b/gcc/sese.c
@@ -40,8 +40,9 @@ along with GCC; see the file COPYING3. If not see
#include "cfgloop.h"
#include "tree-data-ref.h"
#include "tree-scalar-evolution.h"
-#include "sese.h"
#include "tree-ssa-propagate.h"
+#include "cfganal.h"
+#include "sese.h"
/* For a USE in BB, if BB is outside REGION, mark the USE in the
LIVEOUTS set. */
@@ -67,106 +68,80 @@ sese_build_liveouts_use (sese_info_p region, bitmap liveouts, basic_block bb,
used in BB that is outside of the REGION. */
static void
-sese_build_liveouts_bb (sese_info_p region, bitmap liveouts, basic_block bb)
+sese_build_liveouts_bb (sese_info_p region, basic_block bb)
{
- edge e;
- edge_iterator ei;
ssa_op_iter iter;
use_operand_p use_p;
- FOR_EACH_EDGE (e, ei, bb->succs)
- for (gphi_iterator bsi = gsi_start_phis (e->dest); !gsi_end_p (bsi);
- gsi_next (&bsi))
- sese_build_liveouts_use (region, liveouts, bb,
- PHI_ARG_DEF_FROM_EDGE (bsi.phi (), e));
+ for (gphi_iterator bsi = gsi_start_phis (bb); !gsi_end_p (bsi);
+ gsi_next (&bsi))
+ FOR_EACH_PHI_ARG (use_p, bsi.phi (), iter, SSA_OP_USE)
+ sese_build_liveouts_use (region, region->liveout,
+ bb, USE_FROM_PTR (use_p));
for (gimple_stmt_iterator bsi = gsi_start_bb (bb); !gsi_end_p (bsi);
gsi_next (&bsi))
{
gimple *stmt = gsi_stmt (bsi);
+ bitmap liveouts = region->liveout;
if (is_gimple_debug (stmt))
- continue;
+ liveouts = region->debug_liveout;
- FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
+ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
sese_build_liveouts_use (region, liveouts, bb, USE_FROM_PTR (use_p));
}
}
-/* For a USE in BB, return true if BB is outside REGION and it's not
- in the LIVEOUTS set. */
-
-static bool
-sese_bad_liveouts_use (sese_info_p region, bitmap liveouts, basic_block bb,
- tree use)
-{
- gcc_assert (!bb_in_sese_p (bb, region->region));
-
- if (TREE_CODE (use) != SSA_NAME)
- return false;
-
- unsigned ver = SSA_NAME_VERSION (use);
-
- /* If it's in liveouts, the variable will get a new PHI node, and
- the debug use will be properly adjusted. */
- if (bitmap_bit_p (liveouts, ver))
- return false;
-
- basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (use));
-
- if (!def_bb || !bb_in_sese_p (def_bb, region->region))
- return false;
-
- return true;
-}
-
/* Reset debug stmts that reference SSA_NAMES defined in REGION that
are not marked as liveouts. */
static void
-sese_reset_debug_liveouts_bb (sese_info_p region, bitmap liveouts,
- basic_block bb)
+sese_reset_debug_liveouts (sese_info_p region)
{
- gimple_stmt_iterator bsi;
- ssa_op_iter iter;
- use_operand_p use_p;
-
- for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi))
+ bitmap_iterator bi;
+ unsigned i;
+ EXECUTE_IF_AND_COMPL_IN_BITMAP (region->debug_liveout, region->liveout,
+ 0, i, bi)
{
- gimple *stmt = gsi_stmt (bsi);
-
- if (!is_gimple_debug (stmt))
- continue;
-
- FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_ALL_USES)
- if (sese_bad_liveouts_use (region, liveouts, bb,
- USE_FROM_PTR (use_p)))
- {
- gimple_debug_bind_reset_value (stmt);
- update_stmt (stmt);
- break;
- }
+ tree name = ssa_name (i);
+ auto_vec<gimple *, 4> stmts;
+ gimple *use_stmt;
+ imm_use_iterator use_iter;
+ FOR_EACH_IMM_USE_STMT (use_stmt, use_iter, name)
+ {
+ if (! is_gimple_debug (use_stmt)
+ || bb_in_sese_p (gimple_bb (use_stmt), region->region))
+ continue;
+ stmts.safe_push (use_stmt);
+ }
+ while (!stmts.is_empty ())
+ {
+ gimple *stmt = stmts.pop ();
+ gimple_debug_bind_reset_value (stmt);
+ update_stmt (stmt);
+ }
}
}
/* Build the LIVEOUTS of REGION: the set of variables defined inside
and used outside the REGION. */
-static void
-sese_build_liveouts (sese_info_p region, bitmap liveouts)
+void
+sese_build_liveouts (sese_info_p region)
{
basic_block bb;
+ gcc_assert (region->liveout == NULL
+ && region->debug_liveout == NULL);
+
+ region->liveout = BITMAP_ALLOC (NULL);
+ region->debug_liveout = BITMAP_ALLOC (NULL);
+
/* FIXME: We could start iterating form the successor of sese. */
FOR_EACH_BB_FN (bb, cfun)
if (!bb_in_sese_p (bb, region->region))
- sese_build_liveouts_bb (region, liveouts, bb);
-
- /* FIXME: We could start iterating form the successor of sese. */
- if (MAY_HAVE_DEBUG_STMTS)
- FOR_EACH_BB_FN (bb, cfun)
- if (!bb_in_sese_p (bb, region->region))
- sese_reset_debug_liveouts_bb (region, liveouts, bb);
+ sese_build_liveouts_bb (region, bb);
}
/* Builds a new SESE region from edges ENTRY and EXIT. */
@@ -178,14 +153,11 @@ new_sese_info (edge entry, edge exit)
region->region.entry = entry;
region->region.exit = exit;
- region->loop_nest.create (3);
+ region->liveout = NULL;
+ region->debug_liveout = NULL;
region->params.create (3);
- region->rename_map = new rename_map_t;
- region->parameter_rename_map = new parameter_rename_map_t;
- region->copied_bb_map = new bb_map_t;
+ region->rename_map = new hash_map <tree, tree>;
region->bbs.create (3);
- region->incomplete_phis.create (3);
-
return region;
}
@@ -196,26 +168,12 @@ void
free_sese_info (sese_info_p region)
{
region->params.release ();
- region->loop_nest.release ();
-
- for (rename_map_t::iterator it = region->rename_map->begin ();
- it != region->rename_map->end (); ++it)
- (*it).second.release ();
-
- for (bb_map_t::iterator it = region->copied_bb_map->begin ();
- it != region->copied_bb_map->end (); ++it)
- (*it).second.release ();
+ BITMAP_FREE (region->liveout);
+ BITMAP_FREE (region->debug_liveout);
delete region->rename_map;
- delete region->parameter_rename_map;
- delete region->copied_bb_map;
-
region->rename_map = NULL;
- region->parameter_rename_map = NULL;
- region->copied_bb_map = NULL;
-
region->bbs.release ();
- region->incomplete_phis.release ();
XDELETE (region);
}
@@ -247,17 +205,14 @@ void
sese_insert_phis_for_liveouts (sese_info_p region, basic_block bb,
edge false_e, edge true_e)
{
+ if (MAY_HAVE_DEBUG_STMTS)
+ sese_reset_debug_liveouts (region);
+
unsigned i;
bitmap_iterator bi;
- bitmap liveouts = BITMAP_ALLOC (NULL);
-
- sese_build_liveouts (region, liveouts);
-
- EXECUTE_IF_SET_IN_BITMAP (liveouts, 0, i, bi)
+ EXECUTE_IF_SET_IN_BITMAP (region->liveout, 0, i, bi)
if (!virtual_operand_p (ssa_name (i)))
sese_add_exit_phis_edge (bb, ssa_name (i), false_e, true_e);
-
- BITMAP_FREE (liveouts);
}
/* Returns the outermost loop in SCOP that contains BB. */
@@ -333,92 +288,6 @@ get_false_edge_from_guard_bb (basic_block bb)
return NULL;
}
-/* Sets the false region of an IF_REGION to REGION. */
-
-void
-if_region_set_false_region (ifsese if_region, sese_info_p region)
-{
- basic_block condition = if_region_get_condition_block (if_region);
- edge false_edge = get_false_edge_from_guard_bb (condition);
- basic_block dummy = false_edge->dest;
- edge entry_region = region->region.entry;
- edge exit_region = region->region.exit;
- basic_block before_region = entry_region->src;
- basic_block last_in_region = exit_region->src;
- hashval_t hash = htab_hash_pointer (exit_region);
- loop_exit **slot
- = current_loops->exits->find_slot_with_hash (exit_region, hash, NO_INSERT);
-
- entry_region->flags = false_edge->flags;
- false_edge->flags = exit_region->flags;
-
- redirect_edge_pred (entry_region, condition);
- redirect_edge_pred (exit_region, before_region);
- redirect_edge_pred (false_edge, last_in_region);
- redirect_edge_succ (false_edge, single_succ (dummy));
- delete_basic_block (dummy);
-
- exit_region->flags = EDGE_FALLTHRU;
- recompute_all_dominators ();
-
- region->region.exit = false_edge;
-
- free (if_region->false_region);
- if_region->false_region = region;
-
- if (slot)
- {
- struct loop_exit *loop_exit = ggc_cleared_alloc<struct loop_exit> ();
-
- memcpy (loop_exit, *((struct loop_exit **) slot),
- sizeof (struct loop_exit));
- current_loops->exits->clear_slot (slot);
-
- hashval_t hash = htab_hash_pointer (false_edge);
- slot = current_loops->exits->find_slot_with_hash (false_edge, hash,
- INSERT);
- loop_exit->e = false_edge;
- *slot = loop_exit;
- false_edge->src->loop_father->exits->next = loop_exit;
- }
-}
-
-/* Creates an IFSESE with CONDITION on edge ENTRY. */
-
-static ifsese
-create_if_region_on_edge (edge entry, tree condition)
-{
- edge e;
- edge_iterator ei;
- sese_info_p sese_region = XNEW (struct sese_info_t);
- sese_info_p true_region = XNEW (struct sese_info_t);
- sese_info_p false_region = XNEW (struct sese_info_t);
- ifsese if_region = XNEW (struct ifsese_s);
- edge exit = create_empty_if_region_on_edge (entry, condition);
-
- if_region->region = sese_region;
- if_region->region->region.entry = entry;
- if_region->region->region.exit = exit;
-
- FOR_EACH_EDGE (e, ei, entry->dest->succs)
- {
- if (e->flags & EDGE_TRUE_VALUE)
- {
- true_region->region.entry = e;
- true_region->region.exit = single_succ_edge (e->dest);
- if_region->true_region = true_region;
- }
- else if (e->flags & EDGE_FALSE_VALUE)
- {
- false_region->region.entry = e;
- false_region->region.exit = single_succ_edge (e->dest);
- if_region->false_region = false_region;
- }
- }
-
- return if_region;
-}
-
/* Moves REGION in a condition expression:
| if (1)
| ;
@@ -429,13 +298,34 @@ create_if_region_on_edge (edge entry, tree condition)
ifsese
move_sese_in_condition (sese_info_p region)
{
+ basic_block region_entry_dest = region->region.entry->dest;
basic_block pred_block = split_edge (region->region.entry);
- ifsese if_region;
-
- region->region.entry = single_succ_edge (pred_block);
- if_region = create_if_region_on_edge (single_pred_edge (pred_block),
- integer_one_node);
- if_region_set_false_region (if_region, region);
+ basic_block merge_block = split_edge (region->region.exit);
+
+ edge true_edge = make_edge (pred_block, merge_block, EDGE_TRUE_VALUE);
+ edge false_edge = find_edge (pred_block, region_entry_dest);
+ false_edge->flags &= ~EDGE_FALLTHRU;
+ false_edge->flags |= EDGE_FALSE_VALUE;
+ gimple_stmt_iterator gsi = gsi_last_bb (pred_block);
+ gcond *cond = gimple_build_cond (NE_EXPR, integer_one_node, integer_zero_node,
+ NULL_TREE, NULL_TREE);
+ gsi_insert_after (&gsi, cond, GSI_CONTINUE_LINKING);
+ if (dom_info_available_p (CDI_DOMINATORS))
+ set_immediate_dominator (CDI_DOMINATORS, merge_block, pred_block);
+
+ ifsese if_region = XNEW (ifsese_s);
+ if_region->region = XCNEW (sese_info_t);
+ if_region->true_region = XCNEW (sese_info_t);
+ if_region->false_region = XCNEW (sese_info_t);
+ if_region->region->region.entry = single_pred_edge (pred_block);
+ if_region->region->region.exit = single_succ_edge (merge_block);
+ if_region->false_region->region.entry = false_edge;
+ if_region->false_region->region.exit = region->region.exit;
+ if_region->true_region->region.entry = true_edge;
+ if_region->true_region->region.exit
+ = single_succ_edge (split_edge (true_edge));
+
+ region->region = if_region->false_region->region;
return if_region;
}
@@ -535,11 +425,13 @@ scev_analyzable_p (tree def, sese_l &region)
loop = loop_containing_stmt (SSA_NAME_DEF_STMT (def));
scev = scalar_evolution_in_region (region, loop, def);
- return !chrec_contains_undetermined (scev)
- && (TREE_CODE (scev) != SSA_NAME
- || !defined_in_sese_p (scev, region))
- && (tree_does_not_contain_chrecs (scev)
- || evolution_function_is_affine_p (scev));
+ return (!chrec_contains_undetermined (scev)
+ && (TREE_CODE (scev) != SSA_NAME
+ || !defined_in_sese_p (scev, region))
+ && scev_is_linear_expression (scev)
+ && (! loop
+ || ! loop_in_sese_p (loop, region)
+ || ! chrec_contains_symbols_defined_in_loop (scev, loop->num)));
}
/* Returns the scalar evolution of T in REGION. Every variable that
@@ -548,42 +440,31 @@ scev_analyzable_p (tree def, sese_l &region)
tree
scalar_evolution_in_region (const sese_l &region, loop_p loop, tree t)
{
- gimple *def;
- struct loop *def_loop;
- basic_block before = region.entry->src;
-
/* SCOP parameters. */
if (TREE_CODE (t) == SSA_NAME
&& !defined_in_sese_p (t, region))
return t;
- if (TREE_CODE (t) != SSA_NAME
- || loop_in_sese_p (loop, region))
- /* FIXME: we would need instantiate SCEV to work on a region, and be more
- flexible wrt. memory loads that may be invariant in the region. */
- return instantiate_scev (before, loop,
- analyze_scalar_evolution (loop, t));
+ if (!loop_in_sese_p (loop, region))
+ loop = NULL;
- def = SSA_NAME_DEF_STMT (t);
- def_loop = loop_containing_stmt (def);
+ return instantiate_scev (region.entry, loop,
+ analyze_scalar_evolution (loop, t));
+}
- if (loop_in_sese_p (def_loop, region))
- {
- t = analyze_scalar_evolution (def_loop, t);
- def_loop = superloop_at_depth (def_loop, loop_depth (loop) + 1);
- t = compute_overall_effect_of_inner_loop (def_loop, t);
- return t;
- }
+/* Return true if BB is empty, contains only DEBUG_INSNs. */
- bool has_vdefs = false;
- if (invariant_in_sese_p_rec (t, region, &has_vdefs))
- return t;
+bool
+sese_trivially_empty_bb_p (basic_block bb)
+{
+ gimple_stmt_iterator gsi;
- /* T variates in REGION. */
- if (has_vdefs)
- return chrec_dont_know;
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
+ if (gimple_code (gsi_stmt (gsi)) != GIMPLE_DEBUG
+ && gimple_code (gsi_stmt (gsi)) != GIMPLE_LABEL)
+ return false;
- return instantiate_scev (before, loop, t);
+ return true;
}
/* Pretty print edge E to FILE. */
diff --git a/gcc/sese.h b/gcc/sese.h
index e51f1b4..cbc20ab 100644
--- a/gcc/sese.h
+++ b/gcc/sese.h
@@ -22,14 +22,7 @@ along with GCC; see the file COPYING3. If not see
#ifndef GCC_SESE_H
#define GCC_SESE_H
-typedef hash_map<tree, tree> parameter_rename_map_t;
-typedef hash_map<basic_block, vec<basic_block> > bb_map_t;
-typedef hash_map<tree, vec<tree> > rename_map_t;
typedef struct ifsese_s *ifsese;
-/* First phi is the new codegenerated phi second one is original phi. */
-typedef std::pair <gphi *, gphi *> phi_rename;
-/* First edge is the init edge and second is the back edge w.r.t. a loop. */
-typedef std::pair<edge, edge> init_back_edge_pair_t;
/* A Single Entry, Single Exit region is a part of the CFG delimited
by two edges. */
@@ -83,30 +76,21 @@ typedef struct sese_info_t
/* The SESE region. */
sese_l region;
- /* Parameters used within the SCOP. */
- vec<tree> params;
+ /* Liveout vars. */
+ bitmap liveout;
- /* Maps an old name to one or more new names. When there are several new
- names, one has to select the definition corresponding to the immediate
- dominator. */
- rename_map_t *rename_map;
+ /* Liveout in debug stmts. */
+ bitmap debug_liveout;
- /* Parameters to be renamed. */
- parameter_rename_map_t *parameter_rename_map;
+ /* Parameters used within the SCOP. */
+ vec<tree> params;
- /* Loops completely contained in this SESE. */
- vec<loop_p> loop_nest;
+ /* Maps an old name to a new decl. */
+ hash_map<tree, tree> *rename_map;
/* Basic blocks contained in this SESE. */
vec<basic_block> bbs;
- /* Copied basic blocks indexed by the original bb. */
- bb_map_t *copied_bb_map;
-
- /* A vector of phi nodes to be updated when all arguments are available. The
- pair contains first the old_phi and second the new_phi. */
- vec<phi_rename> incomplete_phis;
-
/* The condition region generated for this sese. */
ifsese if_region;
@@ -119,6 +103,8 @@ extern struct loop *outermost_loop_in_sese (sese_l &, basic_block);
extern tree scalar_evolution_in_region (const sese_l &, loop_p, tree);
extern bool scev_analyzable_p (tree, sese_l &);
extern bool invariant_in_sese_p_rec (tree, const sese_l &, bool *);
+extern void sese_build_liveouts (sese_info_p);
+extern bool sese_trivially_empty_bb_p (basic_block);
/* The number of parameters in REGION. */
@@ -233,7 +219,6 @@ typedef struct ifsese_s {
sese_info_p false_region;
} *ifsese;
-extern void if_region_set_false_region (ifsese, sese_info_p);
extern ifsese move_sese_in_condition (sese_info_p);
extern void set_ifsese_condition (ifsese, tree);
extern edge get_true_edge_from_guard_bb (basic_block);
diff --git a/gcc/shrink-wrap.c b/gcc/shrink-wrap.c
index 3cad776..1a2802f 100644
--- a/gcc/shrink-wrap.c
+++ b/gcc/shrink-wrap.c
@@ -561,7 +561,6 @@ handle_simple_exit (edge e)
BB_END (old_bb) = end;
redirect_edge_succ (e, new_bb);
- new_bb->count = e->count;
new_bb->frequency = EDGE_FREQUENCY (e);
e->flags |= EDGE_FALLTHRU;
diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c
index 1b960b9..da0283d 100644
--- a/gcc/simplify-rtx.c
+++ b/gcc/simplify-rtx.c
@@ -62,7 +62,7 @@ neg_const_int (machine_mode mode, const_rtx i)
{
unsigned HOST_WIDE_INT val = -UINTVAL (i);
- if (GET_MODE_PRECISION (mode) > HOST_BITS_PER_WIDE_INT
+ if (!HWI_COMPUTABLE_MODE_P (mode)
&& val == UINTVAL (i))
return simplify_const_unary_operation (NEG, mode, CONST_CAST_RTX (i),
mode);
@@ -1136,7 +1136,7 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
C is equal to the width of MODE minus 1. */
if (GET_CODE (op) == ASHIFTRT
&& CONST_INT_P (XEXP (op, 1))
- && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
+ && INTVAL (XEXP (op, 1)) == GET_MODE_UNIT_PRECISION (mode) - 1)
return simplify_gen_binary (LSHIFTRT, mode,
XEXP (op, 0), XEXP (op, 1));
@@ -1144,7 +1144,7 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
C is equal to the width of MODE minus 1. */
if (GET_CODE (op) == LSHIFTRT
&& CONST_INT_P (XEXP (op, 1))
- && INTVAL (XEXP (op, 1)) == GET_MODE_PRECISION (mode) - 1)
+ && INTVAL (XEXP (op, 1)) == GET_MODE_UNIT_PRECISION (mode) - 1)
return simplify_gen_binary (ASHIFTRT, mode,
XEXP (op, 0), XEXP (op, 1));
@@ -1272,10 +1272,9 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
if ((GET_CODE (op) == FLOAT_TRUNCATE
&& flag_unsafe_math_optimizations)
|| GET_CODE (op) == FLOAT_EXTEND)
- return simplify_gen_unary (GET_MODE_SIZE (GET_MODE (XEXP (op,
- 0)))
- > GET_MODE_SIZE (mode)
- ? FLOAT_TRUNCATE : FLOAT_EXTEND,
+ return simplify_gen_unary (GET_MODE_UNIT_SIZE (GET_MODE (XEXP (op, 0)))
+ > GET_MODE_UNIT_SIZE (mode)
+ ? FLOAT_TRUNCATE : FLOAT_EXTEND,
mode,
XEXP (op, 0), mode);
@@ -1447,19 +1446,21 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
if (lcode == ASHIFTRT)
/* Number of bits not shifted off the end. */
- bits = GET_MODE_PRECISION (lmode) - INTVAL (XEXP (lhs, 1));
+ bits = (GET_MODE_UNIT_PRECISION (lmode)
+ - INTVAL (XEXP (lhs, 1)));
else /* lcode == SIGN_EXTEND */
/* Size of inner mode. */
- bits = GET_MODE_PRECISION (GET_MODE (XEXP (lhs, 0)));
+ bits = GET_MODE_UNIT_PRECISION (GET_MODE (XEXP (lhs, 0)));
if (rcode == ASHIFTRT)
- bits += GET_MODE_PRECISION (rmode) - INTVAL (XEXP (rhs, 1));
+ bits += (GET_MODE_UNIT_PRECISION (rmode)
+ - INTVAL (XEXP (rhs, 1)));
else /* rcode == SIGN_EXTEND */
- bits += GET_MODE_PRECISION (GET_MODE (XEXP (rhs, 0)));
+ bits += GET_MODE_UNIT_PRECISION (GET_MODE (XEXP (rhs, 0)));
/* We can only widen multiplies if the result is mathematiclly
equivalent. I.e. if overflow was impossible. */
- if (bits <= GET_MODE_PRECISION (GET_MODE (op)))
+ if (bits <= GET_MODE_UNIT_PRECISION (GET_MODE (op)))
return simplify_gen_binary
(MULT, mode,
simplify_gen_unary (SIGN_EXTEND, mode, lhs, lmode),
@@ -1484,8 +1485,8 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
(sign_extend:M (zero_extend:N <X>)) is (zero_extend:M <X>). */
if (GET_CODE (op) == SIGN_EXTEND || GET_CODE (op) == ZERO_EXTEND)
{
- gcc_assert (GET_MODE_PRECISION (mode)
- > GET_MODE_PRECISION (GET_MODE (op)));
+ gcc_assert (GET_MODE_UNIT_PRECISION (mode)
+ > GET_MODE_UNIT_PRECISION (GET_MODE (op)));
return simplify_gen_unary (GET_CODE (op), mode, XEXP (op, 0),
GET_MODE (XEXP (op, 0)));
}
@@ -1585,19 +1586,21 @@ simplify_unary_operation_1 (enum rtx_code code, machine_mode mode, rtx op)
if (lcode == LSHIFTRT)
/* Number of bits not shifted off the end. */
- bits = GET_MODE_PRECISION (lmode) - INTVAL (XEXP (lhs, 1));
+ bits = (GET_MODE_UNIT_PRECISION (lmode)
+ - INTVAL (XEXP (lhs, 1)));
else /* lcode == ZERO_EXTEND */
/* Size of inner mode. */
- bits = GET_MODE_PRECISION (GET_MODE (XEXP (lhs, 0)));
+ bits = GET_MODE_UNIT_PRECISION (GET_MODE (XEXP (lhs, 0)));
if (rcode == LSHIFTRT)
- bits += GET_MODE_PRECISION (rmode) - INTVAL (XEXP (rhs, 1));
+ bits += (GET_MODE_UNIT_PRECISION (rmode)
+ - INTVAL (XEXP (rhs, 1)));
else /* rcode == ZERO_EXTEND */
- bits += GET_MODE_PRECISION (GET_MODE (XEXP (rhs, 0)));
+ bits += GET_MODE_UNIT_PRECISION (GET_MODE (XEXP (rhs, 0)));
/* We can only widen multiplies if the result is mathematiclly
equivalent. I.e. if overflow was impossible. */
- if (bits <= GET_MODE_PRECISION (GET_MODE (op)))
+ if (bits <= GET_MODE_UNIT_PRECISION (GET_MODE (op)))
return simplify_gen_binary
(MULT, mode,
simplify_gen_unary (ZERO_EXTEND, mode, lhs, lmode),
@@ -2145,7 +2148,6 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
{
rtx tem, reversed, opleft, opright;
HOST_WIDE_INT val;
- unsigned int width = GET_MODE_PRECISION (mode);
scalar_int_mode int_mode, inner_mode;
/* Even if we can't compute a constant result,
@@ -2673,14 +2675,6 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
/* If (C1|C2) == ~0 then (X&C1)|C2 becomes X|C2. */
if (((c1|c2) & mask) == mask)
return simplify_gen_binary (IOR, mode, XEXP (op0, 0), op1);
-
- /* Minimize the number of bits set in C1, i.e. C1 := C1 & ~C2. */
- if (((c1 & ~c2) & mask) != (c1 & mask))
- {
- tem = simplify_gen_binary (AND, mode, XEXP (op0, 0),
- gen_int_mode (c1 & ~c2, mode));
- return simplify_gen_binary (IOR, mode, tem, op1);
- }
}
/* Convert (A & B) | A to A. */
@@ -2711,7 +2705,7 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
&& CONST_INT_P (XEXP (opleft, 1))
&& CONST_INT_P (XEXP (opright, 1))
&& (INTVAL (XEXP (opleft, 1)) + INTVAL (XEXP (opright, 1))
- == GET_MODE_PRECISION (mode)))
+ == GET_MODE_UNIT_PRECISION (mode)))
return gen_rtx_ROTATE (mode, XEXP (opright, 0), XEXP (opleft, 1));
/* Same, but for ashift that has been "simplified" to a wider mode
@@ -2736,23 +2730,6 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
return gen_rtx_ROTATE (int_mode, XEXP (opright, 0),
XEXP (SUBREG_REG (opleft), 1));
- /* If we have (ior (and (X C1) C2)), simplify this by making
- C1 as small as possible if C1 actually changes. */
- if (CONST_INT_P (op1)
- && (HWI_COMPUTABLE_MODE_P (mode)
- || INTVAL (op1) > 0)
- && GET_CODE (op0) == AND
- && CONST_INT_P (XEXP (op0, 1))
- && CONST_INT_P (op1)
- && (UINTVAL (XEXP (op0, 1)) & UINTVAL (op1)) != 0)
- {
- rtx tmp = simplify_gen_binary (AND, mode, XEXP (op0, 0),
- gen_int_mode (UINTVAL (XEXP (op0, 1))
- & ~UINTVAL (op1),
- mode));
- return simplify_gen_binary (IOR, mode, tmp, op1);
- }
-
/* If OP0 is (ashiftrt (plus ...) C), it might actually be
a (sign_extend (plus ...)). Then check if OP1 is a CONST_INT and
the PLUS does not affect any of the bits in OP1: then we can do
@@ -3354,11 +3331,12 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
#if defined(HAVE_rotate) && defined(HAVE_rotatert)
if (CONST_INT_P (trueop1)
&& IN_RANGE (INTVAL (trueop1),
- GET_MODE_PRECISION (mode) / 2 + (code == ROTATE),
- GET_MODE_PRECISION (mode) - 1))
+ GET_MODE_UNIT_PRECISION (mode) / 2 + (code == ROTATE),
+ GET_MODE_UNIT_PRECISION (mode) - 1))
return simplify_gen_binary (code == ROTATE ? ROTATERT : ROTATE,
- mode, op0, GEN_INT (GET_MODE_PRECISION (mode)
- - INTVAL (trueop1)));
+ mode, op0,
+ GEN_INT (GET_MODE_UNIT_PRECISION (mode)
+ - INTVAL (trueop1)));
#endif
/* FALLTHRU */
case ASHIFTRT:
@@ -3367,7 +3345,8 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
if (trueop0 == CONST0_RTX (mode) && ! side_effects_p (op1))
return op0;
/* Rotating ~0 always results in ~0. */
- if (CONST_INT_P (trueop0) && width <= HOST_BITS_PER_WIDE_INT
+ if (CONST_INT_P (trueop0)
+ && HWI_COMPUTABLE_MODE_P (mode)
&& UINTVAL (trueop0) == GET_MODE_MASK (mode)
&& ! side_effects_p (op1))
return op0;
@@ -3408,7 +3387,7 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
if (SHIFT_COUNT_TRUNCATED && CONST_INT_P (op1))
{
- val = INTVAL (op1) & (GET_MODE_PRECISION (mode) - 1);
+ val = INTVAL (op1) & (GET_MODE_UNIT_PRECISION (mode) - 1);
if (val != INTVAL (op1))
return simplify_gen_binary (code, mode, op0, GEN_INT (val));
}
@@ -3433,7 +3412,7 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
&& is_a <scalar_int_mode> (GET_MODE (XEXP (op0, 0)), &inner_mode)
&& CONST_INT_P (trueop1)
&& STORE_FLAG_VALUE == 1
- && INTVAL (trueop1) < (HOST_WIDE_INT)width)
+ && INTVAL (trueop1) < GET_MODE_UNIT_PRECISION (mode))
{
unsigned HOST_WIDE_INT zero_val = 0;
@@ -3446,7 +3425,7 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
goto canonicalize_shift;
case SMIN:
- if (width <= HOST_BITS_PER_WIDE_INT
+ if (HWI_COMPUTABLE_MODE_P (mode)
&& mode_signbit_p (mode, trueop1)
&& ! side_effects_p (op0))
return op1;
@@ -3458,7 +3437,7 @@ simplify_binary_operation_1 (enum rtx_code code, machine_mode mode,
break;
case SMAX:
- if (width <= HOST_BITS_PER_WIDE_INT
+ if (HWI_COMPUTABLE_MODE_P (mode)
&& CONST_INT_P (trueop1)
&& (UINTVAL (trueop1) == GET_MODE_MASK (mode) >> 1)
&& ! side_effects_p (op0))
diff --git a/gcc/stmt.c b/gcc/stmt.c
index 92bd209..410ae61 100644
--- a/gcc/stmt.c
+++ b/gcc/stmt.c
@@ -941,7 +941,7 @@ expand_case (gswitch *stmt)
original type. Make sure to drop overflow flags. */
low = fold_convert (index_type, low);
if (TREE_OVERFLOW (low))
- low = wide_int_to_tree (index_type, low);
+ low = wide_int_to_tree (index_type, wi::to_wide (low));
/* The canonical from of a case label in GIMPLE is that a simple case
has an empty CASE_HIGH. For the casesi and tablejump expanders,
@@ -950,7 +950,7 @@ expand_case (gswitch *stmt)
high = low;
high = fold_convert (index_type, high);
if (TREE_OVERFLOW (high))
- high = wide_int_to_tree (index_type, high);
+ high = wide_int_to_tree (index_type, wi::to_wide (high));
case_list.safe_push (simple_case_node (low, high, lab));
}
diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c
index a6d4307..02739b0 100644
--- a/gcc/stor-layout.c
+++ b/gcc/stor-layout.c
@@ -853,14 +853,10 @@ start_record_layout (tree t)
tree
bit_from_pos (tree offset, tree bitpos)
{
- if (TREE_CODE (offset) == PLUS_EXPR)
- offset = size_binop (PLUS_EXPR,
- fold_convert (bitsizetype, TREE_OPERAND (offset, 0)),
- fold_convert (bitsizetype, TREE_OPERAND (offset, 1)));
- else
- offset = fold_convert (bitsizetype, offset);
return size_binop (PLUS_EXPR, bitpos,
- size_binop (MULT_EXPR, offset, bitsize_unit_node));
+ size_binop (MULT_EXPR,
+ fold_convert (bitsizetype, offset),
+ bitsize_unit_node));
}
/* Return the combined truncated byte position for the byte offset OFFSET and
@@ -2366,9 +2362,11 @@ layout_type (tree type)
&& tree_int_cst_lt (ub, lb))
{
lb = wide_int_to_tree (ssizetype,
- offset_int::from (lb, SIGNED));
+ offset_int::from (wi::to_wide (lb),
+ SIGNED));
ub = wide_int_to_tree (ssizetype,
- offset_int::from (ub, SIGNED));
+ offset_int::from (wi::to_wide (ub),
+ SIGNED));
}
length
= fold_convert (sizetype,
diff --git a/gcc/substring-locations.c b/gcc/substring-locations.c
index 433023d..095e5d0 100644
--- a/gcc/substring-locations.c
+++ b/gcc/substring-locations.c
@@ -63,7 +63,7 @@ along with GCC; see the file COPYING3. If not see
printf(fmt, msg);
^~~
- For each of cases 1-3, if param_range is non-NULL, then it is used
+ For each of cases 1-3, if param_loc is not UNKNOWN_LOCATION, then it is used
as a secondary range within the warning. For example, here it
is used with case 1:
@@ -100,7 +100,7 @@ along with GCC; see the file COPYING3. If not see
ATTRIBUTE_GCC_DIAG (5,0)
bool
format_warning_va (const substring_loc &fmt_loc,
- const source_range *param_range,
+ location_t param_loc,
const char *corrected_substring,
int opt, const char *gmsgid, va_list *ap)
{
@@ -136,13 +136,8 @@ format_warning_va (const substring_loc &fmt_loc,
rich_location richloc (line_table, primary_loc);
- if (param_range)
- {
- location_t param_loc = make_location (param_range->m_start,
- param_range->m_start,
- param_range->m_finish);
- richloc.add_range (param_loc, false);
- }
+ if (param_loc != UNKNOWN_LOCATION)
+ richloc.add_range (param_loc, false);
if (!err && corrected_substring && substring_within_range)
richloc.add_fixit_replace (fmt_substring_range, corrected_substring);
@@ -171,13 +166,13 @@ format_warning_va (const substring_loc &fmt_loc,
bool
format_warning_at_substring (const substring_loc &fmt_loc,
- const source_range *param_range,
+ location_t param_loc,
const char *corrected_substring,
int opt, const char *gmsgid, ...)
{
va_list ap;
va_start (ap, gmsgid);
- bool warned = format_warning_va (fmt_loc, param_range, corrected_substring,
+ bool warned = format_warning_va (fmt_loc, param_loc, corrected_substring,
opt, gmsgid, &ap);
va_end (ap);
diff --git a/gcc/substring-locations.h b/gcc/substring-locations.h
index a91cc6c..3d7796d 100644
--- a/gcc/substring-locations.h
+++ b/gcc/substring-locations.h
@@ -77,13 +77,13 @@ class substring_loc
/* Functions for emitting a warning about a format string. */
extern bool format_warning_va (const substring_loc &fmt_loc,
- const source_range *param_range,
+ location_t param_loc,
const char *corrected_substring,
int opt, const char *gmsgid, va_list *ap)
ATTRIBUTE_GCC_DIAG (5,0);
extern bool format_warning_at_substring (const substring_loc &fmt_loc,
- const source_range *param_range,
+ location_t param_loc,
const char *corrected_substring,
int opt, const char *gmsgid, ...)
ATTRIBUTE_GCC_DIAG (5,0);
diff --git a/gcc/system.h b/gcc/system.h
index c514cd8..cd46454 100644
--- a/gcc/system.h
+++ b/gcc/system.h
@@ -720,6 +720,16 @@ extern int vsnprintf (char *, size_t, const char *, va_list);
#define __builtin_expect(a, b) (a)
#endif
+/* Some of the headers included by <memory> can use "abort" within a
+ namespace, e.g. "_VSTD::abort();", which fails after we use the
+ preprocessor to redefine "abort" as "fancy_abort" below.
+ Given that unique-ptr.h can use "free", we need to do this after "free"
+ is declared but before "abort" is overridden. */
+
+#ifdef INCLUDE_UNIQUE_PTR
+# include "unique-ptr.h"
+#endif
+
/* Redefine abort to report an internal error w/o coredump, and
reporting the location of the error in the source file. */
extern void fancy_abort (const char *, int, const char *)
@@ -915,7 +925,8 @@ extern void fancy_abort (const char *, int, const char *)
MODES_TIEABLE_P FUNCTION_ARG_PADDING SLOW_UNALIGNED_ACCESS \
HARD_REGNO_NREGS SECONDARY_MEMORY_NEEDED_MODE \
SECONDARY_MEMORY_NEEDED CANNOT_CHANGE_MODE_CLASS \
- TRULY_NOOP_TRUNCATION FUNCTION_ARG_OFFSET
+ TRULY_NOOP_TRUNCATION FUNCTION_ARG_OFFSET CONSTANT_ALIGNMENT \
+ STARTING_FRAME_OFFSET
/* Target macros only used for code built for the target, that have
moved to libgcc-tm.h or have never been present elsewhere. */
@@ -1181,4 +1192,14 @@ helper_const_non_const_cast (const char *p)
/* Get definitions of HOST_WIDE_INT. */
#include "hwint.h"
+/* qsort comparator consistency checking: except in release-checking compilers,
+ redirect 4-argument qsort calls to qsort_chk; keep 1-argument invocations
+ corresponding to vec::qsort (cmp): they use C qsort internally anyway. */
+#if CHECKING_P
+#define PP_5th(a1, a2, a3, a4, a5, ...) a5
+#undef qsort
+#define qsort(...) PP_5th (__VA_ARGS__, qsort_chk, 3, 2, qsort, 0) (__VA_ARGS__)
+void qsort_chk (void *, size_t, size_t, int (*)(const void *, const void *));
+#endif
+
#endif /* ! GCC_SYSTEM_H */
diff --git a/gcc/target-insns.def b/gcc/target-insns.def
index 4669439..75976b2 100644
--- a/gcc/target-insns.def
+++ b/gcc/target-insns.def
@@ -60,6 +60,7 @@ DEF_TARGET_INSN (jump, (rtx x0))
DEF_TARGET_INSN (load_multiple, (rtx x0, rtx x1, rtx x2))
DEF_TARGET_INSN (mem_thread_fence, (rtx x0))
DEF_TARGET_INSN (memory_barrier, (void))
+DEF_TARGET_INSN (memory_blockage, (void))
DEF_TARGET_INSN (movstr, (rtx x0, rtx x1, rtx x2))
DEF_TARGET_INSN (nonlocal_goto, (rtx x0, rtx x1, rtx x2, rtx x3))
DEF_TARGET_INSN (nonlocal_goto_receiver, (void))
diff --git a/gcc/target.def b/gcc/target.def
index f4c3576..435849c 100644
--- a/gcc/target.def
+++ b/gcc/target.def
@@ -1820,6 +1820,20 @@ misalignment value (@var{misalign}).",
int, (enum vect_cost_for_stmt type_of_cost, tree vectype, int misalign),
default_builtin_vectorization_cost)
+DEFHOOK
+(preferred_vector_alignment,
+ "This hook returns the preferred alignment in bits for accesses to\n\
+vectors of type @var{type} in vectorized code. This might be less than\n\
+or greater than the ABI-defined value returned by\n\
+@code{TARGET_VECTOR_ALIGNMENT}. It can be equal to the alignment of\n\
+a single element, in which case the vectorizer will not try to optimize\n\
+for alignment.\n\
+\n\
+The default hook returns @code{TYPE_ALIGN (@var{type})}, which is\n\
+correct for most targets.",
+ HOST_WIDE_INT, (const_tree type),
+ default_preferred_vector_alignment)
+
/* Return true if vector alignment is reachable (by peeling N
iterations) for the given scalar type. */
DEFHOOK
@@ -1833,7 +1847,7 @@ DEFHOOK
DEFHOOK
(vec_perm_const_ok,
"Return true if a vector created for @code{vec_perm_const} is valid.",
- bool, (machine_mode, const unsigned char *sel),
+ bool, (machine_mode, vec_perm_indices),
NULL)
/* Return true if the target supports misaligned store/load of a
@@ -2808,7 +2822,7 @@ DEFHOOK
"This hook should return true if @var{x} should not be emitted into\n\
debug sections.",
bool, (rtx x),
- hook_bool_rtx_false)
+ default_const_not_ok_for_debug_p)
/* Given an address RTX, say whether it is valid. */
DEFHOOK
@@ -3321,6 +3335,21 @@ HOOK_VECTOR_END (addr_space)
#undef HOOK_PREFIX
#define HOOK_PREFIX "TARGET_"
+DEFHOOK
+(constant_alignment,
+ "This hook returns the alignment in bits of a constant that is being\n\
+placed in memory. @var{constant} is the constant and @var{basic_align}\n\
+is the alignment that the object would ordinarily have.\n\
+\n\
+The default definition just returns @var{basic_align}.\n\
+\n\
+The typical use of this hook is to increase alignment for string\n\
+constants to be word aligned so that @code{strcpy} calls that copy\n\
+constants can be done inline. The function\n\
+@code{constant_alignment_word_strings} provides such a definition.",
+ HOST_WIDE_INT, (const_tree constant, HOST_WIDE_INT basic_align),
+ default_constant_alignment)
+
/* True if MODE is valid for the target. By "valid", we mean able to
be manipulated in non-trivial ways. In particular, this means all
the arithmetic is supported. */
@@ -3686,6 +3715,20 @@ registers on machines with lots of registers.",
int, (rtx address, machine_mode mode, addr_space_t as, bool speed),
default_address_cost)
+/* Compute a cost for INSN. */
+DEFHOOK
+(insn_cost,
+ "This target hook describes the relative costs of RTL instructions.\n\
+\n\
+In implementing this hook, you can use the construct\n\
+@code{COSTS_N_INSNS (@var{n})} to specify a cost equal to @var{n} fast\n\
+instructions.\n\
+\n\
+When optimizing for code size, i.e.@: when @code{speed} is\n\
+false, this target hook should be used to estimate the relative\n\
+size cost of an expression, again relative to @code{COSTS_N_INSNS}.",
+ int, (rtx_insn *insn, bool speed), NULL)
+
/* Give a cost, in RTX Costs units, for an edge. Like BRANCH_COST, but with
well defined units. */
DEFHOOK
@@ -5645,6 +5688,16 @@ five otherwise. This is best for most machines.",
unsigned int, (void),
default_case_values_threshold)
+DEFHOOK
+(starting_frame_offset,
+ "This hook returns the offset from the frame pointer to the first local\n\
+variable slot to be allocated. If @code{FRAME_GROWS_DOWNWARD}, it is the\n\
+offset to @emph{end} of the first slot allocated, otherwise it is the\n\
+offset to @emph{beginning} of the first slot allocated. The default\n\
+implementation returns 0.",
+ HOST_WIDE_INT, (void),
+ hook_hwi_void_0)
+
/* Optional callback to advise the target to compute the frame layout. */
DEFHOOK
(compute_frame_layout,
@@ -5735,6 +5788,13 @@ these registers when the target switches are opposed to them.)",
void, (void),
hook_void_void)
+DEFHOOK
+(stack_clash_protection_final_dynamic_probe,
+ "Some targets make optimistic assumptions about the state of stack probing when they emit their prologues. On such targets a probe into the end of any dynamically allocated space is likely required for safety against stack clash style attacks. Define this variable to return nonzero if such a probe is required or zero otherwise. You need not define this macro if it would always have the value zero.",
+ bool, (rtx residual),
+ default_stack_clash_protection_final_dynamic_probe)
+
+
/* Functions specific to the C family of frontends. */
#undef HOOK_PREFIX
#define HOOK_PREFIX "TARGET_C_"
diff --git a/gcc/target.h b/gcc/target.h
index 64e1d68..6260193 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -171,9 +171,11 @@ enum vect_cost_for_stmt
scalar_store,
vector_stmt,
vector_load,
+ vector_gather_load,
unaligned_load,
unaligned_store,
vector_store,
+ vector_scatter_store,
vec_to_scalar,
scalar_to_vec,
cond_branch_not_taken,
@@ -193,11 +195,11 @@ enum vect_cost_model_location {
/* The type to use for vector permutes with a constant permute vector.
Each entry is an index into the concatenated input vectors. */
-typedef vec<unsigned char> vec_perm_indices;
+typedef vec<unsigned short> vec_perm_indices;
/* Same, but can be used to construct local permute vectors that are
automatically freed. */
-typedef auto_vec<unsigned char, 32> auto_vec_perm_indices;
+typedef auto_vec<unsigned short, 32> auto_vec_perm_indices;
/* The target structure. This holds all the backend hooks. */
#define DEFHOOKPOD(NAME, DOC, TYPE, INIT) TYPE NAME;
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index 4bd4833..41cab38 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -177,6 +177,14 @@ default_legitimize_address_displacement (rtx *disp ATTRIBUTE_UNUSED,
return false;
}
+bool
+default_const_not_ok_for_debug_p (rtx x)
+{
+ if (GET_CODE (x) == UNSPEC)
+ return true;
+ return false;
+}
+
rtx
default_expand_builtin_saveregs (void)
{
@@ -245,7 +253,7 @@ default_unwind_word_mode (void)
unsigned HOST_WIDE_INT
default_shift_truncation_mask (machine_mode mode)
{
- return SHIFT_COUNT_TRUNCATED ? GET_MODE_BITSIZE (mode) - 1 : 0;
+ return SHIFT_COUNT_TRUNCATED ? GET_MODE_UNIT_BITSIZE (mode) - 1 : 0;
}
/* The default implementation of TARGET_MIN_DIVISIONS_FOR_RECIP_MUL. */
@@ -1165,6 +1173,25 @@ tree default_mangle_decl_assembler_name (tree decl ATTRIBUTE_UNUSED,
return id;
}
+/* The default implementation of TARGET_CONSTANT_ALIGNMENT. */
+
+HOST_WIDE_INT
+default_constant_alignment (const_tree, HOST_WIDE_INT align)
+{
+ return align;
+}
+
+/* An implementation of TARGET_CONSTANT_ALIGNMENT that aligns strings
+ to at least BITS_PER_WORD but otherwise makes no changes. */
+
+HOST_WIDE_INT
+constant_alignment_word_strings (const_tree exp, HOST_WIDE_INT align)
+{
+ if (TREE_CODE (exp) == STRING_CST)
+ return MAX (align, BITS_PER_WORD);
+ return align;
+}
+
/* Default to natural alignment for vector types. */
HOST_WIDE_INT
default_vector_alignment (const_tree type)
@@ -1175,6 +1202,15 @@ default_vector_alignment (const_tree type)
return align;
}
+/* The default implementation of
+ TARGET_VECTORIZE_PREFERRED_VECTOR_ALIGNMENT. */
+
+HOST_WIDE_INT
+default_preferred_vector_alignment (const_tree type)
+{
+ return TYPE_ALIGN (type);
+}
+
/* By default assume vectors of element TYPE require a multiple of the natural
alignment of TYPE. TYPE is naturally aligned if IS_PACKED is false. */
bool
@@ -2207,4 +2243,10 @@ default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED)
return FLT_EVAL_METHOD_PROMOTE_TO_FLOAT;
}
+bool
+default_stack_clash_protection_final_dynamic_probe (rtx residual ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
#include "gt-targhooks.h"
diff --git a/gcc/targhooks.h b/gcc/targhooks.h
index 6d78508..1510bb9 100644
--- a/gcc/targhooks.h
+++ b/gcc/targhooks.h
@@ -26,6 +26,7 @@ extern void default_external_libcall (rtx);
extern rtx default_legitimize_address (rtx, rtx, machine_mode);
extern bool default_legitimize_address_displacement (rtx *, rtx *,
machine_mode);
+extern bool default_const_not_ok_for_debug_p (rtx);
extern int default_unspec_may_trap_p (const_rtx, unsigned);
extern machine_mode default_promote_function_mode (const_tree, machine_mode,
@@ -93,8 +94,12 @@ extern int default_builtin_vectorization_cost (enum vect_cost_for_stmt, tree, in
extern tree default_builtin_reciprocal (tree);
+extern HOST_WIDE_INT default_constant_alignment (const_tree, HOST_WIDE_INT);
+extern HOST_WIDE_INT constant_alignment_word_strings (const_tree,
+ HOST_WIDE_INT);
extern HOST_WIDE_INT default_vector_alignment (const_tree);
+extern HOST_WIDE_INT default_preferred_vector_alignment (const_tree);
extern bool default_builtin_vector_alignment_reachable (const_tree, bool);
extern bool
default_builtin_support_vector_misalignment (machine_mode mode,
@@ -271,5 +276,6 @@ extern unsigned int default_min_arithmetic_precision (void);
extern enum flt_eval_method
default_excess_precision (enum excess_precision_type ATTRIBUTE_UNUSED);
+extern bool default_stack_clash_protection_final_dynamic_probe (rtx);
#endif /* GCC_TARGHOOKS_H */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 0114205..8dbf3b5 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,9 +1,2086 @@
-2017-09-19 Uros Bizjak <ubizjak@gmail.com>
+2017-10-24 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82460
+ * gcc.target/i386/pr82460-1.c: New test.
+ * gcc.target/i386/pr82460-2.c: New test.
+ * gcc.target/i386/avx512f-vpermt2pd-1.c: Adjust scan-assembler*
+ regexps to allow vpermt2* to vpermi2* replacement or vice versa
+ where possible.
+ * gcc.target/i386/avx512vl-vpermt2pd-1.c: Likewise.
+ * gcc.target/i386/avx512f-vpermt2d-1.c: Likewise.
+ * gcc.target/i386/vect-pack-trunc-2.c: Likewise.
+ * gcc.target/i386/avx512vl-vpermt2ps-1.c: Likewise.
+ * gcc.target/i386/avx512vl-vpermt2q-1.c: Likewise.
+ * gcc.target/i386/avx512f-vpermt2ps-1.c: Likewise.
+ * gcc.target/i386/avx512vl-vpermt2d-1.c: Likewise.
+ * gcc.target/i386/avx512bw-vpermt2w-1.c: Likewise.
+ * gcc.target/i386/avx512vbmi-vpermt2b-1.c: Likewise.
+ * gcc.target/i386/avx512f-vpermt2q-1.c: Likewise.
+
+ PR target/82370
+ * gcc.target/i386/pr82370.c: New test.
+
+2017-10-24 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82466
+ * c-c++-common/Wbuiltin-declaration-mismatch-1.c: New.
+ * c-c++-common/Wno-builtin-declaration-mismatch-1.c: Likewise.
+ * g++.dg/warn/Wbuiltin_declaration_mismatch-1.C: Likewise.
+ * g++.dg/parse/builtin2.C: Adjust.
+ * g++.old-deja/g++.mike/p811.C: Likewise.
+
+2017-10-24 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80991
+ * g++.dg/ext/is_trivially_constructible5.C: New.
+
+2017-10-24 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * gcc.target/i386/387-ficom-1.c: Allow for ficomp without s
+ suffix.
+ * gcc.target/i386/387-ficom-2.c: Likewise.
+
+2017-10-24 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * gcc.target/i386/cet-sjlj-3.c: Allow for emtpy user label prefix
+ in setjmp call.
+
+2017-10-24 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82697
+ * gcc.dg/torture/pr82697.c: New testcase.
+
+2017-10-24 Mukesh Kapoor <mukesh.kapoor@oracle.com>
+ Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82307
+ * g++.dg/cpp0x/enum35.C: New.
+ * g++.dg/cpp0x/enum36.C: Likewise.
+
+2017-10-24 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/82659
+ * gcc.target/i386/cet-label-2.c: New test.
+ * gcc.target/i386/cet-sjlj-4.c: Likewise.
+ * gcc.target/i386/cet-sjlj-5.c: Likewise.
+ * gcc.target/i386/cet-switch-3.c: Likewise.
+ * gcc.target/i386/pr82659-1.c: Likewise.
+ * gcc.target/i386/pr82659-2.c: Likewise.
+ * gcc.target/i386/pr82659-3.c: Likewise.
+ * gcc.target/i386/pr82659-4.c: Likewise.
+ * gcc.target/i386/pr82659-5.c: Likewise.
+ * gcc.target/i386/pr82659-6.c: Likewise.
+
+2017-10-23 Sandra Loosemore <sandra@codesourcery.com>
+
+ * gcc.target/nios2/cdx-branch.c: Fix broken test.
+ * gcc.target/nios2/lo-addr-bypass.c: New.
+ * gcc.target/nios2/lo-addr-char.c: New.
+ * gcc.target/nios2/lo-addr-int.c: New.
+ * gcc.target/nios2/lo-addr-pic.c: New.
+ * gcc.target/nios2/lo-addr-short.c: New.
+ * gcc.target/nios2/lo-addr-tls.c: New.
+ * gcc.target/nios2/lo-addr-uchar.c: New.
+ * gcc.target/nios2/lo-addr-ushort.c: New.
+ * gcc.target/nios2/lo-addr-volatile.c: New.
+
+2017-10-23 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80449
+ * g++.dg/cpp1z/class-deduction46.C: New.
+
+2017-10-23 Jakub Jelinek <jakub@redhat.com>
+
+ PR debug/82630
+ * g++.dg/guality/pr82630.C: New test.
+
+2017-10-23 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/82662
+ * gcc.target/i386/pr82662.c: New test.
+
+2017-10-23 Marek Polacek <polacek@redhat.com>
+
+ PR c/82681
+ * gcc.dg/c90-const-expr-11.c: Fix typos in dg-warning.
+ * gcc.dg/overflow-warn-5.c: Likewise.
+ * gcc.dg/overflow-warn-8.c: Likewise.
+
+2017-10-23 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/82673
+ * gcc.target/i386/pr82673.c: New test.
+
+2017-10-23 Jakub Jelinek <jakub@redhat.com>
+
+ * lib/scanasm.exp (dg-function-on-line): Accept optional column info.
+ * gcc.dg/debug/dwarf2/pr53948.c: Likewise.
+ * g++.dg/debug/dwarf2/pr77363.C: Likewise.
+ * gcc.dg/debug/dwarf2/asm-line1.c: Add -gno-column-info to dg-options.
+ * gcc.dg/debug/dwarf2/discriminator.c: Likewise.
+ * g++.dg/debug/dwarf2/typedef6.C: Likewise.
+
+2017-10-23 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82672
+ * gfortran.dg/graphite/pr82672.f90: New testcase.
+
+2017-10-23 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/77555
+ * g++.dg/torture/pr77555.C: New.
+
+2017-10-23 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82129
+ * gcc.dg/torture/pr82129.c: New testcase.
+
+2017-10-22 Uros Bizjak <ubizjak@gmail.com>
+
+ PR target/52451
+ * gcc.dg/torture/pr52451.c: New test.
+
+2017-10-22 Uros Bizjak <ubizjak@gmail.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82628
+ * gcc.dg/torture/pr82628.c: New test.
+
+2017-10-22 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
+
+ * c-c++-common/attr-nocf-check-1a.c: Remove test.
+ * c-c++-common/attr-nocf-check-3a.c: Likewise.
+ * gcc.target/i386/attr-nocf-check-1a.c: Add test.
+ * gcc.target/i386/attr-nocf-check-3a.c: Likewise.
+
+2017-10-21 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
+
+ * c-c++-common/attr-nocf-check-1.c: Shorten a cheking message.
+ * c-c++-common/attr-nocf-check-3.c: Likewise.
+ * c-c++-common/fcf-protection-1.c: Add x86 specific message.
+ * c-c++-common/fcf-protection-2.c: Likewise.
+ * c-c++-common/fcf-protection-3.c: Likewise.
+ * c-c++-common/fcf-protection-5.c: Likewise.
+ * c-c++-common/attr-nocf-check-1a.c: New test.
+ * c-c++-common/attr-nocf-check-3a.c: Likewise.
+ * g++.dg/cet-notrack-1.C: Likewise.
+ * gcc.target/i386/cet-intrin-1.c: Likewise.
+ * gcc.target/i386/cet-intrin-10.c: Likewise.
+ * gcc.target/i386/cet-intrin-2.c: Likewise.
+ * gcc.target/i386/cet-intrin-3.c: Likewise.
+ * gcc.target/i386/cet-intrin-4.c: Likewise.
+ * gcc.target/i386/cet-intrin-5.c: Likewise.
+ * gcc.target/i386/cet-intrin-6.c: Likewise.
+ * gcc.target/i386/cet-intrin-7.c: Likewise.
+ * gcc.target/i386/cet-intrin-8.c: Likewise.
+ * gcc.target/i386/cet-intrin-9.c: Likewise.
+ * gcc.target/i386/cet-label.c: Likewise.
+ * gcc.target/i386/cet-notrack-1a.c: Likewise.
+ * gcc.target/i386/cet-notrack-1b.c: Likewise.
+ * gcc.target/i386/cet-notrack-2a.c: Likewise.
+ * gcc.target/i386/cet-notrack-2b.c: Likewise.
+ * gcc.target/i386/cet-notrack-3.c: Likewise.
+ * gcc.target/i386/cet-notrack-4a.c: Likewise.
+ * gcc.target/i386/cet-notrack-4b.c: Likewise.
+ * gcc.target/i386/cet-notrack-5a.c: Likewise.
+ * gcc.target/i386/cet-notrack-5b.c: Likewise.
+ * gcc.target/i386/cet-notrack-6a.c: Likewise.
+ * gcc.target/i386/cet-notrack-6b.c: Likewise.
+ * gcc.target/i386/cet-notrack-7.c: Likewise.
+ * gcc.target/i386/cet-property-1.c: Likewise.
+ * gcc.target/i386/cet-property-2.c: Likewise.
+ * gcc.target/i386/cet-rdssp-1.c: Likewise.
+ * gcc.target/i386/cet-sjlj-1.c: Likewise.
+ * gcc.target/i386/cet-sjlj-2.c: Likewise.
+ * gcc.target/i386/cet-sjlj-3.c: Likewise.
+ * gcc.target/i386/cet-switch-1.c: Likewise.
+ * gcc.target/i386/cet-switch-2.c: Likewise.
+ * lib/target-supports.exp (check_effective_target_cet): New proc.
+
+2017-10-20 Jan Hubicka <hubicka@ucw.cz>
+
+ * gcc.target/i386/pr79683.c: Disable costmodel.
+
+2017-10-21 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/specs/discr_private.ads: Rename into ...
+ * gnat.dg/specs/discr2.ads: ...this.
+ * gnat.dg/specs/discr_record_constant.ads: Rename into...
+ * gnat.dg/specs/discr3.ads: ...this.
+ * gnat.dg/specs/discr4.ads: New test.
+ * gnat.dg/specs/discr4_pkg.ads: New helper.
+
+2017-10-21 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82586
+ * gfortran.dg/pdt_16.f03 : New test.
+ * gfortran.dg/pdt_4.f03 : Catch the changed messages.
+ * gfortran.dg/pdt_8.f03 : Ditto.
+
+ PR fortran/82587
+ * gfortran.dg/pdt_17.f03 : New test.
+
+ PR fortran/82589
+ * gfortran.dg/pdt_18.f03 : New test.
+
+2017-10-20 Igor Tsimbalist <igor.v.tsimbalist@intel.com>
+
+ * c-c++-common/fcf-protection-1.c: New test.
+ * c-c++-common/fcf-protection-2.c: Likewise.
+ * c-c++-common/fcf-protection-3.c: Likewise.
+ * c-c++-common/fcf-protection-4.c: Likewise.
+ * c-c++-common/fcf-protection-5.c: Likewise.
+ * c-c++-common/attr-nocf-check-1.c: Likewise.
+ * c-c++-common/attr-nocf-check-2.c: Likewise.
+ * c-c++-common/attr-nocf-check-3.c: Likewise.
+
+2017-10-20 Ed Schonberg <schonberg@adacore.com>
+
+ * gnat.dg/sync_iface_call.adb, gnat.dg/sync_iface_call_pkg.ads,
+ gnat.dg/sync_iface_call_pkg2.adb, gnat.dg/sync_iface_call_pkg2.ads:
+ New testcase.
+
+2017-10-20 Justin Squirek <squirek@adacore.com>
+
+ * gnat.dg/default_pkg_actual.adb, gnat.dg/default_pkg_actual2.adb: New
+ testcases.
+
+2017-10-20 Ed Schonberg <schonberg@adacore.com>
+
+ * gnat.dg/dimensions.adb, gnat.dg/dimensions.ads: New testcase.
+
+2017-10-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82473
+ * gcc.dg/torture/pr82473.c: New testcase.
+
+2017-10-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82603
+ * gcc.dg/torture/pr82603.c: New testcase.
+
+2017-10-20 Tom de Vries <tom@codesourcery.com>
+
+ * gcc.dg/tree-ssa/ldist-27.c: Remove dg-require-stack-size.
+ (main): Move s ...
+ (s): ... here.
+
+2017-10-20 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82158
+ * gcc.dg/tree-ssa/noreturn-1.c: New test.
+
+ PR target/82370
+ * gcc.target/i386/avx-pr82370.c: New test.
+ * gcc.target/i386/avx2-pr82370.c: New test.
+ * gcc.target/i386/avx512f-pr82370.c: New test.
+ * gcc.target/i386/avx512bw-pr82370.c: New test.
+ * gcc.target/i386/avx512vl-pr82370.c: New test.
+ * gcc.target/i386/avx512vlbw-pr82370.c: New test.
+
+2017-10-20 Orlando Arias <oarias@knights.ucf.edu>
+
+ * lib/target-supports.exp (check_effective_target_keeps_null_pointer_checks):
+ Add msp430 to the list.
+
+2017-10-19 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82308
+ * g++.dg/cpp1z/class-deduction45.C: New.
+
+2017-10-19 Uros Bizjak <ubizjak@gmail.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82618
+ * gcc.target/i386/pr82618.c: New test.
+
+2017-10-19 Martin Sebor <msebor@redhat.com>
+
+ PR tree-optimization/82596
+ * gcc/testsuite/gcc.dg/pr82596.c: New test.
+
+2017-10-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc.dg/Walloca-15.c: New test.
+ * gnat.dg/stack_usage4.adb: Likewise.
+ * gnat.dg/stack_usage4_pkg.ads: New helper.
+
+2017-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82600
+ * g++.dg/warn/Wreturn-local-addr-4.C: New test.
+
+2017-10-19 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc.dg/debug/dwarf2/sso.c: Rename into...
+ * gcc.dg/debug/dwarf2/sso-1.c: ...this.
+ * gcc.dg/debug/dwarf2/sso-2.c: New test.
+ * gcc.dg/debug/dwarf2/sso-3.c: Likewise.
+
+2017-10-19 Richard Earnshaw <rearnsha@arm.com>
+
+ PR target/82445
+ * gcc.target/arm/peep-ldrd-1.c: Tighten test scan pattern.
+ * gcc.target/arm/peep-strd-1.c: Likewise.
+ * gcc.target/arm/peep-ldrd-2.c: New test.
+ * gcc.target/arm/peep-strd-2.c: New test.
+
+2017-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ * c-c++-common/ubsan/builtin-1.c: New test.
+
+ * c-c++-common/ubsan/float-cast-overflow-1.c: Drop value keyword
+ from expected output regexps.
+ * c-c++-common/ubsan/float-cast-overflow-2.c: Likewise.
+ * c-c++-common/ubsan/float-cast-overflow-3.c: Likewise.
+ * c-c++-common/ubsan/float-cast-overflow-4.c: Likewise.
+ * c-c++-common/ubsan/float-cast-overflow-5.c: Likewise.
+ * c-c++-common/ubsan/float-cast-overflow-6.c: Likewise.
+ * c-c++-common/ubsan/float-cast-overflow-8.c: Likewise.
+ * c-c++-common/ubsan/float-cast-overflow-9.c: Likewise.
+ * c-c++-common/ubsan/float-cast-overflow-10.c: Likewise.
+ * g++.dg/ubsan/float-cast-overflow-bf.C: Likewise.
+ * gcc.dg/ubsan/float-cast-overflow-bf.c: Likewise.
+ * g++.dg/asan/default-options-1.C (__asan_default_options): Add
+ used attribute.
+ * g++.dg/asan/asan_test.C: Run with ASAN_OPTIONS=handle_segv=2
+ in the environment.
+
+ PR target/82580
+ * gcc.target/i386/pr82580.c: Use {\msbb} instead of "sbb" in
+ scan-assembler-times. Check that there are no movzb* instructions
+ if lp64.
+
+2017-10-19 Tom de Vries <tom@codesourcery.com>
+
+ * gcc.dg/tree-ssa/ldist-27.c: Use dg-require-stack-size.
+
+2017-10-19 Tom de Vries <tom@codesourcery.com>
+
+ * lib/target-supports-dg.exp (dg-require-stack-size): New proc.
+ * gcc.c-torture/execute/20030209-1.c: Use dg-require-stack-size.
+ * gcc.c-torture/execute/20040805-1.c: Same.
+ * gcc.c-torture/execute/920410-1.c: Same.
+ * gcc.c-torture/execute/921113-1.c: Same.
+ * gcc.c-torture/execute/921208-2.c: Same.
+ * gcc.c-torture/execute/comp-goto-1.c: Same.
+ * gcc.c-torture/execute/pr20621-1.c: Same.
+ * gcc.c-torture/execute/pr28982b.c: Same.
+ * gcc.dg/tree-prof/comp-goto-1.c: Same.
+
+2017-10-19 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82517
+ * gcc.dg/asan/pr82517.c: New test.
+
+2017-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ PR fortran/82568
+ * gfortran.dg/gomp/pr82568.f90: New test.
+
+2017-10-19 Bernhard Reutner-Fischer <aldot@gcc.gnu.org>
+
+ * gfortran.dg/spellcheck-operator.f90: New testcase.
+ * gfortran.dg/spellcheck-procedure_1.f90: New testcase.
+ * gfortran.dg/spellcheck-procedure_2.f90: New testcase.
+ * gfortran.dg/spellcheck-structure.f90: New testcase.
+ * gfortran.dg/spellcheck-parameter.f90: New testcase.
+
+2017-10-18 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/82567
+ * gfortran.dg/array_constructor_51.f90: New test.
+
+2017-10-18 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/79795
+ * gfortran.dg/assumed_size_2.f90: New test.
+
+2017-10-18 Uros Bizjak <ubizjak@gmail.com>
+ Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82580
+ * gcc.target/i386/pr82580.c: New test.
+
+2017-10-18 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR libfortran/82233
+ * gfortran.dg/execute_command_line_3.f90: Remove unneeded output.
+ Move test with wait=.false. before the last test.
+
+2017-10-18 Vladimir Makarov <vmakarov@redhat.com>
+
+ PR middle-end/82556
+ * gcc.target/i386/pr82556.c: New.
+
+2017-10-18 Bin Cheng <bin.cheng@arm.com>
+
+ * gcc.dg/tree-ssa/ldist-17.c: Adjust test string.
+ * gcc.dg/tree-ssa/ldist-32.c: New test.
+ * gcc.dg/tree-ssa/ldist-35.c: New test.
+ * gcc.dg/tree-ssa/ldist-36.c: New test.
+
+2017-10-18 Bin Cheng <bin.cheng@arm.com>
+
+ PR tree-optimization/82574
+ * gcc.dg/tree-ssa/pr82574.c: New test.
+
+2017-10-18 Martin Liska <mliska@suse.cz>
+
+ * gcc.dg/tree-prof/switch-case-2.c: Scan IPA profile dump
+ file instead of expand. Reason is that switch statement is
+ not yet expanded as decision tree, which also contains a BB
+ with count == 2000.
+
+017-10-18 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82550
+ * gfortran.dg/submodule_30.f08 : New test.
+
+2017-10-18 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * gcc.target/s390/zvector/vec-cmp-2.c
+ (all_eq_double, all_ne_double, all_gt_double)
+ (all_lt_double, all_ge_double, all_le_double)
+ (any_eq_double, any_ne_double, any_gt_double)
+ (any_lt_double, any_ge_double, any_le_double)
+ (all_eq_int, all_ne_int, all_gt_int)
+ (all_lt_int, all_ge_int, all_le_int)
+ (any_eq_int, any_ne_int, any_gt_int)
+ (any_lt_int, any_ge_int, any_le_int): Set global variable instead
+ of calling foo(). Fix return type.
+
+2017-10-18 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82545
+ * gcc.dg/asan/pr82545.c: New test.
+
+2017-10-18 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/69057
+ * g++.dg/cpp1y/auto-fn45.C: New.
+
+2017-10-18 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/68884
+ * g++.dg/cpp0x/variadic-crash4.C: New.
+
+2017-10-18 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/79474
+ * g++.dg/cpp1y/auto-fn44.C: New.
+
+2017-10-17 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc.dg/attr-alloc_size-11.c: UnXFAIL for visium-*-*.
+
+2017-10-17 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/71821
+ * g++.dg/cpp0x/alignas12.C: New.
+
+2017-10-17 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/71368
+ * g++.dg/concepts/pr71368.C: New.
+
+2017-10-17 Nathan Sidwell <nathan@acm.org>
+
+ PR c++/82560
+ * g++.dg/cpp0x/pr82560.C: New.
+
+ PR middle-end/82577
+ * g++.dg/opt/pr82577.C: New.
+
+2017-10-17 Qing Zhao <qing.zhao@oracle.com>
+ Wilco Dijkstra <wilco.dijkstra@arm.com>
+
+ PR middle-end/80295
+ * gcc.target/aarch64/pr80295.c: New test.
+
+2017-10-17 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82563
+ * gcc.dg/graphite/pr82563.c: New testcase.
+
+2017-10-17 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/67831
+ * g++.dg/cpp0x/constexpr-ice18.C: New.
+
+2017-10-17 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82570
+ * g++.dg/cpp1z/constexpr-lambda18.C: New.
+
+2017-10-17 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/82549
+ * gcc.c-torture/compile/pr82549.c: New test.
+
+2017-10-17 Martin Liska <mliska@suse.cz>
+
+ * lib/scanasm.exp: Print how many times a regex pattern is
+ found.
+ * lib/scandump.exp: Likewise.
+
+2017-10-17 Olga Makhotina <olga.makhotina@intel.com>
+
+ * gcc.target/i386/avx512dq-vreducesd-1.c (_mm_mask_reduce_sd,
+ _mm_maskz_reduce_sd): Test new intrinsics.
+ * gcc.target/i386/avx512dq-vreducesd-2.c: New.
+ * gcc.target/i386/avx512dq-vreducess-1.c (_mm_mask_reduce_ss,
+ _mm_maskz_reduce_ss): Test new intrinsics.
+ * gcc.target/i386/avx512dq-vreducess-2.c: New.
+ * gcc.target/i386/avx-1.c (__builtin_ia32_reducesd,
+ __builtin_ia32_reducess): Remove builtin.
+ (__builtin_ia32_reducesd_mask,
+ __builtin_ia32_reducess_mask): Test new builtin.
+ * gcc.target/i386/sse-13.c: Ditto.
+ * gcc.target/i386/sse-23.c: Ditto.
+
+2017-10-16 Martin Liska <mliska@suse.cz>
+
+ * c-c++-common/ubsan/attrib-5.c (float_cast2): Fix warning scan
+ so that it will work for both C and C++ FEs.
+
+2017-10-16 Fritz Reese <fritzoreese@gmail.com>
+
+ PR fortran/82511
+ * gfortran.dg/dec_structure_22.f90: New testcase.
+
+2017-10-16 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/64931
+ * g++.dg/cpp1y/auto-fn43.C: New.
+
+2017-10-16 Wilco Dijkstra <wdijkstr@arm.com>
+
+ PR target/82442
+ * gcc.dg/vect/pr31699.c: Fix testcase.
+
+2017-10-16 Tamar Christina <tamar.christina@arm.com>
+
+ * gcc.target/aarch64/advsimd-intrinsics/vect-dot-qi.h: New.
+ * gcc.target/aarch64/advsimd-intrinsics/vdot-compile.c: New.
+ * gcc.target/aarch64/advsimd-intrinsics/vect-dot-s8.c: New.
+ * gcc.target/aarch64/advsimd-intrinsics/vect-dot-u8.c: New.
+
+2017-10-16 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/53574
+ * g++.dg/other/pr53574.C: New test.
+
+2017-10-16 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/61323
+ * g++.dg/cpp0x/constexpr-61323.C: New.
+
+2017-10-15 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/54090
+ * g++.dg/template/crash128.C: New.
+
+2017-10-15 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/82372
+ * gfortran.dg/illegal_char.f90: New test.
+
+2017-10-14 Kyrylo Tkachov <kyrylo.tkachov@arm.com>
+ Michael Collison <michael.collison@arm.com>
+
+ * gcc.target/aarch64/cmpelim_mult_uses_1.c: New test.
+
+2017-10-14 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80908
+ * g++.dg/cpp1z/noexcept-type18.C: New.
+
+2017-10-14 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/81016
+ * g++.dg/cpp1z/pr81016.C: New.
+
+2017-10-14 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/62263
+ PR middle-end/82498
+ * c-c++-common/rotate-8.c: Expect no PHIs in optimized dump.
+
+ PR middle-end/62263
+ PR middle-end/82498
+ * c-c++-common/rotate-5.c (f2): New function. Move old
+ function to ...
+ (f4): ... this. Use 127 instead of 128.
+ (f3, f5, f6): New functions.
+ (main): Test all f[1-6] functions, with both 0 and 1 as
+ second arguments.
+ * c-c++-common/rotate-6.c: New test.
+ * c-c++-common/rotate-6a.c: New test.
+ * c-c++-common/rotate-7.c: New test.
+ * c-c++-common/rotate-7a.c: New test.
+ * c-c++-common/rotate-8.c: New test.
+
+2017-10-14 Hristian Kirtchev <kirtchev@adacore.com>
+
+ * gnat.dg/remote_call_iface.ads, gnat.dg/remote_call_iface.adb: New
+ testcase.
+
+2017-10-14 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/81423
+ * gcc.c-torture/execute/pr81423.c (foo): Add missing cast. Change L
+ suffixes to LL.
+ (main): Punt if either long long isn't 64-bit or int isn't 32-bit.
+
+2017-10-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/82353
+ * g++.dg/ubsan/pr82353-2.C: New test.
+ * g++.dg/ubsan/pr82353-2-aux.cc: New file.
+ * g++.dg/ubsan/pr82353-2.h: New file.
+
+2017-10-13 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/81048
+ * gfortran.dg/derived_init_4.f90 : New test.
+
+2017-10-13 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/69078
+ * g++.dg/cpp1y/lambda-generic-69078-1.C: New.
+ * g++.dg/cpp1y/lambda-generic-69078-2.C: Likewise.
+
+2017-10-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82274
+ * gcc.dg/pr82274-1.c: New test.
+ * gcc.dg/pr82274-2.c: New test.
+
+2017-10-13 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80873
+ * g++.dg/cpp1y/auto-fn41.C: New.
+ * g++.dg/cpp1y/auto-fn42.C: Likewise.
+
+2017-10-13 David Malcolm <dmalcolm@redhat.com>
+
+ * g++.dg/cpp0x/udlit-extern-c.C: New test case.
+ * g++.dg/diagnostic/unclosed-extern-c.C: Add example of a template
+ erroneously covered by an unclosed extern "C".
+ * g++.dg/template/extern-c.C: New test case.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/graphite/pr35356-3.c: XFAIL again.
+ * gcc.dg/graphite/pr81373-2.c: Copy from gcc.dg/graphite/pr81373.c
+ with alternate flags.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/graphite/scop-10.c: Enlarge array to avoid undefined
+ behavior.
+ * gcc.dg/graphite/scop-7.c: Likewise.
+ * gcc.dg/graphite/scop-8.c: Likewise.
+
+2017-10-13 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/82499
+ * gcc.target/i386/pr82499-1.c: New file.
+ * gcc.target/i386/pr82499-2.c: Likewise.
+ * gcc.target/i386/pr82499-3.c: Likewise.
+
+2017-10-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82524
+ * gcc.c-torture/execute/pr82524.c: New test.
+
+ PR target/82498
+ * gcc.dg/tree-ssa/pr82498.c: New test.
+
+ PR target/82498
+ * gcc.dg/ubsan/pr82498.c: New test.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82451
+ * gcc.dg/graphite/pr82451.c: New testcase.
+ * gfortran.dg/graphite/id-27.f90: Likewise.
+ * gfortran.dg/graphite/pr82451.f: Likewise.
+
+2017-10-13 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82525
+ * gcc.dg/graphite/id-30.c: New testcase.
+ * gfortran.dg/graphite/id-28.f90: Likewise.
+
+2017-10-13 Alan Modra <amodra@gmail.com>
+
+ * gcc.target/i386/asm-mem.c: New test.
+
+2017-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82498
+ * gcc.target/i386/pr82498-1.c: New test.
+ * gcc.target/i386/pr82498-2.c: New test.
+
+2017-10-12 Jan Hubicka <hubicka@ucw.cz>
+
+ * gcc.dg/predict-13.c: Update template for probaility change.
+ * gcc.dg/predict-8.c: Likewise.
+
+2017-10-12 David Malcolm <dmalcolm@redhat.com>
+
+ * c-c++-common/cilk-plus/AN/parser_errors.c: Update expected
+ output to reflect changes to reported locations of missing
+ symbols.
+ * c-c++-common/cilk-plus/AN/parser_errors2.c: Likewise.
+ * c-c++-common/cilk-plus/AN/parser_errors3.c: Likewise.
+ * c-c++-common/cilk-plus/AN/pr61191.c: Likewise.
+ * c-c++-common/gomp/pr63326.c: Likewise.
+ * c-c++-common/missing-close-symbol.c: Likewise, also update for
+ new fix-it hints.
+ * c-c++-common/missing-symbol.c: Likewise, also add test coverage
+ for missing colon in ternary operator.
+ * g++.dg/cpp1y/digit-sep-neg.C: Likewise.
+ * g++.dg/cpp1y/pr65202.C: Likewise.
+ * g++.dg/missing-symbol-2.C: New test case.
+ * g++.dg/other/do1.C: Update expected output to reflect
+ changes to reported locations of missing symbols.
+ * g++.dg/parse/error11.C: Likewise.
+ * g++.dg/template/error11.C: Likewise.
+ * gcc.dg/missing-symbol-2.c: New test case.
+ * gcc.dg/missing-symbol-3.c: New test case.
+ * gcc.dg/noncompile/940112-1.c: Update expected output to reflect
+ changes to reported locations of missing symbols.
+ * gcc.dg/noncompile/971104-1.c: Likewise.
+ * obj-c++.dg/exceptions-6.mm: Likewise.
+ * obj-c++.dg/pr48187.mm: Likewise.
+ * objc.dg/exceptions-6.m: Likewise.
+
+2017-10-12 Martin Sebor <msebor@redhat.com>
+
+ PR other/82301
+ PR c/82435
+ * g++.dg/ext/attr-ifunc-1.C: Update.
+ * g++.dg/ext/attr-ifunc-2.C: Same.
+ * g++.dg/ext/attr-ifunc-3.C: Same.
+ * g++.dg/ext/attr-ifunc-4.C: Same.
+ * g++.dg/ext/attr-ifunc-5.C: Same.
+ * g++.dg/ext/attr-ifunc-6.C: New test.
+ * g++.old-deja/g++.abi/vtable2.C: Update.
+ * gcc.dg/attr-ifunc-6.c: New test.
+ * gcc.dg/attr-ifunc-7.c: New test.
+ * gcc.dg/pr81854.c: Update.
+ * lib/target-supports.exp: Update.
+
+2017-10-12 David Malcolm <dmalcolm@redhat.com>
+
+ * g++.dg/parse/pragma2.C: Update to reflect reinstatement of the
+ "#pragma is not allowed here" error.
+
+2017-10-12 Bin Cheng <bin.cheng@arm.com>
+
+ * gcc.dg/tree-ssa/ldist-28.c: New test.
+ * gcc.dg/tree-ssa/ldist-29.c: New test.
+ * gcc.dg/tree-ssa/ldist-30.c: New test.
+ * gcc.dg/tree-ssa/ldist-31.c: New test.
+
+2017-10-12 Bin Cheng <bin.cheng@arm.com>
+
+ * gcc.dg/tree-ssa/ldist-7.c: Adjust test string.
+ * gcc.dg/tree-ssa/ldist-16.c: Ditto.
+ * gcc.dg/tree-ssa/ldist-25.c: Ditto.
+ * gcc.dg/tree-ssa/ldist-33.c: New test.
+
+2017-10-12 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/69728
+ * gcc.dg/graphite/pr69728.c: Adjust to reflect we can handle
+ the loop now. Remove unrelated undefined behavior.
+
+2017-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82159
+ * g++.dg/opt/pr82159-2.C: New test.
+
+ PR target/82353
+ * gcc.target/i386/i386.exp (tests): Revert the '.C' extension change.
+ * gcc.target/i386/pr82353.C: Moved to ...
+ * g++.dg/ubsan/pr82353.C: ... here. Restrict to i?86/x86_64 && lp64.
+
+2017-10-11 Uros Bizjak <ubizjak@gmail.com>
+
+ * gcc.target/i386/387-ficom-2.c: New test.
+
+2017-10-11 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/80421
+ * gcc.c-torture/execute/pr80421.c: New test.
+
+ PR tree-optimization/78558
+ * gcc.dg/vect/pr78558.c: New test.
+
+ PR c++/82414
+ * g++.dg/lto/pr82414_0.C: New test.
+
+ PR c++/78523
+ * g++.dg/cpp1y/pr78523.C: New test.
+
+ PR c++/80194
+ * g++.dg/cpp1y/pr80194.C: New test.
+
+2017-10-11 Qing Zhao <qing.zhao@oracle.com>
+
+ PR target/81422
+ * gcc.target/aarch64/pr81422.C: New test.
+
+2017-10-11 Vladimir Makarov <vmakarov@redhat.com>
+
+ PR sanitizer/82353
+ * gcc.target/i386/i386.exp (tests): Permit '.C' extension.
+ * gcc.target/i386/pr82353.C: New.
+
+2017-10-11 Uros Bizjak <ubizjak@gmail.com>
+
+ * gcc.target/i386/387-ficom-1.c: New test.
+
+2017-10-11 Jeff Law <law@redhat.com>
+
+ * gcc.dg/struct-layout-1_generate.c (generate_fields): Fix typo in
+ address computation of end of complex_attrib_array_types.
+
+2017-10-11 Marc Glisse <marc.glisse@inria.fr>
+
+ * gcc.dg/Wstrict-overflow-7.c: Xfail.
+ * gcc.dg/pragma-diag-3.c: Likewise.
+
+2017-10-11 Bin Cheng <bin.cheng@arm.com>
+
+ PR tree-optimization/82472
+ * gcc.dg/tree-ssa/pr82472.c: New test.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82490
+ * c-c++-common/ubsan/attrib-5.c: New test.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ Revert r253637:
+
+ PR sanitizer/82484
+ * gcc.dg/asan/pr82484.c: New test.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ PR sanitizer/82484
+ * gcc.dg/asan/pr82484.c: New test.
+
+2017-10-11 Martin Liska <mliska@suse.cz>
+
+ * c-c++-common/ubsan/ptr-overflow-sanitization-1.c: Scan
+ optimized dump rather than assembly.
+
+2017-10-11 Nathan Sidwell <nathan@acm.org>
+
+ * g++.dg/cpp/string-3.C: Fix dg-final.
+
+2017-10-11 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80412
+ * g++.dg/cpp1z/class-deduction44.C: New.
+
+2017-10-11 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/82230
+ * g++.dg/cpp1y/lambda-generic-ice8.C: New.
+
+2017-10-11 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/81299
+ * g++.dg/cpp1y/lambda-generic-ice7.C: New.
+
+2017-10-10 Nathan Sidwell <nathan@acm.org>
+
+ * g++.dg/lookup/extern-c-redecl6.C: New.
+ * g++.dg/lookup/extern-c-hidden.C: Adjust diagnostics.
+ * g++.dg/lookup/extern-c-redecl.C: Likewise.
+ * g++.old-deja/g++.other/using9.C: Likewise.
+
+2017-10-10 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/78006
+ * g++.dg/cpp1y/auto-fn40.C: New.
+
+2017-10-10 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/81032
+ * g++.dg/cpp1y/lambda-generic-ice6.C: New.
+
+2017-10-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR rtl-optimization/68205
+ * gcc.c-torture/execute/20040709-3.c: New test.
+
+ PR c++/67625
+ * g++.dg/cpp0x/pr67625.C: New test.
+
+ PR middle-end/70887
+ * g++.dg/cpp0x/pr70887.C: New test.
+
+ PR c++/70338
+ * g++.dg/cpp0x/pr70338.C: New test.
+
+ PR c++/77786
+ * g++.dg/cpp1y/pr77786.C: New test.
+
+ PR c++/71875
+ * g++.dg/cpp1y/pr71875.C: New test.
+
+ PR c++/77578
+ * g++.dg/gomp/pr77578.C: New test.
+
+ PR middle-end/70100
+ * g++.dg/opt/pr70100.C: New test.
+
+ PR c++/68252
+ * g++.dg/other/pr68252.C: New test.
+
+ PR target/79565
+ PR target/82483
+ * gcc.target/i386/pr82483-1.c: New test.
+ * gcc.target/i386/pr82483-2.c: New test.
+
+2017-10-10 Will Schmidt <will_schmidt@vnet.ibm.com>
+
+ * gcc.target/powerpc/fold-vec-mult-int128-p8.c: Update options
+ * gcc.target/powerpc/fold-vec-mult-int128-p9.c: Update expected
+ instruction list.
+
+2017-10-10 Nathan Sidwell <nathan@acm.org>
+
+ PR preprocessor/82506
+ * g++.dg/cpp/string-3.C: New.
+
+2017-10-10 Will Schmidt <will_schmidt@vnet.ibm.com>
+
+ * gcc.target/powerpc/fold-vec-splat-16.c: New
+ * gcc.target/powerpc/fold-vec-splat-32.c: New.
+ * gcc.target/powerpc/fold-vec-splat-8.c: New.
+
+2017-10-10 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR libfortran/82233
+ * gfortran.dg/execute_command_line_3.f90: New test.
+
+2017-10-10 Will Schmidt <will_schmidt@vnet.ibm.com>
+
+ * gcc.target/powerpc/fold-vec-splat-16.c: New
+ * gcc.target/powerpc/fold-vec-splat-32.c: New.
+ * gcc.target/powerpc/fold-vec-splat-8.c: New.
+
+2017-10-10 Will Schmidt <will_schmidt@vnet.ibm.com>
+
+ * gcc.target/powerpc/fold-vec-splats-char.c: New.
+ * gcc.target/powerpc/fold-vec-splats-floatdouble.c: New.
+ * gcc.target/powerpc/fold-vec-splats-int.c: New.
+ * gcc.target/powerpc/fold-vec-splats-longlong.c: New.
+ * gcc.target/powerpc/fold-vec-splats-short.c: New.
+
+2017-10-10 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/82437
+ * c-c++-common/Wtautological-compare-7.c: New test.
+
+2017-10-10 Bin Cheng <bin.cheng@arm.com>
+
+ * gcc.dg/tree-ssa/ldist-34.c: New test.
+
+2017-10-10 Bin Cheng <bin.cheng@arm.com>
+
+ * gcc.dg/tree-ssa/ldist-27.c: New test.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * gnat.dg/class_wide4.adb, gnat.dg/class_wide4_pkg.ads,
+ gnat.dg/class_wide4_pkg2.ads: New testcase.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * gnat.dg/class_wide3.adb, gnat.dg/class_wide3_pkg.ads: New testcase.
+
+2017-10-09 Ed Schonberg <schonberg@adacore.com>
+
+ * gnat.dg/validity_check2.adb, gnat.dg/validity_check2_pkg.ads:
+ New testcase.
+
+2017-10-09 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * gcc.target/powerpc/amo1.c: New test.
+ * gcc.target/powerpc/amo2.c: Likewise.
+
+2017-10-09 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82449
+ * gfortran.dg/graphite/pr82449.f: New testcase.
+
+2017-10-09 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ PR target/82463
+ * gcc.target/s390/zvector/pr82463.c: New test.
+
+2017-10-09 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ PR target/82465
+ * gcc.target/s390/zvector/pr82465.c: New test.
+
+2017-10-09 Wilco Dijkstra <wdijkstr@arm.com>
+
+ * gcc.dg/tree-ssa/ssa-dse-26.c (dg-options): Add -fno-short-enums.
+
+2017-10-09 Tom de Vries <tom@codesourcery.com>
+
+ * gcc.dg/cold-1.c (foo1): Fix warning line number. Make warning line
+ number relative.
+ (abort): Declare.
+
+2017-10-08 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gcc.c-torture/execute/20171008-1.c: New test.
+
+2017-10-03 Jeff Law <law@redhat.com>
+
+ * gcc.dg/stack-check-5.c: Skip with -fstack-protector.
+ * gcc.dg/stack-check-6.c: Likewise.
+ * gcc.dg/stack-check-6a.c: Likewise.
- * gcc.target/i386/bt-5.c: New test.
- * gcc.target/i386/bt-6.c: Ditto.
- * gcc.target/i386/bt-mask-3.c: Ditto.
- * gcc.target/i386/bt-mask-4.c: Ditto.
+2017-10-07 Michael Collison <michael.collison@arm.com>
+
+ * gcc.target/aarch64/var_shift_mask_2.c: New test.
+
+2017-10-07 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82375
+ * gfortran.dg/pdt_13.f03 : New test.
+ * gfortran.dg/pdt_14.f03 : New test.
+ * gfortran.dg/pdt_15.f03 : New test.
+
+2017-10-07 Jan Hubicka <hubicka@ucw.cz>
+
+ * gcc.dg/cold-1.c: New testcase.
+
+2017-10-07 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80805
+ * g++.dg/cpp0x/pr80805.C: New.
+
+2017-10-07 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/49232
+ * gfortran.dg/contiguous_4.f90: New test.
+
+2017-10-06 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/66690
+ * g++.dg/cpp1y/pr66690.C: New.
+
+2017-10-06 Nathan Sidwell <nathan@acm.org>
+
+ PR c++/82424
+ * g++.dg/warn/pr82424.C: New.
+
+2017-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82299
+ * g++.dg/cpp0x/pr82299.C: New test.
+
+ P0704R1 - fixing const-qualified pointers to members
+ * g++.dg/cpp2a/ptrmem1.C: New test.
+
+2017-10-06 Martin Liska <mliska@suse.cz>
+
+ * c-c++-common/ubsan/ptr-overflow-sanitization-1.c: New test.
+
+2017-10-06 Sudakshina Das <sudi.das@arm.com>
+
+ * gcc.target/aarch64/bic_imm_1.c: New test.
+ * gcc.target/aarch64/orr_imm_1.c: Likewise.
+
+2017-10-06 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/60153
+ * g++.dg/cpp0x/variadic-crash3.C: New.
+
+2017-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/82434
+ * gcc.dg/store_merging_9.c: New test.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82397
+ * gfortran.dg/pr82397.f: New testcase.
+
+2017-10-06 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ PR target/82322
+ * gcc.target/s390/zvector/pr82322.c: New test.
+
+2017-10-06 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ PR target/82317
+ * gcc.target/s390/zvector/pr82317.c: New test.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82422
+ * gcc.dg/graphite/pr82422.c: New testcase.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82421
+ * gcc.dg/graphite/pr82421.c: New testcase.
+
+2017-10-06 Jakub Jelinek <jakub@redhat.com>
+
+ PR c/82437
+ * c-c++-common/Wtautological-compare-6.c: New test.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/graphite/id-15.c: No longer expect a code generation error.
+ * gcc.dg/graphite/id-16.c: Likewise.
+ * gcc.dg/graphite/pr46168.c: Likewise.
+ * gcc.dg/graphite/pr68756.c: Likewise.
+ * gcc.dg/graphite/pr69728.c: Likewise.
+ * gcc.dg/graphite/pr71575-2.c: Likewise.
+ * gcc.dg/graphite/pr77362.c: Likewise.
+ * gcc.dg/graphite/pr81373.c: Likewise.
+ * gcc.dg/graphite/run-id-pr67700-1.c: Likewise.
+ * gfortran.dg/graphite/interchange-1.f: Likewise.
+ * gfortran.dg/graphite/pr42334-1.f: Likewise.
+ * gfortran.dg/graphite/pr42393-1.f90: Likewise.
+ * gfortran.dg/graphite/pr42393.f90: Likewise.
+ * gfortran.dg/graphite/pr47019.f: Likewise.
+ * gfortran.dg/graphite/id-17.f: Likewise.
+ * gfortran.dg/graphite/id-19.f: Likewise.
+ * gfortran.dg/graphite/run-id-2.f90: Likewise.
+ * gfortran.dg/graphite/pr42326-1.f90: Likewise.
+ * gfortran.dg/graphite/pr42326.f90: Likewise.
+ * gfortran.dg/graphite/pr68550-2.f90: Likewise.
+ * gfortran.dg/graphite/pr29581.f90: Likewise. No longer expect
+ a code generation error.
+ * gfortran.dg/graphite/run-id-3.f90: Likewise.
+ * gfortran.dg/graphite/pr29832.f90: Likewise.
+
+2017-10-06 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82436
+ * gcc.dg/vect/pr82436.c: New testcase.
+
+2017-10-05 Bernd Edlinger <bernd.edlinger@hotmail.de>
+
+ * gcc.dg/Wincompatible-pointer-types-1.c: New test.
+
+2017-10-05 Tamar Christina <tamar.christina@arm.com>
+
+ * gcc.dg/vect/slp-perm-9.c: Use vect_sizes_16B_8B.
+ * lib/target-supports.exp (vect_sizes_16B_8B): New.
+
+2017-10-05 Tamar Christina <tamar.christina@arm.com>
+
+ * gcc.dg/vect/vect-align-1.c: Fix vect_hw_misalign condition.
+ * gcc.dg/vect/vect-align-2.c: Likewise.
+ * gcc.dg/vect/vect-multitypes-1.c: Likewise
+
+2017-10-05 Nathan Sidwell <nathan@acm.org>
+
+ * g++.dg/warn/mvp.C: New.
+
+2017-10-05 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.dg/gomp/pr82374.c (SIZE): Change from 1G to 1M to make it ilp32
+ friendly.
+
+2017-10-05 Richard Biener <rguenther@suse.de>
+
+ * gfortran.dg/graphite/id-17.f: Fix typo.
+ * gfortran.dg/graphite/id-19.f: Likewise.
+ * gfortran.dg/graphite/pr29832.f90: Likewise.
+ * gfortran.dg/graphite/pr42326-1.f90: Likewise.
+ * gfortran.dg/graphite/pr42326.f90: Likewise.
+ * gfortran.dg/graphite/pr68550-2.f90: Likewise.
+ * gfortran.dg/graphite/run-id-2.f90: Likewise.
+ * gfortran.dg/graphite/run-id-3.f90: Likewise.
+
+2017-10-04 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/80471
+ * g++.dg/cpp1y/pr80471.C: New.
+
+2017-10-04 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/78131
+ * g++.dg/cpp1z/constexpr-lambda17.C: New.
+
+2017-10-04 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/78018
+ * g++.dg/cpp1y/lambda-generic-78018.C: New.
+
+2017-10-04 Paolo Carlini <paolo.carlini@oracle.com>
+ Andrew Pinski <apinski@cavium.com>
+
+ PR c++/71946
+ * g++.dg/cpp0x/lambda/lambda-asm1.C: New.
+ * g++.dg/cpp0x/lambda/lambda-stmtexpr1.C: Likewise.
+
+2017-10-04 Sudakshina Das <sudi.das@arm.com>
+
+ * gcc.target/aarch64/bic_imm_1.c: New.
+ * gcc.target/aarch64/orr_imm_1.c: Likewise.
+
+2017-10-04 Nathan Sidwell <nathan@acm.org>
+
+ * g++.dg/abi/mangle41.C: Adjust diagnostics.
+
+2017-10-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82373
+ * g++.dg/cpp1y/pr82373.C: New test.
+
+2017-10-04 David Malcolm <dmalcolm@redhat.com>
+
+ * gcc.dg/diagnostic-range-bad-called-object.c: Update expected
+ underlining for param.
+ * gcc.dg/param-type-mismatch.c: Update expected results to reflect
+ highlighting of parameters; add test coverage for trivial
+ parameter decls, and for callback parameters.
+ * gcc.dg/pr68533.c: Update location of two errors to reflect
+ location of params.
+
+2017-10-04 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-expressions.c (make_test_of_vectors): New function.
+ (create_code): Call it.
+ * jit.dg/test-vector-rvalues.cc: New test case.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * g++.dg/vect/slp-pr56812.cc: xfail for targets which don't want
+ vector loop peeling.
+ * lib/target-supports.exp (check_effective_target_vect_peeling_profitable):
+ New proc.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * gcc.dg/vect/pr66251.c: Replace vect_floatint_cvt with
+ vect_doubleint_cvt and vect_intfloat_cvt with vect_intdouble_cvt.
+ * gcc.dg/vect/vect-floatint-conversion-2.c: Replace
+ vect_floatint_cvt with vect_doubleint_cvt.
+ * gcc.dg/vect/vect-intfloat-conversion-3.c: Replace
+ vect_intfloat_cvt with vect_intdouble_cvt.
+ * gfortran.dg/vect/pr60510.f: Require vect_intdouble_cvt.
+ * gfortran.dg/vect/vect-8.f90: Make number of vectorized loops
+ depend on vect_intdouble_cvt.
+ * lib/target-supports.exp
+ (check_effective_target_vect_doubleint_cvt)
+ (check_effective_target_vect_intdouble_cvt): New procs.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * gcc.dg/vect/pr60656.c: Check vect_long_mult.
+ * lib/target-supports.exp (check_effective_target_vect_long_mult):
+ New proc.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * gfortran.dg/vect/fast-math-mgrid-resid.f: Use -mzarch on S/390.
+ * gfortran.dg/vect/pr77848.f: Likewise.
+
+2017-10-04 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * lib/target-supports.exp (check_effective_target_vect_float):
+ Return 1 being on a S/390 with VXE.
+ * gcc.dg/vect/pr31699.c: Require vec_float.
+ * gcc.dg/vect/pr61194.c: Likewise.
+ * gcc.dg/vect/pr65947-10.c: Likewise.
+ * gcc.dg/vect/pr66142.c: Likewise.
+ * gcc.dg/vect/slp-10.c: Likewise.
+ * gcc.dg/vect/slp-11c.c: Likewise.
+ * gcc.dg/vect/slp-12b.c: Likewise.
+ * gcc.dg/vect/slp-18.c: Likewise.
+ * gcc.dg/vect/slp-33.c: Likewise.
+ * gcc.dg/vect/slp-cond-2-big-array.c: Likewise.
+ * gcc.dg/vect/slp-cond-2.c: Likewise.
+ * gcc.dg/vect/vect-cond-10.c: Likewise.
+ * gcc.dg/vect/vect-cond-8.c: Likewise.
+ * gcc.dg/vect/vect-cond-9.c: Likewise.
+ * gcc.dg/vect/vect-float-extend-1.c: Likewise.
+ * gcc.dg/vect/vect-float-truncate-1.c: Likewise.
+
+2017-10-04 Thomas Schwinge <thomas@codesourcery.com>
+
+ PR tree-optimization/82374
+ * c-c++-common/goacc/kernels-double-reduction-n.c: Adjust for
+ attributes propagation changes for OMP outlined regions.
+ * c-c++-common/goacc/kernels-double-reduction.c: Likewise.
+ * c-c++-common/goacc/kernels-reduction.c: Likewise.
+
+2017-10-04 Richard Sandiford <richard.sandiford@linaro.org>
+
+ PR tree-optimization/82413
+ * g++.dg/pr82413.C: New test.
+
+2017-10-04 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/77296
+ * gfortran.dg/associate_32.f03 : New test.
+
+2017-10-04 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/78816
+ * g++.dg/cpp1y/lambda-generic-variadic6.C: New.
+
+2017-10-04 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/82374
+ * gcc.dg/gomp/pr82374.c: New test.
+
+2017-10-04 Richard Biener <rguenther@suse.de>
+
+ * gfortran.dg/graphite/id-17.f: For ilp32 allow graphite codegen
+ errors and scan for one.
+ * gfortran.dg/graphite/id-19.f: Likewise.
+ * gfortran.dg/graphite/pr29832.f90: Likewise.
+ * gfortran.dg/graphite/pr42326-1.f90: Likewise.
+ * gfortran.dg/graphite/pr42326.f90: Likewise.
+ * gfortran.dg/graphite/pr68550-2.f90: Likewise.
+ * gfortran.dg/graphite/run-id-2.f90: Likewise.
+ * gfortran.dg/graphite/run-id-3.f90: Likewise.
+ * gfortran.dg/graphite/pr42393-1.f90: Dump graphite.
+
+2017-10-03 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * gcc.target/powerpc/float128-odd.c: New test.
+
+2017-10-03 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/70343
+ * g++.dg/cpp0x/lambda/lambda-70343.C: New.
+
+2017-10-03 Jeff Law <law@redhat.com>
+
+ PR target/82358
+ * gcc.target/i386/stack-check-11.c: Use -mtune=generic.
+
+2017-10-03 Martin Jambor <mjambor@suse.cz>
+
+ PR tree-optimization/82363
+ * gcc.dg/tree-ssa/pr82363.c: New test.
+
+2017-10-03 Jakub Jelinek <jakub@redhat.com>
+
+ PR tree-optimization/82381
+ * gcc.c-torture/compile/pr82381.c: New test.
+
+ PR target/82386
+ * gcc.dg/pr82386.c: New test.
+
+2017-10-02 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/70570
+ * g++.dg/cpp1y/lambda-generic-70570.C: New.
+
+2017-10-02 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/79590
+ * g++.dg/cpp1y/lambda-generic-noexcept1.C: New.
+
+2017-10-02 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/79005
+ * g++.dg/cpp1y/lambda-generic-79005.C: New.
+
+2017-10-02 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/82312
+ * gfortran.dg/typebound_proc_36.f90 : New test.
+
+2017-10-02 Peter Bergner <bergner@vnet.ibm.com>
+
+ PR target/80210
+ * gcc.target/powerpc/pr80210-2.c: New test.
+
+2017-10-02 Jakub Jelinek <jakub@redhat.com>
+
+ * gcc.dg/pr82389.c: New test.
+
+ PR tree-optimization/82387
+ PR tree-optimization/82388
+ PR tree-optimization/82389
+ * gcc.c-torture/compile/pr82389.c: New test.
+ * gcc.c-torture/execute/pr82387.c: New test.
+ * gcc.c-torture/execute/pr82388.c: New test.
+
+2017-10-02 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/79180
+ * g++.dg/cpp0x/lambda/lambda-nested8.C: New.
+ * g++.dg/torture/pr79180.C: Likewise.
+
+ PR c++/71386
+ * g++.dg/cpp1y/lambda-generic-nested1.C: New.
+
+2017-10-02 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/graphite/graphite.exp: Add -fdump-tree-graphite-details.
+ * gcc.dg/graphite/id-15.c: Adjust for existing codegen errors.
+ * gcc.dg/graphite/id-16.c: Likewise.
+ * gcc.dg/graphite/pr46168.c: Likewise.
+ * gcc.dg/graphite/pr68756.c: Likewise.
+ * gcc.dg/graphite/pr69728.c: Likewise.
+ * gcc.dg/graphite/pr71575-2.c: Likewise.
+ * gcc.dg/graphite/pr77362.c: Likewise.
+ * gcc.dg/graphite/pr81373.c: Likewise.
+ * gcc.dg/graphite/run-id-pr67700-1.c: Likewise.
+ * gfortran.dg/graphite/interchange-1.f: Likewise.
+ * gfortran.dg/graphite/pr29581.f90: Likewise.
+ * gfortran.dg/graphite/pr42334-1.f: Likewise.
+ * gfortran.dg/graphite/pr42393-1.f90: Likewise.
+ * gfortran.dg/graphite/pr42393.f90: Likewise.
+ * gfortran.dg/graphite/pr47019.f: Likewise.
+
+2017-10-02 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/69977
+ * g++.dg/cpp1y/lambda-generic-69977.C: New.
+
+2017-10-02 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/59991
+ * g++.dg/cpp0x/lambda/lambda-ice23.C: New.
+
+2017-10-02 Tom de Vries <tom@codesourcery.com>
+
+ * gcc.c-torture/compile/pr82337.c: Add
+ dg-require-effective-target nonlocal_goto.
+
+2017-10-02 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ PR target/71307
+ * gcc.target/aarch64/vect_copy_lane_1.c: Remove XFAIL.
+
+2017-10-02 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82355
+ * gcc.dg/graphite/fuse-1.c: Adjust.
+ * gcc.dg/graphite/fuse-2.c: Likewise.
+ * gcc.dg/graphite/pr82355.c: New testcase.
+
+2017-10-01 Jeff Law <law@redhat.com>
+
+ * gcc.dg/tree-ssa/ssa-dom-simplify-1.c: New test.
+
+2017-10-01 Dominique d'Humieres <dominiq@lps.ens.fr>
+
+ PR fortran/61450
+ * gfortran.dg/binding_label_tests_28.f90: New test.
+
+2017-09-30 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/65949
+ * g++.dg/cpp1y/lambda-generic-variadic5.C: New.
+
+2017-09-30 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/68754
+ * g++.dg/cpp1y/constexpr-68754.C: Move...
+ * g++.dg/cpp0x/constexpr-68754.C: ... here, adjust.
+
+2017-09-30 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82361
+ * gcc.target/i386/pr82361-1.c: New test.
+ * gcc.target/i386/pr82361-2.c: New test.
+
+2017-09-29 Yury Gribov <tetra2005@gmail.com>
+
+ PR middle-end/82319
+ * c-c++/common/pr57371-4.c: Test NaN comparisons.
+
+2017-09-29 Eric Botcazou <ebotcazou@adacore.com>
+
+ * g++.dg/other/dump-ada-spec-10.C: New test.
+
+2017-09-29 Jeff Law <law@redhat.com>
+
+ * testsuite/gcc.dg/tree-ssa/ssa-dse-26.c: New test.
+
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ P0683R1 - default member initializers for bit-fields
+ * g++.dg/ext/bitfield6.C: New test.
+ * g++.dg/cpp2a/bitfield1.C: New test.
+ * g++.dg/cpp2a/bitfield2.C: New test.
+ * g++.dg/cpp2a/bitfield3.C: New test.
+
+2017-09-29 Vladimir Makarov <vmakarov@redhat.com>
+
+ PR target/81481
+ * gcc.target/i386/pr81481.c: New.
+
+2017-09-29 Kelvin Nilsen <kelvin@gcc.gnu.org>
+
+ * gcc.target/powerpc/swaps-p8-28.c: Exchange the order of dg-do
+ and dg-require-effective-target directives to correct testing
+ behavior.
+ * gcc.target/powerpc/swaps-p8-29.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-30.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-31.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-32.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-33.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-34.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-35.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-36.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-37.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-38.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-39.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-40.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-41.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-42.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-43.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-44.c: Likewise.
+ * gcc.target/powerpc/swaps-p8-45.c: Likewise.
+
+2017-09-29 Bill Schmidt <wschmidt@linux.vnet.ibm.com>
+
+ PR tree-optimization/82337
+ * gcc.c-torture/compile/pr82337.c: New file.
+
+2017-09-29 Javier Miranda <miranda@adacore.com>
+
+ * gnat.dg/unchecked_union3.adb: New testcase.
+
+2017-09-29 Javier Miranda <miranda@adacore.com>
+
+ * gnat.dg/unchecked_union2.adb: New testcase.
+
+2017-09-29 Dominique d'Humieres <dominiq@lps.ens.fr>
+
+ PR fortran/25071
+ * gfortran.dg/argument_checking_3.f90: Change warnings to errors.
+ * gfortran.dg/argument_checking_4.f90: Likewise.
+ * gfortran.dg/argument_checking_5.f90: Likewise.
+ * gfortran.dg/argument_checking_6.f90: Likewise.
+ * gfortran.dg/argument_checking_10.f90: Likewise.
+ * gfortran.dg/argument_checking_13.f90: Likewise.
+ * gfortran.dg/argument_checking_15.f90: Likewise.
+ * gfortran.dg/argument_checking_18.f90: Likewise.
+ * gfortran.dg/gomp/udr8.f90: Likewise.
+ * gfortran.dg/warn_argument_mismatch_1.f90: Add -std=legacy to
+ the dg-options.
+
+2017-09-29 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.dg/ext/bitfield7.C: New test.
+ * g++.dg/ext/bitfield8.C: New test.
+ * g++.dg/ext/bitfield9.C: New test.
+
+ PR c/82340
+ * gcc.dg/tree-ssa/pr82340.c: New test.
+
+ * g++.dg/eh/uncaught3.C: Add -Wno-deprecated for c++17.
+
+2017-09-28 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/79488
+ * g++.dg/cpp0x/lambda/lambda-ice22.C: New.
+
+2017-09-28 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82342
+ * gcc.target/i386/pr82260-1.c: Add -mno-bmi2 to dg-options.
+ * gcc.target/i386/pr82260-2.c: Likewise.
+
+2017-09-28 Sergey Shalnov <Sergey.Shalnov@intel.com>
+
+ * gcc.target/i386/avx512f-constant-float-return.c: New test.
+
+2017-09-28 Christophe Lyon <christophe.lyon@linaro.org>
+
+ * gcc.target/arm/aapcs/align4.c: Require arm_neon_hw effective target.
+ * gcc.target/arm/aapcs/align_rec4.c: Likewise.
+ * gcc.target/arm/aapcs/neon-vect1.c: Likewise.
+ * gcc.target/arm/aapcs/neon-vect2.c: Likewise.
+ * gcc.target/arm/aapcs/neon-vect3.c: Likewise.
+ * gcc.target/arm/aapcs/neon-vect4.c: Likewise.
+ * gcc.target/arm/aapcs/neon-vect5.c: Likewise.
+ * gcc.target/arm/aapcs/neon-vect6.c: Likewise.
+ * gcc.target/arm/aapcs/neon-vect7.c: Likewise.
+ * gcc.target/arm/aapcs/neon-vect8.c: Likewise.
+
+2017-09-28 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c: New
+ test case.
+ * jit.dg/test-returning-function-ptr.c (create_code): Update to
+ create a function pointer type independently of the call to
+ gcc_jit_function_get_address, and assign the pointer to a local
+ before returning it, to exercise the function pointer type
+ comparison code.
+
+2017-09-27 David Malcolm <dmalcolm@redhat.com>
+
+ * jit.dg/all-non-failing-tests.h: Add
+ test-returning-function-ptr.c.
+ * jit.dg/test-returning-function-ptr.c: New test case.
+
+2017-09-27 Christophe Lyon <christophe.lyon@linaro.org>
+
+ PR target/71727
+ * gcc.target/aarch64/pr71727-2.c: New test.
+
+2017-09-27 Kelvin Nilsen <kelvin@gcc.gnu.org>
+
+ * gcc.target/powerpc/swaps-p8-28.c: New test.
+ * gcc.target/powerpc/swaps-p8-29.c: New test.
+ * gcc.target/powerpc/swaps-p8-30.c: New test.
+ * gcc.target/powerpc/swaps-p8-31.c: New test.
+ * gcc.target/powerpc/swaps-p8-32.c: New test.
+ * gcc.target/powerpc/swaps-p8-33.c: New test.
+ * gcc.target/powerpc/swaps-p8-34.c: New test.
+ * gcc.target/powerpc/swaps-p8-35.c: New test.
+ * gcc.target/powerpc/swaps-p8-36.c: New test.
+ * gcc.target/powerpc/swaps-p8-37.c: New test.
+ * gcc.target/powerpc/swaps-p8-38.c: New test.
+ * gcc.target/powerpc/swaps-p8-39.c: New test.
+ * gcc.target/powerpc/swaps-p8-40.c: New test.
+ * gcc.target/powerpc/swaps-p8-41.c: New test.
+ * gcc.target/powerpc/swaps-p8-42.c: New test.
+ * gcc.target/powerpc/swaps-p8-43.c: New test.
+ * gcc.target/powerpc/swaps-p8-44.c: New test.
+ * gcc.target/powerpc/swaps-p8-45.c: New test.
+
+2017-09-27 Carl Love <cel@us.ibm.com>
+ * gcc.target/powerpc/builtin-fctid-fctiw-runnable.c: New test file
+ for the __builtin_fctid and __builtin_fctiw.
+
+2017-09-27 Pekka Jääskeläinen <pekka.jaaskelainen@parmance.com>
+
+ * brig.dg/test/gimple/fbarrier.hsail: Fixed tests to match the new
+ new group memory offsetting code in the BRIG frontend.
+ * brig.dg/test/gimple/function_calls.hsail: Likewise.
+ * brig.dg/test/gimple/smoke_test.hsail: Likewise.
+ * brig.dg/test/gimple/variables.hsail: Likewise.
+
+2017-09-27 Jakub Jelinek <jakub@redhat.com>
+
+ PR c++/82159
+ * g++.dg/opt/pr82159.C: New test.
+
+2017-09-27 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * gcc.dg/vect/pr65947-9.c: Use signed char explicitly.
+
+2017-09-26 Michael Meissner <meissner@linux.vnet.ibm.com>
+
+ * gcc.target/powerpc/pr71977-1.c: Update test to know that we
+ don't generate a 32-bit shift after doing XSCVDPSPN.
+ * gcc.target/powerpc/direct-move-float1.c: Likewise.
+ * gcc.target/powerpc/direct-move-float3.c: New test.
+
+2017-09-26 Prathamesh Kulkarni <prathamesh.kulkarni@linaro.org>
+
+ * gcc.dg/tree-ssa/cmpdiv.c: New test.
+
+2017-09-26 Carl Love <cel@us.ibm.com>
+
+ * gcc.target/powerpc/builtins-5-p9-runnable.c: Add new runable test
+ file for the new built-ins and the existing built-ins.
+
+2017-09-26 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/82143
+ PR fortran/82324
+ * lib/target-supports.exp (check_effective_target_fortran_real_10): New.
+ * gfortran.dg/promotion_3.f90: Only run if real(16) is available.
+ * gfortran.dg/promotion_4.f90: Only run if real(10) is available.
+ Don't assume that DOUBLE PRECISION has kind=16.
+
+2017-09-26 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * gfortran.dg/gomp/associate1.f90: Remove unnecessary
+ warning from associate construct and do loop.
+
+2017-09-26 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * gfortran.dg/gomp/associate1.f90: Really commit change
+ from 2017-09-25.
+ * gfortran.dg/predcom-1.f: Likewise.
+ * gfortran.dg/unconstrained_commons.f: Likewise.
+
+2017-09-26 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/35691
+ * gcc.dg/pr35691-5.c: New test.
+ * gcc.dg/pr35691-6.c: New test.
+
+2017-09-26 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82321
+ * gcc.dg/graphite/pr82321.c: New testcase.
+
+2017-09-26 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+
+ * lib/target-supports.exp (check_effective_target_vect_int)
+ (check_effective_target_vect_shift)
+ (check_effective_target_whole_vector_shift)
+ (check_effective_target_vect_shift_char)
+ (check_effective_target_vect_long)
+ (check_effective_target_vect_double)
+ (check_effective_target_vect_long_long)
+ (check_effective_target_vect_perm)
+ (check_effective_target_vect_perm_byte)
+ (check_effective_target_vect_perm_short)
+ (check_effective_target_vect_widen_mult_qi_to_hi)
+ (check_effective_target_vect_widen_mult_hi_to_si)
+ (check_effective_target_vect_widen_mult_qi_to_hi_pattern)
+ (check_effective_target_vect_widen_mult_hi_to_si_pattern)
+ (check_effective_target_vect_widen_mult_si_to_di_pattern)
+ (check_effective_target_vect_pack_trunc)
+ (check_effective_target_vect_unpack)
+ (check_effective_target_vect_hw_misalign)
+ (check_effective_target_vect_condition)
+ (check_effective_target_vect_cond_mixed)
+ (check_effective_target_vect_char_mult)
+ (check_effective_target_vect_short_mult)
+ (check_effective_target_vect_int_mult)
+ (check_effective_target_vect_extract_even_odd)
+ (check_effective_target_vect_interleave)
+ (check_effective_target_sqrt_insn)
+ (check_effective_target_vect_call_sqrtf): Return 1 for S/390 with
+ VX.
+ (check_vect_support_and_set_flags): New proc.
+ (check_effective_target_s390_vxe): Rename arch12 to z14.
+
+2017-09-26 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82320
+ * gcc.dg/torture/pr82320.c: New testcase.
+
+2017-09-26 Christophe Lyon <christophe.lyon@linaro.org>
+
+ * lib/target-supports.exp (check_effective_target_vect_hw_misalign):
+ Fix arm check.
+
+2017-09-25 Jeff Law <law@redhat.com>
+
+ * lib/target-supports.exp
+ (check_effective_target_supports_stack_clash_protection): Enable for
+ rs6000 and powerpc targets.
+
+2017-09-25 Bin Cheng <bin.cheng@arm.com>
+
+ PR tree-optimization/82163
+ * gcc.dg/tree-ssa/pr82163.c: New test.
+
+2017-09-25 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ * gfortran.dg/do_subscript_1.f90: New test.
+ * gfortran.dg/do_subscript_2.f90: New test.
+ * gfortran.dg/gomp/associate1.f90: Add out of bounds warning.
+ * gfortran.dg/predcom-1.f: Adjust loop bounds.
+ * gfortran.dg/unconstrained_commons.f: Add out of bounds warning.
+
+2017-09-25 Will Schmidt <will_schmidt@vnet.ibm.com>
+
+ * gcc.target/powerpc/fold-vec-st-char.c: New.
+ * gcc.target/powerpc/fold-vec-st-double.c: New.
+ * gcc.target/powerpc/fold-vec-st-float.c: New.
+ * gcc.target/powerpc/fold-vec-st-int.c: New.
+ * gcc.target/powerpc/fold-vec-st-longlong.c: New.
+ * gcc.target/powerpc/fold-vec-st-pixel.c: New.
+ * gcc.target/powerpc/fold-vec-st-short.c: New.
+
+2017-09-25 Pierre-Marie de Rodat <derodat@adacore.com>
+
+ * g++.dg/pr82155.C: New testcase.
+
+2017-09-25 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82285
+ * gcc.dg/torture/pr82285.c: New testcase.
+
+2017-09-25 Justin Squirek <squirek@adacore.com>
+
+ * gnat.dg/entry_family.adb: New testcase
+
+2017-09-24 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR target/82267
+ * gcc.target/i386/pr82267.c: New test.
+
+2017-09-24 Thomas Koenig <tkoenig@gcc.gnu.org>
+ PR fortran/66328
+
+ * gfortran.dg/data_derived_1.f90: New test.
+
+2017-09-24 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR fortran/54633
+ * gfortran.dg/intrinsic_bounds_1.f90: New test.
+ * gfortran.dg/intrinsic_param_1.f90: New test.
+
+2017-09-24 Thomas Koenig <tkoenig@gcc.gnu.org>
+ Steven G. Kargl <kargl@gcc.gnu.org>
+
+ PR fortran/80118
+ * gfortran.dg/zero_sized_7.f90: New test.
+
+2017-09-23 Janus Weil <janus@gcc.gnu.org>
+
+ PR fortran/82143
+ * gfortran.dg/promotion_3.f90: New test case.
+ * gfortran.dg/promotion_4.f90: New test case.
+
+2017-09-23 Daniel Santos <daniel.santos@pobox.com>
+
+ * gcc.target/i386/pr82196-1.c: (b): Remove volatile asm.
+ * gcc.target/i386/pr82196-2.c: (b): Likewise.
+
+2017-09-22 Jakub Jelinek <jakub@redhat.com>
+
+ PR middle-end/35691
+ * gcc.dg/pr35691-1.c: Use -fdump-tree-forwprop1-details
+ instead of -fdump-tree-forwprop-details in dg-options.
+ * gcc.dg/pr35691-2.c: Likewise.
+ * gcc.dg/pr35691-3.c: New test.
+ * gcc.dg/pr35691-4.c: New test.
+
+ PR sanitizer/81929
+ * g++.dg/ubsan/pr81929.C: New test.
+
+2017-09-22 Richard Sandiford <richard.sandiford@linaro.org>
+
+ PR tree-optimization/82289
+ * gcc.dg/vect/pr82289.c: New test.
+
+2017-09-22 Richard Sandiford <richard.sandiford@linaro.org>
+ Alan Hayward <alan.hayward@arm.com>
+ David Sherwood <david.sherwood@arm.com>
+
+ * gcc.dg/vect/vect-outer-3a.c: Adjust dump scan for new wording
+ of alignment message.
+ * gcc.dg/vect/vect-outer-3a-big-array.c: Likewise.
+
+2017-09-22 Martin Sebor <msebor@redhat.com>
+
+ PR c/81854
+ * gcc.target/i386/pr80732.c: Correct a type error.
+
+2017-09-22 David Malcolm <dmalcolm@redhat.com>
+
+ * g++.dg/diagnostic/param-type-mismatch.C: Update expected results
+ to reflect highlighting of parameters; add test coverage for
+ callback parameters.
+
+2017-09-22 Richard Biener <rguenther@suse.de>
+
+ * gcc.dg/graphite/scop-24.c: New testcase.
+
+2017-09-22 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82291
+ * gcc.dg/torture/pr82291.c: New testcase.
+
+2017-09-22 Sergey Shalnov <sergey.shalnov@intel.com>
+
+ * gcc.target/i386/avx512f-constant-set.c: New test.
+
+2017-09-21 Sergey Shalnov <sergey.shalnov@intel.com>
+
+ * g++.dg/ext/pr57362.C: Test __attribute__((target("prefer-avx256"))).
+ * gcc.target/i386/avx512f-prefer.c: New test.
+
+2017-09-21 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
+
+ * lib/target-supports.exp
+ (check_effective_target_frame_pointer_for_non_leaf): Add
+ case for x86 Solaris.
+
+2017-09-21 Paul Thomas <pault@gcc.gnu.org>
+
+ PR fortran/78512
+ * gfortran.dg/associate_26.f90 : New test.
+
+ PR fortran/80120
+ * gfortran.dg/associate_27.f90 : New test.
+
+ PR fortran/81903
+ * gfortran.dg/associate_28.f90 : New test.
+
+ PR fortran/82121
+ * gfortran.dg/associate_29.f90 : New test.
+
+ PR fortran/67543
+ * gfortran.dg/associate_30.f90 : New test.
+
+ PR fortran/52832
+ * gfortran.dg/associate_31.f90 : New test.
+
+2017-09-21 Eric Botcazou <ebotcazou@adacore.com>
+
+ * gnat.dg/discr48.adb: New test.
+ * gnat.dg/discr48_pkg.ads: New helper.
+
+2017-09-21 Tamar Christina <tamar.christina@arm.com>
+
+ PR testsuite/78421
+ * lib/target-supports.exp (check_effective_target_vect_hw_misalign):
+ Invert arm check.
+
+2017-09-21 Cesar Philippidis <cesar@codesourcery.com>
+
+ * gfortran.dg/goacc/wait.f90: New test.
+
+2017-09-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/81715
+ * g++.dg/tree-ssa/pr8781.C (noop): Change argument type from
+ const predicate to const predicate & to avoid UB.
+ * g++.dg/opt/pr81715.C: New test.
+
+2017-09-21 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82276
+ PR tree-optimization/82244
+ * gcc.dg/torture/pr82276.c: New testcase.
+
+2017-09-21 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/71351
+ * gfortran.dg/graphite/pr71351.f90: New testcase.
+ * gfortran.dg/graphite/interchange-3.f90: Adjust.
+
+2017-09-21 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82260
+ * gcc.target/i386/pr82260-1.c: New test.
+ * gcc.target/i386/pr82260-2.c: New test.
+
+2017-09-20 Andreas Krebbel <krebbel@linux.vnet.ibm.com>
+ Jeff Law <law@redhat.com>
+
+ * gcc.dg/stack-check-5.c: Add argument for s390.
+ * lib/target-supports.exp:
+ (check_effective_target_supports_stack_clash_protection): Enable for
+ s390/s390x targets.
+
+2017-09-20 Martin Sebor <msebor@redhat.com>
+
+ PR c/81854
+ * g++.dg/ext/attr-ifunc-2.C: Correct type errors.
+ * g++.dg/ext/attr-ifunc-4.C: Ditto.
+ * lib/target-supports.exp: Adjust for C++.
+
+ PR c/81854
+ * gcc.dg/attr-ifunc-1.c: Correct type errors.
+ * gcc.dg/attr-ifunc-2.c: Ditto.
+ * gcc.dg/attr-ifunc-3.c: Ditto.
+ * gcc.dg/attr-ifunc-4.c: Ditto.
+ * gcc.dg/attr-ifunc-5.c: Ditto.
+ * gcc.dg/pr81854.c: Require ifunc support.
+ * lib/target-supports.exp: Correct type error.
+
+2017-09-20 Jeff Law <law@redhat.com>
+
+ * gcc.target/i386/stack-check-11.c: Update test and regexp
+ so that it works for both i?86 and x86_64.
+
+2017-09-19 Segher Boessenkool <segher@kernel.crashing.org>
+
+ PR target/77687
+ * gcc.target/powerpc/pr77687.c: New testcase.
+
+2017-09-20 Jakub Jelinek <jakub@redhat.com>
+
+ P0409R2 - allow lambda capture [=, this]
+ * g++.dg/cpp1z/lambda-this1.C: Don't expect error for c++2a on [=, this]
+ capture. Add further tests.
+ * g++.dg/cpp0x/lambda/lambda-capture-redundancy.C: Don't expect error
+ for c++2a on [=, this] capture.
+
+ * g++.dg/cpp1z/cplusplus.C: Test that __cplusplus is equal to 201703L.
+ * g++.dg/cpp1z/cplusplus_1z.C: New test.
+
+2017-09-20 Sebastian Peryt <sebastian.peryt@intel.com>
+
+ * gcc.target/i386/builtin_target.c: Test knm.
+ * gcc.target/i386/funcspec-56.inc: Test arch=knm.
+
+2017-09-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/77362
+ * gcc.dg/graphite/pr77362.c: New testcase.
+
+2017-09-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/82264
+ * gcc.dg/torture/pr82264.c: New testcase.
+
+2017-09-20 Jakub Jelinek <jakub@redhat.com>
+
+ * g++.dg/debug/dwarf2/template-params-13.C: New test.
+ * g++.dg/debug/dwarf2/template-params-5.C: Adjust regexps so that
+ it doesn't match newlines.
+ * g++.dg/debug/dwarf2/template-params-3.C: Likewise.
+ * g++.dg/debug/dwarf2/template-func-params-3.C: Likewise.
+ * g++.dg/debug/dwarf2/lang-cpp98.C: Likewise.
+ * g++.dg/debug/dwarf2/template-func-params-2.C: Likewise.
+ * g++.dg/debug/dwarf2/template-func-params-1.C: Likewise.
+ * g++.dg/debug/dwarf2/template-func-params-5.C: Likewise.
+ * g++.dg/debug/dwarf2/template-params-1.C: Likewise.
+ * g++.dg/debug/dwarf2/template-params-2.C: Likewise.
+ * g++.dg/debug/dwarf2/lang-cpp14.C: Likewise.
+ * g++.dg/debug/dwarf2/lang-cpp11.C: Likewise.
+
+2017-09-20 Paolo Carlini <paolo.carlini@oracle.com>
+
+ PR c++/64954
+ * g++.dg/cpp0x/constexpr-ctor20.C: New.
+
+2017-09-20 Richard Biener <rguenther@suse.de>
+
+ PR tree-optimization/81373
+ * gcc.dg/graphite/pr81373.c: New testcase.
+
+2017-09-19 Jeff Law <law@redhat.com>
+
+ * gcc.target/i386/stack-check-11.c: New test.
+
+ * gcc.dg/stack-check-4.c: New test.
+ * gcc.dg/stack-check-5.c: New test.
+ * gcc.dg/stack-check-6.c: New test.
+ * gcc.dg/stack-check-6a.c: New test.
+ * gcc.dg/stack-check-7.c: New test.
+ * gcc.dg/stack-check-8.c: New test.
+ * gcc.dg/stack-check-9.c: New test.
+ * gcc.dg/stack-check-10.c: New test.
+ * lib/target-supports.exp
+ (check_effective_target_supports_stack_clash_protection): Enable for
+ x86 and x86_64 targets.
+
+ * gcc.dg/stack-check-3.c: New test.
+
+ * gcc.dg/stack-check-2.c: New test.
+ * lib/target-supports.exp
+ (check_effective_target_supports_stack_clash_protection): New.
+ (check_effective_target_frame_pointer_for_non_leaf): Likewise.
+ (check_effective_target_caller_implicit_probes): Likewise.
2017-09-19 Jakub Jelinek <jakub@redhat.com>
@@ -1391,7 +3468,7 @@
2017-08-23 Richard Biener <rguenther@suse.de>
- PR target/81921
+ PR target/81921
* gcc.target/i386/pr81921.c: New testcase.
2017-08-23 Daniel Santos <daniel.santos@pobox.com>
@@ -1472,8 +3549,8 @@
2017-08-22 Yvan Roux <yvan.roux@linaro.org>
- PR c++/80287
- * g++.dg/pr80287.C: New test.
+ PR c++/80287
+ * g++.dg/pr80287.C: New test.
2017-08-22 Richard Biener <rguenther@suse.de>
diff --git a/gcc/testsuite/brig.dg/test/gimple/fbarrier.hsail b/gcc/testsuite/brig.dg/test/gimple/fbarrier.hsail
index a58ca09..9efe027 100644
--- a/gcc/testsuite/brig.dg/test/gimple/fbarrier.hsail
+++ b/gcc/testsuite/brig.dg/test/gimple/fbarrier.hsail
@@ -65,10 +65,10 @@ prog kernel &kernel(kernarg_u64 %input_ptr, kernarg_u64 %output_ptr)
/* { dg-final { scan-tree-dump "__hsail_waitfbar \\\(0, __context\\\);" "gimple"} } */
/* { dg-final { scan-tree-dump "__hsail_initfbar \\\(0, __context\\\);" "gimple"} } */
-/* { dg-final { scan-tree-dump "__hsail_initfbar \\\(32, __context\\\);" "gimple"} } */
+/* { dg-final { scan-tree-dump "__hsail_initfbar \\\(__group_local_offset, __context\\\);" "gimple"} } */
/* { dg-final { scan-tree-dump "__hsail_joinfbar \\\(0, __context\\\);" "gimple"} } */
-/* { dg-final { scan-tree-dump "@skip_init:\[\n ]+__builtin___hsail_barrier \\\(__context\\\);\[\n ]+__builtin___hsail_joinfbar \\\(32, __context\\\);" "gimple"} } */
+/* { dg-final { scan-tree-dump "@skip_init:\[\n ]+__builtin___hsail_barrier \\\(__context\\\);\[\n ]+__builtin___hsail_joinfbar \\\(__group_local_offset, __context\\\);" "gimple"} } */
-/* { dg-final { scan-tree-dump "__hsail_arrivefbar \\\(32, __context\\\);" "gimple"} } */
+/* { dg-final { scan-tree-dump "__hsail_arrivefbar \\\(__group_local_offset, __context\\\);" "gimple"} } */
-/* { dg-final { scan-tree-dump "__hsail_releasefbar \\\(0, __context\\\);\[\n ]+__builtin___hsail_releasefbar \\\(32, __context\\\);" "gimple"} } */
+/* { dg-final { scan-tree-dump "__hsail_releasefbar \\\(0, __context\\\);\[\n ]+__builtin___hsail_releasefbar \\\(__group_local_offset, __context\\\);" "gimple"} } */
diff --git a/gcc/testsuite/brig.dg/test/gimple/function_calls.hsail b/gcc/testsuite/brig.dg/test/gimple/function_calls.hsail
index d3b690c..50f7906 100644
--- a/gcc/testsuite/brig.dg/test/gimple/function_calls.hsail
+++ b/gcc/testsuite/brig.dg/test/gimple/function_calls.hsail
@@ -46,7 +46,7 @@ prog kernel &kernel(kernarg_u64 %input_ptr, kernarg_u64 %output_ptr)
/* The generated function call should have the incoming arguments and three hidden arguments. */
-/* { dg-final { scan-tree-dump "_\[0-9\]+ = subfunction \\\(_kernel.float_arg.\[_0-9\]+, _kernel.double_arg.\[_0-9\]+, _kernel.half_arg.\[_0-9\]+, __context, __group_base_addr, __private_base_addr\\\);" "gimple"} } */
+/* { dg-final { scan-tree-dump "_\[0-9\]+ = subfunction \\\(_kernel.float_arg.\[_0-9\]+, _kernel.double_arg.\[_0-9\]+, _kernel.half_arg.\[_0-9\]+, __context, __group_base_addr, group_local_offset.*, __private_base_addr\\\);" "gimple"} } */
/* The callee should refer directly to the scalar arguments when it reads them. */
/* { dg-final { scan-tree-dump "= float_arg;" "gimple"} } */
diff --git a/gcc/testsuite/brig.dg/test/gimple/smoke_test.hsail b/gcc/testsuite/brig.dg/test/gimple/smoke_test.hsail
index 850aeeb..1f36ddc 100644
--- a/gcc/testsuite/brig.dg/test/gimple/smoke_test.hsail
+++ b/gcc/testsuite/brig.dg/test/gimple/smoke_test.hsail
@@ -42,7 +42,7 @@ prog kernel &KernelWithBarrier(kernarg_u64 %input_ptr, kernarg_u64 %output_ptr)
/* The kernel function itself should have a fingerprint as follows */
/* _Kernel (unsigned char * __args, void * __context, void * __group_base_addr, void * __private_base_addr) */
-/* { dg-final { scan-tree-dump "_Kernel \\\(unsigned char \\\* __args, void \\\* __context, void \\\* __group_base_addr, void \\\* __private_base_addr\\\)" "gimple"} } */
+/* { dg-final { scan-tree-dump "_Kernel \\\(unsigned char \\\* __args, void \\\* __context, void \\\* __group_base_addr, unsigned int __group_local_offset, void \\\* __private_base_addr\\\)" "gimple"} } */
/* ld_kernarg: mem_read.0 = MEM[(unsigned long *)__args]; */
/* { dg-final { scan-tree-dump "mem_read.\[0-9\] = MEM\\\[\\\(unsigned long \\\*\\\)__args\\\];" "gimple"} } */
@@ -73,7 +73,7 @@ prog kernel &KernelWithBarrier(kernarg_u64 %input_ptr, kernarg_u64 %output_ptr)
/* The launcher should call __hsail_launch_wg_function in this case: */
/* Kernel (void * __context, void * __group_base_addr) */
/* { dg-final { scan-tree-dump "Kernel \\\(void \\\* __context, void \\\* __group_base_addr\\\)" "gimple"} } */
-/* { dg-final { scan-tree-dump "__hsail_launch_wg_function \\\(_Kernel, __context, __group_base_addr\\\);" "gimple"} }*/
+/* { dg-final { scan-tree-dump "__hsail_launch_wg_function \\\(_Kernel, __context, __group_base_addr, group_local_offset.*\\\);" "gimple"} }*/
/* The kernel should have the magic metadata section injected to the ELF. */
/* TODO: this should be disabled in case not outputting to an ELF. */
@@ -85,7 +85,7 @@ prog kernel &KernelWithBarrier(kernarg_u64 %input_ptr, kernarg_u64 %output_ptr)
/* { dg-final { scan-tree-dump "s2 = s0 \\\+ s1;\[\n \]+__builtin___hsail_barrier \\\(__context\\\);\[\n \]+s3 = s0 \\\+ 4294967295;" "gimple"} } */
/* The kernel with the barrier call's launcher function should call the thread-spawning function. */
-/* { dg-final { scan-tree-dump "__hsail_launch_kernel \\\(_KernelWithBarrier, __context, __group_base_addr\\\);" "gimple" } } */
+/* { dg-final { scan-tree-dump "__hsail_launch_kernel \\\(_KernelWithBarrier, __context, __group_base_addr, group_local_offset.*\\\);" "gimple" } } */
diff --git a/gcc/testsuite/brig.dg/test/gimple/variables.hsail b/gcc/testsuite/brig.dg/test/gimple/variables.hsail
index c76ea60..5fd96c1 100644
--- a/gcc/testsuite/brig.dg/test/gimple/variables.hsail
+++ b/gcc/testsuite/brig.dg/test/gimple/variables.hsail
@@ -3,7 +3,7 @@ module &module:1:0:$full:$large:$default;
/* Tests for different variable scopes and address spaces. */
/* { dg-do compile } */
-/* { dg-options "-fdump-tree-gimple" } */
+/* { dg-options "-fdump-tree-gimple -fdump-tree-original" } */
prog align(256) private_u32 &prog_private;
private_u32 &mod_private;
@@ -29,7 +29,10 @@ prog function &subfunction(arg_u32 %return_value)(arg_u32 %arg) {
ld_private_u32 $s200, [%func_private];
st_private_u32 $s200, [&prog_private];
+/* { dg-final { scan-tree-dump "__group_base_addr \\\+ \\\(0 \\\+" "original" } } */
ld_group_u32 $s203, [%func_group];
+
+/* { dg-final { scan-tree-dump "__group_base_addr \\\+ 0" "original" } } */
st_group_u32 $s203, [&prog_group];
ld_global_u32 $s204, [%func_global];
@@ -104,8 +107,6 @@ prog kernel &kernel(kernarg_u64 %input_ptr, kernarg_u64 %output_ptr)
kern_group @12 (3)
*/
-/* { dg-final { scan-tree-dump "\\\+ 8;.*\\\+ 12;.*\\\+ 4;" "gimple" } } */
-
/* The "mangling" of the global and readonly vars. */
/* { dg-final { scan-tree-dump "\[ \]*prog_global = s204;" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/Wbuiltin-declaration-mismatch-1.c b/gcc/testsuite/c-c++-common/Wbuiltin-declaration-mismatch-1.c
new file mode 100644
index 0000000..63343b8
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wbuiltin-declaration-mismatch-1.c
@@ -0,0 +1,4 @@
+/* PR c++/82466 */
+/* { dg-options "-Wbuiltin-declaration-mismatch" } */
+
+int printf; /* { dg-warning "declared as non-function" } */
diff --git a/gcc/testsuite/c-c++-common/Wno-builtin-declaration-mismatch-1.c b/gcc/testsuite/c-c++-common/Wno-builtin-declaration-mismatch-1.c
new file mode 100644
index 0000000..6409412
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wno-builtin-declaration-mismatch-1.c
@@ -0,0 +1,4 @@
+/* PR c++/82466 */
+/* { dg-options "-Wno-builtin-declaration-mismatch" } */
+
+int printf;
diff --git a/gcc/testsuite/c-c++-common/Wtautological-compare-6.c b/gcc/testsuite/c-c++-common/Wtautological-compare-6.c
new file mode 100644
index 0000000..fcdca72
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wtautological-compare-6.c
@@ -0,0 +1,11 @@
+/* PR c/82437 */
+/* { dg-do compile { target int32plus } } */
+/* { dg-options "-Wtautological-compare" } */
+
+int
+foo (unsigned int x)
+{
+ if ((x & -1879048192) != -1879048192) /* { dg-bogus "bitwise comparison always evaluates to" } */
+ return 0;
+ return 1;
+}
diff --git a/gcc/testsuite/c-c++-common/Wtautological-compare-7.c b/gcc/testsuite/c-c++-common/Wtautological-compare-7.c
new file mode 100644
index 0000000..1dab587
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/Wtautological-compare-7.c
@@ -0,0 +1,11 @@
+/* PR c/82437 */
+/* { dg-do compile { target int32 } } */
+/* { dg-options "-Wtautological-compare" } */
+
+int
+foo (unsigned long long int x)
+{
+ if ((x | 0x190000000ULL) != -1879048192) /* { dg-bogus "bitwise comparison always evaluates to" } */
+ return 0;
+ return 1;
+}
diff --git a/gcc/testsuite/c-c++-common/attr-nocf-check-1.c b/gcc/testsuite/c-c++-common/attr-nocf-check-1.c
new file mode 100644
index 0000000..15f69731
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-nocf-check-1.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+
+int func (int) __attribute__ ((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored" } */
+int (*fptr) (int) __attribute__ ((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored" } */
+typedef void (*nocf_check_t) (void) __attribute__ ((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored" } */
+
+int
+foo1 (int arg)
+{
+ return func (arg) + fptr (arg);
+}
+
+void
+foo2 (void (*foo) (void))
+{
+ void (*func) (void) __attribute__((nocf_check)) = foo; /* { dg-warning "'nocf_check' attribute ignored" } */
+ func ();
+}
+
+void
+foo3 (nocf_check_t foo)
+{
+ foo ();
+}
+
+void
+foo4 (void (*foo) (void) __attribute__((nocf_check))) /* { dg-warning "'nocf_check' attribute ignored" } */
+{
+ foo ();
+}
diff --git a/gcc/testsuite/c-c++-common/attr-nocf-check-2.c b/gcc/testsuite/c-c++-common/attr-nocf-check-2.c
new file mode 100644
index 0000000..9ab0180
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-nocf-check-2.c
@@ -0,0 +1,5 @@
+/* { dg-do compile } */
+
+int var1 __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
+int *var2 __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
+void (**var3) (void) __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
diff --git a/gcc/testsuite/c-c++-common/attr-nocf-check-3.c b/gcc/testsuite/c-c++-common/attr-nocf-check-3.c
new file mode 100644
index 0000000..ad1ca7e
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/attr-nocf-check-3.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+
+int foo (void) __attribute__ ((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored" } */
+void (*foo1) (void) __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored" } */
+void (*foo2) (void);
+
+int
+foo (void) /* The function's address is not tracked. */
+{
+ /* This call site is not tracked for
+ control-flow instrumentation. */
+ (*foo1)();
+
+ foo1 = foo2;
+ /* This call site is still not tracked for
+ control-flow instrumentation. */
+ (*foo1)();
+
+ /* This call site is tracked for
+ control-flow instrumentation. */
+ (*foo2)();
+
+ foo2 = foo1;
+ /* This call site is still tracked for
+ control-flow instrumentation. */
+ (*foo2)();
+
+ return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c
index 18816e0..fd4fe54 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors.c
@@ -7,5 +7,5 @@ int main (void)
array2[:] = array2[: ; /* { dg-error "expected ']'" } */
- return 0;
-} /* { dg-error "expected ';' before" "" { target c } } */
+ return 0; /* { dg-error "expected ';' before" "" { target c } } */
+}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c
index 2bb9134..d003d7c 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors2.c
@@ -7,6 +7,7 @@ int main (void)
array2[:] = array2[1:2:] ; /* { dg-error "expected expression before" "" { target c } } */
/* { dg-error "expected primary-expression before" "" { target c++ } .-1 } */
+ /* { dg-error "expected ';' before" "" { target c } .-2 } */
- return 0; /* { dg-error "expected ';' before" "" { target c } } */
+ return 0;
}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c
index 9270007..14256e9 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/parser_errors3.c
@@ -7,6 +7,7 @@ int main (void)
array2[:] = array2[1: :] ; /* { dg-error "expected expression before" "" { target c } } */
/* { dg-error "expected primary-expression before" "" { target c++ } .-1 } */
+ /* { dg-error "expected ';' before" "" { target c } .-2 } */
- return 0; /* { dg-error "expected ';' before" "" { target c } } */
+ return 0;
}
diff --git a/gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c b/gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c
index a9a9d66..8c32ad9 100644
--- a/gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c
+++ b/gcc/testsuite/c-c++-common/cilk-plus/AN/pr61191.c
@@ -7,4 +7,5 @@ double f(double * A, double * B)
return __sec_reduce_add((B[0:500])(; /* { dg-error "called object" "" { target c } } */
/* { dg-error "expected expression before ';' token" "" { target c } .-1 } */
/* { dg-error "expected primary-expression before ';' token" "" { target c++ } .-2 } */
-} /* { dg-error "expected" "" { target c } } */
+/* { dg-error "expected" "" { target c } .-3 } */
+}
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-1.c b/gcc/testsuite/c-c++-common/fcf-protection-1.c
new file mode 100644
index 0000000..2e9337c
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-1.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fcf-protection=full" } */
+/* { dg-error "'-fcf-protection=full' requires CET support on this target" "" { target { "i?86-*-* x86_64-*-*" } } 0 } */
+/* { dg-error "'-fcf-protection=full' is not supported for this target" "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-2.c b/gcc/testsuite/c-c++-common/fcf-protection-2.c
new file mode 100644
index 0000000..aa0d2a0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-2.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fcf-protection=branch" } */
+/* { dg-error "'-fcf-protection=branch' requires CET support on this target" "" { target { "i?86-*-* x86_64-*-*" } } 0 } */
+/* { dg-error "'-fcf-protection=branch' is not supported for this target" "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-3.c b/gcc/testsuite/c-c++-common/fcf-protection-3.c
new file mode 100644
index 0000000..028775a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-3.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fcf-protection=return" } */
+/* { dg-error "'-fcf-protection=return' requires CET support on this target" "" { target { "i?86-*-* x86_64-*-*" } } 0 } */
+/* { dg-error "'-fcf-protection=return' is not supported for this target" "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-4.c b/gcc/testsuite/c-c++-common/fcf-protection-4.c
new file mode 100644
index 0000000..af4fc0b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-4.c
@@ -0,0 +1,2 @@
+/* { dg-do compile } */
+/* { dg-options "-fcf-protection=none" } */
diff --git a/gcc/testsuite/c-c++-common/fcf-protection-5.c b/gcc/testsuite/c-c++-common/fcf-protection-5.c
new file mode 100644
index 0000000..a5f8e11
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/fcf-protection-5.c
@@ -0,0 +1,4 @@
+/* { dg-do compile } */
+/* { dg-options "-fcf-protection" } */
+/* { dg-error "'-fcf-protection=full' requires CET support on this target" "" { target { "i?86-*-* x86_64-*-*" } } 0 } */
+/* { dg-error "'-fcf-protection=full' is not supported for this target" "" { target { ! "i?86-*-* x86_64-*-*" } } 0 } */
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-double-reduction-n.c b/gcc/testsuite/c-c++-common/goacc/kernels-double-reduction-n.c
index 27ea2e9..10b364b 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-double-reduction-n.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-double-reduction-n.c
@@ -27,7 +27,7 @@ foo (unsigned int n)
/* Check that only one loop is analyzed, and that it can be parallelized. */
/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 1 "parloops1" } } */
-/* { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc kernels parallelized, oacc function \\(, , \\), oacc kernels, omp target entrypoint\\)\\)" 1 "parloops1" } } */
+/* { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc kernels parallelized, oacc function \\(, , \\), oacc kernels, omp target entrypoint, noclone, noinline\\)\\)" 1 "parloops1" } } */
/* { dg-final { scan-tree-dump-not "FAILED:" "parloops1" } } */
/* { dg-final { scan-tree-dump-times "parallelizing outer loop" 1 "parloops1" } } */
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-double-reduction.c b/gcc/testsuite/c-c++-common/goacc/kernels-double-reduction.c
index 0841e90..c026346 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-double-reduction.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-double-reduction.c
@@ -27,7 +27,7 @@ foo (void)
/* Check that only one loop is analyzed, and that it can be parallelized. */
/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 1 "parloops1" } } */
-/* { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc kernels parallelized, oacc function \\(, , \\), oacc kernels, omp target entrypoint\\)\\)" 1 "parloops1" } } */
+/* { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc kernels parallelized, oacc function \\(, , \\), oacc kernels, omp target entrypoint, noclone, noinline\\)\\)" 1 "parloops1" } } */
/* { dg-final { scan-tree-dump-not "FAILED:" "parloops1" } } */
/* { dg-final { scan-tree-dump-times "parallelizing outer loop" 1 "parloops1" } } */
diff --git a/gcc/testsuite/c-c++-common/goacc/kernels-reduction.c b/gcc/testsuite/c-c++-common/goacc/kernels-reduction.c
index 4a18272..5921b88 100644
--- a/gcc/testsuite/c-c++-common/goacc/kernels-reduction.c
+++ b/gcc/testsuite/c-c++-common/goacc/kernels-reduction.c
@@ -26,7 +26,7 @@ foo (void)
/* Check that only one loop is analyzed, and that it can be parallelized. */
/* { dg-final { scan-tree-dump-times "SUCCESS: may be parallelized" 1 "parloops1" } } */
-/* { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc kernels parallelized, oacc function \\(, , \\), oacc kernels, omp target entrypoint\\)\\)" 1 "parloops1" } } */
+/* { dg-final { scan-tree-dump-times "(?n)__attribute__\\(\\(oacc kernels parallelized, oacc function \\(, , \\), oacc kernels, omp target entrypoint, noclone, noinline\\)\\)" 1 "parloops1" } } */
/* { dg-final { scan-tree-dump-not "FAILED:" "parloops1" } } */
/* Check that the loop has been split off into a function. */
diff --git a/gcc/testsuite/c-c++-common/gomp/pr63326.c b/gcc/testsuite/c-c++-common/gomp/pr63326.c
index e319f49..3e62723 100644
--- a/gcc/testsuite/c-c++-common/gomp/pr63326.c
+++ b/gcc/testsuite/c-c++-common/gomp/pr63326.c
@@ -156,34 +156,34 @@ f4 (int x)
{
do
#pragma omp barrier /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp flush /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp taskwait /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp taskyield /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
#pragma omp parallel
{
do
#pragma omp cancel parallel /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
#pragma omp parallel
{
do
#pragma omp cancellation point parallel /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
#pragma omp for ordered(1)
for (i = 0; i < 16; i++)
@@ -191,28 +191,28 @@ f4 (int x)
{
do
#pragma omp ordered depend(source) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp ordered depend(sink: i-1) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
}
{
do
#pragma omp target enter data map(to:i) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp target update to(i) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
{
do
#pragma omp target exit data map(from:i) /* { dg-error "may only be used in compound statements" } */
- while (0);
+ while (0); /* { dg-error "before" "" { target c++ } } */
} /* { dg-error "before" "" { target c++ } } */
}
diff --git a/gcc/testsuite/c-c++-common/missing-close-symbol.c b/gcc/testsuite/c-c++-common/missing-close-symbol.c
index 85b96f28..abeb837 100644
--- a/gcc/testsuite/c-c++-common/missing-close-symbol.c
+++ b/gcc/testsuite/c-c++-common/missing-close-symbol.c
@@ -12,6 +12,7 @@ void test_static_assert_same_line (void)
/* { dg-begin-multiline-output "" }
_Static_assert(sizeof(int) >= sizeof(char), "msg";
~ ^
+ )
{ dg-end-multiline-output "" } */
}
@@ -25,6 +26,7 @@ void test_static_assert_different_line (void)
/* { dg-begin-multiline-output "" }
"msg";
^
+ )
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
_Static_assert(sizeof(int) >= sizeof(char),
diff --git a/gcc/testsuite/c-c++-common/missing-symbol.c b/gcc/testsuite/c-c++-common/missing-symbol.c
index 33a501b..326b9fa 100644
--- a/gcc/testsuite/c-c++-common/missing-symbol.c
+++ b/gcc/testsuite/c-c++-common/missing-symbol.c
@@ -5,15 +5,14 @@ extern int bar (void);
int missing_close_paren_in_switch (int i)
{
- switch (i /* { dg-message "10: to match this '\\('" } */
- { /* { dg-error "5: expected '\\)' before '.' token" } */
- /* { dg-begin-multiline-output "" }
- {
- ^
- { dg-end-multiline-output "" } */
+ switch (i /* { dg-error "12: expected '\\)' before '.' token" } */
+ {
/* { dg-begin-multiline-output "" }
switch (i
- ^
+ ~ ^
+ )
+ {
+ ~
{ dg-end-multiline-output "" } */
case 0:
@@ -30,21 +29,33 @@ int missing_close_paren_in_switch (int i)
void missing_close_paren_in_if (void)
{
if (foo () /* { dg-line start_of_if } */
- && bar ()
- { /* { dg-error "5: expected '\\)' before '.' token" } */
+ && bar () /* { dg-error "16: expected '\\)' before '.' token" } */
+ {
/* { dg-begin-multiline-output "" }
+ && bar ()
+ ^
+ )
{
- ^
+ ~
{ dg-end-multiline-output "" } */
/* { dg-message "6: to match this '\\('" "" { target *-*-* } start_of_if } */
/* { dg-begin-multiline-output "" }
if (foo ()
^
- { dg-end-multiline-output "" } */
+ { dg-end-multiline-output "" } */
}
-
} /* { dg-error "1: expected" } */
/* { dg-begin-multiline-output "" }
}
^
{ dg-end-multiline-output "" } */
+
+int missing_colon_in_ternary (int flag)
+{
+ return flag ? 42 0; /* { dg-error "expected ':' before numeric constant" } */
+ /* { dg-begin-multiline-output "" }
+ return flag ? 42 0;
+ ^~
+ :
+ { dg-end-multiline-output "" } */
+}
diff --git a/gcc/testsuite/c-c++-common/pr57371-4.c b/gcc/testsuite/c-c++-common/pr57371-4.c
index 6265f52..f43f7c2 100644
--- a/gcc/testsuite/c-c++-common/pr57371-4.c
+++ b/gcc/testsuite/c-c++-common/pr57371-4.c
@@ -69,4 +69,16 @@ void nonfinite(unsigned short x) {
nonfinite_10 = (float) x != SNAN;
/* { dg-final { scan-tree-dump "nonfinite_10 = \\(float\\)" "original" } } */
}
+
+ {
+ volatile int nonfinite_11;
+ nonfinite_11 = (float) x == QNAN;
+ /* { dg-final { scan-tree-dump "nonfinite_11 = 0" "original" } } */
+ }
+
+ {
+ volatile int nonfinite_12;
+ nonfinite_12 = (float) x != QNAN;
+ /* { dg-final { scan-tree-dump "nonfinite_12 = 1" "original" } } */
+ }
}
diff --git a/gcc/testsuite/c-c++-common/rotate-5.c b/gcc/testsuite/c-c++-common/rotate-5.c
index 35b14b8..629ab2f 100644
--- a/gcc/testsuite/c-c++-common/rotate-5.c
+++ b/gcc/testsuite/c-c++-common/rotate-5.c
@@ -15,12 +15,40 @@ f1 (unsigned long long x, unsigned int y)
return (x << y) | (x >> ((-y) & 63));
}
+__attribute__((noinline, noclone))
+unsigned long long
+f2 (unsigned long long x, unsigned int y)
+{
+ return (x << y) + (x >> ((-y) & 63));
+}
+
+__attribute__((noinline, noclone))
+unsigned long long
+f3 (unsigned long long x, unsigned int y)
+{
+ return (x << y) ^ (x >> ((-y) & 63));
+}
+
#if __CHAR_BIT__ * __SIZEOF_INT128__ == 128
__attribute__((noinline, noclone))
unsigned __int128
-f2 (unsigned __int128 x, unsigned int y)
+f4 (unsigned __int128 x, unsigned int y)
+{
+ return (x << y) | (x >> ((-y) & 127));
+}
+
+__attribute__((noinline, noclone))
+unsigned __int128
+f5 (unsigned __int128 x, unsigned int y)
{
- return (x << y) | (x >> ((-y) & 128));
+ return (x << y) + (x >> ((-y) & 127));
+}
+
+__attribute__((noinline, noclone))
+unsigned __int128
+f6 (unsigned __int128 x, unsigned int y)
+{
+ return (x << y) ^ (x >> ((-y) & 127));
}
#endif
#endif
@@ -31,12 +59,45 @@ main ()
#if __CHAR_BIT__ * __SIZEOF_LONG_LONG__ == 64
if (f1 (0x123456789abcdef0ULL, 0) != 0x123456789abcdef0ULL)
abort ();
+ if (f2 (0x123456789abcdef0ULL, 0) != 0x2468acf13579bde0ULL)
+ abort ();
+ if (f3 (0x123456789abcdef0ULL, 0) != 0)
+ abort ();
+ if (f1 (0x123456789abcdef0ULL, 1) != 0x2468acf13579bde0ULL)
+ abort ();
+ if (f2 (0x123456789abcdef0ULL, 1) != 0x2468acf13579bde0ULL)
+ abort ();
+ if (f3 (0x123456789abcdef0ULL, 1) != 0x2468acf13579bde0ULL)
+ abort ();
#if __CHAR_BIT__ * __SIZEOF_INT128__ == 128
- if (f2 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+ if (f4 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
| 0x0fedcba987654321ULL, 0)
!= ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
| 0x0fedcba987654321ULL))
abort ();
+ if (f5 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+ | 0x0fedcba987654321ULL, 0)
+ != ((((unsigned __int128) 0x2468acf13579bde0ULL) << 64)
+ | 0x1fdb97530eca8642ULL))
+ abort ();
+ if (f6 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+ | 0x0fedcba987654321ULL, 0) != 0)
+ abort ();
+ if (f4 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+ | 0x0fedcba987654321ULL, 1)
+ != ((((unsigned __int128) 0x2468acf13579bde0ULL) << 64)
+ | 0x1fdb97530eca8642ULL))
+ abort ();
+ if (f5 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+ | 0x0fedcba987654321ULL, 1)
+ != ((((unsigned __int128) 0x2468acf13579bde0ULL) << 64)
+ | 0x1fdb97530eca8642ULL))
+ abort ();
+ if (f6 ((((unsigned __int128) 0x123456789abcdef0ULL) << 64)
+ | 0x0fedcba987654321ULL, 1)
+ != ((((unsigned __int128) 0x2468acf13579bde0ULL) << 64)
+ | 0x1fdb97530eca8642ULL))
+ abort ();
#endif
#endif
return 0;
diff --git a/gcc/testsuite/c-c++-common/rotate-6.c b/gcc/testsuite/c-c++-common/rotate-6.c
new file mode 100644
index 0000000..715f8a4
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/rotate-6.c
@@ -0,0 +1,582 @@
+/* Check rotate pattern detection. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-ipa-icf -fdump-tree-optimized" } */
+/* Rotates should be recognized only in functions with | instead of + or ^,
+ or in functions that have constant shift counts (unused attribute on y). */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 48 "optimized" } } */
+
+unsigned int
+f1 (unsigned int x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f2 (unsigned int x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f3 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) | (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f4 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> 1);
+}
+
+unsigned short int
+f5 (unsigned short int x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f6 (unsigned short int x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f7 (unsigned char x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f8 (unsigned char x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f9 (unsigned int x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f10 (unsigned int x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f11 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) | (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f12 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x >> 1);
+}
+
+unsigned short int
+f13 (unsigned short int x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f14 (unsigned short int x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f15 (unsigned char x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f16 (unsigned char x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f17 (unsigned int x, unsigned int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f18 (unsigned int x, unsigned long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f19 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << 1);
+}
+
+unsigned int
+f20 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> 1) ^ (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f21 (unsigned short int x, unsigned int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f22 (unsigned short int x, unsigned long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f23 (unsigned char x, unsigned int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ - 1))) ^ (x << (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f24 (unsigned char x, unsigned long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ - 1))) ^ (x << (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f25 (unsigned int x, unsigned int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f26 (unsigned int x, unsigned long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f27 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << 1);
+}
+
+unsigned int
+f28 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> 1) ^ (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f29 (unsigned short int x, unsigned int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f30 (unsigned short int x, unsigned long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f31 (unsigned char x, unsigned int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f32 (unsigned char x, unsigned long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f33 (unsigned int x, unsigned int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f34 (unsigned int x, unsigned long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f35 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> 1) | (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f36 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << 1);
+}
+
+unsigned short int
+f37 (unsigned short int x, unsigned int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f38 (unsigned short int x, unsigned long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f39 (unsigned char x, unsigned int y)
+{
+ return (x >> (y & (__CHAR_BIT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f40 (unsigned char x, unsigned long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f41 (unsigned int x, unsigned int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f42 (unsigned int x, unsigned long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f43 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> 1) | (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f44 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x << 1);
+}
+
+unsigned short int
+f45 (unsigned short int x, unsigned int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f46 (unsigned short int x, unsigned long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f47 (unsigned char x, unsigned int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f48 (unsigned char x, unsigned long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f49 (unsigned int x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f50 (unsigned int x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f51 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> 1);
+}
+
+unsigned int
+f52 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) ^ (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f53 (unsigned short int x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f54 (unsigned short int x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f55 (unsigned char x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f56 (unsigned char x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f57 (unsigned int x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f58 (unsigned int x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f59 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> 1);
+}
+
+unsigned int
+f60 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) ^ (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f61 (unsigned short int x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f62 (unsigned short int x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f63 (unsigned char x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f64 (unsigned char x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f65 (unsigned int x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f66 (unsigned int x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f67 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f68 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> 1);
+}
+
+unsigned short int
+f69 (unsigned short int x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f70 (unsigned short int x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f71 (unsigned char x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f72 (unsigned char x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f73 (unsigned int x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f74 (unsigned int x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f75 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f76 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> 1);
+}
+
+unsigned short int
+f77 (unsigned short int x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f78 (unsigned short int x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f79 (unsigned char x, unsigned int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f80 (unsigned char x, unsigned long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f81 (unsigned int x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f82 (unsigned int x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f83 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> 1);
+}
+
+unsigned int
+f84 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f85 (unsigned short int x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f86 (unsigned short int x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f87 (unsigned char x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ - 1))) + (x >> (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f88 (unsigned char x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ - 1))) + (x >> (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f89 (unsigned int x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f90 (unsigned int x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f91 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> 1);
+}
+
+unsigned int
+f92 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f93 (unsigned short int x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f94 (unsigned short int x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f95 (unsigned char x, unsigned int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f96 (unsigned char x, unsigned long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
diff --git a/gcc/testsuite/c-c++-common/rotate-6a.c b/gcc/testsuite/c-c++-common/rotate-6a.c
new file mode 100644
index 0000000..06ba56a
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/rotate-6a.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-overflow" } */
+
+#define ROTATE_N "rotate-6.c"
+
+#include "rotate-1a.c"
diff --git a/gcc/testsuite/c-c++-common/rotate-7.c b/gcc/testsuite/c-c++-common/rotate-7.c
new file mode 100644
index 0000000..390cef6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/rotate-7.c
@@ -0,0 +1,582 @@
+/* Check rotate pattern detection. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-ipa-icf -fdump-tree-optimized" } */
+/* Rotates should be recognized only in functions with | instead of + or ^,
+ or in functions that have constant shift counts (unused attribute on y). */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 48 "optimized" } } */
+
+unsigned int
+f1 (unsigned int x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f2 (unsigned int x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f3 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) | (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f4 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> 1);
+}
+
+unsigned short int
+f5 (unsigned short int x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f6 (unsigned short int x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f7 (unsigned char x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f8 (unsigned char x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f9 (unsigned int x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f10 (unsigned int x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f11 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) | (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f12 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x >> 1);
+}
+
+unsigned short int
+f13 (unsigned short int x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f14 (unsigned short int x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f15 (unsigned char x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f16 (unsigned char x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) | (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f17 (unsigned int x, int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f18 (unsigned int x, long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f19 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x << 1);
+}
+
+unsigned int
+f20 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> 1) ^ (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f21 (unsigned short int x, int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f22 (unsigned short int x, long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f23 (unsigned char x, int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ - 1))) ^ (x << (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f24 (unsigned char x, long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ - 1))) ^ (x << (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f25 (unsigned int x, int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f26 (unsigned int x, long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f27 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x << 1);
+}
+
+unsigned int
+f28 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> 1) ^ (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f29 (unsigned short int x, int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f30 (unsigned short int x, long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f31 (unsigned char x, int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f32 (unsigned char x, long int y)
+{
+ return (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f33 (unsigned int x, int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f34 (unsigned int x, long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f35 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> 1) | (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f36 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << 1);
+}
+
+unsigned short int
+f37 (unsigned short int x, int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f38 (unsigned short int x, long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f39 (unsigned char x, int y)
+{
+ return (x >> (y & (__CHAR_BIT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f40 (unsigned char x, long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ - 1))) | (x << ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f41 (unsigned int x, int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f42 (unsigned int x, long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f43 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> 1) | (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f44 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) | (x << 1);
+}
+
+unsigned short int
+f45 (unsigned short int x, int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f46 (unsigned short int x, long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f47 (unsigned char x, int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f48 (unsigned char x, long int y)
+{
+ return (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) | (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f49 (unsigned int x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f50 (unsigned int x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f51 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) ^ (x >> 1);
+}
+
+unsigned int
+f52 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) ^ (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f53 (unsigned short int x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f54 (unsigned short int x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f55 (unsigned char x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f56 (unsigned char x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ - 1))) ^ (x >> (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f57 (unsigned int x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f58 (unsigned int x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f59 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) ^ (x >> 1);
+}
+
+unsigned int
+f60 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) ^ (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f61 (unsigned short int x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f62 (unsigned short int x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f63 (unsigned char x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f64 (unsigned char x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) ^ (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f65 (unsigned int x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f66 (unsigned int x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f67 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f68 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> 1);
+}
+
+unsigned short int
+f69 (unsigned short int x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f70 (unsigned short int x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f71 (unsigned char x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f72 (unsigned char x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ - 1))) + (x >> ((-y) & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f73 (unsigned int x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f74 (unsigned int x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f75 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f76 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> 1);
+}
+
+unsigned short int
+f77 (unsigned short int x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f78 (unsigned short int x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f79 (unsigned char x, int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f80 (unsigned char x, long int y)
+{
+ return (x << (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned int
+f81 (unsigned int x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f82 (unsigned int x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f83 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) + (x >> 1);
+}
+
+unsigned int
+f84 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned short int
+f85 (unsigned short int x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned short int
+f86 (unsigned short int x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1))) + (x >> (y & (__CHAR_BIT__ * __SIZEOF_SHORT__ - 1)));
+}
+
+unsigned char
+f87 (unsigned char x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ - 1))) + (x >> (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned char
+f88 (unsigned char x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ - 1))) + (x >> (y & (__CHAR_BIT__ - 1)));
+}
+
+unsigned int
+f89 (unsigned int x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f90 (unsigned int x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned int
+f91 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1))) + (x >> 1);
+}
+
+unsigned int
+f92 (unsigned int x, int y __attribute__((unused)))
+{
+ return (x << 1) + (x >> ((-1) & (__CHAR_BIT__ * sizeof (unsigned int) - 1)));
+}
+
+unsigned short int
+f93 (unsigned short int x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned short int
+f94 (unsigned short int x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned short) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned short) - 1)));
+}
+
+unsigned char
+f95 (unsigned char x, int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
+
+unsigned char
+f96 (unsigned char x, long int y)
+{
+ return (x << ((-y) & (__CHAR_BIT__ * sizeof (unsigned char) - 1))) + (x >> (y & (__CHAR_BIT__ * sizeof (unsigned char) - 1)));
+}
diff --git a/gcc/testsuite/c-c++-common/rotate-7a.c b/gcc/testsuite/c-c++-common/rotate-7a.c
new file mode 100644
index 0000000..4fb0846
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/rotate-7a.c
@@ -0,0 +1,6 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -Wno-overflow" } */
+
+#define ROTATE_N "rotate-7.c"
+
+#include "rotate-1a.c"
diff --git a/gcc/testsuite/c-c++-common/rotate-8.c b/gcc/testsuite/c-c++-common/rotate-8.c
new file mode 100644
index 0000000..9ba3e94
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/rotate-8.c
@@ -0,0 +1,171 @@
+/* PR middle-end/62263 */
+/* PR middle-end/82498 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-ipa-icf -fdump-tree-optimized" } */
+/* { dg-final { scan-tree-dump-times "r\[<>]\[<>]" 23 "optimized" } } */
+/* { dg-final { scan-tree-dump-not "PHI <" "optimized" } } */
+
+unsigned int
+f1 (unsigned int x, unsigned char y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f2 (unsigned int x, signed char y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned int
+f3 (unsigned int x, unsigned char y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))));
+}
+
+unsigned int
+f4 (unsigned int x, unsigned char y)
+{
+ y = y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1);
+ return y ? (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y)) : x;
+}
+
+unsigned int
+f5 (unsigned int x, unsigned char y)
+{
+ y = y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1);
+ return (x << y) | (x >> ((__CHAR_BIT__ * __SIZEOF_INT__ - y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f6 (unsigned int x, unsigned char y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> ((__CHAR_BIT__ * __SIZEOF_INT__ - (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f7 (unsigned int x, unsigned char y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> ((__CHAR_BIT__ * __SIZEOF_INT__ - y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f8 (unsigned int x, unsigned char y)
+{
+ return (x << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> ((-y) & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f9 (unsigned int x, int y)
+{
+ return (0x12345678U << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (0x12345678U >> (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f10 (unsigned int x, int y)
+{
+ return (0x12345678U >> (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (0x12345678U << (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f11 (unsigned int x, int y)
+{
+ return (0x12345678U >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (0x12345678U << (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned int
+f12 (unsigned int x, int y)
+{
+ return (0x12345678U << (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (0x12345678U >> (y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned
+f13 (unsigned x, unsigned char y)
+{
+ if (y == 0)
+ return x;
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f14 (unsigned x, unsigned y)
+{
+ if (y == 0)
+ return x;
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f15 (unsigned x, unsigned short y)
+{
+ if (y == 0)
+ return x;
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f16 (unsigned x, unsigned char y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ if (y == 0)
+ return x;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f17 (unsigned x, unsigned y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ if (y == 0)
+ return x;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f18 (unsigned x, unsigned short y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ if (y == 0)
+ return x;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f19 (unsigned x, unsigned char y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (((unsigned char) -y) % (__CHAR_BIT__ * __SIZEOF_INT__)));
+}
+
+unsigned
+f20 (unsigned x, unsigned int y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (-y % (__CHAR_BIT__ * __SIZEOF_INT__)));
+}
+
+unsigned
+f21 (unsigned x, unsigned short y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (((unsigned short) -y) % (__CHAR_BIT__ * __SIZEOF_INT__)));
+}
+
+unsigned
+f22 (unsigned x, unsigned char y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (-y & ((__CHAR_BIT__ * __SIZEOF_INT__) - 1)));
+}
+
+unsigned
+f23 (unsigned x, unsigned short y)
+{
+ y %= __CHAR_BIT__ * __SIZEOF_INT__;
+ return (x << y) | (x >> (-y & ((__CHAR_BIT__ * __SIZEOF_INT__) - 1)));
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/attrib-5.c b/gcc/testsuite/c-c++-common/ubsan/attrib-5.c
new file mode 100644
index 0000000..209b5dd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/attrib-5.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-fsanitize=undefined" } */
+
+__attribute__((no_sanitize("foobar")))
+static void
+float_cast2 (void) { /* { dg-warning "attribute directive ignored" } */
+ volatile double d = 300;
+ volatile signed char c;
+ c = d;
+}
diff --git a/gcc/testsuite/c-c++-common/ubsan/builtin-1.c b/gcc/testsuite/c-c++-common/ubsan/builtin-1.c
new file mode 100644
index 0000000..2f340e3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/builtin-1.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=undefined" } */
+
+#include <stdio.h>
+
+__attribute__((noinline, noclone)) unsigned long long
+foo (unsigned int x, unsigned long int y, unsigned long long int z, __UINTMAX_TYPE__ w)
+{
+ unsigned long long ret = 0;
+ fprintf (stderr, "FOO MARKER1\n");
+ ret += __builtin_ctz (x);
+ ret += __builtin_ctzl (y);
+ ret += __builtin_ctzll (z);
+ ret += __builtin_ctzimax (w);
+ fprintf (stderr, "FOO MARKER2\n");
+ ret += __builtin_clz (x);
+ ret += __builtin_clzl (y);
+ ret += __builtin_clzll (z);
+ ret += __builtin_clzimax (w);
+ fprintf (stderr, "FOO MARKER3\n");
+ return ret;
+}
+
+int
+main ()
+{
+ volatile __UINTMAX_TYPE__ t = 0;
+ t = foo (t, t, t, t);
+ return 0;
+}
+
+/* { dg-output "FOO MARKER1(\n|\r\n|\r)" } */
+/* { dg-output "(\[^\n\r]*runtime error: passing zero to ctz\\\(\\\), which is not a valid argument\[^\n\r]*(\n|\r\n|\r)){4}" } */
+/* { dg-output "FOO MARKER2(\n|\r\n|\r)" } */
+/* { dg-output "(\[^\n\r]*runtime error: passing zero to clz\\\(\\\), which is not a valid argument\[^\n\r]*(\n|\r\n|\r)){4}" } */
+/* { dg-output "FOO MARKER3" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c
index aae88aa..8139cc1 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-1.c
@@ -91,115 +91,115 @@ main (void)
return 0;
}
-/* { dg-output "value -133 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -32773 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -32769.5 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 32768 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 32768.5 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 32772 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 65536 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 65536.5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 65540 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type 'long long unsigned int'" } */
+/* { dg-output " -133 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -129.5 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 128 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 128.5 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 132 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 256 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 256.5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 260 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -32773 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -32769.5 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 32768 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 32768.5 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 32772 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 65536 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 65536.5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 65540 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 9.22337e\\\+18 is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.84467e\\\+19 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type 'long long unsigned int'" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-10.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-10.c
index a54a838..a4e8ec4 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-10.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-10.c
@@ -9,38 +9,38 @@
#include "float-cast-overflow-8.c"
/* _Decimal32 */
-/* { dg-output "value <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output " <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* _Decimal64 */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
/* _Decimal128 */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c
index b25e312..426c625 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-2.c
@@ -30,44 +30,44 @@ main (void)
return 0;
}
-/* { dg-output "runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value nan is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value -?nan is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value inf is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value -inf is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value -5 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value -1.5 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value nan is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value -?nan is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value inf is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*runtime error: value -inf is outside the range of representable values of type '__int128 unsigned'" } */
+/* { dg-output "runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 1.70141e\\\+38 is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: nan is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: -?nan is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: inf is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: -inf is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: 3.40282e\\\+38 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: -5 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: -1.5 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: nan is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: -?nan is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: inf is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*runtime error: -inf is outside the range of representable values of type '__int128 unsigned'" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c
index ba82111..6567ca9 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-3.c
@@ -26,15 +26,15 @@ main (void)
return 0;
}
-/* { dg-output "value -133* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type" } */
+/* { dg-output " -133* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c
index af76e4a..48ad257 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-4.c
@@ -30,23 +30,23 @@ main (void)
return 0;
}
-/* { dg-output "value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -?nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -inf is outside the range of representable values of type" } */
+/* { dg-output " -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -?nan is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* inf is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -inf is outside the range of representable values of type" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c
index 4c2fbb4..25a9495 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-5.c
@@ -26,15 +26,15 @@ main (void)
return 0;
}
-/* { dg-output "value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[^\n\r]* is outside the range of representable values of type" } */
+/* { dg-output " \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[^\n\r]* is outside the range of representable values of type" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c
index a2b5f9a..90ec268 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-6.c
@@ -26,15 +26,15 @@ main (void)
return 0;
}
-/* { dg-output "value -133 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type" } */
+/* { dg-output " -133 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -129.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -129 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 128 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 128.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 132 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 256 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 256.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 260 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type" } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-8.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-8.c
index 4adb22a..4e7beeb 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-8.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-8.c
@@ -99,45 +99,45 @@ main ()
}
/* float */
-/* { dg-output "value -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
+/* { dg-output " -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
/* No error for float and __int128 unsigned max value, as ui128_MAX is +Inf in float. */
/* double */
-/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
+/* { dg-output "\[^\n\r]* -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
/* long double */
-/* { dg-output "\[^\n\r]*value -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
+/* { dg-output "\[^\n\r]* -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" { target { ilp32 || lp64 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target { int128 } } } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-9.c b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-9.c
index f2d71f6..ca9b425 100644
--- a/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-9.c
+++ b/gcc/testsuite/c-c++-common/ubsan/float-cast-overflow-9.c
@@ -6,30 +6,30 @@
#include "float-cast-overflow-8.c"
/* __float80 */
-/* { dg-output "value -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
+/* { dg-output " -129 is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* (-129|-1) is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -32769 is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* \[0-9.e+-]* is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
/* __float128 */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
-/* { dg-output "\[^\n\r]*value <unknown> is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'signed char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned char'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'short unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type 'long long unsigned int'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type '__int128'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
+/* { dg-output "\[^\n\r]* <unknown> is outside the range of representable values of type '__int128 unsigned'\[^\n\r]*(\n|\r\n|\r)" { target int128 } } */
diff --git a/gcc/testsuite/c-c++-common/ubsan/ptr-overflow-sanitization-1.c b/gcc/testsuite/c-c++-common/ubsan/ptr-overflow-sanitization-1.c
new file mode 100644
index 0000000..c12c7df
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/ptr-overflow-sanitization-1.c
@@ -0,0 +1,78 @@
+/* { dg-options "-O -fsanitize=pointer-overflow -fdump-tree-optimized" } */
+/* { dg-skip-if "" { *-*-* } "-flto" } */
+
+#define SMAX __PTRDIFF_MAX__
+
+void foo(void)
+{
+ char *p;
+ char *p2;
+ char b[1];
+ char c[1];
+
+ p = b + SMAX; /* pointer overflow check is needed */
+ p = b;
+ p++;
+ p2 = p + 1000;
+ p2 = p + 999;
+
+ p = b + SMAX;
+ p2 = p + 1; /* pointer overflow check is needed */
+
+ p = b;
+ p--; /* pointer overflow check is needed */
+ p2 = p + 1;
+ p2 = p + 2;
+
+ p = b - SMAX; /* pointer overflow check is needed */
+ p2 = p + (SMAX - 2); /* b - 2: pointer overflow check is needed */
+ p2 = p + (SMAX - 1); /* b - 1: pointer overflow check is needed */
+ p2 = p + SMAX; /* b: pointer overflow check is needed */
+ p2++; /* b + 1 */
+
+ p = c;
+ p++; /* c + 1 */
+ p = c - SMAX; /* pointer overflow check is needed */
+ p2 = p + SMAX; /* c: pointer overflow check is needed */
+ p2++; /* c + 1 */
+}
+
+void bar(char *ptr)
+{
+ char *p = ptr - 1000; /* pointer overflow check is needed */
+ p = ptr + 1000; /* pointer overflow check is needed */
+ p -= 2000; /* pointer overflow check is needed */
+}
+
+void baz(char *ptr)
+{
+ char **p = &ptr;
+ char **p2 = p + 20; /* pointer overflow check is needed */
+ p2--;
+}
+
+void positive_and_positive (char *ptr)
+{
+ char **p = &ptr;
+ char **p2 = p + 100; /* pointer overflow check is needed */
+ p2 = p + 10;
+ p += 50;
+}
+
+void negative_to_positive (char *ptr)
+{
+ char **p = &ptr;
+ char **p2 = p + 20; /* pointer overflow check is needed */
+ p2 = p - 10; /* pointer overflow check is needed */
+ p2 += 15;
+}
+
+void negative_to_negative (char *ptr)
+{
+ char **p = &ptr;
+ char **p2 = p - 20; /* pointer overflow check is needed */
+ p2 = p - 20;
+ p2 += 5;
+}
+
+/* { dg-final { scan-tree-dump-times "__ubsan_handle_pointer_overflow" 17 "optimized" } } */
diff --git a/gcc/testsuite/g++.dg/abi/mangle41.C b/gcc/testsuite/g++.dg/abi/mangle41.C
index 5fa47f1..9da72f1 100644
--- a/gcc/testsuite/g++.dg/abi/mangle41.C
+++ b/gcc/testsuite/g++.dg/abi/mangle41.C
@@ -3,6 +3,6 @@
// { dg-options "-mavx -fabi-version=2" }
#include <x86intrin.h>
-void f(__m128) { } // { dg-message "previous declaration" }
-void f(__m256) { } // { dg-error "conflicts" }
+void f(__m128) { } // { dg-message "previous mangling" }
+void f(__m256) { } // { dg-error "conflicts with a previous mangle" }
// { dg-message "mangling" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/asan/asan_test.C b/gcc/testsuite/g++.dg/asan/asan_test.C
index 410e4ce..f3f7626 100644
--- a/gcc/testsuite/g++.dg/asan/asan_test.C
+++ b/gcc/testsuite/g++.dg/asan/asan_test.C
@@ -8,6 +8,7 @@
// { dg-additional-options "-DASAN_AVOID_EXPENSIVE_TESTS=1" { target { ! run_expensive_tests } } }
// { dg-additional-options "-msse2" { target { i?86-*-linux* x86_64-*-linux* } } }
// { dg-additional-options "-D__NO_INLINE__" { target { *-*-linux-gnu } } }
+// { dg-set-target-env-var ASAN_OPTIONS "handle_segv=2" }
// { dg-final { asan-gtest } }
#include "asan_test.cc"
diff --git a/gcc/testsuite/g++.dg/asan/default-options-1.C b/gcc/testsuite/g++.dg/asan/default-options-1.C
index dc81891..98abdfb 100644
--- a/gcc/testsuite/g++.dg/asan/default-options-1.C
+++ b/gcc/testsuite/g++.dg/asan/default-options-1.C
@@ -3,7 +3,7 @@
const char *kAsanDefaultOptions="verbosity=1 foo=bar";
extern "C"
-__attribute__((no_sanitize_address))
+__attribute__((no_sanitize_address, used))
const char *__asan_default_options() {
return kAsanDefaultOptions;
}
diff --git a/gcc/testsuite/g++.dg/cet-notrack-1.C b/gcc/testsuite/g++.dg/cet-notrack-1.C
new file mode 100644
index 0000000..43dbbd6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cet-notrack-1.C
@@ -0,0 +1,25 @@
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fcf-protection -mcet" } */
+/* { dg-final { scan-assembler "endbr32|endbr64" } } */
+/* { dg-final { scan-assembler-times "\tcall\[ \t]+puts" 2 } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+" 1 } } */
+#include <stdio.h>
+
+struct A {
+virtual int foo() __attribute__((nocf_check)) { return 42; }
+};
+
+struct B : A {
+int foo() __attribute__((nocf_check)) { return 73; }
+};
+
+int main() {
+B b;
+A& a = b;
+int (A::*amem) () __attribute__((nocf_check)) = &A::foo; // take address
+if ((a.*amem)() == 73) // use the address
+ printf("pass\n");
+else
+ printf("fail\n");
+return 0;
+}
diff --git a/gcc/testsuite/g++.dg/concepts/pr71368.C b/gcc/testsuite/g++.dg/concepts/pr71368.C
new file mode 100644
index 0000000..f0e0a95
--- /dev/null
+++ b/gcc/testsuite/g++.dg/concepts/pr71368.C
@@ -0,0 +1,25 @@
+// { dg-options "-std=c++17 -fconcepts" }
+
+struct inner;
+
+template<typename X> concept bool CompoundReq = requires {
+ // fine with concrete type in trailing type, i.e. inner& instead of X&
+ { X::inner_member() } -> X&;
+};
+
+template<typename X> concept bool Concept = requires {
+ { X::outer_member() } -> CompoundReq;
+};
+
+struct inner { static inner& inner_member(); };
+struct outer { static inner outer_member(); };
+
+int main()
+{
+ // fine
+ static_assert( CompoundReq<inner> );
+ static_assert( CompoundReq<decltype( outer::outer_member() )> );
+
+ // ICE
+ static_assert( Concept<outer> );
+}
diff --git a/gcc/testsuite/g++.dg/concepts/req6.C b/gcc/testsuite/g++.dg/concepts/req6.C
index 670fd54..50fa3b4 100644
--- a/gcc/testsuite/g++.dg/concepts/req6.C
+++ b/gcc/testsuite/g++.dg/concepts/req6.C
@@ -4,7 +4,7 @@ struct X { };
int operator==(X, X) { return 0; }
template<typename T>
- concept bool C1() { return X(); }
+ concept bool C1() { return X(); } // { dg-error "bool" }
template<C1 T>
void h(T) { } // OK until used.
diff --git a/gcc/testsuite/g++.dg/cpp/string-3.C b/gcc/testsuite/g++.dg/cpp/string-3.C
new file mode 100644
index 0000000..ed9c42c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp/string-3.C
@@ -0,0 +1,9 @@
+// PR c++/82506
+// { dg-do preprocess { target c++11 } }
+
+#define STRINGIZE(A) #A
+
+BEGIN STRINGIZE(R"(
+)") END
+
+// { dg-final { scan-file string-3.i "BEGIN \"R\\\\\"\\(\\\\n\\)\\\\\"\"\n END" } }
diff --git a/gcc/testsuite/g++.dg/cpp0x/alignas12.C b/gcc/testsuite/g++.dg/cpp0x/alignas12.C
new file mode 100644
index 0000000..bc16344
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/alignas12.C
@@ -0,0 +1,6 @@
+// PR c++/71821
+// { dg-do compile { target c++11 } }
+
+template < typename > constexpr int f () { return 4; }
+
+alignas (f < int >) char c; // { dg-error "non-integral type" }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-61323.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-61323.C
new file mode 100644
index 0000000..f194bb8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-61323.C
@@ -0,0 +1,26 @@
+// PR c++/61323
+// { dg-do compile { target c++11 } }
+
+char* table1[10];
+template<unsigned size, char*(&table)[size]> void test1() { }
+void tester1() { test1<10,table1>(); }
+
+static char* table2[10];
+template<unsigned size, char*(&table)[size]> void test2() { }
+void tester2() { test2<10,table2>(); }
+
+const char* table3[10];
+template<unsigned size, const char*(&table)[size]> void test3() { }
+void tester3() { test3<10,table3>(); }
+
+const char* const table4[10] = {};
+template<unsigned size, const char*const (&table)[size]> void test4() { }
+void tester4() { test4<10,table4>(); }
+
+const char* volatile table5[10] = {};
+template<unsigned size, const char* volatile (&table)[size]> void test5() { }
+void tester5() { test5<10,table5>(); }
+
+const char* const table6[10] = {};
+template<unsigned size, const char*const (&table)[size]> void test6() { }
+void tester6() { test6<10,table6>(); }
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-64462.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-64462.C
index 69193fd..8200f87 100644
--- a/gcc/testsuite/g++.dg/cpp0x/constexpr-64462.C
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-64462.C
@@ -6,5 +6,5 @@ int z;
int main() {
constexpr int& y = x;
- [=] { z = y; }();
+ [] { z = y; }();
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-68754.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-68754.C
new file mode 100644
index 0000000..643fa07
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-68754.C
@@ -0,0 +1,7 @@
+// PR c++/68754
+// { dg-do compile { target c++11 } }
+
+struct base { };
+struct derived : base {
+ constexpr derived& operator=(derived const&) = default; // { dg-error "defaulted declaration" "" { target { ! c++14 } } }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor20.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor20.C
new file mode 100644
index 0000000..d5df3f6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ctor20.C
@@ -0,0 +1,8 @@
+// PR c++/64954
+// { dg-do compile { target c++11 } }
+
+struct A {};
+int main() {
+ A a;
+ constexpr A b = a;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-ice18.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice18.C
new file mode 100644
index 0000000..0b5ff70
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-ice18.C
@@ -0,0 +1,11 @@
+// PR c++/67831
+// { dg-do compile { target c++11 } }
+
+struct Task {
+ struct TaskStaticData {
+ constexpr TaskStaticData() {}
+ } const &tsd;
+ constexpr Task() : tsd(TaskStaticData()) {}
+};
+
+Task tasks{Task()};
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum35.C b/gcc/testsuite/g++.dg/cpp0x/enum35.C
new file mode 100644
index 0000000..bcc1b26
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/enum35.C
@@ -0,0 +1,14 @@
+// PR c++/82307
+// { dg-do run { target c++11 } }
+
+#include <cassert>
+
+enum : unsigned long long { VAL };
+
+bool foo (unsigned long long) { return true; }
+bool foo (int) { return false; }
+
+int main()
+{
+ assert (foo(VAL));
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/enum36.C b/gcc/testsuite/g++.dg/cpp0x/enum36.C
new file mode 100644
index 0000000..4859670
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/enum36.C
@@ -0,0 +1,14 @@
+// PR c++/82307
+// { dg-do run { target c++11 } }
+
+#include <cassert>
+
+enum : short { VAL };
+
+bool foo (int) { return true; }
+bool foo (unsigned long long) { return false; }
+
+int main()
+{
+ assert (foo (VAL));
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/error1.C b/gcc/testsuite/g++.dg/cpp0x/error1.C
index 33557f2..115d800 100644
--- a/gcc/testsuite/g++.dg/cpp0x/error1.C
+++ b/gcc/testsuite/g++.dg/cpp0x/error1.C
@@ -1,10 +1,17 @@
// PR c++/34395
// { dg-do compile { target c++11 } }
-template<int... N> void foo (int... x[N]) // { dg-message "int \\\[N\\\]\\.\\.\\. x" }
+void f(...);
+template<int... N> void foo (int... x[N]) // { dg-message "declared here" }
{
struct A
{
- A () { x; } // { dg-error "use of parameter from containing function" }
+ A () { f(x...); } // { dg-error "use of parameter from containing function" }
};
}
+
+int main()
+{
+ int ar[4];
+ foo<4>(ar);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-70343.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-70343.C
new file mode 100644
index 0000000..209e207
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-70343.C
@@ -0,0 +1,24 @@
+// PR c++/70343
+// { dg-do run { target c++11 } }
+
+struct Empty{};
+
+template<class T>
+struct Data{
+ int x;
+ float y;
+
+ int properties_parcel4[10];
+
+ Empty j = [&](){
+ int i = 10;
+ properties_parcel4[0] = i;
+ return Empty();
+ }();
+};
+
+int main () {
+ Data<int> k;
+
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-asm1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-asm1.C
new file mode 100644
index 0000000..ef0b125
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-asm1.C
@@ -0,0 +1,4 @@
+// PR c++/71946
+// { dg-do compile { target c++11 } }
+
+auto test = []{ __asm__ __volatile__ ("" : : "r" (0) ); };
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-redundancy.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-redundancy.C
index 49fbdf3..baeb814 100644
--- a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-redundancy.C
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-capture-redundancy.C
@@ -7,7 +7,7 @@ void S2::f(int i) {
[&, i]{ }; // OK
[&, &i]{ }; // { dg-error "" } i preceded by & when & is the default
[=, i]{ }; // { dg-error "" } i not preceded by & when = is the default
- [=, this]{ }; // { dg-error "" } this when = is the default
+ [=, this]{ }; // { dg-error "" "" { target c++17_down } } this when = is the default
[i, i]{ }; // { dg-error "" } i repeated
[this, this]{ }; // { dg-error "" } i repeated
}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const6.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const6.C
new file mode 100644
index 0000000..4edfb70
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const6.C
@@ -0,0 +1,15 @@
+// PR c++/56973
+// { dg-do compile { target c++11 } }
+
+int f()
+{
+ const int i = 42;
+ auto j = *[=]{ return &i; }();
+ auto k = []{ return i; }();
+ return j+k;
+}
+
+int main()
+{
+ return f() != 84;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const7.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const7.C
new file mode 100644
index 0000000..64a37b8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-const7.C
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+// { dg-options -w }
+
+int main()
+{
+ const int i = 4;
+ [] { constexpr int x = i; };
+ [=] { &i; constexpr int x = i; };
+ [&] { &i; constexpr int x = i; };
+ [i] { &i; constexpr int x = i; };
+ [&i] { &i; constexpr int x = i; };
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice22.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice22.C
new file mode 100644
index 0000000..6f2650d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice22.C
@@ -0,0 +1,25 @@
+// PR c++/79488
+// { dg-do compile { target c++11 } }
+
+int f();
+static int g __attribute__((__weakref__("f")));
+
+template <typename Fn> struct res {
+ static Fn val();
+ using type = decltype(val()()); // { dg-error "no match for call" }
+};
+
+template <typename Fn> struct A {
+ template <typename T> void set_result(T) {}
+
+ virtual void run() {
+ auto boundfn = []() -> typename res<Fn>::type{};
+ set_result(boundfn);
+ }
+};
+
+struct F {
+ void operator()() &;
+};
+
+A<F> t;
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice23.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice23.C
new file mode 100644
index 0000000..b811ad2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-ice23.C
@@ -0,0 +1,13 @@
+// PR c++/59991
+// { dg-do compile { target c++11 } }
+
+template <typename T>
+constexpr int r(T x) {
+ auto f = [r,x]() { return r(x); }; // { dg-error "incomplete type" }
+ return 0;
+}
+
+int main()
+{
+ r(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested8.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested8.C
new file mode 100644
index 0000000..5a6f47c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-nested8.C
@@ -0,0 +1,23 @@
+// PR c++/79180
+// { dg-do run { target c++11 } }
+
+void
+foo (int a)
+{
+ if (a != 127)
+ __builtin_abort ();
+}
+
+template <typename... Args>
+void
+bar (Args &&... args)
+{
+ [&]() { [&]() { foo (args...); } (); } ();
+}
+
+int
+main ()
+{
+ int x = 127;
+ bar (x);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-stmtexpr1.C b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-stmtexpr1.C
new file mode 100644
index 0000000..e461db6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/lambda/lambda-stmtexpr1.C
@@ -0,0 +1,5 @@
+// PR c++/71946
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+auto test = []{ int t = ({ int t1; t1 = 7; t1; }); };
diff --git a/gcc/testsuite/g++.dg/cpp0x/noexcept31.C b/gcc/testsuite/g++.dg/cpp0x/noexcept31.C
new file mode 100644
index 0000000..c4c0e7d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/noexcept31.C
@@ -0,0 +1,12 @@
+// PR c++/77369
+// { dg-do compile { target c++11 } }
+
+template<typename F> int caller(F f) noexcept(noexcept(f())) { f(); return 0; }
+
+void func1() noexcept { }
+
+void func2() { throw 1; }
+
+int instantiate_caller_with_func1 = caller(func1);
+
+static_assert( !noexcept(caller(func2)), "" );
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr67625.C b/gcc/testsuite/g++.dg/cpp0x/pr67625.C
new file mode 100644
index 0000000..bcff5af
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr67625.C
@@ -0,0 +1,12 @@
+// PR c++/67625
+// { dg-do compile { target c++11 } }
+
+constexpr unsigned short
+bswap16 (unsigned short x)
+{
+ return __builtin_bswap16 (x);
+}
+constexpr int a = bswap16 (1);
+enum { b = a };
+enum { c = __builtin_bswap16 (1) };
+enum { d = bswap16 (1) };
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr70338.C b/gcc/testsuite/g++.dg/cpp0x/pr70338.C
new file mode 100644
index 0000000..156cb91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr70338.C
@@ -0,0 +1,17 @@
+// PR c++/70338
+// { dg-do compile { target c++11 } }
+// { dg-options "-g" }
+
+template<typename T>
+void
+foo (int x)
+{
+ T a[x];
+ auto b = [&]() { for (auto &c: a) c = 0.; };
+}
+
+int
+main ()
+{
+ foo<double> (3);
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr70887.C b/gcc/testsuite/g++.dg/cpp0x/pr70887.C
new file mode 100644
index 0000000..f5b31b2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr70887.C
@@ -0,0 +1,31 @@
+// PR middle-end/70887
+// { dg-do compile { target { { i?86-*-* x86_64-*-* } && c++11 } } }
+// { dg-options "-O2 -msse2" }
+
+#include <x86intrin.h>
+
+enum R { S };
+template <R> struct C { static constexpr int value = 10; };
+template <typename R, template <R> class T, R... r>
+struct A {
+ template <int, R...> struct B;
+ template <int N, R M, R... O>
+ struct B<N, M, O...> {
+ static constexpr int d = T<M>::value;
+ static __m128i generate()
+ {
+ __attribute__((__vector_size__(16))) long long
+ a = generate(),
+ b = _mm_bslli_si128 (a, 1),
+ c = _mm_bsrli_si128 (_mm_set1_epi32(d), 12);
+ return _mm_or_si128 (b, c);
+ }
+ };
+ A () { B<0, r...>::generate(); }
+};
+
+int
+main () {
+ using RI = A<R, C, S>;
+ RI ri;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr80805.C b/gcc/testsuite/g++.dg/cpp0x/pr80805.C
new file mode 100644
index 0000000..a13ee11
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr80805.C
@@ -0,0 +1,21 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-g" }
+
+template<class T> struct R { using type = T; };
+template<class F> F r(typename R<F>::type f) { return f; }
+template<class F> void s(F) {}
+template<bool, class F> void t(F f) { s(r<F>(f)); }
+template<bool> struct S {};
+template<class> struct P { constexpr static bool value = false; };
+template<class D>
+void g()
+{
+ constexpr static bool H = P<D>::value;
+ using X = S<H>;
+ []() -> X
+ {
+ t<false>([]{});
+ return X{};
+ }();
+}
+int main() { g<int>(); }
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr82299.C b/gcc/testsuite/g++.dg/cpp0x/pr82299.C
new file mode 100644
index 0000000..27f4c5f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr82299.C
@@ -0,0 +1,9 @@
+// PR c++/82299
+// { dg-do compile { target c++11 } }
+// { dg-options "-Wuseless-cast" }
+
+enum Enum : char { A = 0, B = 1 };
+
+struct S {
+ Enum e { Enum::A }; // { dg-bogus "useless cast to type" }
+};
diff --git a/gcc/testsuite/g++.dg/cpp0x/pr82560.C b/gcc/testsuite/g++.dg/cpp0x/pr82560.C
new file mode 100644
index 0000000..3408bae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/pr82560.C
@@ -0,0 +1,28 @@
+// { dg-do run { target c++11 } }
+// PR82560, failed to destruct default arg inside new
+
+static int liveness = 0;
+
+struct Foo {
+
+ Foo (int) {
+ liveness++;
+ }
+
+ ~Foo() {
+ liveness--;
+ }
+
+};
+
+struct Bar {
+ Bar (Foo = 0) { }
+ ~Bar() { }
+};
+
+int main()
+{
+ delete new Bar();
+
+ return liveness != 0;;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C b/gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C
new file mode 100644
index 0000000..d47a49c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/udlit-extern-c.C
@@ -0,0 +1,7 @@
+// { dg-do compile { target c++11 } }
+
+extern "C" { // { dg-message "1: 'extern .C.' linkage started here" }
+
+constexpr double operator"" _deg ( double degrees ); // { dg-error "literal operator with C linkage" }
+
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-crash3.C b/gcc/testsuite/g++.dg/cpp0x/variadic-crash3.C
new file mode 100644
index 0000000..b825067
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-crash3.C
@@ -0,0 +1,32 @@
+// PR c++/60153
+// { dg-do compile { target c++11 } }
+
+enum class foo :int {x,y,z};
+
+template <int a, foo b>
+class A
+{
+public:
+ A()
+ {
+ }
+};
+
+template <typename T>
+struct B
+{
+ typedef T value_type;
+ static const T val;
+};
+
+template <typename... B>
+struct madscience_intitializer
+{
+ template <typename B::value_type... args>
+ using ret_type = A<args...>;
+};
+
+int main()
+{
+ madscience_intitializer<B<int>,B<foo> >::ret_type<1,foo::y> a;
+}
diff --git a/gcc/testsuite/g++.dg/cpp0x/variadic-crash4.C b/gcc/testsuite/g++.dg/cpp0x/variadic-crash4.C
new file mode 100644
index 0000000..2974fe9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/variadic-crash4.C
@@ -0,0 +1,14 @@
+// PR c++/68884
+// { dg-do compile { target c++11 } }
+
+namespace std {
+ template <typename _Tp, _Tp __v> struct A { static constexpr _Tp value = __v; };
+typedef A<bool, true> true_type;
+}
+template <int> struct VsA;
+template <class ValueType> struct ValueTemplate {
+ template <template <ValueType> class, class> struct IsInstanceOf;
+ template <template <ValueType> class TemplateA, ValueType... TypesA>
+ struct IsInstanceOf<TemplateA, TemplateA<TypesA...>> : std::true_type {};
+};
+bool foo = ValueTemplate<int>::IsInstanceOf<VsA, VsA<0>>::value;
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn40.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn40.C
new file mode 100644
index 0000000..e7f1bd4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn40.C
@@ -0,0 +1,37 @@
+// PR c++/78006
+// { dg-do compile { target c++14 } }
+
+template<typename T> T&& declval() noexcept;
+
+template<typename... _Tp>
+ struct common_type;
+
+template<typename _Tp>
+ struct common_type<_Tp>
+ { typedef _Tp type; };
+
+template<typename _Tp, typename _Up>
+ struct common_type<_Tp, _Up>
+ { typedef decltype(true ? declval<_Tp>() : declval<_Up>()) type; };
+
+template<typename _Tp, typename _Up, typename... _Vp>
+ struct common_type<_Tp, _Up, _Vp...>
+ {
+ typedef typename
+ common_type<typename common_type<_Tp, _Up>::type, _Vp...>::type type;
+ };
+
+template<typename... _Tp>
+ using common_type_t = typename common_type<_Tp...>::type;
+
+template <typename... TFs>
+auto x(TFs&&... fs)
+{
+ using rt = common_type_t<decltype(fs(0))...>;
+ return [](auto) -> rt { };
+}
+
+int main()
+{
+ x([](int){})(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn41.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn41.C
new file mode 100644
index 0000000..25a879d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn41.C
@@ -0,0 +1,23 @@
+// PR c++/80873
+// { dg-do compile { target c++14 } }
+
+struct S {};
+
+auto overloaded(S &);
+
+template <typename T>
+int overloaded(T &) {
+ return 0;
+}
+
+template <typename T>
+auto returns_lambda(T &param) {
+ return [&] {
+ overloaded(param); // { dg-error "before deduction" }
+ };
+}
+
+int main() {
+ S s;
+ returns_lambda(s);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn42.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn42.C
new file mode 100644
index 0000000..0f2b68e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn42.C
@@ -0,0 +1,21 @@
+// PR c++/80873
+// { dg-do compile { target c++14 } }
+
+struct Buffer {};
+
+auto parse(Buffer b);
+template <typename T> void parse(T target);
+
+template <typename T>
+auto field(T target) {
+ return [&] {
+ parse(target);
+ };
+}
+
+template <typename T>
+void parse(T target) {}
+
+auto parse(Buffer b) {
+ field(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn43.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn43.C
new file mode 100644
index 0000000..7256ecb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn43.C
@@ -0,0 +1,13 @@
+// PR c++/64931
+// { dg-do compile { target c++14 } }
+
+template<typename T>
+struct S {
+ T data[32];
+};
+
+auto
+foo (S<int> & x)
+{
+ return x;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn44.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn44.C
new file mode 100644
index 0000000..e35215d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn44.C
@@ -0,0 +1,12 @@
+// PR c++/79474
+// { dg-do compile { target c++14 } }
+
+struct Funject
+{
+ operator auto() { return +[](bool b) {return b;}; }
+ operator auto() { return +[](bool b, bool, bool) {return b;}; } // { dg-error "cannot be overloaded" }
+};
+
+Funject fun;
+auto bbb = fun(true);
+auto bbbb = fun(true, false, true); // { dg-error "no match" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/auto-fn45.C b/gcc/testsuite/g++.dg/cpp1y/auto-fn45.C
new file mode 100644
index 0000000..a9c163d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/auto-fn45.C
@@ -0,0 +1,27 @@
+// PR c++/69057
+// { dg-do compile { target c++14 } }
+
+#include <cassert>
+
+using GLenum = unsigned int;
+
+template <typename T>
+inline constexpr auto from_enum(const T& x) noexcept
+{
+ // Comment this line to prevent segmentation fault:
+ assert(true);
+ // ------------------------------------------------
+
+ return (GLenum)x;
+}
+
+enum class buffer_target : GLenum
+{
+ array
+};
+
+struct vbo
+{
+ static constexpr GLenum target_value{from_enum(buffer_target::array)};
+ GLenum x{target_value};
+};
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-68754.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-68754.C
deleted file mode 100644
index e72acb1..0000000
--- a/gcc/testsuite/g++.dg/cpp1y/constexpr-68754.C
+++ /dev/null
@@ -1,7 +0,0 @@
-// PR c++/68754
-// { dg-do compile { target c++14 } }
-
-struct base { };
-struct derived : base {
- constexpr derived& operator=(derived const&) = default;
-};
diff --git a/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C b/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C
index 833fab7..727e74e 100644
--- a/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C
+++ b/gcc/testsuite/g++.dg/cpp1y/digit-sep-neg.C
@@ -26,5 +26,5 @@ main()
}
// { dg-error "exponent has no digits" "exponent has no digits" { target *-*-* } 21 }
-// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 14 }
-// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 25 }
+// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 13 }
+// { dg-error "expected ';' before" "expected ';' before" { target *-*-* } 24 }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69078-1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69078-1.C
new file mode 100644
index 0000000..dc045c7
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69078-1.C
@@ -0,0 +1,28 @@
+// PR c++/69078
+// { dg-do run { target c++14 } }
+// { dg-options "-Wall" }
+
+#include <cassert>
+
+struct Class {
+ Class(void (*_param)()) : data(_param) {}
+ void (*data)();
+};
+
+void funUser(void (*test)(int)) {
+ test(60);
+}
+
+void user(Class& c, int i) {
+ (void)i;
+ assert (c.data);
+}
+
+void probe() {}
+
+int main() {
+ static Class instance = { probe };
+ funUser([](auto... p) {
+ user(instance, p...);
+ });
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69078-2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69078-2.C
new file mode 100644
index 0000000..318e096
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69078-2.C
@@ -0,0 +1,21 @@
+// PR c++/69078
+// { dg-do run { target c++14 } }
+
+#include <cassert>
+
+template<typename F>
+void run( F &&f ) {
+ f(nullptr);
+}
+
+struct V {
+ int i;
+};
+
+int main() {
+ static V const s={2};
+ assert (s.i == 2);
+ run([](auto){
+ assert (s.i == 2);
+ });
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69977.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69977.C
new file mode 100644
index 0000000..5f491da
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-69977.C
@@ -0,0 +1,23 @@
+// PR c++/69977
+// { dg-do compile { target c++14 } }
+
+class A {
+private:
+ void method(int i) {
+ (void) i;
+ }
+
+public:
+ void publicMethod() {
+ auto lambda = [&] (const auto k) {
+ method(k);
+ };
+ lambda(42);
+ }
+};
+
+int main()
+{
+ A a;
+ a.publicMethod();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-70570.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-70570.C
new file mode 100644
index 0000000..debe341
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-70570.C
@@ -0,0 +1,16 @@
+// PR c++/70570
+// { dg-do assemble { target c++14 } }
+
+template<typename T> void foo(T f) {
+ f(1);
+}
+
+int main() {
+ static const int x = 42;
+ foo([](auto y){
+ x;
+ [](){
+ x;
+ };
+ });
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-78018.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-78018.C
new file mode 100644
index 0000000..6cf9c59
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-78018.C
@@ -0,0 +1,37 @@
+// PR c++/78018
+// { dg-do compile { target c++14 } }
+
+struct A
+{
+ void f1();
+
+ template <typename F>
+ void f2(F f);
+
+ template<typename T>
+ void f3(T t);
+};
+
+struct B
+{
+ template<typename L>
+ void f(L) { }
+};
+
+void A::f1()
+{
+ f2([&] (auto t) { f3(t); } );
+}
+
+template <typename F>
+void A::f2(F f)
+{
+ B b;
+ f(b);
+}
+
+template<typename T>
+void A::f3(T t)
+{
+}
+
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-79005.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-79005.C
new file mode 100644
index 0000000..79b89ca
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-79005.C
@@ -0,0 +1,21 @@
+// PR c++/79005
+// { dg-do compile { target c++14 } }
+
+int main()
+{
+ auto glambda = [] (auto a)
+ {
+ const int c = a;
+ auto cglambda = [&] ( auto b )
+ {
+ double result;
+ result = b * a;
+ result = b * c;
+ return result;
+ };
+ cglambda ( 1 );
+ a = c;
+ };
+
+ glambda( 1 );
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
new file mode 100644
index 0000000..b9e98c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-auto1.C
@@ -0,0 +1,19 @@
+// Related to c++/81525
+// { dg-do compile { target c++14 } }
+
+template <class X>
+struct A
+{
+ template <class T>
+ static void f()
+ {
+ [](auto b) {
+ auto c = +b;
+ }(42);
+ }
+};
+
+int main()
+{
+ A<int>::f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C
index 52f4373..1cf8551 100644
--- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4.C
@@ -1,5 +1,5 @@
// PR c++/81525
-// { dg-do compile { target c++14 } }
+// { dg-do run { target c++14 } }
template <int i> struct A {
constexpr operator int () const { return i; }
@@ -13,7 +13,7 @@ template <typename T>
void bar (T) {
constexpr auto N = a<1>;
auto f = [&] (auto i) {
- static_assert (static_cast<int>(N) == 1, "");
+ if (static_cast<int>(N) != 1) __builtin_abort();
};
foo (f);
}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4a.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4a.C
new file mode 100644
index 0000000..a6afb32
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-const4a.C
@@ -0,0 +1,20 @@
+// PR c++/81525
+// { dg-do run { target c++14 } }
+
+template <int i> struct A {
+ constexpr operator int () const { return i; }
+};
+template <int i> constexpr A<i> a = {};
+
+template <typename F> void foo (F f) {
+ f (42);
+}
+template <typename T>
+void bar (T) {
+ constexpr auto N = a<1>;
+ auto f = [&] (auto i) {
+ if (static_cast<decltype(i)>(N) != 1) __builtin_abort();
+ };
+ foo (f);
+}
+int main () { bar (0); }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep2.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep2.C
new file mode 100644
index 0000000..91e3804
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-dep2.C
@@ -0,0 +1,18 @@
+// { dg-do compile { target c++14 } }
+
+struct A { void operator()(int) const {} };
+
+template <class T>
+void f()
+{
+ constexpr A a {};
+
+ [=](auto b) {
+ a(b);
+ }(42);
+}
+
+int main()
+{
+ f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice5.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice5.C
index 473e412..88b7d1a 100644
--- a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice5.C
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice5.C
@@ -12,7 +12,7 @@ using Void = void;
template<typename F,typename A>
auto
-bar(F f, A a) -> decltype( ( f(a) , 0 ) ) // { dg-error "no match" }
+bar(F f, A a) -> decltype( ( f(a) , 0 ) ) // { dg-message "" }
{ return {}; }
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice6.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice6.C
new file mode 100644
index 0000000..6851afc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice6.C
@@ -0,0 +1,13 @@
+// PR c++/81032
+// { dg-do compile { target c++14 } }
+
+template<typename T> constexpr void foo(T t)
+{
+ constexpr int i = t; // { dg-error "constant" }
+ [=](auto){ return i; }(0);
+}
+
+void bar()
+{
+ foo(0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice7.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice7.C
new file mode 100644
index 0000000..fa0fe1d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice7.C
@@ -0,0 +1,15 @@
+// PR c++/81299
+// { dg-do compile { target c++14 } }
+// { dg-options "-Wall" }
+
+struct function_t {
+ template <typename ...Xs>
+ void operator()(Xs&& ...) const { }
+};
+constexpr function_t function{};
+
+int main() {
+ constexpr auto fun = ::function;
+ auto call = [=](auto ...x) { fun(x...); };
+ call();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice8.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice8.C
new file mode 100644
index 0000000..a39ce44
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-ice8.C
@@ -0,0 +1,16 @@
+// PR c++/82230
+// { dg-do compile { target c++14 } }
+
+template <class>
+ struct c
+ {
+ template <class>
+ void f()
+ {
+ [](auto) { auto x = [] {}; }(0);
+ }
+};
+int main()
+{
+ c<int>{}.f<int>();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-nested1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-nested1.C
new file mode 100644
index 0000000..4cfd353
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-nested1.C
@@ -0,0 +1,34 @@
+// PR c++/71386
+// { dg-do run { target c++14 } }
+
+template<class...XS>
+auto List(XS...xs)
+{
+ return [=](auto processList){return processList(xs...);};
+}
+
+auto l1 = List(42);
+
+int test (int a)
+{
+ if (a != 42)
+ __builtin_abort ();
+ return 0;
+}
+
+auto foo = [](auto... xs1)
+ {
+ return [=]()
+ {
+ return l1([=](auto)
+ {
+ return test (xs1...);
+ });
+ };
+ };
+
+int main()
+{
+ auto concat = l1(foo);
+ concat();
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-noexcept1.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-noexcept1.C
new file mode 100644
index 0000000..082aff9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-noexcept1.C
@@ -0,0 +1,10 @@
+// PR c++/79590
+// { dg-do compile { target c++14 } }
+
+auto f = [](auto x) noexcept(noexcept(x)) { };
+
+int main()
+{
+ [](auto x) noexcept(noexcept(x)) { } (0);
+ [](auto) noexcept(noexcept(0)) { } (0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic5.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic5.C
new file mode 100644
index 0000000..6dbb9c8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic5.C
@@ -0,0 +1,61 @@
+// PR c++/65949
+// { dg-do compile { target c++14 } }
+
+#include <initializer_list>
+
+template<class T, class... Ts>
+struct Over : T, Over<Ts...>::type
+{
+ using type = Over;
+
+ Over(T f1, Ts... f2)
+ : T(f1), Over<Ts...>::type(f2...)
+ {
+ }
+
+ using T::operator();
+ using Over<Ts...>::type::operator();
+};
+
+template<class T>
+struct Over<T> : T
+{
+ using type = T;
+ using T::operator();
+};
+
+template <class... Lambdas>
+auto CreateLambdas(Lambdas... lambdas)
+{
+ return Over<Lambdas...>(lambdas...);
+}
+
+int main()
+{
+ auto mesLambda = CreateLambdas
+ (
+ []()
+ {
+
+ },
+
+ [](auto i)
+ {
+ (void)i;
+ },
+
+ [](auto... args)
+ {
+ auto list = {args...};
+
+ for(auto &&a : list)
+ (void)a;
+
+ return 3;
+ }
+ );
+
+ mesLambda();
+ mesLambda(1);
+ mesLambda(12,24,36,48);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic6.C b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic6.C
new file mode 100644
index 0000000..d6672a4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/lambda-generic-variadic6.C
@@ -0,0 +1,19 @@
+// PR c++/78816
+// { dg-do compile { target c++14 } }
+
+void f(void (*f1)(int)) {
+ f1(42);
+}
+
+template <typename Lambda>
+static auto callback(Lambda &&l)
+{
+ static auto* p = &l;
+ p = &l;
+ return [](auto... x){ return (*p)(x...); };
+}
+
+int main() {
+ int x = 5;
+ f(callback([=](int y){}));
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr65202.C b/gcc/testsuite/g++.dg/cpp1y/pr65202.C
index 602b264..7ce4895 100644
--- a/gcc/testsuite/g++.dg/cpp1y/pr65202.C
+++ b/gcc/testsuite/g++.dg/cpp1y/pr65202.C
@@ -22,5 +22,5 @@ struct bar;
int main()
{
foo<ns::bar> f;
- adl::swap(f, f)
-} // { dg-error "" }
+ adl::swap(f, f) // { dg-error "expected ';'" }
+} // { dg-error "expected '.'" "expected end of namespace" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr66690.C b/gcc/testsuite/g++.dg/cpp1y/pr66690.C
new file mode 100644
index 0000000..3e32aa3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr66690.C
@@ -0,0 +1,14 @@
+// PR c++/66690
+// { dg-do compile { target c++14 } }
+
+template<class T> auto foo(T t) {return 3;}
+class B {B();}; // { dg-message "declared private" }
+template<class T> class D:public B
+{
+ D() // { dg-message "declared private" }
+ { // { dg-error "is private" }
+ T x00;
+ foo(x00);
+ }
+};
+D<int> d; // { dg-error "is private" }
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr71875.C b/gcc/testsuite/g++.dg/cpp1y/pr71875.C
new file mode 100644
index 0000000..4d31796
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr71875.C
@@ -0,0 +1,24 @@
+// PR c++/71875
+// { dg-do link { target c++14 } }
+
+template <typename T>
+constexpr bool IsMatrix = false;
+
+template<typename TElem>
+class Matrix {};
+
+template <typename TElem>
+constexpr bool IsMatrix<Matrix<TElem>> = true;
+
+template<typename TNestVec>
+class RowVecExpMatrix;
+
+template <typename TNestVec>
+constexpr bool IsMatrix<RowVecExpMatrix<TNestVec>> = true;
+
+int
+main ()
+{
+ static_assert (IsMatrix<RowVecExpMatrix<Matrix<int>>>, "Matrix check error");
+ static_assert (IsMatrix<Matrix<int>>, "Input type is not a matrix");
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr77786.C b/gcc/testsuite/g++.dg/cpp1y/pr77786.C
new file mode 100644
index 0000000..e242228
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr77786.C
@@ -0,0 +1,21 @@
+// PR c++/77786
+// { dg-do compile { target c++14 } }
+
+#include <vector>
+
+template<int N>
+void
+foo (std::vector<int> a)
+{
+ auto const a_size = a.size();
+ auto bar = [&](auto y) -> void { int a_size_2 = a_size; };
+ double x = 0.0;
+ bar (x);
+}
+
+int
+main ()
+{
+ std::vector<int> a(1);
+ foo<1>(a);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr78523.C b/gcc/testsuite/g++.dg/cpp1y/pr78523.C
new file mode 100644
index 0000000..31e0cc8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr78523.C
@@ -0,0 +1,12 @@
+// PR c++/78523
+// { dg-do compile { target c++14 } }
+
+int bar ();
+
+void
+foo ()
+{
+ const int t = bar ();
+ auto f = [=] (auto x) { return t; };
+ f (0);
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr80194.C b/gcc/testsuite/g++.dg/cpp1y/pr80194.C
new file mode 100644
index 0000000..2a892c3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr80194.C
@@ -0,0 +1,17 @@
+// PR c++/80194
+// { dg-do compile { target c++14 } }
+
+int fn1 ();
+
+template <class Fn>
+void
+fn2 (Fn &&fn)
+{
+ fn (42);
+}
+
+void fn2 ()
+{
+ auto const x = fn1 ();
+ fn2 ([&](auto) { x; });
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr80471.C b/gcc/testsuite/g++.dg/cpp1y/pr80471.C
new file mode 100644
index 0000000..bca4022
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr80471.C
@@ -0,0 +1,23 @@
+// PR c++/80471
+// { dg-do compile { target c++14 } }
+// { dg-options "" }
+
+template <class, class>
+constexpr bool is_same = false;
+template <class T>
+constexpr bool is_same<T, T> = true;
+
+template<class T>
+decltype(auto) f(T&& a){return a;}
+
+decltype(auto) g(auto&& a){return a;}
+
+auto z = [](auto&& a) -> decltype(auto) { return a; };
+
+int main()
+{
+ int i;
+ static_assert(is_same< decltype(f(i)), int& >, "");
+ static_assert(is_same< decltype(g(i)), int >, "");
+ static_assert(is_same< decltype(z(i)), int& >, "");
+}
diff --git a/gcc/testsuite/g++.dg/cpp1y/pr82373.C b/gcc/testsuite/g++.dg/cpp1y/pr82373.C
new file mode 100644
index 0000000..8a2d755
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1y/pr82373.C
@@ -0,0 +1,20 @@
+// PR c++/82373
+// { dg-do compile { target c++14 } }
+
+namespace N
+{
+ int (*fp)(int);
+ auto foo(int a) // { dg-message "In function 'auto N::foo\\(int\\)'" "" { target *-*-* } 0 }
+ {
+ if (a)
+ return fp;
+ return nullptr; // { dg-error "inconsistent deduction for auto return type: 'int \\(\\*\\)\\(int\\)' and then 'std::nullptr_t'" } */
+ }
+}
+int (*fp2)(int);
+auto bar(int a) // { dg-message "In function 'auto bar\\(int\\)'" "" { target *-*-* } 0 }
+{
+ if (a)
+ return fp2;
+ return nullptr; // { dg-error "inconsistent deduction for auto return type: 'int \\(\\*\\)\\(int\\)' and then 'std::nullptr_t'" } */
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction44.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction44.C
new file mode 100644
index 0000000..1571197
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction44.C
@@ -0,0 +1,5 @@
+// PR c++/80412
+// { dg-options -std=c++17 }
+
+template <typename> struct A;
+template <typename> struct B : A < B { , // { dg-error "" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction45.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction45.C
new file mode 100644
index 0000000..3fe8dd3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction45.C
@@ -0,0 +1,24 @@
+// PR c++/82308
+// { dg-options -std=c++17 }
+
+template<typename, unsigned>
+struct array {};
+
+template <unsigned R>
+class X {
+public:
+ using T = array<int, R>;
+
+ enum class C : char { A, B };
+ X(T bounds, C c = C::B) : t(bounds) {}
+
+private:
+ T t;
+};
+
+int main()
+{
+ array<int, 2> a;
+ X d{a};
+ X<2> e{a};
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/class-deduction46.C b/gcc/testsuite/g++.dg/cpp1z/class-deduction46.C
new file mode 100644
index 0000000..cf38ed6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/class-deduction46.C
@@ -0,0 +1,6 @@
+// PR c++/80449
+// { dg-options -std=c++17 }
+
+template<class S> struct C;
+template<> struct C<int> { C(int, int) {} };
+auto k = C{0, 0}; // { dg-error "cannot deduce" }
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda17.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda17.C
new file mode 100644
index 0000000..44bd2b8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda17.C
@@ -0,0 +1,30 @@
+// PR c++/78131
+// { dg-options -std=c++17 }
+
+template <typename TF>
+constexpr auto f(TF)
+{
+ return [](auto...) constexpr { return true; };
+}
+
+// Compiles and works as intended.
+template <typename T0>
+void ok_0(T0)
+{
+ static_assert(f([](auto x) -> decltype(x){})(T0{}));
+}
+
+// Compiles and works as intended.
+template <typename T0>
+void ok_1(T0)
+{
+ constexpr auto a = f([](auto x) -> decltype(x){})(T0{});
+ if constexpr(a) { }
+}
+
+// Compile-time error!
+template <typename T0>
+void fail_0(T0)
+{
+ if constexpr(f([](auto x) -> decltype(x){})(T0{})) { }
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda18.C b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda18.C
new file mode 100644
index 0000000..639018b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/constexpr-lambda18.C
@@ -0,0 +1,30 @@
+// PR c++/82570
+// { dg-options "-std=c++17" }
+
+template< typename Body >
+inline void iterate(Body body)
+{
+ body(10);
+}
+
+template< typename Pred >
+inline void foo(Pred pred)
+{
+ iterate([&](int param)
+ {
+ if (pred(param))
+ {
+ unsigned char buf[4];
+ buf[0] = 0;
+ buf[1] = 1;
+ buf[2] = 2;
+ buf[3] = 3;
+ }
+ });
+}
+
+int main()
+{
+ foo([](int x) { return x > 0; });
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/cplusplus.C b/gcc/testsuite/g++.dg/cpp1z/cplusplus.C
index 0d0ac14..bc6139b 100644
--- a/gcc/testsuite/g++.dg/cpp1z/cplusplus.C
+++ b/gcc/testsuite/g++.dg/cpp1z/cplusplus.C
@@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-std=c++17" }
-#if __cplusplus <= 201402L
-#error "__cplusplus <= 201402L"
+#if __cplusplus != 201703L
+#error "__cplusplus != 201703L"
#endif
diff --git a/gcc/testsuite/g++.dg/cpp1z/cplusplus_1z.C b/gcc/testsuite/g++.dg/cpp1z/cplusplus_1z.C
new file mode 100644
index 0000000..aecbc1e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/cplusplus_1z.C
@@ -0,0 +1,6 @@
+// { dg-do compile }
+// { dg-options "-std=c++1z" }
+
+#if __cplusplus != 201703L
+#error "__cplusplus != 201703L"
+#endif
diff --git a/gcc/testsuite/g++.dg/cpp1z/lambda-this1.C b/gcc/testsuite/g++.dg/cpp1z/lambda-this1.C
index 5a4c5f9..a154380 100644
--- a/gcc/testsuite/g++.dg/cpp1z/lambda-this1.C
+++ b/gcc/testsuite/g++.dg/cpp1z/lambda-this1.C
@@ -17,13 +17,31 @@ struct A {
auto h = [*this] () mutable { a++; };// { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto i = [=] { return a; };
auto j = [&] { return a; };
- auto k = [=, this] { return a; };// { dg-error "explicit by-copy capture of 'this' redundant with by-copy capture default" }
+ // P0409R2 - C++2A lambda capture [=, this]
+ auto k = [=, this] { return a; };// { dg-error "explicit by-copy capture of 'this' redundant with by-copy capture default" "" { target c++17_down } }
auto l = [&, this] { return a; };
auto m = [=, *this] { return a; };// { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto n = [&, *this] { return a; };// { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto o = [*this, &v] { return a + v; };// { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto p = [*this] { this = 0; }; // { dg-error "lvalue required as left operand of assignment" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
+ auto q = [=, this, *this] { return a; };// { dg-error "already captured 'this'" }
+ // { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
+ // { dg-error "explicit by-copy capture of 'this' redundant with by-copy capture default" "" { target c++17_down } .-2 }
+ auto r = [=, this, this] { return a; };// { dg-error "already captured 'this'" }
+ // { dg-error "explicit by-copy capture of 'this' redundant with by-copy capture default" "" { target c++17_down } .-1 }
+ auto s = [=, *this, this] { return a; };// { dg-error "already captured 'this'" }
+ // { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
+ // { dg-error "explicit by-copy capture of 'this' redundant with by-copy capture default" "" { target c++17_down } .-2 }
+ auto t = [=, *this, *this] { return a; };// { dg-error "already captured 'this'" }
+ // { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
+ auto u = [&, this, *this] { return a; };// { dg-error "already captured 'this'" }
+ // { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
+ auto w = [&, this, this] { return a; };// { dg-error "already captured 'this'" }
+ auto x = [&, *this, this] { return a; };// { dg-error "already captured 'this'" }
+ // { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
+ auto y = [&, *this, *this] { return a; };// { dg-error "already captured 'this'" }
+ // { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
}
};
struct B {
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C
index 8eb3be0..b51d7af 100644
--- a/gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type13.C
@@ -5,7 +5,7 @@
void foo () throw () {} // { dg-bogus "mangled name" }
template <class T>
-T bar (T x) { return x; } // { dg-warning "mangled name" "" { target c++14_down } }
+T bar (T x) { return x; }
void baz () { // { dg-bogus "mangled name" }
return (bar (foo)) ();
diff --git a/gcc/testsuite/g++.dg/cpp1z/noexcept-type18.C b/gcc/testsuite/g++.dg/cpp1z/noexcept-type18.C
new file mode 100644
index 0000000..e01fd0a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/noexcept-type18.C
@@ -0,0 +1,15 @@
+// { dg-options "-std=c++17" }
+
+template<typename T>
+struct S;
+
+template<bool IsNoexcept>
+struct S<void(*)() noexcept(IsNoexcept)> {
+ S() {}
+};
+
+void f() {}
+
+int main() {
+ S<decltype(&f)> {};
+}
diff --git a/gcc/testsuite/g++.dg/cpp1z/pr81016.C b/gcc/testsuite/g++.dg/cpp1z/pr81016.C
new file mode 100644
index 0000000..4826fbfb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/pr81016.C
@@ -0,0 +1,4 @@
+// { dg-options "-std=c++17" }
+
+template <typename a, a> struct b;
+template <typename c> struct b<bool, c::d>; // { dg-error "template parameter" }
diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield1.C b/gcc/testsuite/g++.dg/cpp2a/bitfield1.C
new file mode 100644
index 0000000..497b529
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/bitfield1.C
@@ -0,0 +1,77 @@
+// P0683R1
+// { dg-do run { target c++11 } }
+// { dg-options "" }
+
+extern "C" void abort ();
+int a;
+const int b = 0;
+struct S {
+ int c : 5 = 1; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int d : 6 { 2 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int e : true ? 7 : a = 3;
+ int f : (true ? 8 : b) = 4; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int g : (true ? 9 : b) { 5 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int h : 1 || new int { 0 };
+};
+#if __cplusplus >= 201402L
+static_assert (S{}.c == 1);
+static_assert (S{}.d == 2);
+static_assert (S{}.e == 0);
+static_assert (S{}.f == 4);
+static_assert (S{}.g == 5);
+static_assert (S{}.h == 0);
+#endif
+template <bool V, int W>
+struct U {
+ int j : W = 7; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int k : W { 8 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int l : V ? 7 : a = 3;
+ int m : (V ? W : b) = 9; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int n : (V ? W : b) { 10 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int o : 1 || new int { 0 };
+};
+#if __cplusplus >= 201402L
+static_assert (U<true, 12>{}.j == 7);
+static_assert (U<true, 13>{}.k == 8);
+static_assert (U<true, 10>{}.l == 0);
+static_assert (U<true, 11>{}.m == 9);
+static_assert (U<true, 8>{}.n == 10);
+static_assert (U<true, 7>{}.o == 0);
+#endif
+S s;
+U<true, 10> u;
+
+int
+main ()
+{
+ if (s.c != 1 || s.d != 2 || s.e != 0 || s.f != 4 || s.g != 5 || s.h != 0)
+ abort ();
+ s.c = 47; // { dg-warning "overflow in conversion from" }
+ s.d = 47 * 2; // { dg-warning "overflow in conversion from" }
+ s.e = 47 * 4; // { dg-warning "overflow in conversion from" }
+ s.f = 47 * 8; // { dg-warning "overflow in conversion from" }
+ s.g = 47 * 16; // { dg-warning "overflow in conversion from" }
+ s.h = 2; // { dg-warning "overflow in conversion from" }
+ if (s.c != 15 || s.d != 15 * 2 || s.e != 15 * 4 || s.f != 15 * 8 || s.g != 15 * 16 || s.h != 0)
+ abort ();
+ if (u.j != 7 || u.k != 8 || u.l != 0 || u.m != 9 || u.n != 10 || u.o != 0)
+ abort ();
+ u.j = 47 * 32; // { dg-warning "overflow in conversion from" }
+ u.k = 47 * 32; // { dg-warning "overflow in conversion from" }
+ u.l = 47 * 4; // { dg-warning "overflow in conversion from" }
+ u.m = 47 * 32; // { dg-warning "overflow in conversion from" }
+ u.n = 47 * 32; // { dg-warning "overflow in conversion from" }
+ u.o = 2; // { dg-warning "overflow in conversion from" }
+ if (u.j != 15 * 32 || u.k != 15 * 32 || u.l != 15 * 4 || u.m != 15 * 32 || u.n != 15 * 32 || u.o != 0)
+ abort ();
+ s.c = 15;
+ s.d = 15 * 2;
+ s.e = 15 * 4;
+ s.f = 16 * 8;
+ s.g = 15 * 16;
+ u.j = 15 * 32;
+ u.k = 15 * 32;
+ u.l = 15 * 4;
+ u.m = 15 * 32;
+ u.n = 15 * 32;
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield2.C b/gcc/testsuite/g++.dg/cpp2a/bitfield2.C
new file mode 100644
index 0000000..dcb424f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/bitfield2.C
@@ -0,0 +1,26 @@
+// P0683R1
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+int a;
+const int b = 0;
+struct T {
+ int i : true ? 10 : b = 6; // { dg-error "assignment of read-only variable" }
+ int : 4 = 10; // { dg-error "default member initializer for unnamed bit-field" }
+ int : 5 = a + b; // { dg-error "default member initializer for unnamed bit-field" }
+};
+template <bool V, int W>
+struct U {
+ int j : W = 7; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int k : W { 8 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int l : V ? 7 : a = 3; // { dg-error "modification of .a. is not a constant expression" }
+ // { dg-error "width not an integer constant" "" { target *-*-* } .-1 }
+ int m : (V ? W : b) = 9; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ // { dg-error "zero width for bit-field" "" { target *-*-* } .-1 }
+ int n : (V ? W : b) { 10 }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ // { dg-error "zero width for bit-field" "" { target *-*-* } .-1 }
+ int o : 1 || new int { 0 };
+ int : 4 = 10; // { dg-error "default member initializer for unnamed bit-field" }
+ int : 5 = a + b; // { dg-error "default member initializer for unnamed bit-field" }
+};
+U<false, 10> u;
diff --git a/gcc/testsuite/g++.dg/cpp2a/bitfield3.C b/gcc/testsuite/g++.dg/cpp2a/bitfield3.C
new file mode 100644
index 0000000..511c889
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/bitfield3.C
@@ -0,0 +1,55 @@
+// P0683R1
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+extern "C" void abort ();
+
+int
+foo ()
+{
+ return 2;
+}
+
+int a = foo ();
+const int b = 0;
+struct S {
+ int c : 5 = 2 * a; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int d : 6 { c + a }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ // { dg-warning "narrowing conversion of" "" { target *-*-* } .-1 }
+ int e : true ? 7 : a = 3;
+ int f : (true ? 8 : b) = d + a; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int g : (true ? 9 : b) { f + a }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ // { dg-warning "narrowing conversion of" "" { target *-*-* } .-1 }
+ int h : 1 || new int { 0 };
+ int i = g + a;
+};
+S c;
+template <bool V, int W>
+struct U {
+ int j : W = 3 * a; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int k : W { j + a }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ // { dg-warning "narrowing conversion of" "" { target *-*-* } .-1 }
+ int l : V ? 7 : a = 3;
+ int m : (V ? W : b) = k + a; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ int n : (V ? W : b) { m + a }; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+ // { dg-warning "narrowing conversion of" "" { target *-*-* } .-1 }
+ int o : 1 || new int { 0 };
+ int p = n + a;
+};
+U<true, 10> d;
+
+int
+main ()
+{
+ a = 1;
+ if (c.c != 4 || c.d != 6 || c.e != 0 || c.f != 8 || c.g != 10 || c.h != 0 || c.i != 12)
+ abort ();
+ if (d.j != 6 || d.k != 8 || d.l != 0 || d.m != 10 || d.n != 12 || d.o != 0 || d.p != 14)
+ abort ();
+ S s;
+ U<true, 10> u;
+ if (s.c != 2 || s.d != 3 || s.f != 4 || s.g != 5 || s.i != 6)
+ abort ();
+ if (u.j != 3 || u.k != 4 || u.m != 5 || u.n != 6 || u.p != 7)
+ abort ();
+}
diff --git a/gcc/testsuite/g++.dg/cpp2a/ptrmem1.C b/gcc/testsuite/g++.dg/cpp2a/ptrmem1.C
new file mode 100644
index 0000000..d567d08
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp2a/ptrmem1.C
@@ -0,0 +1,23 @@
+// P0704R1
+// { dg-do compile { target c++11 } }
+
+struct S {
+ void ref() & {}
+ void cref() const& {}
+ void vref() volatile & {}
+ void cvref() const volatile & {}
+};
+
+void
+foo ()
+{
+ S{}.ref(); // { dg-error "argument discards qualifiers" }
+ S{}.cref();
+ S{}.vref(); // { dg-error "argument discards qualifiers" }
+ S{}.cvref(); // { dg-error "argument discards qualifiers" }
+
+ (S{}.*&S::ref)(); // { dg-error "pointer-to-member-function type 'void \\(S::\\*\\)\\(\\) &' requires an lvalue" }
+ (S{}.*&S::cref)(); // { dg-error "pointer-to-member-function type 'void \\(S::\\*\\)\\(\\) const &' requires an lvalue" "" { target c++17_down } }
+ (S{}.*&S::vref)(); // { dg-error "pointer-to-member-function type 'void \\(S::\\*\\)\\(\\) volatile &' requires an lvalue" }
+ (S{}.*&S::cvref)(); // { dg-error "pointer-to-member-function type 'void \\(S::\\*\\)\\(\\) const volatile &' requires an lvalue" }
+}
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp11.C b/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp11.C
index 8079c0e..6bdc175 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp11.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp11.C
@@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-O -std=c++11 -gdwarf-5 -dA" }
// DW_LANG_C_plus_plus_11 = 0x001a
-// { dg-final { scan-assembler "0x1a.*DW_AT_language" } } */
+// { dg-final { scan-assembler "0x1a\[^\n\r]* DW_AT_language" } } */
int version;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp14.C b/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp14.C
index 448ec7c..4fbc075 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp14.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp14.C
@@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-O -std=c++14 -gdwarf-5 -dA" }
// DW_LANG_C_plus_plus_14 = 0x0021
-// { dg-final { scan-assembler "0x21.*DW_AT_language" } } */
+// { dg-final { scan-assembler "0x21\[^\n\r]* DW_AT_language" } } */
int version;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp98.C b/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp98.C
index e7272da..bdb15d4 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp98.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/lang-cpp98.C
@@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-options "-O -std=c++98 -gdwarf-2 -dA" }
// DW_LANG_C_plus_plus = 0x0004
-// { dg-final { scan-assembler "0x4.*DW_AT_language" } } */
+// { dg-final { scan-assembler "0x4\[^\n\r]* DW_AT_language" } } */
int version;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/pr77363.C b/gcc/testsuite/g++.dg/debug/dwarf2/pr77363.C
index 47b7143..cd06c36 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/pr77363.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/pr77363.C
@@ -1,9 +1,9 @@
// PR debug/77363
// { dg-options "-gdwarf-2 -dA -fno-merge-debug-strings" }
-// { dg-final { scan-assembler "DIE \\(\[^\n\r\]*\\) DW_TAG_typedef\[^\n\r\]*\[\n\r]*\[^\n\r\]*type2\[^\n\r\]* DW_AT_name\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_file\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_line\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_type" } }
-// { dg-final { scan-assembler "DIE \\(\[^\n\r\]*\\) DW_TAG_typedef\[^\n\r\]*\[\n\r]*\[^\n\r\]*type3\[^\n\r\]* DW_AT_name\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_file\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_line\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_type" } }
-// { dg-final { scan-assembler "DIE \\(\[^\n\r\]*\\) DW_TAG_typedef\[^\n\r\]*\[\n\r]*\[^\n\r\]*type4\[^\n\r\]* DW_AT_name\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_file\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_line\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_type" } }
-// { dg-final { scan-assembler "DIE \\(\[^\n\r\]*\\) DW_TAG_typedef\[^\n\r\]*\[\n\r]*\[^\n\r\]*type5\[^\n\r\]* DW_AT_name\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_file\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_line\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_type" } }
+// { dg-final { scan-assembler "DIE \\(\[^\n\r\]*\\) DW_TAG_typedef\[^\n\r\]*\[\n\r]*\[^\n\r\]*type2\[^\n\r\]* DW_AT_name\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_file\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_line\[^\n\r\]*\[\n\r]*(\[^\n\r\]* DW_AT_decl_column\[^\n\r\]*\[\n\r]*)?\[^\n\r\]* DW_AT_type" } }
+// { dg-final { scan-assembler "DIE \\(\[^\n\r\]*\\) DW_TAG_typedef\[^\n\r\]*\[\n\r]*\[^\n\r\]*type3\[^\n\r\]* DW_AT_name\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_file\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_line\[^\n\r\]*\[\n\r]*(\[^\n\r\]* DW_AT_decl_column\[^\n\r\]*\[\n\r]*)?\[^\n\r\]* DW_AT_type" } }
+// { dg-final { scan-assembler "DIE \\(\[^\n\r\]*\\) DW_TAG_typedef\[^\n\r\]*\[\n\r]*\[^\n\r\]*type4\[^\n\r\]* DW_AT_name\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_file\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_line\[^\n\r\]*\[\n\r]*(\[^\n\r\]* DW_AT_decl_column\[^\n\r\]*\[\n\r]*)?\[^\n\r\]* DW_AT_type" } }
+// { dg-final { scan-assembler "DIE \\(\[^\n\r\]*\\) DW_TAG_typedef\[^\n\r\]*\[\n\r]*\[^\n\r\]*type5\[^\n\r\]* DW_AT_name\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_file\[^\n\r\]*\[\n\r]*\[^\n\r\]* DW_AT_decl_line\[^\n\r\]*\[\n\r]*(\[^\n\r\]* DW_AT_decl_column\[^\n\r\]*\[\n\r]*)?\[^\n\r\]* DW_AT_type" } }
typedef unsigned short type1;
typedef unsigned char type2;
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-1.C
index 5daa220..3556231 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-1.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-1.C
@@ -3,7 +3,7 @@
// { dg-options "-gdwarf-2 -dA" }
// { dg-do compile }
// { dg-final { scan-assembler "DW_TAG_template_type_param" } }
-// { dg-final { scan-assembler "U.*DW_AT_name" } }
+// { dg-final { scan-assembler "U\[^\n\r]* DW_AT_name" } }
template <class U>
U
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-2.C
index 670598b..1096828 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-2.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-2.C
@@ -3,8 +3,8 @@
// { dg-options "-gdwarf-2 -dA" }
// { dg-do compile }
// { dg-final { scan-assembler "DW_TAG_template_value_param" } }
-// { dg-final { scan-assembler "i.*DW_AT_name" } }
-// { dg-final { scan-assembler "3.*DW_AT_const_value" } }
+// { dg-final { scan-assembler "i\[^\n\r]* DW_AT_name" } }
+// { dg-final { scan-assembler "3\[^\n\r]* DW_AT_const_value" } }
template <int i>
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-3.C
index a356a2e..d806104 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-3.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-3.C
@@ -2,7 +2,7 @@
// Origin PR debug/30161
// { dg-options "-gdwarf-2 -dA -gno-strict-dwarf -fno-merge-debug-strings" }
// { dg-final { scan-assembler "DW_TAG_template_value_param" } }
-// { dg-final { scan-assembler "f.*DW_AT_name" } }
+// { dg-final { scan-assembler "f\[^\n\r]* DW_AT_name" } }
// { dg-final { scan-assembler "DW_AT_location\[^\\r\\n\]*\[\\r\\n\]*\[^\\r\\n\]*DW_OP_addr\[^\\r\\n\]*\[\\r\\n\]*\[^\\r\\n\]*_Z4blehv\[^\\r\\n\]*\[\\r\\n\]*\[^\\r\\n\]*DW_OP_stack_value" } } */
typedef void (*func_ptr)();
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-5.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-5.C
index cc8b1ac..cb3a73f 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-5.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-func-params-5.C
@@ -2,7 +2,7 @@
// Origin PR debug/30161
// { dg-options "-gdwarf-2 -dA" }
// { dg-final { scan-assembler "DW_TAG_template_type_param" } }
-// { dg-final { scan-assembler "T.*DW_AT_name" } }
+// { dg-final { scan-assembler "T\[^\n\r]* DW_AT_name" } }
template <class T>
struct vector
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-1.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-1.C
index b8f9202..21c71ec 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-1.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-1.C
@@ -3,7 +3,7 @@
// { dg-options "-gdwarf-2 -dA" }
// { dg-do compile }
// { dg-final { scan-assembler "DW_TAG_template_type_param" } }
-// { dg-final { scan-assembler "U.*DW_AT_name" } }
+// { dg-final { scan-assembler "U\[^\n\r]* DW_AT_name" } }
template <class U>
class A
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-13.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-13.C
new file mode 100644
index 0000000..f32ac17
--- /dev/null
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-13.C
@@ -0,0 +1,10 @@
+// { dg-options "-gdwarf-2 -dA" }
+// { dg-do compile }
+// { dg-final { scan-assembler "DW_TAG_template_value_param" } }
+// { dg-final { scan-assembler "N\[^\n\r]* DW_AT_name" } }
+// { dg-final { scan-assembler "9\[^\n\r]* DW_AT_const_value" } }
+
+template <int N> class C {};
+template <typename T> struct E {};
+E<struct A> f;
+struct A { C<9> g; };
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-2.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-2.C
index 0a00fd6..e6ca525 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-2.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-2.C
@@ -3,8 +3,8 @@
// { dg-options "-gdwarf-2 -dA" }
// { dg-do compile }
// { dg-final { scan-assembler "DW_TAG_template_value_param" } }
-// { dg-final { scan-assembler "i.*DW_AT_name" } }
-// { dg-final { scan-assembler "3.*DW_AT_const_value" } }
+// { dg-final { scan-assembler "i\[^\n\r]* DW_AT_name" } }
+// { dg-final { scan-assembler "3\[^\n\r]* DW_AT_const_value" } }
template <int i>
struct A
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-3.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-3.C
index fc309ec..7a9af77 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-3.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-3.C
@@ -2,7 +2,7 @@
// Origin PR debug/30161
// { dg-options "-gdwarf-2 -dA -gno-strict-dwarf -fno-merge-debug-strings" }
// { dg-final { scan-assembler "DW_TAG_template_value_param" } }
-// { dg-final { scan-assembler "f.*DW_AT_name" } }
+// { dg-final { scan-assembler "f\[^\n\r]* DW_AT_name" } }
// { dg-final { scan-assembler "DW_AT_location\[^\\r\\n\]*\[\\r\\n\]*\[^\\r\\n\]*DW_OP_addr\[^\\r\\n\]*\[\\r\\n\]*\[^\\r\\n\]*_Z4blehv\[^\\r\\n\]*\[\\r\\n\]*\[^\\r\\n\]*DW_OP_stack_value" } } */
typedef void (*func_ptr) ();
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-5.C b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-5.C
index 0258498..ed08122 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/template-params-5.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/template-params-5.C
@@ -2,7 +2,7 @@
// Origin PR debug/30161
// { dg-options "-gdwarf-2 -dA" }
// { dg-final { scan-assembler "DW_TAG_template_type_param" } }
-// { dg-final { scan-assembler "T.*DW_AT_name" } }
+// { dg-final { scan-assembler "T\[^\n\r]* DW_AT_name" } }
template <class T>
struct vector
diff --git a/gcc/testsuite/g++.dg/debug/dwarf2/typedef6.C b/gcc/testsuite/g++.dg/debug/dwarf2/typedef6.C
index 7945dea..654eba0 100644
--- a/gcc/testsuite/g++.dg/debug/dwarf2/typedef6.C
+++ b/gcc/testsuite/g++.dg/debug/dwarf2/typedef6.C
@@ -1,5 +1,5 @@
// Origin PR debug/
-// { dg-options "-gdwarf-2 -dA" }
+// { dg-options "-gdwarf-2 -dA -gno-column-info" }
class C {
public:
diff --git a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
index b8833ef..bc3a938 100644
--- a/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
+++ b/gcc/testsuite/g++.dg/diagnostic/param-type-mismatch.C
@@ -3,10 +3,7 @@
/* A collection of calls where argument 2 is of the wrong type.
TODO: we should put the caret and underline for the diagnostic
- at the second argument, rather than the close paren.
-
- TODO: we should highlight the second parameter of the callee, rather
- than its name. */
+ at the second argument, rather than the close paren. */
/* decl, with argname. */
@@ -22,7 +19,7 @@ int test_1 (int first, int second, float third)
// { dg-message "initializing argument 2 of 'int callee_1\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_1 }
/* { dg-begin-multiline-output "" }
extern int callee_1 (int one, const char *two, float three);
- ^~~~~~~~
+ ~~~~~~~~~~~~^~~
{ dg-end-multiline-output "" } */
}
@@ -40,7 +37,7 @@ int test_2 (int first, int second, float third)
// { dg-message "initializing argument 2 of 'int callee_2\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_2 }
/* { dg-begin-multiline-output "" }
extern int callee_2 (int, const char *, float);
- ^~~~~~~~
+ ^~~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
@@ -61,7 +58,7 @@ int test_3 (int first, int second, float third)
// { dg-message "initializing argument 2 of 'int callee_3\\(int, const char\\*, float\\)'" "" { target *-*-* } callee_3 }
/* { dg-begin-multiline-output "" }
static int callee_3 (int one, const char *two, float three)
- ^~~~~~~~
+ ~~~~~~~~~~~~^~~
{ dg-end-multiline-output "" } */
}
@@ -78,7 +75,7 @@ int test_4 (int first, int second, float third)
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s4 { static int member_1 (int one, const char *two, float three); };
- ^~~~~~~~
+ ~~~~~~~~~~~~^~~
{ dg-end-multiline-output "" } */
}
@@ -96,7 +93,7 @@ int test_5 (int first, int second, float third)
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s5 { int member_1 (int one, const char *two, float three); };
- ^~~~~~~~
+ ~~~~~~~~~~~~^~~
{ dg-end-multiline-output "" } */
}
@@ -113,7 +110,7 @@ int test_6 (int first, int second, float third, s6 *ptr)
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s6 { int member_1 (int one, const char *two, float three); };
- ^~~~~~~~
+ ~~~~~~~~~~~~^~~
{ dg-end-multiline-output "" } */
}
@@ -153,7 +150,7 @@ int test_8 (int first, int second, float third)
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s8 { static int member_1 (int one, T two, float three); };
- ^~~~~~~~
+ ~~^~~
{ dg-end-multiline-output "" } */
}
@@ -172,7 +169,43 @@ int test_9 (int first, int second, float third)
{ dg-end-multiline-output "" } */
/* { dg-begin-multiline-output "" }
struct s9 { int member_1 (int one, T two, float three); };
- ^~~~~~~~
+ ~~^~~
+ { dg-end-multiline-output "" } */
+}
+
+/* Callback with name. */
+
+extern int callee_10 (int one, int (*two)(int, int), float three); // { dg-line callee_10 }
+
+int test_10 (int first, int second, float third)
+{
+ return callee_10 (first, second, third); // { dg-error "invalid conversion from 'int' to 'int \\(\\*\\)\\(int, int\\)'" }
+ /* { dg-begin-multiline-output "" }
+ return callee_10 (first, second, third);
+ ^
+ { dg-end-multiline-output "" } */
+ // { dg-message "initializing argument 2 of 'int callee_10\\(int, int \\(\\*\\)\\(int, int\\), float\\)'" "" { target *-*-* } callee_10 }
+ /* { dg-begin-multiline-output "" }
+ extern int callee_10 (int one, int (*two)(int, int), float three);
+ ~~~~~~^~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+/* Callback without name. */
+
+extern int callee_11 (int one, int (*)(int, int), float three); // { dg-line callee_11 }
+
+int test_11 (int first, int second, float third)
+{
+ return callee_11 (first, second, third); // { dg-error "invalid conversion from 'int' to 'int \\(\\*\\)\\(int, int\\)'" }
+ /* { dg-begin-multiline-output "" }
+ return callee_11 (first, second, third);
+ ^
+ { dg-end-multiline-output "" } */
+ // { dg-message "initializing argument 2 of 'int callee_11\\(int, int \\(\\*\\)\\(int, int\\), float\\)'" "" { target *-*-* } callee_11 }
+ /* { dg-begin-multiline-output "" }
+ extern int callee_11 (int one, int (*)(int, int), float three);
+ ^~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
diff --git a/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C b/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C
index fda3532..44f538e 100644
--- a/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C
+++ b/gcc/testsuite/g++.dg/diagnostic/unclosed-extern-c.C
@@ -1,3 +1,12 @@
-extern "C" { /* { dg-message "12: to match this '.'" } */
+extern "C" { // { dg-line open_extern_c }
+
+ int foo (void);
+
+/* Missing close-brace for the extern "C" here. */
+
+template <typename T> // { dg-error "template with C linkage" }
+void bar (void);
+// { dg-message "1: 'extern .C.' linkage started here" "" { target *-*-* } open_extern_c }
void test (void); /* { dg-error "17: expected '.' at end of input" } */
+// { message "12: to match this '.'" "" { target *-*-* } open_extern_c }
diff --git a/gcc/testsuite/g++.dg/eh/uncaught1.C b/gcc/testsuite/g++.dg/eh/uncaught1.C
index e96af33..4f05be5 100644
--- a/gcc/testsuite/g++.dg/eh/uncaught1.C
+++ b/gcc/testsuite/g++.dg/eh/uncaught1.C
@@ -1,6 +1,7 @@
// PR libstdc++/10606
// { dg-do run }
-// { dg-options "-fuse-cxa-get-exception-ptr" { target powerpc*-*-darwin* } }
+// { dg-options "-Wno-deprecated" }
+// { dg-options "-fuse-cxa-get-exception-ptr -Wno-deprecated" { target powerpc*-*-darwin* } }
#include <exception>
#include <cstdlib>
diff --git a/gcc/testsuite/g++.dg/eh/uncaught2.C b/gcc/testsuite/g++.dg/eh/uncaught2.C
index a99b2d7..62e4d4d 100644
--- a/gcc/testsuite/g++.dg/eh/uncaught2.C
+++ b/gcc/testsuite/g++.dg/eh/uncaught2.C
@@ -1,6 +1,6 @@
// { dg-do compile }
// { dg-final { scan-assembler-not "__cxa_get_exception" } }
-// { dg-options "-fno-use-cxa-get-exception-ptr" }
+// { dg-options "-fno-use-cxa-get-exception-ptr -Wno-deprecated" }
#include <exception>
#include <cstdlib>
diff --git a/gcc/testsuite/g++.dg/eh/uncaught3.C b/gcc/testsuite/g++.dg/eh/uncaught3.C
index 4ce4a53..1b3333e 100644
--- a/gcc/testsuite/g++.dg/eh/uncaught3.C
+++ b/gcc/testsuite/g++.dg/eh/uncaught3.C
@@ -1,6 +1,7 @@
// { dg-do compile { target powerpc*-*-darwin* } }
// { dg-final { scan-assembler-not "__cxa_get_exception" } }
// { dg-options "-mmacosx-version-min=10.4" }
+// { dg-additional-options "-Wno-deprecated" { target c++17 } }
#include <exception>
#include <cstdlib>
diff --git a/gcc/testsuite/g++.dg/eh/uncaught4.C b/gcc/testsuite/g++.dg/eh/uncaught4.C
index 227d11b..8ca2cd2 100644
--- a/gcc/testsuite/g++.dg/eh/uncaught4.C
+++ b/gcc/testsuite/g++.dg/eh/uncaught4.C
@@ -1,5 +1,6 @@
// PR c++/41174
// { dg-do run }
+// { dg-options "-Wno-deprecated" }
#include <exception>
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C
index 2c7bba1..4a29e8b 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-1.C
@@ -4,26 +4,33 @@
struct Klass
{
+ int a[4];
+
int implementation ();
int magic ();
- typedef int (Klass::*MemFuncPtr)();
+ /* An ifunc resolver must return a pointer to an ordinary (non-member)
+ function. To make it possible to use ifunc with member functions,
+ the resolver must convert a member function pointer to an ordinary
+ function pointer (slicing off the high word). */
+ typedef int Func (Klass*);
- static MemFuncPtr resolver ();
+ static Func* resolver ();
};
-Klass::MemFuncPtr p = &Klass::implementation;
-
-int Klass::implementation (void)
+int Klass::implementation ()
{
__builtin_printf ("'ere I am JH\n");
- return 1234;
+ return a[0] + a[1] + a[2] + a[3];
}
-
-Klass::MemFuncPtr Klass::resolver (void)
+Klass::Func* Klass::resolver (void)
{
- return &Klass::implementation;
+ /* GCC guarantees this conversion to be safe and the resulting pointer
+ usable to call the member function using ordinary (i.e., non-member)
+ function call syntax. */
+
+ return reinterpret_cast<Func*>(&Klass::implementation);
}
int f (void) __attribute__ ((ifunc ("foo")));
@@ -32,11 +39,16 @@ typedef int (F)(void);
extern "C" F* foo () { return 0; }
-int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
+int Klass::magic () __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
int main ()
{
Klass obj;
- return !(obj.magic () == 1234);
+ obj.a[0] = 1;
+ obj.a[1] = 2;
+ obj.a[2] = 3;
+ obj.a[3] = 4;
+
+ return !(obj.magic () == 10);
}
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C
index 49872e0..e5be3d2 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-2.C
@@ -9,9 +9,9 @@ struct Klass
int implementation ();
int magic ();
- typedef int (Klass::*MemFuncPtr)();
+ typedef int Func (Klass*);
- static MemFuncPtr resolver ();
+ static Func* resolver ();
};
int Klass::implementation (void)
@@ -20,9 +20,13 @@ int Klass::implementation (void)
return 0;
}
-Klass::memFuncPtr Klass::resolver (void)
+Klass::Func* Klass::resolver (void)
{
- return &Klass::implementation;
+ /* GCC guarantees this conversion to be safe and the resulting pointer
+ usable to call the member function using ordinary (i.e., non-member)
+ function call syntax. */
+
+ return reinterpret_cast<Func*>(&Klass::implementation);
}
int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C
index 04206a1..6d49424 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-3.C
@@ -6,23 +6,29 @@
struct Klass
{
+ int a[4];
+
int implementation ();
int magic ();
- typedef int (Klass::*MemFuncPtr)();
+ typedef int Func (Klass*);
- static MemFuncPtr resolver ();
+ static Func* resolver ();
};
int Klass::implementation (void)
{
printf ("'ere I am JH\n");
- return 0;
+ return a[0] + a[1] + a[2] + a[3];
}
-Klass::MemFuncPtr Klass::resolver (void)
+Klass::Func* Klass::resolver ()
{
- return &Klass::implementation;
+ /* GCC guarantees this conversion to be safe and the resulting pointer
+ usable to call the member function using ordinary (i.e., non-member)
+ function call syntax. */
+
+ return reinterpret_cast<Func*>(&Klass::implementation);
}
int Klass::magic (void) __attribute__ ((ifunc ("_ZN5Klass8resolverEv")));
@@ -36,5 +42,10 @@ int main ()
{
Klass obj;
- return Foo (obj, &Klass::magic) != 0;
+ obj.a[0] = 1;
+ obj.a[1] = 2;
+ obj.a[2] = 3;
+ obj.a[3] = 4;
+
+ return Foo (obj, &Klass::magic) != 10;
}
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C
index b8d8e58..f71dc3b 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-4.C
@@ -14,9 +14,9 @@ struct Klassier : Klass
int implementation ();
int magic ();
- typedef int (Klass::*MemFuncPtr)();
+ typedef int Func (Klass*);
- static MemFuncPtr resolver ();
+ static Func* resolver ();
};
int Klassier::implementation (void)
@@ -25,9 +25,13 @@ int Klassier::implementation (void)
return 0;
}
-Klassier::MemFuncPtr Klassier::resolver (void)
+Klassier::Func* Klassier::resolver ()
{
- return &Klassier::implementation;
+ /* GCC guarantees this conversion to be safe and the resulting pointer
+ usable to call the member function using ordinary (i.e., non-member)
+ function call syntax. */
+
+ return reinterpret_cast<Func*>(&Klassier::implementation);
}
int Klassier::magic (void) __attribute__ ((ifunc ("_ZN8Klassier8resolverEv")));
diff --git a/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C b/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C
index 05855dd..fd8bcff 100644
--- a/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C
+++ b/gcc/testsuite/g++.dg/ext/attr-ifunc-5.C
@@ -1,15 +1,21 @@
// PR c/81854 - weak alias of an incompatible symbol accepted
// { dg-do compile }
// { dg-require-ifunc "" } */
+// { dg-options "-Wextra -Wno-pmf-conversions" }
struct Klass
{
int implementation ();
- const char* magic ();
+ int good_magic ();
+ int iffy_magic ();
+ const char* bad_magic ();
+ typedef int (Func)(Klass*);
typedef int (Klass::*MemFuncPtr)();
- static MemFuncPtr resolver ();
+ static Func* good_resolver ();
+ static void* iffy_resolver ();
+ static MemFuncPtr bad_resolver ();
};
int Klass::implementation (void)
@@ -17,13 +23,42 @@ int Klass::implementation (void)
return 0;
}
-const char* __attribute__ ((ifunc ("_ZN5Klass8resolverEv")))
- Klass::magic (); // { dg-warning "alias between functions of incompatible types" }
+// Verify no warning for the expected/compatible declaration.
+int __attribute__ ((ifunc ("_ZN5Klass13good_resolverEv")))
+Klass::good_magic ();
+
+Klass::Func*
+Klass::good_resolver (void)
+{
+ MemFuncPtr mfp = &Klass::implementation;
+
+ return reinterpret_cast<Func*>(mfp);
+}
+
+
+// Verify a warning for the unsafe declaration.
+
+int __attribute__ ((ifunc ("_ZN5Klass13iffy_resolverEv")))
+Klass::iffy_magic (); // { dg-message "resolver indirect function declared here" }
+
+void*
+Klass::iffy_resolver (void) // { dg-warning ".ifunc. resolver for .int Klass::iffy_magic\\(\\). should return .int \\(\\*\\)\\(Klass\\*\\)." }
+{
+ MemFuncPtr mfp = &Klass::implementation;
+
+ return reinterpret_cast<void*>(mfp);
+}
+
+
+// Verify an error for an incompatible declaration.
+
+const char* __attribute__ ((ifunc ("_ZN5Klass12bad_resolverEv")))
+Klass::bad_magic (); // { dg-message "resolver indirect function declared here" }
Klass::MemFuncPtr
-Klass::resolver (void) // { dg-message "aliased declaration here" }
+Klass::bad_resolver (void) // { dg-error ".ifunc. resolver for .const char\\* Klass::bad_magic\\(\\). must return .const char\\* \\(\\*\\)\\(Klass\\*\\)." }
{
return &Klass::implementation;
}
diff --git a/gcc/testsuite/g++.dg/ext/attrib54.C b/gcc/testsuite/g++.dg/ext/attrib54.C
new file mode 100644
index 0000000..5ff28c8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/attrib54.C
@@ -0,0 +1,14 @@
+// PR c++/82406
+
+class a
+{
+public:
+ template <typename b> void operator() (const b &);
+};
+void c () throw () __attribute__ ((__nonnull__));
+void
+d ()
+{
+ a e;
+ e (c);
+}
diff --git a/gcc/testsuite/g++.dg/ext/bitfield6.C b/gcc/testsuite/g++.dg/ext/bitfield6.C
new file mode 100644
index 0000000..4b0bb77
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/bitfield6.C
@@ -0,0 +1,15 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "" }
+
+struct S {
+ char a [[gnu::packed]] = 1; // { dg-warning "attribute ignored for field of type" }
+ char b [[gnu::packed]] : 8;
+ char c [[gnu::packed]] : 8 = 2; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+};
+template <typename U>
+struct T {
+ U d [[gnu::packed]] = 1; // { dg-warning "attribute ignored for field of type" }
+ U e [[gnu::packed]] : 8;
+ U f [[gnu::packed]] : 8 = 2; // { dg-warning "default member initializers for bit-fields only available with" "" { target c++17_down } }
+};
+T<char> t;
diff --git a/gcc/testsuite/g++.dg/ext/bitfield7.C b/gcc/testsuite/g++.dg/ext/bitfield7.C
new file mode 100644
index 0000000..4efc9bf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/bitfield7.C
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-options "-Wno-packed-bitfield-compat -mno-ms-bitfields" { target { i?86-*-mingw* x86_64-*-mingw* } } } */
+
+struct t /* { dg-message "note: offset of packed bit-field 't::b' has changed in GCC 4.4" "" { target pcc_bitfield_type_matters } } */
+{
+ char a:4;
+ char b __attribute__ ((packed)) : 8;
+ char c:4;
+};
+
+int assrt[sizeof (struct t) == 2 ? 1 : -1];
diff --git a/gcc/testsuite/g++.dg/ext/bitfield8.C b/gcc/testsuite/g++.dg/ext/bitfield8.C
new file mode 100644
index 0000000..688b289
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/bitfield8.C
@@ -0,0 +1,12 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "" } */
+/* { dg-options "-Wno-packed-bitfield-compat -mno-ms-bitfields" { target { i?86-*-mingw* x86_64-*-mingw* } } } */
+
+struct t /* { dg-message "note: offset of packed bit-field 't::b' has changed in GCC 4.4" "" { target pcc_bitfield_type_matters } } */
+{
+ char a:4;
+ char b [[gnu::packed]] : 8;
+ char c:4;
+};
+
+int assrt[sizeof (struct t) == 2 ? 1 : -1];
diff --git a/gcc/testsuite/g++.dg/ext/bitfield9.C b/gcc/testsuite/g++.dg/ext/bitfield9.C
new file mode 100644
index 0000000..4a4ebf2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/bitfield9.C
@@ -0,0 +1,10 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-pedantic" }
+
+struct S
+{
+ char a:4;
+ char b:8 alignas(int); // { dg-warning "ISO C\\+\\+ allows bit-field attributes only before the ':' token" }
+ char c:8 [[gnu::aligned(8)]]; // { dg-warning "ISO C\\+\\+ allows bit-field attributes only before the ':' token" }
+ // { dg-error "two consecutive '\\\[' shall only introduce an attribute before '\\\[' token" "" { target *-*-* } .-1 }
+};
diff --git a/gcc/testsuite/g++.dg/ext/is_trivially_constructible5.C b/gcc/testsuite/g++.dg/ext/is_trivially_constructible5.C
new file mode 100644
index 0000000..15ea336
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/is_trivially_constructible5.C
@@ -0,0 +1,12 @@
+// PR c++/80991
+// { dg-do compile { target c++11 } }
+
+template<bool> void foo()
+{
+ static_assert(__is_trivially_constructible(int, int), "");
+}
+
+void bar()
+{
+ foo<true>();
+}
diff --git a/gcc/testsuite/g++.dg/ext/pr57362.C b/gcc/testsuite/g++.dg/ext/pr57362.C
index 71c53d3..3613b63 100644
--- a/gcc/testsuite/g++.dg/ext/pr57362.C
+++ b/gcc/testsuite/g++.dg/ext/pr57362.C
@@ -81,6 +81,8 @@ __attribute__((target("dispatch-scheduler")))
int foo(void) { return 1; }
__attribute__((target("prefer-avx128")))
int foo(void) { return 1; }
+__attribute__((target("prefer-avx256")))
+int foo(void) { return 1; }
__attribute__((target("32")))
int foo(void) { return 1; }
__attribute__((target("64")))
diff --git a/gcc/testsuite/g++.dg/ext/varargs2.C b/gcc/testsuite/g++.dg/ext/varargs2.C
new file mode 100644
index 0000000..13ddf5b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ext/varargs2.C
@@ -0,0 +1,17 @@
+// { dg-do run }
+
+int c;
+struct X { X() {}; X(const X&) { ++c; } };
+void Foo (X, ...) {}
+void bin (X &p)
+{
+ Foo (p, p);
+}
+
+int main()
+{
+ X x;
+ bin(x);
+ if (c != 2)
+ __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/gomp/pr77578.C b/gcc/testsuite/g++.dg/gomp/pr77578.C
new file mode 100644
index 0000000..d92fddf
--- /dev/null
+++ b/gcc/testsuite/g++.dg/gomp/pr77578.C
@@ -0,0 +1,31 @@
+// PR c++/77578
+// { dg-do compile }
+
+template <typename T>
+class A
+{
+};
+
+template <typename T>
+struct B
+{
+};
+
+template <typename T>
+struct B <A <T> >
+{
+ typedef A <T> C;
+ typedef typename C::D D;
+
+ template <typename U>
+ static void
+ foo (const D x, const D y)
+ {
+ U u;
+ {
+ #pragma omp parallel for
+ for (u.bar().y() = x.y(); u.bar().y() <= y.y(); u.bar().y()++) // { dg-error "expected" }
+ ;
+ }
+ }
+};
diff --git a/gcc/testsuite/g++.dg/guality/pr82630.C b/gcc/testsuite/g++.dg/guality/pr82630.C
new file mode 100644
index 0000000..71d11ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/guality/pr82630.C
@@ -0,0 +1,58 @@
+// PR debug/82630
+// { dg-do run }
+// { dg-additional-options "-fPIC" { target fpic } }
+
+struct C
+{
+ int &c;
+ long d;
+ __attribute__((always_inline)) C (int &x) : c(x), d() {}
+};
+int v;
+
+__attribute__((noipa)) void
+fn1 (const void *x)
+{
+ asm volatile ("" : : "g" (x) : "memory");
+}
+
+__attribute__((noipa)) void
+fn2 (C x)
+{
+ int a = x.c + x.d;
+ asm volatile ("" : : "g" (a) : "memory");
+}
+
+__attribute__((noipa)) void
+fn3 (void)
+{
+ asm volatile ("" : : : "memory");
+}
+
+__attribute__((noipa))
+#ifdef __i386__
+__attribute__((regparm (2)))
+#endif
+static void
+fn4 (int *x, const char *y, C z)
+{
+ fn2 (C (*x));
+ fn1 ("baz");
+ fn2 (z); // { dg-final { gdb-test 41 "y\[0\]" "'f'" } }
+ fn1 ("baz"); // { dg-final { gdb-test 41 "y\[1\]" "'o'" } }
+}
+
+__attribute__((noipa)) void
+fn5 (int *x)
+{
+ fn4 (x, "foo", C (*x));
+ fn3 ();
+}
+
+int
+main ()
+{
+ int a = 10;
+ fn5 (&a);
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C b/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C
index a03dea0..80593db 100644
--- a/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C
+++ b/gcc/testsuite/g++.dg/lookup/extern-c-hidden.C
@@ -1,11 +1,11 @@
// Make sure unhidding an extern-c still checks it is compatible
-extern "C" float fabsf (float); // { dg-error "conflicts with previous declaration" }
+extern "C" float fabsf (float); // { dg-message "previous declaration" }
namespace Bob
{
extern "C" float fabsf (float, float); // { dg-error "C language" }
- extern "C" double fabs (double, double); // { dg-error "conflicts with previous declaration" }
+ extern "C" double fabs (double, double); // { dg-message "previous declaration" }
}
extern "C" double fabs (double); // { dg-error "C language" }
diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C
index 3e901cc..fd49868 100644
--- a/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C
+++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl.C
@@ -3,7 +3,7 @@
// { dg-do compile }
namespace A {
- extern "C" void foo_func () throw(); // { dg-error "conflicts" }
+ extern "C" void foo_func () throw(); // { dg-message "previous" }
}
// next line should trigger an error because
// it conflicts with previous declaration of foo_func (), due to
diff --git a/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C b/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C
new file mode 100644
index 0000000..b4537d6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lookup/extern-c-redecl6.C
@@ -0,0 +1,25 @@
+extern "C" {
+ int i; // { dg-message "previous" }
+ float f; // { dg-message "previous" }
+ void fn (); // { dg-message "previous" }
+ int ai1[1]; // { dg-message "previous" }
+ extern int ai[];
+
+ namespace OK
+ {
+ int i;
+ float f;
+ void fn ();
+ extern int ai1[];
+ int ai[2];
+ }
+
+ namespace BAD
+ {
+ long i; // { dg-error "C language linkage" }
+ double f; // { dg-error "C language linkage" }
+ int fn (); // { dg-error "C language linkage" }
+ int ai1[2]; // { dg-error "C language linkage" }
+ }
+}
+
diff --git a/gcc/testsuite/g++.dg/lto/pr82414_0.C b/gcc/testsuite/g++.dg/lto/pr82414_0.C
new file mode 100644
index 0000000..2975371
--- /dev/null
+++ b/gcc/testsuite/g++.dg/lto/pr82414_0.C
@@ -0,0 +1,13 @@
+// PR c++/82414
+// { dg-lto-do link }
+// { dg-lto-options { { -flto -g } } }
+
+typedef __attribute__ ((__aligned__ (16))) struct S { __extension__ unsigned long long Part[2]; } T; // bogus warning "violates one definition rule"
+
+int
+main ()
+{
+ T tf;
+ asm volatile ("" : : "g" (__alignof__(tf)), "g" (__alignof__ (struct S)), "g" (__alignof__ (T)));
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/missing-symbol-2.C b/gcc/testsuite/g++.dg/missing-symbol-2.C
new file mode 100644
index 0000000..4a119f8
--- /dev/null
+++ b/gcc/testsuite/g++.dg/missing-symbol-2.C
@@ -0,0 +1,58 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+extern int foo (void);
+
+void missing_open_paren (void)
+{
+ if foo ()) /* { dg-error "expected '\\(' before 'foo'" } */
+ {
+ }
+ /* { dg-begin-multiline-output "" }
+ if foo ())
+ ^~~
+ (
+ { dg-end-multiline-output "" } */
+}
+
+
+void missing_close_square (void)
+{
+ const char test [42; /* { dg-error "22: expected ']' before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ const char test [42;
+ ^
+ ]
+ { dg-end-multiline-output "" } */
+}
+
+int missing_semicolon (void)
+{
+ return 42 /* { dg-error "expected ';'" } */
+}
+/* { dg-begin-multiline-output "" }
+ return 42
+ ^
+ ;
+ }
+ ~
+ { dg-end-multiline-output "" } */
+
+
+int missing_colon_in_switch (int val)
+{
+ switch (val)
+ {
+ case 42 /* { dg-error "expected ':' before 'return'" } */
+ return 42;
+ /* { dg-begin-multiline-output "" }
+ case 42
+ ^
+ :
+ return 42;
+ ~~~~~~
+ { dg-end-multiline-output "" } */
+
+ default:
+ return val;
+ }
+}
diff --git a/gcc/testsuite/g++.dg/opt/pr70100.C b/gcc/testsuite/g++.dg/opt/pr70100.C
new file mode 100644
index 0000000..3f612cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr70100.C
@@ -0,0 +1,21 @@
+// PR middle-end/70100
+// { dg-do compile { target c++11 } }
+// { dg-options "-O0" }
+
+void
+bar (int)
+{
+}
+
+template <typename ... Args>
+void
+foo (Args && ... args)
+{
+ [&] { [&] { bar(args...); }; };
+}
+
+int
+main ()
+{
+ foo (2);
+}
diff --git a/gcc/testsuite/g++.dg/opt/pr81715.C b/gcc/testsuite/g++.dg/opt/pr81715.C
new file mode 100644
index 0000000..c38b22b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr81715.C
@@ -0,0 +1,36 @@
+// PR sanitizer/81715
+// { dg-do compile }
+// Verify the variables for inlined foo parameters are reused
+// { dg-options "-O2 -Wframe-larger-than=16384" }
+
+struct S { int a, b, c, d, e; char f[1024]; };
+void baz (int *, int *, int *, struct S *, int *, int *);
+
+static inline struct S
+foo (int a, int b, int c, struct S d, int e, int f)
+{
+ struct S s;
+ baz (&a, &b, &c, &d, &e, &f);
+ s = d;
+ return s;
+}
+
+struct S g[64];
+
+void
+bar (int a, int b, int c, struct S d, int e, int f)
+{
+#define A(N) \
+ g[N+0] = foo (a, b, c, d, e, f); \
+ g[N+1] = foo (a, b, c, d, e, f); \
+ g[N+2] = foo (a, b, c, d, e, f); \
+ g[N+3] = foo (a, b, c, d, e, f); \
+ g[N+4] = foo (a, b, c, d, e, f); \
+ g[N+5] = foo (a, b, c, d, e, f); \
+ g[N+6] = foo (a, b, c, d, e, f); \
+ g[N+7] = foo (a, b, c, d, e, f); \
+ foo (a, b, c, d, e, f); \
+ foo (a, b, c, d, e, f)
+ A(0); A(8); A(16); A(24);
+ A(32); A(40); A(48); A(56);
+}
diff --git a/gcc/testsuite/g++.dg/opt/pr82159-2.C b/gcc/testsuite/g++.dg/opt/pr82159-2.C
new file mode 100644
index 0000000..f153c29
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr82159-2.C
@@ -0,0 +1,65 @@
+// PR c++/82159
+// { dg-do compile }
+// { dg-options "" }
+
+template <typename T> struct D { T e; };
+struct F : D<int[0]> {
+ F(const F &);
+};
+struct G : F {
+ template <class T> G operator-(T);
+};
+template <class T> struct I {
+ typedef typename T::template J<I> ak;
+};
+template <class T> struct K { typename I<T>::ak an; };
+struct H {
+ G l;
+};
+struct C {
+ ~C();
+};
+template <class T> struct M : T {
+ template <typename U, typename V> M(U, V);
+ H h;
+ virtual void foo() { T::bar(&h); }
+};
+template <int, typename> class A;
+template <class> struct B {
+ typedef int BT;
+ struct BC {};
+ template <class T> struct BD {
+ G g;
+ BD(BT, T n) : g(n.l - 0) {}
+ };
+ B(BT, BC);
+};
+template <typename> struct O;
+template <int T, typename U>
+struct O<B<A<T, U> > > : public B<A<T, U> >::BC {};
+struct L : B<A<2, double> > {
+ struct P : C {
+ void bar(H *x) {
+ BT a;
+ BD<H>(a, *x);
+ }
+ };
+ template <typename U, typename V> L(U x, V n) : B(x, n) {}
+ int ll;
+ virtual int baz() { M<P>(this, ll); }
+};
+template <typename> class Q {
+ O<B<A<2, double> > > q;
+ virtual L baz() { L(0, q); }
+};
+template <template <class> class T> struct R {
+ R() { T<int>(); }
+};
+struct S {
+ template <class> class J : R<Q> {};
+};
+void foo() { K<S> c; }
+
+int main() {
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/opt/pr82159.C b/gcc/testsuite/g++.dg/opt/pr82159.C
new file mode 100644
index 0000000..e39dbc3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr82159.C
@@ -0,0 +1,18 @@
+// PR c++/82159
+// { dg-do compile }
+// { dg-options "" }
+
+template<int N>
+struct S
+{
+ ~S () {}
+ template<int M> S<M> foo () { return S<M> (); }
+ unsigned char data[N];
+};
+
+int
+main ()
+{
+ S<16> d;
+ S<0> t = d.foo<0> ();
+}
diff --git a/gcc/testsuite/g++.dg/opt/pr82577.C b/gcc/testsuite/g++.dg/opt/pr82577.C
new file mode 100644
index 0000000..1a06897
--- /dev/null
+++ b/gcc/testsuite/g++.dg/opt/pr82577.C
@@ -0,0 +1,22 @@
+// { dg-additional-options "-O2" }
+// PR c++/82577 ICE when optimizing
+
+#if __cplusplus > 201500L
+// register is no longer a keyword in C++17.
+#define register
+#endif
+
+class a {
+public:
+ int *b();
+};
+struct c {
+ int d;
+ a e;
+} f;
+void fn1(register c *g) {
+ register int *h;
+ do
+ (h) = g->e.b() + (g)->d;
+ while (&f);
+}
diff --git a/gcc/testsuite/g++.dg/other/do1.C b/gcc/testsuite/g++.dg/other/do1.C
index b3a9daf..db65e7d 100644
--- a/gcc/testsuite/g++.dg/other/do1.C
+++ b/gcc/testsuite/g++.dg/other/do1.C
@@ -7,7 +7,7 @@
void init ()
{
- do { } while (0)
- obj = 0; // { dg-error "expected|not declared" }
+ do { } while (0) // { dg-error "expected ';'" }
+ obj = 0; // { dg-error "not declared" }
}
diff --git a/gcc/testsuite/g++.dg/other/dump-ada-spec-10.C b/gcc/testsuite/g++.dg/other/dump-ada-spec-10.C
new file mode 100644
index 0000000..0e641ae
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/dump-ada-spec-10.C
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-fdump-ada-spec" } */
+
+extern int convert_to_int (float f);
+extern int convert_to_int (double d);
+extern int convert_to_int (long double ld);
+
+class S1
+{
+ S1 ();
+ int convert_to_int (float f);
+ int convert_to_int (double d);
+ int convert_to_int (long double ld);
+};
+
+class S2
+{
+ S2 ();
+ virtual int convert_to_int (float f);
+ virtual int convert_to_int (double d);
+ virtual int convert_to_int (long double ld);
+};
+
+/* { dg-final { cleanup-ada-spec } } */
diff --git a/gcc/testsuite/g++.dg/other/pr53574.C b/gcc/testsuite/g++.dg/other/pr53574.C
new file mode 100644
index 0000000..cc899a5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/pr53574.C
@@ -0,0 +1,48 @@
+// PR c++/53574
+// { dg-do compile { target c++11 } }
+// { dg-options "-fstack-usage" }
+
+template <typename> struct A { typedef int type; };
+struct B {
+ typedef __SIZE_TYPE__ H;
+};
+template <typename> class allocator : B {};
+template <typename _Alloc> struct C {
+ template <typename T>
+ static typename T::H foo(T *);
+ typedef decltype(foo((_Alloc *)0)) H;
+ template <typename U>
+ static typename A<H>::type bar(U) { return typename A<H>::type (); }
+ static int baz(_Alloc p1) { bar(p1); return 0; }
+};
+template <typename _Alloc> struct I : C<_Alloc> {};
+template <typename, typename> struct J {
+ typedef I<allocator<int>> K;
+ K k;
+};
+struct D : J<int, allocator<int>> {
+ void fn(int, int) {
+ K m;
+ I<K>::baz(m);
+ }
+};
+template <class Ch, class = int, class = int> struct F {
+ F();
+ F(const Ch *);
+ F test();
+ D d;
+};
+int l;
+struct G {
+ G(F<char>);
+};
+char n;
+template <class Ch, class Tr, class Alloc> F<Ch, Tr, Alloc>::F(const Ch *) {
+ test();
+}
+template <class Ch, class Tr, class Alloc>
+F<Ch, Tr, Alloc> F<Ch, Tr, Alloc>::test() {
+ d.fn(l, 0);
+ return F<Ch, Tr, Alloc> ();
+}
+G fn1() { return G(&n); }
diff --git a/gcc/testsuite/g++.dg/other/pr68252.C b/gcc/testsuite/g++.dg/other/pr68252.C
new file mode 100644
index 0000000..5460d81
--- /dev/null
+++ b/gcc/testsuite/g++.dg/other/pr68252.C
@@ -0,0 +1,5 @@
+// PR c++/68252
+
+struct Test {
+ static const int foo = (1 << sizeof (int)) * -3;
+};
diff --git a/gcc/testsuite/g++.dg/parse/builtin2.C b/gcc/testsuite/g++.dg/parse/builtin2.C
index c524ea6..daa80bb 100644
--- a/gcc/testsuite/g++.dg/parse/builtin2.C
+++ b/gcc/testsuite/g++.dg/parse/builtin2.C
@@ -1,5 +1,5 @@
// PR c++/14432
-// { dg-options "" }
+// { dg-options "-Wno-builtin-declaration-mismatch" }
struct Y {};
Y y1;
diff --git a/gcc/testsuite/g++.dg/parse/error11.C b/gcc/testsuite/g++.dg/parse/error11.C
index d118c19..1a49d6e 100644
--- a/gcc/testsuite/g++.dg/parse/error11.C
+++ b/gcc/testsuite/g++.dg/parse/error11.C
@@ -52,7 +52,7 @@ void func(void)
Foo[:B> k1; // { dg-bogus "cannot begin|alternate spelling" "smart error should not be triggered here" }
// { dg-error "6:missing template arguments before" "template" { target *-*-* } 51 }
// { dg-error "9:expected primary-expression before ':' token" "primary" { target *-*-* } 51 }
-// { dg-error "9:expected '\]' before ':' token" "backslash" { target *-*-* } 51 }
+// { dg-error "8:expected '\]' before ':' token" "backslash" { target *-*-* } 51 }
// { dg-error "6:missing template arguments before" "template" { target *-*-* } 52 }
// { dg-error "7:expected primary-expression before ':' token" "primary" { target *-*-* } 52 }
// { dg-error "7:expected '\]' before ':' token" "backslash" { target *-*-* } 52 }
diff --git a/gcc/testsuite/g++.dg/parse/pragma2.C b/gcc/testsuite/g++.dg/parse/pragma2.C
index 3dc5fc1..c5616ff 100644
--- a/gcc/testsuite/g++.dg/parse/pragma2.C
+++ b/gcc/testsuite/g++.dg/parse/pragma2.C
@@ -4,5 +4,5 @@
// does not.
int f(int x,
#pragma interface // { dg-error "not allowed here" }
- // { dg-bogus "expected identifier" "" { xfail *-*-* } .-1 }
- int y);
+ // The parser gets confused and issues an error on the next line.
+ int y); // { dg-bogus "" "" { xfail *-*-* } }
diff --git a/gcc/testsuite/g++.dg/pr82155.C b/gcc/testsuite/g++.dg/pr82155.C
new file mode 100644
index 0000000..75d9b61
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr82155.C
@@ -0,0 +1,36 @@
+/* { dg-do compile { target c++11 } } */
+/* { dg-options "-g -O2" } */
+
+template <typename a> struct b { a c; };
+template <typename d> struct e { d *operator->(); };
+template <typename d> class h {
+public:
+ typedef e<d> ag;
+};
+class i {
+protected:
+ i(int);
+};
+class j {
+ virtual void k(int) = 0;
+
+public:
+ int f;
+ void l() { k(f); }
+};
+struct m : i {
+ int cn;
+ m() : i(cn) {
+ struct n : j {
+ n() {}
+ void k(int) {}
+ };
+ }
+};
+struct o {
+ o() {
+ for (h<b<b<j *>>>::ag g;;)
+ g->c.c->l();
+ }
+};
+void fn1() { o(); }
diff --git a/gcc/testsuite/g++.dg/pr82413.C b/gcc/testsuite/g++.dg/pr82413.C
new file mode 100644
index 0000000..a44751d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr82413.C
@@ -0,0 +1,3 @@
+bool a;
+int b;
+void c() { b &&a <= 0; }
diff --git a/gcc/testsuite/g++.dg/template/bitfield4.C b/gcc/testsuite/g++.dg/template/bitfield4.C
new file mode 100644
index 0000000..4927b7a
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/bitfield4.C
@@ -0,0 +1,6 @@
+// PR c++/82357
+
+template <typename> struct A {
+ A() { x |= 0; }
+ int x : 8;
+};
diff --git a/gcc/testsuite/g++.dg/template/cast4.C b/gcc/testsuite/g++.dg/template/cast4.C
new file mode 100644
index 0000000..2f46c71
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/cast4.C
@@ -0,0 +1,4 @@
+template <class T> void f()
+{
+ static_cast<int&>(42); // { dg-error "static_cast" }
+}
diff --git a/gcc/testsuite/g++.dg/template/crash108.C b/gcc/testsuite/g++.dg/template/crash108.C
index 221d80e..9bcabc6 100644
--- a/gcc/testsuite/g++.dg/template/crash108.C
+++ b/gcc/testsuite/g++.dg/template/crash108.C
@@ -1,5 +1,5 @@
// PR c++/50861
-template<class T> struct A {A(int b=k(0));}; // { dg-error "parameter|arguments" }
+template<class T> struct A {A(int b=k(0));}; // { dg-error "parameter|argument" }
void f(int k){A<int> a;} // // { dg-message "declared" }
// { dg-message "note" "note" { target *-*-* } 3 }
diff --git a/gcc/testsuite/g++.dg/template/crash128.C b/gcc/testsuite/g++.dg/template/crash128.C
new file mode 100644
index 0000000..2682e3d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/crash128.C
@@ -0,0 +1,19 @@
+// PR c++/54090
+
+template <int n>
+struct X {
+
+ template <int N, bool = (n >= N), typename T = void> struct Y;
+
+ template <int N, typename T>
+ struct Y<N, true, T> {};
+
+ static const int M = n / 2;
+
+ template <typename T>
+ struct Y<X::M, true, T> {};
+};
+
+void foo() {
+ X<10>::Y<10/2> y;
+}
diff --git a/gcc/testsuite/g++.dg/template/error11.C b/gcc/testsuite/g++.dg/template/error11.C
index 3a469fd..1640298 100644
--- a/gcc/testsuite/g++.dg/template/error11.C
+++ b/gcc/testsuite/g++.dg/template/error11.C
@@ -1,4 +1,4 @@
// PR c++/12132
inline template <int> void foo () {} // { dg-error "<" }
-void abort (); // { dg-error ";" }
+void abort (); // { dg-error ";" "" { target *-*-* } .-1 }
diff --git a/gcc/testsuite/g++.dg/template/extern-c.C b/gcc/testsuite/g++.dg/template/extern-c.C
new file mode 100644
index 0000000..c0dd7cb
--- /dev/null
+++ b/gcc/testsuite/g++.dg/template/extern-c.C
@@ -0,0 +1,66 @@
+template <typename T> void specializable (T);
+
+/* Invalid template: within "extern C". */
+
+extern "C" { // { dg-message "1: 'extern .C.' linkage started here" }
+
+template <typename T> // { dg-error "template with C linkage" }
+void within_extern_c_braces (void);
+
+}
+
+/* Valid template: not within "extern C". */
+
+template <typename T>
+void not_within_extern_c (void);
+
+
+/* Invalid specialization: within "extern C". */
+
+extern "C" { // { dg-message "1: 'extern .C.' linkage started here" }
+
+template <> // { dg-error "template specialization with C linkage" }
+void specializable (int);
+
+}
+
+
+/* Valid specialization: not within "extern C". */
+template <>
+void specializable (char);
+
+
+/* Example of extern C without braces. */
+
+extern "C" template <typename T> // { dg-line open_extern_c_no_braces }
+void within_extern_c_no_braces (void);
+// { dg-error "12: template with C linkage" "" { target *-*-* } open_extern_c_no_braces }
+// { dg-message "1: 'extern .C.' linkage started here" "" { target *-*-* } open_extern_c_no_braces }
+
+
+/* Nested extern "C" specifications.
+ We should report within the innermost extern "C" that's still open. */
+
+extern "C" {
+ extern "C" { // { dg-line middle_open_extern_c }
+ extern "C" {
+ }
+
+ template <typename T> // { dg-error "template with C linkage" }
+ void within_nested_extern_c (void);
+ // { dg-message "3: 'extern .C.' linkage started here" "" { target *-*-* } middle_open_extern_c }
+
+ extern "C++" {
+ /* Valid template: within extern "C++". */
+ template <typename T>
+ void within_nested_extern_cpp (void);
+
+ extern "C" { // { dg-line last_open_extern_c }
+ /* Invalid template: within "extern C". */
+ template <typename T> // { dg-error "template with C linkage" }
+ void within_extern_c_within_extern_cpp (void);
+ // { dg-message "7: 'extern .C.' linkage started here" "" { target *-*-* } last_open_extern_c }
+ }
+ }
+ }
+}
diff --git a/gcc/testsuite/g++.dg/torture/pr77555.C b/gcc/testsuite/g++.dg/torture/pr77555.C
new file mode 100644
index 0000000..540d1a0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr77555.C
@@ -0,0 +1,20 @@
+// { dg-do link }
+// { dg-options "-std=c++11" }
+
+extern "C" int printf(const char*, ...);
+struct A {
+ A(int, char *p2) { printf(p2); }
+};
+template <int, typename> struct B { static A static_var; };
+template <int LINE, typename GETTER>
+A B<LINE, GETTER>::static_var{0, GETTER::get()};
+struct C {
+ void unused() {
+ static char function_static;
+ struct D {
+ static char *get() { return &function_static; }
+ };
+ auto addr = B<0, D>::static_var;
+ }
+};
+int main() {}
diff --git a/gcc/testsuite/g++.dg/torture/pr79180.C b/gcc/testsuite/g++.dg/torture/pr79180.C
new file mode 100644
index 0000000..2e3992c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/torture/pr79180.C
@@ -0,0 +1,23 @@
+// { dg-do run }
+// { dg-options "-Wall -std=c++11" }
+
+void
+foo (int a)
+{
+ if (a != 127)
+ __builtin_abort ();
+}
+
+template <typename... Args>
+void
+bar (Args &&... args)
+{
+ [&]() { [&]() { foo (args...); } (); } ();
+}
+
+int
+main ()
+{
+ int x = 127;
+ bar (x);
+}
diff --git a/gcc/testsuite/g++.dg/tree-ssa/pr8781.C b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C
index 1f33900..1f115b2 100644
--- a/gcc/testsuite/g++.dg/tree-ssa/pr8781.C
+++ b/gcc/testsuite/g++.dg/tree-ssa/pr8781.C
@@ -13,7 +13,7 @@ public:
};
template<typename predicate>
-inline noop_t<predicate> noop(const predicate pred) {
+inline noop_t<predicate> noop(const predicate &pred) {
return noop_t<predicate>(pred);
}
diff --git a/gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C b/gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
index f01c576..385a109 100644
--- a/gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
+++ b/gcc/testsuite/g++.dg/ubsan/float-cast-overflow-bf.C
@@ -52,11 +52,11 @@ main (void)
return 0;
}
-/* { dg-output "value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type" } */
+/* { dg-output " -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.14748e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 4.29497e\\\+09 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type" } */
diff --git a/gcc/testsuite/g++.dg/ubsan/pr81929.C b/gcc/testsuite/g++.dg/ubsan/pr81929.C
new file mode 100644
index 0000000..90f2628
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/pr81929.C
@@ -0,0 +1,14 @@
+// PR sanitizer/81929
+// { dg-do compile }
+// { dg-options "-std=c++14 -fsanitize=undefined" }
+
+struct S { S &operator<< (long); S foo (); S (); };
+
+void
+bar ()
+{
+ static_cast<S&>(S () << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0
+ << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0 << 0).foo ();
+}
diff --git a/gcc/testsuite/g++.dg/ubsan/pr82353-2-aux.cc b/gcc/testsuite/g++.dg/ubsan/pr82353-2-aux.cc
new file mode 100644
index 0000000..75d466b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/pr82353-2-aux.cc
@@ -0,0 +1,32 @@
+// PR sanitizer/82353
+
+#include "pr82353-2.h"
+
+B a;
+E b;
+B C::c0;
+unsigned D::d0;
+
+void
+foo ()
+{
+ a.b1 = p.f2.e2.b1 = 5;
+}
+
+void
+bar ()
+{
+ int c = p.f2.e4.d1.a0 - -~p.f4 * 89;
+ q.c0.b0 = i > g * a.b0 * h - k % a.b1;
+ if ((~(m * j) && -~p.f4 * 90284000534361) % ~m * j)
+ b.e2.b0 << l << f;
+ o = -~p.f4 * 89;
+ int d = p.f4;
+ if (b.e2.b0)
+ b.e2.b1 = c;
+ bool e = ~-~p.f4;
+ a.b1 % e;
+ if (k / p.f2.e2.b1)
+ b.e4.d0 = g * a.b0 * h;
+ n = j;
+}
diff --git a/gcc/testsuite/g++.dg/ubsan/pr82353-2.C b/gcc/testsuite/g++.dg/ubsan/pr82353-2.C
new file mode 100644
index 0000000..31a35ac
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/pr82353-2.C
@@ -0,0 +1,20 @@
+// PR sanitizer/82353
+// { dg-do run }
+// { dg-options "-fsanitize=undefined -fno-sanitize-recover=undefined -std=c++11 -O2 -w" }
+// { dg-additional-sources "pr82353-2-aux.cc" }
+
+#include "pr82353-2.h"
+
+unsigned long f, g;
+bool h, k, j, i;
+unsigned char l, m;
+short n;
+unsigned o;
+F p;
+
+int
+main ()
+{
+ foo ();
+ bar ();
+}
diff --git a/gcc/testsuite/g++.dg/ubsan/pr82353-2.h b/gcc/testsuite/g++.dg/ubsan/pr82353-2.h
new file mode 100644
index 0000000..4693d22
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/pr82353-2.h
@@ -0,0 +1,31 @@
+extern unsigned long f, g;
+extern bool h, i, j, k;
+extern unsigned char l, m;
+extern short n;
+extern unsigned o;
+struct B {
+ short b0 : 27;
+ long b1 : 10;
+};
+struct A {
+ int a0 : 5;
+};
+struct C {
+ static B c0;
+};
+struct D {
+ static unsigned d0;
+ A d1;
+};
+struct E {
+ B e2;
+ D e4;
+};
+struct F {
+ E f2;
+ short f4;
+};
+extern F p;
+extern C q;
+void foo ();
+void bar ();
diff --git a/gcc/testsuite/g++.dg/ubsan/pr82353.C b/gcc/testsuite/g++.dg/ubsan/pr82353.C
new file mode 100644
index 0000000..a967cef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/ubsan/pr82353.C
@@ -0,0 +1,60 @@
+/* { dg-do compile { target { { i?86-*-* x86_64-*-* } && lp64 } } } */
+/* { dg-options "-O2 -std=c++11 -fsanitize=undefined -fno-sanitize-recover=undefined -w -fdump-rtl-reload" } */
+
+extern unsigned long tf_2_var_1, tf_2_var_21;
+extern bool tf_2_var_2, tf_2_var_24, tf_2_var_6, tf_2_var_5;
+extern unsigned char tf_2_var_16, tf_2_var_31;
+extern short tf_2_var_69;
+extern unsigned tf_2_var_233;
+struct tf_2_struct_1 {
+ short member_1_0 : 27;
+ long member_1_1 : 10;
+};
+struct a {
+ int member_2_0 : 5;
+};
+struct tf_2_struct_3 {
+ static tf_2_struct_1 member_3_0;
+};
+struct tf_2_struct_4 {
+ static unsigned member_4_0;
+ a member_4_1;
+};
+struct tf_2_struct_5 {
+ tf_2_struct_1 member_5_2;
+ tf_2_struct_4 member_5_4;
+};
+struct tf_2_struct_6 {
+ tf_2_struct_5 member_6_2;
+ short member_6_4;
+} extern tf_2_struct_obj_2;
+extern tf_2_struct_3 tf_2_struct_obj_8;
+tf_2_struct_1 a;
+tf_2_struct_5 b;
+tf_2_struct_1 tf_2_struct_3::member_3_0;
+unsigned tf_2_struct_4::member_4_0;
+void tf_2_init() {
+ a.member_1_1 = tf_2_struct_obj_2.member_6_2.member_5_2.member_1_1 = 5;
+}
+void tf_2_foo() {
+ int c = tf_2_struct_obj_2.member_6_2.member_5_4.member_4_1.member_2_0 -
+ -~tf_2_struct_obj_2.member_6_4 * char(90284000534361);
+ tf_2_struct_obj_8.member_3_0.member_1_0 =
+ tf_2_var_24 >
+ tf_2_var_21 * a.member_1_0 * tf_2_var_2 - tf_2_var_5 % a.member_1_1;
+ if ((~(tf_2_var_31 * tf_2_var_6) &&
+ -~tf_2_struct_obj_2.member_6_4 * 90284000534361) %
+ ~tf_2_var_31 * tf_2_var_6)
+ b.member_5_2.member_1_0 << tf_2_var_16 << tf_2_var_1;
+ tf_2_var_233 = -~tf_2_struct_obj_2.member_6_4 * char(90284000534361);
+ int d(tf_2_struct_obj_2.member_6_4);
+ if (b.member_5_2.member_1_0)
+ b.member_5_2.member_1_1 = c;
+ bool e(~-~tf_2_struct_obj_2.member_6_4);
+ a.member_1_1 % e;
+ if (tf_2_var_5 / tf_2_struct_obj_2.member_6_2.member_5_2.member_1_1)
+ b.member_5_4.member_4_0 = tf_2_var_21 * a.member_1_0 * tf_2_var_2;
+ tf_2_var_69 = tf_2_var_6;
+}
+
+/* { dg-final { scan-rtl-dump-not "Inserting rematerialization insn" "reload" } } */
diff --git a/gcc/testsuite/g++.dg/vect/slp-pr56812.cc b/gcc/testsuite/g++.dg/vect/slp-pr56812.cc
index 80bdcdd..8b24b33 100644
--- a/gcc/testsuite/g++.dg/vect/slp-pr56812.cc
+++ b/gcc/testsuite/g++.dg/vect/slp-pr56812.cc
@@ -17,4 +17,6 @@ void mydata::Set (float x)
data[i] = x;
}
-/* { dg-final { scan-tree-dump-times "basic block vectorized" 1 "slp1" } } */
+/* For targets without vector loop peeling the loop becomes cheap
+ enough to be vectorized. */
+/* { dg-final { scan-tree-dump-times "basic block vectorized" 1 "slp1" { xfail { ! vect_peeling_profitable } } } } */
diff --git a/gcc/testsuite/g++.dg/warn/Wbuiltin_declaration_mismatch-1.C b/gcc/testsuite/g++.dg/warn/Wbuiltin_declaration_mismatch-1.C
new file mode 100644
index 0000000..713073c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wbuiltin_declaration_mismatch-1.C
@@ -0,0 +1,7 @@
+// PR c++/82466
+// { dg-options "-Wbuiltin-declaration-mismatch" }
+
+namespace N
+{
+ int printf;
+}
diff --git a/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-4.C b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-4.C
new file mode 100644
index 0000000..492dcb9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/Wreturn-local-addr-4.C
@@ -0,0 +1,18 @@
+// PR c++/82600
+// { dg-do compile }
+
+void *b[10];
+
+template <int N>
+void **
+foo (int x)
+{
+ void **a = b; // { dg-bogus "address of local variable 'a' returned" }
+ return &a[x];
+}
+
+void **
+bar (int x)
+{
+ return foo <0> (x);
+}
diff --git a/gcc/testsuite/g++.dg/warn/mvp.C b/gcc/testsuite/g++.dg/warn/mvp.C
new file mode 100644
index 0000000..9fbe227
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/mvp.C
@@ -0,0 +1,78 @@
+// { dg-additional-options -Wparentheses }
+
+// Most Vexing Parse warnings
+// in C++ anythig that syntactically looks like a decl IS a decl, this
+// can lead to confused users, but worse silent unexpectedly unsafe
+// code generation.
+
+int (a); // { dg-warning "" }
+int (*b); // { dg-warning "" }
+extern int (&c); // { dg-warning "" }
+
+int h1 = 0, h2 = 0;
+struct H { H(...);};
+
+namespace fns
+{
+ int (*a) ();
+ int (b) ();
+ int (*c ()) ();
+ int (d1 ()); // { dg-warning "" }
+ int (d2 // { dg-warning "" }
+ ());
+ int (e) (int);
+ int g (int (a)); // No warning because ...
+ H h (int (h1), int (h2), 3); // ... not a function decl.
+}
+
+namespace arys
+{
+ int (*a)[1];
+ int (b)[1];
+ int (*c[1])[1];
+ int (d1[1]); // { dg-warning "" }
+ int (d2
+ [1]);
+ int (e[1])[1];
+}
+
+namespace complex
+{
+ int (*a())[1];
+ int (*b[1])();
+ int ((*c1())[1]); // { dg-warning "" }
+ int ((*c2())
+ [1]);
+ int ((*d1[1])()); // { dg-warning "" }
+ int ((*d2[1]) // { dg-warning "" }
+ ());
+}
+
+namespace motivation
+{
+ typedef int shared_mutex; // for exposition
+ struct locker
+ {
+ locker ();
+ locker (int &r);
+ ~locker ();
+ };
+ class protected_state
+ {
+ shared_mutex mutex; // not a real mutex type
+ int state;
+
+ public:
+ void not_thread_safe ()
+ {
+ locker (mutex); // { dg-warning "" }
+ state++; // oops
+ }
+
+ void thread_safe ()
+ {
+ locker lock (mutex);
+ state++; // ok;
+ }
+ };
+}
diff --git a/gcc/testsuite/g++.dg/warn/pr82424.C b/gcc/testsuite/g++.dg/warn/pr82424.C
new file mode 100644
index 0000000..43dd5e4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/warn/pr82424.C
@@ -0,0 +1,20 @@
+// { dg-additional-options "-Wshadow=compatible-local" }
+
+// pr c++/82424 we were trying to convert between dependent types.
+template <typename T> class a
+{
+ struct b;
+ template <typename, typename> void c ();
+};
+template <typename T>
+template <typename, typename>
+void
+a<T>::c ()
+{
+ typedef typename T::b b; // Don't go looking inside the typename
+ T thing;
+ {
+ T thing; // { dg-warning "shadows a previous local" }
+ }
+}
+
diff --git a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
index 2c88a95..96533e0 100644
--- a/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
+++ b/gcc/testsuite/g++.old-deja/g++.abi/vtable2.C
@@ -1,5 +1,5 @@
// { dg-do run }
-// { dg-options "-Wno-attributes -fno-strict-aliasing" }
+// { dg-options "-Wno-attribute-alias -fno-strict-aliasing" }
// Origin: Mark Mitchell <mark@codesourcery.com>
#if defined (__GXX_ABI_VERSION) && __GXX_ABI_VERSION >= 100
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/eh48.C b/gcc/testsuite/g++.old-deja/g++.mike/eh48.C
index d9caf61..458fd01 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/eh48.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/eh48.C
@@ -1,5 +1,5 @@
// { dg-do run { xfail sparc64-*-elf arm-*-pe } }
-// { dg-options "-fexceptions" }
+// { dg-options "-fexceptions -Wno-deprecated" }
#include <exception>
#include <stdlib.h>
diff --git a/gcc/testsuite/g++.old-deja/g++.mike/p811.C b/gcc/testsuite/g++.old-deja/g++.mike/p811.C
index 5c8260a..2ca04ab 100644
--- a/gcc/testsuite/g++.old-deja/g++.mike/p811.C
+++ b/gcc/testsuite/g++.old-deja/g++.mike/p811.C
@@ -1,5 +1,5 @@
// { dg-do assemble }
-// { dg-options "" }
+// { dg-options "-Wno-builtin-declaration-mismatch" }
// This test case caused the compiler to abort at one point in time.
// prms-id: 811
diff --git a/gcc/testsuite/g++.old-deja/g++.other/using9.C b/gcc/testsuite/g++.old-deja/g++.other/using9.C
index 0e34156..c79f993 100644
--- a/gcc/testsuite/g++.old-deja/g++.other/using9.C
+++ b/gcc/testsuite/g++.old-deja/g++.other/using9.C
@@ -13,7 +13,7 @@ struct x {};
using ::x;
using ::a;
-extern "C" void foo (); // { dg-error "previous declaration" }
+extern "C" void foo (); // { dg-message "previous declaration" }
namespace {
extern "C" int foo (); // { dg-error "C.*linkage" }
diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash3.C b/gcc/testsuite/g++.old-deja/g++.pt/crash3.C
index 160cbe5..e5b3f25 100644
--- a/gcc/testsuite/g++.old-deja/g++.pt/crash3.C
+++ b/gcc/testsuite/g++.old-deja/g++.pt/crash3.C
@@ -6,11 +6,11 @@ public:
CVector<int> f() const
{
CVector<int> v();
- return v;
+ return v; // { dg-error "convert" }
}
CVector<long> g() const
{
CVector<long> v();
- return v;
+ return v; // { dg-error "convert" }
}
};
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr82337.c b/gcc/testsuite/gcc.c-torture/compile/pr82337.c
new file mode 100644
index 0000000..e6060e4
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr82337.c
@@ -0,0 +1,27 @@
+/* PR82337: SLSR needs to prevent abnormal SSA names from
+ serving as a basis. */
+/* { dg-require-effective-target nonlocal_goto } */
+
+char *a, *b, *c;
+
+struct d {
+ short e;
+ char f[];
+};
+
+extern void j (void);
+
+void
+g() {
+ struct d *h;
+ char *i;
+ int d;
+ do {
+ i = h->f + d;
+ 20 ? j() : 0;
+ i = c;
+ if (__builtin_setjmp (h))
+ b = h->f + d;
+ d = (int)(*i);
+ } while (a);
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr82381.c b/gcc/testsuite/gcc.c-torture/compile/pr82381.c
new file mode 100644
index 0000000..3ff2c3a
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr82381.c
@@ -0,0 +1,18 @@
+/* PR tree-optimization/82381 */
+/* { dg-do compile } */
+
+signed char b, h;
+unsigned short c, e;
+short int d, f, g;
+
+void
+foo ()
+{
+ if (h)
+ {
+ short a = -(d + c - b);
+ f = e - a - -d;
+ }
+ if (c)
+ g = 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr82389.c b/gcc/testsuite/gcc.c-torture/compile/pr82389.c
new file mode 100644
index 0000000..798bd84
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr82389.c
@@ -0,0 +1,13 @@
+/* PR tree-optimization/82389 */
+
+void bar (short);
+
+void
+foo (void)
+{
+ short a[5];
+ int b;
+ for (b = -1290603998; b < 5; b++)
+ a[b] = 0;
+ bar (a[3]);
+}
diff --git a/gcc/testsuite/gcc.c-torture/compile/pr82549.c b/gcc/testsuite/gcc.c-torture/compile/pr82549.c
new file mode 100644
index 0000000..11525cd
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/compile/pr82549.c
@@ -0,0 +1,9 @@
+/* PR tree-optimization/82549 */
+
+int a, b[1];
+
+int
+main ()
+{
+ return !a || b[-2] || b[-2];
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/20030209-1.c b/gcc/testsuite/gcc.c-torture/execute/20030209-1.c
index 8f076ec..52f71ec 100644
--- a/gcc/testsuite/gcc.c-torture/execute/20030209-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/20030209-1.c
@@ -1,12 +1,5 @@
-/* { dg-add-options stack_size } */
+/* { dg-require-stack-size "8*100*100" } */
-#ifdef STACK_SIZE
-#if STACK_SIZE < 8*100*100
-#define SKIP
-#endif
-#endif
-
-#ifndef SKIP
double x[100][100];
int main ()
{
@@ -18,10 +11,3 @@ int main ()
abort ();
exit (0);
}
-#else
-int
-main ()
-{
- exit (0);
-}
-#endif
diff --git a/gcc/testsuite/gcc.c-torture/execute/20040709-3.c b/gcc/testsuite/gcc.c-torture/execute/20040709-3.c
new file mode 100644
index 0000000..e6622c6
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20040709-3.c
@@ -0,0 +1,5 @@
+/* PR rtl-optimization/68205 */
+/* { dg-require-effective-target int32plus } */
+/* { dg-additional-options "-fno-common" } */
+
+#include "20040709-2.c"
diff --git a/gcc/testsuite/gcc.c-torture/execute/20040805-1.c b/gcc/testsuite/gcc.c-torture/execute/20040805-1.c
index d3208d6..f311092 100644
--- a/gcc/testsuite/gcc.c-torture/execute/20040805-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/20040805-1.c
@@ -1,6 +1,6 @@
-/* { dg-add-options stack_size } */
+/* { dg-require-stack-size "0x12000" } */
-#if __INT_MAX__ < 32768 || (defined(STACK_SIZE) && STACK_SIZE < 0x12000)
+#if __INT_MAX__ < 32768
int main () { exit (0); }
#else
int a[2] = { 2, 3 };
diff --git a/gcc/testsuite/gcc.c-torture/execute/20171008-1.c b/gcc/testsuite/gcc.c-torture/execute/20171008-1.c
new file mode 100644
index 0000000..cde807a
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/20171008-1.c
@@ -0,0 +1,38 @@
+struct S { char c1, c2, c3, c4; } __attribute__((aligned(4)));
+
+static char bar (char **p) __attribute__((noclone, noinline));
+static struct S foo (void) __attribute__((noclone, noinline));
+
+int i;
+
+static char
+bar (char **p)
+{
+ i = 1;
+ return 0;
+}
+
+static struct S
+foo (void)
+{
+ struct S ret;
+ char r, s, c1, c2;
+ char *p = &r;
+
+ s = bar (&p);
+ if (s)
+ c2 = *p;
+ c1 = 0;
+
+ ret.c1 = c1;
+ ret.c2 = c2;
+ return ret;
+}
+
+int main (void)
+{
+ struct S s = foo ();
+ if (s.c1 != 0)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/920410-1.c b/gcc/testsuite/gcc.c-torture/execute/920410-1.c
index 44a72bd..daeff5e 100644
--- a/gcc/testsuite/gcc.c-torture/execute/920410-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/920410-1.c
@@ -1,8 +1,4 @@
-/* { dg-add-options stack_size } */
+/* { dg-require-stack-size "40000 * 4 + 256" } */
-#define STACK_REQUIREMENT (40000 * 4 + 256)
-#if defined (STACK_SIZE) && STACK_SIZE < STACK_REQUIREMENT
-main () { exit (0); }
-#else
main(){int d[40000];d[0]=0;exit(0);}
-#endif
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/921113-1.c b/gcc/testsuite/gcc.c-torture/execute/921113-1.c
index d3e44e3..824e69f 100644
--- a/gcc/testsuite/gcc.c-torture/execute/921113-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/921113-1.c
@@ -1,9 +1,4 @@
-/* { dg-add-options stack_size } */
-
-#define STACK_REQUIREMENT (128 * 128 * 4 + 1024)
-#if defined (STACK_SIZE) && STACK_SIZE < STACK_REQUIREMENT
-main () { exit (0); }
-#else
+/* { dg-require-stack-size "128 * 128 * 4 + 1024" } */
typedef struct {
float wsx;
@@ -62,4 +57,3 @@ main()
exit(0);
}
-#endif
diff --git a/gcc/testsuite/gcc.c-torture/execute/921208-2.c b/gcc/testsuite/gcc.c-torture/execute/921208-2.c
index da9ee52..01e14f8 100644
--- a/gcc/testsuite/gcc.c-torture/execute/921208-2.c
+++ b/gcc/testsuite/gcc.c-torture/execute/921208-2.c
@@ -1,10 +1,5 @@
/* { dg-require-effective-target untyped_assembly } */
-/* { dg-add-options stack_size } */
-
-#define STACK_REQUIREMENT (100000 * 4 + 1024)
-#if defined (STACK_SIZE) && STACK_SIZE < STACK_REQUIREMENT
-main () { exit (0); }
-#else
+/* { dg-require-stack-size "100000 * 4 + 1024" } */
g(){}
@@ -25,5 +20,3 @@ main ()
f();
exit(0);
}
-
-#endif
diff --git a/gcc/testsuite/gcc.c-torture/execute/comp-goto-1.c b/gcc/testsuite/gcc.c-torture/execute/comp-goto-1.c
index 2a84052..4379fe7 100644
--- a/gcc/testsuite/gcc.c-torture/execute/comp-goto-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/comp-goto-1.c
@@ -1,9 +1,9 @@
/* { dg-require-effective-target label_values } */
-/* { dg-add-options stack_size } */
+/* { dg-require-stack-size "4000" } */
#include <stdlib.h>
-#if (!defined(STACK_SIZE) || STACK_SIZE >= 4000) && __INT_MAX__ >= 2147483647
+#if __INT_MAX__ >= 2147483647
typedef unsigned int uint32;
typedef signed int sint32;
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr20621-1.c b/gcc/testsuite/gcc.c-torture/execute/pr20621-1.c
index 9d0119b..b2a9785 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr20621-1.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr20621-1.c
@@ -1,12 +1,9 @@
-/* { dg-add-options stack_size } */
+/* { dg-require-stack-size "0x10000" } */
/* When generating o32 MIPS PIC, main's $gp save slot was out of range
of a single load instruction. */
struct big { int i[sizeof (int) >= 4 && sizeof (void *) >= 4 ? 0x4000 : 4]; };
struct big gb;
int foo (struct big b, int x) { return b.i[x]; }
-#if defined(STACK_SIZE) && STACK_SIZE <= 0x10000
-int main (void) { return 0; }
-#else
int main (void) { return foo (gb, 0) + foo (gb, 1); }
-#endif
+
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr28982b.c b/gcc/testsuite/gcc.c-torture/execute/pr28982b.c
index f28425e..b68fa9a 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr28982b.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr28982b.c
@@ -1,11 +1,8 @@
-/* { dg-add-options stack_size } */
+/* { dg-require-stack-size "0x80100" } */
/* Like pr28982a.c, but with the spill slots outside the range of
a single sp-based load on ARM. This test tests for cases where
the addresses in the base and index reloads require further reloads. */
-#if defined(STACK_SIZE) && STACK_SIZE <= 0x80100
-int main (void) { return 0; }
-#else
#define NITER 4
#define NVARS 20
#define MULTI(X) \
@@ -57,4 +54,3 @@ main (void)
return 1;
return 0;
}
-#endif
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr80421.c b/gcc/testsuite/gcc.c-torture/execute/pr80421.c
new file mode 100644
index 0000000..b13ab5f
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr80421.c
@@ -0,0 +1,121 @@
+/* PR middle-end/80421 */
+
+__attribute__ ((noinline, noclone)) void
+baz (const char *t, ...)
+{
+ asm volatile (""::"r" (t):"memory");
+ if (*t == 'T')
+ __builtin_abort ();
+}
+
+unsigned int
+foo (char x)
+{
+ baz ("x %c\n", x);
+ switch (x)
+ {
+ default:
+ baz ("case default\n");
+ if (x == 'D' || x == 'I')
+ baz ("This should never be reached.\n");
+ return 0;
+ case 'D':
+ baz ("case 'D'\n");
+ return 0;
+ case 'I':
+ baz ("case 'I'\n");
+ return 0;
+ }
+}
+
+void
+bar (void)
+{
+ int a = 2;
+ int b = 5;
+ char c[] = {
+ 2, 4, 1, 2, 5, 5, 2, 4, 4, 0, 0, 0, 0, 0, 0, 3, 4, 4, 2, 4,
+ 1, 2, 5, 5, 2, 4, 1, 0, 0, 0, 2, 4, 4, 3, 4, 3, 3, 5, 1, 3,
+ 5, 5, 2, 4, 4, 2, 4, 1, 3, 5, 3, 3, 5, 1, 3, 5, 1, 2, 4, 4,
+ 2, 4, 2, 3, 5, 1, 3, 5, 1, 3, 5, 5, 2, 4, 1, 2, 4, 2, 3, 5,
+ 3, 3, 5, 1, 3, 5, 5, 2, 4, 1, 2, 4, 1, 3, 5, 3, 3, 5, 1, 3,
+ 5, 5, 2, 4, 4, 2, 4, 1, 3, 5, 3, 3, 5, 1, 3, 5, 1, 2, 4, 1,
+ 2, 4, 2, 3, 5, 1, 3, 5, 1, 3, 5, 1, 2, 4, 1, 2, 4, 1, 3, 5,
+ 1, 3, 5, 1, 3, 5, 1, 2, 4, 4, 2, 4, 1, 3, 5, 1, 3, 5, 1, 3,
+ 5, 5, 2, 4, 4, 2, 4, 2, 3, 5, 3, 3, 5, 1, 3, 5, 5, 2, 4, 4,
+ 2, 4, 1, 3, 5, 3, 3, 5, 1, 3, 5, 1, 2, 5, 5, 2, 4, 2, 3, 5,
+ 1, 3, 4, 1, 3, 5, 1, 2, 5, 5, 2, 4, 1, 2, 5, 1, 3, 5, 3, 3,
+ 5, 1, 2, 5, 5, 2, 4, 2, 2, 5, 1, 3, 5, 3, 3, 5, 1, 2, 5, 1,
+ 2, 4, 1, 2, 5, 2, 3, 5, 1, 3, 5, 1, 2, 5, 1, 2, 4, 2, 2, 5,
+ 1, 3, 5, 1, 3, 5, 1, 2, 5, 5, 2, 4, 2, 2, 5, 2, 3, 5, 3, 3,
+ 5, 1, 2, 5, 5, 2, 4, 2, 2, 5, 2, 3, 5, 3, 3, 5, 1, 2, 5, 5,
+ 2, 4, 2, 2, 5, 1, 3, 5, 3, 3, 5, 1, 2, 5, 5, 2, 4, 2, 2, 5,
+ 1, 3, 5, 3, 3, 5, 1, 2, 5, 1, 2, 4, 1, 2, 5, 2, 3, 5, 1, 3,
+ 5, 1, 2, 5, 5, 2, 4, 2, 2, 5, 2, 3, 5, 3, 3, 5, 1, 2, 5, 5,
+ 2, 4, 1, 2, 5, 1, 3, 5, 3, 3, 5, 1, 2, 5, 5, 2, 4, 2, 2, 5,
+ 1, 3, 5, 3, 3, 5, 1, 2, 5, 5, 2, 4, 2, 2, 5, 1, 3, 5, 3, 3,
+ 5, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ char *f = c + 390;
+ int i, j, e, g, h;
+ char k, l;
+ i = 26;
+ j = 25;
+ k = l = 'M';
+ h = 2;
+ while (i > 0)
+ {
+ int x = i - a;
+ x = x > 0 ? x : 0;
+ x = j - x;
+ g = x * 3 + h;
+ switch (f[g])
+ {
+ case 1:
+ --i;
+ --j;
+ h = 2;
+ f -= b * 3;
+ k = 'M';
+ break;
+ case 2:
+ --i;
+ h = 0;
+ f -= b * 3;
+ k = 'I';
+ break;
+ case 3:
+ --i;
+ h = 2;
+ f -= b * 3;
+ k = 'I';
+ break;
+ case 4:
+ --j;
+ h = 1;
+ k = 'D';
+ break;
+ case 5:
+ --j;
+ h = 2;
+ k = 'D';
+ break;
+ }
+ if (k == l)
+ ++e;
+ else
+ {
+ foo (l);
+ l = k;
+ }
+ }
+}
+
+int
+main ()
+{
+ char l = 'D';
+ foo (l);
+ bar ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr81423.c b/gcc/testsuite/gcc.c-torture/execute/pr81423.c
index 731aa8f..be7413b 100644
--- a/gcc/testsuite/gcc.c-torture/execute/pr81423.c
+++ b/gcc/testsuite/gcc.c-torture/execute/pr81423.c
@@ -1,3 +1,5 @@
+/* PR rtl-optimization/81423 */
+
extern void abort (void);
unsigned long long int ll = 0;
@@ -10,11 +12,11 @@ foo (void)
{
ll = -5597998501375493990LL;
- ll = (5677365550390624949L - ll) - (ull1 > 0);
+ ll = (unsigned int) (5677365550390624949LL - ll) - (ull1 > 0);
unsigned long long int ull3;
ull3 = (unsigned int)
- (2067854353L <<
- (((ll + -2129105131L) ^ 10280750144413668236ULL) -
+ (2067854353LL <<
+ (((ll + -2129105131LL) ^ 10280750144413668236ULL) -
10280750143997242009ULL)) >> ((2873442921854271231ULL | ull2)
- 12098357307243495419ULL);
@@ -24,9 +26,10 @@ foo (void)
int
main (void)
{
- /* We need a long long of exactly 64 bits for this test. */
- ll--;
- if (ll != 0xffffffffffffffffULL)
+ /* We need a long long of exactly 64 bits and int of exactly 32 bits
+ for this test. */
+ if (__SIZEOF_LONG_LONG__ * __CHAR_BIT__ != 64
+ || __SIZEOF_INT__ * __CHAR_BIT__ != 32)
return 0;
ull3 = foo ();
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr82387.c b/gcc/testsuite/gcc.c-torture/execute/pr82387.c
new file mode 100644
index 0000000..ead1a2a
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr82387.c
@@ -0,0 +1,27 @@
+/* PR tree-optimization/82387 */
+
+struct A { int b; };
+int f = 1;
+
+struct A
+foo (void)
+{
+ struct A h[] = {
+ {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1},
+ {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1},
+ {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1},
+ {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1},
+ {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1},
+ {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1},
+ {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1}, {1},
+ };
+ return h[24];
+}
+
+int
+main ()
+{
+ struct A i = foo (), j = i;
+ j.b && (f = 0);
+ return f;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr82388.c b/gcc/testsuite/gcc.c-torture/execute/pr82388.c
new file mode 100644
index 0000000..51e30f8
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr82388.c
@@ -0,0 +1,17 @@
+/* PR tree-optimization/82388 */
+
+struct A { int b; int c; int d; } e;
+
+struct A
+foo (void)
+{
+ struct A h[30] = {{0,0,0}};
+ return h[29];
+}
+
+int
+main ()
+{
+ e = foo ();
+ return e.b;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr82524.c b/gcc/testsuite/gcc.c-torture/execute/pr82524.c
new file mode 100644
index 0000000..07ac4b6
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr82524.c
@@ -0,0 +1,37 @@
+/* PR target/82524 */
+
+struct S { unsigned char b, g, r, a; };
+union U { struct S c; unsigned v; };
+
+static inline unsigned char
+foo (unsigned char a, unsigned char b)
+{
+ return ((a + 1) * b) >> 8;
+}
+
+__attribute__((noinline, noclone)) unsigned
+bar (union U *x, union U *y)
+{
+ union U z;
+ unsigned char v = x->c.a;
+ unsigned char w = foo (y->c.a, 255 - v);
+ z.c.r = foo (x->c.r, v) + foo (y->c.r, w);
+ z.c.g = foo (x->c.g, v) + foo (y->c.g, w);
+ z.c.b = foo (x->c.b, v) + foo (y->c.b, w);
+ z.c.a = 0;
+ return z.v;
+}
+
+int
+main ()
+{
+ union U a, b, c;
+ if ((unsigned char) ~0 != 255 || sizeof (unsigned) != 4)
+ return 0;
+ a.c = (struct S) { 255, 255, 255, 0 };
+ b.c = (struct S) { 255, 255, 255, 255 };
+ c.v = bar (&a, &b);
+ if (c.c.b != 255 || c.c.g != 255 || c.c.r != 255 || c.c.a != 0)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/Walloca-15.c b/gcc/testsuite/gcc.dg/Walloca-15.c
new file mode 100644
index 0000000..f34ffd9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloca-15.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target alloca } */
+/* { dg-options "-Walloca-larger-than=128 -O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+void bar (void*);
+
+void foo1 (size_t len)
+{
+ bar (__builtin_alloca_with_align_and_max (len, 8, 128));
+}
+
+void foo2 (size_t len)
+{
+ bar (__builtin_alloca_with_align_and_max (len, 8, 256)); /* { dg-warning "may be too large" } */
+}
diff --git a/gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c b/gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c
new file mode 100644
index 0000000..9ffdc2e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wincompatible-pointer-types-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-pedantic-errors" } */
+
+void f (int, ...);
+
+int
+f1 (void)
+{
+ int (*x) ();
+ x = f; /* { dg-error "assignment to 'int \\(\\*\\)\\(\\)' from incompatible pointer type 'void \\(\\*\\)\\(int, \.\.\.\\)'" } */
+ return x (1);
+}
diff --git a/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c b/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c
index 5bf7b60..401cbc3 100644
--- a/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c
+++ b/gcc/testsuite/gcc.dg/Wstrict-overflow-7.c
@@ -6,5 +6,5 @@
int
foo (int i)
{
- return i + 10 > i; /* { dg-warning "assuming signed overflow does not occur" "correct warning" } */
+ return i + 10 > i; /* { dg-warning "assuming signed overflow does not occur" "correct warning" { xfail *-*-* } } */
}
diff --git a/gcc/testsuite/gcc.dg/asan/pr82517.c b/gcc/testsuite/gcc.dg/asan/pr82517.c
new file mode 100644
index 0000000..c7743ec
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/pr82517.c
@@ -0,0 +1,43 @@
+/* PR sanitizer/82517. */
+
+static int *pp;
+
+void
+baz ()
+{
+ return;
+}
+
+void
+bar (int *p)
+{
+ *p = 1;
+}
+
+void
+foo (int a)
+{
+ if (a == 2)
+ {
+ lab:
+ baz ();
+ return;
+ }
+ if (a > 1)
+ {
+ int x __attribute__ ((aligned (256)));
+ pp = &x;
+ bar (&x);
+ if (!x)
+ goto lab;
+ }
+}
+
+int
+main (int argc, char **argv)
+{
+ foo (4);
+ foo (3);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/asan/pr82545.c b/gcc/testsuite/gcc.dg/asan/pr82545.c
new file mode 100644
index 0000000..8870db3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/asan/pr82545.c
@@ -0,0 +1,17 @@
+/* PR sanitizer/82545. */
+/* { dg-do compile } */
+
+extern void c(int);
+extern void d(void);
+
+void *buf[5];
+
+void a(void) {
+ {
+ int b;
+ &b;
+ __builtin_setjmp(buf);
+ c(b);
+ }
+ d();
+}
diff --git a/gcc/testsuite/gcc.dg/attr-alloc_size-11.c b/gcc/testsuite/gcc.dg/attr-alloc_size-11.c
index fe6154a..6e10995 100644
--- a/gcc/testsuite/gcc.dg/attr-alloc_size-11.c
+++ b/gcc/testsuite/gcc.dg/attr-alloc_size-11.c
@@ -47,8 +47,8 @@ typedef __SIZE_TYPE__ size_t;
/* The following tests fail because of missing range information. The xfail
exclusions are PR79356. */
-TEST (signed char, SCHAR_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" "missing range info for signed char" { xfail { ! { aarch64*-*-* arm*-*-* alpha*-*-* ia64-*-* mips*-*-* powerpc*-*-* sparc*-*-* s390*-*-* } } } } */
-TEST (short, SHRT_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" "missing range info for short" { xfail { ! { aarch64*-*-* arm*-*-* alpha*-*-* ia64-*-* mips*-*-* powerpc*-*-* sparc*-*-* s390x-*-* } } } } */
+TEST (signed char, SCHAR_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" "missing range info for signed char" { xfail { ! { aarch64*-*-* arm*-*-* alpha*-*-* ia64-*-* mips*-*-* powerpc*-*-* sparc*-*-* s390*-*-* visium-*-* } } } } */
+TEST (short, SHRT_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" "missing range info for short" { xfail { ! { aarch64*-*-* arm*-*-* alpha*-*-* ia64-*-* mips*-*-* powerpc*-*-* sparc*-*-* s390x-*-* visium-*-* } } } } */
TEST (int, INT_MIN + 2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (int, -3, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
TEST (int, -2, ALLOC_MAX); /* { dg-warning "argument 1 range \\\[13, \[0-9\]+\\\] exceeds maximum object size 12" } */
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-1.c b/gcc/testsuite/gcc.dg/attr-ifunc-1.c
index 3f7450e..f1a1986 100644
--- a/gcc/testsuite/gcc.dg/attr-ifunc-1.c
+++ b/gcc/testsuite/gcc.dg/attr-ifunc-1.c
@@ -2,15 +2,13 @@
/* { dg-require-ifunc "" } */
/* { dg-options "" } */
-typedef int F (void);
-
static int implementation (void)
{
__builtin_printf ("'ere I am JH\n");
return 0;
}
-static F* resolver (void)
+static __typeof__ (implementation)* resolver (void)
{
return implementation;
}
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-2.c b/gcc/testsuite/gcc.dg/attr-ifunc-2.c
index 8375af9..8221cd4 100644
--- a/gcc/testsuite/gcc.dg/attr-ifunc-2.c
+++ b/gcc/testsuite/gcc.dg/attr-ifunc-2.c
@@ -1,6 +1,8 @@
/* { dg-require-ifunc "" } */
-static void *resolver ()
+typedef int F (void);
+
+static F *resolver ()
{
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-3.c b/gcc/testsuite/gcc.dg/attr-ifunc-3.c
index fbd972d..653af85 100644
--- a/gcc/testsuite/gcc.dg/attr-ifunc-3.c
+++ b/gcc/testsuite/gcc.dg/attr-ifunc-3.c
@@ -14,7 +14,7 @@ static int __attribute__((noinline))
return 0;
}
-static void *resolver (void)
+static __typeof__ (implementation) *resolver (void)
{
return (void *)implementation;
}
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-4.c b/gcc/testsuite/gcc.dg/attr-ifunc-4.c
index 698c06b..5c87445 100644
--- a/gcc/testsuite/gcc.dg/attr-ifunc-4.c
+++ b/gcc/testsuite/gcc.dg/attr-ifunc-4.c
@@ -4,15 +4,15 @@
#include <stdio.h>
-static void *implementation (void)
+static int implementation (void)
{
printf ("'ere I am JH\n");
return 0;
}
-static void *resolver (void)
+static __typeof__ (implementation)* resolver (void)
{
- return (void *)implementation;
+ return implementation;
}
static int magic (void) __attribute__ ((ifunc ("resolver")));
diff --git a/gcc/testsuite/gcc.dg/attr-ifunc-5.c b/gcc/testsuite/gcc.dg/attr-ifunc-5.c
index 4dddec4..1ecc391 100644
--- a/gcc/testsuite/gcc.dg/attr-ifunc-5.c
+++ b/gcc/testsuite/gcc.dg/attr-ifunc-5.c
@@ -4,13 +4,13 @@
#include <stdio.h>
-static void *implementation (void)
+static int implementation (void)
{
printf ("'ere I am JH\n");
return 0;
}
-static void *resolver (void)
+static __typeof__ (implementation)* resolver (void)
{
return (void *)implementation;
}
diff --git a/gcc/testsuite/gcc.dg/c90-const-expr-11.c b/gcc/testsuite/gcc.dg/c90-const-expr-11.c
index e4f2aff..a2720c4 100644
--- a/gcc/testsuite/gcc.dg/c90-const-expr-11.c
+++ b/gcc/testsuite/gcc.dg/c90-const-expr-11.c
@@ -20,7 +20,7 @@ f (void)
/* Overflow. */
struct t b = { INT_MAX + 1 }; /* { dg-warning "integer overflow in expression" } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } .-1 } */
- struct t c = { DBL_MAX }; /* { dg-warning "overflow in conversion from .double. to .int. chages value " } */
+ struct t c = { DBL_MAX }; /* { dg-warning "overflow in conversion from .double. to .int. changes value " } */
/* { dg-error "overflow in constant expression" "constant" { target *-*-* } .-1 } */
/* Bad operator outside sizeof. */
struct s d = { 1 ? 1.0 : atan (a.d) }; /* { dg-error "is not a constant expression|near initialization" } */
diff --git a/gcc/testsuite/gcc.dg/cold-1.c b/gcc/testsuite/gcc.dg/cold-1.c
new file mode 100644
index 0000000..ba1cd3a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/cold-1.c
@@ -0,0 +1,22 @@
+/* { dg-do compile { target nonpic } } */
+/* { dg-options "-O2 -Wsuggest-attribute=cold" } */
+
+extern void abort (void);
+extern void do_something_interesting_and_never_return ();
+
+int
+foo1(int a)
+{ /* { dg-warning "cold" "detect cold candidate" { target *-*-* } ".-1" } */
+ if (a)
+ abort ();
+ else
+ abort ();
+}
+
+int
+foo2(int a)
+{
+ if (a)
+ do_something_interesting_and_never_return ();
+ abort ();
+}
diff --git a/gcc/testsuite/gcc.dg/compat/struct-layout-1_generate.c b/gcc/testsuite/gcc.dg/compat/struct-layout-1_generate.c
index 80c7355..75e902c 100644
--- a/gcc/testsuite/gcc.dg/compat/struct-layout-1_generate.c
+++ b/gcc/testsuite/gcc.dg/compat/struct-layout-1_generate.c
@@ -1893,7 +1893,7 @@ generate_fields (enum FEATURE features, struct entry *e, struct entry *parent,
|| (e[n].type >= &attrib_array_types[0]
&& e[n].type < &attrib_array_types[NAATYPES2])
|| (e[n].type >= &complex_attrib_array_types[0]
- && e[n].type < &complex_attrib_array_types[NAATYPES2])
+ && e[n].type < &complex_attrib_array_types[NCAATYPES2])
|| (e[n].type >= &aligned_bitfld_types[0]
&& e[n].type < &aligned_bitfld_types[n_aligned_bitfld_types])))
e[n].attrib = NULL;
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/asm-line1.c b/gcc/testsuite/gcc.dg/debug/dwarf2/asm-line1.c
index 3773e1c..aebfcad 100644
--- a/gcc/testsuite/gcc.dg/debug/dwarf2/asm-line1.c
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/asm-line1.c
@@ -1,6 +1,6 @@
/* PR debug/50983 */
/* { dg-do compile { target *-*-gnu* } } */
-/* { dg-options "-O0 -gdwarf" } */
+/* { dg-options "-O0 -gdwarf -gno-column-info" } */
/* { dg-final { scan-assembler "is_stmt 1" } } */
int i;
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/discriminator.c b/gcc/testsuite/gcc.dg/debug/dwarf2/discriminator.c
index b77f7b1..fa24de8 100644
--- a/gcc/testsuite/gcc.dg/debug/dwarf2/discriminator.c
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/discriminator.c
@@ -1,7 +1,7 @@
/* HAVE_AS_DWARF2_DEBUG_LINE macro needs to be defined to pass the unittest.
However, dg cannot access it, so we restrict to GNU targets. */
/* { dg-do compile { target *-*-gnu* } } */
-/* { dg-options "-O0 -gdwarf" } */
+/* { dg-options "-O0 -gdwarf -gno-column-info" } */
/* { dg-final { scan-assembler "loc \[0-9] 11 \[0-9]( is_stmt \[0-9])?\n" } } */
/* { dg-final { scan-assembler "loc \[0-9] 11 \[0-9]( is_stmt \[0-9])? discriminator 2\n" } } */
/* { dg-final { scan-assembler "loc \[0-9] 11 \[0-9]( is_stmt \[0-9])? discriminator 1\n" } } */
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/pr53948.c b/gcc/testsuite/gcc.dg/debug/dwarf2/pr53948.c
index 0ec3e84..4485e19 100644
--- a/gcc/testsuite/gcc.dg/debug/dwarf2/pr53948.c
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/pr53948.c
@@ -1,7 +1,7 @@
/* Test that we have line information for the line
with local variable initializations. */
/* { dg-options "-O0 -gdwarf -dA" } */
-/* { dg-final { scan-assembler ".loc 1 8 0|\[#/!\]\[ \t\]+line 8" } } */
+/* { dg-final { scan-assembler ".loc 1 8 \[0-9\]|\[#/!\]\[ \t\]+line 8" } } */
int f (register int a, register int b) {
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/sso.c b/gcc/testsuite/gcc.dg/debug/dwarf2/sso-1.c
index 698c636..698c636 100644
--- a/gcc/testsuite/gcc.dg/debug/dwarf2/sso.c
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/sso-1.c
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/sso-2.c b/gcc/testsuite/gcc.dg/debug/dwarf2/sso-2.c
new file mode 100644
index 0000000..0965084
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/sso-2.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-gdwarf-3 -dA" } */
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define REVERSE_SSO __attribute__((scalar_storage_order("big-endian")));
+#else
+#define REVERSE_SSO __attribute__((scalar_storage_order("little-endian")));
+#endif
+
+struct reverse
+{
+ int i;
+ short a[4];
+} REVERSE_SSO;
+
+struct native
+{
+ int i;
+ short a[4];
+};
+
+struct reverse R;
+struct native N;
+
+/* Verify that we have endianity on the common base type of 'i' and the
+ * element of 'a' in the first 2 structures. */
+/* { dg-final { scan-assembler-times " DW_AT_endianity" 2 } } */
+/* { dg-final { scan-assembler-times "DIE \\(\[0-9a-z\]*\\) DW_TAG_base_type" 5 } } */
diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/sso-3.c b/gcc/testsuite/gcc.dg/debug/dwarf2/sso-3.c
new file mode 100644
index 0000000..004327c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/debug/dwarf2/sso-3.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-gdwarf-3 -dA" } */
+
+typedef int int_t;
+typedef short short_t;
+
+#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#define REVERSE_SSO __attribute__((scalar_storage_order("big-endian")));
+#else
+#define REVERSE_SSO __attribute__((scalar_storage_order("little-endian")));
+#endif
+
+struct reverse
+{
+ int_t i;
+ short_t a[4];
+} REVERSE_SSO;
+
+struct native
+{
+ int_t i;
+ short_t a[4];
+};
+
+struct reverse R;
+struct native N;
+
+/* Verify that we have endianity on the common base type of 'i' and the
+ * element of 'a' in the first 2 structures. */
+/* { dg-final { scan-assembler-times " DW_AT_endianity" 2 } } */
+/* { dg-final { scan-assembler-times "DIE \\(\[0-9a-z\]*\\) DW_TAG_base_type" 5 } } */
diff --git a/gcc/testsuite/gcc.dg/diagnostic-range-bad-called-object.c b/gcc/testsuite/gcc.dg/diagnostic-range-bad-called-object.c
index 95fb3e9..0f7fd2a 100644
--- a/gcc/testsuite/gcc.dg/diagnostic-range-bad-called-object.c
+++ b/gcc/testsuite/gcc.dg/diagnostic-range-bad-called-object.c
@@ -19,6 +19,6 @@ void call_of_non_function_ptr (char **argP, char **argQ)
{ dg-end-multiline-output "" }
{ dg-begin-multiline-output "" }
void call_of_non_function_ptr (char **argP, char **argQ)
- ^~~~
+ ~~~~~~~^~~~
{ dg-end-multiline-output "" } */
}
diff --git a/gcc/testsuite/gcc.dg/gomp/pr82374.c b/gcc/testsuite/gcc.dg/gomp/pr82374.c
new file mode 100644
index 0000000..453266e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gomp/pr82374.c
@@ -0,0 +1,31 @@
+/* PR tree-optimization/82374 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-tree-vectorize -fdump-tree-vect-details" } */
+/* { dg-additional-options "-mavx -mno-avx2" { target i?86-*-* x86_64-*-* } } */
+/* { dg-additional-options "-mvsx" { target powerpc_vsx_ok } } */
+
+#define SIZE (1024 * 1024)
+
+float a[SIZE];
+float b[SIZE];
+float c[SIZE];
+float d[SIZE];
+
+__attribute__((optimize ("O2", "tree-vectorize"))) void
+foo (void)
+{
+ int i;
+#pragma omp parallel for
+ for (i = 0; i < SIZE; i++)
+ c[i] = a[i] + b[i];
+}
+
+__attribute__((optimize ("O2", "tree-vectorize"))) void
+bar (void)
+{
+ int i;
+ for (i = 0; i < SIZE; i++)
+ d[i] = a[i] + b[i];
+}
+
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" { target { { i?86-*-* x86_64-*-* } || { powerpc_vsx_ok } } } } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/graphite.exp b/gcc/testsuite/gcc.dg/graphite/graphite.exp
index 50aae30..646d192 100644
--- a/gcc/testsuite/gcc.dg/graphite/graphite.exp
+++ b/gcc/testsuite/gcc.dg/graphite/graphite.exp
@@ -57,11 +57,11 @@ set vect_files [lsort [glob -nocomplain $srcdir/$subdir/vect-*.c ] ]
# Tests to be compiled.
set dg-do-what-default compile
dg-runtest $scop_files "" "-O2 -fgraphite -fdump-tree-graphite-all"
-dg-runtest $id_files "" "-O2 -fgraphite-identity -ffast-math"
+dg-runtest $id_files "" "-O2 -fgraphite-identity -ffast-math -fdump-tree-graphite-details"
# Tests to be run.
set dg-do-what-default run
-dg-runtest $run_id_files "" "-O2 -fgraphite-identity"
+dg-runtest $run_id_files "" "-O2 -fgraphite-identity -fdump-tree-graphite-details"
dg-runtest $opt_files "" "-O2 -ffast-math -floop-nest-optimize -fdump-tree-graphite-all"
# Vectorizer tests, to be run or compiled, depending on target capabilities.
diff --git a/gcc/testsuite/gcc.dg/graphite/id-15.c b/gcc/testsuite/gcc.dg/graphite/id-15.c
index b57c209..d1cb2a2 100644
--- a/gcc/testsuite/gcc.dg/graphite/id-15.c
+++ b/gcc/testsuite/gcc.dg/graphite/id-15.c
@@ -117,4 +117,3 @@ mul_double (l1, h1, l2, h2, lv, hv)
}
return (*hv < 0 ? ~(toplow & tophigh) : toplow | tophigh) != 0;
}
-
diff --git a/gcc/testsuite/gcc.dg/graphite/id-30.c b/gcc/testsuite/gcc.dg/graphite/id-30.c
new file mode 100644
index 0000000..f8144ce
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/id-30.c
@@ -0,0 +1,16 @@
+/* The modulo constraints we generate for the niter expression
+ (unsinged long)ubound - (unsigned long)lbound
+ end up with a modulo that we cannot represent in the expression
+ type we are using (int64_t), so we run into the codegen error
+ where ISL generates a modulo/divide by sth that doesn't fit the
+ type we code-generate with. Verify we properly elide those. */
+
+void foo (double *a, long int lbound0, long int ubound0,
+ long int lbound1, long int ubound1, long int stride1)
+{
+ if (lbound0 < ubound0)
+ for (long int i = lbound0; i <= ubound0; ++i)
+ if (lbound1 < ubound1)
+ for (long int j = lbound1; j <= ubound1; ++j)
+ a[i*stride1 + j] = 0.;
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/pr35356-3.c b/gcc/testsuite/gcc.dg/graphite/pr35356-3.c
index f2827a2..8db042f 100644
--- a/gcc/testsuite/gcc.dg/graphite/pr35356-3.c
+++ b/gcc/testsuite/gcc.dg/graphite/pr35356-3.c
@@ -36,4 +36,5 @@ match (void)
"Y[winner].y > 0". This could be fixed when we will use predicates
for such cases. */
-/* { dg-final { scan-tree-dump-times "loop_1" 0 "graphite" } } */
+/* { dg-final { scan-tree-dump-times "loop_1" 0 "graphite" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump "number of SCoPs: 0" "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/pr69728.c b/gcc/testsuite/gcc.dg/graphite/pr69728.c
index 35ea5bd1..e8cd7be 100644
--- a/gcc/testsuite/gcc.dg/graphite/pr69728.c
+++ b/gcc/testsuite/gcc.dg/graphite/pr69728.c
@@ -1,7 +1,7 @@
/* { dg-do compile } */
-/* { dg-options "-O3 -floop-nest-optimize" } */
+/* { dg-options "-O3 -floop-nest-optimize -fdump-tree-graphite-details" } */
-int a[1];
+int a[9];
int b, c, d, e;
void
fn1 ()
@@ -19,3 +19,9 @@ fn1 ()
}
}
}
+
+/* At the moment only ISL figures that if (d) is always true. We've
+ run into scheduling issues before here, not being able to handle
+ empty domains. */
+
+/* { dg-final { scan-tree-dump "loop nest optimized" "graphite" } } */
diff --git a/gcc/testsuite/gcc.dg/graphite/pr77362.c b/gcc/testsuite/gcc.dg/graphite/pr77362.c
new file mode 100644
index 0000000..c6a1e36
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr77362.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -floop-nest-optimize" } */
+
+int mc[2];
+int f2, sk;
+short int hm;
+
+void
+zm (void)
+{
+ int k1;
+
+ for (k1 = 0; k1 < 2; ++k1)
+ {
+ for (sk = 0; sk < 2; ++sk)
+ mc[sk] = hm = ++f2;
+ if (hm >= 0)
+ ++hm;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/pr81373-2.c b/gcc/testsuite/gcc.dg/graphite/pr81373-2.c
new file mode 100644
index 0000000..6a654be
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr81373-2.c
@@ -0,0 +1,40 @@
+/* { dg-options "-fno-tree-scev-cprop -floop-nest-optimize -fgraphite-identity -O -fdump-tree-graphite-all" } */
+
+void bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[101][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ for (k = 1; k < 100; k++)
+ a[j][k] = a[j+1][i-1] + 2;
+
+ b[i] = b[i-1] + 2;
+
+ bar ();
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+
+ b[i] = b[i-1] + 2;
+
+ bar ();
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+
+ b[i] = a[i-1][i] + 2;
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 2" 1 "graphite"} } */
diff --git a/gcc/testsuite/gcc.dg/graphite/pr81373.c b/gcc/testsuite/gcc.dg/graphite/pr81373.c
new file mode 100644
index 0000000..588b9d0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr81373.c
@@ -0,0 +1,40 @@
+/* { dg-options "-fno-tree-scev-cprop -fgraphite-identity -O -fdump-tree-graphite-all" } */
+
+void bar (void);
+
+int toto()
+{
+ int i, j, k;
+ int a[101][100];
+ int b[100];
+
+ for (i = 1; i < 100; i++)
+ {
+ for (j = 1; j < 100; j++)
+ for (k = 1; k < 100; k++)
+ a[j][k] = a[j+1][i-1] + 2;
+
+ b[i] = b[i-1] + 2;
+
+ bar ();
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+
+ b[i] = b[i-1] + 2;
+
+ bar ();
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+
+ b[i] = a[i-1][i] + 2;
+
+ for (j = 1; j < 100; j++)
+ a[j][i] = a[j+1][i-1] + 2;
+ }
+
+ return a[3][5] + b[1];
+}
+
+/* { dg-final { scan-tree-dump-times "number of SCoPs: 2" 1 "graphite"} } */
diff --git a/gcc/testsuite/gcc.dg/graphite/pr82321.c b/gcc/testsuite/gcc.dg/graphite/pr82321.c
new file mode 100644
index 0000000..9232147
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr82321.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -floop-nest-optimize" } */
+
+int y8;
+
+void
+dm (int io)
+{
+ if (y8 != 0)
+ {
+ int pu = 1;
+
+ while (io < 2)
+ {
+ int xo = (pu != 0) ? y8 : 0;
+
+ while (y8 != 0)
+ if (xo != 0)
+ {
+gi:
+ xo = (__INTPTR_TYPE__)&io;
+ pu = 0;
+ }
+ }
+ }
+
+ if (io != 0)
+ {
+ y8 = 1;
+ while (y8 != 0)
+ if (io / !y8 != 0)
+ y8 = 0;
+
+ goto gi;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/pr82355.c b/gcc/testsuite/gcc.dg/graphite/pr82355.c
new file mode 100644
index 0000000..b60772d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr82355.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -floop-nest-optimize" } */
+
+int dc, at;
+
+void
+tv (int *ld, int jl)
+{
+ for (;;)
+ {
+ if (dc != 0)
+ for (;;)
+ {
+ *ld = !!(*ld) + 1;
+ for (dc = 0; dc < 3; ++dc)
+ at = (jl != 0) ? *ld : 0;
+ }
+
+ while (at != 0)
+ {
+ }
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/pr82421.c b/gcc/testsuite/gcc.dg/graphite/pr82421.c
new file mode 100644
index 0000000..5da1636
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr82421.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O -floop-nest-optimize" } */
+
+int pc;
+
+void
+qy (int l9)
+{
+ int tw = 4;
+ int fb[tw];
+
+ while (l9 < 1)
+ {
+ int dr;
+
+ pc = fb[2];
+ for (dr = 0; dr < tw; ++dr)
+ fb[dr] = 0;
+ ++l9;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/pr82422.c b/gcc/testsuite/gcc.dg/graphite/pr82422.c
new file mode 100644
index 0000000..281a749
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr82422.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -floop-nest-optimize -Wno-aggressive-loop-optimizations" } */
+
+int a;
+int b[6];
+int c ()
+{
+ int d;
+ for (; d; d++)
+ b[d] = 0;
+ for (; d < 8; d++)
+ a += b[d];
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/pr82451.c b/gcc/testsuite/gcc.dg/graphite/pr82451.c
new file mode 100644
index 0000000..802b931
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr82451.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O -floop-parallelize-all" } */
+
+static int a[];
+int b[1];
+int c;
+static void
+d (int *f, int *g)
+{
+ int e;
+ for (e = 0; e < 2; e++)
+ g[e] = 1;
+ for (e = 0; e < 2; e++)
+ g[e] = f[e] + f[e + 1];
+}
+void
+h ()
+{
+ for (;; c += 8)
+ d (&a[c], b);
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/pr82563.c b/gcc/testsuite/gcc.dg/graphite/pr82563.c
new file mode 100644
index 0000000..cd492fa
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/pr82563.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -floop-nest-optimize" } */
+
+int tj, cw, xf;
+
+void
+zp (int *ei)
+{
+ for (;;)
+ {
+ int hd = 0;
+
+ if (cw != 0 && xf != 0)
+ {
+ for (hd = 0; hd < 3; ++hd)
+ cw = (tj != 0) ? 0 : *ei;
+ for (;;)
+ ;
+ }
+
+ while (tj != 0)
+ tj = (__UINTPTR_TYPE__)&hd;
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/run-id-pr67700-1.c b/gcc/testsuite/gcc.dg/graphite/run-id-pr67700-1.c
index e0db256..f1fae71 100644
--- a/gcc/testsuite/gcc.dg/graphite/run-id-pr67700-1.c
+++ b/gcc/testsuite/gcc.dg/graphite/run-id-pr67700-1.c
@@ -45,4 +45,3 @@ int main()
assert (obj->elem1[8] == 45);
return 0;
}
-
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-10.c b/gcc/testsuite/gcc.dg/graphite/scop-10.c
index 39ed5d7..20d5351 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-10.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-10.c
@@ -4,7 +4,7 @@ int toto()
{
int i, j, k;
int a[100][100];
- int b[100];
+ int b[200];
for (i = 1; i < 100; i++)
{
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-24.c b/gcc/testsuite/gcc.dg/graphite/scop-24.c
new file mode 100644
index 0000000..a051a11
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/graphite/scop-24.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-Ofast -floop-nest-optimize" } */
+
+typedef struct _IO_FILE FILE;
+extern struct _IO_FILE *stderr;
+typedef float real;
+typedef real rvec[3];
+int rgbset (int);
+void ps_box (int, int);
+void plot_phi(char *fn,rvec box,int natoms,rvec x[],real phi[])
+{
+ real phi_max,rr,gg,bb,fac,dx,x0,y0;
+ int i;
+ for(i=0; (i<natoms); i++)
+ phi_max=((phi_max > __builtin_fabs(phi[i]))
+ ? phi_max : __builtin_fabs(phi[i]));
+ if (__builtin_fabs(phi_max)<1.2e-38)
+ __builtin_fprintf(stderr, "X");
+ ps_box((real)(fac*box[0]-1),(real)(fac*box[1]-1));
+ for(i=0; (i<natoms); i++)
+ {
+ rr=gg=bb=1.0;
+ if (phi[i] < 0)
+ gg=bb=(1.0+(phi[i]/phi_max));
+ else
+ rr=gg=(1.0-(phi[i]/phi_max));
+ rr=rgbset(rr);
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-7.c b/gcc/testsuite/gcc.dg/graphite/scop-7.c
index 3e337d0..2f0a504 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-7.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-7.c
@@ -4,7 +4,7 @@ int toto()
{
int i, j, k;
int a[100][100];
- int b[100];
+ int b[200];
for (i = 1; i < 100; i++)
{
diff --git a/gcc/testsuite/gcc.dg/graphite/scop-8.c b/gcc/testsuite/gcc.dg/graphite/scop-8.c
index 71d5c53..3ceb5d8 100644
--- a/gcc/testsuite/gcc.dg/graphite/scop-8.c
+++ b/gcc/testsuite/gcc.dg/graphite/scop-8.c
@@ -4,7 +4,7 @@ int toto()
{
int i, j, k;
int a[100][100];
- int b[100];
+ int b[200];
for (i = 1; i < 100; i++)
{
diff --git a/gcc/testsuite/gcc.dg/ipa/inlinehint-4.c b/gcc/testsuite/gcc.dg/ipa/inlinehint-4.c
index 441a0c7..71b16f8 100644
--- a/gcc/testsuite/gcc.dg/ipa/inlinehint-4.c
+++ b/gcc/testsuite/gcc.dg/ipa/inlinehint-4.c
@@ -35,5 +35,5 @@ test (int i)
lookup (9 * i);
}
/* { dg-final { scan-ipa-dump "Wrapper penalty" "inline" } } */
-/* { dg-final { scan-ipa-dump-not "Inlining lookup_slow to lookup" "inline" } } */
-/* { dg-final { scan-ipa-dump "Inlining lookup to test" "inline" } } */
+/* { dg-final { scan-ipa-dump-not "Inlined lookup_slow into lookup" "inline" } } */
+/* { dg-final { scan-ipa-dump "Inlined lookup into test" "inline" } } */
diff --git a/gcc/testsuite/gcc.dg/missing-symbol-2.c b/gcc/testsuite/gcc.dg/missing-symbol-2.c
new file mode 100644
index 0000000..7ee795d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/missing-symbol-2.c
@@ -0,0 +1,71 @@
+/* { dg-options "-fdiagnostics-show-caret -Wno-switch-unreachable" } */
+
+extern int foo (void);
+
+void missing_open_paren (void)
+{
+ if foo ()) /* { dg-line missing_open_paren } */
+ {
+ }
+ /* { dg-error "expected '\\(' before 'foo'" "" { target c } missing_open_paren } */
+ /* { dg-begin-multiline-output "" }
+ if foo ())
+ ^~~
+ (
+ { dg-end-multiline-output "" } */
+ /* { dg-error "expected statement before '\\)' token" "" { target c } missing_open_paren } */
+ /* { dg-begin-multiline-output "" }
+ if foo ())
+ ^
+ { dg-end-multiline-output "" } */
+}
+
+void missing_close_square (void)
+{
+ const char test [42; /* { dg-error "22: expected ']' before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ const char test [42;
+ ^
+ ]
+ { dg-end-multiline-output "" } */
+}
+
+int missing_semicolon (void)
+{
+ return 42 /* { dg-error "expected ';'" } */
+}
+/* { dg-begin-multiline-output "" }
+ return 42
+ ^
+ ;
+ }
+ ~
+ { dg-end-multiline-output "" } */
+
+
+/* We don't offer a fix-it hint for this case in C, as it could be
+ colon or ellipsis.
+ TODO: we could be smarter about error-recovery here; given the
+ return perhaps we could assume a missing colon. */
+
+int missing_colon_in_switch (int val)
+{
+ switch (val)
+ {
+ case 42
+ return 42; /* { dg-error "expected ':' or '...' before 'return'" } */
+ /* { dg-begin-multiline-output "" }
+ return 42;
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+
+ default:
+ return val;
+ }
+}
+
+/* { dg-begin-multiline-output "" }
+ int dummy;
+ ^~~
+ { dg-end-multiline-output "" } */
+int dummy;/* { dg-error "expected declaration or statement at end of input" "" { target c } } */
diff --git a/gcc/testsuite/gcc.dg/missing-symbol-3.c b/gcc/testsuite/gcc.dg/missing-symbol-3.c
new file mode 100644
index 0000000..e2d00df
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/missing-symbol-3.c
@@ -0,0 +1,50 @@
+/* { dg-options "-fdiagnostics-show-caret" } */
+
+/* A sequence of bogus _Static_assert.
+ We can offer fix-it hints for some of these, but not all. */
+
+void test_static_assert_1 (void)
+{
+ _Static_assert sizeof(int) >= sizeof(char); /* { dg-error "expected '\\(' before 'sizeof'" } */
+ /* { dg-begin-multiline-output "" }
+ _Static_assert sizeof(int) >= sizeof(char);
+ ^~~~~~
+ (
+ { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_2 (void)
+{
+ _Static_assert(sizeof(int) >= sizeof(char); /* { dg-error "expected ',' before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ _Static_assert(sizeof(int) >= sizeof(char);
+ ^
+ ,
+ { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_3 (void)
+{
+ _Static_assert(sizeof(int) >= sizeof(char),; /* { dg-error "expected string literal before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ _Static_assert(sizeof(int) >= sizeof(char),;
+ ^
+ { dg-end-multiline-output "" } */
+}
+
+void test_static_assert_4 (void)
+{
+ _Static_assert(sizeof(int) >= sizeof(char), "msg"; /* { dg-error "expected '\\)' before ';' token" } */
+ /* { dg-begin-multiline-output "" }
+ _Static_assert(sizeof(int) >= sizeof(char), "msg";
+ ~ ^
+ )
+ { dg-end-multiline-output "" } */
+}
+
+/* The final one is correct. */
+
+void test_static_assert_5 (void)
+{
+ _Static_assert(sizeof(int) >= sizeof(char), "msg");
+}
diff --git a/gcc/testsuite/gcc.dg/noncompile/940112-1.c b/gcc/testsuite/gcc.dg/noncompile/940112-1.c
index bb5e0f6..0a9e07d 100644
--- a/gcc/testsuite/gcc.dg/noncompile/940112-1.c
+++ b/gcc/testsuite/gcc.dg/noncompile/940112-1.c
@@ -3,5 +3,5 @@ f (int x)
{
double e = 1;
e = 1;
- return (e)
-} /* { dg-error "parse error|syntax error|expected" } */
+ return (e) /* { dg-error "parse error|syntax error|expected" } */
+}
diff --git a/gcc/testsuite/gcc.dg/noncompile/971104-1.c b/gcc/testsuite/gcc.dg/noncompile/971104-1.c
index 39e00c6..4a04dad 100644
--- a/gcc/testsuite/gcc.dg/noncompile/971104-1.c
+++ b/gcc/testsuite/gcc.dg/noncompile/971104-1.c
@@ -27,6 +27,6 @@ static void up(int sem){
printf("%s had processes sleeping on it!\n",
({ "MUTEX ", "BARB_SEM 1", "BARB_SEM 2", "CUST_SEM 1",
"CUST_SEM 2", "WAIT_SEM 1", "WAIT_SEM 2", "WAIT_SEM 3",
- "WAIT_SEM 4"} /* { dg-error "parse error|syntax error|expected" } */
- [( sb.sem_num )]) ); /* { dg-error "expected" } */
+ "WAIT_SEM 4"} /* { dg-error "expected" } */
+ [( sb.sem_num )]) );
}
diff --git a/gcc/testsuite/gcc.dg/overflow-warn-5.c b/gcc/testsuite/gcc.dg/overflow-warn-5.c
index b2c8dc3..1a5aa0c 100644
--- a/gcc/testsuite/gcc.dg/overflow-warn-5.c
+++ b/gcc/testsuite/gcc.dg/overflow-warn-5.c
@@ -3,5 +3,5 @@
/* { dg-options "-Woverflow" } */
unsigned char rx_async(unsigned char p) {
- return p & 512; /* { dg-warning "overflow in conversion from .int. to .unsigned char. chages value" } */
+ return p & 512; /* { dg-warning "overflow in conversion from .int. to .unsigned char. changes value" } */
}
diff --git a/gcc/testsuite/gcc.dg/overflow-warn-8.c b/gcc/testsuite/gcc.dg/overflow-warn-8.c
index ace6055..e76bcac 100644
--- a/gcc/testsuite/gcc.dg/overflow-warn-8.c
+++ b/gcc/testsuite/gcc.dg/overflow-warn-8.c
@@ -7,7 +7,7 @@ void foo (int j)
int i3 = 1 + INT_MAX; /* { dg-warning "integer overflow" } */
int i4 = +1 + INT_MAX; /* { dg-warning "integer overflow" } */
int i5 = (int)((double)1.0 + INT_MAX);
- int i6 = (double)1.0 + INT_MAX; /* { dg-warning "overflow in conversion from .double. to .int. chages value" } */
+ int i6 = (double)1.0 + INT_MAX; /* { dg-warning "overflow in conversion from .double. to .int. changes value" } */
int i7 = 0 ? (int)(double)1.0 + INT_MAX : 1;
int i8 = 1 ? 1 : (int)(double)1.0 + INT_MAX;
int i9 = j ? (int)(double)1.0 + INT_MAX : 1; /* { dg-warning "integer overflow" } */
diff --git a/gcc/testsuite/gcc.dg/param-type-mismatch.c b/gcc/testsuite/gcc.dg/param-type-mismatch.c
index 70ea0bc..9498a74 100644
--- a/gcc/testsuite/gcc.dg/param-type-mismatch.c
+++ b/gcc/testsuite/gcc.dg/param-type-mismatch.c
@@ -1,9 +1,6 @@
/* { dg-options "-fdiagnostics-show-caret" } */
-/* A collection of calls where argument 2 is of the wrong type.
-
- TODO: we should highlight the second parameter of the callee, rather
- than its name. */
+/* A collection of calls where argument 2 is of the wrong type. */
/* decl, with argname. */
@@ -19,7 +16,7 @@ int test_1 (int first, int second, float third)
/* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_1 } */
/* { dg-begin-multiline-output "" }
extern int callee_1 (int one, const char *two, float three);
- ^~~~~~~~
+ ~~~~~~~~~~~~^~~
{ dg-end-multiline-output "" } */
}
@@ -37,7 +34,7 @@ int test_2 (int first, int second, float third)
/* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_2 } */
/* { dg-begin-multiline-output "" }
extern int callee_2 (int, const char *, float);
- ^~~~~~~~
+ ^~~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
@@ -58,6 +55,78 @@ int test_3 (int first, int second, float third)
/* { dg-message "expected 'const char \\*' but argument is of type 'int'" "" { target *-*-* } callee_3 } */
/* { dg-begin-multiline-output "" }
static int callee_3 (int one, const char *two, float three)
- ^~~~~~~~
+ ~~~~~~~~~~~~^~~
+ { dg-end-multiline-output "" } */
+}
+
+/* Trivial decl, with argname. */
+
+extern int callee_4 (int one, float two, float three); /* { dg-line callee_4 } */
+
+int test_4 (int first, const char *second, float third)
+{
+ return callee_4 (first, second, third); /* { dg-error "incompatible type for argument 2 of 'callee_4'" } */
+ /* { dg-begin-multiline-output "" }
+ return callee_4 (first, second, third);
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-message "expected 'float' but argument is of type 'const char \\*'" "" { target *-*-* } callee_4 } */
+ /* { dg-begin-multiline-output "" }
+ extern int callee_4 (int one, float two, float three);
+ ~~~~~~^~~
+ { dg-end-multiline-output "" } */
+}
+
+/* Trivial decl, without argname. */
+
+extern int callee_5 (int, float, float); /* { dg-line callee_5 } */
+
+int test_5 (int first, const char *second, float third)
+{
+ return callee_5 (first, second, third); /* { dg-error "incompatible type for argument 2 of 'callee_5'" } */
+ /* { dg-begin-multiline-output "" }
+ return callee_5 (first, second, third);
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-message "expected 'float' but argument is of type 'const char \\*'" "" { target *-*-* } callee_5 } */
+ /* { dg-begin-multiline-output "" }
+ extern int callee_5 (int, float, float);
+ ^~~~~
+ { dg-end-multiline-output "" } */
+}
+
+/* Callback with name. */
+
+extern int callee_6 (int one, int (*two)(int, int), float three); /* { dg-line callee_6 } */
+
+int test_6 (int first, int second, float third)
+{
+ return callee_6 (first, second, third); /* { dg-warning "passing argument 2 of 'callee_6' makes pointer from integer without a cast" } */
+ /* { dg-begin-multiline-output "" }
+ return callee_6 (first, second, third);
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-message " expected 'int \\(\\*\\)\\(int, int\\)' but argument is of type 'int'" "" { target *-*-* } callee_6 } */
+ /* { dg-begin-multiline-output "" }
+ extern int callee_6 (int one, int (*two)(int, int), float three);
+ ~~~~~~^~~~~~~~~~~~~~
+ { dg-end-multiline-output "" } */
+}
+
+/* Callback without name. */
+
+extern int callee_7 (int one, int (*)(int, int), float three); /* { dg-line callee_7 } */
+
+int test_7 (int first, int second, float third)
+{
+ return callee_7 (first, second, third); /* { dg-warning "passing argument 2 of 'callee_7' makes pointer from integer without a cast" } */
+ /* { dg-begin-multiline-output "" }
+ return callee_7 (first, second, third);
+ ^~~~~~
+ { dg-end-multiline-output "" } */
+ /* { dg-message " expected 'int \\(\\*\\)\\(int, int\\)' but argument is of type 'int'" "" { target *-*-* } callee_7 } */
+ /* { dg-begin-multiline-output "" }
+ extern int callee_7 (int one, int (*)(int, int), float three);
+ ^~~~~~~~~~~~~~~~~
{ dg-end-multiline-output "" } */
}
diff --git a/gcc/testsuite/gcc.dg/pr35691-1.c b/gcc/testsuite/gcc.dg/pr35691-1.c
index 125923d..34dc02a 100644
--- a/gcc/testsuite/gcc.dg/pr35691-1.c
+++ b/gcc/testsuite/gcc.dg/pr35691-1.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-forwprop-details" } */
+/* { dg-options "-O2 -fdump-tree-forwprop1-details" } */
int foo(int z0, unsigned z1)
{
diff --git a/gcc/testsuite/gcc.dg/pr35691-2.c b/gcc/testsuite/gcc.dg/pr35691-2.c
index 70f68a6..b89ce48 100644
--- a/gcc/testsuite/gcc.dg/pr35691-2.c
+++ b/gcc/testsuite/gcc.dg/pr35691-2.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O2 -fdump-tree-forwprop-details" } */
+/* { dg-options "-O2 -fdump-tree-forwprop1-details" } */
int foo(int z0, unsigned z1)
{
diff --git a/gcc/testsuite/gcc.dg/pr35691-3.c b/gcc/testsuite/gcc.dg/pr35691-3.c
new file mode 100644
index 0000000..75b49a6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr35691-3.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-forwprop1-details" } */
+
+int foo(int z0, unsigned z1)
+{
+ int t0 = (z0 == -1);
+ int t1 = (z1 == -1U);
+ int t2 = (t0 & t1);
+ return t2;
+}
+
+/* { dg-final { scan-tree-dump "gimple_simplified to _\[0-9\]* = \\(int\\) z1_\[0-9\]*\\(D\\);" "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/pr35691-4.c b/gcc/testsuite/gcc.dg/pr35691-4.c
new file mode 100644
index 0000000..2d9456b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr35691-4.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-forwprop1-details" } */
+
+int foo(int z0, unsigned z1)
+{
+ int t0 = (z0 != -1);
+ int t1 = (z1 != -1U);
+ int t2 = (t0 | t1);
+ return t2;
+}
+
+/* { dg-final { scan-tree-dump "gimple_simplified to _\[0-9\]* = \\(int\\) z1_\[0-9\]*\\(D\\);" "forwprop1" } } */
diff --git a/gcc/testsuite/gcc.dg/pr35691-5.c b/gcc/testsuite/gcc.dg/pr35691-5.c
new file mode 100644
index 0000000..1cde028
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr35691-5.c
@@ -0,0 +1,125 @@
+/* PR middle-end/35691 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-reassoc1-details" } */
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[xyz]1_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[xyz]1_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[xyz]1_\[0-9]*\\(D\\) \\+\\\[0, 0\\\]\[\n\r]" 1 "reassoc1" } } */
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[ghi]1_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[ghi]1_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[ghi]1_\[0-9]*\\(D\\) \\+\\\[0, 0\\\]\[\n\r]" 1 "reassoc1" } } */
+
+int
+f1 (int x1, unsigned int y1, int z1, _Bool d, _Bool e, _Bool f, long long g1, unsigned long long h1, long long i1)
+{
+ int a = x1 == 0;
+ int b = y1 == 0;
+ int c = z1 == 0;
+ int j = g1 == 0;
+ int k = h1 == 0;
+ int l = i1 == 0;
+ return a && d && j && b && e && l && f && c && k;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[xyz]2_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[xyz]2_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[xyz]2_\[0-9]*\\(D\\) \\+\\\[0, 0\\\]\[\n\r]" 1 "reassoc1" } } */
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[ghi]2_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[ghi]2_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[ghi]2_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\]\[\n\r]" 1 "reassoc1" } } */
+
+int
+f2 (int x2, int y2, unsigned int z2, _Bool d, _Bool e, _Bool f, long long g2, unsigned long long h2, long long i2)
+{
+ int a = x2 == 0;
+ int b = y2 == 0;
+ int c = z2 == 0;
+ int j = g2 == -1LL;
+ int k = h2 == -1ULL;
+ int l = i2 == -1LL;
+ return !a || d || !l || !b || !k || e || f || !c || !j;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[xyz]3_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[xyz]3_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[xyz]3_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\]\[\n\r]" 1 "reassoc1" } } */
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[ghi]3_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[ghi]3_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[ghi]3_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\]\[\n\r]" 1 "reassoc1" } } */
+
+int
+f3 (unsigned int x3, int y3, int z3, _Bool d, _Bool e, _Bool f, signed char g3, unsigned char h3, signed char i3)
+{
+ int a = x3 == -1U;
+ int b = y3 == -1;
+ int c = z3 == -1;
+ int j = g3 == -1;
+ int k = h3 == (unsigned char) -1U;
+ int l = i3 == -1;
+ return a && d && j && b && k && e && f && c && l;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[xyz]4_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[xyz]4_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[xyz]4_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\]\[\n\r]" 1 "reassoc1" } } */
+
+int
+f4 (int x4, unsigned int y4, unsigned int z4, _Bool d, _Bool e, _Bool f)
+{
+ int a = x4 == -1U;
+ int b = y4 == -1U;
+ int c = z4 == -1;
+ return !a || d || !b || e || f || !c;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[xyz]5_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[xyz]5_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[xyz]5_\[0-9]*\\(D\\) \\+\\\[0, 0\\\]\[\n\r]" 1 "reassoc1" } } */
+
+int
+f5 (int x5, int y5, int z5, _Bool d, _Bool e, _Bool f)
+{
+ int a = x5 == 0;
+ int b = y5 != 0;
+ int c = z5 != 0;
+ return a && d && !b && e && f && !c;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[xyz]6_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[xyz]6_\[0-9]*\\(D\\) \\+\\\[0, 0\\\] and \[xyz]6_\[0-9]*\\(D\\) \\+\\\[0, 0\\\]\[\n\r]" 1 "reassoc1" } } */
+
+int
+f6 (unsigned int x6, unsigned int y6, unsigned int z6, _Bool d, _Bool e, _Bool f)
+{
+ int a = x6 == 0;
+ int b = y6 != 0;
+ int c = z6 != 0;
+ return !a || d || b || e || f || c;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[xy]7_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[xy]7_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\]\[\n\r]" 1 "reassoc1" } } */
+
+int
+f7 (int x7, int y7, int z7, _Bool d, _Bool e, _Bool f)
+{
+ int a = x7 == -1;
+ int b = y7 != -1;
+ int c = z7 == -1;
+ return a && d && !b && e && f && !c;
+}
+
+/* { dg-final { scan-tree-dump-times "Optimizing range tests \[xy]8_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\] and \[xy]8_\[0-9]*\\(D\\) \\+\\\[\[1-9-]\[0-9]*, \[1-9-]\[0-9]*\\\]\[\n\r]" 1 "reassoc1" } } */
+
+int
+f8 (unsigned int x8, unsigned int y8, unsigned int z8, _Bool d, _Bool e, _Bool f)
+{
+ int a = x8 == -1;
+ int b = y8 != -1;
+ int c = z8 == -1;
+ return !a || d || b || e || f || c;
+}
+
+/* { dg-final { scan-tree-dump-not "Optimizing range tests \[xyz]9_\[0-9]*\\(D\\)" "reassoc1" } } */
+
+int
+f9 (int x9, int y9, int z9, _Bool d, _Bool e, _Bool f)
+{
+ int a = x9 == -1;
+ int b = y9 == -1;
+ int c = z9 == -1;
+ return a || d || b || e || f || c;
+}
+
+/* { dg-final { scan-tree-dump-not "Optimizing range tests \[xyz]0_\[0-9]*\\(D\\)" "reassoc1" } } */
+
+int
+f0 (int x0, int y0, int z0, _Bool d, _Bool e, _Bool f)
+{
+ int a = x0 != 0;
+ int b = y0 != 0;
+ int c = z0 != 0;
+ return a && d && b && e && f && c;
+}
diff --git a/gcc/testsuite/gcc.dg/pr35691-6.c b/gcc/testsuite/gcc.dg/pr35691-6.c
new file mode 100644
index 0000000..b45bbb8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr35691-6.c
@@ -0,0 +1,72 @@
+/* PR middle-end/35691 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+__attribute__((noinline, noclone)) int
+foo (int *p, unsigned long long *q)
+{
+ int p0 = p[0], p10 = p[10], p12 = p[12], p32 = p[32], p77 = p[77], p85 = p[85], p86 = p[86], p97 = p[97], p98 = p[98];
+ unsigned long long q0 = q[0], q10 = q[10], q12 = q[12], q32 = q[32], q77 = q[77], q85 = q[85], q86 = q[86], q97 = q[97], q98 = q[98];
+ return p0 == 0 && q0 == -1 && p10 == 0 && q10 == -1 && p12 == 0 && q12 == -1
+ && p32 == 0 && q32 == -1 && p77 == 0 && q77 == -1 && p85 == 0 && q85 == -1
+ && p86 == 0 && q86 == -1 && p97 == 0 && q97 == -1 && p98 == 0 && q98 == -1;
+}
+
+__attribute__((noinline, noclone)) int
+bar (int *p, unsigned long long *q)
+{
+ int p0 = p[0], p10 = p[10], p12 = p[12], p32 = p[32], p77 = p[77], p85 = p[85], p86 = p[86], p97 = p[97], p98 = p[98];
+ unsigned long long q0 = q[0], q10 = q[10], q12 = q[12], q32 = q[32], q77 = q[77], q85 = q[85], q86 = q[86], q97 = q[97], q98 = q[98];
+ return p0 != 0 | q0 != -1 | p10 != 0 | q10 != -1 | p12 != 0 | q12 != -1
+ | p32 != 0 | q32 != -1 | p77 != 0 | q77 != -1 | p85 != 0 | q85 != -1
+ | p86 != 0 | q86 != -1 | p97 != 0 | q97 != -1 | p98 != 0 | q98 != -1;
+}
+
+int p[100];
+unsigned long long q[100];
+
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 100; i++)
+ {
+ p[i] = 0;
+ q[i] = -1;
+ }
+ asm volatile ("" : : "g" (p), "g" (q) : "memory");
+ if (foo (p, q) != 1 || bar (p, q) != 0)
+ __builtin_abort ();
+ for (i = 0; i < 100; i++)
+ {
+ int f1, b1, f2, b2;
+ p[i] = 1;
+ f1 = foo (p, q);
+ b1 = bar (p, q);
+ p[i] = 0;
+ q[i] = 0;
+ f2 = foo (p, q);
+ b2 = bar (p, q);
+ q[i] = -1;
+ switch (i)
+ {
+ case 0:
+ case 10:
+ case 12:
+ case 32:
+ case 77:
+ case 85:
+ case 86:
+ case 97:
+ case 98:
+ if (f1 != 0 || b1 != 1 || f2 != 0 || b2 != 1)
+ __builtin_abort ();
+ break;
+ default:
+ if (f1 != 1 || b1 != 0 || f2 != 1 || b2 != 0)
+ __builtin_abort ();
+ break;
+ }
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr68533.c b/gcc/testsuite/gcc.dg/pr68533.c
index e1a1f31..49e67a9 100644
--- a/gcc/testsuite/gcc.dg/pr68533.c
+++ b/gcc/testsuite/gcc.dg/pr68533.c
@@ -28,8 +28,8 @@ f2 (
void
f3 (
- const void
- ) /* { dg-error "'void' as only parameter may not be qualified" } */
+ const void /* { dg-error "'void' as only parameter may not be qualified" } */
+ )
{
}
@@ -54,8 +54,8 @@ void
f6 (
int
x,
- void
- ) /* { dg-error "'void' must be the only parameter" } */
+ void /* { dg-error "'void' must be the only parameter" } */
+ )
{
}
diff --git a/gcc/testsuite/gcc.dg/pr81854.c b/gcc/testsuite/gcc.dg/pr81854.c
index 4b0f4da..1021a81 100644
--- a/gcc/testsuite/gcc.dg/pr81854.c
+++ b/gcc/testsuite/gcc.dg/pr81854.c
@@ -1,5 +1,7 @@
/* PR c/81854 - weak alias of an incompatible symbol accepted
- { dg-do compile } */
+ { dg-do compile }
+ { dg-require-ifunc "" }
+ { dg-options "-Wextra" } */
const char* __attribute__ ((weak, alias ("f0_target")))
f0 (void); /* { dg-error "alias between function and variable" } */
@@ -25,39 +27,37 @@ const char* f2_target (int i) /* { dg-message "aliased declaration here" } */
return 0;
}
-
int __attribute__ ((ifunc ("f3_resolver")))
-f3 (void); /* { dg-error ".ifunc. resolver must return a function pointer" } */
+f3 (void); /* { dg-message "resolver indirect function declared here" } */
-int f3_resolver (void) /* { dg-message "resolver declaration here" } */
+void* f3_resolver (void) /* { dg-warning "ifunc. resolver for .f3. should return .int \\(\\*\\)\\(void\\)." } */
{
return 0;
}
int __attribute__ ((ifunc ("f4_resolver")))
-f4 (void); /* { dg-warning ".ifunc. resolver should return a function pointer" } */
+f4 (void); /* { dg-message "resolver indirect function declared here" } */
-void* f4_resolver (void) /* { dg-message "resolver declaration here" } */
+typedef void F4 (void);
+F4* f4_resolver (void) /* { dg-warning ".ifunc. resolver for .f4. should return .int \\(\\*\\)\\(void\\)" } */
{
return 0;
}
+const char* __attribute__ ((ifunc ("f5_resolver")))
+f5 (void);
-int __attribute__ ((ifunc ("f5_resolver")))
-f5 (void); /* { dg-warning "alias between functions of incompatible types" } */
-
-typedef void F5 (void);
-F5* f5_resolver (void) /* { dg-message "aliased declaration here" } */
+typedef const char* F5 (void);
+F5* f5_resolver (void)
{
return 0;
}
-const char* __attribute__ ((ifunc ("f6_resolver")))
-f6 (void);
+int __attribute__ ((ifunc ("f6_resolver")))
+f6 (void); /* { dg-message "resolver indirect function declared here" } */
-typedef const char* F6 (void);
-F6* f6_resolver (void)
+int f6_resolver (void) /* { dg-error ".ifunc. resolver for 'f6' must return .int \\(\\*\\)\\(void\\)." } */
{
return 0;
}
diff --git a/gcc/testsuite/gcc.dg/pr82274-1.c b/gcc/testsuite/gcc.dg/pr82274-1.c
new file mode 100644
index 0000000..f96b733
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr82274-1.c
@@ -0,0 +1,16 @@
+/* PR target/82274 */
+/* { dg-do run } */
+/* { dg-shouldfail "trapv" } */
+/* { dg-options "-ftrapv" } */
+
+int
+main ()
+{
+#ifdef __SIZEOF_INT128__
+ volatile __int128 m = -(((__int128) 1) << (__CHAR_BIT__ * __SIZEOF_INT128__ / 2));
+#else
+ volatile long long m = -(1LL << (__CHAR_BIT__ * __SIZEOF_LONG_LONG__ / 2));
+#endif
+ m = m * m;
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr82274-2.c b/gcc/testsuite/gcc.dg/pr82274-2.c
new file mode 100644
index 0000000..a9643b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr82274-2.c
@@ -0,0 +1,26 @@
+/* PR target/82274 */
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+int
+main ()
+{
+#ifdef __SIZEOF_INT128__
+ __int128 m = -(((__int128) 1) << (__CHAR_BIT__ * __SIZEOF_INT128__ / 2));
+ volatile __int128 mv = m;
+ __int128 r;
+#else
+ long long m = -(1LL << (__CHAR_BIT__ * __SIZEOF_LONG_LONG__ / 2));
+ volatile long long mv = m;
+ long long r;
+#endif
+ if (!__builtin_mul_overflow (mv, mv, &r))
+ __builtin_abort ();
+ if (!__builtin_mul_overflow_p (mv, mv, r))
+ __builtin_abort ();
+ if (!__builtin_mul_overflow (m, m, &r))
+ __builtin_abort ();
+ if (!__builtin_mul_overflow_p (m, m, r))
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/pr82386.c b/gcc/testsuite/gcc.dg/pr82386.c
new file mode 100644
index 0000000..8901f2b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr82386.c
@@ -0,0 +1,38 @@
+/* PR target/82386 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -w" } */
+/* { dg-additional-options "-misel" { target powerpc*-*-* } } */
+
+long long int fs;
+int vm;
+
+void
+sd (void)
+{
+ fs = 1;
+ vm = 2;
+ goto zf;
+
+ if (0)
+ {
+ int y6 = 0;
+ int *uu = &y6;
+ short int he;
+ int of = 0;
+
+ zf:
+ for (;;)
+ {
+ he = of;
+ if (he || (fs |= vm))
+ {
+ *uu = fs;
+ fs += vm;
+ }
+ if (y6 == vm)
+ fs |= he;
+ he = y6 || fs;
+ fs /= 0;
+ }
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/pr82389.c b/gcc/testsuite/gcc.dg/pr82389.c
new file mode 100644
index 0000000..eae5957
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr82389.c
@@ -0,0 +1,13 @@
+/* PR tree-optimization/82389 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-w -O3" } */
+
+struct S { char s[0x40000000]; } s;
+
+void
+foo (struct S *p)
+{
+ char b[0x0ffffffff0000000L];
+ *(struct S *)&b[0x0fffffffef000000L] = s;
+ *p = *(struct S *)&b[0x0fffffffefffffffL];
+}
diff --git a/gcc/testsuite/gcc.dg/pr82596.c b/gcc/testsuite/gcc.dg/pr82596.c
new file mode 100644
index 0000000..5dc67c2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr82596.c
@@ -0,0 +1,27 @@
+/* PR tree-optimization/82596 - missing -Warray-bounds on an out-of-bounds
+ index into string literal
+ { dg-do compile }
+ { dg-options "-O2 -Warray-bounds" } */
+
+#define SIZE_MAX __SIZE_MAX__
+#define SSIZE_MAX __PTRDIFF_MAX__
+#define SSIZE_MIN (-SSIZE_MAX - 1)
+
+void sink (int, ...);
+
+#define T(arg) sink (arg)
+
+void test_cststring (int i)
+{
+ T (""[SSIZE_MIN]); /* { dg-warning "below array bounds" "string" { xfail lp64 } } */
+ T (""[SSIZE_MIN + 1]); /* { dg-warning "below array bounds" "string" } */
+ T (""[-1]); /* { dg-warning "below array bounds" "string" } */
+ T (""[0]);
+ T (""[1]); /* { dg-warning "above array bounds" "string" } */
+ T ("0"[2]); /* { dg-warning "above array bounds" "string" } */
+ T ("012"[2]);
+ T ("012"[3]);
+ T ("012"[4]); /* { dg-warning "above array bounds" "string" } */
+ T ("0123"[SSIZE_MAX]); /* { dg-warning "above array bounds" "string" } */
+ T ("0123"[SIZE_MAX]); /* { dg-warning "above array bounds" "string" } */
+}
diff --git a/gcc/testsuite/gcc.dg/pragma-diag-3.c b/gcc/testsuite/gcc.dg/pragma-diag-3.c
index 2ee439d..b6ee60f 100644
--- a/gcc/testsuite/gcc.dg/pragma-diag-3.c
+++ b/gcc/testsuite/gcc.dg/pragma-diag-3.c
@@ -15,7 +15,7 @@ void testing2() {
void testing3() {
int k = 4;
- k + 4 < k; /* { dg-error "overflow" } */
+ k + 4 < k; /* { dg-error "overflow" "" { xfail *-*-* } } */
}
int bar()
diff --git a/gcc/testsuite/gcc.dg/predict-13.c b/gcc/testsuite/gcc.dg/predict-13.c
index 7fe714a..385be9e 100644
--- a/gcc/testsuite/gcc.dg/predict-13.c
+++ b/gcc/testsuite/gcc.dg/predict-13.c
@@ -21,4 +21,4 @@ int main(int argc, char **argv)
}
/* { dg-final { scan-tree-dump-times "combined heuristics of edge\[^:\]*: 33.3%" 3 "profile_estimate"} } */
-/* { dg-final { scan-tree-dump-times "combined heuristics of edge\[^:\]*: 0.0%" 2 "profile_estimate"} } */
+/* { dg-final { scan-tree-dump-times "combined heuristics of edge\[^:\]*: 0.1%" 2 "profile_estimate"} } */
diff --git a/gcc/testsuite/gcc.dg/predict-8.c b/gcc/testsuite/gcc.dg/predict-8.c
index e13cc00..fa975b3 100644
--- a/gcc/testsuite/gcc.dg/predict-8.c
+++ b/gcc/testsuite/gcc.dg/predict-8.c
@@ -1,5 +1,5 @@
/* { dg-do compile { target { i?86-*-* x86_64-*-* } } } */
-/* { dg-options "-O2 -fdump-rtl-expand" } */
+/* { dg-options "-O2 -fdump-rtl-expand-details-blocks" } */
int foo(float a, float b) {
if (a == b)
@@ -8,4 +8,4 @@ int foo(float a, float b) {
return 2;
}
-/* { dg-final { scan-rtl-dump-times "REG_BR_PROB 400 " 1 "expand"} } */
+/* { dg-final { scan-rtl-dump-times "99.0. .guessed" 2 "expand"} } */
diff --git a/gcc/testsuite/gcc.dg/stack-check-10.c b/gcc/testsuite/gcc.dg/stack-check-10.c
new file mode 100644
index 0000000..a86956a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-10.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-pro_and_epilogue -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=12" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+int f (int *);
+
+int
+g (int a)
+{
+ return f (&a);
+}
+
+int f1 (void);
+int f2 (int);
+
+int
+f3 (void)
+{
+ return f2 (f1 ());
+}
+
+
+/* If we have caller implicit probes, then we should not need probes in either callee.
+ Else callees may need probes, particularly if non-leaf functions require a
+ frame/frame pointer. */
+/* { dg-final { scan-rtl-dump-times "Stack clash no probe" 2 "pro_and_epilogue" { target caller_implicit_probes } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash inline probe" 1 "pro_and_epilogue" { target { ! caller_implicit_probes } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash no probe" 1 "pro_and_epilogue" { target { ! caller_implicit_probes } } } } */
+
+/* Neither of these functions are a nonreturn function. */
+/* { dg-final { scan-rtl-dump-times "Stack clash not noreturn" 2 "pro_and_epilogue" } } */
+
+/* If the callee realigns the stack or has a mandatory frame, then both functions
+ have a residual allocation. Else just g() has a residual allocation. */
+/* { dg-final { scan-rtl-dump-times "Stack clash residual allocation in prologue" 2 "pro_and_epilogue" } } */
+
+
+/* If the target has frame pointers for non-leafs, then both functions will
+ need a frame pointer. Otherwise neither should. */
+/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 2 "pro_and_epilogue" { target { ! frame_pointer_for_non_leaf } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash frame pointer needed" 2 "pro_and_epilogue" { target { frame_pointer_for_non_leaf } } } } */
diff --git a/gcc/testsuite/gcc.dg/stack-check-2.c b/gcc/testsuite/gcc.dg/stack-check-2.c
new file mode 100644
index 0000000..196c4bb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-2.c
@@ -0,0 +1,66 @@
+/* The goal here is to ensure that we never consider a call to a noreturn
+ function as a potential tail call.
+
+ Right now GCC discovers potential tail calls by looking at the
+ predecessors of the exit block. A call to a non-return function
+ has no successors and thus can never match that first filter.
+
+ But that could change one day and we want to catch it. The problem
+ is the compiler could potentially optimize a tail call to a nonreturn
+ function, even if the caller has a frame. That breaks the assumption
+ that calls probe *sp when saving the return address that some targets
+ depend on to elide stack probes. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -fdump-tree-tailc -fdump-tree-optimized" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+extern void foo (void) __attribute__ ((__noreturn__));
+
+
+void
+test_direct_1 (void)
+{
+ foo ();
+}
+
+void
+test_direct_2 (void)
+{
+ return foo ();
+}
+
+void (*indirect)(void)__attribute__ ((noreturn));
+
+
+void
+test_indirect_1 ()
+{
+ (*indirect)();
+}
+
+void
+test_indirect_2 (void)
+{
+ return (*indirect)();;
+}
+
+
+typedef void (*pvfn)() __attribute__ ((noreturn));
+
+void (*indirect_casted)(void);
+
+void
+test_indirect_casted_1 ()
+{
+ (*(pvfn)indirect_casted)();
+}
+
+void
+test_indirect_casted_2 (void)
+{
+ return (*(pvfn)indirect_casted)();
+}
+/* { dg-final { scan-tree-dump-not "tail call" "tailc" } } */
+/* { dg-final { scan-tree-dump-not "tail call" "optimized" } } */
+
diff --git a/gcc/testsuite/gcc.dg/stack-check-3.c b/gcc/testsuite/gcc.dg/stack-check-3.c
new file mode 100644
index 0000000..f0bf7c7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-3.c
@@ -0,0 +1,86 @@
+/* The goal here is to ensure that dynamic allocations via vlas or
+ alloca calls receive probing.
+
+ Scanning the RTL or assembly code seems like insanity here as does
+ checking for particular allocation sizes and probe offsets. For
+ now we just verify that there's an allocation + probe loop and
+ residual allocation + probe for f?. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-expand -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=12" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+__attribute__((noinline, noclone)) void
+foo (char *p)
+{
+ asm volatile ("" : : "r" (p) : "memory");
+}
+
+/* Simple VLA, no other locals. */
+__attribute__((noinline, noclone)) void
+f0 (int x)
+{
+ char vla[x];
+ foo (vla);
+}
+
+/* Simple VLA, small local frame. */
+__attribute__((noinline, noclone)) void
+f1 (int x)
+{
+ char locals[128];
+ char vla[x];
+ foo (vla);
+}
+
+/* Small constant alloca, no other locals. */
+__attribute__((noinline, noclone)) void
+f2 (int x)
+{
+ char *vla = __builtin_alloca (128);
+ foo (vla);
+}
+
+/* Big constant alloca, small local frame. */
+__attribute__((noinline, noclone)) void
+f3 (int x)
+{
+ char locals[128];
+ char *vla = __builtin_alloca (16384);
+ foo (vla);
+}
+
+/* Big constant alloca, small local frame. */
+__attribute__((noinline, noclone)) void
+f3a (int x)
+{
+ char locals[128];
+ char *vla = __builtin_alloca (32768);
+ foo (vla);
+}
+
+/* Nonconstant alloca, no other locals. */
+__attribute__((noinline, noclone)) void
+f4 (int x)
+{
+ char *vla = __builtin_alloca (x);
+ foo (vla);
+}
+
+/* Nonconstant alloca, small local frame. */
+__attribute__((noinline, noclone)) void
+f5 (int x)
+{
+ char locals[128];
+ char *vla = __builtin_alloca (x);
+ foo (vla);
+}
+
+/* { dg-final { scan-rtl-dump-times "allocation and probing residuals" 7 "expand" } } */
+
+
+/* { dg-final { scan-rtl-dump-times "allocation and probing in loop" 7 "expand" { target callee_realigns_stack } } } */
+/* { dg-final { scan-rtl-dump-times "allocation and probing in loop" 4 "expand" { target { ! callee_realigns_stack } } } } */
+/* { dg-final { scan-rtl-dump-times "allocation and probing in rotated loop" 1 "expand" { target { ! callee_realigns_stack } } } } */
+/* { dg-final { scan-rtl-dump-times "allocation and probing inline" 1 "expand" { target { ! callee_realigns_stack } } } } */
+/* { dg-final { scan-rtl-dump-times "skipped dynamic allocation and probing loop" 1 "expand" { target { ! callee_realigns_stack } } } } */
diff --git a/gcc/testsuite/gcc.dg/stack-check-4.c b/gcc/testsuite/gcc.dg/stack-check-4.c
new file mode 100644
index 0000000..b0c5c61
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-4.c
@@ -0,0 +1,42 @@
+/* On targets where the call instruction is an implicit probe of *sp, we
+ elide stack probes as long as the size of the local stack is less than
+ PROBE_INTERVAL.
+
+ But if the caller were to transform a tail call into a direct jump
+ we do not have that implicit probe. This normally isn't a problem as
+ the caller must not have a local frame for that optimization to apply.
+
+ However, a sufficiently smart compiler could realize that the caller's
+ local stack need not be torn down and thus could transform a call into
+ a jump if the target is a noreturn function, even if the caller has
+ a local frame.
+
+ To guard against that, targets that depend on *sp being probed by the
+ call itself must emit a probe if the target function is a noreturn
+ function, even if they just allocate a small amount of stack space.
+
+ Rather than try to parse RTL or assembly code, we instead require the
+ prologue code to emit information into the dump file that we can
+ scan for. We scan for both the positive and negative cases. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-pro_and_epilogue -fno-optimize-sibling-calls" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+extern void arf (char *);
+
+__attribute__ ((noreturn)) void foo1 ()
+{
+ char x[10];
+ while (1)
+ arf (x);
+}
+
+void foo2 ()
+{
+ char x[10];
+ arf (x);
+}
+/* { dg-final { scan-rtl-dump-times "Stack clash noreturn" 1 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash not noreturn" 1 "pro_and_epilogue" } } */
+
diff --git a/gcc/testsuite/gcc.dg/stack-check-5.c b/gcc/testsuite/gcc.dg/stack-check-5.c
new file mode 100644
index 0000000..850e023
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-5.c
@@ -0,0 +1,79 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-pro_and_epilogue -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=12" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-skip-if "" { *-*-* } { "-fstack-protector" } { "" } } */
+
+
+/* Otherwise the S/390 back-end might save the stack pointer in f2 ()
+ into an FPR. */
+/* { dg-additional-options "-msoft-float" { target { s390x-*-* } } } */
+
+extern void foo (char *);
+extern void bar (void);
+
+/* This function allocates no local stack and is a leaf. It should have no
+ probes on any target and should not require a frame pointer. */
+int
+f0 (int x, int y)
+{
+ asm volatile ("" : : : "memory");
+ return x + y;
+}
+
+/* This function allocates no local stack, but is not a leaf. Ideally it
+ should not need probing and no frame pointer. */
+int
+f1 (int x, int y)
+{
+ asm volatile ("" : : : "memory");
+ bar ();
+}
+
+/* This is a leaf with a small frame. On targets with implicit probes in
+ the caller, this should not need probing. On targets with no implicit
+ probes in the caller, it may require probes. Ideally it should need no
+ frame pointer. */
+void
+f2 (void)
+{
+ char buf[512];
+ asm volatile ("" : : "g" (&buf) : "memory");
+}
+
+/* This is a non-leaf with a small frame. On targets with implicit probes in
+ the caller, this should not need probing. On targets with no implicit
+ probes in the caller, it may require probes. It should need no frame
+ pointer. */
+void
+f3 (void)
+{
+ char buf[512];
+ foo (buf);
+}
+
+/* If we have caller implicit probes, then we should not need probes.
+ Else callees may need probes, particularly if non-leaf functions require a
+ frame/frame pointer. */
+/* { dg-final { scan-rtl-dump-times "Stack clash no probe" 4 "pro_and_epilogue" { target caller_implicit_probes } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash no probe" 2 "pro_and_epilogue" { target { ! caller_implicit_probes } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash inline probes " 2 "pro_and_epilogue" { target { ! caller_implicit_probes } } } } */
+
+/* None of these functions are marked with the noreturn attribute. */
+/* { dg-final { scan-rtl-dump-times "Stack clash not noreturn" 4 "pro_and_epilogue" } } */
+
+/* Two functions are leafs, two are not. Verify the target identified them
+ appropriately. */
+/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 4 "pro_and_epilogue" { target { ! frame_pointer_for_non_leaf } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 2 "pro_and_epilogue" { target { frame_pointer_for_non_leaf } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash frame pointer needed" 2 "pro_and_epilogue" { target { frame_pointer_for_non_leaf } } } } */
+
+
+/* We have selected the size of the array in f2/f3 to be large enough
+ to not live in the red zone on targets that support it.
+
+ That allows simplification of this test considerably.
+ f1() should not require any allocations, thus no residuals.
+ All the rest of the functions require some kind of allocation,
+ either for the saved fp/rp or the array. */
+/* { dg-final { scan-rtl-dump-times "Stack clash no residual allocation in prologue" 1 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash residual allocation in prologue" 3 "pro_and_epilogue" } } */
diff --git a/gcc/testsuite/gcc.dg/stack-check-6.c b/gcc/testsuite/gcc.dg/stack-check-6.c
new file mode 100644
index 0000000..ab4b0e8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-6.c
@@ -0,0 +1,56 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-pro_and_epilogue -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=12" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-skip-if "" { *-*-* } { "-fstack-protector" } { "" } } */
+
+
+extern void foo (char *);
+extern void bar (void);
+
+
+/* This is a leaf with a frame that is large enough to require probing with
+ a residual allocation, but small enough to probe inline. */
+void
+f4 (void)
+{
+ char buf[4096 + 512];
+ asm volatile ("" : : "g" (&buf) : "memory");
+}
+
+
+/* This is a non-leaf with a frame large enough to require probing and
+ a residual allocation, but small enough to probe inline. */
+void
+f5 (void)
+{
+ char buf[4096 + 512];
+ foo (buf);
+}
+
+/* This is a leaf with a frame that is large enough to require probing with
+ a loop plus a residual allocation. */
+void
+f6 (void)
+{
+ char buf[4096 * 10 + 512];
+ asm volatile ("" : : "g" (&buf) : "memory");
+}
+
+
+/* This is a non-leaf with a frame large enough to require probing with
+ a loop plus a residual allocation. */
+void
+f7 (void)
+{
+ char buf[4096 * 10 + 512];
+ foo (buf);
+}
+
+/* { dg-final { scan-rtl-dump-times "Stack clash inline probes" 2 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash probe loop" 2 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash residual allocation in prologue" 4 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash not noreturn" 4 "pro_and_epilogue" } } */
+
+/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 4 "pro_and_epilogue" { target { ! frame_pointer_for_non_leaf } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 2 "pro_and_epilogue" { target { frame_pointer_for_non_leaf } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash frame pointer needed" 2 "pro_and_epilogue" { target { frame_pointer_for_non_leaf } } } } */
diff --git a/gcc/testsuite/gcc.dg/stack-check-6a.c b/gcc/testsuite/gcc.dg/stack-check-6a.c
new file mode 100644
index 0000000..468d649
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-6a.c
@@ -0,0 +1,19 @@
+/* The goal here is to verify that increasing the size of the guard allows
+ elimination of all probing on the relevant targets. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-pro_and_epilogue -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=16" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+/* { dg-skip-if "" { *-*-* } { "-fstack-protector" } { "" } } */
+
+
+#include "stack-check-6.c"
+
+/* { dg-final { scan-rtl-dump-times "Stack clash inline probes" 0 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash probe loop" 0 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash residual allocation in prologue" 4 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash not noreturn" 4 "pro_and_epilogue" } } */
+
+/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 4 "pro_and_epilogue" { target { ! frame_pointer_for_non_leaf } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 2 "pro_and_epilogue" { target { frame_pointer_for_non_leaf } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash frame pointer needed" 2 "pro_and_epilogue" { target { frame_pointer_for_non_leaf } } } } */
diff --git a/gcc/testsuite/gcc.dg/stack-check-7.c b/gcc/testsuite/gcc.dg/stack-check-7.c
new file mode 100644
index 0000000..b963a28
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-7.c
@@ -0,0 +1,36 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fstack-clash-protection -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=12" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+/* For further testing, this can be run under valgrind where it's crashed
+ on aarch64 and ppc64le with -fstack-check=specific. */
+
+
+__attribute__((noinline, noclone)) void
+foo (char *p)
+{
+ asm volatile ("" : : "r" (p) : "memory");
+}
+
+__attribute__((noinline, noclone)) void
+bar (void)
+{
+ char buf[131072];
+ foo (buf);
+}
+
+__attribute__((noinline, noclone)) void
+baz (void)
+{
+ char buf[12000];
+ foo (buf);
+}
+
+int
+main ()
+{
+ bar ();
+ baz ();
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/stack-check-8.c b/gcc/testsuite/gcc.dg/stack-check-8.c
new file mode 100644
index 0000000..84d5ade
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-8.c
@@ -0,0 +1,139 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -fstack-clash-protection -Wno-psabi -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=12" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+
+typedef float V __attribute__((vector_size (32)));
+
+__attribute__((noinline, noclone)) void
+foo (char *p)
+{
+ asm volatile ("" : : "r" (p) : "memory");
+}
+
+__attribute__((noinline, noclone)) int
+f0 (int x, int y)
+{
+ asm volatile ("" : : : "memory");
+ return x + y;
+}
+
+__attribute__((noinline, noclone)) void
+f1 (void)
+{
+ char buf[64];
+ foo (buf);
+}
+
+__attribute__((noinline, noclone)) void
+f2 (void)
+{
+ char buf[12000];
+ foo (buf);
+}
+
+__attribute__((noinline, noclone)) void
+f3 (void)
+{
+ char buf[131072];
+ foo (buf);
+}
+
+__attribute__((noinline, noclone)) void
+f4 (int x)
+{
+ char vla[x];
+ foo (vla);
+}
+
+__attribute__((noinline, noclone)) void
+f5 (int x)
+{
+ char buf[12000];
+ foo (buf);
+ {
+ char vla[x];
+ foo (vla);
+ }
+ {
+ char vla[x];
+ foo (vla);
+ }
+}
+
+V v;
+
+__attribute__((noinline, noclone)) int
+f6 (int x, int y, V a, V b, V c)
+{
+ asm volatile ("" : : : "memory");
+ v = a + b + c;
+ return x + y;
+}
+
+__attribute__((noinline, noclone)) void
+f7 (V a, V b, V c)
+{
+ char buf[64];
+ foo (buf);
+ v = a + b + c;
+}
+
+__attribute__((noinline, noclone)) void
+f8 (V a, V b, V c)
+{
+ char buf[12000];
+ foo (buf);
+ v = a + b + c;
+}
+
+__attribute__((noinline, noclone)) void
+f9 (V a, V b, V c)
+{
+ char buf[131072];
+ foo (buf);
+ v = a + b + c;
+}
+
+__attribute__((noinline, noclone)) void
+f10 (int x, V a, V b, V c)
+{
+ char vla[x];
+ foo (vla);
+ v = a + b + c;
+}
+
+__attribute__((noinline, noclone)) void
+f11 (int x, V a, V b, V c)
+{
+ char buf[12000];
+ foo (buf);
+ v = a + b + c;
+ {
+ char vla[x];
+ foo (vla);
+ }
+ {
+ char vla[x];
+ foo (vla);
+ }
+}
+
+int
+main ()
+{
+ f0 (2, 3);
+ f1 ();
+ f2 ();
+ f3 ();
+ f4 (12000);
+ f5 (12000);
+ f6 (2, 3, v, v, v);
+ f7 (v, v, v);
+ f8 (v, v, v);
+ f9 (v, v, v);
+ f10 (12000, v, v, v);
+ f11 (12000, v, v, v);
+ return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/stack-check-9.c b/gcc/testsuite/gcc.dg/stack-check-9.c
new file mode 100644
index 0000000..b84075b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/stack-check-9.c
@@ -0,0 +1,2022 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -fdump-rtl-pro_and_epilogue -fno-optimize-sibling-calls --param stack-clash-protection-probe-interval=12 --param stack-clash-protection-guard-size=12" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+double f1 (void);
+double f2 (double, double);
+
+double
+f3 (void)
+{
+ double d000 = f1 ();
+ double d001 = f1 ();
+ double d002 = f1 ();
+ double d003 = f1 ();
+ double d004 = f1 ();
+ double d005 = f1 ();
+ double d006 = f1 ();
+ double d007 = f1 ();
+ double d008 = f1 ();
+ double d009 = f1 ();
+ double d010 = f1 ();
+ double d011 = f1 ();
+ double d012 = f1 ();
+ double d013 = f1 ();
+ double d014 = f1 ();
+ double d015 = f1 ();
+ double d016 = f1 ();
+ double d017 = f1 ();
+ double d018 = f1 ();
+ double d019 = f1 ();
+ double d020 = f1 ();
+ double d021 = f1 ();
+ double d022 = f1 ();
+ double d023 = f1 ();
+ double d024 = f1 ();
+ double d025 = f1 ();
+ double d026 = f1 ();
+ double d027 = f1 ();
+ double d028 = f1 ();
+ double d029 = f1 ();
+ double d030 = f1 ();
+ double d031 = f1 ();
+ double d032 = f1 ();
+ double d033 = f1 ();
+ double d034 = f1 ();
+ double d035 = f1 ();
+ double d036 = f1 ();
+ double d037 = f1 ();
+ double d038 = f1 ();
+ double d039 = f1 ();
+ double d040 = f1 ();
+ double d041 = f1 ();
+ double d042 = f1 ();
+ double d043 = f1 ();
+ double d044 = f1 ();
+ double d045 = f1 ();
+ double d046 = f1 ();
+ double d047 = f1 ();
+ double d048 = f1 ();
+ double d049 = f1 ();
+ double d050 = f1 ();
+ double d051 = f1 ();
+ double d052 = f1 ();
+ double d053 = f1 ();
+ double d054 = f1 ();
+ double d055 = f1 ();
+ double d056 = f1 ();
+ double d057 = f1 ();
+ double d058 = f1 ();
+ double d059 = f1 ();
+ double d060 = f1 ();
+ double d061 = f1 ();
+ double d062 = f1 ();
+ double d063 = f1 ();
+ double d064 = f1 ();
+ double d065 = f1 ();
+ double d066 = f1 ();
+ double d067 = f1 ();
+ double d068 = f1 ();
+ double d069 = f1 ();
+ double d070 = f1 ();
+ double d071 = f1 ();
+ double d072 = f1 ();
+ double d073 = f1 ();
+ double d074 = f1 ();
+ double d075 = f1 ();
+ double d076 = f1 ();
+ double d077 = f1 ();
+ double d078 = f1 ();
+ double d079 = f1 ();
+ double d080 = f1 ();
+ double d081 = f1 ();
+ double d082 = f1 ();
+ double d083 = f1 ();
+ double d084 = f1 ();
+ double d085 = f1 ();
+ double d086 = f1 ();
+ double d087 = f1 ();
+ double d088 = f1 ();
+ double d089 = f1 ();
+ double d090 = f1 ();
+ double d091 = f1 ();
+ double d092 = f1 ();
+ double d093 = f1 ();
+ double d094 = f1 ();
+ double d095 = f1 ();
+ double d096 = f1 ();
+ double d097 = f1 ();
+ double d098 = f1 ();
+ double d099 = f1 ();
+ double d100 = f1 ();
+ double d101 = f1 ();
+ double d102 = f1 ();
+ double d103 = f1 ();
+ double d104 = f1 ();
+ double d105 = f1 ();
+ double d106 = f1 ();
+ double d107 = f1 ();
+ double d108 = f1 ();
+ double d109 = f1 ();
+ double d110 = f1 ();
+ double d111 = f1 ();
+ double d112 = f1 ();
+ double d113 = f1 ();
+ double d114 = f1 ();
+ double d115 = f1 ();
+ double d116 = f1 ();
+ double d117 = f1 ();
+ double d118 = f1 ();
+ double d119 = f1 ();
+ double d120 = f1 ();
+ double d121 = f1 ();
+ double d122 = f1 ();
+ double d123 = f1 ();
+ double d124 = f1 ();
+ double d125 = f1 ();
+ double d126 = f1 ();
+ double d127 = f1 ();
+ double d128 = f1 ();
+ double d129 = f1 ();
+ double d130 = f1 ();
+ double d131 = f1 ();
+ double d132 = f1 ();
+ double d133 = f1 ();
+ double d134 = f1 ();
+ double d135 = f1 ();
+ double d136 = f1 ();
+ double d137 = f1 ();
+ double d138 = f1 ();
+ double d139 = f1 ();
+ double d140 = f1 ();
+ double d141 = f1 ();
+ double d142 = f1 ();
+ double d143 = f1 ();
+ double d144 = f1 ();
+ double d145 = f1 ();
+ double d146 = f1 ();
+ double d147 = f1 ();
+ double d148 = f1 ();
+ double d149 = f1 ();
+ double d150 = f1 ();
+ double d151 = f1 ();
+ double d152 = f1 ();
+ double d153 = f1 ();
+ double d154 = f1 ();
+ double d155 = f1 ();
+ double d156 = f1 ();
+ double d157 = f1 ();
+ double d158 = f1 ();
+ double d159 = f1 ();
+ double d160 = f1 ();
+ double d161 = f1 ();
+ double d162 = f1 ();
+ double d163 = f1 ();
+ double d164 = f1 ();
+ double d165 = f1 ();
+ double d166 = f1 ();
+ double d167 = f1 ();
+ double d168 = f1 ();
+ double d169 = f1 ();
+ double d170 = f1 ();
+ double d171 = f1 ();
+ double d172 = f1 ();
+ double d173 = f1 ();
+ double d174 = f1 ();
+ double d175 = f1 ();
+ double d176 = f1 ();
+ double d177 = f1 ();
+ double d178 = f1 ();
+ double d179 = f1 ();
+ double d180 = f1 ();
+ double d181 = f1 ();
+ double d182 = f1 ();
+ double d183 = f1 ();
+ double d184 = f1 ();
+ double d185 = f1 ();
+ double d186 = f1 ();
+ double d187 = f1 ();
+ double d188 = f1 ();
+ double d189 = f1 ();
+ double d190 = f1 ();
+ double d191 = f1 ();
+ double d192 = f1 ();
+ double d193 = f1 ();
+ double d194 = f1 ();
+ double d195 = f1 ();
+ double d196 = f1 ();
+ double d197 = f1 ();
+ double d198 = f1 ();
+ double d199 = f1 ();
+ double d200 = f1 ();
+ double d201 = f1 ();
+ double d202 = f1 ();
+ double d203 = f1 ();
+ double d204 = f1 ();
+ double d205 = f1 ();
+ double d206 = f1 ();
+ double d207 = f1 ();
+ double d208 = f1 ();
+ double d209 = f1 ();
+ double d210 = f1 ();
+ double d211 = f1 ();
+ double d212 = f1 ();
+ double d213 = f1 ();
+ double d214 = f1 ();
+ double d215 = f1 ();
+ double d216 = f1 ();
+ double d217 = f1 ();
+ double d218 = f1 ();
+ double d219 = f1 ();
+ double d220 = f1 ();
+ double d221 = f1 ();
+ double d222 = f1 ();
+ double d223 = f1 ();
+ double d224 = f1 ();
+ double d225 = f1 ();
+ double d226 = f1 ();
+ double d227 = f1 ();
+ double d228 = f1 ();
+ double d229 = f1 ();
+ double d230 = f1 ();
+ double d231 = f1 ();
+ double d232 = f1 ();
+ double d233 = f1 ();
+ double d234 = f1 ();
+ double d235 = f1 ();
+ double d236 = f1 ();
+ double d237 = f1 ();
+ double d238 = f1 ();
+ double d239 = f1 ();
+ double d240 = f1 ();
+ double d241 = f1 ();
+ double d242 = f1 ();
+ double d243 = f1 ();
+ double d244 = f1 ();
+ double d245 = f1 ();
+ double d246 = f1 ();
+ double d247 = f1 ();
+ double d248 = f1 ();
+ double d249 = f1 ();
+ double d250 = f1 ();
+ double d251 = f1 ();
+ double d252 = f1 ();
+ double d253 = f1 ();
+ double d254 = f1 ();
+ double d255 = f1 ();
+ double d256 = f1 ();
+ double d257 = f1 ();
+ double d258 = f1 ();
+ double d259 = f1 ();
+ double d260 = f1 ();
+ double d261 = f1 ();
+ double d262 = f1 ();
+ double d263 = f1 ();
+ double d264 = f1 ();
+ double d265 = f1 ();
+ double d266 = f1 ();
+ double d267 = f1 ();
+ double d268 = f1 ();
+ double d269 = f1 ();
+ double d270 = f1 ();
+ double d271 = f1 ();
+ double d272 = f1 ();
+ double d273 = f1 ();
+ double d274 = f1 ();
+ double d275 = f1 ();
+ double d276 = f1 ();
+ double d277 = f1 ();
+ double d278 = f1 ();
+ double d279 = f1 ();
+ double d280 = f1 ();
+ double d281 = f1 ();
+ double d282 = f1 ();
+ double d283 = f1 ();
+ double d284 = f1 ();
+ double d285 = f1 ();
+ double d286 = f1 ();
+ double d287 = f1 ();
+ double d288 = f1 ();
+ double d289 = f1 ();
+ double d290 = f1 ();
+ double d291 = f1 ();
+ double d292 = f1 ();
+ double d293 = f1 ();
+ double d294 = f1 ();
+ double d295 = f1 ();
+ double d296 = f1 ();
+ double d297 = f1 ();
+ double d298 = f1 ();
+ double d299 = f1 ();
+ double d300 = f1 ();
+ double d301 = f1 ();
+ double d302 = f1 ();
+ double d303 = f1 ();
+ double d304 = f1 ();
+ double d305 = f1 ();
+ double d306 = f1 ();
+ double d307 = f1 ();
+ double d308 = f1 ();
+ double d309 = f1 ();
+ double d310 = f1 ();
+ double d311 = f1 ();
+ double d312 = f1 ();
+ double d313 = f1 ();
+ double d314 = f1 ();
+ double d315 = f1 ();
+ double d316 = f1 ();
+ double d317 = f1 ();
+ double d318 = f1 ();
+ double d319 = f1 ();
+ double d320 = f1 ();
+ double d321 = f1 ();
+ double d322 = f1 ();
+ double d323 = f1 ();
+ double d324 = f1 ();
+ double d325 = f1 ();
+ double d326 = f1 ();
+ double d327 = f1 ();
+ double d328 = f1 ();
+ double d329 = f1 ();
+ double d330 = f1 ();
+ double d331 = f1 ();
+ double d332 = f1 ();
+ double d333 = f1 ();
+ double d334 = f1 ();
+ double d335 = f1 ();
+ double d336 = f1 ();
+ double d337 = f1 ();
+ double d338 = f1 ();
+ double d339 = f1 ();
+ double d340 = f1 ();
+ double d341 = f1 ();
+ double d342 = f1 ();
+ double d343 = f1 ();
+ double d344 = f1 ();
+ double d345 = f1 ();
+ double d346 = f1 ();
+ double d347 = f1 ();
+ double d348 = f1 ();
+ double d349 = f1 ();
+ double d350 = f1 ();
+ double d351 = f1 ();
+ double d352 = f1 ();
+ double d353 = f1 ();
+ double d354 = f1 ();
+ double d355 = f1 ();
+ double d356 = f1 ();
+ double d357 = f1 ();
+ double d358 = f1 ();
+ double d359 = f1 ();
+ double d360 = f1 ();
+ double d361 = f1 ();
+ double d362 = f1 ();
+ double d363 = f1 ();
+ double d364 = f1 ();
+ double d365 = f1 ();
+ double d366 = f1 ();
+ double d367 = f1 ();
+ double d368 = f1 ();
+ double d369 = f1 ();
+ double d370 = f1 ();
+ double d371 = f1 ();
+ double d372 = f1 ();
+ double d373 = f1 ();
+ double d374 = f1 ();
+ double d375 = f1 ();
+ double d376 = f1 ();
+ double d377 = f1 ();
+ double d378 = f1 ();
+ double d379 = f1 ();
+ double d380 = f1 ();
+ double d381 = f1 ();
+ double d382 = f1 ();
+ double d383 = f1 ();
+ double d384 = f1 ();
+ double d385 = f1 ();
+ double d386 = f1 ();
+ double d387 = f1 ();
+ double d388 = f1 ();
+ double d389 = f1 ();
+ double d390 = f1 ();
+ double d391 = f1 ();
+ double d392 = f1 ();
+ double d393 = f1 ();
+ double d394 = f1 ();
+ double d395 = f1 ();
+ double d396 = f1 ();
+ double d397 = f1 ();
+ double d398 = f1 ();
+ double d399 = f1 ();
+ double d400 = f1 ();
+ double d401 = f1 ();
+ double d402 = f1 ();
+ double d403 = f1 ();
+ double d404 = f1 ();
+ double d405 = f1 ();
+ double d406 = f1 ();
+ double d407 = f1 ();
+ double d408 = f1 ();
+ double d409 = f1 ();
+ double d410 = f1 ();
+ double d411 = f1 ();
+ double d412 = f1 ();
+ double d413 = f1 ();
+ double d414 = f1 ();
+ double d415 = f1 ();
+ double d416 = f1 ();
+ double d417 = f1 ();
+ double d418 = f1 ();
+ double d419 = f1 ();
+ double d420 = f1 ();
+ double d421 = f1 ();
+ double d422 = f1 ();
+ double d423 = f1 ();
+ double d424 = f1 ();
+ double d425 = f1 ();
+ double d426 = f1 ();
+ double d427 = f1 ();
+ double d428 = f1 ();
+ double d429 = f1 ();
+ double d430 = f1 ();
+ double d431 = f1 ();
+ double d432 = f1 ();
+ double d433 = f1 ();
+ double d434 = f1 ();
+ double d435 = f1 ();
+ double d436 = f1 ();
+ double d437 = f1 ();
+ double d438 = f1 ();
+ double d439 = f1 ();
+ double d440 = f1 ();
+ double d441 = f1 ();
+ double d442 = f1 ();
+ double d443 = f1 ();
+ double d444 = f1 ();
+ double d445 = f1 ();
+ double d446 = f1 ();
+ double d447 = f1 ();
+ double d448 = f1 ();
+ double d449 = f1 ();
+ double d450 = f1 ();
+ double d451 = f1 ();
+ double d452 = f1 ();
+ double d453 = f1 ();
+ double d454 = f1 ();
+ double d455 = f1 ();
+ double d456 = f1 ();
+ double d457 = f1 ();
+ double d458 = f1 ();
+ double d459 = f1 ();
+ double d460 = f1 ();
+ double d461 = f1 ();
+ double d462 = f1 ();
+ double d463 = f1 ();
+ double d464 = f1 ();
+ double d465 = f1 ();
+ double d466 = f1 ();
+ double d467 = f1 ();
+ double d468 = f1 ();
+ double d469 = f1 ();
+ double d470 = f1 ();
+ double d471 = f1 ();
+ double d472 = f1 ();
+ double d473 = f1 ();
+ double d474 = f1 ();
+ double d475 = f1 ();
+ double d476 = f1 ();
+ double d477 = f1 ();
+ double d478 = f1 ();
+ double d479 = f1 ();
+ double d480 = f1 ();
+ double d481 = f1 ();
+ double d482 = f1 ();
+ double d483 = f1 ();
+ double d484 = f1 ();
+ double d485 = f1 ();
+ double d486 = f1 ();
+ double d487 = f1 ();
+ double d488 = f1 ();
+ double d489 = f1 ();
+ double d490 = f1 ();
+ double d491 = f1 ();
+ double d492 = f1 ();
+ double d493 = f1 ();
+ double d494 = f1 ();
+ double d495 = f1 ();
+ double d496 = f1 ();
+ double d497 = f1 ();
+ double d498 = f1 ();
+ double d499 = f1 ();
+ double d500 = f1 ();
+ double d501 = f1 ();
+ double d502 = f1 ();
+ double d503 = f1 ();
+ double d504 = f1 ();
+ double d505 = f1 ();
+ double d506 = f1 ();
+ double d507 = f1 ();
+ double d508 = f1 ();
+ double d509 = f1 ();
+ double d510 = f1 ();
+ double d511 = f1 ();
+ double d512 = f1 ();
+ double d513 = f1 ();
+ double d514 = f1 ();
+ double d515 = f1 ();
+ double d516 = f1 ();
+ double d517 = f1 ();
+ double d518 = f1 ();
+ double d519 = f1 ();
+ double d520 = f1 ();
+ double d521 = f1 ();
+ double d522 = f1 ();
+ double d523 = f1 ();
+ double d524 = f1 ();
+ double d525 = f1 ();
+ double d526 = f1 ();
+ double d527 = f1 ();
+ double d528 = f1 ();
+ double d529 = f1 ();
+ double d530 = f1 ();
+ double d531 = f1 ();
+ double d532 = f1 ();
+ double d533 = f1 ();
+ double d534 = f1 ();
+ double d535 = f1 ();
+ double d536 = f1 ();
+ double d537 = f1 ();
+ double d538 = f1 ();
+ double d539 = f1 ();
+ double d540 = f1 ();
+ double d541 = f1 ();
+ double d542 = f1 ();
+ double d543 = f1 ();
+ double d544 = f1 ();
+ double d545 = f1 ();
+ double d546 = f1 ();
+ double d547 = f1 ();
+ double d548 = f1 ();
+ double d549 = f1 ();
+ double d550 = f1 ();
+ double d551 = f1 ();
+ double d552 = f1 ();
+ double d553 = f1 ();
+ double d554 = f1 ();
+ double d555 = f1 ();
+ double d556 = f1 ();
+ double d557 = f1 ();
+ double d558 = f1 ();
+ double d559 = f1 ();
+ double d560 = f1 ();
+ double d561 = f1 ();
+ double d562 = f1 ();
+ double d563 = f1 ();
+ double d564 = f1 ();
+ double d565 = f1 ();
+ double d566 = f1 ();
+ double d567 = f1 ();
+ double d568 = f1 ();
+ double d569 = f1 ();
+ double d570 = f1 ();
+ double d571 = f1 ();
+ double d572 = f1 ();
+ double d573 = f1 ();
+ double d574 = f1 ();
+ double d575 = f1 ();
+ double d576 = f1 ();
+ double d577 = f1 ();
+ double d578 = f1 ();
+ double d579 = f1 ();
+ double d580 = f1 ();
+ double d581 = f1 ();
+ double d582 = f1 ();
+ double d583 = f1 ();
+ double d584 = f1 ();
+ double d585 = f1 ();
+ double d586 = f1 ();
+ double d587 = f1 ();
+ double d588 = f1 ();
+ double d589 = f1 ();
+ double d590 = f1 ();
+ double d591 = f1 ();
+ double d592 = f1 ();
+ double d593 = f1 ();
+ double d594 = f1 ();
+ double d595 = f1 ();
+ double d596 = f1 ();
+ double d597 = f1 ();
+ double d598 = f1 ();
+ double d599 = f1 ();
+ double d600 = f1 ();
+ double d601 = f1 ();
+ double d602 = f1 ();
+ double d603 = f1 ();
+ double d604 = f1 ();
+ double d605 = f1 ();
+ double d606 = f1 ();
+ double d607 = f1 ();
+ double d608 = f1 ();
+ double d609 = f1 ();
+ double d610 = f1 ();
+ double d611 = f1 ();
+ double d612 = f1 ();
+ double d613 = f1 ();
+ double d614 = f1 ();
+ double d615 = f1 ();
+ double d616 = f1 ();
+ double d617 = f1 ();
+ double d618 = f1 ();
+ double d619 = f1 ();
+ double d620 = f1 ();
+ double d621 = f1 ();
+ double d622 = f1 ();
+ double d623 = f1 ();
+ double d624 = f1 ();
+ double d625 = f1 ();
+ double d626 = f1 ();
+ double d627 = f1 ();
+ double d628 = f1 ();
+ double d629 = f1 ();
+ double d630 = f1 ();
+ double d631 = f1 ();
+ double d632 = f1 ();
+ double d633 = f1 ();
+ double d634 = f1 ();
+ double d635 = f1 ();
+ double d636 = f1 ();
+ double d637 = f1 ();
+ double d638 = f1 ();
+ double d639 = f1 ();
+ double d640 = f1 ();
+ double d641 = f1 ();
+ double d642 = f1 ();
+ double d643 = f1 ();
+ double d644 = f1 ();
+ double d645 = f1 ();
+ double d646 = f1 ();
+ double d647 = f1 ();
+ double d648 = f1 ();
+ double d649 = f1 ();
+ double d650 = f1 ();
+ double d651 = f1 ();
+ double d652 = f1 ();
+ double d653 = f1 ();
+ double d654 = f1 ();
+ double d655 = f1 ();
+ double d656 = f1 ();
+ double d657 = f1 ();
+ double d658 = f1 ();
+ double d659 = f1 ();
+ double d660 = f1 ();
+ double d661 = f1 ();
+ double d662 = f1 ();
+ double d663 = f1 ();
+ double d664 = f1 ();
+ double d665 = f1 ();
+ double d666 = f1 ();
+ double d667 = f1 ();
+ double d668 = f1 ();
+ double d669 = f1 ();
+ double d670 = f1 ();
+ double d671 = f1 ();
+ double d672 = f1 ();
+ double d673 = f1 ();
+ double d674 = f1 ();
+ double d675 = f1 ();
+ double d676 = f1 ();
+ double d677 = f1 ();
+ double d678 = f1 ();
+ double d679 = f1 ();
+ double d680 = f1 ();
+ double d681 = f1 ();
+ double d682 = f1 ();
+ double d683 = f1 ();
+ double d684 = f1 ();
+ double d685 = f1 ();
+ double d686 = f1 ();
+ double d687 = f1 ();
+ double d688 = f1 ();
+ double d689 = f1 ();
+ double d690 = f1 ();
+ double d691 = f1 ();
+ double d692 = f1 ();
+ double d693 = f1 ();
+ double d694 = f1 ();
+ double d695 = f1 ();
+ double d696 = f1 ();
+ double d697 = f1 ();
+ double d698 = f1 ();
+ double d699 = f1 ();
+ double d700 = f1 ();
+ double d701 = f1 ();
+ double d702 = f1 ();
+ double d703 = f1 ();
+ double d704 = f1 ();
+ double d705 = f1 ();
+ double d706 = f1 ();
+ double d707 = f1 ();
+ double d708 = f1 ();
+ double d709 = f1 ();
+ double d710 = f1 ();
+ double d711 = f1 ();
+ double d712 = f1 ();
+ double d713 = f1 ();
+ double d714 = f1 ();
+ double d715 = f1 ();
+ double d716 = f1 ();
+ double d717 = f1 ();
+ double d718 = f1 ();
+ double d719 = f1 ();
+ double d720 = f1 ();
+ double d721 = f1 ();
+ double d722 = f1 ();
+ double d723 = f1 ();
+ double d724 = f1 ();
+ double d725 = f1 ();
+ double d726 = f1 ();
+ double d727 = f1 ();
+ double d728 = f1 ();
+ double d729 = f1 ();
+ double d730 = f1 ();
+ double d731 = f1 ();
+ double d732 = f1 ();
+ double d733 = f1 ();
+ double d734 = f1 ();
+ double d735 = f1 ();
+ double d736 = f1 ();
+ double d737 = f1 ();
+ double d738 = f1 ();
+ double d739 = f1 ();
+ double d740 = f1 ();
+ double d741 = f1 ();
+ double d742 = f1 ();
+ double d743 = f1 ();
+ double d744 = f1 ();
+ double d745 = f1 ();
+ double d746 = f1 ();
+ double d747 = f1 ();
+ double d748 = f1 ();
+ double d749 = f1 ();
+ double d750 = f1 ();
+ double d751 = f1 ();
+ double d752 = f1 ();
+ double d753 = f1 ();
+ double d754 = f1 ();
+ double d755 = f1 ();
+ double d756 = f1 ();
+ double d757 = f1 ();
+ double d758 = f1 ();
+ double d759 = f1 ();
+ double d760 = f1 ();
+ double d761 = f1 ();
+ double d762 = f1 ();
+ double d763 = f1 ();
+ double d764 = f1 ();
+ double d765 = f1 ();
+ double d766 = f1 ();
+ double d767 = f1 ();
+ double d768 = f1 ();
+ double d769 = f1 ();
+ double d770 = f1 ();
+ double d771 = f1 ();
+ double d772 = f1 ();
+ double d773 = f1 ();
+ double d774 = f1 ();
+ double d775 = f1 ();
+ double d776 = f1 ();
+ double d777 = f1 ();
+ double d778 = f1 ();
+ double d779 = f1 ();
+ double d780 = f1 ();
+ double d781 = f1 ();
+ double d782 = f1 ();
+ double d783 = f1 ();
+ double d784 = f1 ();
+ double d785 = f1 ();
+ double d786 = f1 ();
+ double d787 = f1 ();
+ double d788 = f1 ();
+ double d789 = f1 ();
+ double d790 = f1 ();
+ double d791 = f1 ();
+ double d792 = f1 ();
+ double d793 = f1 ();
+ double d794 = f1 ();
+ double d795 = f1 ();
+ double d796 = f1 ();
+ double d797 = f1 ();
+ double d798 = f1 ();
+ double d799 = f1 ();
+ double d800 = f1 ();
+ double d801 = f1 ();
+ double d802 = f1 ();
+ double d803 = f1 ();
+ double d804 = f1 ();
+ double d805 = f1 ();
+ double d806 = f1 ();
+ double d807 = f1 ();
+ double d808 = f1 ();
+ double d809 = f1 ();
+ double d810 = f1 ();
+ double d811 = f1 ();
+ double d812 = f1 ();
+ double d813 = f1 ();
+ double d814 = f1 ();
+ double d815 = f1 ();
+ double d816 = f1 ();
+ double d817 = f1 ();
+ double d818 = f1 ();
+ double d819 = f1 ();
+ double d820 = f1 ();
+ double d821 = f1 ();
+ double d822 = f1 ();
+ double d823 = f1 ();
+ double d824 = f1 ();
+ double d825 = f1 ();
+ double d826 = f1 ();
+ double d827 = f1 ();
+ double d828 = f1 ();
+ double d829 = f1 ();
+ double d830 = f1 ();
+ double d831 = f1 ();
+ double d832 = f1 ();
+ double d833 = f1 ();
+ double d834 = f1 ();
+ double d835 = f1 ();
+ double d836 = f1 ();
+ double d837 = f1 ();
+ double d838 = f1 ();
+ double d839 = f1 ();
+ double d840 = f1 ();
+ double d841 = f1 ();
+ double d842 = f1 ();
+ double d843 = f1 ();
+ double d844 = f1 ();
+ double d845 = f1 ();
+ double d846 = f1 ();
+ double d847 = f1 ();
+ double d848 = f1 ();
+ double d849 = f1 ();
+ double d850 = f1 ();
+ double d851 = f1 ();
+ double d852 = f1 ();
+ double d853 = f1 ();
+ double d854 = f1 ();
+ double d855 = f1 ();
+ double d856 = f1 ();
+ double d857 = f1 ();
+ double d858 = f1 ();
+ double d859 = f1 ();
+ double d860 = f1 ();
+ double d861 = f1 ();
+ double d862 = f1 ();
+ double d863 = f1 ();
+ double d864 = f1 ();
+ double d865 = f1 ();
+ double d866 = f1 ();
+ double d867 = f1 ();
+ double d868 = f1 ();
+ double d869 = f1 ();
+ double d870 = f1 ();
+ double d871 = f1 ();
+ double d872 = f1 ();
+ double d873 = f1 ();
+ double d874 = f1 ();
+ double d875 = f1 ();
+ double d876 = f1 ();
+ double d877 = f1 ();
+ double d878 = f1 ();
+ double d879 = f1 ();
+ double d880 = f1 ();
+ double d881 = f1 ();
+ double d882 = f1 ();
+ double d883 = f1 ();
+ double d884 = f1 ();
+ double d885 = f1 ();
+ double d886 = f1 ();
+ double d887 = f1 ();
+ double d888 = f1 ();
+ double d889 = f1 ();
+ double d890 = f1 ();
+ double d891 = f1 ();
+ double d892 = f1 ();
+ double d893 = f1 ();
+ double d894 = f1 ();
+ double d895 = f1 ();
+ double d896 = f1 ();
+ double d897 = f1 ();
+ double d898 = f1 ();
+ double d899 = f1 ();
+ double d900 = f1 ();
+ double d901 = f1 ();
+ double d902 = f1 ();
+ double d903 = f1 ();
+ double d904 = f1 ();
+ double d905 = f1 ();
+ double d906 = f1 ();
+ double d907 = f1 ();
+ double d908 = f1 ();
+ double d909 = f1 ();
+ double d910 = f1 ();
+ double d911 = f1 ();
+ double d912 = f1 ();
+ double d913 = f1 ();
+ double d914 = f1 ();
+ double d915 = f1 ();
+ double d916 = f1 ();
+ double d917 = f1 ();
+ double d918 = f1 ();
+ double d919 = f1 ();
+ double d920 = f1 ();
+ double d921 = f1 ();
+ double d922 = f1 ();
+ double d923 = f1 ();
+ double d924 = f1 ();
+ double d925 = f1 ();
+ double d926 = f1 ();
+ double d927 = f1 ();
+ double d928 = f1 ();
+ double d929 = f1 ();
+ double d930 = f1 ();
+ double d931 = f1 ();
+ double d932 = f1 ();
+ double d933 = f1 ();
+ double d934 = f1 ();
+ double d935 = f1 ();
+ double d936 = f1 ();
+ double d937 = f1 ();
+ double d938 = f1 ();
+ double d939 = f1 ();
+ double d940 = f1 ();
+ double d941 = f1 ();
+ double d942 = f1 ();
+ double d943 = f1 ();
+ double d944 = f1 ();
+ double d945 = f1 ();
+ double d946 = f1 ();
+ double d947 = f1 ();
+ double d948 = f1 ();
+ double d949 = f1 ();
+ double d950 = f1 ();
+ double d951 = f1 ();
+ double d952 = f1 ();
+ double d953 = f1 ();
+ double d954 = f1 ();
+ double d955 = f1 ();
+ double d956 = f1 ();
+ double d957 = f1 ();
+ double d958 = f1 ();
+ double d959 = f1 ();
+ double d960 = f1 ();
+ double d961 = f1 ();
+ double d962 = f1 ();
+ double d963 = f1 ();
+ double d964 = f1 ();
+ double d965 = f1 ();
+ double d966 = f1 ();
+ double d967 = f1 ();
+ double d968 = f1 ();
+ double d969 = f1 ();
+ double d970 = f1 ();
+ double d971 = f1 ();
+ double d972 = f1 ();
+ double d973 = f1 ();
+ double d974 = f1 ();
+ double d975 = f1 ();
+ double d976 = f1 ();
+ double d977 = f1 ();
+ double d978 = f1 ();
+ double d979 = f1 ();
+ double d980 = f1 ();
+ double d981 = f1 ();
+ double d982 = f1 ();
+ double d983 = f1 ();
+ double d984 = f1 ();
+ double d985 = f1 ();
+ double d986 = f1 ();
+ double d987 = f1 ();
+ double d988 = f1 ();
+ double d989 = f1 ();
+ double d990 = f1 ();
+ double d991 = f1 ();
+ double d992 = f1 ();
+ double d993 = f1 ();
+ double d994 = f1 ();
+ double d995 = f1 ();
+ double d996 = f1 ();
+ double d997 = f1 ();
+ double d998 = f1 ();
+ double d999 = f1 ();
+
+ double x = 0;
+ x = f2 (x, d000);
+ x = f2 (x, d001);
+ x = f2 (x, d002);
+ x = f2 (x, d003);
+ x = f2 (x, d004);
+ x = f2 (x, d005);
+ x = f2 (x, d006);
+ x = f2 (x, d007);
+ x = f2 (x, d008);
+ x = f2 (x, d009);
+ x = f2 (x, d010);
+ x = f2 (x, d011);
+ x = f2 (x, d012);
+ x = f2 (x, d013);
+ x = f2 (x, d014);
+ x = f2 (x, d015);
+ x = f2 (x, d016);
+ x = f2 (x, d017);
+ x = f2 (x, d018);
+ x = f2 (x, d019);
+ x = f2 (x, d020);
+ x = f2 (x, d021);
+ x = f2 (x, d022);
+ x = f2 (x, d023);
+ x = f2 (x, d024);
+ x = f2 (x, d025);
+ x = f2 (x, d026);
+ x = f2 (x, d027);
+ x = f2 (x, d028);
+ x = f2 (x, d029);
+ x = f2 (x, d030);
+ x = f2 (x, d031);
+ x = f2 (x, d032);
+ x = f2 (x, d033);
+ x = f2 (x, d034);
+ x = f2 (x, d035);
+ x = f2 (x, d036);
+ x = f2 (x, d037);
+ x = f2 (x, d038);
+ x = f2 (x, d039);
+ x = f2 (x, d040);
+ x = f2 (x, d041);
+ x = f2 (x, d042);
+ x = f2 (x, d043);
+ x = f2 (x, d044);
+ x = f2 (x, d045);
+ x = f2 (x, d046);
+ x = f2 (x, d047);
+ x = f2 (x, d048);
+ x = f2 (x, d049);
+ x = f2 (x, d050);
+ x = f2 (x, d051);
+ x = f2 (x, d052);
+ x = f2 (x, d053);
+ x = f2 (x, d054);
+ x = f2 (x, d055);
+ x = f2 (x, d056);
+ x = f2 (x, d057);
+ x = f2 (x, d058);
+ x = f2 (x, d059);
+ x = f2 (x, d060);
+ x = f2 (x, d061);
+ x = f2 (x, d062);
+ x = f2 (x, d063);
+ x = f2 (x, d064);
+ x = f2 (x, d065);
+ x = f2 (x, d066);
+ x = f2 (x, d067);
+ x = f2 (x, d068);
+ x = f2 (x, d069);
+ x = f2 (x, d070);
+ x = f2 (x, d071);
+ x = f2 (x, d072);
+ x = f2 (x, d073);
+ x = f2 (x, d074);
+ x = f2 (x, d075);
+ x = f2 (x, d076);
+ x = f2 (x, d077);
+ x = f2 (x, d078);
+ x = f2 (x, d079);
+ x = f2 (x, d080);
+ x = f2 (x, d081);
+ x = f2 (x, d082);
+ x = f2 (x, d083);
+ x = f2 (x, d084);
+ x = f2 (x, d085);
+ x = f2 (x, d086);
+ x = f2 (x, d087);
+ x = f2 (x, d088);
+ x = f2 (x, d089);
+ x = f2 (x, d090);
+ x = f2 (x, d091);
+ x = f2 (x, d092);
+ x = f2 (x, d093);
+ x = f2 (x, d094);
+ x = f2 (x, d095);
+ x = f2 (x, d096);
+ x = f2 (x, d097);
+ x = f2 (x, d098);
+ x = f2 (x, d099);
+ x = f2 (x, d100);
+ x = f2 (x, d101);
+ x = f2 (x, d102);
+ x = f2 (x, d103);
+ x = f2 (x, d104);
+ x = f2 (x, d105);
+ x = f2 (x, d106);
+ x = f2 (x, d107);
+ x = f2 (x, d108);
+ x = f2 (x, d109);
+ x = f2 (x, d110);
+ x = f2 (x, d111);
+ x = f2 (x, d112);
+ x = f2 (x, d113);
+ x = f2 (x, d114);
+ x = f2 (x, d115);
+ x = f2 (x, d116);
+ x = f2 (x, d117);
+ x = f2 (x, d118);
+ x = f2 (x, d119);
+ x = f2 (x, d120);
+ x = f2 (x, d121);
+ x = f2 (x, d122);
+ x = f2 (x, d123);
+ x = f2 (x, d124);
+ x = f2 (x, d125);
+ x = f2 (x, d126);
+ x = f2 (x, d127);
+ x = f2 (x, d128);
+ x = f2 (x, d129);
+ x = f2 (x, d130);
+ x = f2 (x, d131);
+ x = f2 (x, d132);
+ x = f2 (x, d133);
+ x = f2 (x, d134);
+ x = f2 (x, d135);
+ x = f2 (x, d136);
+ x = f2 (x, d137);
+ x = f2 (x, d138);
+ x = f2 (x, d139);
+ x = f2 (x, d140);
+ x = f2 (x, d141);
+ x = f2 (x, d142);
+ x = f2 (x, d143);
+ x = f2 (x, d144);
+ x = f2 (x, d145);
+ x = f2 (x, d146);
+ x = f2 (x, d147);
+ x = f2 (x, d148);
+ x = f2 (x, d149);
+ x = f2 (x, d150);
+ x = f2 (x, d151);
+ x = f2 (x, d152);
+ x = f2 (x, d153);
+ x = f2 (x, d154);
+ x = f2 (x, d155);
+ x = f2 (x, d156);
+ x = f2 (x, d157);
+ x = f2 (x, d158);
+ x = f2 (x, d159);
+ x = f2 (x, d160);
+ x = f2 (x, d161);
+ x = f2 (x, d162);
+ x = f2 (x, d163);
+ x = f2 (x, d164);
+ x = f2 (x, d165);
+ x = f2 (x, d166);
+ x = f2 (x, d167);
+ x = f2 (x, d168);
+ x = f2 (x, d169);
+ x = f2 (x, d170);
+ x = f2 (x, d171);
+ x = f2 (x, d172);
+ x = f2 (x, d173);
+ x = f2 (x, d174);
+ x = f2 (x, d175);
+ x = f2 (x, d176);
+ x = f2 (x, d177);
+ x = f2 (x, d178);
+ x = f2 (x, d179);
+ x = f2 (x, d180);
+ x = f2 (x, d181);
+ x = f2 (x, d182);
+ x = f2 (x, d183);
+ x = f2 (x, d184);
+ x = f2 (x, d185);
+ x = f2 (x, d186);
+ x = f2 (x, d187);
+ x = f2 (x, d188);
+ x = f2 (x, d189);
+ x = f2 (x, d190);
+ x = f2 (x, d191);
+ x = f2 (x, d192);
+ x = f2 (x, d193);
+ x = f2 (x, d194);
+ x = f2 (x, d195);
+ x = f2 (x, d196);
+ x = f2 (x, d197);
+ x = f2 (x, d198);
+ x = f2 (x, d199);
+ x = f2 (x, d200);
+ x = f2 (x, d201);
+ x = f2 (x, d202);
+ x = f2 (x, d203);
+ x = f2 (x, d204);
+ x = f2 (x, d205);
+ x = f2 (x, d206);
+ x = f2 (x, d207);
+ x = f2 (x, d208);
+ x = f2 (x, d209);
+ x = f2 (x, d210);
+ x = f2 (x, d211);
+ x = f2 (x, d212);
+ x = f2 (x, d213);
+ x = f2 (x, d214);
+ x = f2 (x, d215);
+ x = f2 (x, d216);
+ x = f2 (x, d217);
+ x = f2 (x, d218);
+ x = f2 (x, d219);
+ x = f2 (x, d220);
+ x = f2 (x, d221);
+ x = f2 (x, d222);
+ x = f2 (x, d223);
+ x = f2 (x, d224);
+ x = f2 (x, d225);
+ x = f2 (x, d226);
+ x = f2 (x, d227);
+ x = f2 (x, d228);
+ x = f2 (x, d229);
+ x = f2 (x, d230);
+ x = f2 (x, d231);
+ x = f2 (x, d232);
+ x = f2 (x, d233);
+ x = f2 (x, d234);
+ x = f2 (x, d235);
+ x = f2 (x, d236);
+ x = f2 (x, d237);
+ x = f2 (x, d238);
+ x = f2 (x, d239);
+ x = f2 (x, d240);
+ x = f2 (x, d241);
+ x = f2 (x, d242);
+ x = f2 (x, d243);
+ x = f2 (x, d244);
+ x = f2 (x, d245);
+ x = f2 (x, d246);
+ x = f2 (x, d247);
+ x = f2 (x, d248);
+ x = f2 (x, d249);
+ x = f2 (x, d250);
+ x = f2 (x, d251);
+ x = f2 (x, d252);
+ x = f2 (x, d253);
+ x = f2 (x, d254);
+ x = f2 (x, d255);
+ x = f2 (x, d256);
+ x = f2 (x, d257);
+ x = f2 (x, d258);
+ x = f2 (x, d259);
+ x = f2 (x, d260);
+ x = f2 (x, d261);
+ x = f2 (x, d262);
+ x = f2 (x, d263);
+ x = f2 (x, d264);
+ x = f2 (x, d265);
+ x = f2 (x, d266);
+ x = f2 (x, d267);
+ x = f2 (x, d268);
+ x = f2 (x, d269);
+ x = f2 (x, d270);
+ x = f2 (x, d271);
+ x = f2 (x, d272);
+ x = f2 (x, d273);
+ x = f2 (x, d274);
+ x = f2 (x, d275);
+ x = f2 (x, d276);
+ x = f2 (x, d277);
+ x = f2 (x, d278);
+ x = f2 (x, d279);
+ x = f2 (x, d280);
+ x = f2 (x, d281);
+ x = f2 (x, d282);
+ x = f2 (x, d283);
+ x = f2 (x, d284);
+ x = f2 (x, d285);
+ x = f2 (x, d286);
+ x = f2 (x, d287);
+ x = f2 (x, d288);
+ x = f2 (x, d289);
+ x = f2 (x, d290);
+ x = f2 (x, d291);
+ x = f2 (x, d292);
+ x = f2 (x, d293);
+ x = f2 (x, d294);
+ x = f2 (x, d295);
+ x = f2 (x, d296);
+ x = f2 (x, d297);
+ x = f2 (x, d298);
+ x = f2 (x, d299);
+ x = f2 (x, d300);
+ x = f2 (x, d301);
+ x = f2 (x, d302);
+ x = f2 (x, d303);
+ x = f2 (x, d304);
+ x = f2 (x, d305);
+ x = f2 (x, d306);
+ x = f2 (x, d307);
+ x = f2 (x, d308);
+ x = f2 (x, d309);
+ x = f2 (x, d310);
+ x = f2 (x, d311);
+ x = f2 (x, d312);
+ x = f2 (x, d313);
+ x = f2 (x, d314);
+ x = f2 (x, d315);
+ x = f2 (x, d316);
+ x = f2 (x, d317);
+ x = f2 (x, d318);
+ x = f2 (x, d319);
+ x = f2 (x, d320);
+ x = f2 (x, d321);
+ x = f2 (x, d322);
+ x = f2 (x, d323);
+ x = f2 (x, d324);
+ x = f2 (x, d325);
+ x = f2 (x, d326);
+ x = f2 (x, d327);
+ x = f2 (x, d328);
+ x = f2 (x, d329);
+ x = f2 (x, d330);
+ x = f2 (x, d331);
+ x = f2 (x, d332);
+ x = f2 (x, d333);
+ x = f2 (x, d334);
+ x = f2 (x, d335);
+ x = f2 (x, d336);
+ x = f2 (x, d337);
+ x = f2 (x, d338);
+ x = f2 (x, d339);
+ x = f2 (x, d340);
+ x = f2 (x, d341);
+ x = f2 (x, d342);
+ x = f2 (x, d343);
+ x = f2 (x, d344);
+ x = f2 (x, d345);
+ x = f2 (x, d346);
+ x = f2 (x, d347);
+ x = f2 (x, d348);
+ x = f2 (x, d349);
+ x = f2 (x, d350);
+ x = f2 (x, d351);
+ x = f2 (x, d352);
+ x = f2 (x, d353);
+ x = f2 (x, d354);
+ x = f2 (x, d355);
+ x = f2 (x, d356);
+ x = f2 (x, d357);
+ x = f2 (x, d358);
+ x = f2 (x, d359);
+ x = f2 (x, d360);
+ x = f2 (x, d361);
+ x = f2 (x, d362);
+ x = f2 (x, d363);
+ x = f2 (x, d364);
+ x = f2 (x, d365);
+ x = f2 (x, d366);
+ x = f2 (x, d367);
+ x = f2 (x, d368);
+ x = f2 (x, d369);
+ x = f2 (x, d370);
+ x = f2 (x, d371);
+ x = f2 (x, d372);
+ x = f2 (x, d373);
+ x = f2 (x, d374);
+ x = f2 (x, d375);
+ x = f2 (x, d376);
+ x = f2 (x, d377);
+ x = f2 (x, d378);
+ x = f2 (x, d379);
+ x = f2 (x, d380);
+ x = f2 (x, d381);
+ x = f2 (x, d382);
+ x = f2 (x, d383);
+ x = f2 (x, d384);
+ x = f2 (x, d385);
+ x = f2 (x, d386);
+ x = f2 (x, d387);
+ x = f2 (x, d388);
+ x = f2 (x, d389);
+ x = f2 (x, d390);
+ x = f2 (x, d391);
+ x = f2 (x, d392);
+ x = f2 (x, d393);
+ x = f2 (x, d394);
+ x = f2 (x, d395);
+ x = f2 (x, d396);
+ x = f2 (x, d397);
+ x = f2 (x, d398);
+ x = f2 (x, d399);
+ x = f2 (x, d400);
+ x = f2 (x, d401);
+ x = f2 (x, d402);
+ x = f2 (x, d403);
+ x = f2 (x, d404);
+ x = f2 (x, d405);
+ x = f2 (x, d406);
+ x = f2 (x, d407);
+ x = f2 (x, d408);
+ x = f2 (x, d409);
+ x = f2 (x, d410);
+ x = f2 (x, d411);
+ x = f2 (x, d412);
+ x = f2 (x, d413);
+ x = f2 (x, d414);
+ x = f2 (x, d415);
+ x = f2 (x, d416);
+ x = f2 (x, d417);
+ x = f2 (x, d418);
+ x = f2 (x, d419);
+ x = f2 (x, d420);
+ x = f2 (x, d421);
+ x = f2 (x, d422);
+ x = f2 (x, d423);
+ x = f2 (x, d424);
+ x = f2 (x, d425);
+ x = f2 (x, d426);
+ x = f2 (x, d427);
+ x = f2 (x, d428);
+ x = f2 (x, d429);
+ x = f2 (x, d430);
+ x = f2 (x, d431);
+ x = f2 (x, d432);
+ x = f2 (x, d433);
+ x = f2 (x, d434);
+ x = f2 (x, d435);
+ x = f2 (x, d436);
+ x = f2 (x, d437);
+ x = f2 (x, d438);
+ x = f2 (x, d439);
+ x = f2 (x, d440);
+ x = f2 (x, d441);
+ x = f2 (x, d442);
+ x = f2 (x, d443);
+ x = f2 (x, d444);
+ x = f2 (x, d445);
+ x = f2 (x, d446);
+ x = f2 (x, d447);
+ x = f2 (x, d448);
+ x = f2 (x, d449);
+ x = f2 (x, d450);
+ x = f2 (x, d451);
+ x = f2 (x, d452);
+ x = f2 (x, d453);
+ x = f2 (x, d454);
+ x = f2 (x, d455);
+ x = f2 (x, d456);
+ x = f2 (x, d457);
+ x = f2 (x, d458);
+ x = f2 (x, d459);
+ x = f2 (x, d460);
+ x = f2 (x, d461);
+ x = f2 (x, d462);
+ x = f2 (x, d463);
+ x = f2 (x, d464);
+ x = f2 (x, d465);
+ x = f2 (x, d466);
+ x = f2 (x, d467);
+ x = f2 (x, d468);
+ x = f2 (x, d469);
+ x = f2 (x, d470);
+ x = f2 (x, d471);
+ x = f2 (x, d472);
+ x = f2 (x, d473);
+ x = f2 (x, d474);
+ x = f2 (x, d475);
+ x = f2 (x, d476);
+ x = f2 (x, d477);
+ x = f2 (x, d478);
+ x = f2 (x, d479);
+ x = f2 (x, d480);
+ x = f2 (x, d481);
+ x = f2 (x, d482);
+ x = f2 (x, d483);
+ x = f2 (x, d484);
+ x = f2 (x, d485);
+ x = f2 (x, d486);
+ x = f2 (x, d487);
+ x = f2 (x, d488);
+ x = f2 (x, d489);
+ x = f2 (x, d490);
+ x = f2 (x, d491);
+ x = f2 (x, d492);
+ x = f2 (x, d493);
+ x = f2 (x, d494);
+ x = f2 (x, d495);
+ x = f2 (x, d496);
+ x = f2 (x, d497);
+ x = f2 (x, d498);
+ x = f2 (x, d499);
+ x = f2 (x, d500);
+ x = f2 (x, d501);
+ x = f2 (x, d502);
+ x = f2 (x, d503);
+ x = f2 (x, d504);
+ x = f2 (x, d505);
+ x = f2 (x, d506);
+ x = f2 (x, d507);
+ x = f2 (x, d508);
+ x = f2 (x, d509);
+ x = f2 (x, d510);
+ x = f2 (x, d511);
+ x = f2 (x, d512);
+ x = f2 (x, d513);
+ x = f2 (x, d514);
+ x = f2 (x, d515);
+ x = f2 (x, d516);
+ x = f2 (x, d517);
+ x = f2 (x, d518);
+ x = f2 (x, d519);
+ x = f2 (x, d520);
+ x = f2 (x, d521);
+ x = f2 (x, d522);
+ x = f2 (x, d523);
+ x = f2 (x, d524);
+ x = f2 (x, d525);
+ x = f2 (x, d526);
+ x = f2 (x, d527);
+ x = f2 (x, d528);
+ x = f2 (x, d529);
+ x = f2 (x, d530);
+ x = f2 (x, d531);
+ x = f2 (x, d532);
+ x = f2 (x, d533);
+ x = f2 (x, d534);
+ x = f2 (x, d535);
+ x = f2 (x, d536);
+ x = f2 (x, d537);
+ x = f2 (x, d538);
+ x = f2 (x, d539);
+ x = f2 (x, d540);
+ x = f2 (x, d541);
+ x = f2 (x, d542);
+ x = f2 (x, d543);
+ x = f2 (x, d544);
+ x = f2 (x, d545);
+ x = f2 (x, d546);
+ x = f2 (x, d547);
+ x = f2 (x, d548);
+ x = f2 (x, d549);
+ x = f2 (x, d550);
+ x = f2 (x, d551);
+ x = f2 (x, d552);
+ x = f2 (x, d553);
+ x = f2 (x, d554);
+ x = f2 (x, d555);
+ x = f2 (x, d556);
+ x = f2 (x, d557);
+ x = f2 (x, d558);
+ x = f2 (x, d559);
+ x = f2 (x, d560);
+ x = f2 (x, d561);
+ x = f2 (x, d562);
+ x = f2 (x, d563);
+ x = f2 (x, d564);
+ x = f2 (x, d565);
+ x = f2 (x, d566);
+ x = f2 (x, d567);
+ x = f2 (x, d568);
+ x = f2 (x, d569);
+ x = f2 (x, d570);
+ x = f2 (x, d571);
+ x = f2 (x, d572);
+ x = f2 (x, d573);
+ x = f2 (x, d574);
+ x = f2 (x, d575);
+ x = f2 (x, d576);
+ x = f2 (x, d577);
+ x = f2 (x, d578);
+ x = f2 (x, d579);
+ x = f2 (x, d580);
+ x = f2 (x, d581);
+ x = f2 (x, d582);
+ x = f2 (x, d583);
+ x = f2 (x, d584);
+ x = f2 (x, d585);
+ x = f2 (x, d586);
+ x = f2 (x, d587);
+ x = f2 (x, d588);
+ x = f2 (x, d589);
+ x = f2 (x, d590);
+ x = f2 (x, d591);
+ x = f2 (x, d592);
+ x = f2 (x, d593);
+ x = f2 (x, d594);
+ x = f2 (x, d595);
+ x = f2 (x, d596);
+ x = f2 (x, d597);
+ x = f2 (x, d598);
+ x = f2 (x, d599);
+ x = f2 (x, d600);
+ x = f2 (x, d601);
+ x = f2 (x, d602);
+ x = f2 (x, d603);
+ x = f2 (x, d604);
+ x = f2 (x, d605);
+ x = f2 (x, d606);
+ x = f2 (x, d607);
+ x = f2 (x, d608);
+ x = f2 (x, d609);
+ x = f2 (x, d610);
+ x = f2 (x, d611);
+ x = f2 (x, d612);
+ x = f2 (x, d613);
+ x = f2 (x, d614);
+ x = f2 (x, d615);
+ x = f2 (x, d616);
+ x = f2 (x, d617);
+ x = f2 (x, d618);
+ x = f2 (x, d619);
+ x = f2 (x, d620);
+ x = f2 (x, d621);
+ x = f2 (x, d622);
+ x = f2 (x, d623);
+ x = f2 (x, d624);
+ x = f2 (x, d625);
+ x = f2 (x, d626);
+ x = f2 (x, d627);
+ x = f2 (x, d628);
+ x = f2 (x, d629);
+ x = f2 (x, d630);
+ x = f2 (x, d631);
+ x = f2 (x, d632);
+ x = f2 (x, d633);
+ x = f2 (x, d634);
+ x = f2 (x, d635);
+ x = f2 (x, d636);
+ x = f2 (x, d637);
+ x = f2 (x, d638);
+ x = f2 (x, d639);
+ x = f2 (x, d640);
+ x = f2 (x, d641);
+ x = f2 (x, d642);
+ x = f2 (x, d643);
+ x = f2 (x, d644);
+ x = f2 (x, d645);
+ x = f2 (x, d646);
+ x = f2 (x, d647);
+ x = f2 (x, d648);
+ x = f2 (x, d649);
+ x = f2 (x, d650);
+ x = f2 (x, d651);
+ x = f2 (x, d652);
+ x = f2 (x, d653);
+ x = f2 (x, d654);
+ x = f2 (x, d655);
+ x = f2 (x, d656);
+ x = f2 (x, d657);
+ x = f2 (x, d658);
+ x = f2 (x, d659);
+ x = f2 (x, d660);
+ x = f2 (x, d661);
+ x = f2 (x, d662);
+ x = f2 (x, d663);
+ x = f2 (x, d664);
+ x = f2 (x, d665);
+ x = f2 (x, d666);
+ x = f2 (x, d667);
+ x = f2 (x, d668);
+ x = f2 (x, d669);
+ x = f2 (x, d670);
+ x = f2 (x, d671);
+ x = f2 (x, d672);
+ x = f2 (x, d673);
+ x = f2 (x, d674);
+ x = f2 (x, d675);
+ x = f2 (x, d676);
+ x = f2 (x, d677);
+ x = f2 (x, d678);
+ x = f2 (x, d679);
+ x = f2 (x, d680);
+ x = f2 (x, d681);
+ x = f2 (x, d682);
+ x = f2 (x, d683);
+ x = f2 (x, d684);
+ x = f2 (x, d685);
+ x = f2 (x, d686);
+ x = f2 (x, d687);
+ x = f2 (x, d688);
+ x = f2 (x, d689);
+ x = f2 (x, d690);
+ x = f2 (x, d691);
+ x = f2 (x, d692);
+ x = f2 (x, d693);
+ x = f2 (x, d694);
+ x = f2 (x, d695);
+ x = f2 (x, d696);
+ x = f2 (x, d697);
+ x = f2 (x, d698);
+ x = f2 (x, d699);
+ x = f2 (x, d700);
+ x = f2 (x, d701);
+ x = f2 (x, d702);
+ x = f2 (x, d703);
+ x = f2 (x, d704);
+ x = f2 (x, d705);
+ x = f2 (x, d706);
+ x = f2 (x, d707);
+ x = f2 (x, d708);
+ x = f2 (x, d709);
+ x = f2 (x, d710);
+ x = f2 (x, d711);
+ x = f2 (x, d712);
+ x = f2 (x, d713);
+ x = f2 (x, d714);
+ x = f2 (x, d715);
+ x = f2 (x, d716);
+ x = f2 (x, d717);
+ x = f2 (x, d718);
+ x = f2 (x, d719);
+ x = f2 (x, d720);
+ x = f2 (x, d721);
+ x = f2 (x, d722);
+ x = f2 (x, d723);
+ x = f2 (x, d724);
+ x = f2 (x, d725);
+ x = f2 (x, d726);
+ x = f2 (x, d727);
+ x = f2 (x, d728);
+ x = f2 (x, d729);
+ x = f2 (x, d730);
+ x = f2 (x, d731);
+ x = f2 (x, d732);
+ x = f2 (x, d733);
+ x = f2 (x, d734);
+ x = f2 (x, d735);
+ x = f2 (x, d736);
+ x = f2 (x, d737);
+ x = f2 (x, d738);
+ x = f2 (x, d739);
+ x = f2 (x, d740);
+ x = f2 (x, d741);
+ x = f2 (x, d742);
+ x = f2 (x, d743);
+ x = f2 (x, d744);
+ x = f2 (x, d745);
+ x = f2 (x, d746);
+ x = f2 (x, d747);
+ x = f2 (x, d748);
+ x = f2 (x, d749);
+ x = f2 (x, d750);
+ x = f2 (x, d751);
+ x = f2 (x, d752);
+ x = f2 (x, d753);
+ x = f2 (x, d754);
+ x = f2 (x, d755);
+ x = f2 (x, d756);
+ x = f2 (x, d757);
+ x = f2 (x, d758);
+ x = f2 (x, d759);
+ x = f2 (x, d760);
+ x = f2 (x, d761);
+ x = f2 (x, d762);
+ x = f2 (x, d763);
+ x = f2 (x, d764);
+ x = f2 (x, d765);
+ x = f2 (x, d766);
+ x = f2 (x, d767);
+ x = f2 (x, d768);
+ x = f2 (x, d769);
+ x = f2 (x, d770);
+ x = f2 (x, d771);
+ x = f2 (x, d772);
+ x = f2 (x, d773);
+ x = f2 (x, d774);
+ x = f2 (x, d775);
+ x = f2 (x, d776);
+ x = f2 (x, d777);
+ x = f2 (x, d778);
+ x = f2 (x, d779);
+ x = f2 (x, d780);
+ x = f2 (x, d781);
+ x = f2 (x, d782);
+ x = f2 (x, d783);
+ x = f2 (x, d784);
+ x = f2 (x, d785);
+ x = f2 (x, d786);
+ x = f2 (x, d787);
+ x = f2 (x, d788);
+ x = f2 (x, d789);
+ x = f2 (x, d790);
+ x = f2 (x, d791);
+ x = f2 (x, d792);
+ x = f2 (x, d793);
+ x = f2 (x, d794);
+ x = f2 (x, d795);
+ x = f2 (x, d796);
+ x = f2 (x, d797);
+ x = f2 (x, d798);
+ x = f2 (x, d799);
+ x = f2 (x, d800);
+ x = f2 (x, d801);
+ x = f2 (x, d802);
+ x = f2 (x, d803);
+ x = f2 (x, d804);
+ x = f2 (x, d805);
+ x = f2 (x, d806);
+ x = f2 (x, d807);
+ x = f2 (x, d808);
+ x = f2 (x, d809);
+ x = f2 (x, d810);
+ x = f2 (x, d811);
+ x = f2 (x, d812);
+ x = f2 (x, d813);
+ x = f2 (x, d814);
+ x = f2 (x, d815);
+ x = f2 (x, d816);
+ x = f2 (x, d817);
+ x = f2 (x, d818);
+ x = f2 (x, d819);
+ x = f2 (x, d820);
+ x = f2 (x, d821);
+ x = f2 (x, d822);
+ x = f2 (x, d823);
+ x = f2 (x, d824);
+ x = f2 (x, d825);
+ x = f2 (x, d826);
+ x = f2 (x, d827);
+ x = f2 (x, d828);
+ x = f2 (x, d829);
+ x = f2 (x, d830);
+ x = f2 (x, d831);
+ x = f2 (x, d832);
+ x = f2 (x, d833);
+ x = f2 (x, d834);
+ x = f2 (x, d835);
+ x = f2 (x, d836);
+ x = f2 (x, d837);
+ x = f2 (x, d838);
+ x = f2 (x, d839);
+ x = f2 (x, d840);
+ x = f2 (x, d841);
+ x = f2 (x, d842);
+ x = f2 (x, d843);
+ x = f2 (x, d844);
+ x = f2 (x, d845);
+ x = f2 (x, d846);
+ x = f2 (x, d847);
+ x = f2 (x, d848);
+ x = f2 (x, d849);
+ x = f2 (x, d850);
+ x = f2 (x, d851);
+ x = f2 (x, d852);
+ x = f2 (x, d853);
+ x = f2 (x, d854);
+ x = f2 (x, d855);
+ x = f2 (x, d856);
+ x = f2 (x, d857);
+ x = f2 (x, d858);
+ x = f2 (x, d859);
+ x = f2 (x, d860);
+ x = f2 (x, d861);
+ x = f2 (x, d862);
+ x = f2 (x, d863);
+ x = f2 (x, d864);
+ x = f2 (x, d865);
+ x = f2 (x, d866);
+ x = f2 (x, d867);
+ x = f2 (x, d868);
+ x = f2 (x, d869);
+ x = f2 (x, d870);
+ x = f2 (x, d871);
+ x = f2 (x, d872);
+ x = f2 (x, d873);
+ x = f2 (x, d874);
+ x = f2 (x, d875);
+ x = f2 (x, d876);
+ x = f2 (x, d877);
+ x = f2 (x, d878);
+ x = f2 (x, d879);
+ x = f2 (x, d880);
+ x = f2 (x, d881);
+ x = f2 (x, d882);
+ x = f2 (x, d883);
+ x = f2 (x, d884);
+ x = f2 (x, d885);
+ x = f2 (x, d886);
+ x = f2 (x, d887);
+ x = f2 (x, d888);
+ x = f2 (x, d889);
+ x = f2 (x, d890);
+ x = f2 (x, d891);
+ x = f2 (x, d892);
+ x = f2 (x, d893);
+ x = f2 (x, d894);
+ x = f2 (x, d895);
+ x = f2 (x, d896);
+ x = f2 (x, d897);
+ x = f2 (x, d898);
+ x = f2 (x, d899);
+ x = f2 (x, d900);
+ x = f2 (x, d901);
+ x = f2 (x, d902);
+ x = f2 (x, d903);
+ x = f2 (x, d904);
+ x = f2 (x, d905);
+ x = f2 (x, d906);
+ x = f2 (x, d907);
+ x = f2 (x, d908);
+ x = f2 (x, d909);
+ x = f2 (x, d910);
+ x = f2 (x, d911);
+ x = f2 (x, d912);
+ x = f2 (x, d913);
+ x = f2 (x, d914);
+ x = f2 (x, d915);
+ x = f2 (x, d916);
+ x = f2 (x, d917);
+ x = f2 (x, d918);
+ x = f2 (x, d919);
+ x = f2 (x, d920);
+ x = f2 (x, d921);
+ x = f2 (x, d922);
+ x = f2 (x, d923);
+ x = f2 (x, d924);
+ x = f2 (x, d925);
+ x = f2 (x, d926);
+ x = f2 (x, d927);
+ x = f2 (x, d928);
+ x = f2 (x, d929);
+ x = f2 (x, d930);
+ x = f2 (x, d931);
+ x = f2 (x, d932);
+ x = f2 (x, d933);
+ x = f2 (x, d934);
+ x = f2 (x, d935);
+ x = f2 (x, d936);
+ x = f2 (x, d937);
+ x = f2 (x, d938);
+ x = f2 (x, d939);
+ x = f2 (x, d940);
+ x = f2 (x, d941);
+ x = f2 (x, d942);
+ x = f2 (x, d943);
+ x = f2 (x, d944);
+ x = f2 (x, d945);
+ x = f2 (x, d946);
+ x = f2 (x, d947);
+ x = f2 (x, d948);
+ x = f2 (x, d949);
+ x = f2 (x, d950);
+ x = f2 (x, d951);
+ x = f2 (x, d952);
+ x = f2 (x, d953);
+ x = f2 (x, d954);
+ x = f2 (x, d955);
+ x = f2 (x, d956);
+ x = f2 (x, d957);
+ x = f2 (x, d958);
+ x = f2 (x, d959);
+ x = f2 (x, d960);
+ x = f2 (x, d961);
+ x = f2 (x, d962);
+ x = f2 (x, d963);
+ x = f2 (x, d964);
+ x = f2 (x, d965);
+ x = f2 (x, d966);
+ x = f2 (x, d967);
+ x = f2 (x, d968);
+ x = f2 (x, d969);
+ x = f2 (x, d970);
+ x = f2 (x, d971);
+ x = f2 (x, d972);
+ x = f2 (x, d973);
+ x = f2 (x, d974);
+ x = f2 (x, d975);
+ x = f2 (x, d976);
+ x = f2 (x, d977);
+ x = f2 (x, d978);
+ x = f2 (x, d979);
+ x = f2 (x, d980);
+ x = f2 (x, d981);
+ x = f2 (x, d982);
+ x = f2 (x, d983);
+ x = f2 (x, d984);
+ x = f2 (x, d985);
+ x = f2 (x, d986);
+ x = f2 (x, d987);
+ x = f2 (x, d988);
+ x = f2 (x, d989);
+ x = f2 (x, d990);
+ x = f2 (x, d991);
+ x = f2 (x, d992);
+ x = f2 (x, d993);
+ x = f2 (x, d994);
+ x = f2 (x, d995);
+ x = f2 (x, d996);
+ x = f2 (x, d997);
+ x = f2 (x, d998);
+ x = f2 (x, d999);
+ return x;
+}
+
+/* { dg-final { scan-rtl-dump-times "Stack clash inline probes" 1 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash residual allocation in prologue" 1 "pro_and_epilogue" } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash not noreturn" 1 "pro_and_epilogue" } } */
+
+/* f3 is not a leaf
+/* { dg-final { scan-rtl-dump-times "Stack clash no frame pointer needed" 1 "pro_and_epilogue" { target { ! frame_pointer_for_non_leaf } } } } */
+/* { dg-final { scan-rtl-dump-times "Stack clash frame pointer needed" 1 "pro_and_epilogue" { target { frame_pointer_for_non_leaf } } } } */
diff --git a/gcc/testsuite/gcc.dg/store_merging_9.c b/gcc/testsuite/gcc.dg/store_merging_9.c
new file mode 100644
index 0000000..4c9f21e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/store_merging_9.c
@@ -0,0 +1,33 @@
+/* PR tree-optimization/82434 */
+/* { dg-do compile } */
+/* { dg-require-effective-target store_merge } */
+/* { dg-options "-O2 -fdump-tree-store-merging" } */
+
+enum E { E0, E1, E2 = __INT_MAX__, E3 = -__INT_MAX__ - 1 };
+
+struct bar {
+ enum E a;
+ char b;
+ _Bool c;
+ short d;
+};
+
+void
+foo1 (struct bar *p)
+{
+ p->b = 0;
+ p->a = E0;
+ p->c = (_Bool) 0;
+ p->d = 0;
+}
+
+void
+foo2 (struct bar *p)
+{
+ p->b = 0;
+ p->a = E0;
+ p->c = (_Bool) 1;
+ p->d = 0;
+}
+
+/* { dg-final { scan-tree-dump-times "Merging successful" 2 "store-merging" } } */
diff --git a/gcc/testsuite/gcc.dg/torture/pr52451.c b/gcc/testsuite/gcc.dg/torture/pr52451.c
new file mode 100644
index 0000000..81a3d4d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr52451.c
@@ -0,0 +1,55 @@
+/* { dg-do run } */
+/* { dg-add-options ieee } */
+/* { dg-require-effective-target fenv_exceptions } */
+
+#include <fenv.h>
+
+#define TEST_C_NOEX(CMP, S) \
+ r = nan##S CMP arg##S; \
+ if (fetestexcept (FE_INVALID)) \
+ __builtin_abort ()
+
+#define TEST_B_NOEX(FN, S) \
+ r = __builtin_##FN (nan##S, arg##S); \
+ if (fetestexcept (FE_INVALID)) \
+ __builtin_abort ()
+
+#define TEST_C_EX(CMP, S) \
+ r = nan##S CMP arg##S; \
+ if (!fetestexcept (FE_INVALID)) \
+ __builtin_abort (); \
+ feclearexcept (FE_INVALID)
+
+#define TEST(TYPE, S) \
+ volatile TYPE nan##S = __builtin_nan##S (""); \
+ volatile TYPE arg##S = 1.0##S; \
+ \
+ TEST_C_NOEX (==, S); \
+ TEST_C_NOEX (!=, S); \
+ \
+ TEST_B_NOEX (isgreater, S); \
+ TEST_B_NOEX (isless, S); \
+ TEST_B_NOEX (isgreaterequal, S); \
+ TEST_B_NOEX (islessequal, S); \
+ \
+ TEST_B_NOEX (islessgreater, S); \
+ TEST_B_NOEX (isunordered, S); \
+ \
+ TEST_C_EX (>, S); \
+ TEST_C_EX (<, S); \
+ TEST_C_EX (>=, S); \
+ TEST_C_EX (<=, S)
+
+int
+main (void)
+{
+ volatile int r;
+
+ feclearexcept (FE_INVALID);
+
+ TEST (float, f);
+ TEST (double, );
+ TEST (long double, l);
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82129.c b/gcc/testsuite/gcc.dg/torture/pr82129.c
new file mode 100644
index 0000000..b116149
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82129.c
@@ -0,0 +1,52 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-ftree-pre" } */
+
+int pj;
+
+void
+g4 (unsigned long int *bc, unsigned long int *h5)
+{
+ if (pj != 0)
+ {
+ int ib = 0;
+
+ while (bc != 0)
+ {
+m6:
+ for (pj = 0; pj < 2; ++pj)
+ pj = 0;
+
+ while (pj != 0)
+ {
+ for (;;)
+ {
+ }
+
+ while (ib != 0)
+ {
+ unsigned long int tv = *bc;
+ unsigned long int n7;
+
+ *bc = 1;
+ while (*bc != 0)
+ {
+ }
+
+ut:
+ if (pj == 0)
+ n7 = *h5 > 0;
+ else
+ {
+ *h5 = tv;
+ n7 = *h5;
+ }
+ ib += n7;
+ }
+ }
+ }
+
+ goto ut;
+ }
+
+ goto m6;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82264.c b/gcc/testsuite/gcc.dg/torture/pr82264.c
new file mode 100644
index 0000000..2bc0367
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82264.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+
+char a;
+int c;
+unsigned b ();
+unsigned
+setjmp ()
+{
+}
+static void
+d ()
+{
+ if (b ())
+ c = 3;
+}
+void
+e ()
+{
+ d ();
+ a && ({ setjmp (); });
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82276.c b/gcc/testsuite/gcc.dg/torture/pr82276.c
new file mode 100644
index 0000000..2f9efc8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82276.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+
+typedef struct a {
+ struct a *b;
+} a;
+
+extern int d(void);
+extern int g(void);
+extern int h(void);
+extern int _setjmp();
+extern int i(void);
+
+void c(void) {
+ 1 ? d() : 0;
+ a *e;
+ while (e) {
+ e = (e == (a *) c) ? 0 : e->b;
+ while (e) {
+ unsigned int f = 0;
+ g();
+ _setjmp(f);
+ if (f & 6) {
+ ;
+ } else if (f & 2) {
+ ;
+ } else {
+ h();
+ }
+ i();
+ }
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82285.c b/gcc/testsuite/gcc.dg/torture/pr82285.c
new file mode 100644
index 0000000..6edc750
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82285.c
@@ -0,0 +1,16 @@
+/* { dg-do run } */
+
+enum tst { first = 0, second = 1 };
+
+int
+main ()
+{
+ enum tst data[16];
+
+ for (unsigned i = 0; i < 16; i++)
+ data[i] = (i < 5 ? second : first);
+
+ if (data[2] != second)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82291.c b/gcc/testsuite/gcc.dg/torture/pr82291.c
new file mode 100644
index 0000000..daa1665
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82291.c
@@ -0,0 +1,37 @@
+/* { dg-do run } */
+
+int a, c, d, *h;
+unsigned b;
+
+int *fn1 ()
+{
+ int *f[3], g = 0;
+ for (; g < 3; g++)
+ f[g] = &a;
+ if (--b > a)
+ {
+ if (a > b)
+ d++;
+ return f[0];
+ }
+}
+
+void fn2 ()
+{
+ for (; c >= 0; --c)
+ {
+ int j[] = { 0, 0, 0, 0, 0 };
+ int *k = fn1 ();
+ if (!k)
+ __builtin_abort ();
+ h = &j[4];
+ }
+}
+
+int main ()
+{
+ fn2 ();
+ if (d != 0)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82320.c b/gcc/testsuite/gcc.dg/torture/pr82320.c
new file mode 100644
index 0000000..a4943fc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82320.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+
+void
+ec (int n4, short int ea)
+{
+ if (1)
+ {
+ if (ea != 0)
+ {
+ int *c1 = (int *)&ea;
+
+nn:
+ for (;;)
+ ++*c1;
+ }
+ }
+ else
+ {
+ int *lq = &n4;
+ int *md;
+ int da;
+
+ goto nn;
+
+r1:
+ md = lq;
+ for (da = 0; da < 1; ++da)
+ {
+ig:
+ ++n4;
+ *md += n4;
+ }
+ }
+
+ for (ea = 0; ea < 1; ++ea)
+ goto r1;
+
+ goto ig;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82473.c b/gcc/testsuite/gcc.dg/torture/pr82473.c
new file mode 100644
index 0000000..b12de21
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82473.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-ftree-vectorize" } */
+
+void
+zz (int x9, short int gt)
+{
+ if (0)
+ {
+ while (gt < 1)
+ {
+ int pz;
+
+k6:
+ for (pz = 0; pz < 3; ++pz)
+ x9 += gt;
+ ++gt;
+ }
+ }
+
+ if (x9 != 0)
+ goto k6;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82603.c b/gcc/testsuite/gcc.dg/torture/pr82603.c
new file mode 100644
index 0000000..960a48b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82603.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-ftree-loop-vectorize" } */
+
+int
+mr (unsigned int lf, int ms)
+{
+ unsigned int sw = 0;
+ char *cu = (char *)&ms;
+
+ while (ms < 1)
+ {
+ if (lf == 0)
+ ms = 0;
+ else
+ ms = 0;
+ ms += ((lf > 0) && ((lf > sw) ? 1 : ++*cu));
+ }
+
+ if (lf != 0)
+ cu = (char *)&sw;
+ *cu = lf;
+
+ return ms;
+}
diff --git a/gcc/testsuite/gcc.dg/torture/pr82697.c b/gcc/testsuite/gcc.dg/torture/pr82697.c
new file mode 100644
index 0000000..57da8a2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr82697.c
@@ -0,0 +1,23 @@
+/* { dg-do run } */
+
+__attribute__((noinline,noclone))
+void test(int *pi, long *pl, int f)
+{
+ *pl = 0;
+
+ *pi = 1;
+
+ if (f)
+ *pl = 2;
+}
+
+int main()
+{
+ void *p = __builtin_malloc(sizeof (long));
+
+ test(p, p, 0);
+
+ if (*(int *)p != 1)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-prof/comp-goto-1.c b/gcc/testsuite/gcc.dg/tree-prof/comp-goto-1.c
index fe768f9..baed1e3 100644
--- a/gcc/testsuite/gcc.dg/tree-prof/comp-goto-1.c
+++ b/gcc/testsuite/gcc.dg/tree-prof/comp-goto-1.c
@@ -1,11 +1,11 @@
/* { dg-require-effective-target freorder } */
/* { dg-require-effective-target label_values } */
/* { dg-options "-O2 -freorder-blocks-and-partition" } */
-/* { dg-add-options stack_size } */
+/* { dg-require-stack-size "4000" } */
#include <stdlib.h>
-#if (!defined(STACK_SIZE) || STACK_SIZE >= 4000) && __INT_MAX__ >= 2147483647
+#if __INT_MAX__ >= 2147483647
typedef unsigned int uint32;
typedef signed int sint32;
diff --git a/gcc/testsuite/gcc.dg/tree-prof/switch-case-2.c b/gcc/testsuite/gcc.dg/tree-prof/switch-case-2.c
index cfedc9c..9b0dfc2 100644
--- a/gcc/testsuite/gcc.dg/tree-prof/switch-case-2.c
+++ b/gcc/testsuite/gcc.dg/tree-prof/switch-case-2.c
@@ -1,4 +1,4 @@
-/* { dg-options "-O2 -fdump-rtl-expand-all" } */
+/* { dg-options "-O2 -fdump-ipa-profile-all" } */
int g;
__attribute__((noinline)) void foo (int n)
@@ -36,5 +36,5 @@ int main ()
return 0;
}
/* autofdo cannot do that precise execution numbers: */
-/* { dg-final-use-not-autofdo { scan-rtl-dump-times ";; basic block\[^\\n\]*count 4000" 2 "expand"} } */
-/* { dg-final-use-not-autofdo { scan-rtl-dump-times ";; basic block\[^\\n\]*count 2000" 1 "expand"} } */
+/* { dg-final-use-not-autofdo { scan-ipa-dump-times ";; basic block\[^\\n\]*count 4000" 2 "profile"} } */
+/* { dg-final-use-not-autofdo { scan-ipa-dump-times ";; basic block\[^\\n\]*count 2000" 1 "profile"} } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/cmpdiv.c b/gcc/testsuite/gcc.dg/tree-ssa/cmpdiv.c
new file mode 100644
index 0000000..14161f5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/cmpdiv.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-optimized-raw" } */
+
+_Bool f1(unsigned x, unsigned y)
+{
+ unsigned t1 = x / y;
+ _Bool t2 = (t1 != 0);
+ return t2;
+}
+
+_Bool f2(unsigned x, unsigned y)
+{
+ unsigned t1 = x / y;
+ _Bool t2 = (t1 == 0);
+ return t2;
+}
+
+/* { dg-final { scan-tree-dump-not "trunc_div_expr" "optimized" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-16.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-16.c
index f43b64e..f4f3a44 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ldist-16.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-16.c
@@ -16,5 +16,5 @@ void foo (int n)
/* We should not apply loop distribution and not generate a memset (0). */
-/* { dg-final { scan-tree-dump "Loop 1 is the same" "ldist" } } */
+/* { dg-final { scan-tree-dump "Loop 1 not distributed" "ldist" } } */
/* { dg-final { scan-tree-dump-times "generated memset zero" 0 "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-17.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-17.c
index 4efc0a4..b3617f6 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ldist-17.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-17.c
@@ -45,5 +45,5 @@ mad_synth_mute (struct mad_synth *synth)
return;
}
-/* { dg-final { scan-tree-dump "distributed: split to 0 loops and 4 library calls" "ldist" } } */
-/* { dg-final { scan-tree-dump-times "generated memset zero" 4 "ldist" } } */
+/* { dg-final { scan-tree-dump "Loop nest . distributed: split to 0 loops and 1 library calls" "ldist" } } */
+/* { dg-final { scan-tree-dump-times "generated memset zero" 1 "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-25.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-25.c
index 699bf38..c0b95fc 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ldist-25.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-25.c
@@ -22,4 +22,4 @@ foo (void)
}
}
-/* { dg-final { scan-tree-dump "Loop . is the same" "ldist" } } */
+/* { dg-final { scan-tree-dump "Loop . not distributed" "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-27.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-27.c
new file mode 100644
index 0000000..b1fd024
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-27.c
@@ -0,0 +1,41 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define M (300)
+#define N (200)
+
+struct st
+{
+ double a[M];
+ double b[M];
+ double c[M][N];
+};
+
+int __attribute__ ((noinline))
+foo (struct st *s)
+{
+ int i, j;
+ for (i = 0; i != M;)
+ {
+ s->a[i] = 0.0;
+ s->b[i] = 1.0;
+ for (j = 0; 1; ++j)
+ {
+ if (j == N) goto L2;
+ s->c[i][j] = 0.0;
+ }
+L2:
+ ++i;
+ }
+ return 0;
+}
+
+struct st s;
+
+int
+main (void)
+{
+ return foo (&s);
+}
+
+/* { dg-final { scan-tree-dump "distributed: split to " "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-28.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-28.c
new file mode 100644
index 0000000..4420139
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-28.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define M (256)
+#define N (1024)
+int arr[M][N];
+
+void
+foo (void)
+{
+ for (unsigned i = 0; i < M; ++i)
+ for (unsigned j = 0; j < N; ++j)
+ arr[i][j] = 0;
+}
+
+/* { dg-final { scan-tree-dump "Loop nest . distributed: split to 0 loops and 1 library" "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-29.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-29.c
new file mode 100644
index 0000000..9ce93e8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-29.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define M (256)
+#define N (512)
+int arr[M][N];
+
+void
+foo (void)
+{
+ for (unsigned i = 0; i < M; ++i)
+ for (unsigned j = 0; j < N - 1; ++j)
+ arr[i][j] = 0;
+}
+
+/* { dg-final { scan-tree-dump-not "Loop nest . distributed: split to" "ldist" } } */
+/* { dg-final { scan-tree-dump-times "Loop . distributed: split to 0 loops and 1 library" 1 "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-30.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-30.c
new file mode 100644
index 0000000..f31860a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-30.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define M (256)
+#define N (512)
+int a[M][N], b[M][N];
+
+void
+foo (void)
+{
+ for (unsigned i = 0; i < M; ++i)
+ for (unsigned j = N; j > 0; --j)
+ a[i][j - 1] = b[i][j - 1];
+}
+
+/* { dg-final { scan-tree-dump-times "Loop nest . distributed: split to" 1 "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-31.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-31.c
new file mode 100644
index 0000000..60a9f74
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-31.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define M (256)
+#define N (512)
+int a[M][N], b[M][N], c[M];
+
+void
+foo (void)
+{
+ for (int i = M - 1; i >= 0; --i)
+ {
+ c[i] = 0;
+ for (unsigned j = N; j > 0; --j)
+ a[i][j - 1] = b[i][j - 1];
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Loop nest . distributed: split to 0 loops and 2 library" 1 "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-32.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-32.c
new file mode 100644
index 0000000..477d222
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-32.c
@@ -0,0 +1,29 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define M (256)
+#define N (512)
+
+struct st
+{
+ int a[M][N];
+ int c[M];
+ int b[M][N];
+};
+
+void
+foo (struct st *p)
+{
+ for (unsigned i = 0; i < M; ++i)
+ {
+ p->c[i] = 0;
+ for (unsigned j = N; j > 0; --j)
+ {
+ p->a[i][j - 1] = 0;
+ p->b[i][j - 1] = 0;
+ }
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Loop nest . distributed: split to 0 loops and 1 library" 1 "ldist" } } */
+/* { dg-final { scan-tree-dump-times "__builtin_memset \\(.*, 0, 1049600\\);" 1 "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-33.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-33.c
new file mode 100644
index 0000000..24d27fd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-33.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define N (1024)
+double a[N][N], b[N][N], c[N][N];
+
+void
+foo (void)
+{
+ unsigned i, j, k;
+
+ for (i = 0; i < N; ++i)
+ for (j = 0; j < N; ++j)
+ {
+ c[i][j] = 0.0;
+ for (k = 0; k < N; ++k)
+ c[i][j] += a[i][k] * b[k][j];
+ }
+}
+
+/* { dg-final { scan-tree-dump "Loop nest . distributed: split to 1 loops and 1 library" "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-34.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-34.c
new file mode 100644
index 0000000..3d68a85
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-34.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution" } */
+
+#define X (3.0)
+int b, c;
+double a[30000];
+int foo () {
+ for (int i = 0; i < 100; ++i) {
+ for (int j = 0; j < c; ++j)
+ if (b)
+ a[0] = b;
+ a[i * 100] = a[1] = X;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-35.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-35.c
new file mode 100644
index 0000000..445d23d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-35.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define M (256)
+#define N (512)
+
+struct st
+{
+ int a[M][N];
+ int c[M];
+ int b[M][N];
+};
+
+void
+foo (struct st * restrict p, struct st * restrict q)
+{
+ for (unsigned i = 0; i < M; ++i)
+ {
+ p->c[i] = 0;
+ for (unsigned j = N; j > 0; --j)
+ {
+ p->a[i][j - 1] = q->a[i][j - 1];
+ p->b[i][j - 1] = 0;
+ }
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Loop nest . distributed: split to 0 loops and 1 library" 1 "ldist" { xfail *-*-* } } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-36.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-36.c
new file mode 100644
index 0000000..0e843f4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-36.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution -ftree-loop-distribute-patterns -fdump-tree-ldist-details" } */
+
+#define M (256)
+#define N (512)
+
+struct st
+{
+ int a[M][N];
+ int c[M];
+ int b[M][N];
+};
+
+void
+foo (struct st * restrict p)
+{
+ for (unsigned i = 0; i < M; ++i)
+ {
+ p->c[i] = 0;
+ for (unsigned j = N; j > 0; --j)
+ {
+ p->b[i][j - 1] = p->a[i][j - 1];
+ p->a[i][j - 1] = 0;
+ }
+ }
+}
+
+/* { dg-final { scan-tree-dump-times "Loop nest . distributed: split to 0 loops and 3 library" 1 "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ldist-7.c b/gcc/testsuite/gcc.dg/tree-ssa/ldist-7.c
index f31d051..2eb1f74 100644
--- a/gcc/testsuite/gcc.dg/tree-ssa/ldist-7.c
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ldist-7.c
@@ -28,4 +28,4 @@ int loop1 (int k)
return a[1000-2] + b[1000-1] + c[1000-2] + d[1000-2];
}
-/* { dg-final { scan-tree-dump-times "distributed" 0 "ldist" } } */
+/* { dg-final { scan-tree-dump-times "distributed: " 0 "ldist" } } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c b/gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c
new file mode 100644
index 0000000..ae7ee42
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/noreturn-1.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } *
+/* { dg-options "-O2 -fdump-tree-ssa -std=gnu11" } */
+/* { dg-final { scan-tree-dump-times "__builtin_unreachable" 4 "ssa" } } */
+
+void bar1 (void);
+void bar2 (void);
+void bar3 (void);
+void bar4 (void);
+
+_Noreturn void
+foo1 (int *p, int y)
+{
+ bar1 ();
+ *p = y;
+ return; /* { dg-warning "function declared 'noreturn' has a 'return' statement" } */
+} /* { dg-warning "'noreturn' function does return" "" { target *-*-* } .-1 } */
+
+_Noreturn void
+foo2 (int *p, int y)
+{
+ bar2 ();
+ *p = y;
+} /* { dg-warning "'noreturn' function does return" } */
+
+_Noreturn void
+foo3 (int *p, int y)
+{
+ if (y > 10)
+ return; /* { dg-warning "function declared 'noreturn' has a 'return' statement" } */
+ bar3 ();
+ *p = y;
+ return; /* { dg-warning "function declared 'noreturn' has a 'return' statement" } */
+} /* { dg-warning "'noreturn' function does return" } */
+
+_Noreturn void
+foo4 (int *p, int y)
+{
+ if (y > 10)
+ return; /* { dg-warning "function declared 'noreturn' has a 'return' statement" } */
+ bar4 ();
+ *p = y;
+} /* { dg-warning "'noreturn' function does return" } */
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr82163.c b/gcc/testsuite/gcc.dg/tree-ssa/pr82163.c
new file mode 100644
index 0000000..389d5c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr82163.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O3" } */
+
+int a, b, c[4], d, e, f, g;
+
+void h ()
+{
+ for (; a; a++)
+ {
+ c[a + 3] = g;
+ if (b)
+ c[a] = f;
+ else
+ {
+ for (; d; d++)
+ c[d + 3] = c[d];
+ for (e = 1; e == 2; e++)
+ ;
+ if (e)
+ break;
+ }
+ }
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr82340.c b/gcc/testsuite/gcc.dg/tree-ssa/pr82340.c
new file mode 100644
index 0000000..ad9f1cf
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr82340.c
@@ -0,0 +1,14 @@
+/* PR c/82340 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-ssa" } */
+/* { dg-final { scan-tree-dump "D.\[0-9]*\\\[0\\\] ={v} 77;" "ssa" } } */
+
+int
+foo (void)
+{
+ int i;
+ volatile char *p = (volatile char[1]) { 77 };
+ for (i = 1; i < 10; i++)
+ *p = 4;
+ return *p;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr82363.c b/gcc/testsuite/gcc.dg/tree-ssa/pr82363.c
new file mode 100644
index 0000000..6652468
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr82363.c
@@ -0,0 +1,50 @@
+/* { dg-do run } */
+/* { dg-options "-O" } */
+
+struct A
+{
+ int b;
+ int c;
+ int d;
+};
+
+struct E
+{
+ int f;
+ int g:18;
+ struct A h;
+};
+
+struct I
+{
+ int b;
+ int j;
+ struct E k;
+};
+
+int l, *m = &l;
+
+struct A n;
+struct I o;
+
+void __attribute__ ((noipa))
+test_l (void)
+{
+ if (l != 1)
+ __builtin_abort ();
+}
+
+int main ()
+{
+ while (1)
+ {
+ struct I q = { 0, 0, {0, 0, {1, 1, 1}}}, p = q, r = p, *s = &q;
+ if (p.k.h.c)
+ o = p;
+ *m = r.k.h.d;
+ n = (*s).k.h;
+ break;
+ }
+ test_l ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr82472.c b/gcc/testsuite/gcc.dg/tree-ssa/pr82472.c
new file mode 100644
index 0000000..445c95f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr82472.c
@@ -0,0 +1,24 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-loop-distribution" } */
+
+long int xj;
+
+int
+cx (long int *ox, short int mk, char tf)
+{
+ int si, f9;
+ char *p4 = &tf;
+ short int *rm = (tf != 0) ? (short int *)&f9 : &mk;
+
+ for (f9 = 0; f9 < 2; ++f9)
+ {
+ *rm = 0;
+ *p4 = *ox;
+ si = mk;
+ xj = 0;
+ while (p4 < (char *)rm)
+ ++p4;
+ }
+
+ return si;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr82498.c b/gcc/testsuite/gcc.dg/tree-ssa/pr82498.c
new file mode 100644
index 0000000..19a42f0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr82498.c
@@ -0,0 +1,53 @@
+/* PR target/82498 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-original" } */
+/* { dg-final { scan-tree-dump-times "x r<< y" 4 "original" { target int32 } } } */
+/* { dg-final { scan-tree-dump-times "x r>> y" 4 "original" { target int32 } } } */
+
+unsigned
+f1 (unsigned x, int y)
+{
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f2 (unsigned x, int y)
+{
+ return (x << y) | (x >> (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned
+f3 (unsigned x, int y)
+{
+ return (x >> y) | (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f4 (unsigned x, int y)
+{
+ return (x >> y) | (x << (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned
+f5 (unsigned x, int y)
+{
+ return (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y)) | (x << y);
+}
+
+unsigned
+f6 (unsigned x, int y)
+{
+ return (x >> (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x << y);
+}
+
+unsigned
+f7 (unsigned x, int y)
+{
+ return (x << (__CHAR_BIT__ * __SIZEOF_INT__ - y)) | (x >> y);
+}
+
+unsigned
+f8 (unsigned x, int y)
+{
+ return (x << (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1))) | (x >> y);
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr82574.c b/gcc/testsuite/gcc.dg/tree-ssa/pr82574.c
new file mode 100644
index 0000000..8fc4596
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/pr82574.c
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-options "-O3" } */
+
+unsigned char a, b, c, d[200][200];
+
+void abort (void);
+
+int main ()
+{
+ for (; a < 200; a++)
+ for (b = 0; b < 200; b++)
+ if (c)
+ d[a][b] = 1;
+
+ if ((c && d[0][0] != 1) || (!c && d[0][0] != 0))
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-1.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-1.c
new file mode 100644
index 0000000..23741b6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dom-simplify-1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -w -fdump-tree-dom2" } */
+
+extern void frob (void);
+extern void frob (void);
+
+void
+rhs_to_tree (int x, int z)
+{
+ if (x >= 4)
+ frob ();
+ if (x >= 3)
+ frob ();
+}
+
+/* The second conditional should change into a simple equality test. */
+/* { dg-final { scan-tree-dump-times "if \\(x_\[0-9\]+\\(D\\) == 3\\)" 1 "dom2"} } */
+
diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-26.c b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-26.c
new file mode 100644
index 0000000..a5638b5
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-dse-26.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-dse1-details -fno-short-enums" } */
+
+enum constraint_expr_type
+{
+ SCALAR, DEREF, ADDRESSOF
+};
+typedef struct constraint_expr
+{
+ enum constraint_expr_type type;
+ unsigned int var;
+ long offset;
+} constraint_expr ;
+typedef struct constraint
+{
+ struct constraint_expr lhs;
+ struct constraint_expr rhs;
+} constraint;
+static _Bool
+constraint_expr_equal (struct constraint_expr x, struct constraint_expr y)
+{
+ return x.type == y.type && x.var == y.var && x.offset == y.offset;
+}
+
+_Bool
+constraint_equal (struct constraint a, struct constraint b)
+{
+ return constraint_expr_equal (a.lhs, b.lhs)
+ && constraint_expr_equal (a.rhs, b.rhs);
+}
+
+/* { dg-final { scan-tree-dump-times "Deleted dead store" 2 "dse1" } } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c b/gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c
index 1626860..538d900 100644
--- a/gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c
+++ b/gcc/testsuite/gcc.dg/ubsan/float-cast-overflow-bf.c
@@ -48,25 +48,25 @@ main (void)
return 0;
}
-/* { dg-output "value -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
-/* { dg-output "\[^\n\r]*value 2.5 is outside the range of representable values of type" } */
+/* { dg-output " -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1.5 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* -1 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2 is outside the range of representable values of type\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]* 2.5 is outside the range of representable values of type" } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/pr82498.c b/gcc/testsuite/gcc.dg/ubsan/pr82498.c
new file mode 100644
index 0000000..1d093a0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/pr82498.c
@@ -0,0 +1,159 @@
+/* PR target/82498 */
+/* { dg-do run { target i?86-*-* x86_64-*-* } } */
+/* { dg-options "-fsanitize=undefined -fno-sanitize-recover=undefined" } */
+
+#include <x86intrin.h>
+
+volatile unsigned int a;
+volatile unsigned long long b;
+volatile int c;
+
+int
+main ()
+{
+ a = 0x12345678U;
+ a = __rold (a, 0);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ a = __rold (a, 32);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ a = __rold (a, -32);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ a = __rold (a, 37);
+ if (a != 0x468acf02U)
+ __builtin_abort ();
+ a = __rold (a, -5);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ a = __rord (a, 0);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ a = __rord (a, 32);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ a = __rord (a, -32);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ a = __rord (a, -37);
+ if (a != 0x468acf02U)
+ __builtin_abort ();
+ a = __rord (a, 5);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ c = 0;
+ a = __rold (a, c);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ c = 32;
+ a = __rold (a, c);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ c = -32;
+ a = __rold (a, c);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ c = 37;
+ a = __rold (a, c);
+ if (a != 0x468acf02U)
+ __builtin_abort ();
+ c = -5;
+ a = __rold (a, c);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ c = 0;
+ a = __rord (a, c);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ c = 32;
+ a = __rord (a, c);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ c = -32;
+ a = __rord (a, c);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+ c = -37;
+ a = __rord (a, c);
+ if (a != 0x468acf02U)
+ __builtin_abort ();
+ c = 5;
+ a = __rord (a, c);
+ if (a != 0x12345678U)
+ __builtin_abort ();
+#ifdef __x86_64__
+ b = 0x123456789abcdef1ULL;
+ b = __rolq (b, 0);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ b = __rolq (b, 64);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ b = __rolq (b, -64);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ b = __rolq (b, 69);
+ if (b != 0x468acf13579bde22ULL)
+ __builtin_abort ();
+ b = __rolq (b, -5);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ b = __rorq (b, 0);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ b = __rorq (b, 64);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ b = __rorq (b, -64);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ b = __rorq (b, -69);
+ if (b != 0x468acf13579bde22ULL)
+ __builtin_abort ();
+ b = __rorq (b, 5);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ c = 0;
+ b = __rolq (b, c);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ c = 64;
+ b = __rolq (b, c);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ c = -64;
+ b = __rolq (b, c);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ c = 69;
+ b = __rolq (b, c);
+ if (b != 0x468acf13579bde22ULL)
+ __builtin_abort ();
+ c = -5;
+ b = __rolq (b, c);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ c = 0;
+ b = __rorq (b, c);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ c = 64;
+ b = __rorq (b, c);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ c = -64;
+ b = __rorq (b, c);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+ c = -69;
+ b = __rorq (b, c);
+ if (b != 0x468acf13579bde22ULL)
+ __builtin_abort ();
+ c = 5;
+ b = __rorq (b, c);
+ if (b != 0x123456789abcdef1ULL)
+ __builtin_abort ();
+#endif
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/pr31699.c b/gcc/testsuite/gcc.dg/vect/pr31699.c
index 59b8daa..b0b9971 100644
--- a/gcc/testsuite/gcc.dg/vect/pr31699.c
+++ b/gcc/testsuite/gcc.dg/vect/pr31699.c
@@ -1,4 +1,4 @@
-/* { dg-require-effective-target vect_double } */
+/* { dg-require-effective-target vect_float } */
#include <stdlib.h>
#include <stdarg.h>
@@ -7,9 +7,9 @@
float x[256];
__attribute__ ((noinline))
-double *foo(void)
+float *foo(void)
{
- double *z = malloc (sizeof(double) * 256);
+ float *z = malloc (sizeof(float) * 256);
int i;
for (i=0; i<256; ++i)
diff --git a/gcc/testsuite/gcc.dg/vect/pr60656.c b/gcc/testsuite/gcc.dg/vect/pr60656.c
index d9e30bb..70ec0f6 100644
--- a/gcc/testsuite/gcc.dg/vect/pr60656.c
+++ b/gcc/testsuite/gcc.dg/vect/pr60656.c
@@ -43,4 +43,5 @@ int main()
return 0;
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_widen_mult_si_to_di_pattern } } } */
+/* P * P * P requires a widening multiplication first as well as a longxlong->long after that. */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { vect_widen_mult_si_to_di_pattern && vect_long_mult } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr61194.c b/gcc/testsuite/gcc.dg/vect/pr61194.c
index f7c71b9..8421367 100644
--- a/gcc/testsuite/gcc.dg/vect/pr61194.c
+++ b/gcc/testsuite/gcc.dg/vect/pr61194.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_cond_mixed } */
+/* { dg-require-effective-target vect_float } */
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-10.c b/gcc/testsuite/gcc.dg/vect/pr65947-10.c
index a8a674f..321cb8c 100644
--- a/gcc/testsuite/gcc.dg/vect/pr65947-10.c
+++ b/gcc/testsuite/gcc.dg/vect/pr65947-10.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_condition } */
+/* { dg-require-effective-target vect_float } */
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/pr65947-9.c b/gcc/testsuite/gcc.dg/vect/pr65947-9.c
index d769af9..e8f20aa 100644
--- a/gcc/testsuite/gcc.dg/vect/pr65947-9.c
+++ b/gcc/testsuite/gcc.dg/vect/pr65947-9.c
@@ -10,7 +10,7 @@ extern void abort (void) __attribute__ ((noreturn));
vectorize because the vectorisation requires a slot for default values. */
signed char __attribute__((noinline,noclone))
-condition_reduction (char *a, char min_v)
+condition_reduction (signed char *a, signed char min_v)
{
signed char last = -72;
diff --git a/gcc/testsuite/gcc.dg/vect/pr66142.c b/gcc/testsuite/gcc.dg/vect/pr66142.c
index 94854ea..8c79f29 100644
--- a/gcc/testsuite/gcc.dg/vect/pr66142.c
+++ b/gcc/testsuite/gcc.dg/vect/pr66142.c
@@ -41,4 +41,4 @@ foo (float *a, float *b, float *c)
*a = z;
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 1 "vect" { target vect_condition } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops in function" 1 "vect" { target { vect_condition && vect_float } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr66251.c b/gcc/testsuite/gcc.dg/vect/pr66251.c
index 7f0c4bc..26afbc9 100644
--- a/gcc/testsuite/gcc.dg/vect/pr66251.c
+++ b/gcc/testsuite/gcc.dg/vect/pr66251.c
@@ -1,7 +1,7 @@
/* { dg-require-effective-target vect_int } */
/* { dg-require-effective-target vect_double } */
-/* { dg-require-effective-target vect_floatint_cvt } */
-/* { dg-require-effective-target vect_intfloat_cvt } */
+/* { dg-require-effective-target vect_doubleint_cvt } */
+/* { dg-require-effective-target vect_intdouble_cvt } */
/* { dg-require-effective-target vect_pack_trunc } */
/* { dg-require-effective-target vect_unpack } */
/* { dg-require-effective-target vect_hw_misalign } */
diff --git a/gcc/testsuite/gcc.dg/vect/pr78558.c b/gcc/testsuite/gcc.dg/vect/pr78558.c
new file mode 100644
index 0000000..2606d4e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr78558.c
@@ -0,0 +1,44 @@
+/* PR tree-optimization/78558 */
+
+#include "tree-vect.h"
+
+struct S
+{
+ char p[48];
+ unsigned long long q, r, s;
+} s[50];
+
+struct D
+{
+ unsigned long long q, r;
+} d[50];
+
+void
+foo (void)
+{
+ unsigned long i;
+ for (i = 0; i < 50; ++i)
+ {
+ d[i].q = s[i].q;
+ d[i].r = s[i].r;
+ }
+}
+
+int
+main ()
+{
+ check_vect ();
+ unsigned long i;
+ for (i = 0; i < 50; ++i)
+ {
+ s[i].q = i;
+ s[i].r = 50 * i;
+ }
+ asm volatile ("" : : "g" (s), "g" (d) : "memory");
+ foo ();
+ asm volatile ("" : : "g" (s), "g" (d) : "memory");
+ for (i = 0; i < 50; ++i)
+ if (d[i].q != i || d[i].r != 50 * i)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/pr82289.c b/gcc/testsuite/gcc.dg/vect/pr82289.c
new file mode 100644
index 0000000..ae3001f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr82289.c
@@ -0,0 +1,28 @@
+/* { dg-do compile } */
+
+int a, b, c, *d, *f[1];
+
+void fn1 (int *j)
+{
+ int e, g, h = 1;
+ for (; e; e++)
+ {
+ if (g > 0)
+ {
+ d = j;
+ return;
+ }
+ if (!h)
+ while (g)
+ ;
+ while (h < 1)
+ if (a)
+ {
+ fn1 (&h);
+ h = 0;
+ }
+ f[e] = &c;
+ }
+ while (1)
+ ;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/pr82436.c b/gcc/testsuite/gcc.dg/vect/pr82436.c
new file mode 100644
index 0000000..4129e15
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr82436.c
@@ -0,0 +1,35 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-Ofast -fno-tree-scev-cprop" } */
+/* { dg-additional-options "-mavx2" { target { x86_64-*-* i?86-*-* } } } */
+
+struct reflection_type
+{
+ int h;
+ int k;
+ int l;
+ double f_exp;
+ double f_sigma;
+ _Complex double f_calc;
+ double f_pred;
+ double i_exp;
+ double i_sigma;
+ double i_pred;
+};
+
+double y, w;
+int foo (struct reflection_type *r, int n, unsigned s)
+{
+ int i;
+ y = 0;
+ w = 0;
+ for (i = 1; i < n; ++i)
+ {
+ struct reflection_type *x = &r[i*s];
+ double fpred = x->f_pred;
+ double fexp = x->f_exp;
+ double tem = (fpred - fexp);
+ y += __builtin_fabs (tem / x->f_sigma);
+ w += __builtin_fabs (tem / fexp);
+ }
+ return i;
+}
diff --git a/gcc/testsuite/gcc.dg/vect/slp-10.c b/gcc/testsuite/gcc.dg/vect/slp-10.c
index 3395d22..61c5d3c 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-10.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-10.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_float } */
#include <stdarg.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/slp-11c.c b/gcc/testsuite/gcc.dg/vect/slp-11c.c
index 8edd663..bdcf434 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-11c.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-11c.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_float } */
#include <stdarg.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/slp-12b.c b/gcc/testsuite/gcc.dg/vect/slp-12b.c
index d6fe4e4..48e7865 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-12b.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-12b.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_uintfloat_cvt } */
+/* { dg-require-effective-target vect_float } */
#include <stdarg.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/slp-18.c b/gcc/testsuite/gcc.dg/vect/slp-18.c
index 0752363..ed426a34 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-18.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-18.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_float } */
/* { dg-require-effective-target vect_intfloat_cvt } */
#include <stdarg.h>
diff --git a/gcc/testsuite/gcc.dg/vect/slp-33.c b/gcc/testsuite/gcc.dg/vect/slp-33.c
index 30220d4..ad74daf 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-33.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-33.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_int } */
+/* { dg-require-effective-target vect_float } */
#include <stdarg.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/slp-cond-2-big-array.c b/gcc/testsuite/gcc.dg/vect/slp-cond-2-big-array.c
index f171208..57cc67e 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-cond-2-big-array.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-cond-2-big-array.c
@@ -1,4 +1,6 @@
/* { dg-require-effective-target vect_cond_mixed } */
+/* { dg-require-effective-target vect_float } */
+
#include "tree-vect.h"
#define N 128
diff --git a/gcc/testsuite/gcc.dg/vect/slp-cond-2.c b/gcc/testsuite/gcc.dg/vect/slp-cond-2.c
index 68085d4..7350695 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-cond-2.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-cond-2.c
@@ -1,4 +1,6 @@
/* { dg-require-effective-target vect_cond_mixed } */
+/* { dg-require-effective-target vect_float } */
+
#include "tree-vect.h"
#define N 32
diff --git a/gcc/testsuite/gcc.dg/vect/slp-perm-9.c b/gcc/testsuite/gcc.dg/vect/slp-perm-9.c
index 4d9c11d..b9b5a3b 100644
--- a/gcc/testsuite/gcc.dg/vect/slp-perm-9.c
+++ b/gcc/testsuite/gcc.dg/vect/slp-perm-9.c
@@ -54,8 +54,8 @@ int main (int argc, const char* argv[])
return 0;
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { {! vect_perm } || {! vect_sizes_32B_16B } } } } } */
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" { target { { vect_perm } && { vect_sizes_32B_16B } } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target { {! vect_perm } || {! vect_sizes_16B_8B } } } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" { target { { vect_perm } && { vect_sizes_16B_8B } } } } } */
/* { dg-final { scan-tree-dump-times "permutation requires at least three vectors" 1 "vect" { target vect_perm_short } } } */
/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 0 "vect" { target { {! vect_perm } || {! vect_sizes_32B_16B } } } } } */
/* { dg-final { scan-tree-dump-times "vectorizing stmts using SLP" 1 "vect" { target { { vect_perm } && { vect_sizes_32B_16B } } } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-align-1.c b/gcc/testsuite/gcc.dg/vect/vect-align-1.c
index ea5ac04..d56898c 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-align-1.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-align-1.c
@@ -47,6 +47,6 @@ int main (void)
return 0;
}
-/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 1 "vect" { target vect_hw_misalign } } } */
-/* { dg-final { scan-tree-dump-times "Alignment of access forced using versioning" 1 "vect" { xfail vect_hw_misalign} } } */
+/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 1 "vect" { target { vect_hw_misalign && { arm_vect_no_misalign } } } } } */
+/* { dg-final { scan-tree-dump-times "Alignment of access forced using versioning" 1 "vect" { target { vect_hw_misalign && arm_vect_no_misalign } } } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-align-2.c b/gcc/testsuite/gcc.dg/vect/vect-align-2.c
index 200d556..3970864 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-align-2.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-align-2.c
@@ -43,5 +43,5 @@ int main (void)
/* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 0 "vect" } } */
-/* { dg-final { scan-tree-dump-times "Alignment of access forced using versioning" 1 "vect" { xfail vect_hw_misalign} } } */
+/* { dg-final { scan-tree-dump-times "Alignment of access forced using versioning" 1 "vect" { target { vect_hw_misalign && arm_vect_no_misalign } } } } */
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-cond-10.c b/gcc/testsuite/gcc.dg/vect/vect-cond-10.c
index a75ac26..1a18800 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-cond-10.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-cond-10.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_cond_mixed } */
+/* { dg-require-effective-target vect_float } */
/* { dg-additional-options "-fno-ipa-icf" } */
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/vect-cond-8.c b/gcc/testsuite/gcc.dg/vect/vect-cond-8.c
index 1b31d7d..224251d 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-cond-8.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-cond-8.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_cond_mixed } */
+/* { dg-require-effective-target vect_float } */
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/vect-cond-9.c b/gcc/testsuite/gcc.dg/vect/vect-cond-9.c
index 6259ab6..c03ed96 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-cond-9.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-cond-9.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_cond_mixed } */
+/* { dg-require-effective-target vect_float } */
/* { dg-additional-options "-fno-ipa-icf" } */
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/vect-float-extend-1.c b/gcc/testsuite/gcc.dg/vect/vect-float-extend-1.c
index 85a7ad1..867fe20 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-float-extend-1.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-float-extend-1.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_double } */
+/* { dg-require-effective-target vect_float } */
#include <stdarg.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/vect-float-truncate-1.c b/gcc/testsuite/gcc.dg/vect/vect-float-truncate-1.c
index 81c23cf..30d3a83 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-float-truncate-1.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-float-truncate-1.c
@@ -1,4 +1,5 @@
/* { dg-require-effective-target vect_double } */
+/* { dg-require-effective-target vect_float } */
#include <stdarg.h>
#include "tree-vect.h"
diff --git a/gcc/testsuite/gcc.dg/vect/vect-floatint-conversion-2.c b/gcc/testsuite/gcc.dg/vect/vect-floatint-conversion-2.c
index 27d248b..64fab38 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-floatint-conversion-2.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-floatint-conversion-2.c
@@ -36,4 +36,4 @@ main (void)
return main1 ();
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_floatint_cvt } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_doubleint_cvt } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-intfloat-conversion-3.c b/gcc/testsuite/gcc.dg/vect/vect-intfloat-conversion-3.c
index 6eb4fec..78fc3da 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-intfloat-conversion-3.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-intfloat-conversion-3.c
@@ -35,4 +35,4 @@ int main (void)
return main1 ();
}
-/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_intfloat_cvt } } } */
+/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 1 "vect" { target vect_intdouble_cvt } } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c b/gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c
index fd7cacb..836fa76 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-multitypes-1.c
@@ -83,5 +83,5 @@ int main (void)
/* { dg-final { scan-tree-dump-times "vectorized 1 loops" 2 "vect" { xfail { vect_no_align && { ! vect_hw_misalign } } } } } */
/* { dg-final { scan-tree-dump-times "Alignment of access forced using peeling" 2 "vect" { xfail {{ vect_no_align && { ! vect_hw_misalign } } || {vect_sizes_32B_16B }}} } } */
-/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 4 "vect" { xfail {{ vect_no_align && { ! vect_hw_misalign } } || {vect_sizes_32B_16B }}} } } */
+/* { dg-final { scan-tree-dump-times "Vectorizing an unaligned access" 4 "vect" { target {{ vect_no_align && { ! vect_hw_misalign } } || {vect_sizes_32B_16B }}} } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-3a-big-array.c b/gcc/testsuite/gcc.dg/vect/vect-outer-3a-big-array.c
index 1316e80..b84f5af 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-outer-3a-big-array.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-outer-3a-big-array.c
@@ -49,4 +49,4 @@ int main (void)
}
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { vect_no_align && { ! vect_hw_misalign } } } } } */
-/* { dg-final { scan-tree-dump-times "step doesn't divide the vector-size" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "step doesn't divide the vector alignment" 1 "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/vect-outer-3a.c b/gcc/testsuite/gcc.dg/vect/vect-outer-3a.c
index 6a7ab91..d3ba837 100644
--- a/gcc/testsuite/gcc.dg/vect/vect-outer-3a.c
+++ b/gcc/testsuite/gcc.dg/vect/vect-outer-3a.c
@@ -49,4 +49,4 @@ int main (void)
}
/* { dg-final { scan-tree-dump-times "OUTER LOOP VECTORIZED" 1 "vect" { xfail { vect_no_align && { ! vect_hw_misalign } } } } } */
-/* { dg-final { scan-tree-dump-times "step doesn't divide the vector-size" 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times "step doesn't divide the vector alignment" 1 "vect" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/bic_imm_1.c b/gcc/testsuite/gcc.target/aarch64/bic_imm_1.c
new file mode 100644
index 0000000..b14f009
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/bic_imm_1.c
@@ -0,0 +1,56 @@
+/* { dg-do assemble } */
+/* { dg-options "-O2 --save-temps -ftree-vectorize" } */
+
+/* Each function uses the correspoding 'CLASS' in
+ Marco CHECK (aarch64_simd_valid_immediate). */
+
+void
+bic_6 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] &= ~(0xab);
+}
+
+void
+bic_7 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] &= ~(0xcd00);
+}
+
+void
+bic_8 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] &= ~(0xef0000);
+}
+
+void
+bic_9 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] &= ~(0x12000000);
+}
+
+void
+bic_10 (short *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] &= ~(0x34);
+}
+
+
+void
+bic_11 (short *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] &= ~(0x5600);
+}
+
+
+/* { dg-final { scan-assembler "bic\\tv\[0-9\]+.4s, #171" } } */
+/* { dg-final { scan-assembler "bic\\tv\[0-9\]+.4s, #205, lsl #8" } } */
+/* { dg-final { scan-assembler "bic\\tv\[0-9\]+.4s, #239, lsl #16" } } */
+/* { dg-final { scan-assembler "bic\\tv\[0-9\]+.4s, #18, lsl #24" } } */
+/* { dg-final { scan-assembler "bic\\tv\[0-9\]+.8h, #52" } } */
+/* { dg-final { scan-assembler "bic\\tv\[0-9\]+.8h, #86, lsl #8" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/cmpelim_mult_uses_1.c b/gcc/testsuite/gcc.target/aarch64/cmpelim_mult_uses_1.c
new file mode 100644
index 0000000..953c388
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/cmpelim_mult_uses_1.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/* X is both compared against zero and used. Make sure we can still
+ generate an ADDS and avoid an explicit comparison against zero. */
+
+int
+foo (int x, int y)
+{
+ x += y;
+ if (x != 0)
+ x = x + 2;
+ return x;
+}
+
+/* { dg-final { scan-assembler-times "adds\\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" 1 } } */
+/* { dg-final { scan-assembler-not "cmp\\tw\[0-9\]+, 0" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/orr_imm_1.c b/gcc/testsuite/gcc.target/aarch64/orr_imm_1.c
new file mode 100644
index 0000000..ff6f683
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/orr_imm_1.c
@@ -0,0 +1,54 @@
+/* { dg-do assemble } */
+/* { dg-options "-O2 --save-temps -ftree-vectorize" } */
+
+/* Each function uses the correspoding 'CLASS' in
+ Marco CHECK (aarch64_simd_valid_immediate). */
+
+void
+orr_0 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] |= 0xab;
+}
+
+void
+orr_1 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] |= 0x0000cd00;
+}
+
+void
+orr_2 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] |= 0x00ef0000;
+}
+
+void
+orr_3 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] |= 0x12000000;
+}
+
+void
+orr_4 (short *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] |= 0x00340034;
+}
+
+void
+orr_5 (int *a)
+{
+ for (int i = 0; i < 1024; i++)
+ a[i] |= 0x56005600;
+}
+
+/* { dg-final { scan-assembler "orr\\tv\[0-9\]+.4s, #171" } } */
+/* { dg-final { scan-assembler "orr\\tv\[0-9\]+.4s, #205, lsl #8" } } */
+/* { dg-final { scan-assembler "orr\\tv\[0-9\]+.4s, #239, lsl #16" } } */
+/* { dg-final { scan-assembler "orr\\tv\[0-9\]+.4s, #18, lsl #24" } } */
+/* { dg-final { scan-assembler "orr\\tv\[0-9\]+.8h, #52" } } */
+/* { dg-final { scan-assembler "orr\\tv\[0-9\]+.8h, #86, lsl #8" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/pr71727-2.c b/gcc/testsuite/gcc.target/aarch64/pr71727-2.c
new file mode 100644
index 0000000..2bc803a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr71727-2.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-mstrict-align -O3" } */
+
+unsigned char foo(const unsigned char *buffer, unsigned int length)
+{
+ unsigned char sum;
+ unsigned int count;
+
+ for (sum = 0, count = 0; count < length; count++) {
+ sum = (unsigned char) (sum + *(buffer + count));
+ }
+
+ return sum;
+}
+
+/* { dg-final { scan-assembler-times "and\tw\[0-9\]+, w\[0-9\]+, 15" 1 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/pr80295.c b/gcc/testsuite/gcc.target/aarch64/pr80295.c
new file mode 100644
index 0000000..b3866d8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr80295.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-mabi=ilp32" } */
+
+void f (void *b)
+{
+ __builtin_update_setjmp_buf (b);
+}
+
diff --git a/gcc/testsuite/gcc.target/aarch64/pr81422.C b/gcc/testsuite/gcc.target/aarch64/pr81422.C
new file mode 100644
index 0000000..5bcc948
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/pr81422.C
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O0" } */
+
+struct DArray
+{
+ __SIZE_TYPE__ length;
+ int* ptr;
+};
+
+void foo35(DArray)
+{
+ static __thread int x[5];
+ foo35({5, (int*)&x});
+}
+
diff --git a/gcc/testsuite/gcc.target/aarch64/var_shift_mask_2.c b/gcc/testsuite/gcc.target/aarch64/var_shift_mask_2.c
new file mode 100644
index 0000000..c1fe691
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/var_shift_mask_2.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+long long
+f1 (long long x, int i)
+{
+
+ return x >> (64 - i);
+}
+
+unsigned long long
+f2 (unsigned long long x, unsigned int i)
+{
+
+ return x >> (64 - i);
+}
+
+int
+f3 (int x, int i)
+{
+
+ return x >> (32 - i);
+}
+
+unsigned int
+f4 (unsigned int x, unsigned int i)
+{
+
+ return x >> (32 - i);
+}
+
+int
+f5 (int x, int i)
+{
+ return x << (32 - i);
+}
+
+long long
+f6 (long long x, int i)
+{
+ return x << (64 - i);
+}
+
+/* { dg-final { scan-assembler "lsl\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+/* { dg-final { scan-assembler "lsl\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+/* { dg-final { scan-assembler "lsr\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+/* { dg-final { scan-assembler "lsr\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+/* { dg-final { scan-assembler "asr\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
+/* { dg-final { scan-assembler "asr\tx\[0-9\]+, x\[0-9\]+, x\[0-9\]+" } } */
+/* { dg-final { scan-assembler-times "neg\tw\[0-9\]+, w\[0-9\]+" 6 } } */
+/* { dg-final { scan-assembler-not "sub\tw\[0-9\]+, w\[0-9\]+, w\[0-9\]+" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/vect_copy_lane_1.c b/gcc/testsuite/gcc.target/aarch64/vect_copy_lane_1.c
index e144def..2848be5 100644
--- a/gcc/testsuite/gcc.target/aarch64/vect_copy_lane_1.c
+++ b/gcc/testsuite/gcc.target/aarch64/vect_copy_lane_1.c
@@ -45,8 +45,7 @@ BUILD_TEST (uint32x2_t, uint32x4_t, , q, u32, 1, 3)
BUILD_TEST (float64x1_t, float64x2_t, , q, f64, 0, 1)
BUILD_TEST (int64x1_t, int64x2_t, , q, s64, 0, 1)
BUILD_TEST (uint64x1_t, uint64x2_t, , q, u64, 0, 1)
-/* XFAIL due to PR 71307. */
-/* { dg-final { scan-assembler-times "dup\\td0, v1.d\\\[1\\\]" 3 { xfail *-*-* } } } */
+/* { dg-final { scan-assembler-times "dup\\td0, v1.d\\\[1\\\]" 3 } } */
/* vcopyq_lane. */
BUILD_TEST (poly8x16_t, poly8x8_t, q, , p8, 15, 7)
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/align4.c b/gcc/testsuite/gcc.target/arm/aapcs/align4.c
index 5535c55b..df52335 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/align4.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/align4.c
@@ -2,7 +2,8 @@
/* { dg-do run { target arm_eabi } } */
/* { dg-require-effective-target arm32 } */
-/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-options "-O" } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/align_rec4.c b/gcc/testsuite/gcc.target/arm/aapcs/align_rec4.c
index 907b90a..6732fa6 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/align_rec4.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/align_rec4.c
@@ -3,6 +3,7 @@
/* { dg-do run { target arm_eabi } } */
/* { dg-require-effective-target arm32 } */
/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-options "-O -fno-inline" } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect1.c b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect1.c
index 64f9466..1a85761 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect1.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect1.c
@@ -1,8 +1,9 @@
/* Test AAPCS layout (VFP variant for Neon types) */
/* { dg-do run { target arm_eabi } } */
-/* { dg-require-effective-target arm_hard_vfp_ok } */
-/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_hard_vfp_ok } */
+/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-require-effective-target arm32 } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect2.c b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect2.c
index f5d4609..66d73ce 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect2.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect2.c
@@ -3,6 +3,7 @@
/* { dg-do run { target arm_eabi } } */
/* { dg-require-effective-target arm_hard_vfp_ok } */
/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-require-effective-target arm32 } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect3.c b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect3.c
index 31fb1da..38c04ab 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect3.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect3.c
@@ -3,6 +3,7 @@
/* { dg-do run { target arm_eabi } } */
/* { dg-require-effective-target arm_hard_vfp_ok } */
/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-require-effective-target arm32 } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect4.c b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect4.c
index bfefccc..1e6a0a5 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect4.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect4.c
@@ -1,8 +1,9 @@
/* Test AAPCS layout (VFP variant for Neon types) */
/* { dg-do run { target arm_eabi } } */
-/* { dg-require-effective-target arm_hard_vfp_ok } */
+/* { dg-require-effective-target arm_hard_vfp_ok } */
/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-require-effective-target arm32 } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect5.c b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect5.c
index ff7a857..fd78be2 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect5.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect5.c
@@ -3,6 +3,7 @@
/* { dg-do run { target arm_eabi } } */
/* { dg-require-effective-target arm_hard_vfp_ok } */
/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-require-effective-target arm32 } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect6.c b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect6.c
index b952e5d..e5a022b 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect6.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect6.c
@@ -3,6 +3,7 @@
/* { dg-do run { target arm_eabi } } */
/* { dg-require-effective-target arm_hard_vfp_ok } */
/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-require-effective-target arm32 } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect7.c b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect7.c
index 782f3a6..de021ef 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect7.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect7.c
@@ -3,6 +3,7 @@
/* { dg-do run { target arm_eabi } } */
/* { dg-require-effective-target arm_hard_vfp_ok } */
/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-require-effective-target arm32 } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect8.c b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect8.c
index 578a3d3..9eb81a8 100644
--- a/gcc/testsuite/gcc.target/arm/aapcs/neon-vect8.c
+++ b/gcc/testsuite/gcc.target/arm/aapcs/neon-vect8.c
@@ -3,6 +3,7 @@
/* { dg-do run { target arm_eabi } } */
/* { dg-require-effective-target arm_hard_vfp_ok } */
/* { dg-require-effective-target arm_neon_ok } */
+/* { dg-require-effective-target arm_neon_hw } */
/* { dg-require-effective-target arm32 } */
/* { dg-add-options arm_neon } */
diff --git a/gcc/testsuite/gcc.target/arm/peep-ldrd-1.c b/gcc/testsuite/gcc.target/arm/peep-ldrd-1.c
index eb2b86e..d49eff6 100644
--- a/gcc/testsuite/gcc.target/arm/peep-ldrd-1.c
+++ b/gcc/testsuite/gcc.target/arm/peep-ldrd-1.c
@@ -8,4 +8,4 @@ int foo(int a, int b, int* p, int *q)
*p = a;
return a;
}
-/* { dg-final { scan-assembler "ldrd" } } */
+/* { dg-final { scan-assembler "ldrd\\t" } } */
diff --git a/gcc/testsuite/gcc.target/arm/peep-ldrd-2.c b/gcc/testsuite/gcc.target/arm/peep-ldrd-2.c
new file mode 100644
index 0000000..6822c2b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/peep-ldrd-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_prefer_ldrd_strd } */
+/* { dg-options "-O2 -mno-unaligned-access" } */
+int foo(int a, int b, int* p, int *q)
+{
+ a = p[2] + p[3];
+ *q = a;
+ *p = a;
+ return a;
+}
+/* { dg-final { scan-assembler-not "ldrd\\t" } } */
diff --git a/gcc/testsuite/gcc.target/arm/peep-strd-1.c b/gcc/testsuite/gcc.target/arm/peep-strd-1.c
index bd33076..fe1beac 100644
--- a/gcc/testsuite/gcc.target/arm/peep-strd-1.c
+++ b/gcc/testsuite/gcc.target/arm/peep-strd-1.c
@@ -6,4 +6,4 @@ void foo(int a, int b, int* p)
p[2] = a;
p[3] = b;
}
-/* { dg-final { scan-assembler "strd" } } */
+/* { dg-final { scan-assembler "strd\\t" } } */
diff --git a/gcc/testsuite/gcc.target/arm/peep-strd-2.c b/gcc/testsuite/gcc.target/arm/peep-strd-2.c
new file mode 100644
index 0000000..bfc5ebe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/arm/peep-strd-2.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target arm_prefer_ldrd_strd } */
+/* { dg-options "-O2 -mno-unaligned-access" } */
+void foo(int a, int b, int* p)
+{
+ p[2] = a;
+ p[3] = b;
+}
+/* { dg-final { scan-assembler-not "strd\\t" } } */
diff --git a/gcc/testsuite/gcc.target/i386/387-ficom-1.c b/gcc/testsuite/gcc.target/i386/387-ficom-1.c
new file mode 100644
index 0000000..3256988
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/387-ficom-1.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target ia32 } */
+/* { dg-skip-if "" { *-*-* } { "-march=*" } { "-march=i386" } } */
+/* { dg-options "-O2 -march=i386 -ffast-math -masm=att" } */
+
+extern short s;
+
+int test_f_s (short x)
+{
+ return (float)x > s;
+}
+
+int test_d_s (short x)
+{
+ return (double)x < s;
+}
+
+int test_ld_s (short x)
+{
+ return (long double)x == s;
+}
+
+extern int i;
+
+int test_f_i (int x)
+{
+ return (float)i >= x;
+}
+
+int test_d_i (int x)
+{
+ return (double)i <= x;
+}
+
+int test_ld_i (int x)
+{
+ return (long double)i != x;
+}
+
+/* { dg-final { scan-assembler-times "ficomp\[s\t\]" 3 } } */
+/* { dg-final { scan-assembler-times "ficompl" 3 } } */
diff --git a/gcc/testsuite/gcc.target/i386/387-ficom-2.c b/gcc/testsuite/gcc.target/i386/387-ficom-2.c
new file mode 100644
index 0000000..d528368
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/387-ficom-2.c
@@ -0,0 +1,9 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target ia32 } */
+/* { dg-skip-if "" { *-*-* } { "-march=*" } { "-march=i386" } } */
+/* { dg-options "-Os -march=i386 -ffast-math -masm=att" } */
+
+#include "387-ficom-1.c"
+
+/* { dg-final { scan-assembler-times "ficomp\[s\t\]" 3 } } */
+/* { dg-final { scan-assembler-times "ficompl" 3 } } */
diff --git a/gcc/testsuite/gcc.target/i386/asm-mem.c b/gcc/testsuite/gcc.target/i386/asm-mem.c
new file mode 100644
index 0000000..89b713f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/asm-mem.c
@@ -0,0 +1,59 @@
+/* { dg-do run } */
+/* { dg-options "-O3" } */
+
+/* Check that "m" array references are effective in preventing the
+ array initialization from wandering past a use in the asm, and
+ that the casts remain supported. */
+
+static int
+f1 (const char *p)
+{
+ int count;
+
+ __asm__ ("repne scasb"
+ : "=c" (count), "+D" (p)
+ : "m" (*(const char (*)[]) p), "0" (-1), "a" (0));
+ return -2 - count;
+}
+
+static int
+f2 (const char *p)
+{
+ int count;
+
+ __asm__ ("repne scasb"
+ : "=c" (count), "+D" (p)
+ : "m" (*(const char (*)[48]) p), "0" (-1), "a" (0));
+ return -2 - count;
+}
+
+static int
+f3 (int n, const char *p)
+{
+ int count;
+
+ __asm__ ("repne scasb"
+ : "=c" (count), "+D" (p)
+ : "m" (*(const char (*)[n]) p), "0" (-1), "a" (0));
+ return -2 - count;
+}
+
+int
+main ()
+{
+ int a;
+ char buff[48] = "hello world";
+ buff[4] = 0;
+ a = f1 (buff);
+ if (a != 4)
+ __builtin_abort ();
+ buff[4] = 'o';
+ a = f2 (buff);
+ if (a != 11)
+ __builtin_abort ();
+ buff[4] = 0;
+ a = f3 (48, buff);
+ if (a != 4)
+ __builtin_abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/attr-nocf-check-1a.c b/gcc/testsuite/gcc.target/i386/attr-nocf-check-1a.c
new file mode 100644
index 0000000..9549e69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/attr-nocf-check-1a.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-fcf-protection -mcet" } */
+
+int func (int) __attribute__ ((nocf_check));
+int (*fptr) (int) __attribute__ ((nocf_check));
+typedef void (*nocf_check_t) (void) __attribute__ ((nocf_check));
+
+int
+foo1 (int arg)
+{
+ return func (arg) + fptr (arg);
+}
+
+void
+foo2 (void (*foo) (void))
+{
+ void (*func) (void) __attribute__((nocf_check)) = foo; /* { dg-warning "incompatible pointer type" "" { target c } } */
+ /* { dg-error "invalid conversion" "" { target c++ } .-1 } */
+ func ();
+}
+
+void
+foo3 (nocf_check_t foo)
+{
+ foo ();
+}
+
+void
+foo4 (void (*foo) (void) __attribute__((nocf_check)))
+{
+ foo ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/attr-nocf-check-3a.c b/gcc/testsuite/gcc.target/i386/attr-nocf-check-3a.c
new file mode 100644
index 0000000..1a83301
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/attr-nocf-check-3a.c
@@ -0,0 +1,32 @@
+/* { dg-do compile } */
+/* { dg-options "-fcf-protection -mcet" } */
+
+int foo (void) __attribute__ ((nocf_check));
+void (*foo1) (void) __attribute__((nocf_check));
+void (*foo2) (void);
+
+int __attribute__ ((nocf_check))
+foo (void) /* The function's address is not tracked. */
+{
+ /* This call site is not tracked for
+ control-flow instrumentation. */
+ (*foo1)();
+
+ foo1 = foo2; /* { dg-warning "incompatible pointer type" "" { target c } } */
+ /* { dg-error "invalid conversion" "" { target c++ } .-1 } */
+ /* This call site is still not tracked for
+ control-flow instrumentation. */
+ (*foo1)();
+
+ /* This call site is tracked for
+ control-flow instrumentation. */
+ (*foo2)();
+
+ foo2 = foo1; /* { dg-warning "incompatible pointer type" "" { target c } } */
+ /* { dg-error "invalid conversion" "" { target c++ } .-1 } */
+ /* This call site is still tracked for
+ control-flow instrumentation. */
+ (*foo2)();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/avx-1.c b/gcc/testsuite/gcc.target/i386/avx-1.c
index 085ba81..d03625b 100644
--- a/gcc/testsuite/gcc.target/i386/avx-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx-1.c
@@ -412,8 +412,8 @@
/* avx512dqintrin.h */
#define __builtin_ia32_kshiftliqi(A, B) __builtin_ia32_kshiftliqi(A, 8)
#define __builtin_ia32_kshiftriqi(A, B) __builtin_ia32_kshiftriqi(A, 8)
-#define __builtin_ia32_reducess(A, B, F) __builtin_ia32_reducess(A, B, 1)
-#define __builtin_ia32_reducesd(A, B, F) __builtin_ia32_reducesd(A, B, 1)
+#define __builtin_ia32_reducess_mask(A, B, F, W, U) __builtin_ia32_reducess_mask(A, B, 1, W, U)
+#define __builtin_ia32_reducesd_mask(A, B, F, W, U) __builtin_ia32_reducesd_mask(A, B, 1, W, U)
#define __builtin_ia32_reduceps512_mask(A, E, C, D) __builtin_ia32_reduceps512_mask(A, 1, C, D)
#define __builtin_ia32_reducepd512_mask(A, E, C, D) __builtin_ia32_reducepd512_mask(A, 1, C, D)
#define __builtin_ia32_rangess128_round(A, B, I, F) __builtin_ia32_rangess128_round(A, B, 1, 8)
diff --git a/gcc/testsuite/gcc.target/i386/avx-pr82370.c b/gcc/testsuite/gcc.target/i386/avx-pr82370.c
new file mode 100644
index 0000000..4dc8a5b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx-pr82370.c
@@ -0,0 +1,65 @@
+/* PR target/82370 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx -mno-avx2 -masm=att" } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 3 } } */
+
+typedef short int v32hi __attribute__((vector_size (64)));
+typedef short int v16hi __attribute__((vector_size (32)));
+typedef short int v8hi __attribute__((vector_size (16)));
+typedef int v16si __attribute__((vector_size (64)));
+typedef int v8si __attribute__((vector_size (32)));
+typedef int v4si __attribute__((vector_size (16)));
+typedef long long int v8di __attribute__((vector_size (64)));
+typedef long long int v4di __attribute__((vector_size (32)));
+typedef long long int v2di __attribute__((vector_size (16)));
+typedef unsigned short int v32uhi __attribute__((vector_size (64)));
+typedef unsigned short int v16uhi __attribute__((vector_size (32)));
+typedef unsigned short int v8uhi __attribute__((vector_size (16)));
+typedef unsigned int v16usi __attribute__((vector_size (64)));
+typedef unsigned int v8usi __attribute__((vector_size (32)));
+typedef unsigned int v4usi __attribute__((vector_size (16)));
+typedef unsigned long long int v8udi __attribute__((vector_size (64)));
+typedef unsigned long long int v4udi __attribute__((vector_size (32)));
+typedef unsigned long long int v2udi __attribute__((vector_size (16)));
+
+#ifdef __AVX512F__
+v32hi f1 (v32hi *x) { return *x >> 3; }
+v32uhi f2 (v32uhi *x) { return *x >> 5; }
+v32uhi f3 (v32uhi *x) { return *x << 7; }
+#endif
+v16hi f4 (v16hi *x) { return *x >> 3; }
+v16uhi f5 (v16uhi *x) { return *x >> 5; }
+v16uhi f6 (v16uhi *x) { return *x << 7; }
+v8hi f7 (v8hi *x) { return *x >> 3; }
+v8uhi f8 (v8uhi *x) { return *x >> 5; }
+v8uhi f9 (v8uhi *x) { return *x << 7; }
+#ifdef __AVX512F__
+v16si f10 (v16si *x) { return *x >> 3; }
+v16usi f11 (v16usi *x) { return *x >> 5; }
+v16usi f12 (v16usi *x) { return *x << 7; }
+#endif
+v8si f13 (v8si *x) { return *x >> 3; }
+v8usi f14 (v8usi *x) { return *x >> 5; }
+v8usi f15 (v8usi *x) { return *x << 7; }
+v4si f16 (v4si *x) { return *x >> 3; }
+v4usi f17 (v4usi *x) { return *x >> 5; }
+v4usi f18 (v4usi *x) { return *x << 7; }
+#ifdef __AVX512F__
+v8di f19 (v8di *x) { return *x >> 3; }
+v8udi f20 (v8udi *x) { return *x >> 5; }
+v8udi f21 (v8udi *x) { return *x << 7; }
+#endif
+v4di f22 (v4di *x) { return *x >> 3; }
+v4udi f23 (v4udi *x) { return *x >> 5; }
+v4udi f24 (v4udi *x) { return *x << 7; }
+v2di f25 (v2di *x) { return *x >> 3; }
+v2udi f26 (v2udi *x) { return *x >> 5; }
+v2udi f27 (v2udi *x) { return *x << 7; }
diff --git a/gcc/testsuite/gcc.target/i386/avx2-pr82370.c b/gcc/testsuite/gcc.target/i386/avx2-pr82370.c
new file mode 100644
index 0000000..6609ebb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx2-pr82370.c
@@ -0,0 +1,23 @@
+/* PR target/82370 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx2 -mno-avx512f -masm=att" } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+
+#include "avx-pr82370.c"
diff --git a/gcc/testsuite/gcc.target/i386/avx512bw-pr82370.c b/gcc/testsuite/gcc.target/i386/avx512bw-pr82370.c
new file mode 100644
index 0000000..174f499
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512bw-pr82370.c
@@ -0,0 +1,33 @@
+/* PR target/82370 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx512bw -mno-avx512vl -masm=att" } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vps\[lr]\[la]\[dwq]\[ \t]\+\\\$\[357], %zmm\[0-9]\+, %zmm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+
+#include "avx-pr82370.c"
diff --git a/gcc/testsuite/gcc.target/i386/avx512bw-vpermt2w-1.c b/gcc/testsuite/gcc.target/i386/avx512bw-vpermt2w-1.c
index be8737e..a734cb6 100644
--- a/gcc/testsuite/gcc.target/i386/avx512bw-vpermt2w-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512bw-vpermt2w-1.c
@@ -1,14 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-mavx512bw -mavx512vl -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } *
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2w\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } *
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2w\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-1.c b/gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-1.c
index b7549fa..b8f24a0c 100644
--- a/gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-1.c
@@ -2,13 +2,24 @@
/* { dg-options "-mavx512dq -O2" } */
/* { dg-final { scan-assembler-times "vreducesd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vreducesd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vreducesd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vreducesd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+
+
#include <immintrin.h>
+#define IMM 123
+
volatile __m128d x1, x2;
volatile __mmask8 m;
void extern
avx512dq_test (void)
{
- x1 = _mm_reduce_sd (x1, x2, 123);
+ x1 = _mm_reduce_sd (x1, x2, IMM);
+
+ x1 = _mm_mask_reduce_sd(x1, m, x1, x2, IMM);
+
+ x1 = _mm_maskz_reduce_sd(m, x1, x2, IMM);
}
diff --git a/gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-2.c b/gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-2.c
new file mode 100644
index 0000000..93e1827
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512dq-vreducesd-2.c
@@ -0,0 +1,66 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -mavx512dq" } */
+/* { dg-require-effective-target avx512dq } */
+
+#define AVX512DQ
+#include "avx512f-helper.h"
+#include <string.h>
+
+#define SIZE (AVX512F_LEN / 64)
+#include "avx512f-mask-type.h"
+
+#define IMM 0x23
+
+void
+CALC (double *r, double *s)
+{
+ int i;
+
+ memcpy (&r[1], &s[1], sizeof(double));
+
+ for (i = 0; i < 1; i++)
+ {
+ double tmp = (int) (4 * s[i]) / 4.0;
+ r[i] = s[i] - tmp;
+ }
+}
+
+void
+TEST (void)
+{
+ union128d res1, res2, res3;
+ union128d s1, s2, src;
+ double res_ref[2];
+ MASK_TYPE mask = MASK_VALUE;
+ int j;
+
+ for (j = 0; j < 2; j++)
+ {
+ s1.a[j] = j / 123.456;
+ s2.a[j] = j / 123.456;
+ res_ref[j] = j / 123.456;
+ res1.a[j] = DEFAULT_VALUE;
+ res2.a[j] = DEFAULT_VALUE;
+ res3.a[j] = DEFAULT_VALUE;
+ }
+
+ res1.x = _mm_reduce_sd (s1.x, s2.x, IMM);
+ res2.x = _mm_mask_reduce_sd (s1.x, mask, s1.x, s2.x, IMM);
+ res3.x = _mm_maskz_reduce_sd (mask, s1.x, s2.x, IMM);
+
+ CALC (res_ref, s2.a);
+
+ if (check_union128d (res1, res_ref))
+ abort ();
+
+ MASK_MERGE (d) (res_ref, mask, 1);
+
+ if (check_union128d (res2, res_ref))
+ abort ();
+
+ MASK_ZERO (d) (res_ref, mask, 1);
+
+ if (check_union128d (res3, res_ref))
+ abort ();
+
+}
diff --git a/gcc/testsuite/gcc.target/i386/avx512dq-vreducess-1.c b/gcc/testsuite/gcc.target/i386/avx512dq-vreducess-1.c
index 2a6afe9..804074e 100644
--- a/gcc/testsuite/gcc.target/i386/avx512dq-vreducess-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512dq-vreducess-1.c
@@ -2,13 +2,23 @@
/* { dg-options "-mavx512dq -O2" } */
/* { dg-final { scan-assembler-times "vreducess\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vreducess\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vreducess\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vreducess\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\[^\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+
#include <immintrin.h>
+#define IMM 123
+
volatile __m128 x1, x2;
volatile __mmask8 m;
void extern
avx512dq_test (void)
{
- x1 = _mm_reduce_ss (x1, x2, 123);
+ x1 = _mm_reduce_ss (x1, x2, IMM);
+
+ x1 = _mm_mask_reduce_ss (x1, m, x1, x2, IMM);
+
+ x1 = _mm_maskz_reduce_ss (m, x1, x2, IMM);
}
diff --git a/gcc/testsuite/gcc.target/i386/avx512dq-vreducess-2.c b/gcc/testsuite/gcc.target/i386/avx512dq-vreducess-2.c
new file mode 100644
index 0000000..8558c3b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512dq-vreducess-2.c
@@ -0,0 +1,68 @@
+/* { dg-do run } */
+/* { dg-options "-O2 -mavx512dq" } */
+/* { dg-require-effective-target avx512dq } */
+
+#define AVX512DQ
+#include "avx512f-helper.h"
+#include <string.h>
+
+#define SIZE (AVX512F_LEN / 64)
+#include "avx512f-mask-type.h"
+
+#define IMM 0x23
+
+void
+CALC (float *r, float *s)
+{
+ int i;
+
+ memcpy (&r[1], &s[1], 2 * sizeof(float));
+
+ for (i = 0; i < 2; i++)
+ {
+ float tmp = (int) (4 * s[i]) / 4.0;
+ r[i] = s[i] - tmp;
+ }
+}
+
+void
+TEST (void)
+{
+ printf("\nsize = %d\n\n", SIZE);
+
+ union128 res1, res2, res3;
+ union128 s1, s2, src;
+ float res_ref[4];
+ MASK_TYPE mask = MASK_VALUE;
+ int j;
+
+ for (j = 0; j < 4; j++)
+ {
+ s1.a[j] = j / 123.456;
+ s2.a[j] = j / 123.456;
+ res_ref[j] = j / 123.456;
+ res1.a[j] = DEFAULT_VALUE;
+ res2.a[j] = DEFAULT_VALUE;
+ res3.a[j] = DEFAULT_VALUE;
+ }
+
+ res1.x = _mm_reduce_ss (s1.x, s2.x, IMM);
+ res2.x = _mm_mask_reduce_ss (s1.x, mask, s1.x, s2.x, IMM);
+ res3.x = _mm_maskz_reduce_ss (mask, s1.x, s2.x, IMM);
+
+ CALC (res_ref, s2.a);
+
+ if (check_union128 (res1, res_ref))
+ abort ();
+
+ MASK_MERGE () (res_ref, mask, 1);
+
+ if (check_union128 (res2, res_ref))
+ abort ();
+
+ MASK_ZERO () (res_ref, mask, 1);
+
+ if (check_union128 (res3, res_ref))
+ abort ();
+
+}
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-constant-float-return.c b/gcc/testsuite/gcc.target/i386/avx512f-constant-float-return.c
new file mode 100644
index 0000000..153cf69
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512f-constant-float-return.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=skylake-avx512 -mprefer-avx256" } */
+/* { dg-final { scan-assembler-not "%zmm\[0-9\]+" } } */
+
+float
+my_test_f()
+{
+ return 0.0f;
+}
+
+double
+my_test_d()
+{
+ return 0.0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-constant-set.c b/gcc/testsuite/gcc.target/i386/avx512f-constant-set.c
new file mode 100644
index 0000000..022627c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512f-constant-set.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=skylake-avx512" } */
+/* { dg-final { scan-assembler-not "%zmm\[0-9\]+" } } */
+
+void
+avx512f_test (short *table)
+{
+ int i;
+ for (i = 0; i < 128; ++i)
+ table[i] = -1;
+}
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-pr82370.c b/gcc/testsuite/gcc.target/i386/avx512f-pr82370.c
new file mode 100644
index 0000000..20ad8dc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512f-pr82370.c
@@ -0,0 +1,33 @@
+/* PR target/82370 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx512f -mno-avx512bw -mno-avx512vl -masm=att" } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vps\[lr]\[la]\[dwq]\[ \t]\+\\\$\[357], %zmm\[0-9]\+, %zmm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 0 } } */
+
+#include "avx-pr82370.c"
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-prefer.c b/gcc/testsuite/gcc.target/i386/avx512f-prefer.c
new file mode 100644
index 0000000..defe51e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512f-prefer.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -march=skylake-avx512 -mprefer-avx256" } */
+/* { dg-final { scan-assembler-not "%zmm\[0-9\]+" } } */
+/* { dg-final { scan-assembler "vmulpd" } } */
+
+#define N 1024
+
+double a[N], b[N], c[N];
+
+void
+avx512f_test (void)
+{
+ int i;
+
+ for (i = 0; i < N; i++)
+ c[i] = a[i] * b[i];
+}
+
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vpermt2d-1.c b/gcc/testsuite/gcc.target/i386/avx512f-vpermt2d-1.c
index ceb1bd3..919cd21 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vpermt2d-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vpermt2d-1.c
@@ -1,8 +1,8 @@
/* { dg-do compile } */
/* { dg-options "-mavx512f -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vpermt2pd-1.c b/gcc/testsuite/gcc.target/i386/avx512f-vpermt2pd-1.c
index 2a4955b..c021efb 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vpermt2pd-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vpermt2pd-1.c
@@ -1,8 +1,8 @@
/* { dg-do compile } */
/* { dg-options "-mavx512f -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2pd\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2pd\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vpermt2ps-1.c b/gcc/testsuite/gcc.target/i386/avx512f-vpermt2ps-1.c
index dadc6d7..ffe177b 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vpermt2ps-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vpermt2ps-1.c
@@ -1,8 +1,8 @@
/* { dg-do compile } */
/* { dg-options "-mavx512f -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2ps\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2ps\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512f-vpermt2q-1.c b/gcc/testsuite/gcc.target/i386/avx512f-vpermt2q-1.c
index 9c6e989..74bb4ed 100644
--- a/gcc/testsuite/gcc.target/i386/avx512f-vpermt2q-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512f-vpermt2q-1.c
@@ -1,8 +1,8 @@
/* { dg-do compile } */
/* { dg-options "-mavx512f -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512vbmi-vpermt2b-1.c b/gcc/testsuite/gcc.target/i386/avx512vbmi-vpermt2b-1.c
index f1c31cc..24a0b9e 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vbmi-vpermt2b-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vbmi-vpermt2b-1.c
@@ -1,14 +1,14 @@
/* { dg-do compile } */
/* { dg-options "-mavx512vbmi -mavx512vl -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%zmm\[0-9\]+" 3 } } */
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%ymm\[0-9\]+" 3 } } *
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%xmm\[0-9\]+" 3 } } */
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\[^\{\]" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\[^\{\]" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\[^\{\]" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2b\[ \\t\]+\[^\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%zmm\[0-9\]+" 3 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%ymm\[0-9\]+" 3 } } *
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%xmm\[0-9\]+" 3 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\[^\{\]" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\[^\{\]" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\[^\{\]" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%zmm\[0-9\]+\{%k\[1-7\]\}\{z\}" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2b\[ \\t\]+\[^\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-pr82370.c b/gcc/testsuite/gcc.target/i386/avx512vl-pr82370.c
new file mode 100644
index 0000000..486ece5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-pr82370.c
@@ -0,0 +1,31 @@
+/* PR target/82370 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx512vl -mno-avx512bw -masm=att" } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %xmm\[0-9]\+, %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, %ymm\[0-9]\+, %ymm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, %ymm\[0-9]\+, %ymm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, %ymm\[0-9]\+, %ymm\[0-9]\+" 3 } } */
+/* { dg-final { scan-assembler-times "vps\[lr]\[la]\[dq]\[ \t]\+\\\$\[357], %\[xyz]mm\[0-9]\+, %\[xyz]mm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vps\[lr]\[la]w\[ \t]\+\\\$\[357], \\(%\[a-z0-9,]*\\), %\[xyz]mm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+
+#include "avx-pr82370.c"
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2d-1.c b/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2d-1.c
index 3a6de90..218650c 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2d-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2d-1.c
@@ -1,11 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-mavx512vl -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2d\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2d\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2pd-1.c b/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2pd-1.c
index 5dd0734..64bd30e 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2pd-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2pd-1.c
@@ -1,11 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-mavx512vl -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2pd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2pd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2pd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2pd\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2pd\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2ps-1.c b/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2ps-1.c
index 0d7e37b..7af2dea 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2ps-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2ps-1.c
@@ -1,11 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-mavx512vl -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2ps\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2ps\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2ps\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2ps\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2ps\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2q-1.c b/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2q-1.c
index 475aa6d..0cbd8b5 100644
--- a/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2q-1.c
+++ b/gcc/testsuite/gcc.target/i386/avx512vl-vpermt2q-1.c
@@ -1,11 +1,11 @@
/* { dg-do compile } */
/* { dg-options "-mavx512vl -O2" } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
-/* { dg-final { scan-assembler-times "vpermt2q\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%ymm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[ti]2q\[ \\t\]+\[^\{\n\]*%xmm\[0-9\]+\{%k\[1-7\]\}\{z\}(?:\n|\[ \\t\]+#)" 1 } } */
#include <immintrin.h>
diff --git a/gcc/testsuite/gcc.target/i386/avx512vlbw-pr82370.c b/gcc/testsuite/gcc.target/i386/avx512vlbw-pr82370.c
new file mode 100644
index 0000000..6809b4d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/avx512vlbw-pr82370.c
@@ -0,0 +1,33 @@
+/* PR target/82370 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx512vl -mavx512bw -masm=att" } */
+/* { dg-final { scan-assembler-times "vps\[lr]\[la]\[dwq]\[ \t]\+\\\$\[357], %\[xyz]mm\[0-9]\+, %\[xyz]mm\[0-9]\+" 0 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslld\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllq\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsllw\[ \t]\+\\\$7, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrad\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraq\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsraw\[ \t]\+\\\$3, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrld\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrlw\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+
+#include "avx-pr82370.c"
diff --git a/gcc/testsuite/gcc.target/i386/bt-5.c b/gcc/testsuite/gcc.target/i386/bt-5.c
deleted file mode 100644
index 309adfe..0000000
--- a/gcc/testsuite/gcc.target/i386/bt-5.c
+++ /dev/null
@@ -1,11 +0,0 @@
-/* PR target/36473 */
-/* { dg-do compile } */
-/* { dg-options "-O2 -mtune=core2" } */
-/* { dg-additional-options "-mregparm=2" { target ia32 } } */
-
-int test(unsigned x, unsigned n)
-{
- return !(x & ( 0x01 << n ));
-}
-
-/* { dg-final { scan-assembler "btl\[ \t\]" } } */
diff --git a/gcc/testsuite/gcc.target/i386/bt-6.c b/gcc/testsuite/gcc.target/i386/bt-6.c
deleted file mode 100644
index 994ec43..0000000
--- a/gcc/testsuite/gcc.target/i386/bt-6.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/* PR target/36473 */
-/* { dg-do compile } */
-/* { dg-options "-O2 -mtune=core2" } */
-/* { dg-additional-options "-mregparm=2" { target ia32 } } */
-
-int test(unsigned long x, unsigned long n)
-{
- return !(x & ( (long)0x01 << n ));
-}
-
-/* { dg-final { scan-assembler "btl\[ \t\]" { target { ! lp64 } } } } */
-/* { dg-final { scan-assembler "btq\[ \t\]" { target lp64 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/bt-mask-3.c b/gcc/testsuite/gcc.target/i386/bt-mask-3.c
deleted file mode 100644
index bf3a404..0000000
--- a/gcc/testsuite/gcc.target/i386/bt-mask-3.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O2 -mtune=core2" } */
-/* { dg-additional-options "-mregparm=2" { target ia32 } } */
-
-int test (unsigned x, unsigned n)
-{
- n &= 0x1f;
-
- return !(x & (0x01 << n));
-}
-
-/* { dg-final { scan-assembler-not "and\[lq\]\[ \t\]" } } */
diff --git a/gcc/testsuite/gcc.target/i386/bt-mask-4.c b/gcc/testsuite/gcc.target/i386/bt-mask-4.c
deleted file mode 100644
index 8198646..0000000
--- a/gcc/testsuite/gcc.target/i386/bt-mask-4.c
+++ /dev/null
@@ -1,12 +0,0 @@
-/* { dg-do compile } */
-/* { dg-options "-O2 -mtune=core2" } */
-/* { dg-additional-options "-mregparm=2" { target ia32 } } */
-
-int test (unsigned long x, unsigned long n)
-{
- n &= 0x3f;
-
- return !(x & ((long)0x01 << n));
-}
-
-/* { dg-final { scan-assembler-not "and\[lq\]\[ \t\]" } } */
diff --git a/gcc/testsuite/gcc.target/i386/builtin_target.c b/gcc/testsuite/gcc.target/i386/builtin_target.c
index 9c190eb..8fa9797 100644
--- a/gcc/testsuite/gcc.target/i386/builtin_target.c
+++ b/gcc/testsuite/gcc.target/i386/builtin_target.c
@@ -42,6 +42,10 @@ check_intel_cpu_model (unsigned int family, unsigned int model,
/* Knights Landing. */
assert (__builtin_cpu_is ("knl"));
break;
+ case 0x85:
+ /* Knights Mill */
+ assert (__builtin_cpu_is ("knm"));
+ break;
case 0x1a:
case 0x1e:
case 0x1f:
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-10.c b/gcc/testsuite/gcc.target/i386/cet-intrin-10.c
new file mode 100644
index 0000000..695dc5e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin-10.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcet" } */
+/* { dg-final { scan-assembler-times "clrssbsy" 1 } } */
+
+#include <immintrin.h>
+
+void f2 (void *__B)
+{
+ _clrssbsy (__B);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-3.c b/gcc/testsuite/gcc.target/i386/cet-intrin-3.c
new file mode 100644
index 0000000..bcd7203
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin-3.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 2 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 4 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "rdsspd|incsspd\[ \t]+(%|)eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "rdssp\[dq]\[ \t]+(%|)\[re]ax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "incssp\[dq]\[ \t]+(%|)\[re]di" { target { ! ia32 } } } } */
+
+#include <immintrin.h>
+
+unsigned int f1 ()
+{
+ unsigned int x = 0;
+ return _rdsspd (x);
+}
+
+void f3 (unsigned int _a)
+{
+ _incsspd (_a);
+}
+
+#ifdef __x86_64__
+unsigned long long f2 ()
+{
+ unsigned long long x = 0;
+ return _rdsspq (x);
+}
+
+void f4 (unsigned int _a)
+{
+ _incsspq (_a);
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-4.c b/gcc/testsuite/gcc.target/i386/cet-intrin-4.c
new file mode 100644
index 0000000..76ec160
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin-4.c
@@ -0,0 +1,31 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mshstk" } */
+/* { dg-final { scan-assembler "rdsspd|incsspd\[ \t]+(%|)eax" { target ia32 } } } */
+/* { dg-final { scan-assembler "rdssp\[dq]\[ \t]+(%|)\[re]ax" { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler "incssp\[dq]\[ \t]+(%|)\[re]di" { target { ! ia32 } } } } */
+
+#include <immintrin.h>
+
+unsigned int f1 ()
+{
+ unsigned int x = 0;
+ return _rdsspd (x);
+}
+
+void f3 (unsigned int _a)
+{
+ _incsspd (_a);
+}
+
+#ifdef __x86_64__
+unsigned long long f2 ()
+{
+ unsigned long long x = 0;
+ return _rdsspq (x);
+}
+
+void f4 (unsigned int _a)
+{
+ _incsspq (_a);
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-5.c b/gcc/testsuite/gcc.target/i386/cet-intrin-5.c
new file mode 100644
index 0000000..8a1b637
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin-5.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcet" } */
+/* { dg-final { scan-assembler-times "saveprevssp" 1 } } */
+
+#include <immintrin.h>
+
+void f2 (void)
+{
+ _saveprevssp ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-6.c b/gcc/testsuite/gcc.target/i386/cet-intrin-6.c
new file mode 100644
index 0000000..dfa6d20
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin-6.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcet" } */
+/* { dg-final { scan-assembler-times "rstorssp" 1 } } */
+
+#include <immintrin.h>
+
+void f2 (void *__B)
+{
+ _rstorssp (__B);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-7.c b/gcc/testsuite/gcc.target/i386/cet-intrin-7.c
new file mode 100644
index 0000000..ecd1825
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin-7.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcet" } */
+/* { dg-final { scan-assembler-times "wrssd" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "wrss\[d|q]" 2 { target lp64 } } } */
+
+#include <immintrin.h>
+
+void f1 (unsigned int __A, void *__B)
+{
+ _wrssd (__A, __B);
+}
+
+#ifdef __x86_64__
+void f2 (unsigned long long __A, void *__B)
+{
+ _wrssq (__A, __B);
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-8.c b/gcc/testsuite/gcc.target/i386/cet-intrin-8.c
new file mode 100644
index 0000000..2188876
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin-8.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcet" } */
+/* { dg-final { scan-assembler-times "wrussd" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "wruss\[d|q]" 2 { target lp64 } } } */
+
+#include <immintrin.h>
+
+void f1 (unsigned int __A, void *__B)
+{
+ _wrussd (__A, __B);
+}
+
+#ifdef __x86_64__
+void f2 (unsigned long long __A, void *__B)
+{
+ _wrussq (__A, __B);
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/i386/cet-intrin-9.c b/gcc/testsuite/gcc.target/i386/cet-intrin-9.c
new file mode 100644
index 0000000..569931a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-intrin-9.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -mcet" } */
+/* { dg-final { scan-assembler-times "setssbsy" 1 } } */
+
+#include <immintrin.h>
+
+void f2 (void)
+{
+ _setssbsy ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-label-2.c b/gcc/testsuite/gcc.target/i386/cet-label-2.c
new file mode 100644
index 0000000..c7f7981
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-label-2.c
@@ -0,0 +1,24 @@
+/* Verify that CET works. */
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 3 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 3 { target { ! ia32 } } } } */
+
+__attribute__ ((noinline, noclone))
+static int
+func (int arg)
+{
+ static void *array[] = { &&foo, &&bar };
+
+ goto *array[arg];
+foo:
+ return arg*111;
+bar:
+ return arg*777;
+}
+
+int
+foo (int arg)
+{
+ return func (arg);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-label.c b/gcc/testsuite/gcc.target/i386/cet-label.c
new file mode 100644
index 0000000..8fb8d42
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-label.c
@@ -0,0 +1,16 @@
+/* Verify that CET works. */
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 3 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 3 { target { ! ia32 } } } } */
+
+int func (int arg)
+{
+ static void *array[] = { &&foo, &&bar };
+
+ goto *array[arg];
+foo:
+ return arg*111;
+bar:
+ return arg*777;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-1a.c b/gcc/testsuite/gcc.target/i386/cet-notrack-1a.c
new file mode 100644
index 0000000..ab0bd3b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-1a.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fcf-protection=none -mno-cet" } */
+/* { dg-final { scan-assembler-not "endbr" } } */
+/* { dg-final { scan-assembler-not "notrack call\[ \t]+" } } */
+
+int func (int a) __attribute__ ((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored. Use -fcf-protection option to enable it" } */
+int (*fptr) (int a) __attribute__ ((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored. Use -fcf-protection option to enable it" } */
+
+int foo (int arg)
+{
+ int a, b;
+ a = func (arg);
+ b = (*fptr) (arg);
+ return a+b;
+}
+
+int __attribute__ ((nocf_check))
+func (int arg)
+{ /* { dg-warning "'nocf_check' attribute ignored. Use -fcf-protection option to enable it" } */
+ int (*fptrl) (int a) __attribute__ ((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored. Use -fcf-protection option to enable it" } */
+ return arg*(*fptrl)(arg);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-1b.c b/gcc/testsuite/gcc.target/i386/cet-notrack-1b.c
new file mode 100644
index 0000000..6faf88f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-1b.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+" 2 } } */
+
+int func (int a) __attribute__ ((nocf_check));
+int (*fptr) (int a) __attribute__ ((nocf_check));
+
+int foo (int arg)
+{
+int a, b;
+ a = func (arg);
+ b = (*fptr) (arg);
+ return a+b;
+}
+
+int __attribute__ ((nocf_check))
+func (int arg)
+{
+int (*fptrl) (int a) __attribute__ ((nocf_check));
+ return arg*(*fptrl)(arg);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-2a.c b/gcc/testsuite/gcc.target/i386/cet-notrack-2a.c
new file mode 100644
index 0000000..6f441e4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-2a.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+" 1 } } */
+
+void
+bar (void (*foo) (void))
+{
+ void (*func) (void) __attribute__((nocf_check)) = foo; /* { dg-warning "incompatible pointer type" } */
+ func ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-2b.c b/gcc/testsuite/gcc.target/i386/cet-notrack-2b.c
new file mode 100644
index 0000000..0df4645
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-2b.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "notrack jmp\[ \t]+" 1 } } */
+
+void
+bar (void (*foo) (void))
+{
+ void (*func) (void) __attribute__((nocf_check)) = foo; /* { dg-warning "incompatible pointer type" } */
+ func ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-3.c b/gcc/testsuite/gcc.target/i386/cet-notrack-3.c
new file mode 100644
index 0000000..5e124c7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-3.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+" 1 } } */
+
+typedef void (*func_t) (void) __attribute__((nocf_check));
+extern func_t func;
+
+void
+bar (void)
+{
+ func ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-4a.c b/gcc/testsuite/gcc.target/i386/cet-notrack-4a.c
new file mode 100644
index 0000000..34cfd90
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-4a.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-fcf-protection=none -mno-cet" } */
+
+int var1 __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
+int *var2 __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
+void (**var3) (void) __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-4b.c b/gcc/testsuite/gcc.target/i386/cet-notrack-4b.c
new file mode 100644
index 0000000..6065ef6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-4b.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+
+int var1 __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
+int *var2 __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
+void (**var3) (void) __attribute__((nocf_check)); /* { dg-warning "'nocf_check' attribute only applies to function types" } */
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-5a.c b/gcc/testsuite/gcc.target/i386/cet-notrack-5a.c
new file mode 100644
index 0000000..d23968e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-5a.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "\tcall\[ \t]+" } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+" 1 } } */
+
+int (*fptr) (int) __attribute__ ((nocf_check));
+
+int
+foo (int arg)
+{
+ int a;
+ a = (*fptr) (arg); /* notrack call. */
+ return arg+a;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-5b.c b/gcc/testsuite/gcc.target/i386/cet-notrack-5b.c
new file mode 100644
index 0000000..42d9d07
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-5b.c
@@ -0,0 +1,21 @@
+/* Check the attribute do not proparate through assignment. */
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "\tcall\[ \t]+" 1 } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+" 1 } } */
+
+int (*fptr) (int) __attribute__ ((nocf_check));
+int (*fptr1) (int);
+
+int
+foo (int arg)
+{
+ int a;
+ a = (*fptr) (arg); /* non-checked call. */
+ arg += a;
+ fptr1 = fptr; /* { dg-warning "incompatible pointer type" } */
+ a = (*fptr1) (arg); /* checked call. */
+ return arg+a;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-6a.c b/gcc/testsuite/gcc.target/i386/cet-notrack-6a.c
new file mode 100644
index 0000000..e0fb4f9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-6a.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "\t(?:call|jmp)\[ \t]+.*foo" 1 } } */
+/* { dg-final { scan-assembler-not "notrack call\[ \t]+" } } */
+
+int foo (int arg);
+
+int func (int arg)
+{
+ int (*fptrl) (int a) __attribute__ ((nocf_check)) = foo; /* { dg-warning "incompatible pointer type" } */
+
+ return (*fptrl)(arg);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-6b.c b/gcc/testsuite/gcc.target/i386/cet-notrack-6b.c
new file mode 100644
index 0000000..1c47c9f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-6b.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-not "\tcall\[ \t]+" } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+" 1 } } */
+
+int foo (int arg);
+
+int func (int arg)
+{
+ int (*fptrl) (int a) __attribute__ ((nocf_check)) = foo; /* { dg-warning "incompatible pointer type" } */
+
+ return (*fptrl)(arg); /* notrack call. */
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-7.c b/gcc/testsuite/gcc.target/i386/cet-notrack-7.c
new file mode 100644
index 0000000..f2e31d0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-7.c
@@ -0,0 +1,15 @@
+/* Check the notrack prefix is not generated for direct call. */
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "notrack call\[ \t]+.*foo" 0 } } */
+/* { dg-final { scan-assembler-times "\tcall\[ \t]+.*foo" 1 } } */
+
+extern void foo (void) __attribute__((nocf_check));
+
+void
+bar (void)
+{
+ foo ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-icf-1.c b/gcc/testsuite/gcc.target/i386/cet-notrack-icf-1.c
new file mode 100644
index 0000000..7987d53
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-icf-1.c
@@ -0,0 +1,31 @@
+/* Verify nocf_check functions are not ICF optimized. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "endbr" } } */
+/* { dg-final { scan-assembler-not "fn3:" } } */
+/* { dg-final { scan-assembler "set\[ \t]+fn2,fn1" } } */
+/* { dg-final { scan-assembler "set\[ \t]+fn3,fn1" } } */
+
+static __attribute__((noinline)) int
+fn1 (int x)
+{
+ return x + 12;
+}
+
+static __attribute__((noinline)) int
+fn2 (int x)
+{
+ return x + 12;
+}
+
+static __attribute__((noinline, nocf_check)) int
+fn3 (int x)
+{ /* { dg-warning "'nocf_check' attribute ignored. Use -fcf-protection option to enable it" } */
+ return x + 12;
+}
+
+int
+fn4 (int x)
+{
+ return fn1 (x) + fn2 (x) + fn3 (x);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-icf-2.c b/gcc/testsuite/gcc.target/i386/cet-notrack-icf-2.c
new file mode 100644
index 0000000..db0b0a4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-icf-2.c
@@ -0,0 +1,30 @@
+/* Verify nocf_check functions are not ICF optimized. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler "endbr" } } */
+/* { dg-final { scan-assembler "fn3:" } } */
+/* { dg-final { scan-assembler "set\[ \t]+fn2,fn1" } } */
+
+static __attribute__((noinline)) int
+fn1 (int x)
+{
+ return x + 12;
+}
+
+static __attribute__((noinline)) int
+fn2 (int x)
+{
+ return x + 12;
+}
+
+static __attribute__((noinline, nocf_check)) int
+fn3 (int x)
+{
+ return x + 12;
+}
+
+int
+fn4 (int x)
+{
+ return fn1 (x) + fn2 (x) + fn3 (x);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-icf-3.c b/gcc/testsuite/gcc.target/i386/cet-notrack-icf-3.c
new file mode 100644
index 0000000..07c4a6b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-icf-3.c
@@ -0,0 +1,36 @@
+/* Verify nocf_check function calls are not ICF optimized. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "endbr" } } */
+/* { dg-final { scan-assembler-not "fn2:" } } */
+/* { dg-final { scan-assembler "set\[ \t]+fn2,fn1" } } */
+/* { dg-final { scan-assembler "set\[ \t]+fn3,fn1" } } */
+
+int (*foo)(int);
+
+typedef int (*type1_t) (int) __attribute__ ((nocf_check)); /* { dg-warning "'nocf_check' attribute ignored. Use -fcf-protection option to enable it" } */
+typedef int (*type2_t) (int);
+
+static __attribute__((noinline)) int
+fn1 (int x)
+{
+ return ((type2_t)foo)(x + 12);
+}
+
+static __attribute__((noinline)) int
+fn2 (int x)
+{
+ return ((type1_t)foo)(x + 12);
+}
+
+static __attribute__((noinline)) int
+fn3 (int x)
+{
+ return ((type2_t)foo)(x + 12);
+}
+
+int
+fn4 (int x)
+{
+ return fn1 (x) + fn2 (x) + fn3 (x);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-notrack-icf-4.c b/gcc/testsuite/gcc.target/i386/cet-notrack-icf-4.c
new file mode 100644
index 0000000..e4e96aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-notrack-icf-4.c
@@ -0,0 +1,35 @@
+/* Verify nocf_check function calls are not ICF optimized. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler "endbr" } } */
+/* { dg-final { scan-assembler "fn2:" } } */
+/* { dg-final { scan-assembler "set\[ \t]+fn3,fn1" } } */
+
+int (*foo)(int);
+
+typedef int (*type1_t) (int) __attribute__ ((nocf_check));
+typedef int (*type2_t) (int);
+
+static __attribute__((noinline)) int
+fn1 (int x)
+{
+ return ((type2_t)foo)(x + 12);
+}
+
+static __attribute__((noinline)) int
+fn2 (int x)
+{
+ return ((type1_t)foo)(x + 12);
+}
+
+static __attribute__((noinline)) int
+fn3 (int x)
+{
+ return ((type2_t)foo)(x + 12);
+}
+
+int
+fn4 (int x)
+{
+ return fn1 (x) + fn2 (x) + fn3 (x);
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-property-1.c b/gcc/testsuite/gcc.target/i386/cet-property-1.c
new file mode 100644
index 0000000..df243ef
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-property-1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target *-*-linux* } } */
+/* { dg-options "-fcf-protection -mcet" } */
+/* { dg-final { scan-assembler ".note.gnu.property" } } */
+
+extern void foo (void);
+
+void
+bar (void)
+{
+ foo ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-property-2.c b/gcc/testsuite/gcc.target/i386/cet-property-2.c
new file mode 100644
index 0000000..5a87dab
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-property-2.c
@@ -0,0 +1,11 @@
+/* { dg-do compile } */
+/* { dg-options "-mcet" } */
+/* { dg-final { scan-assembler-not ".note.gnu.property" } } */
+
+extern void foo (void);
+
+void
+bar (void)
+{
+ foo ();
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-rdssp-1.c b/gcc/testsuite/gcc.target/i386/cet-rdssp-1.c
new file mode 100644
index 0000000..fb50ff4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-rdssp-1.c
@@ -0,0 +1,39 @@
+/* { dg-do run { target cet } } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+
+void _exit(int status) __attribute__ ((__noreturn__));
+
+#ifdef __x86_64__
+# define incssp(x) __builtin_ia32_incsspq (x)
+# define rdssp(x) __builtin_ia32_rdsspq (x)
+#else
+# define incssp(x) __builtin_ia32_incsspd (x)
+# define rdssp(x) __builtin_ia32_rdsspd (x)
+#endif
+
+static void
+__attribute__ ((noinline, noclone))
+test (unsigned long frames)
+{
+ unsigned long ssp = 0;
+ ssp = rdssp (ssp);
+ if (ssp != 0)
+ {
+ unsigned long tmp = frames;
+ while (tmp > 255)
+ {
+ incssp (tmp);
+ tmp -= 255;
+ }
+ incssp (tmp);
+ }
+ /* We must call _exit since shadow stack is incorrect now. */
+ _exit (0);
+}
+
+int
+main ()
+{
+ test (1);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-sjlj-1.c b/gcc/testsuite/gcc.target/i386/cet-sjlj-1.c
new file mode 100644
index 0000000..374d12a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-sjlj-1.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 4 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 4 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "rdssp\[dq]" 2 } } */
+/* { dg-final { scan-assembler-times "incssp\[dq]" 1 } } */
+
+/* Based on gcc.dg/setjmp-3.c. */
+
+void *buf[5];
+
+extern void abort (void);
+
+void raise0(void)
+{
+ __builtin_longjmp (buf, 1);
+}
+
+int execute(int cmd)
+{
+ int last = 0;
+
+ if (__builtin_setjmp (buf) == 0)
+ while (1)
+ {
+ last = 1;
+ raise0 ();
+ }
+
+ if (last == 0)
+ return 0;
+ else
+ return cmd;
+}
+
+int main(void)
+{
+ if (execute (1) == 0)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-sjlj-2.c b/gcc/testsuite/gcc.target/i386/cet-sjlj-2.c
new file mode 100644
index 0000000..c97094a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-sjlj-2.c
@@ -0,0 +1,4 @@
+/* { dg-do run { target cet } } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+
+#include "cet-sjlj-1.c"
diff --git a/gcc/testsuite/gcc.target/i386/cet-sjlj-3.c b/gcc/testsuite/gcc.target/i386/cet-sjlj-3.c
new file mode 100644
index 0000000..585f4d7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-sjlj-3.c
@@ -0,0 +1,46 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 4 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 4 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "call _?setjmp" 1 } } */
+/* { dg-final { scan-assembler-times "call longjmp" 1 } } */
+
+#include <stdio.h>
+#include <setjmp.h>
+
+jmp_buf buf;
+int bar (int);
+
+int
+foo (int i)
+{
+ int j = i * 11;
+
+ if (!setjmp (buf))
+ {
+ j += 33;
+ printf ("After setjmp: j = %d\n", j);
+ bar (j);
+ }
+
+ return j + i;
+}
+
+int
+bar (int i)
+{
+int j = i;
+
+ j -= 111;
+ printf ("In longjmp: j = %d\n", j);
+ longjmp (buf, 1);
+
+ return j;
+}
+
+int
+main ()
+{
+ foo (10);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-sjlj-4.c b/gcc/testsuite/gcc.target/i386/cet-sjlj-4.c
new file mode 100644
index 0000000..d41406f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-sjlj-4.c
@@ -0,0 +1,45 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 3 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 3 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "rdssp\[dq]" 2 } } */
+/* { dg-final { scan-assembler-times "incssp\[dq]" 1 } } */
+
+/* Based on gcc.dg/setjmp-3.c. */
+
+void *buf[5];
+
+extern void abort (void);
+
+void
+raise0 (void)
+{
+ __builtin_longjmp (buf, 1);
+}
+
+__attribute__ ((noinline, noclone))
+static int
+execute (int cmd)
+{
+ int last = 0;
+
+ if (__builtin_setjmp (buf) == 0)
+ while (1)
+ {
+ last = 1;
+ raise0 ();
+ }
+
+ if (last == 0)
+ return 0;
+ else
+ return cmd;
+}
+
+int main(void)
+{
+ if (execute (1) == 0)
+ abort ();
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-sjlj-5.c b/gcc/testsuite/gcc.target/i386/cet-sjlj-5.c
new file mode 100644
index 0000000..12ea9f4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-sjlj-5.c
@@ -0,0 +1,48 @@
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 2 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 2 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "call _setjmp" 1 } } */
+/* { dg-final { scan-assembler-times "call longjmp" 1 } } */
+
+#include <stdio.h>
+#include <setjmp.h>
+
+jmp_buf buf;
+static int bar (int);
+
+__attribute__ ((noinline, noclone))
+static int
+foo (int i)
+{
+ int j = i * 11;
+
+ if (!setjmp (buf))
+ {
+ j += 33;
+ printf ("After setjmp: j = %d\n", j);
+ bar (j);
+ }
+
+ return j + i;
+}
+
+__attribute__ ((noinline, noclone))
+static int
+bar (int i)
+{
+ int j = i;
+
+ j -= 111;
+ printf ("In longjmp: j = %d\n", j);
+ longjmp (buf, 1);
+
+ return j;
+}
+
+int
+main ()
+{
+ foo (10);
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-switch-1.c b/gcc/testsuite/gcc.target/i386/cet-switch-1.c
new file mode 100644
index 0000000..7a75857
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-switch-1.c
@@ -0,0 +1,26 @@
+/* Verify that CET works. */
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times "endbr32" 1 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 1 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "notrack jmp\[ \t]+\[*]" 1 } } */
+
+void func2 (int);
+
+int func1 (int arg)
+{
+ switch (arg)
+ {
+ case 1: func2 (arg*100);
+ case 2: func2 (arg*300);
+ case 5: func2 (arg*500);
+ case 8: func2 (arg*700);
+ case 7: func2 (arg*900);
+ case -1: func2 (arg*-100);
+ case -2: func2 (arg*-300);
+ case -5: func2 (arg*-500);
+ case -7: func2 (arg*-700);
+ case -9: func2 (arg*-900);
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-switch-2.c b/gcc/testsuite/gcc.target/i386/cet-switch-2.c
new file mode 100644
index 0000000..e620b83
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-switch-2.c
@@ -0,0 +1,26 @@
+/* Verify that CET works. */
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet -mcet-switch" } */
+/* { dg-final { scan-assembler-times "endbr32" 12 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 12 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "\[ \t]+jmp\[ \t]+\[*]" 1 } } */
+
+void func2 (int);
+
+int func1 (int arg)
+{
+ switch (arg)
+ {
+ case 1: func2 (arg*100);
+ case 2: func2 (arg*300);
+ case 5: func2 (arg*500);
+ case 8: func2 (arg*700);
+ case 7: func2 (arg*900);
+ case -1: func2 (arg*-100);
+ case -2: func2 (arg*-300);
+ case -5: func2 (arg*-500);
+ case -7: func2 (arg*-700);
+ case -9: func2 (arg*-900);
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/cet-switch-3.c b/gcc/testsuite/gcc.target/i386/cet-switch-3.c
new file mode 100644
index 0000000..9b1b436
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/cet-switch-3.c
@@ -0,0 +1,34 @@
+/* Verify that CET works. */
+/* { dg-do compile } */
+/* { dg-options "-O -fcf-protection -mcet -mcet-switch" } */
+/* { dg-final { scan-assembler-times "endbr32" 12 { target ia32 } } } */
+/* { dg-final { scan-assembler-times "endbr64" 12 { target { ! ia32 } } } } */
+/* { dg-final { scan-assembler-times "\[ \t]+jmp\[ \t]+\[*]" 1 } } */
+
+void func2 (int);
+
+__attribute__ ((noinline, noclone))
+static int
+func1 (int arg)
+{
+ switch (arg)
+ {
+ case 1: func2 (arg*100);
+ case 2: func2 (arg*300);
+ case 5: func2 (arg*500);
+ case 8: func2 (arg*700);
+ case 7: func2 (arg*900);
+ case -1: func2 (arg*-100);
+ case -2: func2 (arg*-300);
+ case -5: func2 (arg*-500);
+ case -7: func2 (arg*-700);
+ case -9: func2 (arg*-900);
+ }
+ return 0;
+}
+
+int
+foo (int arg)
+{
+ return func1 (arg);
+}
diff --git a/gcc/testsuite/gcc.target/i386/funcspec-56.inc b/gcc/testsuite/gcc.target/i386/funcspec-56.inc
index 746c9cf..9ae74cb 100644
--- a/gcc/testsuite/gcc.target/i386/funcspec-56.inc
+++ b/gcc/testsuite/gcc.target/i386/funcspec-56.inc
@@ -142,6 +142,7 @@ extern void test_arch_corei7 (void) __attribute__((__target__("arch=corei7")));
extern void test_arch_corei7_avx (void) __attribute__((__target__("arch=corei7-avx")));
extern void test_arch_core_avx2 (void) __attribute__((__target__("arch=core-avx2")));
extern void test_arch_knl (void) __attribute__((__target__("arch=knl")));
+extern void test_arch_knm (void) __attribute__((__target__("arch=knm")));
extern void test_arch_skylake_avx512 (void) __attribute__((__target__("arch=skylake-avx512")));
extern void test_arch_k8 (void) __attribute__((__target__("arch=k8")));
extern void test_arch_k8_sse3 (void) __attribute__((__target__("arch=k8-sse3")));
diff --git a/gcc/testsuite/gcc.target/i386/pr79683.c b/gcc/testsuite/gcc.target/i386/pr79683.c
index cbd43fd..9e28d85 100644
--- a/gcc/testsuite/gcc.target/i386/pr79683.c
+++ b/gcc/testsuite/gcc.target/i386/pr79683.c
@@ -1,5 +1,5 @@
/* { dg-do compile } */
-/* { dg-options "-O3 -msse2" } */
+/* { dg-options "-O3 -msse2 -fvect-cost-model=unlimited" } */
struct s {
__INT64_TYPE__ a;
diff --git a/gcc/testsuite/gcc.target/i386/pr80732.c b/gcc/testsuite/gcc.target/i386/pr80732.c
index e120729..0a1f827 100644
--- a/gcc/testsuite/gcc.target/i386/pr80732.c
+++ b/gcc/testsuite/gcc.target/i386/pr80732.c
@@ -34,7 +34,7 @@ static double f2_default(double a, double b, double c)
return a * b + c;
}
-static void *f2_resolve(void)
+static __typeof__ (f2_fma)* f2_resolve(void)
{
__builtin_cpu_init ();
if (__builtin_cpu_supports("fma"))
diff --git a/gcc/testsuite/gcc.target/i386/pr81481.c b/gcc/testsuite/gcc.target/i386/pr81481.c
new file mode 100644
index 0000000..a5b936f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr81481.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-require-effective-target ssse3 } */
+/* { dg-options "-O2 -fpic -mssse3" } */
+/* { dg-final { scan-assembler-not "pshufb\[ \t\]\\(%esp\\)" } } */
+#include <immintrin.h>
+
+extern const signed char c[31] __attribute__((visibility("hidden")));
+
+__m128i f(__m128i *x, void *v)
+{
+ int i;
+ asm("# %0" : "=r"(i));
+ __m128i t = _mm_loadu_si128((void*)&c[i]);
+ __m128i xx = *x;
+ xx = _mm_shuffle_epi8(xx, t);
+ asm("# %0 %1 %2" : "+x"(xx) : "r"(c), "r"(i));
+ return xx;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82196-1.c b/gcc/testsuite/gcc.target/i386/pr82196-1.c
index ef85832..541d975 100644
--- a/gcc/testsuite/gcc.target/i386/pr82196-1.c
+++ b/gcc/testsuite/gcc.target/i386/pr82196-1.c
@@ -1,7 +1,7 @@
/* { dg-do compile { target lp64 } } */
/* { dg-options "-msse -mcall-ms2sysv-xlogues -O2" } */
-/* { dg-final { scan-assembler "call.*__sse_savms64_18" } } */
-/* { dg-final { scan-assembler "jmp.*__sse_resms64x_18" } } */
+/* { dg-final { scan-assembler "call.*__sse_savms64f?_12" } } */
+/* { dg-final { scan-assembler "jmp.*__sse_resms64f?x_12" } } */
void __attribute__((sysv_abi)) a() {
}
@@ -9,6 +9,5 @@ void __attribute__((sysv_abi)) a() {
static void __attribute__((sysv_abi)) (*volatile a_noinfo)() = a;
void __attribute__((ms_abi)) b() {
- __asm__ __volatile__ ("" :::"rbx", "rbp", "r12", "r13", "r14", "r15");
a_noinfo ();
}
diff --git a/gcc/testsuite/gcc.target/i386/pr82196-2.c b/gcc/testsuite/gcc.target/i386/pr82196-2.c
index 8fe5841..7166d06 100644
--- a/gcc/testsuite/gcc.target/i386/pr82196-2.c
+++ b/gcc/testsuite/gcc.target/i386/pr82196-2.c
@@ -1,7 +1,7 @@
/* { dg-do compile { target lp64 } } */
/* { dg-options "-mavx -mcall-ms2sysv-xlogues -O2" } */
-/* { dg-final { scan-assembler "call.*__avx_savms64_18" } } */
-/* { dg-final { scan-assembler "jmp.*__avx_resms64x_18" } } */
+/* { dg-final { scan-assembler "call.*__avx_savms64f?_12" } } */
+/* { dg-final { scan-assembler "jmp.*__avx_resms64f?x_12" } } */
void __attribute__((sysv_abi)) a() {
}
@@ -9,6 +9,5 @@ void __attribute__((sysv_abi)) a() {
static void __attribute__((sysv_abi)) (*volatile a_noinfo)() = a;
void __attribute__((ms_abi)) b() {
- __asm__ __volatile__ ("" :::"rbx", "rbp", "r12", "r13", "r14", "r15");
a_noinfo ();
}
diff --git a/gcc/testsuite/gcc.target/i386/pr82260-1.c b/gcc/testsuite/gcc.target/i386/pr82260-1.c
new file mode 100644
index 0000000..3804fcc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82260-1.c
@@ -0,0 +1,26 @@
+/* PR target/82260 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-Os -mtune=generic -masm=att -mno-bmi2" } */
+/* movl %esi, %ecx is shorter than movb %sil, %cl. While
+ movl %edx, %ecx is the same size as movb %dl, %cl and
+ movl %r8d, %ecx is the same size as movb %r8b, %cl, movl
+ is faster on contemporary CPUs. */
+/* { dg-final { scan-assembler-not {\mmovb\M} } } */
+
+int
+foo (int x, int c)
+{
+ return x >> c;
+}
+
+int
+bar (int x, int y, int z)
+{
+ return x >> z;
+}
+
+int
+baz (int x, int y, int z, int u, int v)
+{
+ return x >> v;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82260-2.c b/gcc/testsuite/gcc.target/i386/pr82260-2.c
new file mode 100644
index 0000000..14328fc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82260-2.c
@@ -0,0 +1,25 @@
+/* PR target/82260 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-Os -mtune=generic -masm=att -mtune-ctrl=^partial_reg_dependency -mno-bmi2" } */
+/* { dg-final { scan-assembler-not {\mmovb\t%sil, %cl} } } */
+/* { dg-final { scan-assembler {\mmovl\t%esi, %ecx} } } */
+/* { dg-final { scan-assembler {\mmovb\t%dl, %cl} } } */
+/* { dg-final { scan-assembler {\mmovb\t%r8b, %cl} } } */
+
+int
+foo (int x, int c)
+{
+ return x >> c;
+}
+
+int
+bar (int x, int y, int z)
+{
+ return x >> z;
+}
+
+int
+baz (int x, int y, int z, int u, int v)
+{
+ return x >> v;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82267.c b/gcc/testsuite/gcc.target/i386/pr82267.c
new file mode 100644
index 0000000..5e4b271
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82267.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { ! ia32 } } } */
+/* { dg-require-effective-target maybe_x32 } */
+/* { dg-options "-O2 -mx32 -maddress-mode=short" } */
+
+int
+stackuse (void)
+{
+ volatile int foo = 2;
+ return foo * 3;
+}
+
+/* Verify we that use %rsp to access stack. */
+/* { dg-final { scan-assembler-not "%esp" } } */
+/* { dg-final { scan-assembler "%rsp" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr82361-1.c b/gcc/testsuite/gcc.target/i386/pr82361-1.c
new file mode 100644
index 0000000..fbef3c9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82361-1.c
@@ -0,0 +1,53 @@
+/* PR target/82361 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -mtune=generic -masm=att -mno-8bit-idiv" } */
+/* We should be able to optimize all %eax to %rax zero extensions, because
+ div and idiv instructions with 32-bit operands zero-extend both results. */
+/* { dg-final { scan-assembler-not "movl\t%eax, %eax" } } */
+/* FIXME: We are still not able to optimize the modulo in f1/f2, only manage
+ one. */
+/* { dg-final { scan-assembler-times "movl\t%edx, %edx" 2 } } */
+
+void
+f1 (unsigned int a, unsigned int b)
+{
+ unsigned long long c = a / b;
+ unsigned long long d = a % b;
+ asm volatile ("" : : "r" (c), "r" (d));
+}
+
+void
+f2 (int a, int b)
+{
+ unsigned long long c = (unsigned int) (a / b);
+ unsigned long long d = (unsigned int) (a % b);
+ asm volatile ("" : : "r" (c), "r" (d));
+}
+
+void
+f3 (unsigned int a, unsigned int b)
+{
+ unsigned long long c = a / b;
+ asm volatile ("" : : "r" (c));
+}
+
+void
+f4 (int a, int b)
+{
+ unsigned long long c = (unsigned int) (a / b);
+ asm volatile ("" : : "r" (c));
+}
+
+void
+f5 (unsigned int a, unsigned int b)
+{
+ unsigned long long d = a % b;
+ asm volatile ("" : : "r" (d));
+}
+
+void
+f6 (int a, int b)
+{
+ unsigned long long d = (unsigned int) (a % b);
+ asm volatile ("" : : "r" (d));
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82361-2.c b/gcc/testsuite/gcc.target/i386/pr82361-2.c
new file mode 100644
index 0000000..c1e484d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82361-2.c
@@ -0,0 +1,10 @@
+/* PR target/82361 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -mtune=generic -masm=att -m8bit-idiv" } */
+/* We should be able to optimize all %eax to %rax zero extensions, because
+ div and idiv instructions with 32-bit operands zero-extend both results. */
+/* { dg-final { scan-assembler-not "movl\t%eax, %eax" } } */
+/* Ditto %edx to %rdx zero extensions. */
+/* { dg-final { scan-assembler-not "movl\t%edx, %edx" } } */
+
+#include "pr82361-1.c"
diff --git a/gcc/testsuite/gcc.target/i386/pr82370.c b/gcc/testsuite/gcc.target/i386/pr82370.c
new file mode 100644
index 0000000..cc4d9b6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82370.c
@@ -0,0 +1,18 @@
+/* PR target/82370 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx512vl -mavx512bw -masm=att" } */
+/* { dg-final { scan-assembler-times "vpslldq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrldq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %xmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslldq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrldq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %ymm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpslldq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+/* { dg-final { scan-assembler-times "vpsrldq\[ \t]\+\\\$5, \\(%\[a-z0-9,]*\\), %zmm\[0-9]\+" 1 } } */
+
+#include <x86intrin.h>
+
+__m512i f1 (__m512i *x) { return _mm512_bslli_epi128 (*x, 5); }
+__m512i f2 (__m512i *x) { return _mm512_bsrli_epi128 (*x, 5); }
+__m256i f3 (__m256i *x) { return _mm256_bslli_epi128 (*x, 5); }
+__m256i f4 (__m256i *x) { return _mm256_bsrli_epi128 (*x, 5); }
+__m128i f5 (__m128i *x) { return _mm_bslli_si128 (*x, 5); }
+__m128i f6 (__m128i *x) { return _mm_bsrli_si128 (*x, 5); }
diff --git a/gcc/testsuite/gcc.target/i386/pr82460-1.c b/gcc/testsuite/gcc.target/i386/pr82460-1.c
new file mode 100644
index 0000000..6529c4a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82460-1.c
@@ -0,0 +1,30 @@
+/* PR target/82460 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mavx512vbmi" } */
+/* { dg-final { scan-assembler-not {\mvmovd} } } */
+
+#include <x86intrin.h>
+
+__m512i
+f1 (__m512i x, __m512i y, char *z)
+{
+ return _mm512_permutex2var_epi32 (y, x, _mm512_loadu_si512 (z));
+}
+
+__m512i
+f2 (__m512i x, __m512i y, char *z)
+{
+ return _mm512_permutex2var_epi32 (x, y, _mm512_loadu_si512 (z));
+}
+
+__m512i
+f3 (__m512i x, __m512i y, __m512i z)
+{
+ return _mm512_permutex2var_epi8 (y, x, z);
+}
+
+__m512i
+f4 (__m512i x, __m512i y, __m512i z)
+{
+ return _mm512_permutex2var_epi8 (x, y, z);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82460-2.c b/gcc/testsuite/gcc.target/i386/pr82460-2.c
new file mode 100644
index 0000000..4d96521
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82460-2.c
@@ -0,0 +1,17 @@
+/* PR target/82460 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftree-vectorize -mavx512vbmi -mno-prefer-avx256" } */
+/* We want to reuse the permutation mask in the loop, so use vpermt2b rather
+ than vpermi2b. */
+/* { dg-final { scan-assembler-not {\mvpermi2b\M} } } */
+/* { dg-final { scan-assembler {\mvpermt2b\M} } } */
+
+void
+foo (unsigned char *__restrict__ x, const unsigned short *__restrict__ y,
+ unsigned long z)
+{
+ unsigned char *w = x + z;
+ do
+ *x++ = *y++ >> 8;
+ while (x < w);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82483-1.c b/gcc/testsuite/gcc.target/i386/pr82483-1.c
new file mode 100644
index 0000000..59a59dc8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82483-1.c
@@ -0,0 +1,44 @@
+/* PR target/82483 */
+/* { dg-do compile } */
+/* { dg-options "-mssse3 -mno-mmx -Wno-psabi" } */
+/* { dg-error "needs isa option" "" { target *-*-* } 0 } */
+
+#include <x86intrin.h>
+
+void f1 (__m64 x, __m64 y, char *z) { _mm_maskmove_si64 (x, y, z); }
+int f2 (__m64 x) { return _mm_extract_pi16 (x, 1); }
+__m64 f3 (__m64 x, int y) { return _mm_insert_pi16 (x, y, 1); }
+__m64 f4 (__m128 x) { return _mm_cvtps_pi32 (x); }
+__m64 f5 (__m128 x) { return _mm_cvttps_pi32 (x); }
+__m128 f6 (__m128 x, __m64 y) { return _mm_cvtpi32_ps (x, y); }
+__m64 f7 (__m64 x, __m64 y) { return _mm_avg_pu8 (x, y); }
+__m64 f8 (__m64 x, __m64 y) { return _mm_avg_pu16 (x, y); }
+__m64 f9 (__m64 x, __m64 y) { return _mm_mulhi_pu16 (x, y); }
+__m64 f10 (__m64 x, __m64 y) { return _mm_max_pu8 (x, y); }
+__m64 f11 (__m64 x, __m64 y) { return _mm_max_pi16 (x, y); }
+__m64 f12 (__m64 x, __m64 y) { return _mm_min_pu8 (x, y); }
+__m64 f13 (__m64 x, __m64 y) { return _mm_min_pi16 (x, y); }
+__m64 f14 (__m64 x, __m64 y) { return _mm_sad_pu8 (x, y); }
+int f15 (__m64 x) { return _mm_movemask_pi8 (x); }
+__m64 f16 (__m64 x) { return _mm_shuffle_pi16 (x, 1); }
+__m64 f17 (__m128d x) { return _mm_cvtpd_pi32 (x); }
+__m64 f18 (__m128d x) { return _mm_cvttpd_pi32 (x); }
+__m128d f19 (__m64 x) { return _mm_cvtpi32_pd (x); }
+__m64 f20 (__m64 x, __m64 y) { return _mm_mul_su32 (x, y); }
+__m64 f21 (__m64 x) { return _mm_abs_pi8 (x); }
+__m64 f22 (__m64 x) { return _mm_abs_pi16 (x); }
+__m64 f23 (__m64 x) { return _mm_abs_pi32 (x); }
+__m64 f24 (__m64 x, __m64 y) { return _mm_hadd_pi16 (x, y); }
+__m64 f25 (__m64 x, __m64 y) { return _mm_hadd_pi32 (x, y); }
+__m64 f26 (__m64 x, __m64 y) { return _mm_hadds_pi16 (x, y); }
+__m64 f27 (__m64 x, __m64 y) { return _mm_hsub_pi16 (x, y); }
+__m64 f28 (__m64 x, __m64 y) { return _mm_hsub_pi32 (x, y); }
+__m64 f29 (__m64 x, __m64 y) { return _mm_hsubs_pi16 (x, y); }
+__m64 f30 (__m64 x, __m64 y) { return _mm_maddubs_pi16 (x, y); }
+__m64 f31 (__m64 x, __m64 y) { return _mm_mulhrs_pi16 (x, y); }
+__m64 f32 (__m64 x, __m64 y) { return _mm_shuffle_pi8 (x, y); }
+__m64 f33 (__m64 x, __m64 y) { return _mm_sign_pi8 (x, y); }
+__m64 f34 (__m64 x, __m64 y) { return _mm_sign_pi16 (x, y); }
+__m64 f35 (__m64 x, __m64 y) { return _mm_sign_pi32 (x, y); }
+void f36 (__m64 *x, __m64 y) { _mm_stream_pi (x, y); }
+__m64 f37 (__m64 x, __m64 y) { return _mm_alignr_pi8 (x, y, 3); }
diff --git a/gcc/testsuite/gcc.target/i386/pr82483-2.c b/gcc/testsuite/gcc.target/i386/pr82483-2.c
new file mode 100644
index 0000000..305ddbd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82483-2.c
@@ -0,0 +1,9 @@
+/* PR target/82483 */
+/* { dg-do compile } */
+/* { dg-options "-mssse3 -mno-mmx -Wno-psabi" } */
+/* { dg-error "needs isa option" "" { target *-*-* } 0 } */
+
+#include <x86intrin.h>
+
+__v1di f1 (__v1di x, __v1di y) { return __builtin_ia32_paddq (x, y); }
+__v1di f2 (__v1di x, __v1di y) { return __builtin_ia32_psubq (x, y); }
diff --git a/gcc/testsuite/gcc.target/i386/pr82498-1.c b/gcc/testsuite/gcc.target/i386/pr82498-1.c
new file mode 100644
index 0000000..78a6698
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82498-1.c
@@ -0,0 +1,52 @@
+/* PR target/82498 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=generic -masm=att" } */
+/* { dg-final { scan-assembler-not {\mand[bwlq]\M} } } */
+
+unsigned
+f1 (unsigned x, unsigned char y)
+{
+ if (y == 0)
+ return x;
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f2 (unsigned x, unsigned y)
+{
+ if (y == 0)
+ return x;
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f3 (unsigned x, unsigned short y)
+{
+ if (y == 0)
+ return x;
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return (x << y) | (x >> (__CHAR_BIT__ * __SIZEOF_INT__ - y));
+}
+
+unsigned
+f4 (unsigned x, unsigned char y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return (x << y) | (x >> (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned
+f5 (unsigned x, unsigned int y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return (x << y) | (x >> (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
+
+unsigned
+f6 (unsigned x, unsigned short y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return (x << y) | (x >> (-y & (__CHAR_BIT__ * __SIZEOF_INT__ - 1)));
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82498-2.c b/gcc/testsuite/gcc.target/i386/pr82498-2.c
new file mode 100644
index 0000000..9e065ee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82498-2.c
@@ -0,0 +1,46 @@
+/* PR target/82498 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -mtune=generic -masm=att" } */
+/* { dg-final { scan-assembler-not {\mand[bwlq]\M} } } */
+
+int
+f1 (int x, unsigned char y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return x >> y;
+}
+
+unsigned
+f2 (unsigned x, unsigned char y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return x >> y;
+}
+
+unsigned
+f3 (unsigned x, unsigned char y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return x << y;
+}
+
+unsigned
+f4 (unsigned x, unsigned char y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return x | (1U << y);
+}
+
+unsigned
+f5 (unsigned x, unsigned char y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return x ^ (1U << y);
+}
+
+unsigned
+f6 (unsigned x, unsigned char y)
+{
+ y &= __CHAR_BIT__ * __SIZEOF_INT__ - 1;
+ return (x + 2) & ~(1U << y);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82499-1.c b/gcc/testsuite/gcc.target/i386/pr82499-1.c
new file mode 100644
index 0000000..3aba62a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82499-1.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* The pic register save adds unavoidable stack pointer references. */
+/* { dg-skip-if "" { ia32 && { ! nonpic } } } */
+/* These options are selected to ensure 1 word needs to be allocated
+ on the stack to maintain alignment for the call. This should be
+ transformed to push+pop. We also want to force unwind info updates. */
+/* { dg-options "-Os -fomit-frame-pointer -fasynchronous-unwind-tables" } */
+/* { dg-additional-options "-mpreferred-stack-boundary=3" { target ia32 } } */
+/* { dg-additional-options "-mpreferred-stack-boundary=4" { target { ! ia32 } } } */
+/* ms_abi has reserved stack-region. */
+/* { dg-skip-if "" { x86_64-*-mingw* } } */
+
+extern void g (void);
+int
+f (void)
+{
+ g ();
+ return 42;
+}
+
+/* { dg-final { scan-assembler-not "(sub|add)(l|q)\[\\t \]*\\$\[0-9\]*,\[\\t \]*%\[re\]?sp" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr82499-2.c b/gcc/testsuite/gcc.target/i386/pr82499-2.c
new file mode 100644
index 0000000..dde4d65
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82499-2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* The pic register save adds unavoidable stack pointer references. */
+/* { dg-skip-if "" { ia32 && { ! nonpic } } } */
+/* These options are selected to ensure 1 word needs to be allocated
+ on the stack to maintain alignment for the call. This should be
+ transformed to push+pop. We also want to force unwind info updates. */
+/* { dg-options "-Os -fomit-frame-pointer -fasynchronous-unwind-tables" } */
+/* { dg-additional-options "-mpreferred-stack-boundary=3" { target ia32 } } */
+/* { dg-additional-options "-mpreferred-stack-boundary=4 -mno-red-zone" { target { ! ia32 } } } */
+/* ms_abi has reserved stack-region. */
+/* { dg-skip-if "" { x86_64-*-mingw* } } */
+
+extern void g (void);
+int
+f (void)
+{
+ g ();
+ return 42;
+}
+
+/* { dg-final { scan-assembler-not "(sub|add)(l|q)\[\\t \]*\\$\[0-9\]*,\[\\t \]*%\[re\]?sp" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr82499-3.c b/gcc/testsuite/gcc.target/i386/pr82499-3.c
new file mode 100644
index 0000000..b55a860
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82499-3.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* The pic register save adds unavoidable stack pointer references. */
+/* { dg-skip-if "" { ia32 && { ! nonpic } } } */
+/* These options are selected to ensure 1 word needs to be allocated
+ on the stack to maintain alignment for the call. This should be
+ transformed to push+pop. We also want to force unwind info updates. */
+/* { dg-options "-O2 -mtune-ctrl=single_push,single_pop -fomit-frame-pointer -fasynchronous-unwind-tables" } */
+/* { dg-additional-options "-mpreferred-stack-boundary=3" { target ia32 } } */
+/* { dg-additional-options "-mpreferred-stack-boundary=4" { target { ! ia32 } } } */
+/* ms_abi has reserved stack-region. */
+/* { dg-skip-if "" { x86_64-*-mingw* } } */
+
+extern void g (void);
+int
+f (void)
+{
+ g ();
+ return 42;
+}
+
+/* { dg-final { scan-assembler-not "(sub|add)(l|q)\[\\t \]*\\$\[0-9\]*,\[\\t \]*%\[re\]?sp" } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr82556.c b/gcc/testsuite/gcc.target/i386/pr82556.c
new file mode 100644
index 0000000..409a301
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82556.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-strict-aliasing -fwrapv -fexcess-precision=standard" } */
+extern int foo();
+typedef struct {
+ char id;
+ unsigned char fork_flags;
+ short data_length;
+} Header;
+int a;
+void X() {
+ do {
+ char* b;
+ Header c;
+ if (a)
+ c.fork_flags |= 1;
+ __builtin_memcpy(b, &c, __builtin_offsetof(Header, data_length));
+ b += foo();
+ } while (1);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82580.c b/gcc/testsuite/gcc.target/i386/pr82580.c
new file mode 100644
index 0000000..965dfee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82580.c
@@ -0,0 +1,39 @@
+/* PR target/82580 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#ifdef __SIZEOF_INT128__
+typedef unsigned __int128 U;
+typedef signed __int128 S;
+#else
+typedef unsigned long long U;
+typedef signed long long S;
+#endif
+void bar (void);
+int f0 (U x, U y) { return x == y; }
+int f1 (U x, U y) { return x != y; }
+int f2 (U x, U y) { return x > y; }
+int f3 (U x, U y) { return x >= y; }
+int f4 (U x, U y) { return x < y; }
+int f5 (U x, U y) { return x <= y; }
+int f6 (S x, S y) { return x == y; }
+int f7 (S x, S y) { return x != y; }
+int f8 (S x, S y) { return x > y; }
+int f9 (S x, S y) { return x >= y; }
+int f10 (S x, S y) { return x < y; }
+int f11 (S x, S y) { return x <= y; }
+void f12 (U x, U y) { if (x == y) bar (); }
+void f13 (U x, U y) { if (x != y) bar (); }
+void f14 (U x, U y) { if (x > y) bar (); }
+void f15 (U x, U y) { if (x >= y) bar (); }
+void f16 (U x, U y) { if (x < y) bar (); }
+void f17 (U x, U y) { if (x <= y) bar (); }
+void f18 (S x, S y) { if (x == y) bar (); }
+void f19 (S x, S y) { if (x != y) bar (); }
+void f20 (S x, S y) { if (x > y) bar (); }
+void f21 (S x, S y) { if (x >= y) bar (); }
+void f22 (S x, S y) { if (x < y) bar (); }
+void f23 (S x, S y) { if (x <= y) bar (); }
+
+/* { dg-final { scan-assembler-times {\msbb} 16 } } */
+/* { dg-final { scan-assembler-not {\mmovzb} { target lp64 } } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr82618.c b/gcc/testsuite/gcc.target/i386/pr82618.c
new file mode 100644
index 0000000..f6e3589
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82618.c
@@ -0,0 +1,18 @@
+/* PR target/82618 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#ifdef __SIZEOF_INT128__
+typedef unsigned __int128 U;
+typedef unsigned long long H;
+#else
+typedef unsigned long long U;
+typedef unsigned int H;
+#endif
+
+H f0 (U x, U y)
+{
+ return (x - y) >> (__CHAR_BIT__ * sizeof (H));
+}
+
+/* { dg-final { scan-assembler {\mcmp} } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr82628.c b/gcc/testsuite/gcc.target/i386/pr82628.c
new file mode 100644
index 0000000..d713522
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82628.c
@@ -0,0 +1,34 @@
+/* { dg-do run { target ia32 } } */
+/* { dg-options "-Os" } */
+
+void
+__attribute__ ((noipa))
+foo (const char *x)
+{
+ asm volatile ("" : "+g" (x) : : "memory");
+ if (x)
+ __builtin_abort ();
+}
+
+int a, b = 1;
+
+int
+main ()
+{
+ while (1)
+ {
+ unsigned long long d = 18446744073709551615UL;
+ while (1)
+ {
+ int e = b;
+ while (d < 2)
+ foo ("0");
+ if (a)
+ d++;
+ if (b)
+ break;
+ }
+ break;
+ }
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82659-1.c b/gcc/testsuite/gcc.target/i386/pr82659-1.c
new file mode 100644
index 0000000..485771d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82659-1.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+
+extern int x;
+
+static void
+__attribute__ ((noinline, noclone))
+test (int i)
+{
+ x = i;
+}
+
+void
+bar (int i)
+{
+ test (i);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82659-2.c b/gcc/testsuite/gcc.target/i386/pr82659-2.c
new file mode 100644
index 0000000..7afffa4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82659-2.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+extern int x;
+
+void
+test (int i)
+{
+ x = i;
+}
+
+void
+bar (int i)
+{
+ test (i);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82659-3.c b/gcc/testsuite/gcc.target/i386/pr82659-3.c
new file mode 100644
index 0000000..5f97b31
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82659-3.c
@@ -0,0 +1,20 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+extern int x;
+
+static void
+__attribute__ ((noinline, noclone))
+test (int i)
+{
+ x = i;
+}
+
+extern __typeof (test) foo __attribute__ ((alias ("test")));
+
+void
+bar (int i)
+{
+ test (i);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82659-4.c b/gcc/testsuite/gcc.target/i386/pr82659-4.c
new file mode 100644
index 0000000..c3cacac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82659-4.c
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+static void
+test (void)
+{
+}
+
+void *
+bar (void)
+{
+ return test;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82659-5.c b/gcc/testsuite/gcc.target/i386/pr82659-5.c
new file mode 100644
index 0000000..9541367
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82659-5.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times {\mendbr} 1 } } */
+
+static void
+test (void)
+{
+}
+
+void (*test_p) (void) = test;
diff --git a/gcc/testsuite/gcc.target/i386/pr82659-6.c b/gcc/testsuite/gcc.target/i386/pr82659-6.c
new file mode 100644
index 0000000..51fc1a9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82659-6.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fcf-protection -mcet" } */
+/* { dg-final { scan-assembler-times {\mendbr} 2 } } */
+
+extern int x;
+
+ __attribute__ ((visibility ("hidden")))
+void
+test (int i)
+{
+ x = i;
+}
+
+void
+bar (int i)
+{
+ test (i);
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82662.c b/gcc/testsuite/gcc.target/i386/pr82662.c
new file mode 100644
index 0000000..8a9332b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82662.c
@@ -0,0 +1,26 @@
+/* PR target/82580 */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#ifdef __SIZEOF_INT128__
+typedef unsigned __int128 U;
+typedef signed __int128 S;
+#else
+typedef unsigned long long U;
+typedef signed long long S;
+#endif
+void bar (void);
+int f0 (U x, U y) { return x == y; }
+int f1 (U x, U y) { return x != y; }
+int f2 (U x, U y) { return x > y; }
+int f3 (U x, U y) { return x >= y; }
+int f4 (U x, U y) { return x < y; }
+int f5 (U x, U y) { return x <= y; }
+int f6 (S x, S y) { return x == y; }
+int f7 (S x, S y) { return x != y; }
+int f8 (S x, S y) { return x > y; }
+int f9 (S x, S y) { return x >= y; }
+int f10 (S x, S y) { return x < y; }
+int f11 (S x, S y) { return x <= y; }
+
+/* { dg-final { scan-assembler-times {\mset} 12 } } */
diff --git a/gcc/testsuite/gcc.target/i386/pr82673.c b/gcc/testsuite/gcc.target/i386/pr82673.c
new file mode 100644
index 0000000..50eb5a3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr82673.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-O0 -fno-omit-frame-pointer -fvar-tracking-assignments" } */
+
+register long *B asm ("ebp");
+
+long y = 20;
+
+void
+bar (void) /* { dg-error "frame pointer required, but reserved" } */
+{
+ B = &y;
+} /* { dg-error "bp cannot be used in asm here" } */
diff --git a/gcc/testsuite/gcc.target/i386/sse-13.c b/gcc/testsuite/gcc.target/i386/sse-13.c
index c5c43b1..7ab2223 100644
--- a/gcc/testsuite/gcc.target/i386/sse-13.c
+++ b/gcc/testsuite/gcc.target/i386/sse-13.c
@@ -429,8 +429,8 @@
/* avx512dqintrin.h */
#define __builtin_ia32_kshiftliqi(A, B) __builtin_ia32_kshiftliqi(A, 8)
#define __builtin_ia32_kshiftriqi(A, B) __builtin_ia32_kshiftriqi(A, 8)
-#define __builtin_ia32_reducess(A, B, F) __builtin_ia32_reducess(A, B, 1)
-#define __builtin_ia32_reducesd(A, B, F) __builtin_ia32_reducesd(A, B, 1)
+#define __builtin_ia32_reducess_mask(A, B, F, W, U) __builtin_ia32_reducess_mask(A, B, 1, W, U)
+#define __builtin_ia32_reducesd_mask(A, B, F, W, U) __builtin_ia32_reducesd_mask(A, B, 1, W, U)
#define __builtin_ia32_reduceps512_mask(A, E, C, D) __builtin_ia32_reduceps512_mask(A, 1, C, D)
#define __builtin_ia32_reducepd512_mask(A, E, C, D) __builtin_ia32_reducepd512_mask(A, 1, C, D)
#define __builtin_ia32_rangess128_round(A, B, I, F) __builtin_ia32_rangess128_round(A, B, 1, 8)
diff --git a/gcc/testsuite/gcc.target/i386/sse-23.c b/gcc/testsuite/gcc.target/i386/sse-23.c
index fc339a5..3a90e54 100644
--- a/gcc/testsuite/gcc.target/i386/sse-23.c
+++ b/gcc/testsuite/gcc.target/i386/sse-23.c
@@ -428,8 +428,8 @@
/* avx512dqintrin.h */
#define __builtin_ia32_kshiftliqi(A, B) __builtin_ia32_kshiftliqi(A, 8)
#define __builtin_ia32_kshiftriqi(A, B) __builtin_ia32_kshiftriqi(A, 8)
-#define __builtin_ia32_reducess(A, B, F) __builtin_ia32_reducess(A, B, 1)
-#define __builtin_ia32_reducesd(A, B, F) __builtin_ia32_reducesd(A, B, 1)
+#define __builtin_ia32_reducess_mask(A, B, F, W, U) __builtin_ia32_reducess_mask(A, B, 1, W, U)
+#define __builtin_ia32_reducesd_mask(A, B, F, W, U) __builtin_ia32_reducesd_mask(A, B, 1, W, U)
#define __builtin_ia32_reduceps512_mask(A, E, C, D) __builtin_ia32_reduceps512_mask(A, 1, C, D)
#define __builtin_ia32_reducepd512_mask(A, E, C, D) __builtin_ia32_reducepd512_mask(A, 1, C, D)
#define __builtin_ia32_rangess128_round(A, B, I, F) __builtin_ia32_rangess128_round(A, B, 1, 8)
diff --git a/gcc/testsuite/gcc.target/i386/stack-check-11.c b/gcc/testsuite/gcc.target/i386/stack-check-11.c
new file mode 100644
index 0000000..90ab602
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/stack-check-11.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fstack-clash-protection -mtune=generic" } */
+/* { dg-require-effective-target supports_stack_clash_protection } */
+
+#include <stdint.h>
+
+extern void arf (uint64_t *, uint64_t *);
+void
+frob ()
+{
+ uint64_t num[859];
+ uint64_t den[859];
+ arf (den, num);
+}
+
+/* { dg-final { scan-assembler-times "sub\[ql\]" 4 } } */
+/* { dg-final { scan-assembler-times "or\[ql\]" 3 } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/vect-pack-trunc-2.c b/gcc/testsuite/gcc.target/i386/vect-pack-trunc-2.c
index f3d899c..3503dea 100644
--- a/gcc/testsuite/gcc.target/i386/vect-pack-trunc-2.c
+++ b/gcc/testsuite/gcc.target/i386/vect-pack-trunc-2.c
@@ -25,4 +25,4 @@ avx512bw_test ()
abort ();
}
-/* { dg-final { scan-assembler-times "vpermi2w\[ \\t\]+\[^\n\]*%zmm" 1 } } */
+/* { dg-final { scan-assembler-times "vperm\[it]2w\[ \\t\]+\[^\n\]*%zmm" 1 } } */
diff --git a/gcc/testsuite/gcc.target/nios2/cdx-branch.c b/gcc/testsuite/gcc.target/nios2/cdx-branch.c
index 3b984f2..3a9c459 100644
--- a/gcc/testsuite/gcc.target/nios2/cdx-branch.c
+++ b/gcc/testsuite/gcc.target/nios2/cdx-branch.c
@@ -23,7 +23,7 @@ extern int i (int);
extern int j (int);
extern int k (int);
-int h (int a)
+int h (int a, int b)
{
int x;
@@ -31,7 +31,7 @@ int h (int a)
an unconditional branch from one branch of the "if" to
the return statement. We compile this testcase with -Os to
avoid insertion of a duplicate epilogue in place of the branch. */
- if (a == 1)
+ if (a == b)
x = i (37);
else
x = j (42);
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-bypass.c b/gcc/testsuite/gcc.target/nios2/lo-addr-bypass.c
new file mode 100644
index 0000000..24e6cfd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-bypass.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mbypass-cache" } */
+/* { dg-final { scan-assembler-times "addi\tr., r., %lo" 12 } } */
+/* { dg-final { scan-assembler-not "ldw\t" } } */
+/* { dg-final { scan-assembler-not "stw\t" } } */
+/* { dg-final { scan-assembler-not "ldwio\tr., %lo" } } */
+/* { dg-final { scan-assembler-not "stwio\tr., %lo" } } */
+
+/* Check that we do not generate %lo addresses with R2 ldstio instructions.
+ %lo requires a 16-bit relocation and on R2 these instructions only have a
+ 12-bit register offset. */
+#define TYPE int
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern TYPE S1;
+extern TYPE S2[];
+
+extern struct ss S3;
+extern struct ss S4[];
+
+TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-char.c b/gcc/testsuite/gcc.target/nios2/lo-addr-char.c
new file mode 100644
index 0000000..dd99245
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-char.c
@@ -0,0 +1,60 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "addi\tr., r., %lo" 4 } } */
+/* { dg-final { scan-assembler-times "ldbu\tr., %lo" 4 } } */
+/* { dg-final { scan-assembler-times "ldb\tr., %lo" 16 } } */
+/* { dg-final { scan-assembler-times "stb\tr., %lo" 4 } } */
+
+/* Check that various address forms involving a symbolic constant
+ with a possible constant offset and/or index register are optimized
+ to generate a %lo relocation in the load/store instructions instead
+ of a plain register indirect addressing mode. */
+/* Note: get* uses ldhu but ext* uses ldh since TYPE is signed. */
+
+#define TYPE signed char
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern TYPE S1;
+extern TYPE S2[];
+
+extern struct ss S3;
+extern struct ss S4[];
+
+TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
+int extw1 (void) { return (int)(S1); }
+int extw2 (int i) { return (int)(S2[i]); }
+int extw3 (void) { return (int)(S3.x2); }
+int extw4 (int i) { return (int)(S4[i].x2); }
+unsigned int extwu1 (void) { return (unsigned int)(S1); }
+unsigned int extwu2 (int i) { return (unsigned int)(S2[i]); }
+unsigned int extwu3 (void) { return (unsigned int)(S3.x2); }
+unsigned int extwu4 (int i) { return (unsigned int)(S4[i].x2); }
+
+short exth1 (void) { return (short)(S1); }
+short exth2 (int i) { return (short)(S2[i]); }
+short exth3 (void) { return (short)(S3.x2); }
+short exth4 (int i) { return (short)(S4[i].x2); }
+unsigned short exthu1 (void) { return (unsigned short)(S1); }
+unsigned short exthu2 (int i) { return (unsigned short)(S2[i]); }
+unsigned short exthu3 (void) { return (unsigned short)(S3.x2); }
+unsigned short exthu4 (int i) { return (unsigned short)(S4[i].x2); }
+
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-int.c b/gcc/testsuite/gcc.target/nios2/lo-addr-int.c
new file mode 100644
index 0000000..9a6f779
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-int.c
@@ -0,0 +1,40 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "addi\tr., r., %lo" 4 } } */
+/* { dg-final { scan-assembler-times "ldw\tr., %lo" 4 } } */
+/* { dg-final { scan-assembler-times "stw\tr., %lo" 4 } } */
+
+/* Check that various address forms involving a symbolic constant
+ with a possible constant offset and/or index register are optimized
+ to generate a %lo relocation in the load/store instructions instead
+ of a plain register indirect addressing mode. */
+
+#define TYPE int
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern TYPE S1;
+extern TYPE S2[];
+
+extern struct ss S3;
+extern struct ss S4[];
+
+TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-pic.c b/gcc/testsuite/gcc.target/nios2/lo-addr-pic.c
new file mode 100644
index 0000000..bcd6237
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-pic.c
@@ -0,0 +1,38 @@
+/* { dg-do compile { target nios2-*-linux-gnu } } */
+/* { dg-options "-O2 -fpic" } */
+/* { dg-final { scan-assembler-not "ldw\tr., %lo" } } */
+/* { dg-final { scan-assembler-not "stw\tr., %lo" } } */
+
+/* Check that address transformations for symbolic constants do NOT
+ apply to code compiled with -fPIC, which requires references to
+ go through the GOT pointer (r22) instead. */
+
+#define TYPE int
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern TYPE S1;
+extern TYPE S2[];
+
+extern struct ss S3;
+extern struct ss S4[];
+
+TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-short.c b/gcc/testsuite/gcc.target/nios2/lo-addr-short.c
new file mode 100644
index 0000000..792ec22
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-short.c
@@ -0,0 +1,51 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "addi\tr., r., %lo" 4 } } */
+/* { dg-final { scan-assembler-times "ldhu\tr., %lo" 4 } } */
+/* { dg-final { scan-assembler-times "ldh\tr., %lo" 8 } } */
+/* { dg-final { scan-assembler-times "sth\tr., %lo" 4 } } */
+
+/* Check that various address forms involving a symbolic constant
+ with a possible constant offset and/or index register are optimized
+ to generate a %lo relocation in the load/store instructions instead
+ of a plain register indirect addressing mode. */
+/* Note: get* uses ldhu but ext* uses ldh since TYPE is signed. */
+
+#define TYPE short
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern TYPE S1;
+extern TYPE S2[];
+
+extern struct ss S3;
+extern struct ss S4[];
+
+TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
+int extw1 (void) { return (int)(S1); }
+int extw2 (int i) { return (int)(S2[i]); }
+int extw3 (void) { return (int)(S3.x2); }
+int extw4 (int i) { return (int)(S4[i].x2); }
+unsigned int extwu1 (void) { return (unsigned int)(S1); }
+unsigned int extwu2 (int i) { return (unsigned int)(S2[i]); }
+unsigned int extwu3 (void) { return (unsigned int)(S3.x2); }
+unsigned int extwu4 (int i) { return (unsigned int)(S4[i].x2); }
+
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-tls.c b/gcc/testsuite/gcc.target/nios2/lo-addr-tls.c
new file mode 100644
index 0000000..d56fbc2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-tls.c
@@ -0,0 +1,38 @@
+/* { dg-require-effective-target tls } */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-not "ldw\tr., %lo" } } */
+/* { dg-final { scan-assembler-not "stw\tr., %lo" } } */
+
+/* Check that address transformations for symbolic constants do NOT
+ apply to TLS variables. */
+
+#define TYPE int
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern __thread TYPE S1;
+extern __thread TYPE S2[];
+
+extern __thread struct ss S3;
+extern __thread struct ss S4[];
+
+TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-uchar.c b/gcc/testsuite/gcc.target/nios2/lo-addr-uchar.c
new file mode 100644
index 0000000..e9733af
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-uchar.c
@@ -0,0 +1,58 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "addi\tr., r., %lo" 4 } } */
+/* { dg-final { scan-assembler-times "ldbu\tr., %lo" 20 } } */
+/* { dg-final { scan-assembler-times "stb\tr., %lo" 4 } } */
+
+/* Check that various address forms involving a symbolic constant
+ with a possible constant offset and/or index register are optimized
+ to generate a %lo relocation in the load/store instructions instead
+ of a plain register indirect addressing mode. */
+
+#define TYPE unsigned char
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern TYPE S1;
+extern TYPE S2[];
+
+extern struct ss S3;
+extern struct ss S4[];
+
+TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
+int extw1 (void) { return (int)(S1); }
+int extw2 (int i) { return (int)(S2[i]); }
+int extw3 (void) { return (int)(S3.x2); }
+int extw4 (int i) { return (int)(S4[i].x2); }
+unsigned int extwu1 (void) { return (unsigned int)(S1); }
+unsigned int extwu2 (int i) { return (unsigned int)(S2[i]); }
+unsigned int extwu3 (void) { return (unsigned int)(S3.x2); }
+unsigned int extwu4 (int i) { return (unsigned int)(S4[i].x2); }
+
+short exth1 (void) { return (short)(S1); }
+short exth2 (int i) { return (short)(S2[i]); }
+short exth3 (void) { return (short)(S3.x2); }
+short exth4 (int i) { return (short)(S4[i].x2); }
+unsigned short exthu1 (void) { return (unsigned short)(S1); }
+unsigned short exthu2 (int i) { return (unsigned short)(S2[i]); }
+unsigned short exthu3 (void) { return (unsigned short)(S3.x2); }
+unsigned short exthu4 (int i) { return (unsigned short)(S4[i].x2); }
+
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-ushort.c b/gcc/testsuite/gcc.target/nios2/lo-addr-ushort.c
new file mode 100644
index 0000000..4a19c13
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-ushort.c
@@ -0,0 +1,49 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+/* { dg-final { scan-assembler-times "addi\tr., r., %lo" 4 } } */
+/* { dg-final { scan-assembler-times "ldhu\tr., %lo" 12 } } */
+/* { dg-final { scan-assembler-times "sth\tr., %lo" 4 } } */
+
+/* Check that various address forms involving a symbolic constant
+ with a possible constant offset and/or index register are optimized
+ to generate a %lo relocation in the load/store instructions instead
+ of a plain register indirect addressing mode. */
+
+#define TYPE unsigned short
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern TYPE S1;
+extern TYPE S2[];
+
+extern struct ss S3;
+extern struct ss S4[];
+
+TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
+int extw1 (void) { return (int)(S1); }
+int extw2 (int i) { return (int)(S2[i]); }
+int extw3 (void) { return (int)(S3.x2); }
+int extw4 (int i) { return (int)(S4[i].x2); }
+unsigned int extwu1 (void) { return (unsigned int)(S1); }
+unsigned int extwu2 (int i) { return (unsigned int)(S2[i]); }
+unsigned int extwu3 (void) { return (unsigned int)(S3.x2); }
+unsigned int extwu4 (int i) { return (unsigned int)(S4[i].x2); }
+
diff --git a/gcc/testsuite/gcc.target/nios2/lo-addr-volatile.c b/gcc/testsuite/gcc.target/nios2/lo-addr-volatile.c
new file mode 100644
index 0000000..40a8be4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/nios2/lo-addr-volatile.c
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -march=r2 -mno-cache-volatile" } */
+/* { dg-final { scan-assembler-times "addi\tr., r., %lo" 12 } } */
+/* { dg-final { scan-assembler-not "ldw\t" } } */
+/* { dg-final { scan-assembler-not "stw\t" } } */
+/* { dg-final { scan-assembler-not "ldwio\tr., %lo" } } */
+/* { dg-final { scan-assembler-not "stwio\tr., %lo" } } */
+
+/* Check that we do not generate %lo addresses with R2 ldstio instructions.
+ %lo requires a 16-bit relocation and on R2 these instructions only have a
+ 12-bit register offset. */
+
+#define TYPE int
+
+struct ss
+{
+ TYPE x1,x2;
+};
+
+extern volatile TYPE S1;
+extern volatile TYPE S2[];
+
+extern volatile struct ss S3;
+extern volatile struct ss S4[];
+
+volatile TYPE *addr1 (void) { return &S1; }
+TYPE get1 (void) { return S1; }
+void set1 (TYPE value) { S1 = value; }
+
+volatile TYPE *addr2 (int i) { return &(S2[i]); }
+TYPE get2 (int i) { return S2[i]; }
+void set2 (int i, TYPE value) { S2[i] = value; }
+
+volatile TYPE *addr3 (void) { return &(S3.x2); }
+TYPE get3 (void) { return S3.x2; }
+void set3 (TYPE value) { S3.x2 = value; }
+
+volatile TYPE *addr4 (int i) { return &(S4[i].x2); }
+TYPE get4 (int i) { return S4[i].x2; }
+void set4 (int i, TYPE value) { S4[i].x2 = value; }
+
diff --git a/gcc/testsuite/gcc.target/powerpc/amo1.c b/gcc/testsuite/gcc.target/powerpc/amo1.c
new file mode 100644
index 0000000..152f0e5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/amo1.c
@@ -0,0 +1,253 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -mpower9-misc -O2" } */
+
+/* Verify P9 atomic memory operations. */
+
+#include <amo.h>
+#include <stdint.h>
+
+uint32_t
+do_lw_add (uint32_t *mem, uint32_t value)
+{
+ return amo_lwat_add (mem, value);
+}
+
+int32_t
+do_lw_sadd (int32_t *mem, int32_t value)
+{
+ return amo_lwat_sadd (mem, value);
+}
+
+uint32_t
+do_lw_xor (uint32_t *mem, uint32_t value)
+{
+ return amo_lwat_xor (mem, value);
+}
+
+uint32_t
+do_lw_ior (uint32_t *mem, uint32_t value)
+{
+ return amo_lwat_ior (mem, value);
+}
+
+uint32_t
+do_lw_and (uint32_t *mem, uint32_t value)
+{
+ return amo_lwat_and (mem, value);
+}
+
+uint32_t
+do_lw_umax (uint32_t *mem, uint32_t value)
+{
+ return amo_lwat_umax (mem, value);
+}
+
+int32_t
+do_lw_smax (int32_t *mem, int32_t value)
+{
+ return amo_lwat_smax (mem, value);
+}
+
+uint32_t
+do_lw_umin (uint32_t *mem, uint32_t value)
+{
+ return amo_lwat_umin (mem, value);
+}
+
+int32_t
+do_lw_smin (int32_t *mem, int32_t value)
+{
+ return amo_lwat_smin (mem, value);
+}
+
+uint32_t
+do_lw_swap (uint32_t *mem, uint32_t value)
+{
+ return amo_lwat_swap (mem, value);
+}
+
+int32_t
+do_lw_sswap (int32_t *mem, int32_t value)
+{
+ return amo_lwat_sswap (mem, value);
+}
+
+uint64_t
+do_ld_add (uint64_t *mem, uint64_t value)
+{
+ return amo_ldat_add (mem, value);
+}
+
+int64_t
+do_ld_sadd (int64_t *mem, int64_t value)
+{
+ return amo_ldat_sadd (mem, value);
+}
+
+uint64_t
+do_ld_xor (uint64_t *mem, uint64_t value)
+{
+ return amo_ldat_xor (mem, value);
+}
+
+uint64_t
+do_ld_ior (uint64_t *mem, uint64_t value)
+{
+ return amo_ldat_ior (mem, value);
+}
+
+uint64_t
+do_ld_and (uint64_t *mem, uint64_t value)
+{
+ return amo_ldat_and (mem, value);
+}
+
+uint64_t
+do_ld_umax (uint64_t *mem, uint64_t value)
+{
+ return amo_ldat_umax (mem, value);
+}
+
+int64_t
+do_ld_smax (int64_t *mem, int64_t value)
+{
+ return amo_ldat_smax (mem, value);
+}
+
+uint64_t
+do_ld_umin (uint64_t *mem, uint64_t value)
+{
+ return amo_ldat_umin (mem, value);
+}
+
+int64_t
+do_ld_smin (int64_t *mem, int64_t value)
+{
+ return amo_ldat_smin (mem, value);
+}
+
+uint64_t
+do_ld_swap (uint64_t *mem, uint64_t value)
+{
+ return amo_ldat_swap (mem, value);
+}
+
+int64_t
+do_ld_sswap (int64_t *mem, int64_t value)
+{
+ return amo_ldat_sswap (mem, value);
+}
+
+void
+do_sw_add (uint32_t *mem, uint32_t value)
+{
+ amo_stwat_add (mem, value);
+}
+
+void
+do_sw_sadd (int32_t *mem, int32_t value)
+{
+ amo_stwat_sadd (mem, value);
+}
+
+void
+do_sw_xor (uint32_t *mem, uint32_t value)
+{
+ amo_stwat_xor (mem, value);
+}
+
+void
+do_sw_ior (uint32_t *mem, uint32_t value)
+{
+ amo_stwat_ior (mem, value);
+}
+
+void
+do_sw_and (uint32_t *mem, uint32_t value)
+{
+ amo_stwat_and (mem, value);
+}
+
+void
+do_sw_umax (int32_t *mem, int32_t value)
+{
+ amo_stwat_umax (mem, value);
+}
+
+void
+do_sw_smax (int32_t *mem, int32_t value)
+{
+ amo_stwat_smax (mem, value);
+}
+
+void
+do_sw_umin (int32_t *mem, int32_t value)
+{
+ amo_stwat_umin (mem, value);
+}
+
+void
+do_sw_smin (int32_t *mem, int32_t value)
+{
+ amo_stwat_smin (mem, value);
+}
+
+void
+do_sd_add (uint64_t *mem, uint64_t value)
+{
+ amo_stdat_add (mem, value);
+}
+
+void
+do_sd_sadd (int64_t *mem, int64_t value)
+{
+ amo_stdat_sadd (mem, value);
+}
+
+void
+do_sd_xor (uint64_t *mem, uint64_t value)
+{
+ amo_stdat_xor (mem, value);
+}
+
+void
+do_sd_ior (uint64_t *mem, uint64_t value)
+{
+ amo_stdat_ior (mem, value);
+}
+
+void
+do_sd_and (uint64_t *mem, uint64_t value)
+{
+ amo_stdat_and (mem, value);
+}
+
+void
+do_sd_umax (int64_t *mem, int64_t value)
+{
+ amo_stdat_umax (mem, value);
+}
+
+void
+do_sd_smax (int64_t *mem, int64_t value)
+{
+ amo_stdat_smax (mem, value);
+}
+
+void
+do_sd_umin (int64_t *mem, int64_t value)
+{
+ amo_stdat_umin (mem, value);
+}
+
+void
+do_sd_smin (int64_t *mem, int64_t value)
+{
+ amo_stdat_smin (mem, value);
+}
+
+/* { dg-final { scan-assembler-times {\mldat\M} 11 } } */
+/* { dg-final { scan-assembler-times {\mlwat\M} 11 } } */
+/* { dg-final { scan-assembler-times {\mstdat\M} 9 } } */
+/* { dg-final { scan-assembler-times {\mstwat\M} 9 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/amo2.c b/gcc/testsuite/gcc.target/powerpc/amo2.c
new file mode 100644
index 0000000..cc7cfe4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/amo2.c
@@ -0,0 +1,121 @@
+/* { dg-do run { target { powerpc*-*-linux* && { lp64 && p9vector_hw } } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-O2 -mpower9-vector -mpower9-misc" } */
+
+#include <amo.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+/* Test whether the ISA 3.0 amo (atomic memory operations) functions perform as
+ expected. */
+
+/* 32-bit tests. */
+static uint32_t u32_ld[4] = {
+ 9, /* add */
+ 7, /* xor */
+ 6, /* ior */
+ 7, /* and */
+};
+
+static uint32_t u32_st[4] = {
+ 9, /* add */
+ 7, /* xor */
+ 6, /* ior */
+ 7, /* and */
+};
+
+static uint32_t u32_result[4];
+
+static uint32_t u32_update[4] = {
+ 9 + 1, /* add */
+ 7 ^ 1, /* xor */
+ 6 | 1, /* ior */
+ 7 & 1, /* and */
+};
+
+static uint32_t u32_prev[4] = {
+ 9, /* add */
+ 7, /* xor */
+ 6, /* ior */
+ 7, /* and */
+};
+
+/* 64-bit tests. */
+static uint64_t u64_ld[4] = {
+ 9, /* add */
+ 7, /* xor */
+ 6, /* ior */
+ 7, /* and */
+};
+
+static uint64_t u64_st[4] = {
+ 9, /* add */
+ 7, /* xor */
+ 6, /* ior */
+ 7, /* and */
+};
+
+static uint64_t u64_result[4];
+
+static uint64_t u64_update[4] = {
+ 9 + 1, /* add */
+ 7 ^ 1, /* xor */
+ 6 | 1, /* ior */
+ 7 & 1, /* and */
+};
+
+static uint64_t u64_prev[4] = {
+ 9, /* add */
+ 7, /* xor */
+ 6, /* ior */
+ 7, /* and */
+};
+
+int
+main (void)
+{
+ size_t i;
+
+ u32_result[0] = amo_lwat_add (&u32_ld[0], 1);
+ u32_result[1] = amo_lwat_xor (&u32_ld[1], 1);
+ u32_result[2] = amo_lwat_ior (&u32_ld[2], 1);
+ u32_result[3] = amo_lwat_and (&u32_ld[3], 1);
+
+ u64_result[0] = amo_ldat_add (&u64_ld[0], 1);
+ u64_result[1] = amo_ldat_xor (&u64_ld[1], 1);
+ u64_result[2] = amo_ldat_ior (&u64_ld[2], 1);
+ u64_result[3] = amo_ldat_and (&u64_ld[3], 1);
+
+ amo_stwat_add (&u32_st[0], 1);
+ amo_stwat_xor (&u32_st[1], 1);
+ amo_stwat_ior (&u32_st[2], 1);
+ amo_stwat_and (&u32_st[3], 1);
+
+ amo_stdat_add (&u64_st[0], 1);
+ amo_stdat_xor (&u64_st[1], 1);
+ amo_stdat_ior (&u64_st[2], 1);
+ amo_stdat_and (&u64_st[3], 1);
+
+ for (i = 0; i < 4; i++)
+ {
+ if (u32_result[i] != u32_prev[i])
+ abort ();
+
+ if (u32_ld[i] != u32_update[i])
+ abort ();
+
+ if (u32_st[i] != u32_update[i])
+ abort ();
+
+ if (u64_result[i] != u64_prev[i])
+ abort ();
+
+ if (u64_ld[i] != u64_update[i])
+ abort ();
+
+ if (u64_st[i] != u64_update[i])
+ abort ();
+ }
+
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/builtin-fctid-fctiw-runnable.c b/gcc/testsuite/gcc.target/powerpc/builtin-fctid-fctiw-runnable.c
new file mode 100644
index 0000000..b99fae3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtin-fctid-fctiw-runnable.c
@@ -0,0 +1,137 @@
+/* { dg-do run { target { powerpc*-*-* && { lp64 && p8vector_hw } } } } */
+/* { dg-options "-mcpu=power8" } */
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+void abort (void);
+
+long
+test_bi_lrint_1 (float __A)
+{
+ return (__builtin_fctid (__A));
+}
+long
+test_bi_lrint_2 (double __A)
+{
+ return (__builtin_fctid (__A));
+}
+
+int
+test_bi_rint_1 (float __A)
+{
+ return (__builtin_fctiw (__A));
+}
+
+int
+test_bi_rint_2 (double __A)
+{
+ return (__builtin_fctiw (__A));
+}
+
+
+int main( void)
+{
+ signed long lx, expected_l;
+ double dy;
+
+ signed int x, expected_i;
+ float y;
+
+ dy = 1.45;
+ expected_l = 1;
+ lx = __builtin_fctid (dy);
+
+ if( lx != expected_l)
+#ifdef DEBUG
+ printf("ERROR: __builtin_fctid(dy= %f) = %ld, expected %ld\n",
+ dy, lx, expected_l);
+#else
+ abort();
+#endif
+
+ dy = 3.51;
+ expected_l = 4;
+ lx = __builtin_fctid (dy);
+
+ if( lx != expected_l)
+#ifdef DEBUG
+ printf("ERROR: __builtin_fctid(dy= %f) = %ld, expected %ld\n",
+ dy, lx, expected_l);
+#else
+ abort();
+#endif
+
+ dy = 5.57;
+ expected_i = 6;
+ x = __builtin_fctiw (dy);
+
+ if( x != expected_i)
+#ifdef DEBUG
+ printf("ERROR: __builtin_fctiw(dy= %f) = %d, expected %d\n",
+ dy, x, expected_i);
+#else
+ abort();
+#endif
+
+ y = 11.47;
+ expected_i = 11;
+ x = __builtin_fctiw (y);
+
+ if( x != expected_i)
+#ifdef DEBUG
+ printf("ERROR: __builtin_fctiw(y = %f) = %d, expected %d\n",
+ y, x, expected_i);
+#else
+ abort();
+#endif
+
+ y = 17.77;
+ expected_l = 18;
+ lx = test_bi_lrint_1 (y);
+
+ if( lx != expected_l)
+#ifdef DEBUG
+ printf("ERROR: function call test_bi_lrint_1 (y = %f) = %ld, expected %ld\n",
+ y, lx, expected_l);
+#else
+ abort();
+#endif
+
+ dy = 7.1;
+ expected_l = 7;
+ lx = test_bi_lrint_2 (dy);
+
+ if( lx != expected_l)
+#ifdef DEBUG
+ printf("ERROR: function call test_bi_lrint_2 (dy = %f) = %ld, expected %ld\n",
+ dy, lx, expected_l);
+#else
+ abort();
+#endif
+
+ y = 0.001;
+ expected_i = 0;
+ x = test_bi_rint_1 (y);
+
+ if( x != expected_i)
+#ifdef DEBUG
+ printf("ERROR: function call test_bi_rint_1 (y = %f) = %d, expected %d\n",
+ y, x, expected_i);
+#else
+ abort();
+#endif
+
+ dy = 0.9999;
+ expected_i = 1;
+ x = test_bi_rint_2 (dy);
+
+ if( x != expected_i)
+#ifdef DEBUG
+ printf("ERROR: function call test_bi_rint_2 (dy = %f) = %d, expected %d\n",
+ dy, x, expected_i);
+#else
+ abort();
+#endif
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/builtins-5-p9-runnable.c b/gcc/testsuite/gcc.target/powerpc/builtins-5-p9-runnable.c
new file mode 100644
index 0000000..ad39471
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/builtins-5-p9-runnable.c
@@ -0,0 +1,309 @@
+/* { dg-do run { target { powerpc*-*-* && p9vector_hw } } } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
+/* { dg-options "-mcpu=power9 -O2" } */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <inttypes.h>
+#include <altivec.h> // vector
+
+#define TRUE 1
+#define FALSE 0
+
+#ifdef DEBUG
+#include <stdio.h>
+#endif
+
+void abort (void);
+
+int result_wrong(vector unsigned char vec_expected,
+ vector unsigned char vec_actual)
+{
+ int i;
+
+ for (i=0; i<16; i++)
+ if (vec_expected[i] != vec_actual[i])
+ return TRUE;
+
+ return FALSE;
+}
+
+int main() {
+ int i, j;
+ size_t size;
+ unsigned char data_uc[100];
+ vector unsigned char store_data_uc;
+ unsigned char *address;
+ vector unsigned char *datap;
+
+ vector unsigned char vec_uc_expected1, vec_uc_expected2,
+ vec_uc_result1, vec_uc_result2;
+ vector int data_int;
+
+ for (i=0; i<100; i++)
+ data_uc[i] = i+1;
+
+
+ /* VEC_XL_LEN */
+
+ size = 8;
+ vec_uc_result1 = vec_xl_len (data_uc, size);
+
+ vec_uc_expected1 = (vector unsigned char){ 1, 2, 3, 4, 5, 6, 7, 8,
+ 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if (result_wrong (vec_uc_expected1, vec_uc_result1))
+ {
+#ifdef DEBUG
+ printf("Error: result does not match expected result\n");
+ printf("vec_xl_len (%d): vec_uc_expected1[0] to vec_uc_expected1[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,",vec_uc_expected1[i]);
+
+ printf("\nvec_xl_len (%d): vec_uc_result1[0] to vec_uc_result1[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_result1[i]);
+
+ printf("\n\n");
+#else
+ abort();
+#endif
+ }
+
+
+ /* VEC_XL_LEN_R */
+ size = 8;
+ vec_uc_result2 = vec_xl_len_r(data_uc, size);
+
+ vec_uc_expected2 = (vector unsigned char){8, 7, 6, 5, 4, 3, 2, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0,};
+
+ if (result_wrong (vec_uc_expected2, vec_uc_result2))
+ {
+#ifdef DEBUG
+ printf("Error: result does not match expected result\n");
+ printf("vec_xl_len_r(%d): vec_uc_expected2[0] to vec_uc_expected2[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_expected2[i]);
+
+ printf("\nvec_xl_len_r(%d): vec_uc_result2[0] to vec_uc_result2[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_result2[i]);
+
+ printf("\n\n");
+#else
+ abort();
+#endif
+ }
+
+
+ size = 4;
+ vec_uc_result2 = vec_xl_len_r(data_uc, size);
+
+ vec_uc_expected2 = (vector unsigned char){ 4, 3, 2, 1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ if (result_wrong (vec_uc_expected2, vec_uc_result2))
+ {
+#ifdef DEBUG
+ printf("Error: result does not match expected result\n");
+ printf("vec_xl_len_r(%d): vec_uc_expected2[0] to vec_uc_expected2[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_expected2[i]);
+
+ printf("\nvec_xl_len_r(%d): vec_uc_result2[0] to vec_uc_result2[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_result2[i]);
+
+ printf("\n\n");
+#else
+ abort();
+#endif
+ }
+
+ size = 2;
+ vec_uc_result2 = vec_xl_len_r(data_uc, size);
+
+ vec_uc_expected2 = (vector unsigned char){ 2, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ if (result_wrong (vec_uc_expected2, vec_uc_result2))
+ {
+#ifdef DEBUG
+ printf("Error: result does not match expected result\n");
+ printf("vec_xl_len_r(%d): vec_uc_expected2[0] to vec_uc_expected2[15]\n",
+ size);
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_expected2[i]);
+
+ printf("\nvec_xl_len_r(%d) vec_uc_result2[0] to vec_uc_result2[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_result2[i]);
+
+ printf("\n\n");
+#else
+ abort();
+#endif
+ }
+
+
+ /* VEC_XST_LEN */
+ vec_uc_expected2 = (vector unsigned char){ 1, 2, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+ store_data_uc = (vector unsigned char){ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16 };
+ size = 2;
+
+ for (i=0; i<16; i++)
+ vec_uc_result2[i] = 0;
+
+ address = &vec_uc_result2[0];
+ vec_xst_len (store_data_uc, address, size);
+
+ if (result_wrong (vec_uc_expected2, vec_uc_result2))
+ {
+#ifdef DEBUG
+ printf("Error: result does not match expected result\n");
+ printf("vec_xst_len (%d) vec_uc_result2[0] to vec_uc_result2[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_expected2[i]);
+
+ printf("\nvec_xst_len (%d) store_data_uc[0] to store_data_uc[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_result2[i]);
+
+ printf("\n\n");
+#else
+ abort();
+#endif
+ }
+
+ vec_uc_expected2 = (vector unsigned char){ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 0, 0 };
+ store_data_uc = (vector unsigned char){ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16 };
+ size = 14;
+
+ for (i=0; i<16; i++)
+ vec_uc_result2[i] = 0;
+
+ address = &vec_uc_result2[0];
+
+ vec_xst_len (store_data_uc, address, size);
+
+ if (result_wrong (vec_uc_expected2, vec_uc_result2))
+ {
+#ifdef DEBUG
+ printf("Error: result does not match expected result\n");
+ printf("vec_xst_len (%d) vec_uc_result2[0] to vec_uc_result2[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_expected2[i]);
+
+ printf("\nvec_xst_len (%d) store_data_uc[0] to store_data_uc[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_result2[i]);
+
+ printf("\n\n");
+#else
+ abort();
+#endif
+ }
+
+ /* VEC_XST_LEN_R */
+ vec_uc_expected1 = (vector unsigned char){ 2, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+ store_data_uc = (vector unsigned char){ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16 };
+ vec_uc_result1 = (vector unsigned char){ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ size = 2;
+
+ for (i=0; i<16; i++)
+ vec_uc_result1[i] = 0;
+
+ address = &vec_uc_result1[0];
+
+ vec_xst_len_r(store_data_uc, address, size);
+
+ if (result_wrong (vec_uc_expected1, vec_uc_result1))
+ {
+#ifdef DEBUG
+ printf("Error: result does not match expected result\n");
+ printf("vec_xst_len_r(%d) vec_uc_expected1[0] to vec_uc_expected1[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_expected1[i]);
+
+ printf("\nvec_xst_len_r(%d) result[0] to result[15]\n", size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_result1[i]);
+
+ printf("\n\n");
+#else
+ abort();
+#endif
+ }
+
+
+ vec_uc_expected1 = (vector unsigned char){ 14, 13, 12, 11, 10, 9, 8, 7,
+ 6, 5, 4, 3, 2, 1, 0, 0 };
+ store_data_uc = (vector unsigned char){ 1, 2, 3, 4, 5, 6, 7, 8,
+ 9, 10, 11, 12, 13, 14, 15, 16 };
+ vec_uc_result1 = (vector unsigned char){ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0 };
+
+ size = 14;
+
+ for (i=0; i<16; i++)
+ vec_uc_result1[i] = 0;
+
+ address = &vec_uc_result1[0];
+
+ vec_xst_len_r(store_data_uc, address, size);
+
+ if (result_wrong (vec_uc_expected1, vec_uc_result1))
+ {
+#ifdef DEBUG
+ printf("Error: result does not match expected result\n");
+ printf("vec_xst_len_r(%d) vec_uc_expected2[0] to vec_uc_expected2[15]\n",
+ size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_expected2[i]);
+
+ printf("\nvec_xst_len_r(%d) result[0] to result[15]\n", size);
+
+ for (i=0; i<16; i++)
+ printf(" %d,", vec_uc_result1[i]);
+
+ printf("\n\n");
+#else
+ abort();
+#endif
+ }
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/direct-move-float1.c b/gcc/testsuite/gcc.target/powerpc/direct-move-float1.c
index 2551077..f5cff6c 100644
--- a/gcc/testsuite/gcc.target/powerpc/direct-move-float1.c
+++ b/gcc/testsuite/gcc.target/powerpc/direct-move-float1.c
@@ -4,10 +4,10 @@
/* { dg-require-effective-target powerpc_p8vector_ok } */
/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
/* { dg-options "-mcpu=power8 -O2" } */
-/* { dg-final { scan-assembler "mtvsrd" } } */
-/* { dg-final { scan-assembler "mfvsrd" } } */
-/* { dg-final { scan-assembler "xscvdpspn" } } */
-/* { dg-final { scan-assembler "xscvspdpn" } } */
+/* { dg-final { scan-assembler {\mmtvsrd\M} } } */
+/* { dg-final { scan-assembler {\mmfvsrwz\M} } } */
+/* { dg-final { scan-assembler {\mxscvdpspn\M} } } */
+/* { dg-final { scan-assembler {\mxscvspdpn\M} } } */
/* Check code generation for direct move for float types. */
diff --git a/gcc/testsuite/gcc.target/powerpc/direct-move-float3.c b/gcc/testsuite/gcc.target/powerpc/direct-move-float3.c
new file mode 100644
index 0000000..6e294aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/direct-move-float3.c
@@ -0,0 +1,30 @@
+/* { dg-do compile { target { powerpc*-*-linux* && lp64 } } } */
+/* { dg-skip-if "" { powerpc*-*-darwin* } } */
+/* { dg-skip-if "" { powerpc*-*-*spe* } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-mpower8-vector -O2" } */
+
+/* Test that we generate XSCVDPSP instead of FRSP and XSCVDPSPN when we combine
+ a round from double to float and moving the float value to a GPR. */
+
+union u {
+ float f;
+ unsigned int ui;
+ int si;
+};
+
+unsigned int
+ui_d (double d)
+{
+ union u x;
+ x.f = d;
+ return x.ui;
+}
+
+/* { dg-final { scan-assembler {\mmfvsrwz\M} } } */
+/* { dg-final { scan-assembler {\mxscvdpsp\M} } } */
+/* { dg-final { scan-assembler-not {\mmfvsrd\M} } } */
+/* { dg-final { scan-assembler-not {\mmtvsrwz\M} } } */
+/* { dg-final { scan-assembler-not {\mmtvsrd\M} } } */
+/* { dg-final { scan-assembler-not {\mxscvdpspn\M} } } */
+/* { dg-final { scan-assembler-not {\msrdi\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-fma1.c b/gcc/testsuite/gcc.target/powerpc/float128-fma1.c
new file mode 100644
index 0000000..9bc538e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-fma1.c
@@ -0,0 +1,32 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2" } */
+
+__float128
+xfma (__float128 a, __float128 b, __float128 c)
+{
+ return __builtin_fmaf128 (a, b, c);
+}
+
+__float128
+xfms (__float128 a, __float128 b, __float128 c)
+{
+ return __builtin_fmaf128 (a, b, -c);
+}
+
+__float128
+xfnma (__float128 a, __float128 b, __float128 c)
+{
+ return -__builtin_fmaf128 (a, b, c);
+}
+
+__float128
+xfnms (__float128 a, __float128 b, __float128 c)
+{
+ return -__builtin_fmaf128 (a, b, -c);
+}
+
+/* { dg-final { scan-assembler "xsmaddqp" } } */
+/* { dg-final { scan-assembler "xsmsubqp" } } */
+/* { dg-final { scan-assembler "xsnmaddqp" } } */
+/* { dg-final { scan-assembler "xsnmsubqp" } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-fma2.c b/gcc/testsuite/gcc.target/powerpc/float128-fma2.c
new file mode 100644
index 0000000..e5f15aa
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-fma2.c
@@ -0,0 +1,9 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -mno-float128-hardware -O2" } */
+
+__float128
+xfma (__float128 a, __float128 b, __float128 c)
+{
+ return __builtin_fmaf128 (a, b, c); /* { dg-error "ISA 3.0 IEEE 128-bit" } */
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-odd.c b/gcc/testsuite/gcc.target/powerpc/float128-odd.c
new file mode 100644
index 0000000..68c1510
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-odd.c
@@ -0,0 +1,75 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2" } */
+
+/* Test the generation of the round to odd instructions. */
+__float128
+f128_add(__float128 a, __float128 b)
+{
+ return __builtin_addf128_round_to_odd (a, b);
+}
+
+__float128
+f128_sub (__float128 a, __float128 b)
+{
+ return __builtin_subf128_round_to_odd (a, b);
+}
+
+__float128
+f128_mul (__float128 a, __float128 b)
+{
+ return __builtin_mulf128_round_to_odd (a, b);
+}
+
+__float128
+f128_div (__float128 a, __float128 b)
+{
+ return __builtin_divf128_round_to_odd (a, b);
+}
+
+__float128
+f128_sqrt (__float128 a)
+{
+ return __builtin_sqrtf128_round_to_odd (a);
+}
+
+double
+f128_trunc (__float128 a)
+{
+ return __builtin_truncf128_round_to_odd (a);
+}
+
+__float128
+f128_fma (__float128 a, __float128 b, __float128 c)
+{
+ return __builtin_fmaf128_round_to_odd (a, b, c);
+}
+
+__float128
+f128_fms (__float128 a, __float128 b, __float128 c)
+{
+ return __builtin_fmaf128_round_to_odd (a, b, -c);
+}
+
+__float128
+f128_nfma (__float128 a, __float128 b, __float128 c)
+{
+ return - __builtin_fmaf128_round_to_odd (a, b, c);
+}
+
+__float128
+f128_nfms (__float128 a, __float128 b, __float128 c)
+{
+ return - __builtin_fmaf128_round_to_odd (a, b, -c);
+}
+
+/* { dg-final { scan-assembler {\mxsaddqpo\M} } } */
+/* { dg-final { scan-assembler {\mxssubqpo\M} } } */
+/* { dg-final { scan-assembler {\mxsmulqpo\M} } } */
+/* { dg-final { scan-assembler {\mxsdivqpo\M} } } */
+/* { dg-final { scan-assembler {\mxssqrtqpo\M} } } */
+/* { dg-final { scan-assembler {\mxscvqpdpo\M} } } */
+/* { dg-final { scan-assembler {\mxsmaddqpo\M} } } */
+/* { dg-final { scan-assembler {\mxsmsubqpo\M} } } */
+/* { dg-final { scan-assembler {\mxsnmaddqpo\M} } } */
+/* { dg-final { scan-assembler {\mxsnmsubqpo\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-sqrt1.c b/gcc/testsuite/gcc.target/powerpc/float128-sqrt1.c
new file mode 100644
index 0000000..792aa05
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-sqrt1.c
@@ -0,0 +1,11 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -O2" } */
+
+__float128
+xsqrt (__float128 a)
+{
+ return __builtin_sqrtf128 (a);
+}
+
+/* { dg-final { scan-assembler "xssqrtqp" } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-sqrt2.c b/gcc/testsuite/gcc.target/powerpc/float128-sqrt2.c
new file mode 100644
index 0000000..94527eb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-sqrt2.c
@@ -0,0 +1,9 @@
+/* { dg-do compile { target { powerpc*-*-* && lp64 } } } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
+/* { dg-options "-mpower9-vector -mno-float128-hardware -O2" } */
+
+__float128
+xsqrt (__float128 a)
+{
+ return __builtin_sqrtf128 (a); /* { dg-error "ISA 3.0 IEEE 128-bit" } */
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-char.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-char.c
new file mode 100644
index 0000000..3a1aa60
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-char.c
@@ -0,0 +1,86 @@
+/* Verify that overloaded built-ins for vec_cmp{eq,ge,gt,le,lt,ne} with
+ char inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-mpower8-vector -O2" } */
+
+#include <altivec.h>
+
+vector bool char
+test3_eq (vector signed char x, vector signed char y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool char
+test6_eq (vector unsigned char x, vector unsigned char y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool char
+test3_ge (vector signed char x, vector signed char y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool char
+test6_ge (vector unsigned char x, vector unsigned char y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool char
+test3_gt (vector signed char x, vector signed char y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool char
+test6_gt (vector unsigned char x, vector unsigned char y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool char
+test3_le (vector signed char x, vector signed char y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool char
+test6_le (vector unsigned char x, vector unsigned char y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool char
+test3_lt (vector signed char x, vector signed char y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool char
+test6_lt (vector unsigned char x, vector unsigned char y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool char
+test3_ne (vector signed char x, vector signed char y)
+{
+ return vec_cmpne (x, y);
+}
+
+vector bool char
+test6_ne (vector unsigned char x, vector unsigned char y)
+{
+ return vec_cmpne (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vcmpequb" 4 } } */
+/* { dg-final { scan-assembler-times "vcmpgtsb" 4 } } */
+/* { dg-final { scan-assembler-times "vcmpgtub" 4 } } */
+/* { dg-final { scan-assembler-times "xxlnor" 6 } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-double.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-double.c
new file mode 100644
index 0000000..9d56862
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-double.c
@@ -0,0 +1,51 @@
+/* Verify that overloaded built-ins for vec_cmp with
+ double inputs for VSX produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-mvsx -O2" } */
+
+#include <altivec.h>
+
+vector bool long long
+test2_eq (vector double x, vector double y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool long long
+test2_ge (vector double x, vector double y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool long long
+test2_gt (vector double x, vector double y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool long long
+test2_le (vector double x, vector double y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool long long
+test2_lt (vector double x, vector double y)
+{
+ return vec_cmplt (x, y);
+}
+
+ vector bool long long
+test2_ne (vector double x, vector double y)
+{
+ return vec_cmpne (x, y);
+}
+
+/* { dg-final { scan-assembler-times "xvcmpeqdp" 2 } } */
+/* { dg-final { scan-assembler-times "xvcmpgtdp" 2 } } */
+/* { dg-final { scan-assembler-times "xvcmpnedp" 0 } } */
+/* { dg-final { scan-assembler-times "xvcmpgedp" 2 } } */
+/* { dg-final { scan-assembler-times "fcmpu" 0 } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-float.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-float.c
new file mode 100644
index 0000000..b75250a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-float.c
@@ -0,0 +1,51 @@
+/* Verify that overloaded built-ins for vec_cmp with float
+ inputs for VSX produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-mvsx -O2" } */
+
+#include <altivec.h>
+
+vector bool int
+test1_eq (vector float x, vector float y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool int
+test1_ge (vector float x, vector float y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool int
+test1_gt (vector float x, vector float y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool int
+test1_le (vector float x, vector float y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool int
+test1_lt (vector float x, vector float y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool int
+test1_ne (vector float x, vector float y)
+{
+ return vec_cmpne (x, y);
+}
+
+/* { dg-final { scan-assembler-times "xvcmpeqsp" 2 } } */
+/* { dg-final { scan-assembler-times "xvcmpgtsp" 2 } } */
+/* { dg-final { scan-assembler-times "xvcmpnesp" 0 } } */
+/* { dg-final { scan-assembler-times "xvcmpgesp" 2 } } */
+/* { dg-final { scan-assembler-times "fcmpu" 0 } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-int.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-int.c
new file mode 100644
index 0000000..d53994d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-int.c
@@ -0,0 +1,86 @@
+/* Verify that overloaded built-ins for vec_cmp with int
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-mpower8-vector -O2" } */
+
+#include <altivec.h>
+
+vector bool int
+test3_eq (vector signed int x, vector signed int y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool int
+test6_eq (vector unsigned int x, vector unsigned int y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool int
+test3_ge (vector signed int x, vector signed int y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool int
+test6_ge (vector unsigned int x, vector unsigned int y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool int
+test3_gt (vector signed int x, vector signed int y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool int
+test6_gt (vector unsigned int x, vector unsigned int y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool int
+test3_le (vector signed int x, vector signed int y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool int
+test6_le (vector unsigned int x, vector unsigned int y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool int
+test3_lt (vector signed int x, vector signed int y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool int
+test6_lt (vector unsigned int x, vector unsigned int y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool int
+test3_ne (vector signed int x, vector signed int y)
+{
+ return vec_cmpne (x, y);
+}
+
+vector bool int
+test6_ne (vector unsigned int x, vector unsigned int y)
+{
+ return vec_cmpne (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vcmpequw" 4 } } */
+/* { dg-final { scan-assembler-times "vcmpgtsw" 4 } } */
+/* { dg-final { scan-assembler-times "vcmpgtuw" 4 } } */
+/* { dg-final { scan-assembler-times "xxlnor" 6 } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-longlong.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-longlong.c
new file mode 100644
index 0000000..536ee75
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-longlong.c
@@ -0,0 +1,86 @@
+/* Verify that overloaded built-ins for vec_cmp with long long
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-mpower8-vector -O2" } */
+
+#include <altivec.h>
+
+vector bool long long
+test3_eq (vector signed long long x, vector signed long long y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool long long
+test6_eq (vector unsigned long long x, vector unsigned long long y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool long long
+test3_ge (vector signed long long x, vector signed long long y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool long long
+test6_ge (vector unsigned long long x, vector unsigned long long y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool long long
+test3_gt (vector signed long long x, vector signed long long y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool long long
+test6_gt (vector unsigned long long x, vector unsigned long long y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool long long
+test3_le (vector signed long long x, vector signed long long y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool long long
+test6_le (vector unsigned long long x, vector unsigned long long y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool long long
+test3_lt (vector signed long long x, vector signed long long y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool long long
+test6_lt (vector unsigned long long x, vector unsigned long long y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool long long
+test3_ne (vector signed long long x, vector signed long long y)
+{
+ return vec_cmpne (x, y);
+}
+
+vector bool long long
+test6_ne (vector unsigned long long x, vector unsigned long long y)
+{
+ return vec_cmpne (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vcmpequd" 4 } } */
+/* { dg-final { scan-assembler-times "vcmpgtsd" 4 } } */
+/* { dg-final { scan-assembler-times "vcmpgtud" 4 } } */
+/* { dg-final { scan-assembler-times "xxlnor" 6 } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-short.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-short.c
new file mode 100644
index 0000000..6067669
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-cmp-short.c
@@ -0,0 +1,87 @@
+/* Verify that overloaded built-ins for vec_cmp with short
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-mpower8-vector -O2" } */
+
+#include <altivec.h>
+
+vector bool short
+test3_eq (vector signed short x, vector signed short y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool short
+test6_eq (vector unsigned short x, vector unsigned short y)
+{
+ return vec_cmpeq (x, y);
+}
+
+vector bool short
+test3_ge (vector signed short x, vector signed short y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool short
+test6_ge (vector unsigned short x, vector unsigned short y)
+{
+ return vec_cmpge (x, y);
+}
+
+vector bool short
+test3_gt (vector signed short x, vector signed short y)
+{
+ return vec_cmpgt (x, y);
+}
+
+vector bool short
+test6_gt (vector unsigned short x, vector unsigned short y)
+{
+ return vec_cmpgt (x, y);
+}
+
+
+vector bool short
+test3_le (vector signed short x, vector signed short y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool short
+test6_le (vector unsigned short x, vector unsigned short y)
+{
+ return vec_cmple (x, y);
+}
+
+vector bool short
+test3_lt (vector signed short x, vector signed short y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool short
+test6_lt (vector unsigned short x, vector unsigned short y)
+{
+ return vec_cmplt (x, y);
+}
+
+vector bool short
+test3_ne (vector signed short x, vector signed short y)
+{
+ return vec_cmpne (x, y);
+}
+
+vector bool short
+test6_ne (vector unsigned short x, vector unsigned short y)
+{
+ return vec_cmpne (x, y);
+}
+
+/* { dg-final { scan-assembler-times "vcmpequh" 4 } } */
+/* { dg-final { scan-assembler-times "vcmpgtsh" 4 } } */
+/* { dg-final { scan-assembler-times "vcmpgtuh" 4 } } */
+/* { dg-final { scan-assembler-times "xxlnor" 6 } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p8.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p8.c
index 97d6b94..b1cf0a7 100644
--- a/gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p8.c
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p8.c
@@ -5,7 +5,8 @@
/* { dg-require-effective-target powerpc_p8vector_ok } */
/* { dg-require-effective-target int128 } */
/* { dg-require-effective-target lp64 } */
-/* { dg-options "-mpower8-vector" } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mpower8-vector -mcpu=power8 -O2" } */
/* { dg-additional-options "-maix64" { target powerpc-ibm-aix* } } */
#include "altivec.h"
@@ -22,5 +23,5 @@ test2 (vector unsigned __int128 x, vector unsigned __int128 y)
return vec_mul (x, y);
}
-/* { dg-final { scan-assembler-times "\[ \t\]mulld " 6 } } */
-/* { dg-final { scan-assembler-times "\[ \t\]mulhdu" 2 } } */
+/* { dg-final { scan-assembler-times {\mmulld\M} 6 } } */
+/* { dg-final { scan-assembler-times {\mmulhdu\M} 2 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p9.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p9.c
index e81ea5f..6571884 100644
--- a/gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p9.c
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-mult-int128-p9.c
@@ -2,10 +2,10 @@
inputs produce the right results. */
/* { dg-do compile } */
-/* { dg-require-effective-target powerpc_float128_hw_ok } */
+/* { dg-require-effective-target powerpc_p9vector_ok } */
/* { dg-require-effective-target int128 } */
/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power9" } } */
-/* { dg-options "-mcpu=power9 -O2" } */
+/* { dg-options "-mpower9-vector -mcpu=power9 -O2" } */
/* { dg-additional-options "-maix64" { target powerpc-ibm-aix* } } */
#include "altivec.h"
@@ -22,4 +22,5 @@ test2 (vector unsigned __int128 x, vector unsigned __int128 y)
return vec_mul (x, y);
}
-/* { dg-final { scan-assembler-times "\[ \t\]xsmulqp" 2 } } */
+/* { dg-final { scan-assembler-times {\mmulld\M} 4 } } */
+/* { dg-final { scan-assembler-times {\mmulhdu\M} 2 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-16.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-16.c
new file mode 100644
index 0000000..bb4a8d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-16.c
@@ -0,0 +1,46 @@
+/* Verify that overloaded built-ins for vec_splat with int
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-mvsx -O2" } */
+
+#include <altivec.h>
+
+vector signed short
+testss_1 ()
+{
+ return vec_splat_s16 (5);
+}
+
+vector signed short
+testss_2 ()
+{
+ return vec_splat_s16 (-5);
+}
+
+vector signed short
+testss_3 ()
+{
+ return vec_splat_s16 (15);
+}
+
+vector unsigned short
+testus_1 ()
+{
+ return vec_splat_u16 (5);
+}
+
+vector unsigned short
+testus_2 ()
+{
+ return vec_splat_u16 (-5);
+}
+
+vector unsigned short
+testus_3 ()
+{
+ return vec_splat_u16 (15);
+}
+
+/* { dg-final { scan-assembler-times "vspltish" 6 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-32.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-32.c
new file mode 100644
index 0000000..f59849e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-32.c
@@ -0,0 +1,46 @@
+/* Verify that overloaded built-ins for vec_splat with int
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2" } */
+
+#include <altivec.h>
+
+vector signed int
+testsi_1 ()
+{
+ return vec_splat_s32 (5);
+}
+
+vector signed int
+testsi_2 ()
+{
+ return vec_splat_s32 (-5);
+}
+
+vector signed int
+testsi_3 ()
+{
+ return vec_splat_s32 (15);
+}
+
+vector unsigned int
+testui_1 ()
+{
+ return vec_splat_u32 (5);
+}
+
+vector unsigned int
+testui_2 ()
+{
+ return vec_splat_u32 (-5);
+}
+
+vector unsigned int
+testui_3 ()
+{
+ return vec_splat_u32 (15);
+}
+
+/* { dg-final { scan-assembler-times "vspltisw" 6 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-8.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-8.c
new file mode 100644
index 0000000..679fcb3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-8.c
@@ -0,0 +1,46 @@
+/* Verify that overloaded built-ins for vec_splat with int
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2" } */
+
+#include <altivec.h>
+
+vector signed char
+testsc_1 ()
+{
+ return vec_splat_s8 (5);
+}
+
+vector signed char
+testsc_2 ()
+{
+ return vec_splat_s8 (-5);
+}
+
+vector signed char
+testsc_3 ()
+{
+ return vec_splat_s8 (15);
+}
+
+vector unsigned char
+testuc_1 ()
+{
+ return vec_splat_u8 (5);
+}
+
+vector unsigned char
+testuc_2 ()
+{
+ return vec_splat_u8 (-5);
+}
+
+vector unsigned char
+testuc_3 ()
+{
+ return vec_splat_u8 (15);
+}
+
+/* { dg-final { scan-assembler-times "vspltisb" 6 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-char.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-char.c
new file mode 100644
index 0000000..8f21153
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-char.c
@@ -0,0 +1,22 @@
+/* Verify that overloaded built-ins for vec_splats() with char
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2 " } */
+
+#include <altivec.h>
+
+vector signed char
+test1s (signed char x)
+{
+ return vec_splats (x);
+}
+
+vector unsigned char
+test1u (unsigned char x)
+{
+ return vec_splats (x);
+}
+
+/* { dg-final { scan-assembler-times "vspltb" 2 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-floatdouble.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-floatdouble.c
new file mode 100644
index 0000000..c4544f1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-floatdouble.c
@@ -0,0 +1,27 @@
+/* Verify that overloaded built-ins for vec_splat with float and
+ double inputs for VSX produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-mvsx -O1" } */
+
+#include <altivec.h>
+
+vector float
+test1d (float x)
+{
+ return vec_splats (x);
+}
+
+vector double
+test1f (double x)
+{
+ return vec_splats (x);
+}
+
+// float test generates the permute instruction.
+/* { dg-final { scan-assembler-times "xxpermdi" 1 } } */
+
+// double test generates a convert (double to single non-signalling) followed by a splat.
+/* { dg-final { scan-assembler-times {\mxscvdpspn?\M} 1 } } */
+/* { dg-final { scan-assembler-times {\mvspltw\M|\mxxspltw\M} 1 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-int.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-int.c
new file mode 100644
index 0000000..6671523
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-int.c
@@ -0,0 +1,22 @@
+/* Verify that overloaded built-ins for vec_splat with int
+ inputs produce the right code. */
+
+/* { dg-do compile { target { powerpc*-*-linux* && lp64 } } } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2 " } */
+
+#include <altivec.h>
+
+vector signed int
+test3s (signed int x)
+{
+ return vec_splats (x);
+}
+
+vector unsigned int
+test3u (unsigned int x)
+{
+ return vec_splats (x);
+}
+
+/* { dg-final { scan-assembler-times {\mvspltw\M|\mxxspltw\M} 2 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-longlong.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-longlong.c
new file mode 100644
index 0000000..c5884ba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-longlong.c
@@ -0,0 +1,22 @@
+/* Verify that overloaded built-ins for vec_splat with long long
+ inputs produce the right code. */
+
+/* { dg-do compile { target { powerpc*-*-linux* && lp64 } } } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-mvsx -O2" } */
+
+#include <altivec.h>
+
+vector signed long long
+test3s (signed long long x)
+{
+ return vec_splats (x);
+}
+
+vector unsigned long long
+test3u (unsigned long long x)
+{
+ return vec_splats (x);
+}
+
+/* { dg-final { scan-assembler-times "xxpermdi" 2 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-short.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-short.c
new file mode 100644
index 0000000..18102ac
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splats-short.c
@@ -0,0 +1,23 @@
+/* Verify that overloaded built-ins for vec_splat with short
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2" } */
+
+#include <altivec.h>
+
+vector signed short
+test3s (signed short x)
+{
+ return vec_splats (x);
+}
+
+vector unsigned short
+test3u (unsigned short x)
+{
+ return vec_splats (x);
+}
+
+/* { dg-final { scan-assembler-times "vsplth" 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-st-char.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-char.c
new file mode 100644
index 0000000..4c45827
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-char.c
@@ -0,0 +1,94 @@
+/* Verify that overloaded built-ins for vec_st* with char
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2" } */
+
+#include <altivec.h>
+
+void
+testst_1 (vector signed char vsc1, int i1, vector signed char * vscp)
+{
+ return vec_st(vsc1, i1, vscp);
+}
+
+void
+testst_2 (vector signed char vsc1, int i1, signed char * scp)
+{
+ return vec_st(vsc1, i1, scp);
+}
+
+void
+testst_3 (vector unsigned char vuc1, int i1, vector unsigned char * vscp)
+{
+ return vec_st(vuc1, i1, vscp);
+}
+
+void
+testst_4 (vector unsigned char vuc1, int i1, unsigned char * scp)
+{
+ return vec_st(vuc1, i1, scp);
+}
+
+void
+testst_5 (vector bool char vbc1, int i1, vector bool char * vbcp)
+{
+ return vec_st(vbc1, i1, vbcp);
+}
+
+void
+testst_6 (vector bool char vbc1, int i1, unsigned char * vucp)
+{
+ return vec_st(vbc1, i1, vucp);
+}
+
+void
+testst_7 (vector bool char vbc1, int i1, signed char * vscp)
+{
+ return vec_st(vbc1, i1, vscp);
+}
+
+void
+testst_cst1 (vector signed char vsc1, int i1, vector signed char * vscp)
+{
+ return vec_st(vsc1, 12, vscp);
+}
+
+void
+testst_cst2 (vector signed char vsc1, int i1, signed char * scp)
+{
+ return vec_st(vsc1, 16, scp);
+}
+
+void
+testst_cst3 (vector unsigned char vuc1, int i1, vector unsigned char * vscp)
+{
+ return vec_st(vuc1, 20, vscp);
+}
+
+void
+testst_cst4 (vector unsigned char vuc1, int i1, unsigned char * scp)
+{
+ return vec_st(vuc1, 24, scp);
+}
+
+void
+testst_cst5 (vector bool char vbc1, int i1, vector bool char * vbcp)
+{
+ return vec_st(vbc1, 28, vbcp);
+}
+
+void
+testst_cst6 (vector bool char vbc1, int i1, unsigned char * vucp)
+{
+ return vec_st(vbc1, 32, vucp);
+}
+
+void
+testst_cst7 (vector bool char vbc1, int i1, signed char * vscp)
+{
+ return vec_st(vbc1, 36, vscp);
+}
+
+/* { dg-final { scan-assembler-times {\mstvx\M} 14 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-st-double.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-double.c
new file mode 100644
index 0000000..100caf4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-double.c
@@ -0,0 +1,22 @@
+/* Verify that overloaded built-ins for vec_st with
+ double inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-mvsx -O2" } */
+
+#include <altivec.h>
+
+void
+testst_1 (vector double vd1, int i1, vector double * vdp)
+{
+ return vec_st(vd1, i1, vdp);
+}
+
+void
+testst_cst1 (vector double vd1, int i1, vector double * vdp)
+{
+ return vec_st(vd1, 12, vdp);
+}
+
+/* { dg-final { scan-assembler-times {\mstvx\M} 2 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-st-float.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-float.c
new file mode 100644
index 0000000..5a8fc66
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-float.c
@@ -0,0 +1,34 @@
+/* Verify that overloaded built-ins for vec_st with float
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2" } */
+
+#include <altivec.h>
+
+void
+testst_1 (vector float vf1, int i1, vector float * vfp)
+{
+ return vec_st(vf1, i1, vfp);
+}
+
+void
+testst_2 (vector float vf1, int i1, float * fp)
+{
+ return vec_st(vf1, i1, fp);
+}
+
+void
+testst_cst1 (vector float vf1, int i1, vector float * vfp)
+{
+ return vec_st(vf1, 16, vfp);
+}
+
+void
+testst_cst2 (vector float vf1, int i1, float * fp)
+{
+ return vec_st(vf1, 24, fp);
+}
+
+/* { dg-final { scan-assembler-times {\mstvx\M} 4 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-st-int.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-int.c
new file mode 100644
index 0000000..4db35f0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-int.c
@@ -0,0 +1,84 @@
+/* Verify that overloaded built-ins for vec_st* with int
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2" } */
+
+#include <altivec.h>
+// void vec_st (vector signed int, int, vector signed int *);
+
+void
+testst_1 (vector signed int vsi1, int i1, vector signed int * vsip)
+{
+ return vec_st(vsi1, i1, vsip);
+}
+void
+testst_2 (vector signed int vsi1, int i1, signed int * sip)
+{
+ return vec_st(vsi1, i1, sip);
+}
+void
+testst_3 (vector unsigned int vui1, int i1, vector unsigned int * vsip)
+{
+ return vec_st(vui1, i1, vsip);
+}
+void
+testst_4 (vector unsigned int vui1, int i1, unsigned int * sip)
+{
+ return vec_st(vui1, i1, sip);
+}
+void
+testst_5 (vector bool int vbi1, int i1, vector bool int * vbip)
+{
+ return vec_st(vbi1, i1, vbip);
+}
+void
+testst_6 (vector bool int vbi1, int i1, unsigned int * vuip)
+{
+ return vec_st(vbi1, i1, vuip);
+}
+void
+testst_7 (vector bool int vbi1, int i1, signed int * vsip)
+{
+ return vec_st(vbi1, i1, vsip);
+}
+
+void
+testst_cst1 (vector signed int vsi1, int i1, vector signed int * vsip)
+{
+ return vec_st(vsi1, 12, vsip);
+}
+void
+testst_cst2 (vector signed int vsi1, int i1, signed int * sip)
+{
+ return vec_st(vsi1, 16, sip);
+}
+void
+testst_cst3 (vector unsigned int vui1, int i1, vector unsigned int * vsip)
+{
+ return vec_st(vui1, 20, vsip);
+}
+void
+testst_cst4 (vector unsigned int vui1, int i1, unsigned int * sip)
+{
+ return vec_st(vui1, 24, sip);
+}
+void
+testst_cst5 (vector bool int vbi1, int i1, vector bool int * vbip)
+{
+ return vec_st(vbi1, 28, vbip);
+}
+void
+testst_cst6 (vector bool int vbi1, int i1, unsigned int * vuip)
+{
+ return vec_st(vbi1, 32, vuip);
+}
+void
+testst_cst7 (vector bool int vbi1, int i1, signed int * vsip)
+{
+ return vec_st(vbi1, 36, vsip);
+}
+
+/* { dg-final { scan-assembler-times {\mstvx\M} 14 } } */
+
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-st-longlong.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-longlong.c
new file mode 100644
index 0000000..a33f64e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-longlong.c
@@ -0,0 +1,41 @@
+/* Verify that overloaded built-ins for vec_st* with long long
+ inputs produce the right code. */
+
+/* { dg-do compile { target lp64 } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-options "-mpower8-vector -O2" } */
+
+#include <altivec.h>
+
+void
+testst_1 (vector signed long long vsll1, int i1, vector signed long long * vsllp)
+{
+ return vec_st(vsll1, i1, vsllp);
+}
+void
+testst_3 (vector unsigned long long vull1, int i1, vector unsigned long long * vsllp)
+{
+ return vec_st(vull1, i1, vsllp);
+}
+void
+testst_5 (vector bool long long vbll1, int i1, vector bool long long * vbllp)
+{
+ return vec_st(vbll1, i1, vbllp);
+}
+void
+testst_cst1 (vector signed long long vsll1, int i1, vector signed long long * vsllp)
+{
+ return vec_st(vsll1, 12, vsllp);
+}
+void
+testst_cst3 (vector unsigned long long vull1, int i1, vector unsigned long long * vsllp)
+{
+ return vec_st(vull1, 24, vsllp);
+}
+void
+testst_cst5 (vector bool long long vbll1, int i1, vector bool long long * vbllp)
+{
+ return vec_st(vbll1, 36, vbllp);
+}
+
+/* { dg-final { scan-assembler-times {\mstvx\M} 6 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-st-pixel.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-pixel.c
new file mode 100644
index 0000000..5b95cc7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-pixel.c
@@ -0,0 +1,22 @@
+/* Verify that overloaded built-ins for vec_st* with pixel
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_vsx_ok } */
+/* { dg-options "-mvsx -O2" } */
+
+#include <altivec.h>
+
+void
+testst_1 (vector pixel vp1, int i1, vector pixel * vpp)
+{
+ return vec_st(vp1, i1, vpp);
+}
+
+void
+testst_cst1 (vector pixel vp1, int i1, vector pixel * vpp)
+{
+ return vec_st(vp1, 12, vpp);
+}
+
+/* { dg-final { scan-assembler-times {\mstvx\M} 2 } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-st-short.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-short.c
new file mode 100644
index 0000000..ba8397e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-st-short.c
@@ -0,0 +1,83 @@
+/* Verify that overloaded built-ins for vec_st* with short
+ inputs produce the right code. */
+
+/* { dg-do compile } */
+/* { dg-require-effective-target powerpc_altivec_ok } */
+/* { dg-options "-maltivec -O2" } */
+
+#include <altivec.h>
+// vector signed short vec_ld (int, const vector signed short *);
+// void vec_st (vector signed short, int, vector signed short *);
+
+void
+testst_1 (vector signed short vss1, int i1, vector signed short * vssp)
+{
+ return vec_st(vss1, i1, vssp);
+}
+void
+testst_2 (vector signed short vss1, int i1, signed short * ssp)
+{
+ return vec_st(vss1, i1, ssp);
+}
+void
+testst_3 (vector unsigned short vus1, int i1, vector unsigned short * vusp)
+{
+ return vec_st(vus1, i1, vusp);
+}
+void
+testst_4 (vector unsigned short vus1, int i1, unsigned short * usp)
+{
+ return vec_st(vus1, i1, usp);
+}
+void
+testst_5 (vector bool short vbs1, int i1, vector bool short * vbsp)
+{
+ return vec_st(vbs1, i1, vbsp);
+}
+void
+testst_6 (vector bool short vbs1, int i1, unsigned short * vusp)
+{
+ return vec_st(vbs1, i1, vusp);
+}
+void
+testst_7 (vector bool short vbs1, int i1, signed short * vssp)
+{
+ return vec_st(vbs1, i1, vssp);
+}
+void
+testst_cst1 (vector signed short vss1, int i1, vector signed short * vssp)
+{
+ return vec_st(vss1, 12, vssp);
+}
+void
+testst_cst2 (vector signed short vss1, int i1, signed short * ssp)
+{
+ return vec_st(vss1, 16, ssp);
+}
+void
+testst_cst3 (vector unsigned short vus1, int i1, vector unsigned short * vusp)
+{
+ return vec_st(vus1, 20, vusp);
+}
+void
+testst_cst4 (vector unsigned short vus1, int i1, unsigned short * usp)
+{
+ return vec_st(vus1, 24, usp);
+}
+void
+testst_cst5 (vector bool short vbs1, int i1, vector bool short * vbsp)
+{
+ return vec_st(vbs1, 28, vbsp);
+}
+void
+testst_cst6 (vector bool short vbs1, int i1, unsigned short * vusp)
+{
+ return vec_st(vbs1, 32, vusp);
+}
+void
+testst_cst7 (vector bool short vbs1, int i1, signed short * vssp)
+{
+ return vec_st(vbs1, 36, vssp);
+}
+
+/* { dg-final { scan-assembler-times {\mstvx\M} 14} } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr71977-1.c b/gcc/testsuite/gcc.target/powerpc/pr71977-1.c
index 1cb2ec3..65dd3ab 100644
--- a/gcc/testsuite/gcc.target/powerpc/pr71977-1.c
+++ b/gcc/testsuite/gcc.target/powerpc/pr71977-1.c
@@ -23,9 +23,9 @@ mask_and_float_var (float f, uint32_t mask)
return u.value;
}
-/* { dg-final { scan-assembler "\[ \t\]xxland " } } */
-/* { dg-final { scan-assembler-not "\[ \t\]and " } } */
-/* { dg-final { scan-assembler-not "\[ \t\]mfvsrd " } } */
-/* { dg-final { scan-assembler-not "\[ \t\]stxv" } } */
-/* { dg-final { scan-assembler-not "\[ \t\]lxv" } } */
-/* { dg-final { scan-assembler-not "\[ \t\]srdi " } } */
+/* { dg-final { scan-assembler {\mxxland\M} } } */
+/* { dg-final { scan-assembler-not {\mand\M} } } */
+/* { dg-final { scan-assembler-not {\mmfvsrd\M} } } */
+/* { dg-final { scan-assembler-not {\mstxv\M} } } */
+/* { dg-final { scan-assembler-not {\mlxv\M} } } */
+/* { dg-final { scan-assembler-not {\msrdi\M} } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/pr77687.c b/gcc/testsuite/gcc.target/powerpc/pr77687.c
new file mode 100644
index 0000000..95b27ae
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr77687.c
@@ -0,0 +1,20 @@
+/* { dg-options "-std=gnu99 -O2" } */
+/* { dg-final { scan-assembler-not {\mmr r?1,r?11\M.*11.*\mblr\M} } } */
+
+/* PR77687: We used to do stack accesses (via r11) after restoring r1. */
+
+void g(int, char *);
+const char * dum = "hello";
+
+void f(int x)
+{
+ char big[200000];
+ start:
+ g(x, big);
+ g(x, big);
+ register void *p asm("r11") = &&start;
+ asm("" : : "r"(p));
+ asm("" : : :"r28");
+ asm("" : : :"r29");
+ asm("" : : :"r30");
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/pr80210-2.c b/gcc/testsuite/gcc.target/powerpc/pr80210-2.c
new file mode 100644
index 0000000..455f7d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/pr80210-2.c
@@ -0,0 +1,11 @@
+/* Test for ICE arising from GCC target pragma. */
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+#pragma GCC target "no-powerpc-gpopt"
+double
+foo (double a)
+{
+ return __builtin_sqrt (a);
+}
+/* { dg-final { scan-assembler-not "fsqrt" } } */
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-28.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-28.c
new file mode 100644
index 0000000..4ab2bc3
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-28.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector char y = { 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14, 15 };
+
+vector char
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector char fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[15] != 15)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-29.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-29.c
new file mode 100644
index 0000000..d2025df
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-29.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector char y = { 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14, 15 };
+
+vector char
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector char fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[15] != 15)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-30.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-30.c
new file mode 100644
index 0000000..9421dbb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-30.c
@@ -0,0 +1,31 @@
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+/* { dg-final { scan-assembler-not "xxpermdi" } } */
+/* { dg-final { scan-assembler-not "xxswapd" } } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector char y = { 0, 1, 2, 3,
+ 4, 5, 6, 7,
+ 8, 9, 10, 11,
+ 12, 13, 14, 15 };
+
+vector char
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector char fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[15] != 15)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-31.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-31.c
new file mode 100644
index 0000000..a3c2f82
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-31.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector short y = { 0, 1, 2, 3,
+ 4, 5, 6, 7 };
+
+vector short
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector short fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[7] != 7)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-32.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-32.c
new file mode 100644
index 0000000..57b76ec
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-32.c
@@ -0,0 +1,27 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector short y = { 0, 1, 2, 3,
+ 4, 5, 6, 7 };
+
+vector short
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector short fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[7] != 7)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-33.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-33.c
new file mode 100644
index 0000000..2289be4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-33.c
@@ -0,0 +1,29 @@
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+/* { dg-final { scan-assembler-not "xxpermdi" } } */
+/* { dg-final { scan-assembler-not "xxswapd" } } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector short y = { 0, 1, 2, 3,
+ 4, 5, 6, 7 };
+
+vector short
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector short fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[15] != 15)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-34.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-34.c
new file mode 100644
index 0000000..a7ddb01
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-34.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector int y = { 0, 1, 2, 3 };
+
+vector int
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector int fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[3] != 3)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-35.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-35.c
new file mode 100644
index 0000000..da98e90
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-35.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector int y = { 0, 1, 2, 3 };
+
+vector int
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector int fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[3] != 3)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-36.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-36.c
new file mode 100644
index 0000000..52990a6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-36.c
@@ -0,0 +1,28 @@
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+/* { dg-final { scan-assembler-not "xxpermdi" } } */
+/* { dg-final { scan-assembler-not "xxswapd" } } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector int y = { 0, 1, 2, 3 };
+
+vector int
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector int fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[3] != 3)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-37.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-37.c
new file mode 100644
index 0000000..4d8ae11
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-37.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector float y = { 0.0f, 0.1f, 0.2f, 0.3f };
+
+vector float
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector float fetched_value = foo ();
+ if (fetched_value[0] != 0.0f || fetched_value[3] != 0.3f)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-38.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-38.c
new file mode 100644
index 0000000..bf08574
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-38.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector float y = { 0.0f, 0.1f, 0.2f, 0.3f };
+
+vector float
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector float fetched_value = foo ();
+ if (fetched_value[0] != 0.0f || fetched_value[3] != 0.3f)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-39.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-39.c
new file mode 100644
index 0000000..8cd68dd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-39.c
@@ -0,0 +1,28 @@
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+/* { dg-final { scan-assembler-not "xxpermdi" } } */
+/* { dg-final { scan-assembler-not "xxswapd" } } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector float y = { 0.0f, 0.1f, 0.2f, 0.3f };
+
+vector float
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector float fetched_value = foo ();
+ if (fetched_value[0] != 0.0f || fetched_value[3] != 0.3)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-40.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-40.c
new file mode 100644
index 0000000..3d1bd3f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-40.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector long long int y = { 0, 1 };
+
+vector long long int
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, int *argv[])
+{
+ vector long long int fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[1] != 1)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-41.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-41.c
new file mode 100644
index 0000000..3ac52fd
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-41.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector long long int y = { 0, 1 };
+
+vector long long int
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector long long int fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[1] != 1)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-42.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-42.c
new file mode 100644
index 0000000..1f2a73a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-42.c
@@ -0,0 +1,28 @@
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+/* { dg-final { scan-assembler-not "xxpermdi" } } */
+/* { dg-final { scan-assembler-not "xxswapd" } } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector long long int y = { 0, 1 };
+
+vector long long int
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector long long int fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[1] != 1)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-43.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-43.c
new file mode 100644
index 0000000..c3caf88
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-43.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+vector double y = { 0.0, 0.1 };
+
+vector double
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector double fetched_value = foo ();
+ if (fetched_value[0] != 0 || fetched_value[1] != 0.1)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-44.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-44.c
new file mode 100644
index 0000000..8ab513c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-44.c
@@ -0,0 +1,26 @@
+/* { dg-do run { target { powerpc*-*-* } } } */
+/* { dg-require-effective-target p8vector_hw } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector double y = { 0.0, 0.1 };
+
+vector double
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector double fetched_value = foo ();
+ if (fetched_value[0] != 0.0 || fetched_value[1] != 0.1)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/swaps-p8-45.c b/gcc/testsuite/gcc.target/powerpc/swaps-p8-45.c
new file mode 100644
index 0000000..6995358
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/swaps-p8-45.c
@@ -0,0 +1,28 @@
+/* { dg-do compile { target { powerpc64le-*-* } } } */
+/* { dg-require-effective-target powerpc_p8vector_ok } */
+/* { dg-skip-if "do not override -mcpu" { powerpc*-*-* } { "-mcpu=*" } { "-mcpu=power8" } } */
+/* { dg-options "-mcpu=power8 -O3 " } */
+/* { dg-final { scan-assembler-not "xxpermdi" } } */
+/* { dg-final { scan-assembler-not "xxswapd" } } */
+
+#include <altivec.h>
+
+extern void abort (void);
+
+const vector double y = { 0.0, 0.1 };
+
+vector double
+foo (void)
+{
+ return y;
+}
+
+int
+main (int argc, char *argv[])
+{
+ vector double fetched_value = foo ();
+ if (fetched_value[0] != 0.0 || fetched_value[15] != 0.1)
+ abort ();
+ else
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.target/s390/zvector/pr82317.c b/gcc/testsuite/gcc.target/s390/zvector/pr82317.c
new file mode 100644
index 0000000..4b7cc83
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/pr82317.c
@@ -0,0 +1,19 @@
+/* { dg-do compile { target { s390*-*-* } } } */
+/* { dg-options "-march=z13 -mzarch -mzvector" } */
+
+/* With IBM z14 a hardware instruction for floating point min and max
+ has been added while for IBM z13 we emulated min/max for vector
+ double with compare and select. This testcase makes sure that we
+ fall back to the emulated variant when compiling for z13. */
+
+#include <vecintrin.h>
+
+vector double
+foo (vector double a, vector double b) {
+ return vec_min (a, b);
+}
+
+vector double
+bar (vector double a, vector double b) {
+ return vec_max (a, b);
+}
diff --git a/gcc/testsuite/gcc.target/s390/zvector/pr82322.c b/gcc/testsuite/gcc.target/s390/zvector/pr82322.c
new file mode 100644
index 0000000..87410e7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/pr82322.c
@@ -0,0 +1,22 @@
+/* { dg-do compile { target { s390*-*-* } } } */
+/* { dg-options "-march=z14 -mzarch -mzvector" } */
+
+/* vec_ceil and friends are expanded by vecintrin.h to
+ __builtin_s390_vfi which is an overloaded builtin being replaced by
+ either __builtin_s390_vfisb or __builtin_s390_vfidb depending on
+ its argument types.
+
+ The problem in this PR was that the overloaded builtin definition
+ was missing in s390-builtins.def. */
+
+#include <vecintrin.h>
+
+vector double
+foo (vector double a) {
+ return vec_ceil (a);
+}
+
+vector float
+bar (vector float a) {
+ return vec_ceil (a);
+}
diff --git a/gcc/testsuite/gcc.target/s390/zvector/pr82463.c b/gcc/testsuite/gcc.target/s390/zvector/pr82463.c
new file mode 100644
index 0000000..5014ed6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/pr82463.c
@@ -0,0 +1,14 @@
+/* { dg-do compile { target { s390*-*-* } } } */
+/* { dg-options "-march=z14 -mzarch -mzvector" } */
+
+/* The builtin was not correctly defined in the vecintrin.h header
+ file. */
+
+#include <vecintrin.h>
+
+typedef __vector float v4sf;
+
+v4sf
+foo (v4sf a, v4sf b, v4sf c) {
+ return vec_madd(a, b, c);
+}
diff --git a/gcc/testsuite/gcc.target/s390/zvector/pr82465.c b/gcc/testsuite/gcc.target/s390/zvector/pr82465.c
new file mode 100644
index 0000000..ae8f8ad
--- /dev/null
+++ b/gcc/testsuite/gcc.target/s390/zvector/pr82465.c
@@ -0,0 +1,16 @@
+/* { dg-do compile { target { s390*-*-* } } } */
+/* { dg-options "-march=z13 -mzarch -mzvector" } */
+
+/* The vector double variant is available with z13. A wrong flag in
+ the s390-builtins.def file triggered an error when compiling for
+ z13. */
+
+typedef __vector double v2df;
+
+#include <vecintrin.h>
+
+v2df
+foo (v2df a)
+{
+ return vec_sqrt(a);
+}
diff --git a/gcc/testsuite/gcc.target/s390/zvector/vec-cmp-2.c b/gcc/testsuite/gcc.target/s390/zvector/vec-cmp-2.c
index 0711f9c..1e63def 100644
--- a/gcc/testsuite/gcc.target/s390/zvector/vec-cmp-2.c
+++ b/gcc/testsuite/gcc.target/s390/zvector/vec-cmp-2.c
@@ -7,197 +7,197 @@
#include <vecintrin.h>
-extern void foo (void);
+int g = 1;
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_eq_double (vector double a, vector double b)
{
if (__builtin_expect (vec_all_eq (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_eq_double:\n\tvfcedbs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_ne_double (vector double a, vector double b)
{
if (__builtin_expect (vec_all_ne (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_ne_double:\n\tvfcedbs\t%v\[0-9\]*,%v24,%v26\n\tjle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_gt_double (vector double a, vector double b)
{
if (__builtin_expect (vec_all_gt (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_gt_double:\n\tvfchdbs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_lt_double (vector double a, vector double b)
{
if (__builtin_expect (vec_all_lt (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_lt_double:\n\tvfchdbs\t%v\[0-9\]*,%v26,%v24\n\tjne 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_ge_double (vector double a, vector double b)
{
if (__builtin_expect (vec_all_ge (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_ge_double:\n\tvfchedbs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_le_double (vector double a, vector double b)
{
if (__builtin_expect (vec_all_le (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_le_double:\n\tvfchedbs\t%v\[0-9\]*,%v26,%v24\n\tjne 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_eq_double (vector double a, vector double b)
{
if (__builtin_expect (vec_any_eq (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_eq_double:\n\tvfcedbs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_ne_double (vector double a, vector double b)
{
if (__builtin_expect (vec_any_ne (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_ne_double:\n\tvfcedbs\t%v\[0-9\]*,%v24,%v26\n\tje 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_gt_double (vector double a, vector double b)
{
if (__builtin_expect (vec_any_gt (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_gt_double:\n\tvfchdbs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_lt_double (vector double a, vector double b)
{
if (__builtin_expect (vec_any_lt (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_lt_double:\n\tvfchdbs\t%v\[0-9\]*,%v26,%v24\n\tjnle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_ge_double (vector double a, vector double b)
{
if (__builtin_expect (vec_any_ge (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_ge_double:\n\tvfchedbs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_le_double (vector double a, vector double b)
{
if (__builtin_expect (vec_any_le (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_le_double:\n\tvfchedbs\t%v\[0-9\]*,%v26,%v24\n\tjnle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_eq_int (vector int a, vector int b)
{
if (__builtin_expect (vec_all_eq (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_eq_int:\n\tvceqfs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_ne_int (vector int a, vector int b)
{
if (__builtin_expect (vec_all_ne (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_ne_int:\n\tvceqfs\t%v\[0-9\]*,%v24,%v26\n\tjle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_gt_int (vector int a, vector int b)
{
if (__builtin_expect (vec_all_gt (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_gt_int:\n\tvchfs\t%v\[0-9\]*,%v24,%v26\n\tjne 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_lt_int (vector int a, vector int b)
{
if (__builtin_expect (vec_all_lt (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_lt_int:\n\tvchfs\t%v\[0-9\]*,%v26,%v24\n\tjne 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_ge_int (vector int a, vector int b)
{
if (__builtin_expect (vec_all_ge (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_ge_int:\n\tvchfs\t%v\[0-9\]*,%v26,%v24\n\tjle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
all_le_int (vector int a, vector int b)
{
if (__builtin_expect (vec_all_le (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times all_le_int:\n\tvchfs\t%v\[0-9\]*,%v24,%v26\n\tjle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_eq_int (vector int a, vector int b)
{
if (__builtin_expect (vec_any_eq (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_eq_int:\n\tvceqfs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_ne_int (vector int a, vector int b)
{
if (__builtin_expect (vec_any_ne (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_ne_int:\n\tvceqfs\t%v\[0-9\]*,%v24,%v26\n\tje 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_gt_int (vector int a, vector int b)
{
if (__builtin_expect (vec_any_gt (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_gt_int:\n\tvchfs\t%v\[0-9\]*,%v24,%v26\n\tjnle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_lt_int (vector int a, vector int b)
{
if (__builtin_expect (vec_any_lt (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_lt_int:\n\tvchfs\t%v\[0-9\]*,%v26,%v24\n\tjnle 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_ge_int (vector int a, vector int b)
{
if (__builtin_expect (vec_any_ge (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_ge_int:\n\tvchfs\t%v\[0-9\]*,%v26,%v24\n\tje 1 } } */
-int __attribute__((noinline,noclone))
+void __attribute__((noinline,noclone))
any_le_int (vector int a, vector int b)
{
if (__builtin_expect (vec_any_le (a, b), 1))
- foo ();
+ g = 2;
}
/* { dg-final { scan-assembler-times any_le_int:\n\tvchfs\t%v\[0-9\]*,%v24,%v26\n\tje 1 } } */
diff --git a/gcc/testsuite/gfortran.dg/argument_checking_10.f90 b/gcc/testsuite/gfortran.dg/argument_checking_10.f90
index 315ee03..db49e71 100644
--- a/gcc/testsuite/gfortran.dg/argument_checking_10.f90
+++ b/gcc/testsuite/gfortran.dg/argument_checking_10.f90
@@ -8,7 +8,7 @@ IMPLICIT NONE
INTEGER :: i(-1:1)
INTEGER :: j(-2:-1)
CALL S(i)
-CALL S(j) ! { dg-warning "Actual argument contains too few elements for dummy argument 'i' .2/3." }
+CALL S(j) ! { dg-error "Actual argument contains too few elements for dummy argument 'i' .2/3." }
CONTAINS
SUBROUTINE S(i)
INTEGER :: i(0:2)
diff --git a/gcc/testsuite/gfortran.dg/argument_checking_13.f90 b/gcc/testsuite/gfortran.dg/argument_checking_13.f90
index b94bbc7..26e9497 100644
--- a/gcc/testsuite/gfortran.dg/argument_checking_13.f90
+++ b/gcc/testsuite/gfortran.dg/argument_checking_13.f90
@@ -53,8 +53,8 @@ call rlv2(pointer_dummy(1,1,1)) ! Valid F2003
! We warn nonetheless as the result is not what is intented
! and also formally wrong.
! Using (1:string_length) would be ok.
-call rlv2(ptr(1,1,1)(1:1)) ! { dg-warning "contains too few elements" }
-call rlv2(assumed_sh_dummy(1,1,1)(1:2)) ! { dg-warning "contains too few elements" }
+call rlv2(ptr(1,1,1)(1:1)) ! { dg-error "contains too few elements" }
+call rlv2(assumed_sh_dummy(1,1,1)(1:2)) ! { dg-error "contains too few elements" }
call rlv2(pointer_dummy(1,1,1)(1:3)) ! Valid F2003
end
@@ -72,12 +72,12 @@ character(2), pointer :: pointer_dummy(:,:,:)
character(2), allocatable :: deferred(:,:,:)
character(2), pointer :: ptr(:,:,:)
call rlv3(deferred(1,1,1)) ! Valid since contiguous
-call rlv3(ptr(1,1,1)) ! { dg-warning "contains too few elements" }
-call rlv3(assumed_sh_dummy(1,1,1)) ! { dg-warning "contains too few elements" }
-call rlv3(pointer_dummy(1,1,1)) ! { dg-warning "contains too few elements" }
+call rlv3(ptr(1,1,1)) ! { dg-error "contains too few elements" }
+call rlv3(assumed_sh_dummy(1,1,1)) ! { dg-error "contains too few elements" }
+call rlv3(pointer_dummy(1,1,1)) ! { dg-error "contains too few elements" }
call rlv3(deferred(1,1,1)(1:2)) ! Valid since contiguous
-call rlv3(ptr(1,1,1)(1:2)) ! { dg-warning "contains too few elements" }
-call rlv3(assumed_sh_dummy(1,1,1)(1:2)) ! { dg-warning "contains too few elements" }
-call rlv3(pointer_dummy(1,1,1)(1:2)) ! { dg-warning "contains too few elements" }
+call rlv3(ptr(1,1,1)(1:2)) ! { dg-error "contains too few elements" }
+call rlv3(assumed_sh_dummy(1,1,1)(1:2)) ! { dg-error "contains too few elements" }
+call rlv3(pointer_dummy(1,1,1)(1:2)) ! { dg-error "contains too few elements" }
end
diff --git a/gcc/testsuite/gfortran.dg/argument_checking_15.f90 b/gcc/testsuite/gfortran.dg/argument_checking_15.f90
index 5d3c9f6..e79541f 100644
--- a/gcc/testsuite/gfortran.dg/argument_checking_15.f90
+++ b/gcc/testsuite/gfortran.dg/argument_checking_15.f90
@@ -14,20 +14,20 @@ character(len=4) :: str2(2,2)
call test()
-call foo(i(8)) ! { dg-warning "too few elements for dummy argument 'a' .3/4." }
+call foo(i(8)) ! { dg-error "too few elements for dummy argument 'a' .3/4." }
call foo(j(1,1))
-call foo(j(2,1)) ! { dg-warning "too few elements for dummy argument 'a' .3/4." }
-call foo(j(1,2)) ! { dg-warning "too few elements for dummy argument 'a' .2/4." }
+call foo(j(2,1)) ! { dg-error "too few elements for dummy argument 'a' .3/4." }
+call foo(j(1,2)) ! { dg-error "too few elements for dummy argument 'a' .2/4." }
str = 'FORT'
str2 = 'fort'
-call bar(str(:)(1:2)) ! { dg-warning "too few elements for dummy argument 'c' .4/6." }
-call bar(str(1:2)(1:1)) ! { dg-warning "too few elements for dummy argument 'c' .2/6." }
-call bar(str(2)) ! { dg-warning "too few elements for dummy argument 'c' .4/6." }
+call bar(str(:)(1:2)) ! { dg-error "too few elements for dummy argument 'c' .4/6." }
+call bar(str(1:2)(1:1)) ! { dg-error "too few elements for dummy argument 'c' .2/6." }
+call bar(str(2)) ! { dg-error "too few elements for dummy argument 'c' .4/6." }
call bar(str(1)(2:1)) ! OK
call bar(str2(2,1)(4:1)) ! OK
call bar(str2(1,2)(3:4)) ! OK
-call bar(str2(1,2)(4:4)) ! { dg-warning "too few elements for dummy argument 'c' .5/6." }
+call bar(str2(1,2)(4:4)) ! { dg-error "too few elements for dummy argument 'c' .5/6." }
contains
subroutine foo(a)
integer :: a(4)
diff --git a/gcc/testsuite/gfortran.dg/argument_checking_18.f90 b/gcc/testsuite/gfortran.dg/argument_checking_18.f90
index dd95b61..613a8a7 100644
--- a/gcc/testsuite/gfortran.dg/argument_checking_18.f90
+++ b/gcc/testsuite/gfortran.dg/argument_checking_18.f90
@@ -14,8 +14,8 @@
tt%j = i
- call sub1 (i) ! { dg-warning "Actual argument contains too few elements" }
- call sub1 (tt%j) ! { dg-warning "Actual argument contains too few elements" }
+ call sub1 (i) ! { dg-error "Actual argument contains too few elements" }
+ call sub1 (tt%j) ! { dg-error "Actual argument contains too few elements" }
call sub2 (i) ! { dg-error "Rank mismatch in argument" }
call sub2 (tt%j) ! { dg-error "Rank mismatch in argument" }
diff --git a/gcc/testsuite/gfortran.dg/argument_checking_3.f90 b/gcc/testsuite/gfortran.dg/argument_checking_3.f90
index 5f451bf..4498957 100644
--- a/gcc/testsuite/gfortran.dg/argument_checking_3.f90
+++ b/gcc/testsuite/gfortran.dg/argument_checking_3.f90
@@ -25,12 +25,12 @@ end interface
call foo(len2) ! { dg-error "Rank mismatch in argument" }
call foo("ca") ! { dg-error "Rank mismatch in argument" }
call bar("ca") ! { dg-error "Rank mismatch in argument" }
- call foobar(len2) ! { dg-warning "contains too few elements" }
+ call foobar(len2) ! { dg-error "contains too few elements" }
call foobar(len4)
- call foobar("bar") ! { dg-warning "contains too few elements" }
+ call foobar("bar") ! { dg-error "contains too few elements" }
call foobar("bar33")
- call arr(len2) ! { dg-warning "contains too few elements" }
+ call arr(len2) ! { dg-error "contains too few elements" }
call arr(len4)
- call arr("bar") ! { dg-warning "contains too few elements" }
+ call arr("bar") ! { dg-error "contains too few elements" }
call arr("bar33")
end program test
diff --git a/gcc/testsuite/gfortran.dg/argument_checking_4.f90 b/gcc/testsuite/gfortran.dg/argument_checking_4.f90
index a2a56e8..702b37a 100644
--- a/gcc/testsuite/gfortran.dg/argument_checking_4.f90
+++ b/gcc/testsuite/gfortran.dg/argument_checking_4.f90
@@ -12,10 +12,10 @@ interface
end subroutine arr
end interface
- call foobar( [ "bar" ]) ! { dg-warning "contains too few elements" }
+ call foobar( [ "bar" ]) ! { dg-error "contains too few elements" }
call foobar( ["ba ","r33"])
- call arr( [ "bar" ]) ! { dg-warning "contains too few elements" }
+ call arr( [ "bar" ]) ! { dg-error "contains too few elements" }
call arr( reshape(["b","a","r","3"], [2,2]))
- call arr( reshape(["b","a"], [1,2])) ! { dg-warning "contains too few elements" }
- call arr( reshape(["b","a"], [2,1])) ! { dg-warning "contains too few elements" }
+ call arr( reshape(["b","a"], [1,2])) ! { dg-error "contains too few elements" }
+ call arr( reshape(["b","a"], [2,1])) ! { dg-error "contains too few elements" }
end program test
diff --git a/gcc/testsuite/gfortran.dg/argument_checking_5.f90 b/gcc/testsuite/gfortran.dg/argument_checking_5.f90
index 3715b30..f19d9aa 100644
--- a/gcc/testsuite/gfortran.dg/argument_checking_5.f90
+++ b/gcc/testsuite/gfortran.dg/argument_checking_5.f90
@@ -13,23 +13,23 @@ interface
end interface
integer a(3), b(5)
-call foobar(a) ! { dg-warning "contains too few elements" }
+call foobar(a) ! { dg-error "contains too few elements" }
call foobar(b)
-call foobar(b(1:3)) ! { dg-warning "contains too few elements" }
+call foobar(b(1:3)) ! { dg-error "contains too few elements" }
call foobar(b(1:5))
-call foobar(b(1:5:2)) ! { dg-warning "contains too few elements" }
+call foobar(b(1:5:2)) ! { dg-error "contains too few elements" }
call foobar(b(2))
-call foobar(b(3)) ! { dg-warning "Actual argument contains too few elements" }
-call foobar(reshape(a(1:3),[2,1])) ! { dg-warning "contains too few elements" }
+call foobar(b(3)) ! { dg-error "Actual argument contains too few elements" }
+call foobar(reshape(a(1:3),[2,1])) ! { dg-error "contains too few elements" }
call foobar(reshape(b(2:5),[2,2]))
-call arr(a) ! { dg-warning "contains too few elements" }
+call arr(a) ! { dg-error "contains too few elements" }
call arr(b)
-call arr(b(1:3)) ! { dg-warning "contains too few elements" }
+call arr(b(1:3)) ! { dg-error "contains too few elements" }
call arr(b(1:5))
-call arr(b(1:5:2)) ! { dg-warning "contains too few elements" }
+call arr(b(1:5:2)) ! { dg-error "contains too few elements" }
call arr(b(2))
-call arr(b(3)) ! { dg-warning "contains too few elements" }
-call arr(reshape(a(1:3),[2,1])) ! { dg-warning "contains too few elements" }
+call arr(b(3)) ! { dg-error "contains too few elements" }
+call arr(reshape(a(1:3),[2,1])) ! { dg-error "contains too few elements" }
call arr(reshape(b(2:5),[2,2]))
end program test
diff --git a/gcc/testsuite/gfortran.dg/argument_checking_6.f90 b/gcc/testsuite/gfortran.dg/argument_checking_6.f90
index e2d2692..3742ab6 100644
--- a/gcc/testsuite/gfortran.dg/argument_checking_6.f90
+++ b/gcc/testsuite/gfortran.dg/argument_checking_6.f90
@@ -14,7 +14,7 @@ real,dimension(-1:2) :: z
call sub(x(:))
call sub(y(:))
call sub(z(:))
-call sub(w(:)) ! { dg-warning "too few elements" }
+call sub(w(:)) ! { dg-error "too few elements" }
contains
subroutine sub(a)
diff --git a/gcc/testsuite/gfortran.dg/array_constructor_51.f90 b/gcc/testsuite/gfortran.dg/array_constructor_51.f90
new file mode 100644
index 0000000..4c3cdf7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/array_constructor_51.f90
@@ -0,0 +1,20 @@
+! { dg-do compile }
+! { dg-additional-options "-ffrontend-optimize -fdump-tree-original" }
+! PR 82567 - long compile times caused by large constant constructors
+! multiplied by variables
+
+ SUBROUTINE sub()
+ IMPLICIT NONE
+
+ INTEGER, PARAMETER :: n = 1000
+ REAL, ALLOCATABLE :: x(:)
+ REAL :: xc, h
+ INTEGER :: i
+
+ ALLOCATE( x(n) )
+ xc = 100.
+ h = xc/n
+ x = h*[(i,i=1,n)]
+
+end
+! { dg-final { scan-tree-dump-times "__var" 0 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/associate_26.f90 b/gcc/testsuite/gfortran.dg/associate_26.f90
new file mode 100644
index 0000000..ae19aca
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_26.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+! { dg-options "-fcoarray=single" }
+!
+! Test the fix for PR78152
+!
+! Contributed by <physiker@toast2.net>
+!
+program co_assoc
+ implicit none
+ integer, parameter :: p = 5
+ real, allocatable :: a(:,:)[:,:]
+ allocate (a(p,p)[2,*])
+ associate (i => a(1:p, 1:p))
+ end associate
+end program co_assoc
diff --git a/gcc/testsuite/gfortran.dg/associate_27.f90 b/gcc/testsuite/gfortran.dg/associate_27.f90
new file mode 100644
index 0000000..6fcb8a9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_27.f90
@@ -0,0 +1,23 @@
+! { dg-do run }
+!
+! Test the fix for PR80120
+!
+! Contributed by Marco Restelli <mrestelli@gmail.com>
+!
+program p
+ implicit none
+
+ type :: t
+ character(len=25) :: text(2)
+ end type t
+ type(t) :: x
+
+ x%text(1) = "ABC"
+ x%text(2) = "defgh"
+
+ associate( c => x%text )
+ if (c(1)(:maxval(len_trim(c))) .ne. trim (x%text(1))) call abort
+ if (c(2)(:maxval(len_trim(c))) .ne. trim (x%text(2))) call abort
+ end associate
+
+end program p
diff --git a/gcc/testsuite/gfortran.dg/associate_28.f90 b/gcc/testsuite/gfortran.dg/associate_28.f90
new file mode 100644
index 0000000..8715472
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_28.f90
@@ -0,0 +1,64 @@
+! { dg-do run }
+!
+! Test the fix for PR81903
+!
+! Contributed by Karl May <karl.may0@freenet.de>
+!
+Module TestMod_A
+ Type :: TestType_A
+ Real, Allocatable :: a(:,:)
+ End type TestType_A
+End Module TestMod_A
+Module TestMod_B
+ Type :: TestType_B
+ Real, Pointer, contiguous :: a(:,:)
+ End type TestType_B
+End Module TestMod_B
+Module TestMod_C
+ use TestMod_A
+ use TestMod_B
+ Implicit None
+ Type :: TestType_C
+ Class(TestType_A), Pointer :: TT_A(:)
+ Type(TestType_B), Allocatable :: TT_B(:)
+ contains
+ Procedure, Pass :: SetPt => SubSetPt
+ End type TestType_C
+ Interface
+ Module Subroutine SubSetPt(this)
+ class(TestType_C), Intent(InOut), Target :: this
+ End Subroutine
+ End Interface
+End Module TestMod_C
+Submodule(TestMod_C) SetPt
+contains
+ Module Procedure SubSetPt
+ Implicit None
+ integer :: i
+ integer :: sum_a = 0
+ outer:block
+ associate(x=>this%TT_B,y=>this%TT_A)
+ Do i=1,size(x)
+ x(i)%a=>y(i)%a
+ sum_a = sum_a + sum (int (x(i)%a))
+ End Do
+ end associate
+ End block outer
+ if (sum_a .ne. 30) call abort
+ End Procedure
+End Submodule SetPt
+Program Test
+ use TestMod_C
+ use TestMod_A
+ Implicit None
+ Type(TestType_C) :: tb
+ Type(TestType_A), allocatable, Target :: ta(:)
+ integer :: i
+ real :: src(2,2) = reshape ([(real(i), i = 1,4)],[2,2])
+ allocate(ta(2),tb%tt_b(2))
+ do i=1,size(ta)
+ allocate(ta(i)%a(2,2), source = src*real(i))
+ End do
+ tb%TT_A=>ta
+ call tb%setpt()
+End Program Test
diff --git a/gcc/testsuite/gfortran.dg/associate_29.f90 b/gcc/testsuite/gfortran.dg/associate_29.f90
new file mode 100644
index 0000000..786e3c5
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_29.f90
@@ -0,0 +1,30 @@
+! { dg-do compile }
+!
+! Test the fix for PR82121
+!
+! Contributed by Iain Miller <iain.miller@ecmwf.int>
+!
+MODULE YOMCDDH
+ IMPLICIT NONE
+ SAVE
+ TYPE :: TCDDH
+ CHARACTER(len=12),ALLOCATABLE :: CADHTLS(:)
+ END TYPE TCDDH
+ CHARACTER(len=12),ALLOCATABLE :: CADHTTS(:)
+ TYPE(TCDDH), POINTER :: YRCDDH => NULL()
+END MODULE YOMCDDH
+
+
+SUBROUTINE SUCDDH()
+ USE YOMCDDH , ONLY : YRCDDH,CADHTTS
+ IMPLICIT NONE
+ ALLOCATE (YRCDDH%CADHTLS(20))
+ ALLOCATE (CADHTTS(20))
+ ASSOCIATE(CADHTLS=>YRCDDH%CADHTLS, NORMCHAR=>CADHTTS)
+! Direct reference to character array compiled correctly
+! YRCDDH%CADHTLS(1)='SVGTLF'
+! Reference to associated variable name failed to compile
+ CADHTLS(2)='SVGTLT'
+ NORMCHAR(1)='SVLTTC'
+ END ASSOCIATE
+END SUBROUTINE SUCDDH
diff --git a/gcc/testsuite/gfortran.dg/associate_30.f90 b/gcc/testsuite/gfortran.dg/associate_30.f90
new file mode 100644
index 0000000..ad15d8b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_30.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+!
+! Test the fix for PR67543
+!
+! Contributed by Gerhard Steinmetz <gerhard.steinmetz.fortran@t-online.de>
+!
+ subroutine s1
+ associate (x => null()) ! { dg-error "cannot be NULL()" }
+ end associate
+ end subroutine
+
+ subroutine s2
+ associate (x => [null()]) ! { dg-error "has no type" }
+ end associate
+ end subroutine
diff --git a/gcc/testsuite/gfortran.dg/associate_32.f03 b/gcc/testsuite/gfortran.dg/associate_32.f03
new file mode 100644
index 0000000..9a1f598
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/associate_32.f03
@@ -0,0 +1,93 @@
+! { dg-do run }
+!
+! Tests fix for PR77296 and other bugs found on the way.
+!
+! Contributed by Matt Thompson <matthew.thompson@nasa.gov>
+!
+program test
+
+ implicit none
+ type :: str_type
+ character(len=:), allocatable :: str
+ end type
+
+ character(len=:), allocatable :: s, sd(:)
+ character(len=2), allocatable :: sf, sfd(:)
+ character(len=6) :: str
+ type(str_type) :: string
+
+ s = 'ab'
+ associate(ss => s)
+ if (ss .ne. 'ab') call abort ! This is the original bug.
+ ss = 'c'
+ end associate
+ if (s .ne. 'c ') call abort ! No reallocation within ASSOCIATE block!
+
+ sf = 'c'
+ associate(ss => sf)
+ if (ss .ne. 'c ') call abort ! This the bug in comment #2 of the PR.
+ ss = 'cd'
+ end associate
+
+ sd = [s, sf]
+ associate(ss => sd)
+ if (any (ss .ne. ['c ','cd'])) call abort
+ end associate
+
+ sfd = [sd,'ef']
+ associate(ss => sfd)
+ if (any (ss .ne. ['c ','cd','ef'])) call abort
+ ss = ['gh']
+ end associate
+ if (any (sfd .ne. ['gh','cd','ef'])) call abort ! No reallocation!
+
+ string%str = 'xyz'
+ associate(ss => string%str)
+ if (ss .ne. 'xyz') call abort
+ ss = 'c'
+ end associate
+ if (string%str .ne. 'c ') call abort ! No reallocation!
+
+ str = "foobar"
+ call test_char (5 , str)
+ IF (str /= "abcder") call abort
+
+ associate(ss => foo())
+ if (ss .ne. 'pqrst') call abort
+ end associate
+
+ associate(ss => bar())
+ if (ss(2) .ne. 'uvwxy') call abort
+ end associate
+
+! The deallocation is not strictly necessary but it does allow
+! other memory leakage to be tested for.
+ deallocate (s, sd, sf, sfd, string%str)
+contains
+
+! This is a modified version of the subroutine in associate_1.f03.
+! 'str' is now a dummy.
+ SUBROUTINE test_char (n, str)
+ INTEGER, INTENT(IN) :: n
+
+ CHARACTER(LEN=n) :: str
+
+ ASSOCIATE (my => str)
+ IF (LEN (my) /= n) call abort
+ IF (my /= "fooba") call abort
+ my = "abcde"
+ END ASSOCIATE
+ IF (str /= "abcde") call abort
+ END SUBROUTINE test_char
+
+ function foo() result(res)
+ character (len=:), pointer :: res
+ allocate (res, source = 'pqrst')
+ end function
+
+ function bar() result(res)
+ character (len=:), allocatable :: res(:)
+ allocate (res, source = ['pqrst','uvwxy'])
+ end function
+
+end program test
diff --git a/gcc/testsuite/gfortran.dg/assumed_size_2.f90 b/gcc/testsuite/gfortran.dg/assumed_size_2.f90
new file mode 100644
index 0000000..e9a1185
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/assumed_size_2.f90
@@ -0,0 +1,4 @@
+! { dg-do compile }
+subroutine foo(a)
+ dimension a(*,*) ! { dg-error "Bad specification for assumed size array" }
+end
diff --git a/gcc/testsuite/gfortran.dg/binding_label_tests_28.f90 b/gcc/testsuite/gfortran.dg/binding_label_tests_28.f90
new file mode 100644
index 0000000..0066a4a
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/binding_label_tests_28.f90
@@ -0,0 +1,12 @@
+! { dg-do compile }
+!
+! PR fortran/61450
+! Contributed by Francois-Xavier Coudert <fxcoudert@gmail.com>
+!
+module p
+ integer i1 ! { dg-error "Global binding name 'foo' at .1. is already being used at .2." }
+ bind(c,name="foo") :: i1
+end module
+
+subroutine truc() bind(c,name="foo") ! { dg-error "Global binding name 'foo' at .1. is already being used at .2." }
+end
diff --git a/gcc/testsuite/gfortran.dg/contiguous_4.f90 b/gcc/testsuite/gfortran.dg/contiguous_4.f90
new file mode 100644
index 0000000..b05dcfb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/contiguous_4.f90
@@ -0,0 +1,19 @@
+! { dg-do compile }
+program cont_01_neg
+ implicit none
+ real, pointer, contiguous :: r(:)
+ real, pointer, contiguous :: r2(:,:)
+ real, target :: x(45)
+ real, target :: x2(5,9)
+ integer :: i
+ integer :: n=1
+
+ x = (/ (real(i),i=1,45) /)
+ x2 = reshape(x,shape(x2))
+ r => x(::3) ! { dg-error "Assignment to contiguous pointer" }
+ r2 => x2(2:,:) ! { dg-error "Assignment to contiguous pointer" }
+ r2 => x2(:,2:3)
+ r => x2(2:3,1)
+ r => x(::1)
+ r => x(::n) ! { dg-error "Assignment to contiguous pointer" }
+end program
diff --git a/gcc/testsuite/gfortran.dg/data_derived_1.f90 b/gcc/testsuite/gfortran.dg/data_derived_1.f90
new file mode 100644
index 0000000..3ec08e2
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/data_derived_1.f90
@@ -0,0 +1,13 @@
+! { dg-do run }
+! PR 66328 - this used to give a wrong value for integer values for DATA
+program main
+ TYPE t
+ REAL r
+ END TYPE t
+ TYPE (t) e1, e2
+
+ DATA e1 / t(1) /
+ DATA e2 / t(1.0) /
+ if (abs(e1%r - 1.0) > 1e-6) call abort
+ if (abs(e2%r - 1.0) > 1e-6) call abort
+END
diff --git a/gcc/testsuite/gfortran.dg/dec_structure_22.f90 b/gcc/testsuite/gfortran.dg/dec_structure_22.f90
new file mode 100644
index 0000000..ddbee02
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/dec_structure_22.f90
@@ -0,0 +1,38 @@
+ ! { dg-do run }
+ ! { dg-options "-fdec-structure" }
+ !
+ ! PR fortran/82511
+ !
+ ! Verify that structure variables with UNION components
+ ! are accepted in an I/O-list READ.
+ !
+ implicit none
+
+ structure /s/
+ union
+ map
+ character(16) :: c16_1
+ end map
+ map
+ character(16) :: c16_2
+ end map
+ end union
+ end structure
+
+ record /s/ r
+ character(32) :: instr = "ABCDEFGHIJKLMNOPQRSTUVWXYZ!@#$%^"
+
+ r.c16_1 = ' '
+ r.c16_2 = ' '
+ ! The record r shall be treated as if its components are listed:
+ ! read(...) r.c16_1, r.c16_2
+ ! This shall correspond to the formatted read of A16,A16
+ read(instr, '(A16,A16)') r
+
+ ! r.c16_1 and r.c16_2 are in a union, thus share the same memory
+ ! and the first 16 bytes of instr are overwritten
+ if ( r.c16_1 .ne. instr(17:32) .or. r.c16_2 .ne. instr(17:32) ) then
+ call abort()
+ endif
+
+ end
diff --git a/gcc/testsuite/gfortran.dg/derived_init_4.f90 b/gcc/testsuite/gfortran.dg/derived_init_4.f90
new file mode 100644
index 0000000..1149751
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/derived_init_4.f90
@@ -0,0 +1,60 @@
+! { dg-do run }
+!
+! Test the fix for PR81048, where in the second call to 'g2' the
+! default initialization was "forgotten". 'g1', 'g1a' and 'g3' check
+! that this does not occur for scalars and explicit results.
+!
+! Contributed by David Smith <dm577216smith@gmail.com>
+!
+program test
+ type f
+ integer :: f = -1
+ end type
+ type(f) :: a, b(3)
+ type(f), allocatable :: ans
+ b = g2(a)
+ b = g2(a)
+ ans = g1(a)
+ if (ans%f .ne. -1) call abort
+ ans = g1(a)
+ if (ans%f .ne. -1) call abort
+ ans = g1a(a)
+ if (ans%f .ne. -1) call abort
+ ans = g1a(a)
+ if (ans%f .ne. -1) call abort
+ b = g3(a)
+ b = g3(a)
+contains
+ function g3(a) result(res)
+ type(f) :: a, res(3)
+ do j = 1, 3
+ if (res(j)%f == -1) then
+ res(j)%f = a%f - 1
+ else
+ call abort
+ endif
+ enddo
+ end function g3
+
+ function g2(a)
+ type(f) :: a, g2(3)
+ do j = 1, 3
+ if (g2(j)%f == -1) then
+ g2(j)%f = a%f - 1
+ else
+ call abort
+ endif
+ enddo
+ end function g2
+
+ function g1(a)
+ type(f) :: g1, a
+ if (g1%f .ne. -1 ) call abort
+ end function
+
+ function g1a(a) result(res)
+ type(f) :: res, a
+ if (res%f .ne. -1 ) call abort
+ end function
+end program test
+
diff --git a/gcc/testsuite/gfortran.dg/do_subscript_1.f90 b/gcc/testsuite/gfortran.dg/do_subscript_1.f90
new file mode 100644
index 0000000..a4b5058
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/do_subscript_1.f90
@@ -0,0 +1,57 @@
+! { dg-do compile }
+program main
+ real, dimension(3) :: a
+ a = 42.
+ do i=-1,3,2 ! { dg-warning "out of bounds" }
+ a(i) = 0 ! { dg-warning "out of bounds \\(-1 < 1\\)" }
+ end do
+ do i=4,1,-1 ! { dg-warning "out of bounds" }
+ a(i) = 22 ! { dg-warning "out of bounds \\(4 > 3\\)" }
+ end do
+ do i=1,4 ! { dg-warning "out of bounds" }
+ a(i) = 32 ! { dg-warning "out of bounds \\(4 > 3\\)" }
+ end do
+ do i=3,0,-1 ! { dg-warning "out of bounds" }
+ a(i) = 12 ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ end do
+ do i=-1,3
+ if (i>0) a(i) = a(i) + 1 ! No warning inside if
+ end do
+ do i=-1,4
+ select case(i)
+ case(1:3)
+ a(i) = -234 ! No warning inside select case
+ end select
+ end do
+ do i=1,3 ! { dg-warning "out of bounds" }
+ a(i+1) = a(i) ! { dg-warning "out of bounds \\(4 > 3\\)" }
+ a(i-1) = a(i) ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ end do
+ do i=3,1,-1 ! { dg-warning "out of bounds" }
+ a(i) = a(i-1) ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ a(i) = a(i+1) ! { dg-warning "out of bounds \\(4 > 3\\)" }
+ end do
+ do i=1,2 ! { dg-warning "out of bounds" }
+ a(i) = a(i*i) ! { dg-warning "out of bounds \\(4 > 3\\)" }
+ end do
+ do i=1,4,2
+ a(i) = a(i)*2 ! No error
+ end do
+ do i=1,4
+ if (i > 3) exit
+ a(i) = 33
+ end do
+ do i=0,3 ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ a(i) = 13. ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ if (i < 1) exit
+ end do
+ do i=0,3
+ if (i < 1) cycle
+ a(i) = -21.
+ end do
+ do i=0,3 ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ do j=1,2
+ a(i) = -123 ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ end do
+ end do
+end program main
diff --git a/gcc/testsuite/gfortran.dg/do_subscript_2.f90 b/gcc/testsuite/gfortran.dg/do_subscript_2.f90
new file mode 100644
index 0000000..efea428
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/do_subscript_2.f90
@@ -0,0 +1,23 @@
+! { dg-do compile }
+! { dg-additional-options "-Wdo-subscript" }
+program main
+ real, dimension(3) :: a
+ a = 42.
+ do i=-1,3 ! { dg-warning "out of bounds \\(-1 < 1\\)" }
+ select case(i)
+ case(1:3)
+ a(i) = -234 ! { dg-warning "out of bounds \\(-1 < 1\\)" }
+ end select
+ end do
+ do i=1,4,2
+ a(i) = a(i)*2 ! No warning - end value is 3
+ end do
+ do i=1,4 ! { dg-warning "out of bounds \\(4 > 3\\)" }
+ if (i > 3) exit
+ a(i) = 33 ! { dg-warning "out of bounds \\(4 > 3\\)" }
+ end do
+ do i=0,3 ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ if (i < 1) cycle
+ a(i) = -21. ! { dg-warning "out of bounds \\(0 < 1\\)" }
+ end do
+end program main
diff --git a/gcc/testsuite/gfortran.dg/execute_command_line_3.f90 b/gcc/testsuite/gfortran.dg/execute_command_line_3.f90
new file mode 100644
index 0000000..c1790d8
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/execute_command_line_3.f90
@@ -0,0 +1,23 @@
+! { dg-do run }
+! PR 82233 - there were program aborts for some of these commands.
+! Original test case by Urban Jost.
+program boom
+implicit none
+integer :: i,j
+character(len=256) :: msg
+character(len=:), allocatable :: command
+ command='notthere'
+ msg='' ! seems to only be defined if exitstatus.ne.0
+ ! ok -- these work
+ call execute_command_line(command , wait=.false., exitstat=i, cmdstat=j, cmdmsg=msg)
+ if (j /= 0 .or. msg /= '') call abort
+ call execute_command_line(command , exitstat=i, cmdstat=j, cmdmsg=msg )
+ if (j /= 3 .or. msg /= "Invalid command line" ) call abort
+ msg = ''
+ call execute_command_line(command , wait=.false., exitstat=i, cmdmsg=msg )
+ if (j /= 3) call abort
+ call execute_command_line(command , wait=.false., exitstat=i )
+ if (msg /= '') call abort
+ call execute_command_line(command , exitstat=i, cmdstat=j )
+
+end program boom
diff --git a/gcc/testsuite/gfortran.dg/goacc/wait.f90 b/gcc/testsuite/gfortran.dg/goacc/wait.f90
new file mode 100644
index 0000000..9cdbcdf
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/goacc/wait.f90
@@ -0,0 +1,12 @@
+! Ensure that ACC WAIT accept integer arguments.
+
+subroutine foo (wqueue)
+ implicit none
+ integer :: wqueue, waitno
+ integer, parameter :: waitp = 100
+
+ !$acc wait (wqueue)
+ !$acc wait (waitno)
+ !$acc wait (waitp)
+ !$acc wait (0)
+end subroutine foo
diff --git a/gcc/testsuite/gfortran.dg/gomp/pr82568.f90 b/gcc/testsuite/gfortran.dg/gomp/pr82568.f90
new file mode 100644
index 0000000..303278c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/gomp/pr82568.f90
@@ -0,0 +1,75 @@
+! PR fortran/82568
+
+MODULE PR82568_MOD
+ INTEGER :: N
+END MODULE
+PROGRAM PR82568
+ INTEGER :: I, L
+ !$OMP PARALLEL DO
+ DO I=1,2
+ BLOCK
+ USE PR82568_MOD
+ INTEGER :: J
+ DO J=1,2
+ PRINT*,I,J
+ END DO
+ DO K=1,2
+ PRINT*,I,K
+ END DO
+ DO L=1,2
+ PRINT*,I,L
+ END DO
+ DO N=1,2
+ PRINT*,I,N
+ END DO
+ END BLOCK
+ DO M=1,2
+ PRINT*,I,M
+ END DO
+ END DO
+ !$OMP TASK
+ DO I=1,2
+ BLOCK
+ USE PR82568_MOD
+ INTEGER :: J
+ DO J=1,2
+ PRINT*,I,J
+ END DO
+ DO K=1,2
+ PRINT*,I,K
+ END DO
+ DO L=1,2
+ PRINT*,I,L
+ END DO
+ DO N=1,2
+ PRINT*,I,N
+ END DO
+ END BLOCK
+ DO M=1,2
+ PRINT*,I,M
+ END DO
+ END DO
+ !$OMP END TASK
+ !$OMP TASKLOOP
+ DO I=1,2
+ BLOCK
+ USE PR82568_MOD
+ INTEGER :: J
+ DO J=1,2
+ PRINT*,I,J
+ END DO
+ DO K=1,2
+ PRINT*,I,K
+ END DO
+ DO L=1,2
+ PRINT*,I,L
+ END DO
+ DO N=1,2
+ PRINT*,I,N
+ END DO
+ END BLOCK
+ DO M=1,2
+ PRINT*,I,M
+ END DO
+ END DO
+END PROGRAM PR82568
diff --git a/gcc/testsuite/gfortran.dg/gomp/udr8.f90 b/gcc/testsuite/gfortran.dg/gomp/udr8.f90
index e040b3d..f11e1a9 100644
--- a/gcc/testsuite/gfortran.dg/gomp/udr8.f90
+++ b/gcc/testsuite/gfortran.dg/gomp/udr8.f90
@@ -274,11 +274,11 @@ subroutine test13
use m
!$omp declare reduction (foo : integer : omp_out = omp_out + omp_in) initializer (omp_priv = 0)
!$omp declare reduction (bar : integer : omp_out = & ! { dg-error "Different shape for array assignment at \[^\n\r]* on dimension 1 .9 and 10" }
-!$omp & fn5 (omp_out, omp_in)) & ! { dg-warning "Actual argument contains too few elements for dummy argument \[^\n\r]* .9/10" }
-!$omp & initializer (sub5 (omp_priv, omp_orig)) ! { dg-warning "Actual argument contains too few elements for dummy argument \[^\n\r]* .9/10" }
-!$omp declare reduction (baz : integer : sub6 (omp_out, omp_in)) & ! { dg-warning "Actual argument contains too few elements for dummy argument \[^\n\r]* .9/10" }
+!$omp & fn5 (omp_out, omp_in)) & ! { dg-error "Actual argument contains too few elements for dummy argument \[^\n\r]* .9/10" }
+!$omp & initializer (sub5 (omp_priv, omp_orig)) ! { dg-error "Actual argument contains too few elements for dummy argument \[^\n\r]* .9/10" }
+!$omp declare reduction (baz : integer : sub6 (omp_out, omp_in)) & ! { dg-error "Actual argument contains too few elements for dummy argument \[^\n\r]* .9/10" }
!$omp initializer (omp_priv = & ! { dg-error "Different shape for array assignment at \[^\n\r]* on dimension 1 .9 and 10" }
-!$omp & fn6 (omp_orig)) ! { dg-warning "Actual argument contains too few elements for dummy argument \[^\n\r]* .9/10" }
+!$omp & fn6 (omp_orig)) ! { dg-error "Actual argument contains too few elements for dummy argument \[^\n\r]* .9/10" }
integer :: a(9)
!$omp parallel reduction (foo : a)
!$omp end parallel
diff --git a/gcc/testsuite/gfortran.dg/graphite/id-27.f90 b/gcc/testsuite/gfortran.dg/graphite/id-27.f90
new file mode 100644
index 0000000..e1e7ec0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/id-27.f90
@@ -0,0 +1,40 @@
+! { dg-additional-options "-Ofast" }
+MODULE module_ra_gfdleta
+ INTEGER, PARAMETER :: NBLY=15
+ REAL , SAVE :: EM1(28,180),EM1WDE(28,180),TABLE1(28,180), &
+ TABLE2(28,180),TABLE3(28,180),EM3(28,180), &
+ SOURCE(28,NBLY), DSRCE(28,NBLY)
+CONTAINS
+ SUBROUTINE TABLE
+ INTEGER, PARAMETER :: NBLX=47
+ INTEGER , PARAMETER:: NBLW = 163
+ REAL :: &
+ SUM(28,180),PERTSM(28,180),SUM3(28,180), &
+ SUMWDE(28,180),SRCWD(28,NBLX),SRC1NB(28,NBLW), &
+ DBDTNB(28,NBLW)
+ REAL :: &
+ ZMASS(181),ZROOT(181),SC(28),DSC(28),XTEMV(28), &
+ TFOUR(28),FORTCU(28),X(28),X1(28),X2(180),SRCS(28), &
+ R1T(28),R2(28),S2(28),T3(28),R1WD(28)
+ REAL :: EXPO(180),FAC(180)
+ I = 0
+ DO 417 J=121,180
+ FAC(J)=ZMASS(J)*(ONE-(ONE+X2(J))*EXPO(J))/(X2(J)*X2(J))
+417 CONTINUE
+ DO 421 J=121,180
+ SUM3(I,J)=SUM3(I,J)+DBDTNB(I,N)*FAC(J)
+421 CONTINUE
+ IF (CENT.GT.160. .AND. CENT.LT.560.) THEN
+ DO 420 J=1,180
+ DO 420 I=1,28
+ SUMWDE(I,J)=SUMWDE(I,J)+SRC1NB(I,N)*EXPO(J)
+420 CONTINUE
+ ENDIF
+ DO 433 J=121,180
+ EM3(I,J)=SUM3(I,J)/FORTCU(I)
+433 CONTINUE
+ DO 501 I=1,28
+ EM1WDE(I,J)=SUMWDE(I,J)/TFOUR(I)
+501 CONTINUE
+ END SUBROUTINE TABLE
+ END MODULE module_RA_GFDLETA
diff --git a/gcc/testsuite/gfortran.dg/graphite/id-28.f90 b/gcc/testsuite/gfortran.dg/graphite/id-28.f90
new file mode 100644
index 0000000..d66cb12
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/id-28.f90
@@ -0,0 +1,15 @@
+! Verify we elide modulo operations we cannot represent
+module OPMATRIX_MODULE
+ implicit none
+ type opmatrix_type
+ real(kind=kind(1.0d0)), dimension(:,:), pointer :: restricted
+ end type
+ interface zero_
+ module procedure zero
+ end interface
+contains
+ subroutine zero(self)
+ type(opmatrix_type) :: self
+ self%restricted = 0.0d0
+ end subroutine
+end
diff --git a/gcc/testsuite/gfortran.dg/graphite/interchange-3.f90 b/gcc/testsuite/gfortran.dg/graphite/interchange-3.f90
index f20eaa9..8070bbb 100644
--- a/gcc/testsuite/gfortran.dg/graphite/interchange-3.f90
+++ b/gcc/testsuite/gfortran.dg/graphite/interchange-3.f90
@@ -24,4 +24,4 @@ Program FOO
end Program FOO
-! { dg-final { scan-tree-dump-times "codegen error: reverting back to the original code." "1" "graphite" } }
+! { dg-final { scan-tree-dump "tiled" "graphite" } }
diff --git a/gcc/testsuite/gfortran.dg/graphite/pr29581.f90 b/gcc/testsuite/gfortran.dg/graphite/pr29581.f90
index 3e4a39e..bfcb860 100644
--- a/gcc/testsuite/gfortran.dg/graphite/pr29581.f90
+++ b/gcc/testsuite/gfortran.dg/graphite/pr29581.f90
@@ -1,6 +1,7 @@
! PR tree-optimization/29581
! { dg-do run }
-! { dg-options "-O2 -ftree-loop-linear" }
+! { dg-skip-if "" { *-*-* } { "-O0" } { "" } }
+! { dg-additional-options "-ftree-loop-linear" }
SUBROUTINE FOO (K)
INTEGER I, J, K, A(5,5), B
diff --git a/gcc/testsuite/gfortran.dg/graphite/pr29832.f90 b/gcc/testsuite/gfortran.dg/graphite/pr29832.f90
index ab222ab..f98a7d3 100644
--- a/gcc/testsuite/gfortran.dg/graphite/pr29832.f90
+++ b/gcc/testsuite/gfortran.dg/graphite/pr29832.f90
@@ -1,5 +1,6 @@
! { dg-do run }
-! { dg-options "-O2 -ftree-loop-linear" }
+! { dg-skip-if "" { *-*-* } { "-O0" } { "" } }
+! { dg-additional-options "-ftree-loop-linear" }
! Program to test the scalarizer
program testarray
@@ -23,4 +24,3 @@ program testarray
if (b(4, n) .ne. (6 - n)) call abort
end do
end program
-
diff --git a/gcc/testsuite/gfortran.dg/graphite/pr42326-1.f90 b/gcc/testsuite/gfortran.dg/graphite/pr42326-1.f90
index 8c9d110..b2c3b9b 100644
--- a/gcc/testsuite/gfortran.dg/graphite/pr42326-1.f90
+++ b/gcc/testsuite/gfortran.dg/graphite/pr42326-1.f90
@@ -16,4 +16,3 @@ subroutine phasad(t,i,ium)
enddo
return
end subroutine phasad
-
diff --git a/gcc/testsuite/gfortran.dg/graphite/pr42326.f90 b/gcc/testsuite/gfortran.dg/graphite/pr42326.f90
index 06ef2b7..e4d1936 100644
--- a/gcc/testsuite/gfortran.dg/graphite/pr42326.f90
+++ b/gcc/testsuite/gfortran.dg/graphite/pr42326.f90
@@ -33,4 +33,3 @@ subroutine phasad(t,i,ium)
enddo
return
end subroutine phasad
-
diff --git a/gcc/testsuite/gfortran.dg/graphite/pr71351.f90 b/gcc/testsuite/gfortran.dg/graphite/pr71351.f90
new file mode 100644
index 0000000..8251930
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/pr71351.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+! { dg-options "-O2 -floop-nest-optimize" }
+
+SUBROUTINE print_crys_symmetry(nc,v)
+ INTEGER :: nc
+ REAL(KIND=8), DIMENSION(3,48) :: v
+ INTEGER :: n,i
+ vs = 0.0_8
+ DO n = 1, nc
+ DO i = 1, 3
+ vs = vs + ABS(v(i,n))
+ END DO
+ END DO
+ CALL foo(vs)
+END SUBROUTINE print_crys_symmetry
diff --git a/gcc/testsuite/gfortran.dg/graphite/pr82449.f b/gcc/testsuite/gfortran.dg/graphite/pr82449.f
new file mode 100644
index 0000000..974ea20
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/pr82449.f
@@ -0,0 +1,11 @@
+! { dg-do compile }
+! { dg-options "-O2 -floop-nest-optimize" }
+
+ SUBROUTINE JDFIDX(MKL,KGSH)
+ DIMENSION MKL(6,6)
+ NKL=0
+ 400 DO 40 KG = 1,KGSH
+ DO 40 LG = 1,KG
+ NKL = NKL + 1
+ 40 MKL(LG,KG) = NKL
+ END
diff --git a/gcc/testsuite/gfortran.dg/graphite/pr82451.f b/gcc/testsuite/gfortran.dg/graphite/pr82451.f
new file mode 100644
index 0000000..88ff85b
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/pr82451.f
@@ -0,0 +1,39 @@
+! { dg-do compile }
+! { dg-options "-O2 -floop-nest-optimize" }
+ MODULE LES3D_DATA
+ PARAMETER ( NSCHEME = 4, ICHEM = 0, ISGSK = 0, IVISC = 1 )
+ DOUBLE PRECISION DT, TIME, STATTIME, CFL, RELNO, TSTND, ALREF
+ INTEGER IDYN, IMAX, JMAX, KMAX
+ PARAMETER( RUNIV = 8.3145D3,
+ > TPRANDLT = 0.91D0)
+ DOUBLE PRECISION,ALLOCATABLE,DIMENSION(:,:,:) ::
+ > U, V, W, P, T, H, EK,
+ > UAV, VAV, WAV, PAV, TAV, HAV, EKAV
+ DOUBLE PRECISION,ALLOCATABLE,DIMENSION(:,:,:,:) ::
+ > CONC, HF, QAV, COAV, HFAV, DU
+ DOUBLE PRECISION,ALLOCATABLE,DIMENSION(:,:,:,:,:) ::
+ > Q
+ END MODULE LES3D_DATA
+ SUBROUTINE FLUXJ()
+ USE LES3D_DATA
+ ALLOCATABLE QS(:), FSJ(:,:,:)
+ ALLOCATABLE DWDX(:),DWDY(:),DWDZ(:)
+ ALLOCATABLE DHDY(:), DKDY(:)
+ PARAMETER ( R12I = 1.0D0 / 12.0D0,
+ > TWO3 = 2.0D0 / 3.0D0 )
+ ALLOCATE( QS(IMAX-1), FSJ(IMAX-1,0:JMAX-1,ND))
+ ALLOCATE( DWDX(IMAX-1),DWDY(IMAX-1),DWDZ(IMAX-1))
+ I1 = 1
+ DO K = K1,K2
+ DO J = J1,J2
+ DO I = I1, I2
+ FSJ(I,J,5) = FSJ(I,J,5) + PAV(I,J,K) * QS(I)
+ END DO
+ DO I = I1, I2
+ DWDX(I) = DXI * R12I * (WAV(I-2,J,K) - WAV(I+2,J,K) +
+ > 8.0D0 * (WAV(I+1,J,K) - WAV(I-1,J,K)))
+ END DO
+ END DO
+ END DO
+ DEALLOCATE( QS, FSJ, DHDY, DKDY)
+ END
diff --git a/gcc/testsuite/gfortran.dg/graphite/pr82672.f90 b/gcc/testsuite/gfortran.dg/graphite/pr82672.f90
new file mode 100644
index 0000000..77a1c70
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/graphite/pr82672.f90
@@ -0,0 +1,33 @@
+! { dg-do compile }
+! { dg-options "-O2 -floop-nest-optimize" }
+
+ character(len=20,kind=4) :: s4
+ character(len=20,kind=1) :: s1
+
+ s1 = "foo\u0000"
+ s1 = "foo\u00ff"
+ s1 = "foo\u0100"
+ s1 = "foo\u0101"
+ s1 = "foo\U00000101"
+
+ s1 = 4_"foo bar"
+ s1 = 4_"foo\u00ff"
+ s1 = 4_"foo\u0101"
+ s1 = 4_"foo\u1101"
+ s1 = 4_"foo\UFFFFFFFF"
+
+ s4 = "foo\u0000"
+ s4 = "foo\u00ff"
+ s4 = "foo\u0100"
+ s4 = "foo\U00000100"
+
+ s4 = 4_"foo bar"
+ s4 = 4_"\xFF\x96"
+ s4 = 4_"\x00\x96"
+ s4 = 4_"foo\u00ff"
+ s4 = 4_"foo\u0101"
+ s4 = 4_"foo\u1101"
+ s4 = 4_"foo\Uab98EF56"
+ s4 = 4_"foo\UFFFFFFFF"
+
+end
diff --git a/gcc/testsuite/gfortran.dg/graphite/run-id-3.f90 b/gcc/testsuite/gfortran.dg/graphite/run-id-3.f90
index 54139ef..ab16a44 100644
--- a/gcc/testsuite/gfortran.dg/graphite/run-id-3.f90
+++ b/gcc/testsuite/gfortran.dg/graphite/run-id-3.f90
@@ -1,5 +1,6 @@
! { dg-do run }
-! { dg-options "-ffrontend-optimize -floop-nest-optimize" }
+! { dg-skip-if "" { *-*-* } { "-O0" } { "" } }
+! { dg-additional-options "-ffrontend-optimize -floop-nest-optimize" }
! PR 56872 - wrong front-end optimization with a single constructor.
! Original bug report by Rich Townsend.
integer :: k
diff --git a/gcc/testsuite/gfortran.dg/illegal_char.f90 b/gcc/testsuite/gfortran.dg/illegal_char.f90
new file mode 100644
index 0000000..597c7b9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/illegal_char.f90
@@ -0,0 +1,6 @@
+! { dg-do compile }
+! PR 82372 - show hexcode of illegal, non-printable characters
+program main
+ tmp =È 1.0 ! { dg-error "Invalid character 0xC8" }
+ print *,tmp
+end
diff --git a/gcc/testsuite/gfortran.dg/intrinsic_bounds_1.f90 b/gcc/testsuite/gfortran.dg/intrinsic_bounds_1.f90
new file mode 100644
index 0000000..a9586fb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/intrinsic_bounds_1.f90
@@ -0,0 +1,7 @@
+! { dg-do compile }
+! PR 54633 - this used to be rejected
+program main
+ integer :: x(minval((/1/),mask=(/.TRUE./)))
+ integer, parameter :: m = minval((/1/))
+ integer :: y(minval((/1/),mask=(/.TRUE./)))
+end
diff --git a/gcc/testsuite/gfortran.dg/intrinsic_param_1.f90 b/gcc/testsuite/gfortran.dg/intrinsic_param_1.f90
new file mode 100644
index 0000000..7c168a7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/intrinsic_param_1.f90
@@ -0,0 +1,6 @@
+! { dg-do compile }
+! { dg-additional-options "-std=f95" }
+! PR 54633 - this used to be accepted
+program main
+ integer, parameter :: m = minval((/1/)) ! { dg-error "Transformational function" }
+end
diff --git a/gcc/testsuite/gfortran.dg/pdt_13.f03 b/gcc/testsuite/gfortran.dg/pdt_13.f03
new file mode 100644
index 0000000..e53d0b7
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_13.f03
@@ -0,0 +1,92 @@
+! { dg-do run }
+!
+! Test the fix for PR82375
+!
+! Based on contribution by Ian Chivers <ian@rhymneyconsulting.co.uk>
+!
+module precision_module
+ implicit none
+ integer, parameter :: sp = selected_real_kind(6, 37)
+ integer, parameter :: dp = selected_real_kind(15, 307)
+ integer, parameter :: qp = selected_real_kind( 30, 291)
+end module precision_module
+
+module link_module
+ use precision_module
+
+ type link(real_kind)
+ integer, kind :: real_kind
+ real (kind=real_kind) :: n
+ type (link(real_kind)), pointer :: next => NULL()
+ end type link
+
+contains
+
+ function push_8 (self, arg) result(current)
+ real(dp) :: arg
+ type (link(real_kind=dp)), pointer :: self
+ type (link(real_kind=dp)), pointer :: current
+
+ if (associated (self)) then
+ current => self
+ do while (associated (current%next))
+ current => current%next
+ end do
+
+ allocate (current%next)
+ current => current%next
+ else
+ allocate (current)
+ self => current
+ end if
+
+ current%n = arg
+ current%next => NULL ()
+ end function push_8
+
+ function pop_8 (self) result(res)
+ type (link(real_kind=dp)), pointer :: self
+ type (link(real_kind=dp)), pointer :: current => NULL()
+ type (link(real_kind=dp)), pointer :: previous => NULL()
+ real(dp) :: res
+
+ res = 0.0_8
+ if (associated (self)) then
+ current => self
+ do while (associated (current) .and. associated (current%next))
+ previous => current
+ current => current%next
+ end do
+
+ previous%next => NULL ()
+
+ res = current%n
+ if (associated (self, current)) then
+ deallocate (self)
+ else
+ deallocate (current)
+ end if
+
+ end if
+ end function pop_8
+
+end module link_module
+
+program ch2701
+ use precision_module
+ use link_module
+ implicit none
+ integer, parameter :: wp = dp
+ type (link(real_kind=wp)), pointer :: root => NULL()
+ type (link(real_kind=wp)), pointer :: current
+
+ current => push_8 (root, 1.0_8)
+ current => push_8 (root, 2.0_8)
+ current => push_8 (root, 3.0_8)
+
+ if (int (pop_8 (root)) .ne. 3) call abort
+ if (int (pop_8 (root)) .ne. 2) call abort
+ if (int (pop_8 (root)) .ne. 1) call abort
+ if (int (pop_8 (root)) .ne. 0) call abort
+
+end program ch2701
diff --git a/gcc/testsuite/gfortran.dg/pdt_14.f03 b/gcc/testsuite/gfortran.dg/pdt_14.f03
new file mode 100644
index 0000000..7497898
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_14.f03
@@ -0,0 +1,90 @@
+! { dg-do run }
+!
+! Test the fix for PR82375. This is the allocatable version of pdt_13.f03.
+!
+! Based on contribution by Ian Chivers <ian@rhymneyconsulting.co.uk>
+!
+module precision_module
+ implicit none
+ integer, parameter :: sp = selected_real_kind(6, 37)
+ integer, parameter :: dp = selected_real_kind(15, 307)
+ integer, parameter :: qp = selected_real_kind( 30, 291)
+end module precision_module
+
+module link_module
+ use precision_module
+
+ type link(real_kind)
+ integer, kind :: real_kind
+ real (kind=real_kind) :: n
+ type (link(real_kind)), allocatable :: next
+ end type link
+
+contains
+
+ function push_8 (self, arg) result(current)
+ real(dp) :: arg
+ type (link(real_kind=dp)), allocatable, target :: self
+ type (link(real_kind=dp)), pointer :: current
+
+ if (allocated (self)) then
+ current => self
+ do while (allocated (current%next))
+ current => current%next
+ end do
+
+ allocate (current%next)
+ current => current%next
+ else
+ allocate (self)
+ current => self
+ end if
+
+ current%n = arg
+
+ end function push_8
+
+ function pop_8 (self) result(res)
+ type (link(real_kind=dp)), allocatable, target :: self
+ type (link(real_kind=dp)), pointer:: current
+ type (link(real_kind=dp)), pointer :: previous
+ real(dp) :: res
+
+ res = 0.0_8
+ if (allocated (self)) then
+ current => self
+ previous => self
+ do while (allocated (current%next))
+ previous => current
+ current => current%next
+ end do
+ res = current%n
+ if (.not.allocated (previous%next)) then
+ deallocate (self)
+ else
+ deallocate (previous%next)
+ end if
+
+ end if
+ end function pop_8
+
+end module link_module
+
+program ch2701
+ use precision_module
+ use link_module
+ implicit none
+ integer, parameter :: wp = dp
+ type (link(real_kind=wp)), allocatable :: root
+ type (link(real_kind=wp)), pointer :: current
+
+ current => push_8 (root, 1.0_8)
+ current => push_8 (root, 2.0_8)
+ current => push_8 (root, 3.0_8)
+
+ if (int (pop_8 (root)) .ne. 3) call abort
+ if (int (pop_8 (root)) .ne. 2) call abort
+ if (int (pop_8 (root)) .ne. 1) call abort
+ if (int (pop_8 (root)) .ne. 0) call abort
+
+end program ch2701
diff --git a/gcc/testsuite/gfortran.dg/pdt_15.f03 b/gcc/testsuite/gfortran.dg/pdt_15.f03
new file mode 100644
index 0000000..bbf140e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_15.f03
@@ -0,0 +1,106 @@
+! { dg-do compile }
+! { dg-options "-fdump-tree-original" }
+!
+! Test the fix for PR82375. This is a wrinkle on the the allocatable
+! version of pdt_13.f03, pdt_14.f03, whereby 'root' is now declared
+! in a subroutine so that it should be cleaned up automatically. This
+! is best tested with valgrind or its like.
+! In addition, the field 'n' has now become a parameterized length
+! array to verify that the combination of allocatable components and
+! parameterization works correctly.
+!
+! Based on contribution by Ian Chivers <ian@rhymneyconsulting.co.uk>
+!
+module precision_module
+ implicit none
+ integer, parameter :: sp = selected_real_kind(6, 37)
+ integer, parameter :: dp = selected_real_kind(15, 307)
+ integer, parameter :: qp = selected_real_kind( 30, 291)
+end module precision_module
+
+module link_module
+ use precision_module
+
+ type link(real_kind, mat_len)
+ integer, kind :: real_kind
+ integer, len :: mat_len
+ real (kind=real_kind) :: n(mat_len)
+ type (link(real_kind, :)), allocatable :: next
+ end type link
+
+contains
+
+ function push_8 (self, arg) result(current)
+ real(dp) :: arg
+ type (link(real_kind=dp, mat_len=:)), allocatable, target :: self
+ type (link(real_kind=dp, mat_len=:)), pointer :: current
+
+ if (allocated (self)) then
+ current => self
+ do while (allocated (current%next))
+ current => current%next
+ end do
+
+ allocate (link(real_kind=dp, mat_len=1) :: current%next)
+ current => current%next
+ else
+ allocate (link(real_kind=dp, mat_len=1) :: self)
+ current => self
+ end if
+
+ current%n(1) = arg
+
+ end function push_8
+
+ function pop_8 (self) result(res)
+ type (link(real_kind=dp, mat_len=:)), allocatable, target :: self
+ type (link(real_kind=dp, mat_len=:)), pointer:: current => NULL()
+ type (link(real_kind=dp, mat_len=:)), pointer :: previous => NULL()
+ real(dp) :: res
+
+ res = 0.0_8
+ if (allocated (self)) then
+ current => self
+ previous => self
+ do while (allocated (current%next))
+ previous => current
+ current => current%next
+ end do
+ res = current%n(1)
+ if (.not.allocated (previous%next)) then
+ deallocate (self)
+ else
+ deallocate (previous%next)
+ end if
+
+ end if
+ end function pop_8
+
+end module link_module
+
+program ch2701
+ use precision_module
+ use link_module
+ implicit none
+ integer, parameter :: wp = dp
+
+ call foo
+contains
+
+ subroutine foo
+ type (link(real_kind=wp, mat_len=:)), allocatable :: root
+ type (link(real_kind=wp, mat_len=:)), pointer :: current => NULL()
+
+ current => push_8 (root, 1.0_8)
+ current => push_8 (root, 2.0_8)
+ current => push_8 (root, 3.0_8)
+
+ if (int (pop_8 (root)) .ne. 3) call abort
+ if (int (pop_8 (root)) .ne. 2) call abort
+ if (int (pop_8 (root)) .ne. 1) call abort
+! if (int (pop_8 (root)) .ne. 0) call abort
+ end subroutine
+end program ch2701
+! { dg-final { scan-tree-dump-times "Pdtlink_8._deallocate " 5 "original" } }
+! { dg-final { scan-tree-dump-times ".n.data = 0B" 7 "original" } }
+! { dg-final { scan-tree-dump-times "__builtin_free" 14 "original" } }
diff --git a/gcc/testsuite/gfortran.dg/pdt_16.f03 b/gcc/testsuite/gfortran.dg/pdt_16.f03
new file mode 100644
index 0000000..067d87d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_16.f03
@@ -0,0 +1,21 @@
+! { dg-do compile }
+!
+! Test the fix for all three errors in PR82586
+!
+! Contributed by G Steinmetz <gscfq@t-online.de>
+!
+module m
+ type t(a) ! { dg-error "does not have a component" }
+ end type
+end
+
+program p
+ type t(a ! { dg-error "Expected parameter list" }
+ integer, kind :: a
+ real(a) :: x
+ end type
+ type u(a, a) ! { dg-error "Duplicate name" }
+ integer, kind :: a ! { dg-error "already declared" }
+ integer, len :: a ! { dg-error "already declared" }
+ end type
+end
diff --git a/gcc/testsuite/gfortran.dg/pdt_17.f03 b/gcc/testsuite/gfortran.dg/pdt_17.f03
new file mode 100644
index 0000000..1b0a30d
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_17.f03
@@ -0,0 +1,11 @@
+! { dg-do compile }
+!
+! Test the fix for PR82587
+!
+! Contributed by G Steinmetz <gscfq@t-online.de>
+!
+program p
+ type t(a) ! { dg-error "does not have a component" }
+ integer(kind=t()) :: x ! { dg-error "used before it is defined" }
+ end type
+end
diff --git a/gcc/testsuite/gfortran.dg/pdt_18.f03 b/gcc/testsuite/gfortran.dg/pdt_18.f03
new file mode 100644
index 0000000..896a727
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pdt_18.f03
@@ -0,0 +1,19 @@
+! { dg-do compile }
+!
+! Test the fix for PR82589
+!
+! Contributed by G Steinmetz <gscfq@t-online.de>
+!
+module m
+ type t(a)
+ integer, KIND, private :: a ! { dg-error "attribute conflicts with" }
+ integer, KIND, allocatable :: a ! { dg-error "attribute conflicts with" }
+ integer, KIND, POINTER :: a ! { dg-error "attribute conflicts with" }
+ integer, KIND, dimension(2) :: a ! { dg-error "attribute conflicts with" }
+ integer, len, private :: a ! { dg-error "attribute conflicts with" }
+ integer, len, allocatable :: a ! { dg-error "attribute conflicts with" }
+ integer, len, POINTER :: a ! { dg-error "attribute conflicts with" }
+ integer, len, dimension(2) :: a ! { dg-error "attribute conflicts with" }
+ integer, kind :: a
+ end type
+end
diff --git a/gcc/testsuite/gfortran.dg/pdt_4.f03 b/gcc/testsuite/gfortran.dg/pdt_4.f03
index 13c00af..15cb641 100644
--- a/gcc/testsuite/gfortran.dg/pdt_4.f03
+++ b/gcc/testsuite/gfortran.dg/pdt_4.f03
@@ -26,7 +26,7 @@ end module
integer, kind :: bad_kind ! { dg-error "not allowed outside a TYPE definition" }
integer, len :: bad_len ! { dg-error "not allowed outside a TYPE definition" }
- type :: bad_pdt (a,b, c, d)
+ type :: bad_pdt (a,b, c, d) ! { dg-error "does not have a component" }
real, kind :: a ! { dg-error "must be INTEGER" }
INTEGER(8), kind :: b ! { dg-error "be default integer kind" }
real, LEN :: c ! { dg-error "must be INTEGER" }
diff --git a/gcc/testsuite/gfortran.dg/pdt_8.f03 b/gcc/testsuite/gfortran.dg/pdt_8.f03
index d5e393e..aeec407 100644
--- a/gcc/testsuite/gfortran.dg/pdt_8.f03
+++ b/gcc/testsuite/gfortran.dg/pdt_8.f03
@@ -15,9 +15,10 @@ type :: t(i,a,x) ! { dg-error "does not|has neither" }
real, kind :: x ! { dg-error "must be INTEGER" }
end type
-type :: t1(k,y) ! { dg-error "not declared as a component of the type" }
+type :: t1(k,y) ! { dg-error "does not have a component" }
integer, kind :: k
end type
-type(t1(4,4)) :: z
+! This is a knock-on from the previous error
+type(t1(4,4)) :: z ! { dg-error "Invalid character in name" }
end
diff --git a/gcc/testsuite/gfortran.dg/pr82397.f b/gcc/testsuite/gfortran.dg/pr82397.f
new file mode 100644
index 0000000..9a51e9e
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/pr82397.f
@@ -0,0 +1,32 @@
+! { dg-do compile }
+! { dg-options "-Ofast" }
+
+ subroutine foo(U,V,R,N,A)
+ integer N
+ real*8 U(N,N,N),V(N,N,N),R(N,N,N),A(0:3)
+ integer I3, I2, I1
+C
+ do I3=2,N-1
+ do I2=2,N-1
+ do I1=2,N-1
+ R(I1,I2,I3)=V(I1,I2,I3)
+ * -A(0)*( U(I1, I2, I3 ) )
+ * -A(1)*( U(I1-1,I2, I3 ) + U(I1+1,I2, I3 )
+ * + U(I1, I2-1,I3 ) + U(I1, I2+1,I3 )
+ * + U(I1, I2, I3-1) + U(I1, I2, I3+1) )
+ * -A(2)*( U(I1-1,I2-1,I3 ) + U(I1+1,I2-1,I3 )
+ * + U(I1-1,I2+1,I3 ) + U(I1+1,I2+1,I3 )
+ * + U(I1, I2-1,I3-1) + U(I1, I2+1,I3-1)
+ * + U(I1, I2-1,I3+1) + U(I1, I2+1,I3+1)
+ * + U(I1-1,I2, I3-1) + U(I1-1,I2, I3+1)
+ * + U(I1+1,I2, I3-1) + U(I1+1,I2, I3+1) )
+ * -A(3)*( U(I1-1,I2-1,I3-1) + U(I1+1,I2-1,I3-1)
+ * + U(I1-1,I2+1,I3-1) + U(I1+1,I2+1,I3-1)
+ * + U(I1-1,I2-1,I3+1) + U(I1+1,I2-1,I3+1)
+ * + U(I1-1,I2+1,I3+1) + U(I1+1,I2+1,I3+1) )
+ enddo
+ enddo
+ enddo
+ return
+ end
+
diff --git a/gcc/testsuite/gfortran.dg/predcom-1.f b/gcc/testsuite/gfortran.dg/predcom-1.f
index 1cc0bf2..0321633 100644
--- a/gcc/testsuite/gfortran.dg/predcom-1.f
+++ b/gcc/testsuite/gfortran.dg/predcom-1.f
@@ -8,7 +8,7 @@
INTEGER I
REAL ANORM
INTRINSIC ABS
- DO 20 I = 1, N
+ DO 20 I = 2, N
ANORM = ANORM +ABS( E( I ) )+ ABS( E( I-1 ) )
20 CONTINUE
CLANHT = ANORM
diff --git a/gcc/testsuite/gfortran.dg/promotion_3.f90 b/gcc/testsuite/gfortran.dg/promotion_3.f90
new file mode 100644
index 0000000..3571bd1
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/promotion_3.f90
@@ -0,0 +1,17 @@
+! { dg-do run }
+! { dg-options "-fdefault-real-16" }
+! { dg-require-effective-target fortran_real_16 }
+!
+! PR 82143: add a -fdefault-real-16 flag
+!
+! Contributed by Janus Weil <janus@gcc.gnu.org>
+
+real :: r
+real(kind=4) :: r4
+real(kind=8) :: r8
+double precision :: d
+if (kind(r4) /= 4) call abort
+if (kind(r8) /= 8) call abort
+if (kind(r) /= 16) call abort
+if (kind(d) /= 16) call abort
+end
diff --git a/gcc/testsuite/gfortran.dg/promotion_4.f90 b/gcc/testsuite/gfortran.dg/promotion_4.f90
new file mode 100644
index 0000000..8378cdd
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/promotion_4.f90
@@ -0,0 +1,17 @@
+! { dg-do run }
+! { dg-options "-fdefault-real-10" }
+! { dg-require-effective-target fortran_real_10 }
+!
+! PR 82143: add a -fdefault-real-16 flag
+!
+! Contributed by Janus Weil <janus@gcc.gnu.org>
+
+real :: r
+real(kind=4) :: r4
+real(kind=8) :: r8
+double precision :: d
+if (kind(r4) /= 4) call abort
+if (kind(r8) /= 8) call abort
+if (kind(r) /= 10) call abort
+if (kind(d) < 10) call abort
+end
diff --git a/gcc/testsuite/gfortran.dg/spellcheck-operator.f90 b/gcc/testsuite/gfortran.dg/spellcheck-operator.f90
new file mode 100644
index 0000000..810a770
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/spellcheck-operator.f90
@@ -0,0 +1,30 @@
+! { dg-do compile }
+! test levenshtein based spelling suggestions
+
+module mymod1
+ implicit none
+ contains
+ function something_good (iarg1)
+ integer :: something_good
+ integer, intent(in) :: iarg1
+ something_good = iarg1 + 42
+ end function something_good
+end module mymod1
+
+program spellchekc
+ use mymod1
+ implicit none
+
+ interface operator (.mywrong.)
+ module procedure something_wring ! { dg-error "Procedure .something_wring. in operator interface .mywrong. at .1. is neither function nor subroutine; did you mean .something_good.\\?|User operator procedure .something_wring. at .1. must be a FUNCTION" }
+ end interface
+
+ interface operator (.mygood.)
+ module procedure something_good
+ end interface
+
+ integer :: i, j, added
+ i = 0
+ j = 0
+ added = .mygoof. j ! { dg-error "Unknown operator .mygoof. at .1.; did you mean .mygood.\\?" }
+end program spellchekc
diff --git a/gcc/testsuite/gfortran.dg/spellcheck-parameter.f90 b/gcc/testsuite/gfortran.dg/spellcheck-parameter.f90
new file mode 100644
index 0000000..715c5ab
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/spellcheck-parameter.f90
@@ -0,0 +1,15 @@
+! { dg-do compile }
+! Contributed by Joost VandeVondele
+! test levenshtein based spelling suggestions for keyword arguments
+
+module test
+contains
+ subroutine mysub(iarg1)
+ integer :: iarg1
+ end subroutine
+end module
+
+use test
+call mysub(iarg=1) ! { dg-error "Keyword argument .iarg. at .1. is not in the procedure; did you mean .iarg1.\\?" }
+
+end
diff --git a/gcc/testsuite/gfortran.dg/spellcheck-procedure_1.f90 b/gcc/testsuite/gfortran.dg/spellcheck-procedure_1.f90
new file mode 100644
index 0000000..3b7f716
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/spellcheck-procedure_1.f90
@@ -0,0 +1,41 @@
+! { dg-do compile }
+! test levenshtein based spelling suggestions
+
+module mymod1
+ implicit none
+ contains
+ function something_else (iarg1)
+ integer :: something_else
+ integer, intent(in) :: iarg1
+ something_else = iarg1 + 42
+ end function something_else
+ function add_fourtytwo (iarg1)
+ integer :: add_fourtytwo
+ integer, intent(in) :: iarg1
+ add_fourtytwo = iarg1 + 42
+ end function add_fourtytwo
+end module mymod1
+
+function myadd(iarg1, iarg2)
+ implicit none
+ integer :: myadd
+ integer, intent(in) :: iarg1, iarg2
+ myadd = iarg1 + iarg2
+end function myadd
+
+program spellchekc
+ use mymod1, something_good => something_else
+ implicit none
+
+ integer :: myadd, i, j, myvar
+ i = 0
+ j = 0
+
+ j = something_goof(j) ! { dg-error "no IMPLICIT type; did you mean .something_good.\\?" }
+ j = myaddd(i, j) ! { dg-error "no IMPLICIT type; did you mean .myadd.\\?" }
+ if (j /= 42) call abort
+ j = add_fourtytow(i, j) ! { dg-error "no IMPLICIT type; did you mean .add_fourtytwo.\\?" }
+ myval = myadd(i, j) ! { dg-error "no IMPLICIT type; did you mean .myvar.\\?" }
+ if (j /= 42 * 2) call abort
+
+end program spellchekc
diff --git a/gcc/testsuite/gfortran.dg/spellcheck-procedure_2.f90 b/gcc/testsuite/gfortran.dg/spellcheck-procedure_2.f90
new file mode 100644
index 0000000..a6ea5f9
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/spellcheck-procedure_2.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! test levenshtein based spelling suggestions
+
+
+program spellchekc
+ implicit none (external) ! { dg-warning "GNU Extension: IMPORT NONE with spec list" }
+
+ interface
+ subroutine bark_unless_zero(iarg)
+ implicit none
+ integer, intent(in) :: iarg
+ end subroutine bark_unless_zero
+ end interface
+
+ integer :: i
+ i = 0
+
+ if (i /= 1) call abort
+ call bark_unless_0(i) ! { dg-error "not explicitly declared; did you mean .bark_unless_zero.\\?" }
+! call complain_about_0(i) ! { -dg-error "not explicitly declared; did you mean .complain_about_zero.\\?" }
+
+contains
+! We cannot reliably see this ATM, would need an unambiguous bit somewhere
+ subroutine complain_about_zero(iarg)
+ integer, intent(in) :: iarg
+ if (iarg /= 0) call abort
+ end subroutine complain_about_zero
+
+end program spellchekc
+
+subroutine bark_unless_zero(iarg)
+ implicit none
+ integer, intent(in) :: iarg
+ if (iarg /= 0) call abort
+end subroutine bark_unless_zero
diff --git a/gcc/testsuite/gfortran.dg/spellcheck-structure.f90 b/gcc/testsuite/gfortran.dg/spellcheck-structure.f90
new file mode 100644
index 0000000..929e05f
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/spellcheck-structure.f90
@@ -0,0 +1,35 @@
+! { dg-do compile }
+! test levenshtein based spelling suggestions
+implicit none
+
+!!!!!!!!!!!!!! structure tests !!!!!!!!!!!!!!
+type type1
+ real :: radius
+ integer :: i
+end type type1
+
+type type2
+ integer :: myint
+ type(type1) :: mytype
+end type type2
+
+type type3
+ type(type2) :: type_2
+end type type3
+type type4
+ type(type3) :: type_3
+end type type4
+
+type(type1) :: t1
+t1%radiuz = .0 ! { dg-error ".radiuz. at .1. is not a member of the .type1. structure; did you mean .radius.\\?" }
+t1%x = .0 ! { dg-error ".x. at .1. is not a member of the .type1. structure" }
+type(type2) :: t2
+t2%mytape%radius = .0 ! { dg-error ".mytape. at .1. is not a member of the .type2. structure; did you mean .mytype.\\?" }
+t2%mytype%radious = .0 ! { dg-error ".radious. at .1. is not a member of the .type1. structure; did you mean .radius.\\?" }
+type(type4) :: t4
+t4%type_3%type_2%mytype%radium = 88.0 ! { dg-error ".radium. at .1. is not a member of the .type1. structure; did you mean .radius.\\?" }
+
+!!!!!!!!!!!!!! symbol tests !!!!!!!!!!!!!!
+integer :: iarg1
+iarg2 = 1 ! { dg-error "Symbol .iarg2. at .1. has no IMPLICIT type; did you mean .iarg1.\\?" }
+end
diff --git a/gcc/testsuite/gfortran.dg/submodule_30.f08 b/gcc/testsuite/gfortran.dg/submodule_30.f08
new file mode 100644
index 0000000..25dcbeb
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/submodule_30.f08
@@ -0,0 +1,42 @@
+! { dg-do run }
+!
+! Test the fix for PR82550 in which the reference to 'p' in 'foo'
+! was not being correctly handled.
+!
+! Contributed by Reinhold Bader <Bader@lrz.de>
+!
+module m_subm_18_pos
+ implicit none
+ integer :: i = 0
+ interface
+ module subroutine foo(fun_ptr)
+ procedure(p), pointer, intent(out) :: fun_ptr
+ end subroutine
+ end interface
+contains
+ subroutine p()
+ i = 1
+ end subroutine p
+end module m_subm_18_pos
+submodule (m_subm_18_pos) subm_18_pos
+ implicit none
+contains
+ module subroutine foo(fun_ptr)
+ procedure(p), pointer, intent(out) :: fun_ptr
+ fun_ptr => p
+ end subroutine
+end submodule
+program p_18_pos
+ use m_subm_18_pos
+ implicit none
+ procedure(), pointer :: x
+ call foo(x)
+ call x()
+ if (i == 1) then
+ write(*,*) 'OK'
+ else
+ write(*,*) 'FAIL'
+ call abort
+ end if
+end program p_18_pos
+
diff --git a/gcc/testsuite/gfortran.dg/typebound_proc_36.f90 b/gcc/testsuite/gfortran.dg/typebound_proc_36.f90
new file mode 100644
index 0000000..5c9193c
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/typebound_proc_36.f90
@@ -0,0 +1,77 @@
+! { dg-do run }
+!
+! Test the fix for PR82312.f90
+!
+! Posted on Stack Overflow:
+! https://stackoverflow.com/questions/46369744
+! /gfortran-associates-wrong-type-bound-procedure/46388339#46388339
+!
+module minimalisticcase
+ implicit none
+
+ type, public :: DataStructure
+ integer :: i
+ contains
+ procedure, pass :: init => init_data_structure
+ procedure, pass :: a => beginning_of_alphabet
+ end type
+
+ type, public :: DataLogger
+ type(DataStructure), pointer :: data_structure
+ contains
+ procedure, pass :: init => init_data_logger
+ procedure, pass :: do_something => do_something
+ end type
+
+ integer :: ctr = 0
+
+contains
+ subroutine init_data_structure(self)
+ implicit none
+ class(DataStructure), intent(inout) :: self
+ write(*,*) 'init_data_structure'
+ ctr = ctr + 1
+ end subroutine
+
+ subroutine beginning_of_alphabet(self)
+ implicit none
+ class(DataStructure), intent(inout) :: self
+
+ write(*,*) 'beginning_of_alphabet'
+ ctr = ctr + 10
+ end subroutine
+
+ subroutine init_data_logger(self, data_structure)
+ implicit none
+ class(DataLogger), intent(inout) :: self
+ class(DataStructure), target :: data_structure
+ write(*,*) 'init_data_logger'
+ ctr = ctr + 100
+
+ self%data_structure => data_structure ! Invalid change of 'self' vptr
+ call self%do_something()
+ end subroutine
+
+ subroutine do_something(self)
+ implicit none
+ class(DataLogger), intent(inout) :: self
+
+ write(*,*) 'do_something'
+ ctr = ctr + 1000
+
+ end subroutine
+end module
+
+program main
+ use minimalisticcase
+ implicit none
+
+ type(DataStructure) :: data_structure
+ type(DataLogger) :: data_logger
+
+ call data_structure%init()
+ call data_structure%a()
+ call data_logger%init(data_structure)
+
+ if (ctr .ne. 1111) call abort
+end program
diff --git a/gcc/testsuite/gfortran.dg/unconstrained_commons.f b/gcc/testsuite/gfortran.dg/unconstrained_commons.f
index cb84e7f..28972b6 100644
--- a/gcc/testsuite/gfortran.dg/unconstrained_commons.f
+++ b/gcc/testsuite/gfortran.dg/unconstrained_commons.f
@@ -9,8 +9,8 @@
IMPLICIT DOUBLE PRECISION (X)
INTEGER J
COMMON /MYCOMMON / X(1)
- DO 10 J=1,1024
- X(J+1)=X(J+7)
+ DO 10 J=1,1024 ! { dg-warning "out of bounds" }
+ X(J+1)=X(J+7) ! { dg-warning "out of bounds" }
10 CONTINUE
RETURN
END
diff --git a/gcc/testsuite/gfortran.dg/vect/fast-math-mgrid-resid.f b/gcc/testsuite/gfortran.dg/vect/fast-math-mgrid-resid.f
index 54f1e9e..7e2816b 100644
--- a/gcc/testsuite/gfortran.dg/vect/fast-math-mgrid-resid.f
+++ b/gcc/testsuite/gfortran.dg/vect/fast-math-mgrid-resid.f
@@ -2,6 +2,7 @@
! { dg-require-effective-target vect_double }
! { dg-options "-O3 --param vect-max-peeling-for-alignment=0 -fpredictive-commoning -fdump-tree-pcom-details" }
! { dg-additional-options "-mprefer-avx128" { target { i?86-*-* x86_64-*-* } } }
+! { dg-additional-options "-mzarch" { target { s390*-*-* } } }
******* RESID COMPUTES THE RESIDUAL: R = V - AU
*
diff --git a/gcc/testsuite/gfortran.dg/vect/pr60510.f b/gcc/testsuite/gfortran.dg/vect/pr60510.f
index 5e2c085..202c1be 100644
--- a/gcc/testsuite/gfortran.dg/vect/pr60510.f
+++ b/gcc/testsuite/gfortran.dg/vect/pr60510.f
@@ -1,5 +1,6 @@
! { dg-do run }
! { dg-require-effective-target vect_double }
+! { dg-require-effective-target vect_intdouble_cvt }
! { dg-additional-options "-fno-inline -ffast-math" }
subroutine foo(a,x,y,n)
implicit none
diff --git a/gcc/testsuite/gfortran.dg/vect/pr77848.f b/gcc/testsuite/gfortran.dg/vect/pr77848.f
index d54676e..4752205 100644
--- a/gcc/testsuite/gfortran.dg/vect/pr77848.f
+++ b/gcc/testsuite/gfortran.dg/vect/pr77848.f
@@ -1,6 +1,7 @@
! PR 77848: Verify versioning is on when vectorization fails
! { dg-do compile }
! { dg-options "-O3 -ffast-math -fdump-tree-ifcvt -fdump-tree-vect-details" }
+! { dg-additional-options "-mzarch" { target { s390*-*-* } } }
subroutine sub(x,a,n,m)
implicit none
diff --git a/gcc/testsuite/gfortran.dg/vect/vect-8.f90 b/gcc/testsuite/gfortran.dg/vect/vect-8.f90
index ec95598..8e18be5 100644
--- a/gcc/testsuite/gfortran.dg/vect/vect-8.f90
+++ b/gcc/testsuite/gfortran.dg/vect/vect-8.f90
@@ -704,4 +704,5 @@ CALL track('KERNEL ')
RETURN
END SUBROUTINE kernel
-! { dg-final { scan-tree-dump-times "vectorized 21 loops" 1 "vect" } }
+! { dg-final { scan-tree-dump-times "vectorized 21 loops" 1 "vect" { target { vect_intdouble_cvt } } } }
+! { dg-final { scan-tree-dump-times "vectorized 17 loops" 1 "vect" { target { ! vect_intdouble_cvt } } } }
diff --git a/gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f90 b/gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f90
index 6a663e6..19097a7 100644
--- a/gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f90
+++ b/gcc/testsuite/gfortran.dg/warn_argument_mismatch_1.f90
@@ -1,5 +1,5 @@
! { dg-do compile }
-! { dg-options "-Wno-argument-mismatch" }
+! { dg-options "-std=legacy -Wno-argument-mismatch" }
!
! No warnings should be output here with -Wno-argument-mismatch.
!
diff --git a/gcc/testsuite/gfortran.dg/zero_sized_7.f90 b/gcc/testsuite/gfortran.dg/zero_sized_7.f90
new file mode 100644
index 0000000..7908532
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/zero_sized_7.f90
@@ -0,0 +1,18 @@
+! { dg-do compile }
+! PR 80118 - this used to ICE
+! Original test case by Marco Restelli
+module m
+implicit none
+
+ integer, parameter :: not_empty(1) = 0
+ integer, parameter :: empty1(0) = (/integer :: /)
+ integer, parameter :: empty2(0) = 0
+
+contains
+
+ subroutine sub(v)
+ integer, allocatable, intent(out) :: v(:)
+ v = 2*empty2 ! internal compiler error
+ end subroutine sub
+
+end module m
diff --git a/gcc/testsuite/gnat.dg/class_wide3.adb b/gcc/testsuite/gnat.dg/class_wide3.adb
new file mode 100644
index 0000000..c177029
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/class_wide3.adb
@@ -0,0 +1,8 @@
+with Ada.Text_IO; use Ada.Text_IO;
+with Class_Wide3_Pkg; use Class_Wide3_Pkg;
+
+procedure Class_Wide3 is
+ DC : Disc_Child := (N => 1, I => 3, J => 5);
+begin
+ DC.Put_Line;
+end Class_Wide3;
diff --git a/gcc/testsuite/gnat.dg/class_wide3_pkg.ads b/gcc/testsuite/gnat.dg/class_wide3_pkg.ads
new file mode 100644
index 0000000..a4104fc
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/class_wide3_pkg.ads
@@ -0,0 +1,16 @@
+package Class_Wide3_Pkg is
+
+ type Iface is interface;
+ type Iface_Ptr is access all Iface'Class;
+
+ procedure Put_Line (I : Iface'Class);
+
+ type Root is tagged record
+ I : Integer;
+ end record;
+
+ type Disc_Child (N : Integer) is new Root and Iface with record
+ J : Integer;
+ end record;
+
+end Class_Wide3_Pkg;
diff --git a/gcc/testsuite/gnat.dg/class_wide4.adb b/gcc/testsuite/gnat.dg/class_wide4.adb
new file mode 100644
index 0000000..f44d641
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/class_wide4.adb
@@ -0,0 +1,20 @@
+-- { dg-do run }
+
+with Class_Wide4_Pkg;
+with Class_Wide4_Pkg2;
+
+procedure Class_Wide4 is
+ D : aliased Class_Wide4_Pkg.Data_Object;
+ O : aliased Class_Wide4_Pkg2.Object;
+ IA : not null access Class_Wide4_Pkg.Conditional_Interface'Class :=
+ O'Access;
+ I : Class_Wide4_Pkg.Conditional_Interface'Class renames
+ Class_Wide4_Pkg.Conditional_Interface'Class (O);
+begin
+ O.Do_Stuff;
+ O.Do_Stuff_Access;
+ IA.Do_Stuff;
+ IA.Do_Stuff_Access;
+ I.Do_Stuff;
+ I.Do_Stuff_Access;
+end Class_Wide4;
diff --git a/gcc/testsuite/gnat.dg/class_wide4_pkg.ads b/gcc/testsuite/gnat.dg/class_wide4_pkg.ads
new file mode 100644
index 0000000..b8ba44c
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/class_wide4_pkg.ads
@@ -0,0 +1,21 @@
+package Class_Wide4_Pkg is
+
+ type Conditional_Interface is limited interface;
+
+ type Data_Object is tagged null record;
+
+ function Is_Valid
+ (This : in Conditional_Interface)
+ return Boolean is abstract;
+
+ procedure Do_Stuff
+ (This : in out Conditional_Interface) is abstract
+ with
+ Pre'Class => This.Is_Valid;
+
+ procedure Do_Stuff_Access
+ (This : not null access Conditional_Interface) is abstract
+ with
+ Pre'Class => This.Is_Valid;
+
+end Class_Wide4_Pkg;
diff --git a/gcc/testsuite/gnat.dg/class_wide4_pkg2.ads b/gcc/testsuite/gnat.dg/class_wide4_pkg2.ads
new file mode 100644
index 0000000..1e5799d
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/class_wide4_pkg2.ads
@@ -0,0 +1,30 @@
+with Class_Wide4_Pkg;
+
+package Class_Wide4_Pkg2 is
+
+ type Object is limited new
+ Class_Wide4_Pkg.Conditional_Interface with
+ record
+ Val : Integer := 1234;
+ end record;
+
+ function Is_Valid
+ (This : in Object)
+ return Boolean
+ is
+ (This.Val = 1234);
+
+ function Is_Supported_Data
+ (This : in Object;
+ Data : not null access Class_Wide4_Pkg.Data_Object'Class)
+ return Boolean
+ is
+ (This.Val = 1234);
+
+ procedure Do_Stuff
+ (This : in out Object) is null;
+
+ procedure Do_Stuff_Access
+ (This : not null access Object) is null;
+
+end Class_Wide4_Pkg2;
diff --git a/gcc/testsuite/gnat.dg/default_pkg_actual.adb b/gcc/testsuite/gnat.dg/default_pkg_actual.adb
new file mode 100644
index 0000000..d10ae0c
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/default_pkg_actual.adb
@@ -0,0 +1,32 @@
+-- { dg-do compile }
+
+procedure Default_Pkg_Actual is
+
+ generic
+ package As is
+ end As;
+
+ generic
+ type T is private;
+ with package A0 is new As;
+ package Bs is
+ end Bs;
+
+ generic
+ with package Xa is new As;
+ package Xs is
+ package Xb is new Bs(T => Integer, A0 => Xa);
+ end Xs;
+
+ generic
+ with package Yb is new Bs(T => Integer, others => <>);
+ package Ys is
+ end Ys;
+
+ package A is new As;
+ package X is new Xs(Xa => A);
+ package Y is new Ys(Yb => X.Xb);
+
+begin
+ null;
+end;
diff --git a/gcc/testsuite/gnat.dg/default_pkg_actual2.adb b/gcc/testsuite/gnat.dg/default_pkg_actual2.adb
new file mode 100644
index 0000000..7ab614a
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/default_pkg_actual2.adb
@@ -0,0 +1,27 @@
+-- { dg-do compile }
+
+procedure Default_Pkg_Actual2 is
+
+ generic
+ package P1 is
+ end;
+
+ generic
+ with package FP1a is new P1;
+ with package FP1b is new P1;
+ package P2 is
+ end;
+
+ generic
+ with package FP2 is new P2 (FP1a => <>, FP1b => <>);
+ package P3 is
+ end;
+
+ package NP1a is new P1;
+ package NP1b is new P1;
+ package NP2 is new P2 (NP1a, NP1b);
+ package NP4 is new P3 (NP2);
+
+begin
+ null;
+end;
diff --git a/gcc/testsuite/gnat.dg/dimensions.adb b/gcc/testsuite/gnat.dg/dimensions.adb
new file mode 100644
index 0000000..86fc6ee
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/dimensions.adb
@@ -0,0 +1,5 @@
+-- { dg-do compile }
+
+package body Dimensions is
+ procedure Dummy is null;
+end Dimensions;
diff --git a/gcc/testsuite/gnat.dg/dimensions.ads b/gcc/testsuite/gnat.dg/dimensions.ads
new file mode 100644
index 0000000..54bab08
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/dimensions.ads
@@ -0,0 +1,29 @@
+package Dimensions is
+
+ type Mks_Int_Type is new Integer
+ with
+ Dimension_System => (
+ (Unit_Name => Meter, Unit_Symbol => 'm', Dim_Symbol => 'L'),
+ (Unit_Name => Kilogram, Unit_Symbol => "kg", Dim_Symbol => 'M'),
+ (Unit_Name => Second, Unit_Symbol => 's', Dim_Symbol => 'T'),
+ (Unit_Name => Ampere, Unit_Symbol => 'A', Dim_Symbol => 'I'),
+ (Unit_Name => Kelvin, Unit_Symbol => 'K', Dim_Symbol => '@'),
+ (Unit_Name => Mole, Unit_Symbol => "mol", Dim_Symbol => 'N'),
+ (Unit_Name => Candela, Unit_Symbol => "cd", Dim_Symbol => 'J'));
+
+ subtype Int_Length is Mks_Int_Type
+ with
+ Dimension => (Symbol => 'm',
+ Meter => 1,
+ others => 0);
+
+ subtype Int_Speed is Mks_Int_Type
+ with
+ Dimension => (
+ Meter => 1,
+ Second => -1,
+ others => 0);
+
+ procedure Dummy;
+
+end Dimensions;
diff --git a/gcc/testsuite/gnat.dg/discr48.adb b/gcc/testsuite/gnat.dg/discr48.adb
new file mode 100644
index 0000000..677f6ec
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/discr48.adb
@@ -0,0 +1,9 @@
+-- { dg-do compile }
+
+with Discr48_Pkg; use Discr48_Pkg;
+
+function Discr48 return Rec_Access is
+ C : constant Rec := (Count => 1, Seps => (1 .. 0 => Null_XString));
+begin
+ return new Rec'(C);
+end;
diff --git a/gcc/testsuite/gnat.dg/discr48_pkg.ads b/gcc/testsuite/gnat.dg/discr48_pkg.ads
new file mode 100644
index 0000000..646b4f11
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/discr48_pkg.ads
@@ -0,0 +1,19 @@
+with Ada.Finalization;
+
+package Discr48_Pkg is
+
+ type XString is new Ada.Finalization.Controlled with record
+ B : Boolean;
+ end record;
+
+ Null_XString : constant XString := (Ada.Finalization.Controlled with B => False);
+
+ type XString_Array is array (Natural range <>) of XString;
+
+ type Rec (Count : Positive) is record
+ Seps : XString_Array (2 .. Count);
+ end record;
+
+ type Rec_Access is access all Rec;
+
+end Discr48_Pkg;
diff --git a/gcc/testsuite/gnat.dg/entry_family.adb b/gcc/testsuite/gnat.dg/entry_family.adb
new file mode 100644
index 0000000..21d208f
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/entry_family.adb
@@ -0,0 +1,28 @@
+-- { dg-do compile }
+-- { dg-options "-gnatwu" }
+
+with Ada.Numerics.Discrete_Random; use Ada.Numerics;
+
+procedure Entry_Family is
+ protected Family is
+ entry Call (Boolean);
+ end Family;
+
+ protected body Family is
+ entry Call (for P in Boolean) when True is
+ begin
+ null;
+ end Call;
+
+ end Family;
+
+ package Random_Boolean is new Discrete_Random (Result_Subtype => Boolean);
+ use Random_Boolean;
+
+ Boolean_Generator : Generator;
+
+ B : constant Boolean := Random (Boolean_Generator);
+
+begin
+ Family.Call (B);
+end Entry_Family;
diff --git a/gcc/testsuite/gnat.dg/remote_call_iface.adb b/gcc/testsuite/gnat.dg/remote_call_iface.adb
new file mode 100644
index 0000000..6816ad9
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/remote_call_iface.adb
@@ -0,0 +1,7 @@
+-- { dg-do compile }
+
+package body Remote_Call_Iface is
+ procedure Proc is begin null; end;
+begin
+ Proc;
+end Remote_Call_Iface;
diff --git a/gcc/testsuite/gnat.dg/remote_call_iface.ads b/gcc/testsuite/gnat.dg/remote_call_iface.ads
new file mode 100644
index 0000000..ce12fef
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/remote_call_iface.ads
@@ -0,0 +1,5 @@
+generic
+package Remote_Call_Iface is
+ pragma Remote_Call_Interface;
+ procedure Proc;
+end Remote_Call_Iface;
diff --git a/gcc/testsuite/gnat.dg/specs/discr_private.ads b/gcc/testsuite/gnat.dg/specs/discr2.ads
index 0ddfbd1..f7ece05 100644
--- a/gcc/testsuite/gnat.dg/specs/discr_private.ads
+++ b/gcc/testsuite/gnat.dg/specs/discr2.ads
@@ -1,7 +1,7 @@
-- { dg-do compile }
-- { dg-options "-gnatws" }
-package Discr_Private is
+package Discr2 is
package Dec is
type T_DECIMAL (Prec : Integer := 1) is private;
@@ -47,4 +47,4 @@ package Discr_Private is
end case;
end record;
-end Discr_Private;
+end Discr2;
diff --git a/gcc/testsuite/gnat.dg/specs/discr_record_constant.ads b/gcc/testsuite/gnat.dg/specs/discr3.ads
index f43b138..bcb996b 100644
--- a/gcc/testsuite/gnat.dg/specs/discr_record_constant.ads
+++ b/gcc/testsuite/gnat.dg/specs/discr3.ads
@@ -2,7 +2,7 @@
pragma Restrictions (No_Implicit_Heap_Allocations);
-package Discr_Record_Constant is
+package Discr3 is
type T (Big : Boolean := False) is record
case Big is
@@ -19,4 +19,4 @@ package Discr_Record_Constant is
Con : constant T := D; -- Violation of restriction
Ter : constant T := Con; -- Violation of restriction
-end Discr_Record_Constant;
+end Discr3;
diff --git a/gcc/testsuite/gnat.dg/specs/discr4.ads b/gcc/testsuite/gnat.dg/specs/discr4.ads
new file mode 100644
index 0000000..a7fc25b
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/specs/discr4.ads
@@ -0,0 +1,23 @@
+-- { dg-do compile }
+-- { dg-options "-O" }
+
+with Discr4_Pkg; use Discr4_Pkg;
+
+package Discr4 is
+
+ type Data is record
+ Val : Rec;
+ Set : Boolean;
+ end record;
+
+ type Pair is record
+ Lower, Upper : Data;
+ end record;
+
+ function Build (L, U : Rec) return Pair is ((L, True), (U, False));
+
+ C1 : constant Pair := Build (Rec_One, Rec_Three);
+
+ C2 : constant Pair := Build (Get (0), Rec_Three);
+
+end Discr4;
diff --git a/gcc/testsuite/gnat.dg/specs/discr4_pkg.ads b/gcc/testsuite/gnat.dg/specs/discr4_pkg.ads
new file mode 100644
index 0000000..231a8fb
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/specs/discr4_pkg.ads
@@ -0,0 +1,27 @@
+package Discr4_Pkg is
+
+ type Enum is (One, Two, Three);
+
+ type Rec is private;
+
+ Rec_One : constant Rec;
+ Rec_Three : constant Rec;
+
+ function Get (Value : Integer) return Rec;
+
+private
+
+ type Rec (D : Enum := Two) is record
+ case D is
+ when One => null;
+ when Two => Value : Integer;
+ when Three => null;
+ end case;
+ end record;
+
+ Rec_One : constant Rec := (D => One);
+ Rec_Three : constant Rec := (D => Three);
+
+ function Get (Value : Integer) return Rec is (Two, Value);
+
+end Discr4_Pkg;
diff --git a/gcc/testsuite/gnat.dg/stack_usage4.adb b/gcc/testsuite/gnat.dg/stack_usage4.adb
new file mode 100644
index 0000000..24cd1a7
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/stack_usage4.adb
@@ -0,0 +1,11 @@
+-- { dg-do compile }
+-- { dg-options "-Wstack-usage=512" }
+
+with Stack_Usage4_Pkg; use Stack_Usage4_Pkg;
+
+procedure Stack_Usage4 is
+ BS : Bounded_String := Get;
+ S : String := BS.Data (BS.Data'First .. BS.Len);
+begin
+ null;
+end;
diff --git a/gcc/testsuite/gnat.dg/stack_usage4_pkg.ads b/gcc/testsuite/gnat.dg/stack_usage4_pkg.ads
new file mode 100644
index 0000000..9bad627
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/stack_usage4_pkg.ads
@@ -0,0 +1,12 @@
+package Stack_Usage4_Pkg is
+
+ subtype Name_Index_Type is Natural range 1 .. 63;
+
+ type Bounded_String is record
+ Len : Name_Index_Type;
+ Data : String (Name_Index_Type'Range);
+ end record;
+
+ function Get return Bounded_String;
+
+end Stack_Usage4_Pkg;
diff --git a/gcc/testsuite/gnat.dg/sync_iface_call.adb b/gcc/testsuite/gnat.dg/sync_iface_call.adb
new file mode 100644
index 0000000..16039818
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/sync_iface_call.adb
@@ -0,0 +1,34 @@
+-- { dg-do compile }
+
+with Sync_Iface_Call_Pkg;
+with Sync_Iface_Call_Pkg2;
+
+procedure Sync_Iface_Call is
+
+ Impl : access Sync_Iface_Call_Pkg.IFace'Class :=
+ new Sync_Iface_Call_Pkg2.Impl;
+ Val : aliased Integer := 10;
+begin
+ select
+ Impl.Do_Stuff (Val);
+ or
+ delay 10.0;
+ end select;
+ select
+ Impl.Do_Stuff_Access (Val'Access);
+ or
+ delay 10.0;
+ end select;
+
+ select
+ Impl.Do_Stuff_2 (Val);
+ or
+ delay 10.0;
+ end select;
+
+ select
+ Impl.Do_Stuff_2_Access (Val'Access);
+ or
+ delay 10.0;
+ end select;
+end Sync_Iface_Call;
diff --git a/gcc/testsuite/gnat.dg/sync_iface_call_pkg.ads b/gcc/testsuite/gnat.dg/sync_iface_call_pkg.ads
new file mode 100644
index 0000000..e392c02
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/sync_iface_call_pkg.ads
@@ -0,0 +1,21 @@
+package Sync_Iface_Call_Pkg is
+
+ type IFace is synchronized interface;
+
+ procedure Do_Stuff
+ (This : in out IFace;
+ Value : in Integer) is null;
+
+ procedure Do_Stuff_Access
+ (This : in out IFace;
+ Value : not null access Integer) is null;
+
+ procedure Do_Stuff_2
+ (This : not null access IFace;
+ Value : in Integer) is null;
+
+ procedure Do_Stuff_2_Access
+ (This : not null access IFace;
+ Value : not null access Integer) is null;
+
+end Sync_Iface_Call_Pkg;
diff --git a/gcc/testsuite/gnat.dg/sync_iface_call_pkg2.adb b/gcc/testsuite/gnat.dg/sync_iface_call_pkg2.adb
new file mode 100644
index 0000000..b3c221e
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/sync_iface_call_pkg2.adb
@@ -0,0 +1,8 @@
+package body Sync_Iface_Call_Pkg2 is
+
+ task body Impl is
+ begin
+ null;
+ end Impl;
+
+end Sync_Iface_Call_Pkg2;
diff --git a/gcc/testsuite/gnat.dg/sync_iface_call_pkg2.ads b/gcc/testsuite/gnat.dg/sync_iface_call_pkg2.ads
new file mode 100644
index 0000000..ca21b1d
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/sync_iface_call_pkg2.ads
@@ -0,0 +1,7 @@
+with Sync_Iface_Call_Pkg;
+
+package Sync_Iface_Call_Pkg2 is
+
+ task type Impl is new Sync_Iface_Call_Pkg.IFace with end;
+
+end Sync_Iface_Call_Pkg2;
diff --git a/gcc/testsuite/gnat.dg/unchecked_union2.adb b/gcc/testsuite/gnat.dg/unchecked_union2.adb
new file mode 100644
index 0000000..ccb6e60
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/unchecked_union2.adb
@@ -0,0 +1,35 @@
+-- { dg-do compile }
+
+procedure Unchecked_Union2 is
+ type small_array is array (0 .. 2) of Integer;
+ type big_array is array (0 .. 3) of Integer;
+
+ type small_record is record
+ field1 : aliased Integer := 0;
+ field2 : aliased small_array := (0, 0, 0);
+ end record;
+
+ type big_record is record
+ field1 : aliased Integer := 0;
+ field2 : aliased big_array := (0, 0, 0, 0);
+ end record;
+
+ type myUnion (discr : Integer := 0) is record
+ case discr is
+ when 0 =>
+ record1 : aliased small_record;
+ when others =>
+ record2 : aliased big_record;
+ end case;
+ end record;
+
+ type UU_myUnion3 (discr : Integer := 0) is new myUnion (discr); -- Test
+ pragma Unchecked_Union (UU_myUnion3);
+ pragma Convention (C, UU_myUnion3);
+
+ procedure Convert (A : in UU_myUnion3; B : out UU_myUnion3);
+ pragma Import (C, Convert);
+
+begin
+ null;
+end Unchecked_Union2;
diff --git a/gcc/testsuite/gnat.dg/unchecked_union3.adb b/gcc/testsuite/gnat.dg/unchecked_union3.adb
new file mode 100644
index 0000000..638861a
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/unchecked_union3.adb
@@ -0,0 +1,38 @@
+-- { dg-do compile }
+
+procedure Unchecked_Union3 is
+ type small_array is array (0 .. 2) of Integer;
+ type big_array is array (0 .. 3) of Integer;
+
+ type small_record is record
+ field1 : aliased Integer := 0;
+ field2 : aliased small_array := (0, 0, 0);
+ end record;
+
+ type big_record is record
+ field1 : aliased Integer := 0;
+ field2 : aliased big_array := (0, 0, 0, 0);
+ end record;
+
+ type myUnion (discr : Integer := 0) is record
+ case discr is
+ when 0 =>
+ record1 : aliased small_record;
+ when others =>
+ record2 : aliased big_record;
+ end case;
+ end record;
+
+ type UU_myUnion1 is new myUnion;
+ pragma Unchecked_Union (UU_myUnion1);
+ pragma Convention (C, UU_myUnion1);
+
+ procedure Convert (A : in myUnion; B : out UU_myUnion1) is
+ L : UU_myUnion1 := UU_myUnion1 (A); -- Test
+ begin
+ B := L;
+ end Convert;
+
+begin
+ null;
+end Unchecked_Union3;
diff --git a/gcc/testsuite/gnat.dg/validity_check2.adb b/gcc/testsuite/gnat.dg/validity_check2.adb
new file mode 100644
index 0000000..f349cf1
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/validity_check2.adb
@@ -0,0 +1,11 @@
+-- { dg-do compile }
+-- { dg-options "-gnatVi -gnatws" }
+
+with Validity_Check2_Pkg; use Validity_Check2_Pkg;
+
+procedure Validity_Check2 (R : access Rec) is
+begin
+ if Op_Code_To_Msg (R.Code) in Valid_Msg then
+ raise Program_Error;
+ end if;
+end;
diff --git a/gcc/testsuite/gnat.dg/validity_check2_pkg.ads b/gcc/testsuite/gnat.dg/validity_check2_pkg.ads
new file mode 100644
index 0000000..c9b6a01
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/validity_check2_pkg.ads
@@ -0,0 +1,16 @@
+with Ada.unchecked_conversion;
+
+package Validity_Check2_Pkg is
+
+ type Op_Code is (One, Two, Three, Four);
+
+ subtype Valid_Msg is Integer range 0 .. 15;
+
+ function Op_Code_To_Msg is
+ new Ada.Unchecked_Conversion (Source => Op_code, Target => Valid_Msg);
+
+ type Rec is record
+ Code : Op_Code;
+ end record;
+
+end Validity_Check2_Pkg;
diff --git a/gcc/testsuite/jit.dg/all-non-failing-tests.h b/gcc/testsuite/jit.dg/all-non-failing-tests.h
index acfcc40..bf02e12 100644
--- a/gcc/testsuite/jit.dg/all-non-failing-tests.h
+++ b/gcc/testsuite/jit.dg/all-non-failing-tests.h
@@ -71,6 +71,13 @@
#undef create_code
#undef verify_code
+/* test-returning-function-ptr.c */
+#define create_code create_code_calling_internal_function
+#define verify_code verify_code_calling_internal_function
+#include "test-returning-function-ptr.c"
+#undef create_code
+#undef verify_code
+
/* test-compound-assignment.c */
#define create_code create_code_compound_assignment
#define verify_code verify_code_compound_assignment
@@ -283,6 +290,9 @@ const struct testcase testcases[] = {
{"calling_function_ptr",
create_code_calling_function_ptr,
verify_code_calling_function_ptr},
+ {"calling_internal_function",
+ create_code_calling_internal_function,
+ verify_code_calling_internal_function},
{"compound_assignment",
create_code_compound_assignment,
verify_code_compound_assignment},
diff --git a/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c
new file mode 100644
index 0000000..4faa3b4
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-error-mismatching-types-in-assignment-fn-ptr.c
@@ -0,0 +1,92 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+
+ typedef void (*fn_ptr_iii) (int, int, int);
+ typedef void (*fn_ptr_ifi) (int, float, int);
+ void
+ test_fn (void)
+ {
+ fn_ptr_iii iii_ptr;
+ fn_ptr_ifi ifi_ptr;
+
+ iii_ptr = NULL;
+ ifi_ptr = iii_ptr;
+ }
+
+ and verify that the API complains about the mismatching types
+ in the second assignment (but not the first).
+ */
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *float_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+
+ gcc_jit_type *iii_types[] = {int_type, int_type, int_type};
+ gcc_jit_type *fn_ptr_type_iii
+ = gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 3, iii_types,
+ 0);
+
+ gcc_jit_type *ifi_types[] = {int_type, float_type, int_type};
+ gcc_jit_type *fn_ptr_type_ifi
+ = gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 3, ifi_types,
+ 0);
+
+ gcc_jit_function *test_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "test_fn",
+ 0, NULL,
+ 0);
+ gcc_jit_lvalue *iii_ptr =
+ gcc_jit_function_new_local (
+ test_fn, NULL, fn_ptr_type_iii, "iii_ptr");
+ gcc_jit_lvalue *ifi_ptr =
+ gcc_jit_function_new_local (
+ test_fn, NULL, fn_ptr_type_ifi, "ifi_ptr");
+
+ gcc_jit_block *block = gcc_jit_function_new_block (test_fn, NULL);
+
+ /* iii_ptr = NULL; */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ iii_ptr,
+ gcc_jit_context_null (ctxt, fn_ptr_type_iii));
+ /* ifi_ptr = iii_ptr; */
+ gcc_jit_block_add_assignment (
+ block, NULL,
+ ifi_ptr,
+ gcc_jit_lvalue_as_rvalue (iii_ptr));
+ gcc_jit_block_end_with_void_return (block, NULL);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ CHECK_VALUE (result, NULL);
+
+ /* Verify that the correct error message was emitted. */
+ CHECK_STRING_VALUE (gcc_jit_context_get_first_error (ctxt),
+ "gcc_jit_block_add_assignment:"
+ " mismatching types:"
+ " assignment to ifi_ptr"
+ " (type: void (*) (int, float, int))"
+ " from iii_ptr"
+ " (type: void (*) (int, int, int))");
+}
+
diff --git a/gcc/testsuite/jit.dg/test-expressions.c b/gcc/testsuite/jit.dg/test-expressions.c
index 548cfa2..f9cc64f 100644
--- a/gcc/testsuite/jit.dg/test-expressions.c
+++ b/gcc/testsuite/jit.dg/test-expressions.c
@@ -920,6 +920,35 @@ verify_get_address (gcc_jit_result *result)
}
/**********************************************************************
+ Vector values
+ **********************************************************************/
+
+static void
+make_test_of_vectors (gcc_jit_context *ctxt)
+{
+ gcc_jit_type *scalar_type;
+ gcc_jit_type *vec_type;
+ gcc_jit_rvalue *elements[4];
+
+ scalar_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ vec_type = gcc_jit_type_get_vector (scalar_type, 4);
+
+ elements[0] = gcc_jit_context_new_rvalue_from_int (ctxt, scalar_type, 1);
+ elements[1] = gcc_jit_context_new_rvalue_from_int (ctxt, scalar_type, -2);
+ elements[2] = gcc_jit_context_new_rvalue_from_int (ctxt, scalar_type, 3);
+ elements[3] = gcc_jit_context_new_rvalue_from_int (ctxt, scalar_type, -4);
+
+ gcc_jit_rvalue *vec_rvalue
+ = gcc_jit_context_new_rvalue_from_vector (ctxt, NULL, vec_type,
+ 4, elements);
+ CHECK_STRING_VALUE (
+ gcc_jit_object_get_debug_string (
+ gcc_jit_rvalue_as_object (vec_rvalue)),
+ "{(int)1, (int)-2, (int)3, (int)-4}");
+}
+
+/**********************************************************************
Code for harness
**********************************************************************/
@@ -932,6 +961,7 @@ create_code (gcc_jit_context *ctxt, void *user_data)
make_tests_of_casts (ctxt);
make_tests_of_dereferences (ctxt);
make_test_of_get_address (ctxt);
+ make_test_of_vectors (ctxt);
}
void
diff --git a/gcc/testsuite/jit.dg/test-returning-function-ptr.c b/gcc/testsuite/jit.dg/test-returning-function-ptr.c
new file mode 100644
index 0000000..f96079c
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-returning-function-ptr.c
@@ -0,0 +1,162 @@
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ extern void
+ internally_called_function (int i, int j, int k);
+
+#ifdef __cplusplus
+}
+#endif
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ /* Let's try to inject the equivalent of:
+ extern void internally_called_function (int i, int j, int k);
+
+ static void
+ internal_test_caller (int a)
+ {
+ internally_called_function (a * 3, a * 4, a * 5);
+ }
+
+ typedef void (*fn_ptr_type) (int);
+
+ fn_ptr_type
+ get_test_caller (void)
+ {
+ // Verify that we can assign function pointers to variables
+ fn_ptr_type p;
+ p = internal_test_caller;
+ return p;
+ }
+ */
+ int i;
+ gcc_jit_type *void_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+ gcc_jit_type *int_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+
+ /* Declare the imported function. */
+ gcc_jit_param *params[3];
+ params[0] =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "i");
+ params[1] =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "j");
+ params[2] =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "k");
+ gcc_jit_function *called_fn =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_IMPORTED,
+ void_type,
+ "internally_called_function",
+ 3, params,
+ 0);
+
+ /* Build the test_caller fn. */
+ gcc_jit_param *param_a =
+ gcc_jit_context_new_param (ctxt, NULL, int_type, "a");
+ gcc_jit_function *test_caller =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ void_type,
+ "internal_test_caller",
+ 1, &param_a,
+ 0);
+ /* "a * 3, a * 4, a * 5" */
+ gcc_jit_rvalue *args[3];
+ for (i = 0; i < 3; i++)
+ args[i]
+ = gcc_jit_context_new_binary_op
+ (ctxt, NULL,
+ GCC_JIT_BINARY_OP_MULT,
+ int_type,
+ gcc_jit_param_as_rvalue (param_a),
+ gcc_jit_context_new_rvalue_from_int (ctxt,
+ int_type,
+ (i + 3) ));
+ gcc_jit_block *block = gcc_jit_function_new_block (test_caller, NULL);
+ gcc_jit_block_add_eval (
+ block, NULL,
+ gcc_jit_context_new_call (ctxt,
+ NULL,
+ called_fn,
+ 3, args));
+ gcc_jit_block_end_with_void_return (block, NULL);
+
+ gcc_jit_type *fn_ptr_type
+ = gcc_jit_context_new_function_ptr_type (ctxt, NULL,
+ void_type,
+ 1, &int_type,
+ 0);
+
+ /* Build the get_test_caller fn. */
+ gcc_jit_function *get_test_caller =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ fn_ptr_type,
+ "get_test_caller",
+ 0, NULL,
+ 0);
+ block = gcc_jit_function_new_block (get_test_caller, NULL);
+
+ /* fn_ptr_type p; */
+ gcc_jit_lvalue *local_p
+ = gcc_jit_function_new_local (get_test_caller, NULL,
+ fn_ptr_type, "p");
+
+ /* p = internal_test_caller; */
+ gcc_jit_block_add_assignment (block, NULL,
+ local_p,
+ gcc_jit_function_get_address (test_caller,
+ NULL));
+
+ /* return p; */
+ gcc_jit_block_end_with_return (block, NULL,
+ gcc_jit_lvalue_as_rvalue (local_p));
+}
+
+static int called_with[3];
+
+extern void
+internally_called_function (int i, int j, int k)
+{
+ called_with[0] = i;
+ called_with[1] = j;
+ called_with[2] = k;
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ typedef void (*test_caller_type) (int);
+ typedef test_caller_type (*get_test_caller_type) (void);
+ CHECK_NON_NULL (result);
+
+ get_test_caller_type get_test_caller =
+ (get_test_caller_type)gcc_jit_result_get_code (result, "get_test_caller");
+ CHECK_NON_NULL (get_test_caller);
+
+ test_caller_type test_caller = (test_caller_type)get_test_caller ();
+ CHECK_NON_NULL (test_caller);
+
+ called_with[0] = 0;
+ called_with[1] = 0;
+ called_with[2] = 0;
+
+ /* Call the JIT-generated function. */
+ test_caller (5);
+
+ /* Verify that it correctly called "internally_called_function". */
+ CHECK_VALUE (called_with[0], 15);
+ CHECK_VALUE (called_with[1], 20);
+ CHECK_VALUE (called_with[2], 25);
+}
diff --git a/gcc/testsuite/jit.dg/test-vector-rvalues.cc b/gcc/testsuite/jit.dg/test-vector-rvalues.cc
new file mode 100644
index 0000000..ac230bf7
--- /dev/null
+++ b/gcc/testsuite/jit.dg/test-vector-rvalues.cc
@@ -0,0 +1,211 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "libgccjit.h"
+
+#include "harness.h"
+
+typedef int v4si __attribute__ ((vector_size (16)));
+typedef unsigned int v4ui __attribute__ ((vector_size (16)));
+typedef float v4f __attribute__ ((vector_size (16)));
+
+static void
+create_vec_fn (gcc_jit_context *ctxt, const char *fnname,
+ gcc_jit_type *vec_type,
+ gcc_jit_type *elem_type,
+ enum gcc_jit_binary_op op)
+{
+ /* Create equivalent to:
+
+ static void
+ FNNAME (V *dst, const V *lhs, E p, E q, E r, E s)
+ {
+ V pqrs;
+ pqrs = {p, q, r, s};
+ *dst = *lhs OP pqrs;
+ }
+
+ where V is "vec_type" (e.g. v4si)
+ and E is "elem_type" (e.g. int). */
+
+ gcc_jit_type *ptr_type = gcc_jit_type_get_pointer (vec_type);
+
+ gcc_jit_type *const_type = gcc_jit_type_get_const (vec_type);
+ gcc_jit_type *ptr_to_const_type = gcc_jit_type_get_pointer (const_type);
+
+ gcc_jit_param *dst =
+ gcc_jit_context_new_param (ctxt, NULL, ptr_type, "dst");
+ gcc_jit_param *lhs =
+ gcc_jit_context_new_param (ctxt, NULL, ptr_to_const_type, "lhs");
+ gcc_jit_param *p =
+ gcc_jit_context_new_param (ctxt, NULL, elem_type, "p");
+ gcc_jit_param *q =
+ gcc_jit_context_new_param (ctxt, NULL, elem_type, "q");
+ gcc_jit_param *r =
+ gcc_jit_context_new_param (ctxt, NULL, elem_type, "r");
+ gcc_jit_param *s =
+ gcc_jit_context_new_param (ctxt, NULL, elem_type, "s");
+
+ gcc_jit_type *return_type =
+ gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_VOID);
+
+ gcc_jit_param *params[6] = {dst, lhs, p, q, r, s};
+ gcc_jit_function *func =
+ gcc_jit_context_new_function (ctxt, NULL,
+ GCC_JIT_FUNCTION_EXPORTED,
+ return_type,
+ fnname,
+ 6, params, 0);
+ gcc_jit_block *initial =
+ gcc_jit_function_new_block (func, "initial");
+
+ /* V pqrs; */
+ gcc_jit_lvalue *pqrs
+ = gcc_jit_function_new_local (func, NULL,
+ vec_type, "pqrs");
+
+ /* pqrs = {p, q, r, s}; */
+ gcc_jit_rvalue *elems[4];
+ elems[0] = gcc_jit_param_as_rvalue (p);
+ elems[1] = gcc_jit_param_as_rvalue (q);
+ elems[2] = gcc_jit_param_as_rvalue (r);
+ elems[3] = gcc_jit_param_as_rvalue (s);
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ pqrs,
+ gcc_jit_context_new_rvalue_from_vector (ctxt, NULL, vec_type, 4, elems));
+
+ /* (*lhs OP pqrs) */
+ gcc_jit_rvalue *op_result =
+ gcc_jit_context_new_binary_op (
+ ctxt, NULL,
+ op,
+ vec_type,
+ gcc_jit_lvalue_as_rvalue (gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (lhs),
+ NULL)),
+ gcc_jit_lvalue_as_rvalue (pqrs));
+ /* *dst = *lhs OP pqrs; */
+ gcc_jit_block_add_assignment (
+ initial, NULL,
+ gcc_jit_rvalue_dereference (gcc_jit_param_as_rvalue (dst), NULL),
+ op_result);
+ gcc_jit_block_end_with_void_return (initial, NULL);
+}
+
+void
+create_code (gcc_jit_context *ctxt, void *user_data)
+{
+ gcc_jit_type *int_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_INT);
+ gcc_jit_type *unsigned_type
+ = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_UNSIGNED_INT);
+ gcc_jit_type *float_type = gcc_jit_context_get_type (ctxt, GCC_JIT_TYPE_FLOAT);
+
+ gcc_jit_type *v4si_type = gcc_jit_type_get_vector (int_type, 4);
+ gcc_jit_type *v4ui_type = gcc_jit_type_get_vector (unsigned_type, 4);
+ gcc_jit_type *v4f_type = gcc_jit_type_get_vector (float_type, 4);
+
+ create_vec_fn (ctxt, "jit_v4si_add",
+ v4si_type, int_type, GCC_JIT_BINARY_OP_PLUS);
+ create_vec_fn (ctxt, "jit_v4si_sub",
+ v4si_type, int_type, GCC_JIT_BINARY_OP_MINUS);
+ create_vec_fn (ctxt, "jit_v4si_mult",
+ v4si_type, int_type, GCC_JIT_BINARY_OP_MULT);
+ create_vec_fn (ctxt, "jit_v4si_div",
+ v4si_type, int_type, GCC_JIT_BINARY_OP_DIVIDE);
+
+ create_vec_fn (ctxt, "jit_v4ui_add",
+ v4ui_type, unsigned_type, GCC_JIT_BINARY_OP_PLUS);
+ create_vec_fn (ctxt, "jit_v4ui_sub",
+ v4ui_type, unsigned_type, GCC_JIT_BINARY_OP_MINUS);
+ create_vec_fn (ctxt, "jit_v4ui_mult",
+ v4ui_type, unsigned_type, GCC_JIT_BINARY_OP_MULT);
+ create_vec_fn (ctxt, "jit_v4ui_div",
+ v4ui_type, unsigned_type, GCC_JIT_BINARY_OP_DIVIDE);
+
+ create_vec_fn (ctxt, "jit_v4f_add",
+ v4f_type, float_type, GCC_JIT_BINARY_OP_PLUS);
+ create_vec_fn (ctxt, "jit_v4f_sub",
+ v4f_type, float_type, GCC_JIT_BINARY_OP_MINUS);
+ create_vec_fn (ctxt, "jit_v4f_mult",
+ v4f_type, float_type, GCC_JIT_BINARY_OP_MULT);
+ create_vec_fn (ctxt, "jit_v4f_div",
+ v4f_type, float_type, GCC_JIT_BINARY_OP_DIVIDE);
+}
+
+template <typename V>
+void
+check_add (const V &a, const V &b, const V &c)
+{
+ for (int i = 0; i < 4; i++)
+ CHECK_VALUE (c[i], a[i] + b[i]);
+}
+
+template <typename V>
+void
+check_sub (const V &a, const V &b, const V &c)
+{
+ for (int i = 0; i < 4; i++)
+ CHECK_VALUE (c[i], a[i] - b[i]);
+}
+
+template <typename V>
+void
+check_mult (const V &a, const V &b, const V &c)
+{
+ for (int i = 0; i < 4; i++)
+ CHECK_VALUE (c[i], a[i] * b[i]);
+}
+
+template <typename V>
+void
+check_div (const V &a, const V &b, const V &c)
+{
+ for (int i = 0; i < 4; i++)
+ CHECK_VALUE (c[i], a[i] / b[i]);
+}
+
+template <typename V, typename E>
+void
+verify_vec_code (gcc_jit_context *ctxt, gcc_jit_result *result,
+ const char *fnname,
+ void (*check_cb) (const V &a, const V &b, const V &c))
+{
+ typedef void (*binop_type) (const V *a, V *b, E p, E q, E r, E s);
+ CHECK_NON_NULL (result);
+ binop_type fn =
+ (binop_type)gcc_jit_result_get_code (result, fnname);
+ CHECK_NON_NULL (fn);
+
+ V dst, lhs, pqrs;
+
+ /* Init. */
+ for (int i = 0; i < 4; i++)
+ {
+ lhs[i] = i + 5;
+ pqrs[i] = (i + 4) * 3;
+ }
+
+ /* Run jit-compiled code and verify result. */
+ fn (&dst, &lhs, pqrs[0], pqrs[1], pqrs[2], pqrs[3]);
+ check_cb (lhs, pqrs, dst);
+}
+
+void
+verify_code (gcc_jit_context *ctxt, gcc_jit_result *result)
+{
+ verify_vec_code<v4si, int> (ctxt, result, "jit_v4si_add", check_add);
+ verify_vec_code<v4si, int> (ctxt, result, "jit_v4si_sub", check_sub);
+ verify_vec_code<v4si, int> (ctxt, result, "jit_v4si_mult", check_mult);
+ verify_vec_code<v4si, int> (ctxt, result, "jit_v4si_div", check_div);
+
+ verify_vec_code<v4ui, unsigned int> (ctxt, result, "jit_v4ui_add", check_add);
+ verify_vec_code<v4ui, unsigned int> (ctxt, result, "jit_v4ui_sub", check_sub);
+ verify_vec_code<v4ui, unsigned int> (ctxt, result, "jit_v4ui_mult", check_mult);
+ verify_vec_code<v4ui, unsigned int> (ctxt, result, "jit_v4ui_div", check_div);
+
+ verify_vec_code<v4f, float> (ctxt, result, "jit_v4f_add", check_add);
+ verify_vec_code<v4f, float> (ctxt, result, "jit_v4f_sub", check_sub);
+ verify_vec_code<v4f, float> (ctxt, result, "jit_v4f_mult", check_mult);
+ verify_vec_code<v4f, float> (ctxt, result, "jit_v4f_div", check_div);
+}
diff --git a/gcc/testsuite/lib/scanasm.exp b/gcc/testsuite/lib/scanasm.exp
index bab23e8..a66bb28 100644
--- a/gcc/testsuite/lib/scanasm.exp
+++ b/gcc/testsuite/lib/scanasm.exp
@@ -231,6 +231,7 @@ proc scan-assembler-times { args } {
set testcase [testname-for-summary]
set pattern [lindex $args 0]
+ set times [lindex $args 1]
set pp_pattern [make_pattern_printable $pattern]
# This must match the rule in gcc-dg.exp.
@@ -239,7 +240,7 @@ proc scan-assembler-times { args } {
set files [glob -nocomplain $output_file]
if { $files == "" } {
verbose -log "$testcase: output file does not exist"
- unresolved "$testcase scan-assembler-times $pp_pattern [lindex $args 1]"
+ unresolved "$testcase scan-assembler-times $pp_pattern $times"
return
}
@@ -247,10 +248,11 @@ proc scan-assembler-times { args } {
set text [read $fd]
close $fd
- if { [llength [regexp -inline -all -- $pattern $text]] == [lindex $args 1]} {
- pass "$testcase scan-assembler-times $pp_pattern [lindex $args 1]"
+ set result_count [llength [regexp -inline -all -- $pattern $text]]
+ if {$result_count == $times} {
+ pass "$testcase scan-assembler-times $pp_pattern $times"
} else {
- fail "$testcase scan-assembler-times $pp_pattern [lindex $args 1]"
+ fail "$testcase scan-assembler-times $pp_pattern $times (found $result_count times)"
}
}
@@ -482,16 +484,16 @@ proc dg-function-on-line { args } {
}
if { [istarget hppa*-*-*] } {
- set pattern [format {\t;[^:]+:%d\n(\t[^\t]+\n)+%s:\n\t.PROC} \
+ set pattern [format {\t;[^:]+:%d(:[0-9]+)?\n(\t[^\t]+\n)+%s:\n\t.PROC} \
$line $symbol]
} elseif { [istarget mips*-*-*] } {
- set pattern [format {\t\.loc [0-9]+ %d 0( [^\n]*)?\n(\t.cfi_startproc[^\t]*\n)*\t\.set\t(no)?mips16\n\t(\.set\t(no)?micromips\n\t)?\.ent\t%s\n\t\.type\t%s, @function\n%s:\n} \
+ set pattern [format {\t\.loc [0-9]+ %d [0-9]+( [^\n]*)?\n(\t.cfi_startproc[^\t]*\n)*\t\.set\t(no)?mips16\n\t(\.set\t(no)?micromips\n\t)?\.ent\t%s\n\t\.type\t%s, @function\n%s:\n} \
$line $symbol $symbol $symbol]
} elseif { [istarget microblaze*-*-*] } {
- set pattern [format {:%d\n\$.*:\n\t\.ent\t%s\n\t\.type\t%s, @function\n%s:\n} \
+ set pattern [format {:%d(:[0-9]+)?\n\$.*:\n\t\.ent\t%s\n\t\.type\t%s, @function\n%s:\n} \
$line $symbol $symbol $symbol]
} else {
- set pattern [format {%s:[^\t]*(\t.(fnstart|frame|mask|file)[^\t]*)*\t[^:]+:%d\n} \
+ set pattern [format {%s:[^\t]*(\t.(fnstart|frame|mask|file)[^\t]*)*\t[^:]+:%d(:[0-9]+)?\n} \
$symbol $line]
}
diff --git a/gcc/testsuite/lib/scandump.exp b/gcc/testsuite/lib/scandump.exp
index 2e6eebf..4a64ac6 100644
--- a/gcc/testsuite/lib/scandump.exp
+++ b/gcc/testsuite/lib/scandump.exp
@@ -86,6 +86,7 @@ proc scan-dump-times { args } {
}
set testcase [testname-for-summary]
+ set times [lindex $args 2]
set suf [dump-suffix [lindex $args 3]]
set printable_pattern [make_pattern_printable [lindex $args 1]]
set testname "$testcase scan-[lindex $args 0]-dump-times $suf \"$printable_pattern\" [lindex $args 2]"
@@ -101,10 +102,11 @@ proc scan-dump-times { args } {
set text [read $fd]
close $fd
- if { [llength [regexp -inline -all -- [lindex $args 1] $text]] == [lindex $args 2]} {
+ set result_count [llength [regexp -inline -all -- [lindex $args 1] $text]]
+ if {$result_count == $times} {
pass "$testname"
} else {
- fail "$testname"
+ fail "$testname (found $result_count times)"
}
}
diff --git a/gcc/testsuite/lib/target-supports-dg.exp b/gcc/testsuite/lib/target-supports-dg.exp
index d50d8b0..6080421f 100644
--- a/gcc/testsuite/lib/target-supports-dg.exp
+++ b/gcc/testsuite/lib/target-supports-dg.exp
@@ -180,6 +180,21 @@ proc dg-require-iconv { args } {
}
}
+# If this target does not have sufficient stack size, skip this test.
+
+proc dg-require-stack-size { args } {
+ if { ![is-effective-target stack_size] } {
+ return
+ }
+
+ set stack_size [dg-effective-target-value stack_size]
+ set required [expr [lindex $args 1]]
+ if { $stack_size < $required } {
+ upvar dg-do-what dg-do-what
+ set dg-do-what [list [lindex ${dg-do-what} 0] "N" "P"]
+ }
+}
+
# If this target does not support named sections skip this test.
proc dg-require-named-sections { args } {
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 6ea7122..56ac221 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -437,10 +437,14 @@ proc check_effective_target_alias { } {
proc check_ifunc_available { } {
return [check_no_compiler_messages ifunc_available object {
#ifdef __cplusplus
- extern "C"
+ extern "C" {
+ #endif
+ typedef void F (void);
+ F* g (void) {}
+ void f () __attribute__ ((ifunc ("g")));
+ #ifdef __cplusplus
+ }
#endif
- void g() {}
- void f() __attribute__((ifunc("g")));
}]
}
@@ -544,7 +548,8 @@ proc check_effective_target_keeps_null_pointer_checks { } {
if [target_info exists keeps_null_pointer_checks] {
return 1
}
- if { [istarget avr-*-*] } {
+ if { [istarget avr-*-*]
+ || [istarget msp430-*-*] } {
return 1;
}
return 0
@@ -1460,6 +1465,20 @@ proc check_effective_target_fortran_real_16 { } {
}]
}
+# Return 1 if the target supports Fortran real kind 10,
+# 0 otherwise. Contrary to check_effective_target_fortran_large_real
+# this checks for real(10) only.
+#
+# When the target name changes, replace the cached result.
+
+proc check_effective_target_fortran_real_10 { } {
+ return [check_no_compiler_messages fortran_real_10 executable {
+ ! Fortran
+ real(kind=10) :: x
+ x = cos (x)
+ end
+ }]
+}
# Return 1 if the target supports Fortran's IEEE modules,
# 0 otherwise.
@@ -3062,7 +3081,9 @@ proc check_effective_target_vect_int { } {
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_loongson]
- || [et-is-effective-target mips_msa])) } {
+ || [et-is-effective-target mips_msa]))
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_int_saved($et_index) 1
}
}
@@ -3099,6 +3120,68 @@ proc check_effective_target_vect_intfloat_cvt { } {
return $et_vect_intfloat_cvt_saved($et_index)
}
+# Return 1 if the target supports signed double->int conversion
+#
+
+proc check_effective_target_vect_doubleint_cvt { } {
+ global et_vect_doubleint_cvt_saved
+ global et_index
+
+ if [info exists et_vect_doubleint_cvt_saved($et_index)] {
+ verbose "check_effective_target_vect_doubleint_cvt: using cached result" 2
+ } else {
+ set et_vect_doubleint_cvt_saved($et_index) 0
+ if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && [check_no_compiler_messages vect_doubleint_cvt assembly {
+ #ifdef __tune_atom__
+ # error No double vectorizer support.
+ #endif
+ }])
+ || [istarget aarch64*-*-*]
+ || [istarget spu-*-*]
+ || ([istarget powerpc*-*-*] && [check_vsx_hw_available])
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa]) } {
+ set et_vect_doubleint_cvt_saved($et_index) 1
+ }
+ }
+
+ verbose "check_effective_target_vect_doubleint_cvt:\
+ returning $et_vect_doubleint_cvt_saved($et_index)" 2
+ return $et_vect_doubleint_cvt_saved($et_index)
+}
+
+# Return 1 if the target supports signed int->double conversion
+#
+
+proc check_effective_target_vect_intdouble_cvt { } {
+ global et_vect_intdouble_cvt_saved
+ global et_index
+
+ if [info exists et_vect_intdouble_cvt_saved($et_index)] {
+ verbose "check_effective_target_vect_intdouble_cvt: using cached result" 2
+ } else {
+ set et_vect_intdouble_cvt_saved($et_index) 0
+ if { (([istarget i?86-*-*] || [istarget x86_64-*-*])
+ && [check_no_compiler_messages vect_intdouble_cvt assembly {
+ #ifdef __tune_atom__
+ # error No double vectorizer support.
+ #endif
+ }])
+ || [istarget aarch64*-*-*]
+ || [istarget spu-*-*]
+ || ([istarget powerpc*-*-*] && [check_vsx_hw_available])
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa]) } {
+ set et_vect_intdouble_cvt_saved($et_index) 1
+ }
+ }
+
+ verbose "check_effective_target_vect_intdouble_cvt:\
+ returning $et_vect_intdouble_cvt_saved($et_index)" 2
+ return $et_vect_intdouble_cvt_saved($et_index)
+}
+
#Return 1 if we're supporting __int128 for target, 0 otherwise.
proc check_effective_target_int128 { } {
@@ -3195,6 +3278,28 @@ proc check_effective_target_vect_floatuint_cvt { } {
return $et_vect_floatuint_cvt_saved($et_index)
}
+# Return 1 if peeling for alignment might be profitable on the target
+#
+
+proc check_effective_target_vect_peeling_profitable { } {
+ global et_vect_peeling_profitable_saved
+ global et_index
+
+ if [info exists et_vect_peeling_profitable_saved($et_index)] {
+ verbose "check_effective_target_vect_peeling_profitable: using cached result" 2
+ } else {
+ set et_vect_peeling_profitable_saved($et_index) 1
+ if { ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
+ set et_vect_peeling_profitable_saved($et_index) 0
+ }
+ }
+
+ verbose "check_effective_target_vect_peeling_profitable:\
+ returning $et_vect_peeling_profitable_saved($et_index)" 2
+ return $et_vect_peeling_profitable_saved($et_index)
+}
+
# Return 1 if the target supports #pragma omp declare simd, 0 otherwise.
#
# This won't change for different subtargets so cache the result.
@@ -5065,7 +5170,9 @@ proc check_effective_target_vect_shift { } {
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_msa]
- || [et-is-effective-target mips_loongson])) } {
+ || [et-is-effective-target mips_loongson]))
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_shift_saved($et_index) 1
}
}
@@ -5083,7 +5190,9 @@ proc check_effective_target_whole_vector_shift { } {
|| ([is-effective-target arm_neon]
&& [check_effective_target_arm_little_endian])
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_loongson]) } {
+ && [et-is-effective-target mips_loongson])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set answer 1
} else {
set answer 0
@@ -5129,7 +5238,9 @@ proc check_effective_target_vect_shift_char { } {
&& ![istarget powerpc-*-linux*paired*])
|| [is-effective-target arm_neon]
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_shift_char_saved($et_index) 1
}
}
@@ -5152,7 +5263,9 @@ proc check_effective_target_vect_long { } {
|| ([istarget sparc*-*-*] && [check_effective_target_ilp32])
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set answer 1
} else {
set answer 0
@@ -5183,7 +5296,9 @@ proc check_effective_target_vect_float { } {
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
- || [is-effective-target arm_neon] } {
+ || [is-effective-target arm_neon]
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vxe]) } {
set et_vect_float_saved($et_index) 1
}
}
@@ -5215,7 +5330,9 @@ proc check_effective_target_vect_double { } {
|| [istarget spu-*-*]
|| ([istarget powerpc*-*-*] && [check_vsx_hw_available])
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_double_saved($et_index) 1
}
}
@@ -5239,7 +5356,9 @@ proc check_effective_target_vect_long_long { } {
set et_vect_long_long_saved($et_index) 0
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_long_long_saved($et_index) 1
}
}
@@ -5339,7 +5458,9 @@ proc check_effective_target_vect_perm { } {
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mpaired_single]
- || [et-is-effective-target mips_msa])) } {
+ || [et-is-effective-target mips_msa]))
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_perm_saved($et_index) 1
}
}
@@ -5368,7 +5489,9 @@ proc check_effective_target_vect_perm_byte { } {
|| [istarget powerpc*-*-*]
|| [istarget spu-*-*]
|| ([istarget mips-*.*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_perm_byte_saved($et_index) 1
}
}
@@ -5397,7 +5520,9 @@ proc check_effective_target_vect_perm_short { } {
|| [istarget powerpc*-*-*]
|| [istarget spu-*-*]
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_perm_short_saved($et_index) 1
}
}
@@ -5556,7 +5681,9 @@ proc check_effective_target_vect_widen_mult_qi_to_hi { } {
}
if { [istarget powerpc*-*-*]
|| [istarget aarch64*-*-*]
- || [is-effective-target arm_neon] } {
+ || [is-effective-target arm_neon]
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_widen_mult_qi_to_hi_saved($et_index) 1
}
}
@@ -5593,7 +5720,9 @@ proc check_effective_target_vect_widen_mult_hi_to_si { } {
|| [istarget ia64-*-*]
|| [istarget aarch64*-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
- || [is-effective-target arm_neon] } {
+ || [is-effective-target arm_neon]
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_widen_mult_hi_to_si_saved($et_index) 1
}
}
@@ -5618,7 +5747,9 @@ proc check_effective_target_vect_widen_mult_qi_to_hi_pattern { } {
set et_vect_widen_mult_qi_to_hi_pattern_saved($et_index) 0
if { [istarget powerpc*-*-*]
|| ([is-effective-target arm_neon]
- && [check_effective_target_arm_little_endian]) } {
+ && [check_effective_target_arm_little_endian])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_widen_mult_qi_to_hi_pattern_saved($et_index) 1
}
}
@@ -5646,7 +5777,9 @@ proc check_effective_target_vect_widen_mult_hi_to_si_pattern { } {
|| [istarget ia64-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([is-effective-target arm_neon]
- && [check_effective_target_arm_little_endian]) } {
+ && [check_effective_target_arm_little_endian])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_widen_mult_hi_to_si_pattern_saved($et_index) 1
}
}
@@ -5670,7 +5803,9 @@ proc check_effective_target_vect_widen_mult_si_to_di_pattern { } {
} else {
set et_vect_widen_mult_si_to_di_pattern_saved($et_index) 0
if {[istarget ia64-*-*]
- || [istarget i?86-*-*] || [istarget x86_64-*-*] } {
+ || [istarget i?86-*-*] || [istarget x86_64-*-*]
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_widen_mult_si_to_di_pattern_saved($et_index) 1
}
}
@@ -5843,7 +5978,9 @@ proc check_effective_target_vect_pack_trunc { } {
|| ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok]
&& [check_effective_target_arm_little_endian])
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_pack_trunc_saved($et_index) 1
}
}
@@ -5873,7 +6010,9 @@ proc check_effective_target_vect_unpack { } {
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget arm*-*-*] && [check_effective_target_arm_neon_ok]
- && [check_effective_target_arm_little_endian]) } {
+ && [check_effective_target_arm_little_endian])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_unpack_saved($et_index) 1
}
}
@@ -5943,11 +6082,13 @@ proc check_effective_target_vect_hw_misalign { } {
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| ([istarget powerpc*-*-*] && [check_p8vector_hw_available])
|| [istarget aarch64*-*-*]
- || ([istarget mips*-*-*] && [et-is-effective-target mips_msa]) } {
+ || ([istarget mips*-*-*] && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_hw_misalign_saved($et_index) 1
}
if { [istarget arm*-*-*] } {
- set et_vect_hw_misalign_saved($et_index) [check_effective_target_arm_vect_no_misalign]
+ set et_vect_hw_misalign_saved($et_index) [expr ![check_effective_target_arm_vect_no_misalign]]
}
}
verbose "check_effective_target_vect_hw_misalign:\
@@ -6117,7 +6258,9 @@ proc check_effective_target_vect_condition { } {
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
|| ([istarget arm*-*-*]
- && [check_effective_target_arm_neon_ok]) } {
+ && [check_effective_target_arm_neon_ok])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_cond_saved($et_index) 1
}
}
@@ -6142,7 +6285,9 @@ proc check_effective_target_vect_cond_mixed { } {
|| [istarget aarch64*-*-*]
|| [istarget powerpc*-*-*]
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_cond_mixed_saved($et_index) 1
}
}
@@ -6168,7 +6313,9 @@ proc check_effective_target_vect_char_mult { } {
|| [check_effective_target_arm32]
|| [check_effective_target_powerpc_altivec]
|| ([istarget mips*-*-*]
- && [et-is-effective-target mips_msa]) } {
+ && [et-is-effective-target mips_msa])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_char_mult_saved($et_index) 1
}
}
@@ -6196,7 +6343,9 @@ proc check_effective_target_vect_short_mult { } {
|| [check_effective_target_arm32]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_msa]
- || [et-is-effective-target mips_loongson])) } {
+ || [et-is-effective-target mips_loongson]))
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_short_mult_saved($et_index) 1
}
}
@@ -6223,7 +6372,9 @@ proc check_effective_target_vect_int_mult { } {
|| [istarget aarch64*-*-*]
|| ([istarget mips*-*-*]
&& [et-is-effective-target mips_msa])
- || [check_effective_target_arm32] } {
+ || [check_effective_target_arm32]
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_int_mult_saved($et_index) 1
}
}
@@ -6233,6 +6384,30 @@ proc check_effective_target_vect_int_mult { } {
return $et_vect_int_mult_saved($et_index)
}
+# Return 1 if the target supports 64 bit hardware vector
+# multiplication of long operands with a long result, 0 otherwise.
+#
+# This can change for different subtargets so do not cache the result.
+
+proc check_effective_target_vect_long_mult { } {
+ if { [istarget i?86-*-*] || [istarget x86_64-*-*]
+ || (([istarget powerpc*-*-*]
+ && ![istarget powerpc-*-linux*paired*])
+ && [check_effective_target_ilp32])
+ || [is-effective-target arm_neon]
+ || ([istarget sparc*-*-*] && [check_effective_target_ilp32])
+ || [istarget aarch64*-*-*]
+ || ([istarget mips*-*-*]
+ && [et-is-effective-target mips_msa]) } {
+ set answer 1
+ } else {
+ set answer 0
+ }
+
+ verbose "check_effective_target_vect_long_mult: returning $answer" 2
+ return $answer
+}
+
# Return 1 if the target supports vector even/odd elements extraction, 0 otherwise.
proc check_effective_target_vect_extract_even_odd { } {
@@ -6252,7 +6427,9 @@ proc check_effective_target_vect_extract_even_odd { } {
|| [istarget spu-*-*]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mips_msa]
- || [et-is-effective-target mpaired_single])) } {
+ || [et-is-effective-target mpaired_single]))
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_extract_even_odd_saved($et_index) 1
}
}
@@ -6280,7 +6457,9 @@ proc check_effective_target_vect_interleave { } {
|| [istarget spu-*-*]
|| ([istarget mips*-*-*]
&& ([et-is-effective-target mpaired_single]
- || [et-is-effective-target mips_msa])) } {
+ || [et-is-effective-target mips_msa]))
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_interleave_saved($et_index) 1
}
}
@@ -6397,7 +6576,9 @@ proc check_effective_target_sqrt_insn { } {
if { [istarget i?86-*-*] || [istarget x86_64-*-*]
|| [istarget powerpc*-*-*]
|| [istarget aarch64*-*-*]
- || ([istarget arm*-*-*] && [check_effective_target_arm_vfp_ok]) } {
+ || ([istarget arm*-*-*] && [check_effective_target_arm_vfp_ok])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_sqrt_insn_saved 1
}
}
@@ -6418,7 +6599,9 @@ proc check_effective_target_vect_call_sqrtf { } {
set et_vect_call_sqrtf_saved($et_index) 0
if { [istarget aarch64*-*-*]
|| [istarget i?86-*-*] || [istarget x86_64-*-*]
- || ([istarget powerpc*-*-*] && [check_vsx_hw_available]) } {
+ || ([istarget powerpc*-*-*] && [check_vsx_hw_available])
+ || ([istarget s390*-*-*]
+ && [check_effective_target_s390_vx]) } {
set et_vect_call_sqrtf_saved($et_index) 1
}
}
@@ -7489,6 +7672,19 @@ proc check_effective_target_vect_sizes_32B_16B { } {
}
}
+# Return true if 16- and 8-bytes vectors are available.
+
+proc check_effective_target_vect_sizes_16B_8B { } {
+ if { [check_avx_available]
+ || [is-effective-target arm_neon]
+ || [istarget aarch64*-*-*] } {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+
# Return true if 128-bits vectors are preferred even if 256-bits vectors
# are available.
@@ -8023,6 +8219,25 @@ proc check_vect_support_and_set_flags { } {
}
} elseif [istarget "aarch64*-*-*"] {
set dg-do-what-default run
+ } elseif [istarget s390*-*-*] {
+ # The S/390 backend set a default of 2 for that value.
+ # Override it to have the same situation as with other
+ # targets.
+ lappend DEFAULT_VECTCFLAGS "--param" "min-vect-loop-bound=1"
+ lappend DEFAULT_VECTCFLAGS "--param" "max-unrolled-insns=200"
+ lappend DEFAULT_VECTCFLAGS "--param" "max-unroll-times=8"
+ lappend DEFAULT_VECTCFLAGS "--param" "max-completely-peeled-insns=200"
+ lappend DEFAULT_VECTCFLAGS "--param" "max-completely-peel-times=16"
+ if [check_effective_target_s390_vxe] {
+ lappend DEFAULT_VECTCFLAGS "-march=z14" "-mzarch"
+ set dg-do-what-default run
+ } elseif [check_effective_target_s390_vx] {
+ lappend DEFAULT_VECTCFLAGS "-march=z13" "-mzarch"
+ set dg-do-what-default run
+ } else {
+ lappend DEFAULT_VECTCFLAGS "-march=z14" "-mzarch"
+ set dg-do-what-default compile
+ }
} else {
return 0
}
@@ -8449,7 +8664,7 @@ proc check_effective_target_s390_vx { } {
} "-march=z13 -mzarch" ]
}
-# Same as above but for the arch12 vector enhancement facility. Test
+# Same as above but for the z14 vector enhancement facility. Test
# is performed with the vector nand instruction.
proc check_effective_target_s390_vxe { } {
if ![istarget s390*-*-*] then {
@@ -8462,7 +8677,7 @@ proc check_effective_target_s390_vxe { } {
asm ("vnn %%v24, %%v26, %%v28" : : : "v24", "v26", "v28");
return 0;
}
- } "-march=arch12 -mzarch" ]
+ } "-march=z14 -mzarch" ]
}
#For versions of ARM architectures that have hardware div insn,
@@ -8621,3 +8836,103 @@ proc check_effective_target_autoincdec { } {
}
return 0
}
+
+# Return 1 if the target has support for stack probing designed
+# to avoid stack-clash style attacks.
+#
+# This is used to restrict the stack-clash mitigation tests to
+# just those targets that have been explicitly supported.
+#
+# In addition to the prologue work on those targets, each target's
+# properties should be described in the functions below so that
+# tests do not become a mess of unreadable target conditions.
+#
+proc check_effective_target_supports_stack_clash_protection { } {
+
+ # Temporary until the target bits are fully ACK'd.
+# if { [istarget aarch*-*-*] } {
+# return 1
+# }
+
+ if { [istarget x86_64-*-*] || [istarget i?86-*-*]
+ || [istarget powerpc*-*-*] || [istarget rs6000*-*-*]
+ || [istarget s390*-*-*] } {
+ return 1
+ }
+ return 0
+}
+
+# Return 1 if the target creates a frame pointer for non-leaf functions
+# Note we ignore cases where we apply tail call optimization here.
+proc check_effective_target_frame_pointer_for_non_leaf { } {
+ if { [istarget aarch*-*-*] } {
+ return 1
+ }
+
+ # Solaris/x86 defaults to -fno-omit-frame-pointer.
+ if { [istarget i?86-*-solaris*] || [istarget x86_64-*-solaris*] } {
+ return 1
+ }
+
+ return 0
+}
+
+# Return 1 if the target's calling sequence or its ABI
+# create implicit stack probes at or prior to function entry.
+proc check_effective_target_caller_implicit_probes { } {
+
+ # On x86/x86_64 the call instruction itself pushes the return
+ # address onto the stack. That is an implicit probe of *sp.
+ if { [istarget x86_64-*-*] || [istarget i?86-*-*] } {
+ return 1
+ }
+
+ # On PPC, the ABI mandates that the address of the outer
+ # frame be stored at *sp. Thus each allocation of stack
+ # space is itself an implicit probe of *sp.
+ if { [istarget powerpc*-*-*] || [istarget rs6000*-*-*] } {
+ return 1
+ }
+
+ # s390's ABI has a register save area allocated by the
+ # caller for use by the callee. The mere existence does
+ # not constitute a probe by the caller, but when the slots
+ # used by the callee those stores are implicit probes.
+ if { [istarget s390*-*-*] } {
+ return 1
+ }
+
+ # Not strictly true on aarch64, but we have agreed that we will
+ # consider any function that pushes SP more than 3kbytes into
+ # the guard page as broken. This essentially means that we can
+ # consider the aarch64 as having a caller implicit probe at
+ # *(sp + 1k).
+ if { [istarget aarch64*-*-*] } {
+ return 1;
+ }
+
+ return 0
+}
+
+# Targets that potentially realign the stack pointer often cause residual
+# stack allocations and make it difficult to elimination loops or residual
+# allocations for dynamic stack allocations
+proc check_effective_target_callee_realigns_stack { } {
+ if { [istarget x86_64-*-*] || [istarget i?86-*-*] } {
+ return 1
+ }
+ return 0
+}
+
+# Return 1 if CET instructions can be compiled.
+proc check_effective_target_cet { } {
+ if { !([istarget i?86-*-*] || [istarget x86_64-*-*]) } {
+ return 0
+ }
+ return [check_no_compiler_messages cet object {
+ void foo (void)
+ {
+ asm ("setssbsy");
+ }
+ } "-O2" ]
+}
diff --git a/gcc/testsuite/obj-c++.dg/exceptions-6.mm b/gcc/testsuite/obj-c++.dg/exceptions-6.mm
index 58882fe..6f6ba78 100644
--- a/gcc/testsuite/obj-c++.dg/exceptions-6.mm
+++ b/gcc/testsuite/obj-c++.dg/exceptions-6.mm
@@ -11,15 +11,15 @@ void test (id object)
@throw object; /* Ok */
@throw; /* { dg-error ".@throw. .rethrow. used outside of a @catch block" } */
@throw (object); /* Ok. */
- @throw (id)0
-} /* { dg-error "expected" } */
+ @throw (id)0 /* { dg-error "expected" } */
+}
void test2 (id object)
{
@throw object); /* { dg-error "expected" } */
@throw (...); /* { dg-error "expected" } */
@throw (); /* { dg-error "expected" } */
- @throw
+ @throw /* { dg-error "expected" } */
} /* { dg-error "expected" } */
void test3 (id object1, id object2)
diff --git a/gcc/testsuite/obj-c++.dg/pr48187.mm b/gcc/testsuite/obj-c++.dg/pr48187.mm
index 750710b..99677a5 100644
--- a/gcc/testsuite/obj-c++.dg/pr48187.mm
+++ b/gcc/testsuite/obj-c++.dg/pr48187.mm
@@ -1,19 +1,19 @@
/* { dg-do compile } */
@interface A
-{
+{ /* { dg-error "xpected" } */
] /* { dg-error "xpected" } */
}
@end
@interface B
-{
+{ /* { dg-error "xpected" } */
]; /* { dg-error "xpected" } */
}
@end
@interface C
-{
+{ /* { dg-error "xpected" } */
]; /* { dg-error "xpected" } */
int x;
}
@@ -21,7 +21,7 @@
@interface D
{
- (
+ ( /* { dg-error "xpected" } */
} /* { dg-error "xpected" } */
@end
diff --git a/gcc/testsuite/objc.dg/exceptions-6.m b/gcc/testsuite/objc.dg/exceptions-6.m
index 58882fe..74be98d 100644
--- a/gcc/testsuite/objc.dg/exceptions-6.m
+++ b/gcc/testsuite/objc.dg/exceptions-6.m
@@ -11,8 +11,8 @@ void test (id object)
@throw object; /* Ok */
@throw; /* { dg-error ".@throw. .rethrow. used outside of a @catch block" } */
@throw (object); /* Ok. */
- @throw (id)0
-} /* { dg-error "expected" } */
+ @throw (id)0 /* { dg-error "expected" } */
+}
void test2 (id object)
{
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 7d2b8ff..8c45e1d 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -239,7 +239,7 @@ announce_function (tree decl)
}
}
-/* Initialize local_tick with a random number or -1 if
+/* Initialize local_tick with the time of day, or -1 if
flag_random_seed is set. */
static void
@@ -247,19 +247,6 @@ init_local_tick (void)
{
if (!flag_random_seed)
{
- /* Try urandom first. Time of day is too likely to collide.
- In case of any error we just use the local tick. */
-
- int fd = open ("/dev/urandom", O_RDONLY);
- if (fd >= 0)
- {
- if (read (fd, &random_seed, sizeof (random_seed))
- != sizeof (random_seed))
- random_seed = 0;
- close (fd);
- }
-
- /* Now get the tick anyways */
#ifdef HAVE_GETTIMEOFDAY
{
struct timeval tv;
@@ -280,34 +267,33 @@ init_local_tick (void)
local_tick = -1;
}
-/* Set up a default flag_random_seed and local_tick, unless the user
- already specified one. Must be called after init_local_tick. */
-
-static void
-init_random_seed (void)
-{
- if (!random_seed)
- random_seed = local_tick ^ getpid (); /* Old racey fallback method */
-}
-
/* Obtain the random_seed. Unless NOINIT, initialize it if
it's not provided in the command line. */
HOST_WIDE_INT
get_random_seed (bool noinit)
{
- if (!flag_random_seed && !noinit)
- init_random_seed ();
+ if (!random_seed && !noinit)
+ {
+ int fd = open ("/dev/urandom", O_RDONLY);
+ if (fd >= 0)
+ {
+ if (read (fd, &random_seed, sizeof (random_seed))
+ != sizeof (random_seed))
+ random_seed = 0;
+ close (fd);
+ }
+ if (!random_seed)
+ random_seed = local_tick ^ getpid ();
+ }
return random_seed;
}
-/* Modify the random_seed string to VAL. Return its previous
- value. */
+/* Set flag_random_seed to VAL, and if non-null, reinitialize random_seed. */
-const char *
+void
set_random_seed (const char *val)
{
- const char *old = flag_random_seed;
flag_random_seed = val;
if (flag_random_seed)
{
@@ -318,7 +304,6 @@ set_random_seed (const char *val)
if (!(endp > flag_random_seed && *endp == 0))
random_seed = crc32_string (0, flag_random_seed);
}
- return old;
}
/* Handler for fatal signals, such as SIGSEGV. These are transformed
@@ -818,11 +803,6 @@ print_switch_values (print_switch_fn_type print_fn)
int pos = 0;
size_t j;
- /* Fill in the -frandom-seed option, if the user didn't pass it, so
- that it can be printed below. This helps reproducibility. */
- if (!flag_random_seed)
- init_random_seed ();
-
/* Print the options as passed. */
pos = print_single_switch (print_fn, pos,
SWITCH_TYPE_DESCRIPTIVE, _("options passed: "));
@@ -1297,6 +1277,32 @@ process_options (void)
"-floop-parallelize-all)");
#endif
+ if (flag_cf_protection != CF_NONE
+ && !(flag_cf_protection & CF_SET))
+ {
+ if (flag_cf_protection == CF_FULL)
+ {
+ error_at (UNKNOWN_LOCATION,
+ "%<-fcf-protection=full%> is not supported for this "
+ "target");
+ flag_cf_protection = CF_NONE;
+ }
+ if (flag_cf_protection == CF_BRANCH)
+ {
+ error_at (UNKNOWN_LOCATION,
+ "%<-fcf-protection=branch%> is not supported for this "
+ "target");
+ flag_cf_protection = CF_NONE;
+ }
+ if (flag_cf_protection == CF_RETURN)
+ {
+ error_at (UNKNOWN_LOCATION,
+ "%<-fcf-protection=return%> is not supported for this "
+ "target");
+ flag_cf_protection = CF_NONE;
+ }
+ }
+
if (flag_check_pointer_bounds)
{
if (targetm.chkp_bound_mode () == VOIDmode)
@@ -1605,6 +1611,26 @@ process_options (void)
flag_associative_math = 0;
}
+ /* -fstack-clash-protection is not currently supported on targets
+ where the stack grows up. */
+ if (flag_stack_clash_protection && !STACK_GROWS_DOWNWARD)
+ {
+ warning_at (UNKNOWN_LOCATION, 0,
+ "%<-fstack-clash-protection%> is not supported on targets "
+ "where the stack grows from lower to higher addresses");
+ flag_stack_clash_protection = 0;
+ }
+
+ /* We can not support -fstack-check= and -fstack-clash-protection at
+ the same time. */
+ if (flag_stack_check != NO_STACK_CHECK && flag_stack_clash_protection)
+ {
+ warning_at (UNKNOWN_LOCATION, 0,
+ "%<-fstack-check=%> and %<-fstack-clash_protection%> are "
+ "mutually exclusive. Disabling %<-fstack-check=%>");
+ flag_stack_check = NO_STACK_CHECK;
+ }
+
/* With -fcx-limited-range, we do cheap and quick complex arithmetic. */
if (flag_cx_limited_range)
flag_complex_method = 0;
@@ -2186,7 +2212,7 @@ toplev::main (int argc, char **argv)
{
gcc_assert (global_dc->edit_context_ptr);
- pretty_printer (pp);
+ pretty_printer pp;
pp_show_color (&pp) = pp_show_color (global_dc->printer);
global_dc->edit_context_ptr->print_diff (&pp, true);
pp_flush (&pp);
diff --git a/gcc/toplev.h b/gcc/toplev.h
index 2f6b587..aed806e 100644
--- a/gcc/toplev.h
+++ b/gcc/toplev.h
@@ -91,7 +91,7 @@ extern bool set_src_pwd (const char *);
/* Functions used to manipulate the random seed. */
extern HOST_WIDE_INT get_random_seed (bool);
-extern const char *set_random_seed (const char *);
+extern void set_random_seed (const char *);
extern void initialize_rtl (void);
diff --git a/gcc/tracer.c b/gcc/tracer.c
index dd071c1..f3e401b 100644
--- a/gcc/tracer.c
+++ b/gcc/tracer.c
@@ -132,9 +132,9 @@ count_insns (basic_block bb)
static bool
better_p (const_edge e1, const_edge e2)
{
- if (e1->count.initialized_p () && e2->count.initialized_p ()
- && !(e1->count == e2->count))
- return e1->count > e2->count;
+ if (e1->count ().initialized_p () && e2->count ().initialized_p ()
+ && ((e1->count () > e2->count ()) || (e1->count () < e2->count ())))
+ return e1->count () > e2->count ();
if (EDGE_FREQUENCY (e1) != EDGE_FREQUENCY (e2))
return EDGE_FREQUENCY (e1) > EDGE_FREQUENCY (e2);
/* This is needed to avoid changes in the decision after
diff --git a/gcc/trans-mem.c b/gcc/trans-mem.c
index 40b5368..2c701f0 100644
--- a/gcc/trans-mem.c
+++ b/gcc/trans-mem.c
@@ -2938,10 +2938,8 @@ expand_transaction (struct tm_region *region, void *data ATTRIBUTE_UNUSED)
ei->probability = profile_probability::always ();
et->probability = profile_probability::likely ();
ef->probability = profile_probability::unlikely ();
- et->count = test_bb->count.apply_probability (et->probability);
- ef->count = test_bb->count.apply_probability (ef->probability);
- code_bb->count = et->count;
+ code_bb->count = et->count ();
code_bb->frequency = EDGE_FREQUENCY (et);
transaction_bb = join_bb;
@@ -2975,15 +2973,11 @@ expand_transaction (struct tm_region *region, void *data ATTRIBUTE_UNUSED)
redirect_edge_pred (fallthru_edge, test_bb);
fallthru_edge->flags = EDGE_FALSE_VALUE;
fallthru_edge->probability = profile_probability::very_likely ();
- fallthru_edge->count = test_bb->count.apply_probability
- (fallthru_edge->probability);
// Abort/over edge.
redirect_edge_pred (abort_edge, test_bb);
abort_edge->flags = EDGE_TRUE_VALUE;
abort_edge->probability = profile_probability::unlikely ();
- abort_edge->count = test_bb->count.apply_probability
- (abort_edge->probability);
transaction_bb = test_bb;
}
@@ -3011,7 +3005,7 @@ expand_transaction (struct tm_region *region, void *data ATTRIBUTE_UNUSED)
// out of the fallthru edge.
edge e = make_edge (transaction_bb, test_bb, fallthru_edge->flags);
e->probability = fallthru_edge->probability;
- test_bb->count = e->count = fallthru_edge->count;
+ test_bb->count = fallthru_edge->count ();
test_bb->frequency = EDGE_FREQUENCY (e);
// Now update the edges to the inst/uninist implementations.
@@ -3022,14 +3016,10 @@ expand_transaction (struct tm_region *region, void *data ATTRIBUTE_UNUSED)
redirect_edge_pred (inst_edge, test_bb);
inst_edge->flags = EDGE_FALSE_VALUE;
inst_edge->probability = profile_probability::even ();
- inst_edge->count
- = test_bb->count.apply_probability (inst_edge->probability);
redirect_edge_pred (uninst_edge, test_bb);
uninst_edge->flags = EDGE_TRUE_VALUE;
uninst_edge->probability = profile_probability::even ();
- uninst_edge->count
- = test_bb->count.apply_probability (uninst_edge->probability);
}
// If we have no previous special cases, and we have PHIs at the beginning
@@ -3214,10 +3204,7 @@ split_bb_make_tm_edge (gimple *stmt, basic_block dest_bb,
}
edge e = make_edge (bb, dest_bb, EDGE_ABNORMAL);
if (e)
- {
- e->probability = profile_probability::guessed_never ();
- e->count = profile_count::guessed_zero ();
- }
+ e->probability = profile_probability::guessed_never ();
// Record the need for the edge for the benefit of the rtl passes.
if (cfun->gimple_df->tm_restart == NULL)
diff --git a/gcc/tree-affine.c b/gcc/tree-affine.c
index f7a5f12..47f56bf 100644
--- a/gcc/tree-affine.c
+++ b/gcc/tree-affine.c
@@ -408,8 +408,8 @@ tree_to_aff_combination (tree expr, tree type, aff_tree *comb)
&& get_range_info (op0, &minv, &maxv) == VR_RANGE)
{
if (icode == PLUS_EXPR)
- op1 = wide_int_to_tree (itype, wi::neg (op1));
- if (wi::geu_p (minv, op1))
+ op1 = wide_int_to_tree (itype, -wi::to_wide (op1));
+ if (wi::geu_p (minv, wi::to_wide (op1)))
{
op0 = fold_convert (otype, op0);
op1 = fold_convert (otype, op1);
diff --git a/gcc/tree-call-cdce.c b/gcc/tree-call-cdce.c
index 1578350..4398772 100644
--- a/gcc/tree-call-cdce.c
+++ b/gcc/tree-call-cdce.c
@@ -913,21 +913,17 @@ shrink_wrap_one_built_in_call_with_conds (gcall *bi_call, vec <gimple *> conds,
gcc_assert (src_bb == nocall_edge->src);
call_edge->probability = profile_probability::very_unlikely ();
- call_edge->count
- = src_bb->count.apply_probability (call_edge->probability);
nocall_edge->probability = profile_probability::always ()
- call_edge->probability;
- nocall_edge->count = src_bb->count - call_edge->count;
unsigned int call_frequency
= call_edge->probability.apply (src_bb->frequency);
- bi_call_bb->count += call_edge->count;
+ bi_call_bb->count += call_edge->count ();
bi_call_bb->frequency += call_frequency;
if (nocall_edge->dest != join_tgt_bb)
{
- nocall_edge->dest->count = nocall_edge->count;
nocall_edge->dest->frequency = src_bb->frequency - call_frequency;
}
}
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 99d1f1e..ae1cdb3 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -1062,8 +1062,8 @@ gimple_find_sub_bbs (gimple_seq seq, gimple_stmt_iterator *gsi)
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->preds)
{
- if (e->count.initialized_p ())
- cnt += e->count;
+ if (e->count ().initialized_p ())
+ cnt += e->count ();
else
all = false;
freq += EDGE_FREQUENCY (e);
@@ -1072,8 +1072,6 @@ gimple_find_sub_bbs (gimple_seq seq, gimple_stmt_iterator *gsi)
if (all || profile_status_for_fn (cfun) == PROFILE_READ)
bb->count = cnt;
bb->frequency = freq;
- FOR_EACH_EDGE (e, ei, bb->succs)
- e->count = bb->count.apply_probability (e->probability);
bb = bb->next_bb;
}
@@ -1721,12 +1719,12 @@ group_case_labels_stmt (gswitch *stmt)
{
tree merge_case = gimple_switch_label (stmt, next_index);
basic_block merge_bb = label_to_block (CASE_LABEL (merge_case));
- wide_int bhp1 = wi::add (base_high, 1);
+ wide_int bhp1 = wi::to_wide (base_high) + 1;
/* Merge the cases if they jump to the same place,
and their ranges are consecutive. */
if (merge_bb == base_bb
- && wi::eq_p (CASE_LOW (merge_case), bhp1))
+ && wi::to_wide (CASE_LOW (merge_case)) == bhp1)
{
base_high = CASE_HIGH (merge_case) ?
CASE_HIGH (merge_case) : CASE_LOW (merge_case);
@@ -2843,7 +2841,7 @@ gimple_split_edge (edge edge_in)
new_bb = create_empty_bb (after_bb);
new_bb->frequency = EDGE_FREQUENCY (edge_in);
- new_bb->count = edge_in->count;
+ new_bb->count = edge_in->count ();
e = redirect_edge_and_branch (edge_in, new_bb);
gcc_assert (e == edge_in);
@@ -6372,7 +6370,7 @@ gimple_duplicate_sese_region (edge entry, edge exit,
if (entry->dest->count.initialized_p ())
{
total_count = entry->dest->count;
- entry_count = entry->count;
+ entry_count = entry->count ();
/* Fix up corner cases, to avoid division by zero or creation of negative
frequencies. */
if (entry_count > total_count)
@@ -6542,7 +6540,7 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
if (exit->src->count > 0)
{
total_count = exit->src->count;
- exit_count = exit->count;
+ exit_count = exit->count ();
/* Fix up corner cases, to avoid division by zero or creation of negative
frequencies. */
if (exit_count > total_count)
@@ -6597,10 +6595,8 @@ gimple_duplicate_sese_tail (edge entry, edge exit,
sorig = single_succ_edge (switch_bb);
sorig->flags = exits[1]->flags;
sorig->probability = exits[1]->probability;
- sorig->count = exits[1]->count;
snew = make_edge (switch_bb, nentry_bb, exits[0]->flags);
snew->probability = exits[0]->probability;
- snew->count = exits[1]->count;
/* Register the new edge from SWITCH_BB in loop exit lists. */
@@ -8335,7 +8331,6 @@ gimple_flow_call_edges_add (sbitmap blocks)
}
e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), EDGE_FAKE);
e->probability = profile_probability::guessed_never ();
- e->count = profile_count::guessed_zero ();
}
gsi_prev (&gsi);
}
@@ -8847,14 +8842,12 @@ insert_cond_bb (basic_block bb, gimple *stmt, gimple *cond,
new_bb = create_empty_bb (bb);
edge e = make_edge (bb, new_bb, EDGE_TRUE_VALUE);
e->probability = prob;
- e->count = bb->count.apply_probability (prob);
- new_bb->count = e->count;
+ new_bb->count = e->count ();
new_bb->frequency = prob.apply (bb->frequency);
make_single_succ_edge (new_bb, fall->dest, EDGE_FALLTHRU);
/* Fix edge for split bb. */
fall->flags = EDGE_FALSE_VALUE;
- fall->count -= e->count;
fall->probability -= e->probability;
/* Update dominance info. */
@@ -9084,13 +9077,29 @@ pass_warn_function_return::execute (function *fun)
&& EDGE_COUNT (EXIT_BLOCK_PTR_FOR_FN (fun)->preds) > 0)
{
location = UNKNOWN_LOCATION;
- FOR_EACH_EDGE (e, ei, EXIT_BLOCK_PTR_FOR_FN (fun)->preds)
+ for (ei = ei_start (EXIT_BLOCK_PTR_FOR_FN (fun)->preds);
+ (e = ei_safe_edge (ei)); )
{
last = last_stmt (e->src);
if ((gimple_code (last) == GIMPLE_RETURN
|| gimple_call_builtin_p (last, BUILT_IN_RETURN))
- && (location = gimple_location (last)) != UNKNOWN_LOCATION)
+ && location == UNKNOWN_LOCATION
+ && (location = gimple_location (last)) != UNKNOWN_LOCATION
+ && !optimize)
break;
+ /* When optimizing, replace return stmts in noreturn functions
+ with __builtin_unreachable () call. */
+ if (optimize && gimple_code (last) == GIMPLE_RETURN)
+ {
+ tree fndecl = builtin_decl_implicit (BUILT_IN_UNREACHABLE);
+ gimple *new_stmt = gimple_build_call (fndecl, 0);
+ gimple_set_location (new_stmt, gimple_location (last));
+ gimple_stmt_iterator gsi = gsi_for_stmt (last);
+ gsi_replace (&gsi, new_stmt, true);
+ remove_edge (e);
+ }
+ else
+ ei_next (&ei);
}
if (location == UNKNOWN_LOCATION)
location = cfun->function_end_locus;
@@ -9252,8 +9261,6 @@ execute_fixup_cfg (void)
basic_block bb;
gimple_stmt_iterator gsi;
int todo = 0;
- edge e;
- edge_iterator ei;
cgraph_node *node = cgraph_node::get (current_function_decl);
profile_count num = node->count;
profile_count den = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count;
@@ -9266,9 +9273,6 @@ execute_fixup_cfg (void)
ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = node->count;
EXIT_BLOCK_PTR_FOR_FN (cfun)->count
= EXIT_BLOCK_PTR_FOR_FN (cfun)->count.apply_scale (num, den);
-
- FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
- e->count = e->count.apply_scale (num, den);
}
FOR_EACH_BB_FN (bb, cfun)
@@ -9343,10 +9347,6 @@ execute_fixup_cfg (void)
gsi_next (&gsi);
}
- if (scale)
- FOR_EACH_EDGE (e, ei, bb->succs)
- e->count = e->count.apply_scale (num, den);
-
/* If we have a basic block with no successors that does not
end with a control statement or a noreturn call end it with
a call to __builtin_unreachable. This situation can occur
diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c
index a7053d7..9b7f08c 100644
--- a/gcc/tree-cfgcleanup.c
+++ b/gcc/tree-cfgcleanup.c
@@ -195,7 +195,6 @@ cleanup_control_expr_graph (basic_block bb, gimple_stmt_iterator gsi,
}
taken_edge->probability += e->probability;
- taken_edge->count += e->count;
remove_edge_and_dominated_blocks (e);
retval = true;
}
@@ -892,7 +891,11 @@ cleanup_tree_cfg_noloop (void)
changed |= cleanup_tree_cfg_1 ();
gcc_assert (dom_info_available_p (CDI_DOMINATORS));
- compact_blocks ();
+
+ /* Do not renumber blocks if the SCEV cache is active, it is indexed by
+ basic-block numbers. */
+ if (! scev_initialized_p ())
+ compact_blocks ();
checking_verify_flow_info ();
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index 951aec1..025155a 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -2276,8 +2276,7 @@ chkp_build_returned_bound (gcall *call)
it separately. */
if (fndecl
&& DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL
- && (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA
- || DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN))
+ && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (fndecl)))
{
tree size = gimple_call_arg (call, 0);
gimple_stmt_iterator iter = gsi_for_stmt (call);
diff --git a/gcc/tree-chrec.c b/gcc/tree-chrec.c
index 66d3a7b..beddf10 100644
--- a/gcc/tree-chrec.c
+++ b/gcc/tree-chrec.c
@@ -872,8 +872,7 @@ reset_evolution_in_loop (unsigned loop_num,
new_evol);
tree right = reset_evolution_in_loop (loop_num, CHREC_RIGHT (chrec),
new_evol);
- return build3 (POLYNOMIAL_CHREC, TREE_TYPE (left),
- CHREC_VAR (chrec), left, right);
+ return build_polynomial_chrec (CHREC_VARIABLE (chrec), left, right);
}
while (TREE_CODE (chrec) == POLYNOMIAL_CHREC
@@ -1610,6 +1609,9 @@ operator_is_linear (tree scev)
bool
scev_is_linear_expression (tree scev)
{
+ if (evolution_function_is_constant_p (scev))
+ return true;
+
if (scev == NULL
|| !operator_is_linear (scev))
return false;
diff --git a/gcc/tree-chrec.h b/gcc/tree-chrec.h
index e980ec1..4838bae 100644
--- a/gcc/tree-chrec.h
+++ b/gcc/tree-chrec.h
@@ -157,8 +157,9 @@ build_polynomial_chrec (unsigned loop_num,
if (chrec_zerop (right))
return left;
- return build3 (POLYNOMIAL_CHREC, TREE_TYPE (left),
- build_int_cst (NULL_TREE, loop_num), left, right);
+ tree chrec = build2 (POLYNOMIAL_CHREC, TREE_TYPE (left), left, right);
+ CHREC_VARIABLE (chrec) = loop_num;
+ return chrec;
}
/* Determines whether the expression CHREC is a constant. */
@@ -169,15 +170,9 @@ evolution_function_is_constant_p (const_tree chrec)
if (chrec == NULL_TREE)
return false;
- switch (TREE_CODE (chrec))
- {
- case INTEGER_CST:
- case REAL_CST:
- return true;
-
- default:
- return false;
- }
+ if (CONSTANT_CLASS_P (chrec))
+ return true;
+ return is_gimple_min_invariant (chrec);
}
/* Determine whether CHREC is an affine evolution function in LOOPNUM. */
diff --git a/gcc/tree-complex.c b/gcc/tree-complex.c
index d61047b..e2d93b7 100644
--- a/gcc/tree-complex.c
+++ b/gcc/tree-complex.c
@@ -1192,13 +1192,11 @@ expand_complex_div_wide (gimple_stmt_iterator *gsi, tree inner_type,
/* Wire the blocks together. */
e->flags = EDGE_TRUE_VALUE;
- e->count = bb_true->count;
/* TODO: With value profile we could add an historgram to determine real
branch outcome. */
e->probability = profile_probability::even ();
redirect_edge_succ (e, bb_true);
edge e2 = make_edge (bb_cond, bb_false, EDGE_FALSE_VALUE);
- e2->count = bb_false->count;
e2->probability = profile_probability::even ();
make_single_succ_edge (bb_true, bb_join, EDGE_FALLTHRU);
make_single_succ_edge (bb_false, bb_join, EDGE_FALLTHRU);
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index b34080e..ed35847 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -981,6 +981,9 @@ struct GTY(()) tree_base {
/* SSA version number. This field is only used with SSA_NAME. */
unsigned int version;
+ /* CHREC_VARIABLE. This field is only used with POLYNOMIAL_CHREC. */
+ unsigned int chrec_var;
+
/* Internal function code. */
enum internal_fn ifn;
@@ -2055,7 +2058,7 @@ struct floatn_type_info {
Global variables
---------------------------------------------------------------------------*/
/* Matrix describing the structures contained in a given tree code. */
-extern unsigned char tree_contains_struct[MAX_TREE_CODES][64];
+extern bool tree_contains_struct[MAX_TREE_CODES][64];
/* Class of tree given its code. */
extern const enum tree_code_class tree_code_type[];
diff --git a/gcc/tree-data-ref.c b/gcc/tree-data-ref.c
index 26387f8..559a8e4 100644
--- a/gcc/tree-data-ref.c
+++ b/gcc/tree-data-ref.c
@@ -957,15 +957,14 @@ access_fn_component_p (tree op)
}
/* Determines the base object and the list of indices of memory reference
- DR, analyzed in LOOP and instantiated in loop nest NEST. */
+ DR, analyzed in LOOP and instantiated before NEST. */
static void
-dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop)
+dr_analyze_indices (struct data_reference *dr, edge nest, loop_p loop)
{
vec<tree> access_fns = vNULL;
tree ref, op;
tree base, off, access_fn;
- basic_block before_loop;
/* If analyzing a basic-block there are no indices to analyze
and thus no access functions. */
@@ -977,7 +976,6 @@ dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop)
}
ref = DR_REF (dr);
- before_loop = block_before_loop (nest);
/* REALPART_EXPR and IMAGPART_EXPR can be handled like accesses
into a two element array with a constant index. The base is
@@ -1002,7 +1000,7 @@ dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop)
{
op = TREE_OPERAND (ref, 1);
access_fn = analyze_scalar_evolution (loop, op);
- access_fn = instantiate_scev (before_loop, loop, access_fn);
+ access_fn = instantiate_scev (nest, loop, access_fn);
access_fns.safe_push (access_fn);
}
else if (TREE_CODE (ref) == COMPONENT_REF
@@ -1034,7 +1032,7 @@ dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop)
{
op = TREE_OPERAND (ref, 0);
access_fn = analyze_scalar_evolution (loop, op);
- access_fn = instantiate_scev (before_loop, loop, access_fn);
+ access_fn = instantiate_scev (nest, loop, access_fn);
if (TREE_CODE (access_fn) == POLYNOMIAL_CHREC)
{
tree orig_type;
@@ -1060,12 +1058,15 @@ dr_analyze_indices (struct data_reference *dr, loop_p nest, loop_p loop)
if (TYPE_SIZE_UNIT (TREE_TYPE (ref))
&& TREE_CODE (TYPE_SIZE_UNIT (TREE_TYPE (ref))) == INTEGER_CST
&& !integer_zerop (TYPE_SIZE_UNIT (TREE_TYPE (ref))))
- rem = wi::mod_trunc (off, TYPE_SIZE_UNIT (TREE_TYPE (ref)), SIGNED);
+ rem = wi::mod_trunc
+ (wi::to_wide (off),
+ wi::to_wide (TYPE_SIZE_UNIT (TREE_TYPE (ref))),
+ SIGNED);
else
/* If we can't compute the remainder simply force the initial
condition to zero. */
- rem = off;
- off = wide_int_to_tree (ssizetype, wi::sub (off, rem));
+ rem = wi::to_wide (off);
+ off = wide_int_to_tree (ssizetype, wi::to_wide (off) - rem);
memoff = wide_int_to_tree (TREE_TYPE (memoff), rem);
/* And finally replace the initial condition. */
access_fn = chrec_replace_initial_condition
@@ -1136,7 +1137,7 @@ free_data_ref (data_reference_p dr)
in which the data reference should be analyzed. */
struct data_reference *
-create_data_ref (loop_p nest, loop_p loop, tree memref, gimple *stmt,
+create_data_ref (edge nest, loop_p loop, tree memref, gimple *stmt,
bool is_read, bool is_conditional_in_stmt)
{
struct data_reference *dr;
@@ -1207,35 +1208,28 @@ data_ref_compare_tree (tree t1, tree t2)
if (t2 == NULL)
return 1;
- STRIP_NOPS (t1);
- STRIP_NOPS (t2);
+ STRIP_USELESS_TYPE_CONVERSION (t1);
+ STRIP_USELESS_TYPE_CONVERSION (t2);
+ if (t1 == t2)
+ return 0;
- if (TREE_CODE (t1) != TREE_CODE (t2))
+ if (TREE_CODE (t1) != TREE_CODE (t2)
+ && ! (CONVERT_EXPR_P (t1) && CONVERT_EXPR_P (t2)))
return TREE_CODE (t1) < TREE_CODE (t2) ? -1 : 1;
code = TREE_CODE (t1);
switch (code)
{
- /* For const values, we can just use hash values for comparisons. */
case INTEGER_CST:
- case REAL_CST:
- case FIXED_CST:
+ return tree_int_cst_compare (t1, t2);
+
case STRING_CST:
- case COMPLEX_CST:
- case VECTOR_CST:
- {
- hashval_t h1 = iterative_hash_expr (t1, 0);
- hashval_t h2 = iterative_hash_expr (t2, 0);
- if (h1 != h2)
- return h1 < h2 ? -1 : 1;
- break;
- }
+ if (TREE_STRING_LENGTH (t1) != TREE_STRING_LENGTH (t2))
+ return TREE_STRING_LENGTH (t1) < TREE_STRING_LENGTH (t2) ? -1 : 1;
+ return memcmp (TREE_STRING_POINTER (t1), TREE_STRING_POINTER (t2),
+ TREE_STRING_LENGTH (t1));
case SSA_NAME:
- cmp = data_ref_compare_tree (SSA_NAME_VAR (t1), SSA_NAME_VAR (t2));
- if (cmp != 0)
- return cmp;
-
if (SSA_NAME_VERSION (t1) != SSA_NAME_VERSION (t2))
return SSA_NAME_VERSION (t1) < SSA_NAME_VERSION (t2) ? -1 : 1;
break;
@@ -1243,22 +1237,26 @@ data_ref_compare_tree (tree t1, tree t2)
default:
tclass = TREE_CODE_CLASS (code);
- /* For var-decl, we could compare their UIDs. */
+ /* For decls, compare their UIDs. */
if (tclass == tcc_declaration)
{
if (DECL_UID (t1) != DECL_UID (t2))
return DECL_UID (t1) < DECL_UID (t2) ? -1 : 1;
break;
}
-
- /* For expressions with operands, compare their operands recursively. */
- for (i = TREE_OPERAND_LENGTH (t1) - 1; i >= 0; --i)
+ /* For expressions, compare their operands recursively. */
+ else if (IS_EXPR_CODE_CLASS (tclass))
{
- cmp = data_ref_compare_tree (TREE_OPERAND (t1, i),
- TREE_OPERAND (t2, i));
- if (cmp != 0)
- return cmp;
+ for (i = TREE_OPERAND_LENGTH (t1) - 1; i >= 0; --i)
+ {
+ cmp = data_ref_compare_tree (TREE_OPERAND (t1, i),
+ TREE_OPERAND (t2, i));
+ if (cmp != 0)
+ return cmp;
+ }
}
+ else
+ gcc_unreachable ();
}
return 0;
@@ -1488,14 +1486,16 @@ prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *alias_pairs,
std::swap (*dr_a1, *dr_a2);
bool do_remove = false;
- wide_int diff = wi::sub (DR_INIT (dr_a2->dr), DR_INIT (dr_a1->dr));
+ wide_int diff = (wi::to_wide (DR_INIT (dr_a2->dr))
+ - wi::to_wide (DR_INIT (dr_a1->dr)));
wide_int min_seg_len_b;
tree new_seg_len;
if (TREE_CODE (dr_b1->seg_len) == INTEGER_CST)
- min_seg_len_b = wi::abs (dr_b1->seg_len);
+ min_seg_len_b = wi::abs (wi::to_wide (dr_b1->seg_len));
else
- min_seg_len_b = wi::mul (factor, wi::abs (DR_STEP (dr_b1->dr)));
+ min_seg_len_b
+ = factor * wi::abs (wi::to_wide (DR_STEP (dr_b1->dr)));
/* Now we try to merge alias check dr_a1 & dr_b and dr_a2 & dr_b.
@@ -1534,7 +1534,7 @@ prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *alias_pairs,
/* Adjust diff according to access size of both references. */
tree size_a1 = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr_a1->dr)));
tree size_a2 = TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr_a2->dr)));
- diff = wi::add (diff, wi::sub (size_a2, size_a1));
+ diff += wi::to_wide (size_a2) - wi::to_wide (size_a1);
/* Case A.1. */
if (wi::leu_p (diff, min_seg_len_b)
/* Case A.2 and B combined. */
@@ -1542,11 +1542,12 @@ prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *alias_pairs,
{
if (tree_fits_uhwi_p (dr_a1->seg_len)
&& tree_fits_uhwi_p (dr_a2->seg_len))
- new_seg_len
- = wide_int_to_tree (sizetype,
- wi::umin (wi::sub (dr_a1->seg_len,
- diff),
- dr_a2->seg_len));
+ {
+ wide_int min_len
+ = wi::umin (wi::to_wide (dr_a1->seg_len) - diff,
+ wi::to_wide (dr_a2->seg_len));
+ new_seg_len = wide_int_to_tree (sizetype, min_len);
+ }
else
new_seg_len
= size_binop (MINUS_EXPR, dr_a2->seg_len,
@@ -1565,11 +1566,12 @@ prune_runtime_alias_test_list (vec<dr_with_seg_len_pair_t> *alias_pairs,
{
if (tree_fits_uhwi_p (dr_a1->seg_len)
&& tree_fits_uhwi_p (dr_a2->seg_len))
- new_seg_len
- = wide_int_to_tree (sizetype,
- wi::umax (wi::add (dr_a2->seg_len,
- diff),
- dr_a1->seg_len));
+ {
+ wide_int max_len
+ = wi::umax (wi::to_wide (dr_a2->seg_len) + diff,
+ wi::to_wide (dr_a1->seg_len));
+ new_seg_len = wide_int_to_tree (sizetype, max_len);
+ }
else
new_seg_len
= size_binop (PLUS_EXPR, dr_a2->seg_len,
@@ -4944,17 +4946,6 @@ loop_nest_has_data_refs (loop_p loop)
}
}
free (bbs);
-
- if (loop->inner)
- {
- loop = loop->inner;
- while (loop)
- {
- if (loop_nest_has_data_refs (loop))
- return true;
- loop = loop->next;
- }
- }
return false;
}
@@ -4977,7 +4968,8 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt,
FOR_EACH_VEC_ELT (references, i, ref)
{
- dr = create_data_ref (nest, loop_containing_stmt (stmt), ref->ref,
+ dr = create_data_ref (nest ? loop_preheader_edge (nest) : NULL,
+ loop_containing_stmt (stmt), ref->ref,
stmt, ref->is_read, ref->is_conditional_in_stmt);
gcc_assert (dr != NULL);
datarefs->safe_push (dr);
@@ -4993,7 +4985,7 @@ find_data_references_in_stmt (struct loop *nest, gimple *stmt,
should be analyzed. */
bool
-graphite_find_data_references_in_stmt (loop_p nest, loop_p loop, gimple *stmt,
+graphite_find_data_references_in_stmt (edge nest, loop_p loop, gimple *stmt,
vec<data_reference_p> *datarefs)
{
unsigned i;
diff --git a/gcc/tree-data-ref.h b/gcc/tree-data-ref.h
index a66d335..d9d297a 100644
--- a/gcc/tree-data-ref.h
+++ b/gcc/tree-data-ref.h
@@ -436,11 +436,11 @@ extern void free_data_ref (data_reference_p);
extern void free_data_refs (vec<data_reference_p> );
extern bool find_data_references_in_stmt (struct loop *, gimple *,
vec<data_reference_p> *);
-extern bool graphite_find_data_references_in_stmt (loop_p, loop_p, gimple *,
+extern bool graphite_find_data_references_in_stmt (edge, loop_p, gimple *,
vec<data_reference_p> *);
tree find_data_references_in_loop (struct loop *, vec<data_reference_p> *);
bool loop_nest_has_data_refs (loop_p loop);
-struct data_reference *create_data_ref (loop_p, loop_p, tree, gimple *, bool,
+struct data_reference *create_data_ref (edge, loop_p, tree, gimple *, bool,
bool);
extern bool find_loop_nest (struct loop *, vec<loop_p> *);
extern struct data_dependence_relation *initialize_data_dependence_relation
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index 2e65a44..db69bda 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -654,7 +654,22 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
if (!wi::fits_shwi_p (maxsize) || wi::neg_p (maxsize))
*pmax_size = -1;
else
- *pmax_size = maxsize.to_shwi ();
+ {
+ *pmax_size = maxsize.to_shwi ();
+ if (*poffset > HOST_WIDE_INT_MAX - *pmax_size)
+ *pmax_size = -1;
+ }
+
+ /* Punt if *POFFSET + *PSIZE overflows in HOST_WIDE_INT, the callers don't
+ check for such overflows individually and assume it works. */
+ if (*psize != -1 && *poffset > HOST_WIDE_INT_MAX - *psize)
+ {
+ *poffset = 0;
+ *psize = -1;
+ *pmax_size = -1;
+
+ return exp;
+ }
return exp;
}
diff --git a/gcc/tree-dump.c b/gcc/tree-dump.c
index da36031..ac0c7b8 100644
--- a/gcc/tree-dump.c
+++ b/gcc/tree-dump.c
@@ -540,7 +540,7 @@ dequeue_and_dump (dump_info_p di)
case INTEGER_CST:
fprintf (di->stream, "int: ");
- print_decs (t, di->stream);
+ print_decs (wi::to_wide (t), di->stream);
break;
case STRING_CST:
diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c
index 329fadb..e255e08 100644
--- a/gcc/tree-eh.c
+++ b/gcc/tree-eh.c
@@ -3259,7 +3259,6 @@ lower_resx (basic_block bb, gresx *stmt,
gcc_assert (e->flags & EDGE_EH);
e->flags = (e->flags & ~EDGE_EH) | EDGE_FALLTHRU;
e->probability = profile_probability::always ();
- e->count = bb->count;
/* If there are no more EH users of the landing pad, delete it. */
FOR_EACH_EDGE (e, ei, e->dest->preds)
@@ -4099,7 +4098,6 @@ unsplit_eh (eh_landing_pad lp)
redirect_edge_pred (e_out, e_in->src);
e_out->flags = e_in->flags;
e_out->probability = e_in->probability;
- e_out->count = e_in->count;
remove_edge (e_in);
return true;
@@ -4292,7 +4290,6 @@ cleanup_empty_eh_move_lp (basic_block bb, edge e_out,
/* Clean up E_OUT for the fallthru. */
e_out->flags = (e_out->flags & ~EDGE_EH) | EDGE_FALLTHRU;
e_out->probability = profile_probability::always ();
- e_out->count = e_out->src->count;
}
/* A subroutine of cleanup_empty_eh. Handle more complex cases of
diff --git a/gcc/tree-if-conv.c b/gcc/tree-if-conv.c
index 968d93c..a1803ff 100644
--- a/gcc/tree-if-conv.c
+++ b/gcc/tree-if-conv.c
@@ -2197,7 +2197,7 @@ predicate_mem_writes (loop_p loop)
gimple *stmt;
int index;
- if (is_true_predicate (cond) || is_false_predicate (cond))
+ if (is_true_predicate (cond))
continue;
swap = false;
@@ -2210,97 +2210,108 @@ predicate_mem_writes (loop_p loop)
vect_sizes.truncate (0);
vect_masks.truncate (0);
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- if (!gimple_assign_single_p (stmt = gsi_stmt (gsi)))
- continue;
- else if (gimple_plf (stmt, GF_PLF_2))
- {
- tree lhs = gimple_assign_lhs (stmt);
- tree rhs = gimple_assign_rhs1 (stmt);
- tree ref, addr, ptr, mask;
- gcall *new_stmt;
- gimple_seq stmts = NULL;
- int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (lhs)));
- ref = TREE_CODE (lhs) == SSA_NAME ? rhs : lhs;
- mark_addressable (ref);
- addr = force_gimple_operand_gsi (&gsi, build_fold_addr_expr (ref),
- true, NULL_TREE, true,
- GSI_SAME_STMT);
- if (!vect_sizes.is_empty ()
- && (index = mask_exists (bitsize, vect_sizes)) != -1)
- /* Use created mask. */
- mask = vect_masks[index];
- else
- {
- if (COMPARISON_CLASS_P (cond))
- mask = gimple_build (&stmts, TREE_CODE (cond),
- boolean_type_node,
- TREE_OPERAND (cond, 0),
- TREE_OPERAND (cond, 1));
- else
- {
- gcc_assert (TREE_CODE (cond) == SSA_NAME);
- mask = cond;
- }
-
- if (swap)
- {
- tree true_val
- = constant_boolean_node (true, TREE_TYPE (mask));
- mask = gimple_build (&stmts, BIT_XOR_EXPR,
- TREE_TYPE (mask), mask, true_val);
- }
- gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
-
- mask = ifc_temp_var (TREE_TYPE (mask), mask, &gsi);
- /* Save mask and its size for further use. */
- vect_sizes.safe_push (bitsize);
- vect_masks.safe_push (mask);
- }
- ptr = build_int_cst (reference_alias_ptr_type (ref),
- get_object_alignment (ref));
- /* Copy points-to info if possible. */
- if (TREE_CODE (addr) == SSA_NAME && !SSA_NAME_PTR_INFO (addr))
- copy_ref_info (build2 (MEM_REF, TREE_TYPE (ref), addr, ptr),
- ref);
- if (TREE_CODE (lhs) == SSA_NAME)
- {
- new_stmt
- = gimple_build_call_internal (IFN_MASK_LOAD, 3, addr,
- ptr, mask);
- gimple_call_set_lhs (new_stmt, lhs);
- gimple_set_vuse (new_stmt, gimple_vuse (stmt));
- }
- else
- {
- new_stmt
- = gimple_build_call_internal (IFN_MASK_STORE, 4, addr, ptr,
+ for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
+ {
+ if (!gimple_assign_single_p (stmt = gsi_stmt (gsi)))
+ ;
+ else if (is_false_predicate (cond)
+ && gimple_vdef (stmt))
+ {
+ unlink_stmt_vdef (stmt);
+ gsi_remove (&gsi, true);
+ release_defs (stmt);
+ continue;
+ }
+ else if (gimple_plf (stmt, GF_PLF_2))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
+ tree ref, addr, ptr, mask;
+ gcall *new_stmt;
+ gimple_seq stmts = NULL;
+ int bitsize = GET_MODE_BITSIZE (TYPE_MODE (TREE_TYPE (lhs)));
+ ref = TREE_CODE (lhs) == SSA_NAME ? rhs : lhs;
+ mark_addressable (ref);
+ addr = force_gimple_operand_gsi (&gsi, build_fold_addr_expr (ref),
+ true, NULL_TREE, true,
+ GSI_SAME_STMT);
+ if (!vect_sizes.is_empty ()
+ && (index = mask_exists (bitsize, vect_sizes)) != -1)
+ /* Use created mask. */
+ mask = vect_masks[index];
+ else
+ {
+ if (COMPARISON_CLASS_P (cond))
+ mask = gimple_build (&stmts, TREE_CODE (cond),
+ boolean_type_node,
+ TREE_OPERAND (cond, 0),
+ TREE_OPERAND (cond, 1));
+ else
+ {
+ gcc_assert (TREE_CODE (cond) == SSA_NAME);
+ mask = cond;
+ }
+
+ if (swap)
+ {
+ tree true_val
+ = constant_boolean_node (true, TREE_TYPE (mask));
+ mask = gimple_build (&stmts, BIT_XOR_EXPR,
+ TREE_TYPE (mask), mask, true_val);
+ }
+ gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
+
+ mask = ifc_temp_var (TREE_TYPE (mask), mask, &gsi);
+ /* Save mask and its size for further use. */
+ vect_sizes.safe_push (bitsize);
+ vect_masks.safe_push (mask);
+ }
+ ptr = build_int_cst (reference_alias_ptr_type (ref),
+ get_object_alignment (ref));
+ /* Copy points-to info if possible. */
+ if (TREE_CODE (addr) == SSA_NAME && !SSA_NAME_PTR_INFO (addr))
+ copy_ref_info (build2 (MEM_REF, TREE_TYPE (ref), addr, ptr),
+ ref);
+ if (TREE_CODE (lhs) == SSA_NAME)
+ {
+ new_stmt
+ = gimple_build_call_internal (IFN_MASK_LOAD, 3, addr,
+ ptr, mask);
+ gimple_call_set_lhs (new_stmt, lhs);
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ }
+ else
+ {
+ new_stmt
+ = gimple_build_call_internal (IFN_MASK_STORE, 4, addr, ptr,
mask, rhs);
- gimple_set_vuse (new_stmt, gimple_vuse (stmt));
- gimple_set_vdef (new_stmt, gimple_vdef (stmt));
- SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
- }
- gimple_call_set_nothrow (new_stmt, true);
+ gimple_set_vuse (new_stmt, gimple_vuse (stmt));
+ gimple_set_vdef (new_stmt, gimple_vdef (stmt));
+ SSA_NAME_DEF_STMT (gimple_vdef (new_stmt)) = new_stmt;
+ }
+ gimple_call_set_nothrow (new_stmt, true);
- gsi_replace (&gsi, new_stmt, true);
- }
- else if (gimple_vdef (stmt))
- {
- tree lhs = gimple_assign_lhs (stmt);
- tree rhs = gimple_assign_rhs1 (stmt);
- tree type = TREE_TYPE (lhs);
-
- lhs = ifc_temp_var (type, unshare_expr (lhs), &gsi);
- rhs = ifc_temp_var (type, unshare_expr (rhs), &gsi);
- if (swap)
- std::swap (lhs, rhs);
- cond = force_gimple_operand_gsi_1 (&gsi, unshare_expr (cond),
- is_gimple_condexpr, NULL_TREE,
- true, GSI_SAME_STMT);
- rhs = fold_build_cond_expr (type, unshare_expr (cond), rhs, lhs);
- gimple_assign_set_rhs1 (stmt, ifc_temp_var (type, rhs, &gsi));
- update_stmt (stmt);
- }
+ gsi_replace (&gsi, new_stmt, true);
+ }
+ else if (gimple_vdef (stmt))
+ {
+ tree lhs = gimple_assign_lhs (stmt);
+ tree rhs = gimple_assign_rhs1 (stmt);
+ tree type = TREE_TYPE (lhs);
+
+ lhs = ifc_temp_var (type, unshare_expr (lhs), &gsi);
+ rhs = ifc_temp_var (type, unshare_expr (rhs), &gsi);
+ if (swap)
+ std::swap (lhs, rhs);
+ cond = force_gimple_operand_gsi_1 (&gsi, unshare_expr (cond),
+ is_gimple_condexpr, NULL_TREE,
+ true, GSI_SAME_STMT);
+ rhs = fold_build_cond_expr (type, unshare_expr (cond), rhs, lhs);
+ gimple_assign_set_rhs1 (stmt, ifc_temp_var (type, rhs, &gsi));
+ update_stmt (stmt);
+ }
+ gsi_next (&gsi);
+ }
}
}
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c
index cce5dc7..597addb 100644
--- a/gcc/tree-inline.c
+++ b/gcc/tree-inline.c
@@ -949,7 +949,7 @@ remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data)
*walk_subtrees = 0;
else if (TREE_CODE (*tp) == INTEGER_CST)
- *tp = wide_int_to_tree (new_type, *tp);
+ *tp = wide_int_to_tree (new_type, wi::to_wide (*tp));
else
{
*tp = copy_node (*tp);
@@ -1133,7 +1133,7 @@ copy_tree_body_r (tree *tp, int *walk_subtrees, void *data)
*walk_subtrees = 0;
else if (TREE_CODE (*tp) == INTEGER_CST)
- *tp = wide_int_to_tree (new_type, *tp);
+ *tp = wide_int_to_tree (new_type, wi::to_wide (*tp));
else
{
*tp = copy_node (*tp);
@@ -2215,7 +2215,7 @@ update_ssa_across_abnormal_edges (basic_block bb, basic_block ret_bb,
debug stmts are left after a statement that must end the basic block. */
static bool
-copy_edges_for_bb (basic_block bb, profile_count num, profile_count den,
+copy_edges_for_bb (basic_block bb,
basic_block ret_bb, basic_block abnormal_goto_dest)
{
basic_block new_bb = (basic_block) bb->aux;
@@ -2224,8 +2224,6 @@ copy_edges_for_bb (basic_block bb, profile_count num, profile_count den,
gimple_stmt_iterator si;
int flags;
bool need_debug_cleanup = false;
- bool scale = num.initialized_p ()
- && (den > 0 || num == profile_count::zero ());
/* Use the indices from the original blocks to create edges for the
new ones. */
@@ -2242,8 +2240,6 @@ copy_edges_for_bb (basic_block bb, profile_count num, profile_count den,
&& old_edge->dest->aux != EXIT_BLOCK_PTR_FOR_FN (cfun))
flags |= EDGE_FALLTHRU;
new_edge = make_edge (new_bb, (basic_block) old_edge->dest->aux, flags);
- if (scale)
- new_edge->count = old_edge->count.apply_scale (num, den);
new_edge->probability = old_edge->probability;
}
@@ -2324,17 +2320,11 @@ copy_edges_for_bb (basic_block bb, profile_count num, profile_count den,
&& (e = find_edge (copy_stmt_bb,
(basic_block) old_edge->dest->aux))
&& (e->flags & EDGE_EH))
- {
- e->probability = old_edge->probability;
- e->count = old_edge->count;
- }
+ e->probability = old_edge->probability;
FOR_EACH_EDGE (e, ei, copy_stmt_bb->succs)
if ((e->flags & EDGE_EH) && !e->probability.initialized_p ())
- {
- e->probability = profile_probability::never ();
- e->count = profile_count::zero ();
- }
+ e->probability = profile_probability::never ();
}
@@ -2700,16 +2690,10 @@ void
freqs_to_counts (struct cgraph_node *node, profile_count count)
{
basic_block bb;
- edge_iterator ei;
- edge e;
struct function *fn = DECL_STRUCT_FUNCTION (node->decl);
FOR_ALL_BB_FN(bb, fn)
- {
- bb->count = count.apply_scale (bb->frequency, BB_FREQ_MAX);
- FOR_EACH_EDGE (e, ei, bb->succs)
- e->count = e->src->count.apply_probability (e->probability);
- }
+ bb->count = count.apply_scale (bb->frequency, BB_FREQ_MAX);
}
/* Make a copy of the body of FN so that it can be inserted inline in
@@ -2769,10 +2753,7 @@ copy_cfg_body (copy_body_data * id, profile_count count, int frequency_scale,
FOR_EACH_EDGE (e, ei, new_entry->preds)
if (!e->src->aux)
- {
- incoming_frequency += EDGE_FREQUENCY (e);
- incoming_count += e->count;
- }
+ incoming_frequency += EDGE_FREQUENCY (e);
if (scale)
incoming_count = incoming_count.apply_scale (num, den);
else
@@ -2826,14 +2807,13 @@ copy_cfg_body (copy_body_data * id, profile_count count, int frequency_scale,
FOR_ALL_BB_FN (bb, cfun_to_copy)
if (!id->blocks_to_copy
|| (bb->index > 0 && bitmap_bit_p (id->blocks_to_copy, bb->index)))
- need_debug_cleanup |= copy_edges_for_bb (bb, num, den, exit_block_map,
+ need_debug_cleanup |= copy_edges_for_bb (bb, exit_block_map,
abnormal_goto_dest);
if (new_entry)
{
edge e = make_edge (entry_block_map, (basic_block)new_entry->aux, EDGE_FALLTHRU);
e->probability = profile_probability::always ();
- e->count = incoming_count;
}
/* Duplicate the loop tree, if available and wanted. */
@@ -4796,6 +4776,22 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
reset_debug_bindings (id, stmt_gsi);
+ if (flag_stack_reuse != SR_NONE)
+ for (tree p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p))
+ if (!TREE_THIS_VOLATILE (p))
+ {
+ tree *varp = id->decl_map->get (p);
+ if (varp && VAR_P (*varp) && !is_gimple_reg (*varp))
+ {
+ tree clobber = build_constructor (TREE_TYPE (*varp), NULL);
+ gimple *clobber_stmt;
+ TREE_THIS_VOLATILE (clobber) = 1;
+ clobber_stmt = gimple_build_assign (*varp, clobber);
+ gimple_set_location (clobber_stmt, gimple_location (stmt));
+ gsi_insert_before (&stmt_gsi, clobber_stmt, GSI_SAME_STMT);
+ }
+ }
+
/* Reset the escaped solution. */
if (cfun->gimple_df)
pt_solution_reset (&cfun->gimple_df->escaped);
@@ -4846,6 +4842,23 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
stmt = gimple_build_assign (gimple_call_lhs (stmt), use_retvar);
gsi_replace (&stmt_gsi, stmt, false);
maybe_clean_or_replace_eh_stmt (old_stmt, stmt);
+ /* Append a clobber for id->retvar if easily possible. */
+ if (flag_stack_reuse != SR_NONE
+ && id->retvar
+ && VAR_P (id->retvar)
+ && id->retvar != return_slot
+ && id->retvar != modify_dest
+ && !TREE_THIS_VOLATILE (id->retvar)
+ && !is_gimple_reg (id->retvar)
+ && !stmt_ends_bb_p (stmt))
+ {
+ tree clobber = build_constructor (TREE_TYPE (id->retvar), NULL);
+ gimple *clobber_stmt;
+ TREE_THIS_VOLATILE (clobber) = 1;
+ clobber_stmt = gimple_build_assign (id->retvar, clobber);
+ gimple_set_location (clobber_stmt, gimple_location (old_stmt));
+ gsi_insert_after (&stmt_gsi, clobber_stmt, GSI_SAME_STMT);
+ }
/* Copy bounds if we copy structure with bounds. */
if (chkp_function_instrumented_p (id->dst_fn)
@@ -4884,8 +4897,25 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
SSA_NAME_DEF_STMT (name) = gimple_build_nop ();
}
}
+ /* Replace with a clobber for id->retvar. */
+ else if (flag_stack_reuse != SR_NONE
+ && id->retvar
+ && VAR_P (id->retvar)
+ && id->retvar != return_slot
+ && id->retvar != modify_dest
+ && !TREE_THIS_VOLATILE (id->retvar)
+ && !is_gimple_reg (id->retvar))
+ {
+ tree clobber = build_constructor (TREE_TYPE (id->retvar), NULL);
+ gimple *clobber_stmt;
+ TREE_THIS_VOLATILE (clobber) = 1;
+ clobber_stmt = gimple_build_assign (id->retvar, clobber);
+ gimple_set_location (clobber_stmt, gimple_location (stmt));
+ gsi_replace (&stmt_gsi, clobber_stmt, false);
+ maybe_clean_or_replace_eh_stmt (stmt, clobber_stmt);
+ }
else
- gsi_remove (&stmt_gsi, true);
+ gsi_remove (&stmt_gsi, true);
}
/* Put returned bounds into the correct place if required. */
@@ -4934,6 +4964,8 @@ expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id)
cg_edge->callee->remove ();
id->block = NULL_TREE;
+ id->retvar = NULL_TREE;
+ id->retbnd = NULL_TREE;
successfully_inlined = true;
egress:
diff --git a/gcc/tree-into-ssa.c b/gcc/tree-into-ssa.c
index 28f72e4..a250f81 100644
--- a/gcc/tree-into-ssa.c
+++ b/gcc/tree-into-ssa.c
@@ -1226,6 +1226,8 @@ get_reaching_def (tree var)
if (currdef == NULL_TREE)
{
tree sym = DECL_P (var) ? var : SSA_NAME_VAR (var);
+ if (! sym)
+ sym = create_tmp_reg (TREE_TYPE (var));
currdef = get_or_create_ssa_default_def (cfun, sym);
}
diff --git a/gcc/tree-loop-distribution.c b/gcc/tree-loop-distribution.c
index 26b8b9a..52db3c9 100644
--- a/gcc/tree-loop-distribution.c
+++ b/gcc/tree-loop-distribution.c
@@ -83,13 +83,14 @@ along with GCC; see the file COPYING3. If not see
loops and recover to the original one.
TODO:
- 1) We only distribute innermost loops now. This pass should handle loop
- nests in the future.
+ 1) We only distribute innermost two-level loop nest now. We should
+ extend it for arbitrary loop nests in the future.
2) We only fuse partitions in SCC now. A better fusion algorithm is
desired to minimize loop overhead, maximize parallelism and maximize
data reuse. */
#include "config.h"
+#define INCLUDE_ALGORITHM /* stable_sort */
#include "system.h"
#include "coretypes.h"
#include "backend.h"
@@ -106,6 +107,7 @@ along with GCC; see the file COPYING3. If not see
#include "stor-layout.h"
#include "tree-cfg.h"
#include "tree-ssa-loop-manip.h"
+#include "tree-ssa-loop-ivopts.h"
#include "tree-ssa-loop.h"
#include "tree-into-ssa.h"
#include "tree-ssa.h"
@@ -118,6 +120,11 @@ along with GCC; see the file COPYING3. If not see
#define MAX_DATAREFS_NUM \
((unsigned) PARAM_VALUE (PARAM_LOOP_MAX_DATAREFS_FOR_DATADEPS))
+/* Threshold controlling number of distributed partitions. Given it may
+ be unnecessary if a memory stream cost model is invented in the future,
+ we define it as a temporary macro, rather than a parameter. */
+#define NUM_PARTITION_THRESHOLD (4)
+
/* Hashtable helpers. */
struct ddr_hasher : nofree_ptr_hash <struct data_dependence_relation>
@@ -588,27 +595,36 @@ enum partition_type {
PTYPE_SEQUENTIAL
};
+/* Builtin info for loop distribution. */
+struct builtin_info
+{
+ /* data-references a kind != PKIND_NORMAL partition is about. */
+ data_reference_p dst_dr;
+ data_reference_p src_dr;
+ /* Base address and size of memory objects operated by the builtin. Note
+ both dest and source memory objects must have the same size. */
+ tree dst_base;
+ tree src_base;
+ tree size;
+ /* Base and offset part of dst_base after stripping constant offset. This
+ is only used in memset builtin distribution for now. */
+ tree dst_base_base;
+ unsigned HOST_WIDE_INT dst_base_offset;
+};
+
/* Partition for loop distribution. */
struct partition
{
/* Statements of the partition. */
bitmap stmts;
- /* Loops of the partition. */
- bitmap loops;
/* True if the partition defines variable which is used outside of loop. */
bool reduction_p;
- /* For builtin partition, true if it executes one iteration more than
- number of loop (latch) iterations. */
- bool plus_one;
enum partition_kind kind;
enum partition_type type;
- /* data-references a kind != PKIND_NORMAL partition is about. */
- data_reference_p main_dr;
- data_reference_p secondary_dr;
- /* Number of loop (latch) iterations. */
- tree niter;
/* Data references in the partition. */
bitmap datarefs;
+ /* Information of builtin parition. */
+ struct builtin_info *builtin;
};
@@ -619,7 +635,6 @@ partition_alloc (void)
{
partition *partition = XCNEW (struct partition);
partition->stmts = BITMAP_ALLOC (NULL);
- partition->loops = BITMAP_ALLOC (NULL);
partition->reduction_p = false;
partition->kind = PKIND_NORMAL;
partition->datarefs = BITMAP_ALLOC (NULL);
@@ -632,8 +647,10 @@ static void
partition_free (partition *partition)
{
BITMAP_FREE (partition->stmts);
- BITMAP_FREE (partition->loops);
BITMAP_FREE (partition->datarefs);
+ if (partition->builtin)
+ free (partition->builtin);
+
free (partition);
}
@@ -718,9 +735,11 @@ ssa_name_has_uses_outside_loop_p (tree def, loop_p loop)
FOR_EACH_IMM_USE_FAST (use_p, imm_iter, def)
{
- gimple *use_stmt = USE_STMT (use_p);
- if (!is_gimple_debug (use_stmt)
- && loop != loop_containing_stmt (use_stmt))
+ if (is_gimple_debug (USE_STMT (use_p)))
+ continue;
+
+ basic_block use_bb = gimple_bb (USE_STMT (use_p));
+ if (!flow_bb_inside_loop_p (loop, use_bb))
return true;
}
@@ -834,6 +853,10 @@ generate_loops_for_partition (struct loop *loop, partition *partition,
for (i = 0; i < loop->num_nodes; i++)
{
basic_block bb = bbs[i];
+ edge inner_exit = NULL;
+
+ if (loop != bb->loop_father)
+ inner_exit = single_exit (bb->loop_father);
for (gphi_iterator bsi = gsi_start_phis (bb); !gsi_end_p (bsi);)
{
@@ -852,11 +875,17 @@ generate_loops_for_partition (struct loop *loop, partition *partition,
&& !is_gimple_debug (stmt)
&& !bitmap_bit_p (partition->stmts, gimple_uid (stmt)))
{
- /* Choose an arbitrary path through the empty CFG part
- that this unnecessary control stmt controls. */
+ /* In distribution of loop nest, if bb is inner loop's exit_bb,
+ we choose its exit edge/path in order to avoid generating
+ infinite loop. For all other cases, we choose an arbitrary
+ path through the empty CFG part that this unnecessary
+ control stmt controls. */
if (gcond *cond_stmt = dyn_cast <gcond *> (stmt))
{
- gimple_cond_make_false (cond_stmt);
+ if (inner_exit && inner_exit->flags & EDGE_TRUE_VALUE)
+ gimple_cond_make_true (cond_stmt);
+ else
+ gimple_cond_make_false (cond_stmt);
update_stmt (stmt);
}
else if (gimple_code (stmt) == GIMPLE_SWITCH)
@@ -881,43 +910,6 @@ generate_loops_for_partition (struct loop *loop, partition *partition,
free (bbs);
}
-/* Build the size argument for a memory operation call. */
-
-static tree
-build_size_arg_loc (location_t loc, data_reference_p dr, tree nb_iter,
- bool plus_one)
-{
- tree size = fold_convert_loc (loc, sizetype, nb_iter);
- if (plus_one)
- size = size_binop (PLUS_EXPR, size, size_one_node);
- size = fold_build2_loc (loc, MULT_EXPR, sizetype, size,
- TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr))));
- size = fold_convert_loc (loc, size_type_node, size);
- return size;
-}
-
-/* Build an address argument for a memory operation call. */
-
-static tree
-build_addr_arg_loc (location_t loc, data_reference_p dr, tree nb_bytes)
-{
- tree addr_base;
-
- addr_base = size_binop_loc (loc, PLUS_EXPR, DR_OFFSET (dr), DR_INIT (dr));
- addr_base = fold_convert_loc (loc, sizetype, addr_base);
-
- /* Test for a negative stride, iterating over every element. */
- if (tree_int_cst_sgn (DR_STEP (dr)) == -1)
- {
- addr_base = size_binop_loc (loc, MINUS_EXPR, addr_base,
- fold_convert_loc (loc, sizetype, nb_bytes));
- addr_base = size_binop_loc (loc, PLUS_EXPR, addr_base,
- TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr))));
- }
-
- return fold_build_pointer_plus_loc (loc, DR_BASE_ADDRESS (dr), addr_base);
-}
-
/* If VAL memory representation contains the same value in all bytes,
return that value, otherwise return -1.
E.g. for 0x24242424 return 0x24, for IEEE double
@@ -982,27 +974,23 @@ static void
generate_memset_builtin (struct loop *loop, partition *partition)
{
gimple_stmt_iterator gsi;
- gimple *stmt, *fn_call;
tree mem, fn, nb_bytes;
- location_t loc;
tree val;
-
- stmt = DR_STMT (partition->main_dr);
- loc = gimple_location (stmt);
+ struct builtin_info *builtin = partition->builtin;
+ gimple *fn_call;
/* The new statements will be placed before LOOP. */
gsi = gsi_last_bb (loop_preheader_edge (loop)->src);
- nb_bytes = build_size_arg_loc (loc, partition->main_dr, partition->niter,
- partition->plus_one);
+ nb_bytes = builtin->size;
nb_bytes = force_gimple_operand_gsi (&gsi, nb_bytes, true, NULL_TREE,
false, GSI_CONTINUE_LINKING);
- mem = build_addr_arg_loc (loc, partition->main_dr, nb_bytes);
+ mem = builtin->dst_base;
mem = force_gimple_operand_gsi (&gsi, mem, true, NULL_TREE,
false, GSI_CONTINUE_LINKING);
/* This exactly matches the pattern recognition in classify_partition. */
- val = gimple_assign_rhs1 (stmt);
+ val = gimple_assign_rhs1 (DR_STMT (builtin->dst_dr));
/* Handle constants like 0x15151515 and similarly
floating point constants etc. where all bytes are the same. */
int bytev = const_with_all_bytes_same (val);
@@ -1038,23 +1026,19 @@ static void
generate_memcpy_builtin (struct loop *loop, partition *partition)
{
gimple_stmt_iterator gsi;
- gimple *stmt, *fn_call;
+ gimple *fn_call;
tree dest, src, fn, nb_bytes;
- location_t loc;
enum built_in_function kind;
-
- stmt = DR_STMT (partition->main_dr);
- loc = gimple_location (stmt);
+ struct builtin_info *builtin = partition->builtin;
/* The new statements will be placed before LOOP. */
gsi = gsi_last_bb (loop_preheader_edge (loop)->src);
- nb_bytes = build_size_arg_loc (loc, partition->main_dr, partition->niter,
- partition->plus_one);
+ nb_bytes = builtin->size;
nb_bytes = force_gimple_operand_gsi (&gsi, nb_bytes, true, NULL_TREE,
false, GSI_CONTINUE_LINKING);
- dest = build_addr_arg_loc (loc, partition->main_dr, nb_bytes);
- src = build_addr_arg_loc (loc, partition->secondary_dr, nb_bytes);
+ dest = builtin->dst_base;
+ src = builtin->src_base;
if (partition->kind == PKIND_MEMCPY
|| ! ptr_derefs_may_alias_p (dest, src))
kind = BUILT_IN_MEMCPY;
@@ -1279,8 +1263,6 @@ build_rdg_partition_for_vertex (struct graph *rdg, int v)
FOR_EACH_VEC_ELT (nodes, i, x)
{
bitmap_set_bit (partition->stmts, x);
- bitmap_set_bit (partition->loops,
- loop_containing_stmt (RDG_STMT (rdg, x))->num);
for (j = 0; RDG_DATAREFS (rdg, x).iterate (j, &dr); ++j)
{
@@ -1307,69 +1289,22 @@ build_rdg_partition_for_vertex (struct graph *rdg, int v)
return partition;
}
-/* Classifies the builtin kind we can generate for PARTITION of RDG and LOOP.
- For the moment we detect memset, memcpy and memmove patterns. Bitmap
- STMT_IN_ALL_PARTITIONS contains statements belonging to all partitions. */
+/* Given PARTITION of LOOP and RDG, record single load/store data references
+ for builtin partition in SRC_DR/DST_DR, return false if there is no such
+ data references. */
-static void
-classify_partition (loop_p loop, struct graph *rdg, partition *partition,
- bitmap stmt_in_all_partitions)
+static bool
+find_single_drs (struct loop *loop, struct graph *rdg, partition *partition,
+ data_reference_p *dst_dr, data_reference_p *src_dr)
{
- bitmap_iterator bi;
unsigned i;
- tree nb_iter;
- data_reference_p single_load, single_store;
- bool volatiles_p = false, plus_one = false, has_reduction = false;
-
- partition->kind = PKIND_NORMAL;
- partition->main_dr = NULL;
- partition->secondary_dr = NULL;
- partition->niter = NULL_TREE;
- partition->plus_one = false;
-
- EXECUTE_IF_SET_IN_BITMAP (partition->stmts, 0, i, bi)
- {
- gimple *stmt = RDG_STMT (rdg, i);
-
- if (gimple_has_volatile_ops (stmt))
- volatiles_p = true;
-
- /* If the stmt is not included by all partitions and there is uses
- outside of the loop, then mark the partition as reduction. */
- if (stmt_has_scalar_dependences_outside_loop (loop, stmt))
- {
- /* Due to limitation in the transform phase we have to fuse all
- reduction partitions. As a result, this could cancel valid
- loop distribution especially for loop that induction variable
- is used outside of loop. To workaround this issue, we skip
- marking partition as reudction if the reduction stmt belongs
- to all partitions. In such case, reduction will be computed
- correctly no matter how partitions are fused/distributed. */
- if (!bitmap_bit_p (stmt_in_all_partitions, i))
- {
- partition->reduction_p = true;
- return;
- }
- has_reduction = true;
- }
- }
-
- /* Perform general partition disqualification for builtins. */
- if (volatiles_p
- /* Simple workaround to prevent classifying the partition as builtin
- if it contains any use outside of loop. */
- || has_reduction
- || !flag_tree_loop_distribute_patterns)
- return;
+ data_reference_p single_ld = NULL, single_st = NULL;
+ bitmap_iterator bi;
- /* Detect memset and memcpy. */
- single_load = NULL;
- single_store = NULL;
EXECUTE_IF_SET_IN_BITMAP (partition->stmts, 0, i, bi)
{
gimple *stmt = RDG_STMT (rdg, i);
data_reference_p dr;
- unsigned j;
if (gimple_code (stmt) == GIMPLE_PHI)
continue;
@@ -1380,107 +1315,324 @@ classify_partition (loop_p loop, struct graph *rdg, partition *partition,
/* Otherwise just regular loads/stores. */
if (!gimple_assign_single_p (stmt))
- return;
+ return false;
/* But exactly one store and/or load. */
- for (j = 0; RDG_DATAREFS (rdg, i).iterate (j, &dr); ++j)
+ for (unsigned j = 0; RDG_DATAREFS (rdg, i).iterate (j, &dr); ++j)
{
tree type = TREE_TYPE (DR_REF (dr));
/* The memset, memcpy and memmove library calls are only
able to deal with generic address space. */
if (!ADDR_SPACE_GENERIC_P (TYPE_ADDR_SPACE (type)))
- return;
+ return false;
if (DR_IS_READ (dr))
{
- if (single_load != NULL)
- return;
- single_load = dr;
+ if (single_ld != NULL)
+ return false;
+ single_ld = dr;
}
else
{
- if (single_store != NULL)
- return;
- single_store = dr;
+ if (single_st != NULL)
+ return false;
+ single_st = dr;
}
}
}
- if (!single_store)
- return;
+ if (!single_st)
+ return false;
- nb_iter = number_of_latch_executions (loop);
- gcc_assert (nb_iter && nb_iter != chrec_dont_know);
- if (dominated_by_p (CDI_DOMINATORS, single_exit (loop)->src,
- gimple_bb (DR_STMT (single_store))))
- plus_one = true;
+ /* Bail out if this is a bitfield memory reference. */
+ if (TREE_CODE (DR_REF (single_st)) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (DR_REF (single_st), 1)))
+ return false;
- if (single_store && !single_load)
- {
- gimple *stmt = DR_STMT (single_store);
- tree rhs = gimple_assign_rhs1 (stmt);
- if (const_with_all_bytes_same (rhs) == -1
- && (!INTEGRAL_TYPE_P (TREE_TYPE (rhs))
- || (TYPE_MODE (TREE_TYPE (rhs))
- != TYPE_MODE (unsigned_char_type_node))))
- return;
- if (TREE_CODE (rhs) == SSA_NAME
- && !SSA_NAME_IS_DEFAULT_DEF (rhs)
- && flow_bb_inside_loop_p (loop, gimple_bb (SSA_NAME_DEF_STMT (rhs))))
- return;
- if (!adjacent_dr_p (single_store)
- || !dominated_by_p (CDI_DOMINATORS,
- loop->latch, gimple_bb (stmt)))
- return;
- partition->kind = PKIND_MEMSET;
- partition->main_dr = single_store;
- partition->niter = nb_iter;
- partition->plus_one = plus_one;
- }
- else if (single_store && single_load)
+ /* Data reference must be executed exactly once per iteration of each
+ loop in the loop nest. We only need to check dominance information
+ against the outermost one in a perfect loop nest because a bb can't
+ dominate outermost loop's latch without dominating inner loop's. */
+ basic_block bb_st = gimple_bb (DR_STMT (single_st));
+ if (!dominated_by_p (CDI_DOMINATORS, loop->latch, bb_st))
+ return false;
+
+ if (single_ld)
{
- gimple *store = DR_STMT (single_store);
- gimple *load = DR_STMT (single_load);
+ gimple *store = DR_STMT (single_st), *load = DR_STMT (single_ld);
/* Direct aggregate copy or via an SSA name temporary. */
if (load != store
&& gimple_assign_lhs (load) != gimple_assign_rhs1 (store))
- return;
- if (!adjacent_dr_p (single_store)
- || !adjacent_dr_p (single_load)
- || !operand_equal_p (DR_STEP (single_store),
- DR_STEP (single_load), 0)
- || !dominated_by_p (CDI_DOMINATORS,
- loop->latch, gimple_bb (store)))
- return;
- /* Now check that if there is a dependence this dependence is
- of a suitable form for memmove. */
- ddr_p ddr = get_data_dependence (rdg, single_load, single_store);
- if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know)
- return;
+ return false;
+
+ /* Bail out if this is a bitfield memory reference. */
+ if (TREE_CODE (DR_REF (single_ld)) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (DR_REF (single_ld), 1)))
+ return false;
+
+ /* Load and store must be in the same loop nest. */
+ basic_block bb_ld = gimple_bb (DR_STMT (single_ld));
+ if (bb_st->loop_father != bb_ld->loop_father)
+ return false;
+
+ /* Data reference must be executed exactly once per iteration.
+ Same as single_st, we only need to check against the outermost
+ loop. */
+ if (!dominated_by_p (CDI_DOMINATORS, loop->latch, bb_ld))
+ return false;
+
+ edge e = single_exit (bb_st->loop_father);
+ bool dom_ld = dominated_by_p (CDI_DOMINATORS, e->src, bb_ld);
+ bool dom_st = dominated_by_p (CDI_DOMINATORS, e->src, bb_st);
+ if (dom_ld != dom_st)
+ return false;
+ }
+
+ *src_dr = single_ld;
+ *dst_dr = single_st;
+ return true;
+}
+
+/* Given data reference DR in LOOP_NEST, this function checks the enclosing
+ loops from inner to outer to see if loop's step equals to access size at
+ each level of loop. Return true if yes; record access base and size in
+ BASE and SIZE; save loop's step at each level of loop in STEPS if it is
+ not null. For example:
+
+ int arr[100][100][100];
+ for (i = 0; i < 100; i++) ;steps[2] = 40000
+ for (j = 100; j > 0; j--) ;steps[1] = -400
+ for (k = 0; k < 100; k++) ;steps[0] = 4
+ arr[i][j - 1][k] = 0; ;base = &arr, size = 4000000. */
+
+static bool
+compute_access_range (loop_p loop_nest, data_reference_p dr, tree *base,
+ tree *size, vec<tree> *steps = NULL)
+{
+ location_t loc = gimple_location (DR_STMT (dr));
+ basic_block bb = gimple_bb (DR_STMT (dr));
+ struct loop *loop = bb->loop_father;
+ tree ref = DR_REF (dr);
+ tree access_base = build_fold_addr_expr (ref);
+ tree access_size = TYPE_SIZE_UNIT (TREE_TYPE (ref));
+
+ do {
+ tree scev_fn = analyze_scalar_evolution (loop, access_base);
+ if (TREE_CODE (scev_fn) != POLYNOMIAL_CHREC)
+ return false;
+
+ access_base = CHREC_LEFT (scev_fn);
+ if (tree_contains_chrecs (access_base, NULL))
+ return false;
+
+ tree scev_step = CHREC_RIGHT (scev_fn);
+ /* Only support constant steps. */
+ if (TREE_CODE (scev_step) != INTEGER_CST)
+ return false;
- if (DDR_ARE_DEPENDENT (ddr) != chrec_known)
+ enum ev_direction access_dir = scev_direction (scev_fn);
+ if (access_dir == EV_DIR_UNKNOWN)
+ return false;
+
+ if (steps != NULL)
+ steps->safe_push (scev_step);
+
+ scev_step = fold_convert_loc (loc, sizetype, scev_step);
+ /* Compute absolute value of scev step. */
+ if (access_dir == EV_DIR_DECREASES)
+ scev_step = fold_build1_loc (loc, NEGATE_EXPR, sizetype, scev_step);
+
+ /* At each level of loop, scev step must equal to access size. In other
+ words, DR must access consecutive memory between loop iterations. */
+ if (!operand_equal_p (scev_step, access_size, 0))
+ return false;
+
+ /* Compute DR's execution times in loop. */
+ tree niters = number_of_latch_executions (loop);
+ niters = fold_convert_loc (loc, sizetype, niters);
+ if (dominated_by_p (CDI_DOMINATORS, single_exit (loop)->src, bb))
+ niters = size_binop_loc (loc, PLUS_EXPR, niters, size_one_node);
+
+ /* Compute DR's overall access size in loop. */
+ access_size = fold_build2_loc (loc, MULT_EXPR, sizetype,
+ niters, scev_step);
+ /* Adjust base address in case of negative step. */
+ if (access_dir == EV_DIR_DECREASES)
{
- if (DDR_NUM_DIST_VECTS (ddr) == 0)
- return;
+ tree adj = fold_build2_loc (loc, MINUS_EXPR, sizetype,
+ scev_step, access_size);
+ access_base = fold_build_pointer_plus_loc (loc, access_base, adj);
+ }
+ } while (loop != loop_nest && (loop = loop_outer (loop)) != NULL);
+
+ *base = access_base;
+ *size = access_size;
+ return true;
+}
+
+/* Allocate and return builtin struct. Record information like DST_DR,
+ SRC_DR, DST_BASE, SRC_BASE and SIZE in the allocated struct. */
+
+static struct builtin_info *
+alloc_builtin (data_reference_p dst_dr, data_reference_p src_dr,
+ tree dst_base, tree src_base, tree size)
+{
+ struct builtin_info *builtin = XNEW (struct builtin_info);
+ builtin->dst_dr = dst_dr;
+ builtin->src_dr = src_dr;
+ builtin->dst_base = dst_base;
+ builtin->src_base = src_base;
+ builtin->size = size;
+ return builtin;
+}
+
+/* Given data reference DR in loop nest LOOP, classify if it forms builtin
+ memset call. */
+
+static void
+classify_builtin_st (loop_p loop, partition *partition, data_reference_p dr)
+{
+ gimple *stmt = DR_STMT (dr);
+ tree base, size, rhs = gimple_assign_rhs1 (stmt);
+
+ if (const_with_all_bytes_same (rhs) == -1
+ && (!INTEGRAL_TYPE_P (TREE_TYPE (rhs))
+ || (TYPE_MODE (TREE_TYPE (rhs))
+ != TYPE_MODE (unsigned_char_type_node))))
+ return;
+
+ if (TREE_CODE (rhs) == SSA_NAME
+ && !SSA_NAME_IS_DEFAULT_DEF (rhs)
+ && flow_bb_inside_loop_p (loop, gimple_bb (SSA_NAME_DEF_STMT (rhs))))
+ return;
+
+ if (!compute_access_range (loop, dr, &base, &size))
+ return;
+
+ struct builtin_info *builtin;
+ builtin = alloc_builtin (dr, NULL, base, NULL_TREE, size);
+ builtin->dst_base_base = strip_offset (builtin->dst_base,
+ &builtin->dst_base_offset);
+ partition->builtin = builtin;
+ partition->kind = PKIND_MEMSET;
+}
+
+/* Given data references DST_DR and SRC_DR in loop nest LOOP and RDG, classify
+ if it forms builtin memcpy or memmove call. */
+
+static void
+classify_builtin_ldst (loop_p loop, struct graph *rdg, partition *partition,
+ data_reference_p dst_dr, data_reference_p src_dr)
+{
+ tree base, size, src_base, src_size;
+ auto_vec<tree> dst_steps, src_steps;
+
+ /* Compute access range of both load and store. They much have the same
+ access size. */
+ if (!compute_access_range (loop, dst_dr, &base, &size, &dst_steps)
+ || !compute_access_range (loop, src_dr, &src_base, &src_size, &src_steps)
+ || !operand_equal_p (size, src_size, 0))
+ return;
+
+ /* Load and store in loop nest must access memory in the same way, i.e,
+ their must have the same steps in each loop of the nest. */
+ if (dst_steps.length () != src_steps.length ())
+ return;
+ for (unsigned i = 0; i < dst_steps.length (); ++i)
+ if (!operand_equal_p (dst_steps[i], src_steps[i], 0))
+ return;
+
+ /* Now check that if there is a dependence. */
+ ddr_p ddr = get_data_dependence (rdg, src_dr, dst_dr);
+
+ /* Classify as memcpy if no dependence between load and store. */
+ if (DDR_ARE_DEPENDENT (ddr) == chrec_known)
+ {
+ partition->builtin = alloc_builtin (dst_dr, src_dr, base, src_base, size);
+ partition->kind = PKIND_MEMCPY;
+ return;
+ }
+
+ /* Can't do memmove in case of unknown dependence or dependence without
+ classical distance vector. */
+ if (DDR_ARE_DEPENDENT (ddr) == chrec_dont_know
+ || DDR_NUM_DIST_VECTS (ddr) == 0)
+ return;
+
+ unsigned i;
+ lambda_vector dist_v;
+ int num_lev = (DDR_LOOP_NEST (ddr)).length ();
+ FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v)
+ {
+ unsigned dep_lev = dependence_level (dist_v, num_lev);
+ /* Can't do memmove if load depends on store. */
+ if (dep_lev > 0 && dist_v[dep_lev - 1] > 0 && !DDR_REVERSED_P (ddr))
+ return;
+ }
+
+ partition->builtin = alloc_builtin (dst_dr, src_dr, base, src_base, size);
+ partition->kind = PKIND_MEMMOVE;
+ return;
+}
- lambda_vector dist_v;
- FOR_EACH_VEC_ELT (DDR_DIST_VECTS (ddr), i, dist_v)
+/* Classifies the builtin kind we can generate for PARTITION of RDG and LOOP.
+ For the moment we detect memset, memcpy and memmove patterns. Bitmap
+ STMT_IN_ALL_PARTITIONS contains statements belonging to all partitions. */
+
+static void
+classify_partition (loop_p loop, struct graph *rdg, partition *partition,
+ bitmap stmt_in_all_partitions)
+{
+ bitmap_iterator bi;
+ unsigned i;
+ data_reference_p single_ld = NULL, single_st = NULL;
+ bool volatiles_p = false, has_reduction = false;
+
+ EXECUTE_IF_SET_IN_BITMAP (partition->stmts, 0, i, bi)
+ {
+ gimple *stmt = RDG_STMT (rdg, i);
+
+ if (gimple_has_volatile_ops (stmt))
+ volatiles_p = true;
+
+ /* If the stmt is not included by all partitions and there is uses
+ outside of the loop, then mark the partition as reduction. */
+ if (stmt_has_scalar_dependences_outside_loop (loop, stmt))
+ {
+ /* Due to limitation in the transform phase we have to fuse all
+ reduction partitions. As a result, this could cancel valid
+ loop distribution especially for loop that induction variable
+ is used outside of loop. To workaround this issue, we skip
+ marking partition as reudction if the reduction stmt belongs
+ to all partitions. In such case, reduction will be computed
+ correctly no matter how partitions are fused/distributed. */
+ if (!bitmap_bit_p (stmt_in_all_partitions, i))
{
- int dist = dist_v[index_in_loop_nest (loop->num,
- DDR_LOOP_NEST (ddr))];
- if (dist > 0 && !DDR_REVERSED_P (ddr))
- return;
+ partition->reduction_p = true;
+ return;
}
- partition->kind = PKIND_MEMMOVE;
+ has_reduction = true;
}
- else
- partition->kind = PKIND_MEMCPY;
- partition->main_dr = single_store;
- partition->secondary_dr = single_load;
- partition->niter = nb_iter;
- partition->plus_one = plus_one;
}
+
+ /* Perform general partition disqualification for builtins. */
+ if (volatiles_p
+ /* Simple workaround to prevent classifying the partition as builtin
+ if it contains any use outside of loop. */
+ || has_reduction
+ || !flag_tree_loop_distribute_patterns)
+ return;
+
+ /* Find single load/store data references for builtin partition. */
+ if (!find_single_drs (loop, rdg, partition, &single_st, &single_ld))
+ return;
+
+ /* Classify the builtin kind. */
+ if (single_ld == NULL)
+ classify_builtin_st (loop, partition, single_st);
+ else
+ classify_builtin_ldst (loop, rdg, partition, single_st, single_ld);
}
/* Returns true when PARTITION1 and PARTITION2 access the same memory
@@ -1939,7 +2091,8 @@ build_partition_graph (struct graph *rdg,
return pg;
}
-/* Sort partitions in PG by post order and store them in PARTITIONS. */
+/* Sort partitions in PG in descending post order and store them in
+ PARTITIONS. */
static void
sort_partitions_by_post_order (struct graph *pg,
@@ -1948,7 +2101,7 @@ sort_partitions_by_post_order (struct graph *pg,
int i;
struct pg_vdata *data;
- /* Now order the remaining nodes in postorder. */
+ /* Now order the remaining nodes in descending postorder. */
qsort (pg->vertices, pg->n_vertices, sizeof (vertex), pgcmp);
partitions->truncate (0);
for (i = 0; i < pg->n_vertices; ++i)
@@ -1960,16 +2113,18 @@ sort_partitions_by_post_order (struct graph *pg,
}
/* Given reduced dependence graph RDG merge strong connected components
- of PARTITIONS. In this function, data dependence caused by possible
- alias between references is ignored, as if it doesn't exist at all. */
+ of PARTITIONS. If IGNORE_ALIAS_P is true, data dependence caused by
+ possible alias between references is ignored, as if it doesn't exist
+ at all; otherwise all depdendences are considered. */
static void
merge_dep_scc_partitions (struct graph *rdg,
- vec<struct partition *> *partitions)
+ vec<struct partition *> *partitions,
+ bool ignore_alias_p)
{
struct partition *partition1, *partition2;
struct pg_vdata *data;
- graph *pg = build_partition_graph (rdg, partitions, true);
+ graph *pg = build_partition_graph (rdg, partitions, ignore_alias_p);
int i, j, num_sccs = graphds_scc (pg, NULL);
/* Strong connected compoenent means dependence cycle, we cannot distribute
@@ -2044,7 +2199,7 @@ break_alias_scc_partitions (struct graph *rdg,
vec<struct partition *> *partitions,
vec<ddr_p> *alias_ddrs)
{
- int i, j, num_sccs, num_sccs_no_alias;
+ int i, j, k, num_sccs, num_sccs_no_alias;
/* Build partition dependence graph. */
graph *pg = build_partition_graph (rdg, partitions, false);
@@ -2061,7 +2216,7 @@ break_alias_scc_partitions (struct graph *rdg,
auto_vec<enum partition_type> scc_types;
struct partition *partition, *first;
- /* If all paritions in a SCC has the same type, we can simply merge the
+ /* If all partitions in a SCC have the same type, we can simply merge the
SCC. This loop finds out such SCCS and record them in bitmap. */
bitmap_set_range (sccs_to_merge, 0, (unsigned) num_sccs);
for (i = 0; i < num_sccs; ++i)
@@ -2074,6 +2229,10 @@ break_alias_scc_partitions (struct graph *rdg,
if (pg->vertices[j].component != i)
continue;
+ /* Note we Merge partitions of parallel type on purpose, though
+ the result partition is sequential. The reason is vectorizer
+ can do more accurate runtime alias check in this case. Also
+ it results in more conservative distribution. */
if (first->type != partition->type)
{
bitmap_clear_bit (sccs_to_merge, i);
@@ -2095,7 +2254,7 @@ break_alias_scc_partitions (struct graph *rdg,
if (bitmap_count_bits (sccs_to_merge) != (unsigned) num_sccs)
{
/* Run SCC finding algorithm again, with alias dependence edges
- skipped. This is to topologically sort paritions according to
+ skipped. This is to topologically sort partitions according to
compilation time known dependence. Note the topological order
is stored in the form of pg's post order number. */
num_sccs_no_alias = graphds_scc (pg, NULL, pg_skip_alias_edge);
@@ -2117,19 +2276,29 @@ break_alias_scc_partitions (struct graph *rdg,
for (j = 0; partitions->iterate (j, &first); ++j)
if (cbdata.vertices_component[j] == i)
break;
- for (++j; partitions->iterate (j, &partition); ++j)
+ for (k = j + 1; partitions->iterate (k, &partition); ++k)
{
struct pg_vdata *data;
- if (cbdata.vertices_component[j] != i)
+ if (cbdata.vertices_component[k] != i)
continue;
+ /* Update postorder number so that merged reduction partition is
+ sorted after other partitions. */
+ if (!partition_reduction_p (first)
+ && partition_reduction_p (partition))
+ {
+ gcc_assert (pg->vertices[k].post < pg->vertices[j].post);
+ pg->vertices[j].post = pg->vertices[k].post;
+ }
partition_merge_into (NULL, first, partition, FUSE_SAME_SCC);
- (*partitions)[j] = NULL;
+ (*partitions)[k] = NULL;
partition_free (partition);
- data = (struct pg_vdata *)pg->vertices[j].data;
- gcc_assert (data->id == j);
+ data = (struct pg_vdata *)pg->vertices[k].data;
+ gcc_assert (data->id == k);
data->partition = NULL;
+ /* The result partition of merged SCC must be sequential. */
+ first->type = PTYPE_SEQUENTIAL;
}
}
}
@@ -2321,38 +2490,160 @@ version_for_distribution_p (vec<struct partition *> *partitions,
return (alias_ddrs->length () > 0);
}
-/* Fuse all partitions if necessary before finalizing distribution. */
+/* Compare base offset of builtin mem* partitions P1 and P2. */
+
+static bool
+offset_cmp (struct partition *p1, struct partition *p2)
+{
+ gcc_assert (p1 != NULL && p1->builtin != NULL);
+ gcc_assert (p2 != NULL && p2->builtin != NULL);
+ return p1->builtin->dst_base_offset < p2->builtin->dst_base_offset;
+}
+
+/* Fuse adjacent memset builtin PARTITIONS if possible. This is a special
+ case optimization transforming below code:
+
+ __builtin_memset (&obj, 0, 100);
+ _1 = &obj + 100;
+ __builtin_memset (_1, 0, 200);
+ _2 = &obj + 300;
+ __builtin_memset (_2, 0, 100);
+
+ into:
+
+ __builtin_memset (&obj, 0, 400);
+
+ Note we don't have dependence information between different partitions
+ at this point, as a result, we can't handle nonadjacent memset builtin
+ partitions since dependence might be broken. */
+
+static void
+fuse_memset_builtins (vec<struct partition *> *partitions)
+{
+ unsigned i, j;
+ struct partition *part1, *part2;
+
+ for (i = 0; partitions->iterate (i, &part1);)
+ {
+ if (part1->kind != PKIND_MEMSET)
+ {
+ i++;
+ continue;
+ }
+
+ /* Find sub-array of memset builtins of the same base. Index range
+ of the sub-array is [i, j) with "j > i". */
+ for (j = i + 1; partitions->iterate (j, &part2); ++j)
+ {
+ if (part2->kind != PKIND_MEMSET
+ || !operand_equal_p (part1->builtin->dst_base_base,
+ part2->builtin->dst_base_base, 0))
+ break;
+ }
+
+ /* Stable sort is required in order to avoid breaking dependence. */
+ std::stable_sort (&(*partitions)[i],
+ &(*partitions)[i] + j - i, offset_cmp);
+ /* Continue with next partition. */
+ i = j;
+ }
+
+ /* Merge all consecutive memset builtin partitions. */
+ for (i = 0; i < partitions->length () - 1;)
+ {
+ part1 = (*partitions)[i];
+ if (part1->kind != PKIND_MEMSET)
+ {
+ i++;
+ continue;
+ }
+
+ part2 = (*partitions)[i + 1];
+ /* Only merge memset partitions of the same base and with constant
+ access sizes. */
+ if (part2->kind != PKIND_MEMSET
+ || TREE_CODE (part1->builtin->size) != INTEGER_CST
+ || TREE_CODE (part2->builtin->size) != INTEGER_CST
+ || !operand_equal_p (part1->builtin->dst_base_base,
+ part2->builtin->dst_base_base, 0))
+ {
+ i++;
+ continue;
+ }
+ tree rhs1 = gimple_assign_rhs1 (DR_STMT (part1->builtin->dst_dr));
+ tree rhs2 = gimple_assign_rhs1 (DR_STMT (part2->builtin->dst_dr));
+ int bytev1 = const_with_all_bytes_same (rhs1);
+ int bytev2 = const_with_all_bytes_same (rhs2);
+ /* Only merge memset partitions of the same value. */
+ if (bytev1 != bytev2 || bytev1 == -1)
+ {
+ i++;
+ continue;
+ }
+ wide_int end1 = wi::add (part1->builtin->dst_base_offset,
+ wi::to_wide (part1->builtin->size));
+ /* Only merge adjacent memset partitions. */
+ if (wi::ne_p (end1, part2->builtin->dst_base_offset))
+ {
+ i++;
+ continue;
+ }
+ /* Merge partitions[i] and partitions[i+1]. */
+ part1->builtin->size = fold_build2 (PLUS_EXPR, sizetype,
+ part1->builtin->size,
+ part2->builtin->size);
+ partition_free (part2);
+ partitions->ordered_remove (i + 1);
+ }
+}
+
+/* Fuse PARTITIONS of LOOP if necessary before finalizing distribution.
+ ALIAS_DDRS contains ddrs which need runtime alias check. */
static void
-finalize_partitions (vec<struct partition *> *partitions,
+finalize_partitions (struct loop *loop, vec<struct partition *> *partitions,
vec<ddr_p> *alias_ddrs)
{
unsigned i;
- struct partition *a, *partition;
+ struct partition *partition, *a;
if (partitions->length () == 1
|| alias_ddrs->length () > 0)
return;
- a = (*partitions)[0];
- if (a->kind != PKIND_NORMAL)
- return;
-
- for (i = 1; partitions->iterate (i, &partition); ++i)
+ unsigned num_builtin = 0, num_normal = 0;
+ bool same_type_p = true;
+ enum partition_type type = ((*partitions)[0])->type;
+ for (i = 0; partitions->iterate (i, &partition); ++i)
{
- /* Don't fuse if partition has different type or it is a builtin. */
- if (partition->type != a->type
- || partition->kind != PKIND_NORMAL)
- return;
+ same_type_p &= (type == partition->type);
+ if (partition->kind != PKIND_NORMAL)
+ num_builtin++;
+ else
+ num_normal++;
}
- /* Fuse all partitions. */
- for (i = 1; partitions->iterate (i, &partition); ++i)
+ /* Don't distribute current loop into too many loops given we don't have
+ memory stream cost model. Be even more conservative in case of loop
+ nest distribution. */
+ if ((same_type_p && num_builtin == 0)
+ || (loop->inner != NULL
+ && i >= NUM_PARTITION_THRESHOLD && num_normal > 1)
+ || (loop->inner == NULL
+ && i >= NUM_PARTITION_THRESHOLD && num_normal > num_builtin))
{
- partition_merge_into (NULL, a, partition, FUSE_FINALIZE);
- partition_free (partition);
+ a = (*partitions)[0];
+ for (i = 1; partitions->iterate (i, &partition); ++i)
+ {
+ partition_merge_into (NULL, a, partition, FUSE_FINALIZE);
+ partition_free (partition);
+ }
+ partitions->truncate (1);
}
- partitions->truncate (1);
+
+ /* Fuse memset builtins if possible. */
+ if (partitions->length () > 1)
+ fuse_memset_builtins (partitions);
}
/* Distributes the code from LOOP in such a way that producer statements
@@ -2505,16 +2796,23 @@ distribute_loop (struct loop *loop, vec<gimple *> stmts,
i--;
}
- /* Build the partition dependency graph. */
+ /* Build the partition dependency graph and fuse partitions in strong
+ connected component. */
if (partitions.length () > 1)
{
- merge_dep_scc_partitions (rdg, &partitions);
- alias_ddrs.truncate (0);
- if (partitions.length () > 1)
- break_alias_scc_partitions (rdg, &partitions, &alias_ddrs);
+ /* Don't support loop nest distribution under runtime alias check
+ since it's not likely to enable many vectorization opportunities. */
+ if (loop->inner)
+ merge_dep_scc_partitions (rdg, &partitions, false);
+ else
+ {
+ merge_dep_scc_partitions (rdg, &partitions, true);
+ if (partitions.length () > 1)
+ break_alias_scc_partitions (rdg, &partitions, &alias_ddrs);
+ }
}
- finalize_partitions (&partitions, &alias_ddrs);
+ finalize_partitions (loop, &partitions, &alias_ddrs);
nbp = partitions.length ();
if (nbp == 0
@@ -2595,6 +2893,86 @@ public:
}; // class pass_loop_distribution
+
+/* Given LOOP, this function records seed statements for distribution in
+ WORK_LIST. Return false if there is nothing for distribution. */
+
+static bool
+find_seed_stmts_for_distribution (struct loop *loop, vec<gimple *> *work_list)
+{
+ basic_block *bbs = get_loop_body_in_dom_order (loop);
+
+ /* Initialize the worklist with stmts we seed the partitions with. */
+ for (unsigned i = 0; i < loop->num_nodes; ++i)
+ {
+ for (gphi_iterator gsi = gsi_start_phis (bbs[i]);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gphi *phi = gsi.phi ();
+ if (virtual_operand_p (gimple_phi_result (phi)))
+ continue;
+ /* Distribute stmts which have defs that are used outside of
+ the loop. */
+ if (!stmt_has_scalar_dependences_outside_loop (loop, phi))
+ continue;
+ work_list->safe_push (phi);
+ }
+ for (gimple_stmt_iterator gsi = gsi_start_bb (bbs[i]);
+ !gsi_end_p (gsi); gsi_next (&gsi))
+ {
+ gimple *stmt = gsi_stmt (gsi);
+
+ /* If there is a stmt with side-effects bail out - we
+ cannot and should not distribute this loop. */
+ if (gimple_has_side_effects (stmt))
+ {
+ free (bbs);
+ return false;
+ }
+
+ /* Distribute stmts which have defs that are used outside of
+ the loop. */
+ if (stmt_has_scalar_dependences_outside_loop (loop, stmt))
+ ;
+ /* Otherwise only distribute stores for now. */
+ else if (!gimple_vdef (stmt))
+ continue;
+
+ work_list->safe_push (stmt);
+ }
+ }
+ free (bbs);
+ return work_list->length () > 0;
+}
+
+/* Given innermost LOOP, return the outermost enclosing loop that forms a
+ perfect loop nest. */
+
+static struct loop *
+prepare_perfect_loop_nest (struct loop *loop)
+{
+ struct loop *outer = loop_outer (loop);
+ tree niters = number_of_latch_executions (loop);
+
+ /* TODO: We only support the innermost 2-level loop nest distribution
+ because of compilation time issue for now. This should be relaxed
+ in the future. */
+ while (loop->inner == NULL
+ && loop_outer (outer)
+ && outer->inner == loop && loop->next == NULL
+ && single_exit (outer)
+ && optimize_loop_for_speed_p (outer)
+ && !chrec_contains_symbols_defined_in_loop (niters, outer->num)
+ && (niters = number_of_latch_executions (outer)) != NULL_TREE
+ && niters != chrec_dont_know)
+ {
+ loop = outer;
+ outer = loop_outer (loop);
+ }
+
+ return loop;
+}
+
unsigned int
pass_loop_distribution::execute (function *fun)
{
@@ -2637,18 +3015,9 @@ pass_loop_distribution::execute (function *fun)
walking to innermost loops. */
FOR_EACH_LOOP (loop, LI_ONLY_INNERMOST)
{
- auto_vec<gimple *> work_list;
- basic_block *bbs;
- int num = loop->num;
- unsigned int i;
-
- /* If the loop doesn't have a single exit we will fail anyway,
- so do that early. */
- if (!single_exit (loop))
- continue;
-
- /* Only optimize hot loops. */
- if (!optimize_loop_for_speed_p (loop))
+ /* Don't distribute multiple exit edges loop, or cold loop. */
+ if (!single_exit (loop)
+ || !optimize_loop_for_speed_p (loop))
continue;
/* Don't distribute loop if niters is unknown. */
@@ -2656,56 +3025,16 @@ pass_loop_distribution::execute (function *fun)
if (niters == NULL_TREE || niters == chrec_dont_know)
continue;
- /* Initialize the worklist with stmts we seed the partitions with. */
- bbs = get_loop_body_in_dom_order (loop);
- for (i = 0; i < loop->num_nodes; ++i)
+ /* Get the perfect loop nest for distribution. */
+ loop = prepare_perfect_loop_nest (loop);
+ for (; loop; loop = loop->inner)
{
- for (gphi_iterator gsi = gsi_start_phis (bbs[i]);
- !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gphi *phi = gsi.phi ();
- if (virtual_operand_p (gimple_phi_result (phi)))
- continue;
- /* Distribute stmts which have defs that are used outside of
- the loop. */
- if (!stmt_has_scalar_dependences_outside_loop (loop, phi))
- continue;
- work_list.safe_push (phi);
- }
- for (gimple_stmt_iterator gsi = gsi_start_bb (bbs[i]);
- !gsi_end_p (gsi);
- gsi_next (&gsi))
- {
- gimple *stmt = gsi_stmt (gsi);
+ auto_vec<gimple *> work_list;
+ if (!find_seed_stmts_for_distribution (loop, &work_list))
+ break;
- /* If there is a stmt with side-effects bail out - we
- cannot and should not distribute this loop. */
- if (gimple_has_side_effects (stmt))
- {
- work_list.truncate (0);
- goto out;
- }
-
- /* Distribute stmts which have defs that are used outside of
- the loop. */
- if (stmt_has_scalar_dependences_outside_loop (loop, stmt))
- ;
- /* Otherwise only distribute stores for now. */
- else if (!gimple_vdef (stmt))
- continue;
-
- work_list.safe_push (stmt);
- }
- }
-out:
- free (bbs);
-
- int nb_generated_loops = 0;
- int nb_generated_calls = 0;
- location_t loc = find_loop_location (loop);
- if (work_list.length () > 0)
- {
+ const char *str = loop->inner ? " nest" : "";
+ location_t loc = find_loop_location (loop);
if (!cd)
{
calculate_dominance_info (CDI_DOMINATORS);
@@ -2713,24 +3042,29 @@ out:
cd = new control_dependences ();
free_dominance_info (CDI_POST_DOMINATORS);
}
+
bool destroy_p;
+ int nb_generated_loops, nb_generated_calls;
nb_generated_loops = distribute_loop (loop, work_list, cd,
&nb_generated_calls,
&destroy_p);
if (destroy_p)
loops_to_be_destroyed.safe_push (loop);
- }
- if (nb_generated_loops + nb_generated_calls > 0)
- {
- changed = true;
- dump_printf_loc (MSG_OPTIMIZED_LOCATIONS,
- loc, "Loop %d distributed: split to %d loops "
- "and %d library calls.\n",
- num, nb_generated_loops, nb_generated_calls);
+ if (nb_generated_loops + nb_generated_calls > 0)
+ {
+ changed = true;
+ dump_printf_loc (MSG_OPTIMIZED_LOCATIONS,
+ loc, "Loop%s %d distributed: split to %d loops "
+ "and %d library calls.\n", str, loop->num,
+ nb_generated_loops, nb_generated_calls);
+
+ break;
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Loop%s %d not distributed.\n", str, loop->num);
}
- else if (dump_file && (dump_flags & TDF_DETAILS))
- fprintf (dump_file, "Loop %d is the same.\n", num);
}
if (cd)
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index a56b78a..d45f50d 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -430,8 +430,7 @@ alloc_object_size (const gcall *call, int object_size_type)
arg2 = 1;
/* fall through */
case BUILT_IN_MALLOC:
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
arg1 = 0;
default:
break;
diff --git a/gcc/tree-outof-ssa.c b/gcc/tree-outof-ssa.c
index 0ce6c15..6327c07 100644
--- a/gcc/tree-outof-ssa.c
+++ b/gcc/tree-outof-ssa.c
@@ -969,6 +969,7 @@ remove_ssa_form (bool perform_ter, struct ssaexpand *sa)
sa->map = map;
sa->values = values;
sa->partitions_for_parm_default_defs = get_parm_default_def_partitions (map);
+ sa->partitions_for_undefined_values = get_undefined_value_partitions (map);
}
@@ -1144,6 +1145,7 @@ finish_out_of_ssa (struct ssaexpand *sa)
BITMAP_FREE (sa->values);
delete_var_map (sa->map);
BITMAP_FREE (sa->partitions_for_parm_default_defs);
+ BITMAP_FREE (sa->partitions_for_undefined_values);
memset (sa, 0, sizeof *sa);
}
diff --git a/gcc/tree-outof-ssa.h b/gcc/tree-outof-ssa.h
index e751a26..ebbaea1 100644
--- a/gcc/tree-outof-ssa.h
+++ b/gcc/tree-outof-ssa.h
@@ -42,6 +42,10 @@ struct ssaexpand
/* If partition I contains an SSA name that has a default def for a
parameter, bit I will be set in this bitmap. */
bitmap partitions_for_parm_default_defs;
+
+ /* If partition I contains an SSA name that has an undefined value,
+ bit I will be set in this bitmap. */
+ bitmap partitions_for_undefined_values;
};
/* This is the singleton described above. */
diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
index 9f76d82..9777308 100644
--- a/gcc/tree-pass.h
+++ b/gcc/tree-pass.h
@@ -223,6 +223,7 @@ protected:
current choices have
been optimized. */
#define PROP_gimple_lomp_dev (1 << 16) /* done omp_device_lower */
+#define PROP_rtl_split_insns (1 << 17) /* RTL has insns split. */
#define PROP_trees \
(PROP_gimple_any | PROP_gimple_lcf | PROP_gimple_leh | PROP_gimple_lomp)
diff --git a/gcc/tree-predcom.c b/gcc/tree-predcom.c
index e7b10cb..fdb32f1 100644
--- a/gcc/tree-predcom.c
+++ b/gcc/tree-predcom.c
@@ -1655,7 +1655,8 @@ is_inv_store_elimination_chain (struct loop *loop, chain_p chain)
/* If loop iterates for unknown times or fewer times than chain->lenght,
we still need to setup root variable and propagate it with PHI node. */
tree niters = number_of_latch_executions (loop);
- if (TREE_CODE (niters) != INTEGER_CST || wi::leu_p (niters, chain->length))
+ if (TREE_CODE (niters) != INTEGER_CST
+ || wi::leu_p (wi::to_wide (niters), chain->length))
return false;
/* Check stores in chain for elimination if they only store loop invariant
diff --git a/gcc/tree-pretty-print.c b/gcc/tree-pretty-print.c
index 14c7caa..61a28c6 100644
--- a/gcc/tree-pretty-print.c
+++ b/gcc/tree-pretty-print.c
@@ -249,8 +249,10 @@ dump_decl_name (pretty_printer *pp, tree node, dump_flags_t flags)
{
if (DECL_NAME (node))
{
- if ((flags & TDF_ASMNAME) && DECL_ASSEMBLER_NAME_SET_P (node))
- pp_tree_identifier (pp, DECL_ASSEMBLER_NAME (node));
+ if ((flags & TDF_ASMNAME)
+ && HAS_DECL_ASSEMBLER_NAME_P (node)
+ && DECL_ASSEMBLER_NAME_SET_P (node))
+ pp_tree_identifier (pp, DECL_ASSEMBLER_NAME_RAW (node));
/* For DECL_NAMELESS names look for embedded uids in the
names and sanitize them for TDF_NOUID. */
else if ((flags & TDF_NOUID) && DECL_NAMELESS (node))
@@ -1710,7 +1712,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
pp_unsigned_wide_integer (pp, tree_to_uhwi (node));
else
{
- wide_int val = node;
+ wide_int val = wi::to_wide (node);
if (wi::neg_p (val, TYPE_SIGN (TREE_TYPE (node))))
{
@@ -2819,8 +2821,7 @@ dump_generic_node (pretty_printer *pp, tree node, int spc, dump_flags_t flags,
dump_generic_node (pp, CHREC_LEFT (node), spc, flags, false);
pp_string (pp, ", +, ");
dump_generic_node (pp, CHREC_RIGHT (node), spc, flags, false);
- pp_string (pp, "}_");
- dump_generic_node (pp, CHREC_VAR (node), spc, flags, false);
+ pp_printf (pp, "}_%u", CHREC_VARIABLE (node));
is_stmt = false;
break;
diff --git a/gcc/tree-scalar-evolution.c b/gcc/tree-scalar-evolution.c
index 8459793..b47b4ed 100644
--- a/gcc/tree-scalar-evolution.c
+++ b/gcc/tree-scalar-evolution.c
@@ -281,7 +281,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-ssa-propagate.h"
#include "gimple-fold.h"
-static tree analyze_scalar_evolution_1 (struct loop *, tree, tree);
+static tree analyze_scalar_evolution_1 (struct loop *, tree);
static tree analyze_scalar_evolution_for_address_of (struct loop *loop,
tree var);
@@ -564,22 +564,30 @@ get_scalar_evolution (basic_block instantiated_below, tree scalar)
nb_get_scev++;
}
- switch (TREE_CODE (scalar))
- {
- case SSA_NAME:
- res = *find_var_scev_info (instantiated_below, scalar);
- break;
+ if (VECTOR_TYPE_P (TREE_TYPE (scalar))
+ || TREE_CODE (TREE_TYPE (scalar)) == COMPLEX_TYPE)
+ /* For chrec_dont_know we keep the symbolic form. */
+ res = scalar;
+ else
+ switch (TREE_CODE (scalar))
+ {
+ case SSA_NAME:
+ if (SSA_NAME_IS_DEFAULT_DEF (scalar))
+ res = scalar;
+ else
+ res = *find_var_scev_info (instantiated_below, scalar);
+ break;
- case REAL_CST:
- case FIXED_CST:
- case INTEGER_CST:
- res = scalar;
- break;
+ case REAL_CST:
+ case FIXED_CST:
+ case INTEGER_CST:
+ res = scalar;
+ break;
- default:
- res = chrec_not_analyzed_yet;
- break;
- }
+ default:
+ res = chrec_not_analyzed_yet;
+ break;
+ }
if (dump_file && (dump_flags & TDF_SCEV))
{
@@ -1628,19 +1636,7 @@ interpret_loop_phi (struct loop *loop, gphi *loop_phi_node)
struct loop *phi_loop = loop_containing_stmt (loop_phi_node);
tree init_cond;
- if (phi_loop != loop)
- {
- struct loop *subloop;
- tree evolution_fn = analyze_scalar_evolution
- (phi_loop, PHI_RESULT (loop_phi_node));
-
- /* Dive one level deeper. */
- subloop = superloop_at_depth (phi_loop, loop_depth (loop) + 1);
-
- /* Interpret the subloop. */
- res = compute_overall_effect_of_inner_loop (subloop, evolution_fn);
- return res;
- }
+ gcc_assert (phi_loop == loop);
/* Otherwise really interpret the loop phi. */
init_cond = analyze_initial_condition (loop_phi_node);
@@ -2016,73 +2012,38 @@ interpret_gimple_assign (struct loop *loop, gimple *stmt)
- instantiate_parameters.
*/
-/* Compute and return the evolution function in WRTO_LOOP, the nearest
- common ancestor of DEF_LOOP and USE_LOOP. */
-
-static tree
-compute_scalar_evolution_in_loop (struct loop *wrto_loop,
- struct loop *def_loop,
- tree ev)
-{
- bool val;
- tree res;
-
- if (def_loop == wrto_loop)
- return ev;
-
- def_loop = superloop_at_depth (def_loop, loop_depth (wrto_loop) + 1);
- res = compute_overall_effect_of_inner_loop (def_loop, ev);
-
- if (no_evolution_in_loop_p (res, wrto_loop->num, &val) && val)
- return res;
-
- return analyze_scalar_evolution_1 (wrto_loop, res, chrec_not_analyzed_yet);
-}
-
/* Helper recursive function. */
static tree
-analyze_scalar_evolution_1 (struct loop *loop, tree var, tree res)
+analyze_scalar_evolution_1 (struct loop *loop, tree var)
{
- tree type = TREE_TYPE (var);
gimple *def;
basic_block bb;
struct loop *def_loop;
-
- if (loop == NULL
- || TREE_CODE (type) == VECTOR_TYPE
- || TREE_CODE (type) == COMPLEX_TYPE)
- return chrec_dont_know;
+ tree res;
if (TREE_CODE (var) != SSA_NAME)
return interpret_expr (loop, NULL, var);
def = SSA_NAME_DEF_STMT (var);
bb = gimple_bb (def);
- def_loop = bb ? bb->loop_father : NULL;
+ def_loop = bb->loop_father;
- if (bb == NULL
- || !flow_bb_inside_loop_p (loop, bb))
+ if (!flow_bb_inside_loop_p (loop, bb))
{
/* Keep symbolic form, but look through obvious copies for constants. */
res = follow_copies_to_constant (var);
goto set_and_end;
}
- if (res != chrec_not_analyzed_yet)
- {
- if (loop != bb->loop_father)
- res = compute_scalar_evolution_in_loop
- (find_common_loop (loop, bb->loop_father), bb->loop_father, res);
-
- goto set_and_end;
- }
-
if (loop != def_loop)
{
- res = analyze_scalar_evolution_1 (def_loop, var, chrec_not_analyzed_yet);
- res = compute_scalar_evolution_in_loop (loop, def_loop, res);
-
+ res = analyze_scalar_evolution_1 (def_loop, var);
+ struct loop *loop_to_skip = superloop_at_depth (def_loop,
+ loop_depth (loop) + 1);
+ res = compute_overall_effect_of_inner_loop (loop_to_skip, res);
+ if (chrec_contains_symbols_defined_in_loop (res, loop->num))
+ res = analyze_scalar_evolution_1 (loop, res);
goto set_and_end;
}
@@ -2134,6 +2095,10 @@ analyze_scalar_evolution (struct loop *loop, tree var)
{
tree res;
+ /* ??? Fix callers. */
+ if (! loop)
+ return var;
+
if (dump_file && (dump_flags & TDF_SCEV))
{
fprintf (dump_file, "(analyze_scalar_evolution \n");
@@ -2144,7 +2109,8 @@ analyze_scalar_evolution (struct loop *loop, tree var)
}
res = get_scalar_evolution (block_before_loop (loop), var);
- res = analyze_scalar_evolution_1 (loop, var, res);
+ if (res == chrec_not_analyzed_yet)
+ res = analyze_scalar_evolution_1 (loop, var);
if (dump_file && (dump_flags & TDF_SCEV))
fprintf (dump_file, ")\n");
@@ -2309,7 +2275,7 @@ eq_idx_scev_info (const void *e1, const void *e2)
static unsigned
get_instantiated_value_entry (instantiate_cache_type &cache,
- tree name, basic_block instantiate_below)
+ tree name, edge instantiate_below)
{
if (!cache.map)
{
@@ -2319,7 +2285,7 @@ get_instantiated_value_entry (instantiate_cache_type &cache,
scev_info_str e;
e.name_version = SSA_NAME_VERSION (name);
- e.instantiated_below = instantiate_below->index;
+ e.instantiated_below = instantiate_below->dest->index;
void **slot = htab_find_slot_with_hash (cache.map, &e,
scev_info_hasher::hash (&e), INSERT);
if (!*slot)
@@ -2363,7 +2329,7 @@ loop_closed_phi_def (tree var)
return NULL_TREE;
}
-static tree instantiate_scev_r (basic_block, struct loop *, struct loop *,
+static tree instantiate_scev_r (edge, struct loop *, struct loop *,
tree, bool *, int);
/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
@@ -2382,7 +2348,7 @@ static tree instantiate_scev_r (basic_block, struct loop *, struct loop *,
instantiated, and to stop if it exceeds some limit. */
static tree
-instantiate_scev_name (basic_block instantiate_below,
+instantiate_scev_name (edge instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
bool *fold_conversions,
@@ -2392,11 +2358,9 @@ instantiate_scev_name (basic_block instantiate_below,
struct loop *def_loop;
basic_block def_bb = gimple_bb (SSA_NAME_DEF_STMT (chrec));
- /* A parameter (or loop invariant and we do not want to include
- evolutions in outer loops), nothing to do. */
+ /* A parameter, nothing to do. */
if (!def_bb
- || loop_depth (def_bb->loop_father) == 0
- || dominated_by_p (CDI_DOMINATORS, instantiate_below, def_bb))
+ || !dominated_by_p (CDI_DOMINATORS, def_bb, instantiate_below->dest))
return chrec;
/* We cache the value of instantiated variable to avoid exponential
@@ -2418,6 +2382,51 @@ instantiate_scev_name (basic_block instantiate_below,
def_loop = find_common_loop (evolution_loop, def_bb->loop_father);
+ if (! dominated_by_p (CDI_DOMINATORS,
+ def_loop->header, instantiate_below->dest))
+ {
+ gimple *def = SSA_NAME_DEF_STMT (chrec);
+ if (gassign *ass = dyn_cast <gassign *> (def))
+ {
+ switch (gimple_assign_rhs_class (ass))
+ {
+ case GIMPLE_UNARY_RHS:
+ {
+ tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
+ inner_loop, gimple_assign_rhs1 (ass),
+ fold_conversions, size_expr);
+ if (op0 == chrec_dont_know)
+ return chrec_dont_know;
+ res = fold_build1 (gimple_assign_rhs_code (ass),
+ TREE_TYPE (chrec), op0);
+ break;
+ }
+ case GIMPLE_BINARY_RHS:
+ {
+ tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
+ inner_loop, gimple_assign_rhs1 (ass),
+ fold_conversions, size_expr);
+ if (op0 == chrec_dont_know)
+ return chrec_dont_know;
+ tree op1 = instantiate_scev_r (instantiate_below, evolution_loop,
+ inner_loop, gimple_assign_rhs2 (ass),
+ fold_conversions, size_expr);
+ if (op1 == chrec_dont_know)
+ return chrec_dont_know;
+ res = fold_build2 (gimple_assign_rhs_code (ass),
+ TREE_TYPE (chrec), op0, op1);
+ break;
+ }
+ default:
+ res = chrec_dont_know;
+ }
+ }
+ else
+ res = chrec_dont_know;
+ global_cache->set (si, res);
+ return res;
+ }
+
/* If the analysis yields a parametric chrec, instantiate the
result again. */
res = analyze_scalar_evolution (def_loop, chrec);
@@ -2449,8 +2458,9 @@ instantiate_scev_name (basic_block instantiate_below,
inner_loop, res,
fold_conversions, size_expr);
}
- else if (!dominated_by_p (CDI_DOMINATORS, instantiate_below,
- gimple_bb (SSA_NAME_DEF_STMT (res))))
+ else if (dominated_by_p (CDI_DOMINATORS,
+ gimple_bb (SSA_NAME_DEF_STMT (res)),
+ instantiate_below->dest))
res = chrec_dont_know;
}
@@ -2488,7 +2498,7 @@ instantiate_scev_name (basic_block instantiate_below,
instantiated, and to stop if it exceeds some limit. */
static tree
-instantiate_scev_poly (basic_block instantiate_below,
+instantiate_scev_poly (edge instantiate_below,
struct loop *evolution_loop, struct loop *,
tree chrec, bool *fold_conversions, int size_expr)
{
@@ -2533,7 +2543,7 @@ instantiate_scev_poly (basic_block instantiate_below,
instantiated, and to stop if it exceeds some limit. */
static tree
-instantiate_scev_binary (basic_block instantiate_below,
+instantiate_scev_binary (edge instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, enum tree_code code,
tree type, tree c0, tree c1,
@@ -2579,43 +2589,6 @@ instantiate_scev_binary (basic_block instantiate_below,
/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
and EVOLUTION_LOOP, that were left under a symbolic form.
- "CHREC" is an array reference to be instantiated.
-
- CACHE is the cache of already instantiated values.
-
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
-
- SIZE_EXPR is used for computing the size of the expression to be
- instantiated, and to stop if it exceeds some limit. */
-
-static tree
-instantiate_array_ref (basic_block instantiate_below,
- struct loop *evolution_loop, struct loop *inner_loop,
- tree chrec, bool *fold_conversions, int size_expr)
-{
- tree res;
- tree index = TREE_OPERAND (chrec, 1);
- tree op1 = instantiate_scev_r (instantiate_below, evolution_loop,
- inner_loop, index,
- fold_conversions, size_expr);
-
- if (op1 == chrec_dont_know)
- return chrec_dont_know;
-
- if (chrec && op1 == index)
- return chrec;
-
- res = unshare_expr (chrec);
- TREE_OPERAND (res, 1) = op1;
- return res;
-}
-
-/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
- and EVOLUTION_LOOP, that were left under a symbolic form.
-
"CHREC" that stands for a convert expression "(TYPE) OP" is to be
instantiated.
@@ -2630,7 +2603,7 @@ instantiate_array_ref (basic_block instantiate_below,
instantiated, and to stop if it exceeds some limit. */
static tree
-instantiate_scev_convert (basic_block instantiate_below,
+instantiate_scev_convert (edge instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec, tree type, tree op,
bool *fold_conversions, int size_expr)
@@ -2681,7 +2654,7 @@ instantiate_scev_convert (basic_block instantiate_below,
instantiated, and to stop if it exceeds some limit. */
static tree
-instantiate_scev_not (basic_block instantiate_below,
+instantiate_scev_not (edge instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
enum tree_code code, tree type, tree op,
@@ -2719,130 +2692,6 @@ instantiate_scev_not (basic_block instantiate_below,
/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
and EVOLUTION_LOOP, that were left under a symbolic form.
- CHREC is an expression with 3 operands to be instantiated.
-
- CACHE is the cache of already instantiated values.
-
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
-
- SIZE_EXPR is used for computing the size of the expression to be
- instantiated, and to stop if it exceeds some limit. */
-
-static tree
-instantiate_scev_3 (basic_block instantiate_below,
- struct loop *evolution_loop, struct loop *inner_loop,
- tree chrec,
- bool *fold_conversions, int size_expr)
-{
- tree op1, op2;
- tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
- inner_loop, TREE_OPERAND (chrec, 0),
- fold_conversions, size_expr);
- if (op0 == chrec_dont_know)
- return chrec_dont_know;
-
- op1 = instantiate_scev_r (instantiate_below, evolution_loop,
- inner_loop, TREE_OPERAND (chrec, 1),
- fold_conversions, size_expr);
- if (op1 == chrec_dont_know)
- return chrec_dont_know;
-
- op2 = instantiate_scev_r (instantiate_below, evolution_loop,
- inner_loop, TREE_OPERAND (chrec, 2),
- fold_conversions, size_expr);
- if (op2 == chrec_dont_know)
- return chrec_dont_know;
-
- if (op0 == TREE_OPERAND (chrec, 0)
- && op1 == TREE_OPERAND (chrec, 1)
- && op2 == TREE_OPERAND (chrec, 2))
- return chrec;
-
- return fold_build3 (TREE_CODE (chrec),
- TREE_TYPE (chrec), op0, op1, op2);
-}
-
-/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
- and EVOLUTION_LOOP, that were left under a symbolic form.
-
- CHREC is an expression with 2 operands to be instantiated.
-
- CACHE is the cache of already instantiated values.
-
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
-
- SIZE_EXPR is used for computing the size of the expression to be
- instantiated, and to stop if it exceeds some limit. */
-
-static tree
-instantiate_scev_2 (basic_block instantiate_below,
- struct loop *evolution_loop, struct loop *inner_loop,
- tree chrec,
- bool *fold_conversions, int size_expr)
-{
- tree op1;
- tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
- inner_loop, TREE_OPERAND (chrec, 0),
- fold_conversions, size_expr);
- if (op0 == chrec_dont_know)
- return chrec_dont_know;
-
- op1 = instantiate_scev_r (instantiate_below, evolution_loop,
- inner_loop, TREE_OPERAND (chrec, 1),
- fold_conversions, size_expr);
- if (op1 == chrec_dont_know)
- return chrec_dont_know;
-
- if (op0 == TREE_OPERAND (chrec, 0)
- && op1 == TREE_OPERAND (chrec, 1))
- return chrec;
-
- return fold_build2 (TREE_CODE (chrec), TREE_TYPE (chrec), op0, op1);
-}
-
-/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
- and EVOLUTION_LOOP, that were left under a symbolic form.
-
- CHREC is an expression with 2 operands to be instantiated.
-
- CACHE is the cache of already instantiated values.
-
- Variable pointed by FOLD_CONVERSIONS is set to TRUE when the
- conversions that may wrap in signed/pointer type are folded, as long
- as the value of the chrec is preserved. If FOLD_CONVERSIONS is NULL
- then we don't do such fold.
-
- SIZE_EXPR is used for computing the size of the expression to be
- instantiated, and to stop if it exceeds some limit. */
-
-static tree
-instantiate_scev_1 (basic_block instantiate_below,
- struct loop *evolution_loop, struct loop *inner_loop,
- tree chrec,
- bool *fold_conversions, int size_expr)
-{
- tree op0 = instantiate_scev_r (instantiate_below, evolution_loop,
- inner_loop, TREE_OPERAND (chrec, 0),
- fold_conversions, size_expr);
-
- if (op0 == chrec_dont_know)
- return chrec_dont_know;
-
- if (op0 == TREE_OPERAND (chrec, 0))
- return chrec;
-
- return fold_build1 (TREE_CODE (chrec), TREE_TYPE (chrec), op0);
-}
-
-/* Analyze all the parameters of the chrec, between INSTANTIATE_BELOW
- and EVOLUTION_LOOP, that were left under a symbolic form.
-
CHREC is the scalar evolution to instantiate.
CACHE is the cache of already instantiated values.
@@ -2856,7 +2705,7 @@ instantiate_scev_1 (basic_block instantiate_below,
instantiated, and to stop if it exceeds some limit. */
static tree
-instantiate_scev_r (basic_block instantiate_below,
+instantiate_scev_r (edge instantiate_below,
struct loop *evolution_loop, struct loop *inner_loop,
tree chrec,
bool *fold_conversions, int size_expr)
@@ -2908,50 +2757,20 @@ instantiate_scev_r (basic_block instantiate_below,
fold_conversions, size_expr);
case ADDR_EXPR:
+ if (is_gimple_min_invariant (chrec))
+ return chrec;
+ /* Fallthru. */
case SCEV_NOT_KNOWN:
return chrec_dont_know;
case SCEV_KNOWN:
return chrec_known;
- case ARRAY_REF:
- return instantiate_array_ref (instantiate_below, evolution_loop,
- inner_loop, chrec,
- fold_conversions, size_expr);
-
- default:
- break;
- }
-
- if (VL_EXP_CLASS_P (chrec))
- return chrec_dont_know;
-
- switch (TREE_CODE_LENGTH (TREE_CODE (chrec)))
- {
- case 3:
- return instantiate_scev_3 (instantiate_below, evolution_loop,
- inner_loop, chrec,
- fold_conversions, size_expr);
-
- case 2:
- return instantiate_scev_2 (instantiate_below, evolution_loop,
- inner_loop, chrec,
- fold_conversions, size_expr);
-
- case 1:
- return instantiate_scev_1 (instantiate_below, evolution_loop,
- inner_loop, chrec,
- fold_conversions, size_expr);
-
- case 0:
- return chrec;
-
default:
- break;
+ if (CONSTANT_CLASS_P (chrec))
+ return chrec;
+ return chrec_dont_know;
}
-
- /* Too complicated to handle. */
- return chrec_dont_know;
}
/* Analyze all the parameters of the chrec that were left under a
@@ -2961,7 +2780,7 @@ instantiate_scev_r (basic_block instantiate_below,
a function parameter. */
tree
-instantiate_scev (basic_block instantiate_below, struct loop *evolution_loop,
+instantiate_scev (edge instantiate_below, struct loop *evolution_loop,
tree chrec)
{
tree res;
@@ -2969,8 +2788,10 @@ instantiate_scev (basic_block instantiate_below, struct loop *evolution_loop,
if (dump_file && (dump_flags & TDF_SCEV))
{
fprintf (dump_file, "(instantiate_scev \n");
- fprintf (dump_file, " (instantiate_below = %d)\n", instantiate_below->index);
- fprintf (dump_file, " (evolution_loop = %d)\n", evolution_loop->num);
+ fprintf (dump_file, " (instantiate_below = %d -> %d)\n",
+ instantiate_below->src->index, instantiate_below->dest->index);
+ if (evolution_loop)
+ fprintf (dump_file, " (evolution_loop = %d)\n", evolution_loop->num);
fprintf (dump_file, " (chrec = ");
print_generic_expr (dump_file, chrec);
fprintf (dump_file, ")\n");
@@ -3018,7 +2839,7 @@ resolve_mixers (struct loop *loop, tree chrec, bool *folded_casts)
destr = true;
}
- tree ret = instantiate_scev_r (block_before_loop (loop), loop, NULL,
+ tree ret = instantiate_scev_r (loop_preheader_edge (loop), loop, NULL,
chrec, &fold_conversions, 0);
if (folded_casts && !*folded_casts)
@@ -3264,6 +3085,8 @@ scev_initialize (void)
{
struct loop *loop;
+ gcc_assert (! scev_initialized_p ());
+
scalar_evolution_info = hash_table<scev_info_hasher>::create_ggc (100);
initialize_scalar_evolutions_analyzer ();
@@ -3329,7 +3152,7 @@ iv_can_overflow_p (struct loop *loop, tree type, tree base, tree step)
return false;
if (TREE_CODE (base) == INTEGER_CST)
- base_min = base_max = base;
+ base_min = base_max = wi::to_wide (base);
else if (TREE_CODE (base) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (base))
&& get_range_info (base, &base_min, &base_max) == VR_RANGE)
@@ -3338,7 +3161,7 @@ iv_can_overflow_p (struct loop *loop, tree type, tree base, tree step)
return true;
if (TREE_CODE (step) == INTEGER_CST)
- step_min = step_max = step;
+ step_min = step_max = wi::to_wide (step);
else if (TREE_CODE (step) == SSA_NAME
&& INTEGRAL_TYPE_P (TREE_TYPE (step))
&& get_range_info (step, &step_min, &step_max) == VR_RANGE)
@@ -3598,7 +3421,8 @@ simple_iv_with_niters (struct loop *wrto_loop, struct loop *use_loop,
extreme = wi::max_value (type);
}
overflow = false;
- extreme = wi::sub (extreme, iv->step, TYPE_SIGN (type), &overflow);
+ extreme = wi::sub (extreme, wi::to_wide (iv->step),
+ TYPE_SIGN (type), &overflow);
if (overflow)
return true;
e = fold_build2 (code, boolean_type_node, base,
diff --git a/gcc/tree-scalar-evolution.h b/gcc/tree-scalar-evolution.h
index c3980d0..55b8ca4 100644
--- a/gcc/tree-scalar-evolution.h
+++ b/gcc/tree-scalar-evolution.h
@@ -30,7 +30,7 @@ extern void scev_reset (void);
extern void scev_reset_htab (void);
extern void scev_finalize (void);
extern tree analyze_scalar_evolution (struct loop *, tree);
-extern tree instantiate_scev (basic_block, struct loop *, tree);
+extern tree instantiate_scev (edge, struct loop *, tree);
extern tree resolve_mixers (struct loop *, tree, bool *);
extern void gather_stats_on_scev_database (void);
extern void final_value_replacement_loop (struct loop *);
@@ -60,7 +60,7 @@ block_before_loop (loop_p loop)
static inline tree
instantiate_parameters (struct loop *loop, tree chrec)
{
- return instantiate_scev (block_before_loop (loop), loop, chrec);
+ return instantiate_scev (loop_preheader_edge (loop), loop, chrec);
}
/* Returns the loop of the polynomial chrec CHREC. */
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 163b7a2..bac5939 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -1542,19 +1542,20 @@ compare_access_positions (const void *a, const void *b)
&& TREE_CODE (f2->type) != COMPLEX_TYPE
&& TREE_CODE (f2->type) != VECTOR_TYPE)
return -1;
- /* Put the integral type with the bigger precision first. */
+ /* Put any integral type before any non-integral type. When splicing, we
+ make sure that those with insufficient precision and occupying the
+ same space are not scalarized. */
else if (INTEGRAL_TYPE_P (f1->type)
+ && !INTEGRAL_TYPE_P (f2->type))
+ return -1;
+ else if (!INTEGRAL_TYPE_P (f1->type)
&& INTEGRAL_TYPE_P (f2->type))
- return TYPE_PRECISION (f2->type) - TYPE_PRECISION (f1->type);
- /* Put any integral type with non-full precision last. */
- else if (INTEGRAL_TYPE_P (f1->type)
- && (TREE_INT_CST_LOW (TYPE_SIZE (f1->type))
- != TYPE_PRECISION (f1->type)))
return 1;
- else if (INTEGRAL_TYPE_P (f2->type)
- && (TREE_INT_CST_LOW (TYPE_SIZE (f2->type))
- != TYPE_PRECISION (f2->type)))
- return -1;
+ /* Put the integral type with the bigger precision first. */
+ else if (INTEGRAL_TYPE_P (f1->type)
+ && INTEGRAL_TYPE_P (f2->type)
+ && (TYPE_PRECISION (f2->type) != TYPE_PRECISION (f1->type)))
+ return TYPE_PRECISION (f2->type) - TYPE_PRECISION (f1->type);
/* Stabilize the sort. */
return TYPE_UID (f1->type) - TYPE_UID (f2->type);
}
@@ -2055,6 +2056,11 @@ sort_and_splice_var_accesses (tree var)
bool grp_partial_lhs = access->grp_partial_lhs;
bool first_scalar = is_gimple_reg_type (access->type);
bool unscalarizable_region = access->grp_unscalarizable_region;
+ bool bf_non_full_precision
+ = (INTEGRAL_TYPE_P (access->type)
+ && TYPE_PRECISION (access->type) != access->size
+ && TREE_CODE (access->expr) == COMPONENT_REF
+ && DECL_BIT_FIELD (TREE_OPERAND (access->expr, 1)));
if (first || access->offset >= high)
{
@@ -2102,6 +2108,22 @@ sort_and_splice_var_accesses (tree var)
this combination of size and offset, the comparison function
should have put the scalars first. */
gcc_assert (first_scalar || !is_gimple_reg_type (ac2->type));
+ /* It also prefers integral types to non-integral. However, when the
+ precision of the selected type does not span the entire area and
+ should also be used for a non-integer (i.e. float), we must not
+ let that happen. Normally analyze_access_subtree expands the type
+ to cover the entire area but for bit-fields it doesn't. */
+ if (bf_non_full_precision && !INTEGRAL_TYPE_P (ac2->type))
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Cannot scalarize the following access "
+ "because insufficient precision integer type was "
+ "selected.\n ");
+ dump_access (dump_file, access, false);
+ }
+ unscalarizable_region = true;
+ }
ac2->group_representative = access;
j++;
}
@@ -2669,7 +2691,7 @@ propagate_subaccesses_across_link (struct access *lacc, struct access *racc)
}
else
{
- if (rchild->grp_write && !lacc->grp_write)
+ if (!lacc->grp_write)
{
ret = true;
subtree_mark_written_and_enqueue (lacc);
diff --git a/gcc/tree-ssa-address.c b/gcc/tree-ssa-address.c
index 5e354a1..14c7434 100644
--- a/gcc/tree-ssa-address.c
+++ b/gcc/tree-ssa-address.c
@@ -197,13 +197,13 @@ addr_for_mem_ref (struct mem_address *addr, addr_space_t as,
struct mem_addr_template *templ;
if (addr->step && !integer_onep (addr->step))
- st = immed_wide_int_const (addr->step, pointer_mode);
+ st = immed_wide_int_const (wi::to_wide (addr->step), pointer_mode);
else
st = NULL_RTX;
if (addr->offset && !integer_zerop (addr->offset))
{
- offset_int dc = offset_int::from (addr->offset, SIGNED);
+ offset_int dc = offset_int::from (wi::to_wide (addr->offset), SIGNED);
off = immed_wide_int_const (dc, pointer_mode);
}
else
diff --git a/gcc/tree-ssa-alias.c b/gcc/tree-ssa-alias.c
index 9bbc163..5340fd3 100644
--- a/gcc/tree-ssa-alias.c
+++ b/gcc/tree-ssa-alias.c
@@ -1779,8 +1779,7 @@ ref_maybe_used_by_call_p_1 (gcall *call, ao_ref *ref)
case BUILT_IN_POSIX_MEMALIGN:
case BUILT_IN_ALIGNED_ALLOC:
case BUILT_IN_CALLOC:
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
case BUILT_IN_STACK_SAVE:
case BUILT_IN_STACK_RESTORE:
case BUILT_IN_MEMSET:
@@ -2118,8 +2117,7 @@ call_may_clobber_ref_p_1 (gcall *call, ao_ref *ref)
return true;
return false;
case BUILT_IN_STACK_SAVE:
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
case BUILT_IN_ASSUME_ALIGNED:
return false;
/* But posix_memalign stores a pointer into the memory pointed to
diff --git a/gcc/tree-ssa-ccp.c b/gcc/tree-ssa-ccp.c
index 3940d53..569b057 100644
--- a/gcc/tree-ssa-ccp.c
+++ b/gcc/tree-ssa-ccp.c
@@ -569,9 +569,11 @@ get_value_from_alignment (tree expr)
gcc_assert (TREE_CODE (expr) == ADDR_EXPR);
get_pointer_alignment_1 (expr, &align, &bitpos);
- val.mask = (POINTER_TYPE_P (type) || TYPE_UNSIGNED (type)
- ? wi::mask <widest_int> (TYPE_PRECISION (type), false)
- : -1).and_not (align / BITS_PER_UNIT - 1);
+ val.mask = wi::bit_and_not
+ (POINTER_TYPE_P (type) || TYPE_UNSIGNED (type)
+ ? wi::mask <widest_int> (TYPE_PRECISION (type), false)
+ : -1,
+ align / BITS_PER_UNIT - 1);
val.lattice_val
= wi::sext (val.mask, TYPE_PRECISION (type)) == -1 ? VARYING : CONSTANT;
if (val.lattice_val == CONSTANT)
@@ -617,7 +619,7 @@ get_value_for_expr (tree expr, bool for_bits_p)
}
}
else if (is_gimple_min_invariant (expr)
- && (!for_bits_p || TREE_CODE (expr) != ADDR_EXPR))
+ && (!for_bits_p || TREE_CODE (expr) == INTEGER_CST))
{
val.lattice_val = CONSTANT;
val.value = expr;
@@ -949,8 +951,9 @@ ccp_finalize (bool nonzero_p)
else
{
unsigned int precision = TYPE_PRECISION (TREE_TYPE (val->value));
- wide_int nonzero_bits = wide_int::from (val->mask, precision,
- UNSIGNED) | val->value;
+ wide_int nonzero_bits
+ = (wide_int::from (val->mask, precision, UNSIGNED)
+ | wi::to_wide (val->value));
nonzero_bits &= get_nonzero_bits (name);
set_nonzero_bits (name, nonzero_bits);
}
@@ -1308,8 +1311,9 @@ bit_value_binop (enum tree_code code, signop sgn, int width,
case BIT_IOR_EXPR:
/* The mask is constant where there is a known
set bit, (m1 | m2) & ~((v1 & ~m1) | (v2 & ~m2)). */
- *mask = (r1mask | r2mask)
- .and_not (r1val.and_not (r1mask) | r2val.and_not (r2mask));
+ *mask = wi::bit_and_not (r1mask | r2mask,
+ wi::bit_and_not (r1val, r1mask)
+ | wi::bit_and_not (r2val, r2mask));
*val = r1val | r2val;
break;
@@ -1395,7 +1399,8 @@ bit_value_binop (enum tree_code code, signop sgn, int width,
{
/* Do the addition with unknown bits set to zero, to give carry-ins of
zero wherever possible. */
- widest_int lo = r1val.and_not (r1mask) + r2val.and_not (r2mask);
+ widest_int lo = (wi::bit_and_not (r1val, r1mask)
+ + wi::bit_and_not (r2val, r2mask));
lo = wi::ext (lo, width, sgn);
/* Do the addition with unknown bits set to one, to give carry-ins of
one wherever possible. */
@@ -1447,7 +1452,7 @@ bit_value_binop (enum tree_code code, signop sgn, int width,
case NE_EXPR:
{
widest_int m = r1mask | r2mask;
- if (r1val.and_not (m) != r2val.and_not (m))
+ if (wi::bit_and_not (r1val, m) != wi::bit_and_not (r2val, m))
{
*mask = 0;
*val = ((code == EQ_EXPR) ? 0 : 1);
@@ -1486,8 +1491,10 @@ bit_value_binop (enum tree_code code, signop sgn, int width,
/* If we know the most significant bits we know the values
value ranges by means of treating varying bits as zero
or one. Do a cross comparison of the max/min pairs. */
- maxmin = wi::cmp (o1val | o1mask, o2val.and_not (o2mask), sgn);
- minmax = wi::cmp (o1val.and_not (o1mask), o2val | o2mask, sgn);
+ maxmin = wi::cmp (o1val | o1mask,
+ wi::bit_and_not (o2val, o2mask), sgn);
+ minmax = wi::cmp (wi::bit_and_not (o1val, o1mask),
+ o2val | o2mask, sgn);
if (maxmin < 0) /* o1 is less than o2. */
{
*mask = 0;
@@ -1879,11 +1886,10 @@ evaluate_stmt (gimple *stmt)
/ BITS_PER_UNIT - 1);
break;
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
- align = (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA_WITH_ALIGN
- ? TREE_INT_CST_LOW (gimple_call_arg (stmt, 1))
- : BIGGEST_ALIGNMENT);
+ CASE_BUILT_IN_ALLOCA:
+ align = (DECL_FUNCTION_CODE (fndecl) == BUILT_IN_ALLOCA
+ ? BIGGEST_ALIGNMENT
+ : TREE_INT_CST_LOW (gimple_call_arg (stmt, 1)));
val.lattice_val = CONSTANT;
val.value = build_int_cst (TREE_TYPE (gimple_get_lhs (stmt)), 0);
val.mask = ~((HOST_WIDE_INT) align / BITS_PER_UNIT - 1);
@@ -1966,9 +1972,10 @@ evaluate_stmt (gimple *stmt)
}
else
{
- if (wi::bit_and_not (val.value, nonzero_bits) != 0)
+ if (wi::bit_and_not (wi::to_wide (val.value), nonzero_bits) != 0)
val.value = wide_int_to_tree (TREE_TYPE (lhs),
- nonzero_bits & val.value);
+ nonzero_bits
+ & wi::to_wide (val.value));
if (nonzero_bits == 0)
val.mask = 0;
else
@@ -2235,7 +2242,8 @@ ccp_fold_stmt (gimple_stmt_iterator *gsi)
/* The heuristic of fold_builtin_alloca_with_align differs before and
after inlining, so we don't require the arg to be changed into a
constant for folding, but just to be constant. */
- if (gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN))
+ if (gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN)
+ || gimple_call_builtin_p (stmt, BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX))
{
tree new_rhs = fold_builtin_alloca_with_align (stmt);
if (new_rhs)
@@ -2527,8 +2535,7 @@ optimize_stack_restore (gimple_stmt_iterator i)
if (!callee
|| DECL_BUILT_IN_CLASS (callee) != BUILT_IN_NORMAL
/* All regular builtins are ok, just obviously not alloca. */
- || DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
- || DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA_WITH_ALIGN)
+ || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee)))
return NULL_TREE;
if (DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE)
diff --git a/gcc/tree-ssa-coalesce.c b/gcc/tree-ssa-coalesce.c
index e166314..3938f06 100644
--- a/gcc/tree-ssa-coalesce.c
+++ b/gcc/tree-ssa-coalesce.c
@@ -28,6 +28,7 @@ along with GCC; see the file COPYING3. If not see
#include "memmodel.h"
#include "tm_p.h"
#include "ssa.h"
+#include "tree-ssa.h"
#include "tree-pretty-print.h"
#include "diagnostic-core.h"
#include "dumpfile.h"
@@ -1923,7 +1924,7 @@ set_parm_default_def_partition (tree var, void *arg_)
/* Allocate and return a bitmap that has a bit set for each partition
that contains a default def for a parameter. */
-extern bitmap
+bitmap
get_parm_default_def_partitions (var_map map)
{
bitmap parm_default_def_parts = BITMAP_ALLOC (NULL);
@@ -1935,3 +1936,28 @@ get_parm_default_def_partitions (var_map map)
return parm_default_def_parts;
}
+
+/* Allocate and return a bitmap that has a bit set for each partition
+ that contains an undefined value. */
+
+bitmap
+get_undefined_value_partitions (var_map map)
+{
+ bitmap undefined_value_parts = BITMAP_ALLOC (NULL);
+
+ for (unsigned int i = 1; i < num_ssa_names; i++)
+ {
+ tree var = ssa_name (i);
+ if (var
+ && !virtual_operand_p (var)
+ && !has_zero_uses (var)
+ && ssa_undefined_value_p (var))
+ {
+ const int p = var_to_partition (map, var);
+ if (p != NO_PARTITION)
+ bitmap_set_bit (undefined_value_parts, p);
+ }
+ }
+
+ return undefined_value_parts;
+}
diff --git a/gcc/tree-ssa-coalesce.h b/gcc/tree-ssa-coalesce.h
index 9eebddd..98e61c5 100644
--- a/gcc/tree-ssa-coalesce.h
+++ b/gcc/tree-ssa-coalesce.h
@@ -23,5 +23,6 @@ along with GCC; see the file COPYING3. If not see
extern var_map coalesce_ssa_name (void);
extern bool gimple_can_coalesce_p (tree, tree);
extern bitmap get_parm_default_def_partitions (var_map);
+extern bitmap get_undefined_value_partitions (var_map);
#endif /* GCC_TREE_SSA_COALESCE_H */
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index e62afad..a5f0edf 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -231,8 +231,7 @@ mark_stmt_if_obviously_necessary (gimple *stmt, bool aggressive)
case BUILT_IN_MALLOC:
case BUILT_IN_ALIGNED_ALLOC:
case BUILT_IN_CALLOC:
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
case BUILT_IN_STRDUP:
case BUILT_IN_STRNDUP:
return;
@@ -576,8 +575,7 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED,
case BUILT_IN_MALLOC:
case BUILT_IN_ALIGNED_ALLOC:
case BUILT_IN_CALLOC:
- case BUILT_IN_ALLOCA:
- case BUILT_IN_ALLOCA_WITH_ALIGN:
+ CASE_BUILT_IN_ALLOCA:
case BUILT_IN_FREE:
return false;
@@ -845,9 +843,7 @@ propagate_necessity (bool aggressive)
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_CALLOC
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_FREE
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END
- || DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA
- || (DECL_FUNCTION_CODE (callee)
- == BUILT_IN_ALLOCA_WITH_ALIGN)
+ || ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (callee))
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_SAVE
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED))
@@ -1055,7 +1051,6 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb)
}
gcc_assert (e);
e->probability = profile_probability::always ();
- e->count = bb->count;
/* The edge is no longer associated with a conditional, so it does
not have TRUE/FALSE flags.
@@ -1348,9 +1343,8 @@ eliminate_unnecessary_stmts (void)
|| (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
&& DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
&& DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
- && DECL_FUNCTION_CODE (call) != BUILT_IN_ALLOCA
- && (DECL_FUNCTION_CODE (call)
- != BUILT_IN_ALLOCA_WITH_ALIGN)))
+ && !ALLOCA_FUNCTION_CODE_P
+ (DECL_FUNCTION_CODE (call))))
/* Avoid doing so for bndret calls for the same reason. */
&& !chkp_gimple_call_builtin_p (stmt, BUILT_IN_CHKP_BNDRET))
{
diff --git a/gcc/tree-ssa-dom.c b/gcc/tree-ssa-dom.c
index d91766e..06be69a 100644
--- a/gcc/tree-ssa-dom.c
+++ b/gcc/tree-ssa-dom.c
@@ -103,9 +103,6 @@ struct opt_stats_d
static struct opt_stats_d opt_stats;
/* Local functions. */
-static edge optimize_stmt (basic_block, gimple_stmt_iterator,
- class const_and_copies *,
- class avail_exprs_stack *);
static void record_equality (tree, tree, class const_and_copies *);
static void record_equivalences_from_phis (basic_block);
static void record_equivalences_from_incoming_edge (basic_block,
@@ -572,11 +569,12 @@ class dom_opt_dom_walker : public dom_walker
public:
dom_opt_dom_walker (cdi_direction direction,
class const_and_copies *const_and_copies,
- class avail_exprs_stack *avail_exprs_stack)
+ class avail_exprs_stack *avail_exprs_stack,
+ gcond *dummy_cond)
: dom_walker (direction, true),
m_const_and_copies (const_and_copies),
m_avail_exprs_stack (avail_exprs_stack),
- m_dummy_cond (NULL) {}
+ m_dummy_cond (dummy_cond) { }
virtual edge before_dom_children (basic_block);
virtual void after_dom_children (basic_block);
@@ -587,7 +585,14 @@ private:
class const_and_copies *m_const_and_copies;
class avail_exprs_stack *m_avail_exprs_stack;
+ /* Dummy condition to avoid creating lots of throw away statements. */
gcond *m_dummy_cond;
+
+ /* Optimize a single statement within a basic block using the
+ various tables mantained by DOM. Returns the taken edge if
+ the statement is a conditional with a statically determined
+ value. */
+ edge optimize_stmt (basic_block, gimple_stmt_iterator);
};
/* Jump threading, redundancy elimination and const/copy propagation.
@@ -684,10 +689,12 @@ pass_dominator::execute (function *fun)
FOR_EACH_BB_FN (bb, fun)
record_edge_info (bb);
+ gcond *dummy_cond = gimple_build_cond (NE_EXPR, integer_zero_node,
+ integer_zero_node, NULL, NULL);
+
/* Recursively walk the dominator tree optimizing statements. */
- dom_opt_dom_walker walker (CDI_DOMINATORS,
- const_and_copies,
- avail_exprs_stack);
+ dom_opt_dom_walker walker (CDI_DOMINATORS, const_and_copies,
+ avail_exprs_stack, dummy_cond);
walker.walk (fun->cfg->x_entry_block_ptr);
/* Look for blocks where we cleared EDGE_EXECUTABLE on an outgoing
@@ -1348,8 +1355,7 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
edge taken_edge = NULL;
for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- taken_edge
- = optimize_stmt (bb, gsi, m_const_and_copies, m_avail_exprs_stack);
+ taken_edge = this->optimize_stmt (bb, gsi);
/* Now prepare to process dominated blocks. */
record_edge_info (bb);
@@ -1367,10 +1373,6 @@ dom_opt_dom_walker::before_dom_children (basic_block bb)
void
dom_opt_dom_walker::after_dom_children (basic_block bb)
{
- if (! m_dummy_cond)
- m_dummy_cond = gimple_build_cond (NE_EXPR, integer_zero_node,
- integer_zero_node, NULL, NULL);
-
thread_outgoing_edges (bb, m_dummy_cond, m_const_and_copies,
m_avail_exprs_stack,
simplify_stmt_for_jump_threading);
@@ -1700,8 +1702,99 @@ cprop_into_stmt (gimple *stmt)
}
}
-/* Optimize the statement in block BB pointed to by iterator SI
- using equivalences from CONST_AND_COPIES and AVAIL_EXPRS_STACK.
+/* If STMT contains a relational test, try to convert it into an
+ equality test if there is only a single value which can ever
+ make the test true.
+
+ For example, if the expression hash table contains:
+
+ TRUE = (i <= 1)
+
+ And we have a test within statement of i >= 1, then we can safely
+ rewrite the test as i == 1 since there only a single value where
+ the test is true.
+
+ This is similar to code in VRP. */
+
+static void
+test_for_singularity (gimple *stmt, gcond *dummy_cond,
+ avail_exprs_stack *avail_exprs_stack)
+{
+ /* We want to support gimple conditionals as well as assignments
+ where the RHS contains a conditional. */
+ if (is_gimple_assign (stmt) || gimple_code (stmt) == GIMPLE_COND)
+ {
+ enum tree_code code = ERROR_MARK;
+ tree lhs, rhs;
+
+ /* Extract the condition of interest from both forms we support. */
+ if (is_gimple_assign (stmt))
+ {
+ code = gimple_assign_rhs_code (stmt);
+ lhs = gimple_assign_rhs1 (stmt);
+ rhs = gimple_assign_rhs2 (stmt);
+ }
+ else if (gimple_code (stmt) == GIMPLE_COND)
+ {
+ code = gimple_cond_code (as_a <gcond *> (stmt));
+ lhs = gimple_cond_lhs (as_a <gcond *> (stmt));
+ rhs = gimple_cond_rhs (as_a <gcond *> (stmt));
+ }
+
+ /* We're looking for a relational test using LE/GE. Also note we can
+ canonicalize LT/GT tests against constants into LE/GT tests. */
+ if (code == LE_EXPR || code == GE_EXPR
+ || ((code == LT_EXPR || code == GT_EXPR)
+ && TREE_CODE (rhs) == INTEGER_CST))
+ {
+ /* For LT_EXPR and GT_EXPR, canonicalize to LE_EXPR and GE_EXPR. */
+ if (code == LT_EXPR)
+ rhs = fold_build2 (MINUS_EXPR, TREE_TYPE (rhs),
+ rhs, build_int_cst (TREE_TYPE (rhs), 1));
+
+ if (code == GT_EXPR)
+ rhs = fold_build2 (PLUS_EXPR, TREE_TYPE (rhs),
+ rhs, build_int_cst (TREE_TYPE (rhs), 1));
+
+ /* Determine the code we want to check for in the hash table. */
+ enum tree_code test_code;
+ if (code == GE_EXPR || code == GT_EXPR)
+ test_code = LE_EXPR;
+ else
+ test_code = GE_EXPR;
+
+ /* Update the dummy statement so we can query the hash tables. */
+ gimple_cond_set_code (dummy_cond, test_code);
+ gimple_cond_set_lhs (dummy_cond, lhs);
+ gimple_cond_set_rhs (dummy_cond, rhs);
+ tree cached_lhs
+ = avail_exprs_stack->lookup_avail_expr (dummy_cond, false, false);
+
+ /* If the lookup returned 1 (true), then the expression we
+ queried was in the hash table. As a result there is only
+ one value that makes the original conditional true. Update
+ STMT accordingly. */
+ if (cached_lhs && integer_onep (cached_lhs))
+ {
+ if (is_gimple_assign (stmt))
+ {
+ gimple_assign_set_rhs_code (stmt, EQ_EXPR);
+ gimple_assign_set_rhs2 (stmt, rhs);
+ gimple_set_modified (stmt, true);
+ }
+ else
+ {
+ gimple_set_modified (stmt, true);
+ gimple_cond_set_code (as_a <gcond *> (stmt), EQ_EXPR);
+ gimple_cond_set_rhs (as_a <gcond *> (stmt), rhs);
+ gimple_set_modified (stmt, true);
+ }
+ }
+ }
+ }
+}
+
+/* Optimize the statement in block BB pointed to by iterator SI.
We try to perform some simplistic global redundancy elimination and
constant propagation:
@@ -1714,12 +1807,15 @@ cprop_into_stmt (gimple *stmt)
2- Constant values and copy assignments. This is used to do very
simplistic constant and copy propagation. When a constant or copy
assignment is found, we map the value on the RHS of the assignment to
- the variable in the LHS in the CONST_AND_COPIES table. */
+ the variable in the LHS in the CONST_AND_COPIES table.
-static edge
-optimize_stmt (basic_block bb, gimple_stmt_iterator si,
- class const_and_copies *const_and_copies,
- class avail_exprs_stack *avail_exprs_stack)
+ 3- Very simple redundant store elimination is performed.
+
+ 4- We can simpify a condition to a constant or from a relational
+ condition to an equality condition. */
+
+edge
+dom_opt_dom_walker::optimize_stmt (basic_block bb, gimple_stmt_iterator si)
{
gimple *stmt, *old_stmt;
bool may_optimize_p;
@@ -1832,8 +1928,8 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
}
update_stmt_if_modified (stmt);
- eliminate_redundant_computations (&si, const_and_copies,
- avail_exprs_stack);
+ eliminate_redundant_computations (&si, m_const_and_copies,
+ m_avail_exprs_stack);
stmt = gsi_stmt (si);
/* Perform simple redundant store elimination. */
@@ -1855,8 +1951,8 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
else
new_stmt = gimple_build_assign (rhs, lhs);
gimple_set_vuse (new_stmt, gimple_vuse (stmt));
- cached_lhs = avail_exprs_stack->lookup_avail_expr (new_stmt, false,
- false);
+ cached_lhs = m_avail_exprs_stack->lookup_avail_expr (new_stmt, false,
+ false);
if (cached_lhs && operand_equal_p (rhs, cached_lhs, 0))
{
basic_block bb = gimple_bb (stmt);
@@ -1871,11 +1967,16 @@ optimize_stmt (basic_block bb, gimple_stmt_iterator si,
return retval;
}
}
+
+ /* If this statement was not redundant, we may still be able to simplify
+ it, which may in turn allow other part of DOM or other passes to do
+ a better job. */
+ test_for_singularity (stmt, m_dummy_cond, m_avail_exprs_stack);
}
/* Record any additional equivalences created by this statement. */
if (is_gimple_assign (stmt))
- record_equivalences_from_stmt (stmt, may_optimize_p, avail_exprs_stack);
+ record_equivalences_from_stmt (stmt, may_optimize_p, m_avail_exprs_stack);
/* If STMT is a COND_EXPR or SWITCH_EXPR and it was modified, then we may
know where it goes. */
diff --git a/gcc/tree-ssa-dse.c b/gcc/tree-ssa-dse.c
index 70c8b07..c1a6475 100644
--- a/gcc/tree-ssa-dse.c
+++ b/gcc/tree-ssa-dse.c
@@ -131,6 +131,7 @@ valid_ao_ref_for_dse (ao_ref *ref)
&& ref->max_size != -1
&& ref->size != 0
&& ref->max_size == ref->size
+ && ref->offset >= 0
&& (ref->offset % BITS_PER_UNIT) == 0
&& (ref->size % BITS_PER_UNIT) == 0
&& (ref->size != -1));
@@ -468,6 +469,36 @@ maybe_trim_partially_dead_store (ao_ref *ref, sbitmap live, gimple *stmt)
}
}
+/* Return TRUE if USE_REF reads bytes from LIVE where live is
+ derived from REF, a write reference.
+
+ While this routine may modify USE_REF, it's passed by value, not
+ location. So callers do not see those modifications. */
+
+static bool
+live_bytes_read (ao_ref use_ref, ao_ref *ref, sbitmap live)
+{
+ /* We have already verified that USE_REF and REF hit the same object.
+ Now verify that there's actually an overlap between USE_REF and REF. */
+ if (ranges_overlap_p (use_ref.offset, use_ref.size, ref->offset, ref->size))
+ {
+ normalize_ref (&use_ref, ref);
+
+ /* If USE_REF covers all of REF, then it will hit one or more
+ live bytes. This avoids useless iteration over the bitmap
+ below. */
+ if (use_ref.offset <= ref->offset
+ && use_ref.offset + use_ref.size >= ref->offset + ref->size)
+ return true;
+
+ /* Now check if any of the remaining bits in use_ref are set in LIVE. */
+ unsigned int start = (use_ref.offset - ref->offset) / BITS_PER_UNIT;
+ unsigned int end = start + (use_ref.size / BITS_PER_UNIT) - 1;
+ return bitmap_bit_in_range_p (live, start, end);
+ }
+ return true;
+}
+
/* A helper of dse_optimize_stmt.
Given a GIMPLE_ASSIGN in STMT that writes to REF, find a candidate
statement *USE_STMT that may prove STMT to be dead.
@@ -547,6 +578,31 @@ dse_classify_store (ao_ref *ref, gimple *stmt, gimple **use_stmt,
/* If the statement is a use the store is not dead. */
else if (ref_maybe_used_by_stmt_p (use_stmt, ref))
{
+ /* Handle common cases where we can easily build an ao_ref
+ structure for USE_STMT and in doing so we find that the
+ references hit non-live bytes and thus can be ignored. */
+ if (byte_tracking_enabled && (!gimple_vdef (use_stmt) || !temp))
+ {
+ if (is_gimple_assign (use_stmt))
+ {
+ /* Other cases were noted as non-aliasing by
+ the call to ref_maybe_used_by_stmt_p. */
+ ao_ref use_ref;
+ ao_ref_init (&use_ref, gimple_assign_rhs1 (use_stmt));
+ if (valid_ao_ref_for_dse (&use_ref)
+ && use_ref.base == ref->base
+ && use_ref.size == use_ref.max_size
+ && !live_bytes_read (use_ref, ref, live_bytes))
+ {
+ /* If this statement has a VDEF, then it is the
+ first store we have seen, so walk through it. */
+ if (gimple_vdef (use_stmt))
+ temp = use_stmt;
+ continue;
+ }
+ }
+ }
+
fail = true;
BREAK_FROM_IMM_USE_STMT (ui);
}
diff --git a/gcc/tree-ssa-forwprop.c b/gcc/tree-ssa-forwprop.c
index 11511b4..5569b98 100644
--- a/gcc/tree-ssa-forwprop.c
+++ b/gcc/tree-ssa-forwprop.c
@@ -1491,9 +1491,14 @@ defcodefor_name (tree name, enum tree_code *code, tree *arg1, tree *arg2)
applied, otherwise return false.
We are looking for X with unsigned type T with bitsize B, OP being
- +, | or ^, some type T2 wider than T and
+ +, | or ^, some type T2 wider than T. For:
(X << CNT1) OP (X >> CNT2) iff CNT1 + CNT2 == B
((T) ((T2) X << CNT1)) OP ((T) ((T2) X >> CNT2)) iff CNT1 + CNT2 == B
+
+ transform these into:
+ X r<< CNT1
+
+ Or for:
(X << Y) OP (X >> (B - Y))
(X << (int) Y) OP (X >> (int) (B - Y))
((T) ((T2) X << Y)) OP ((T) ((T2) X >> (B - Y)))
@@ -1503,12 +1508,23 @@ defcodefor_name (tree name, enum tree_code *code, tree *arg1, tree *arg2)
((T) ((T2) X << Y)) | ((T) ((T2) X >> ((-Y) & (B - 1))))
((T) ((T2) X << (int) Y)) | ((T) ((T2) X >> (int) ((-Y) & (B - 1))))
- and transform these into:
- X r<< CNT1
+ transform these into:
X r<< Y
+ Or for:
+ (X << (Y & (B - 1))) | (X >> ((-Y) & (B - 1)))
+ (X << (int) (Y & (B - 1))) | (X >> (int) ((-Y) & (B - 1)))
+ ((T) ((T2) X << (Y & (B - 1)))) | ((T) ((T2) X >> ((-Y) & (B - 1))))
+ ((T) ((T2) X << (int) (Y & (B - 1)))) \
+ | ((T) ((T2) X >> (int) ((-Y) & (B - 1))))
+
+ transform these into:
+ X r<< (Y & (B - 1))
+
Note, in the patterns with T2 type, the type of OP operands
- might be even a signed type, but should have precision B. */
+ might be even a signed type, but should have precision B.
+ Expressions with & (B - 1) should be recognized only if B is
+ a power of 2. */
static bool
simplify_rotate (gimple_stmt_iterator *gsi)
@@ -1578,7 +1594,9 @@ simplify_rotate (gimple_stmt_iterator *gsi)
def_arg1[i] = tem;
}
/* Both shifts have to use the same first operand. */
- if (TREE_CODE (def_arg1[0]) != SSA_NAME || def_arg1[0] != def_arg1[1])
+ if (!operand_equal_for_phi_arg_p (def_arg1[0], def_arg1[1])
+ || !types_compatible_p (TREE_TYPE (def_arg1[0]),
+ TREE_TYPE (def_arg1[1])))
return false;
if (!TYPE_UNSIGNED (TREE_TYPE (def_arg1[0])))
return false;
@@ -1649,8 +1667,10 @@ simplify_rotate (gimple_stmt_iterator *gsi)
/* The above sequence isn't safe for Y being 0,
because then one of the shifts triggers undefined behavior.
This alternative is safe even for rotation count of 0.
- One shift count is Y and the other (-Y) & (B - 1). */
+ One shift count is Y and the other (-Y) & (B - 1).
+ Or one shift count is Y & (B - 1) and the other (-Y) & (B - 1). */
else if (cdef_code[i] == BIT_AND_EXPR
+ && pow2p_hwi (TYPE_PRECISION (rtype))
&& tree_fits_shwi_p (cdef_arg2[i])
&& tree_to_shwi (cdef_arg2[i])
== TYPE_PRECISION (rtype) - 1
@@ -1675,17 +1695,50 @@ simplify_rotate (gimple_stmt_iterator *gsi)
rotcnt = tem;
break;
}
- defcodefor_name (tem, &code, &tem, NULL);
+ tree tem2;
+ defcodefor_name (tem, &code, &tem2, NULL);
if (CONVERT_EXPR_CODE_P (code)
- && INTEGRAL_TYPE_P (TREE_TYPE (tem))
- && TYPE_PRECISION (TREE_TYPE (tem))
+ && INTEGRAL_TYPE_P (TREE_TYPE (tem2))
+ && TYPE_PRECISION (TREE_TYPE (tem2))
> floor_log2 (TYPE_PRECISION (rtype))
- && type_has_mode_precision_p (TREE_TYPE (tem))
- && (tem == def_arg2[1 - i]
- || tem == def_arg2_alt[1 - i]))
+ && type_has_mode_precision_p (TREE_TYPE (tem2)))
{
- rotcnt = tem;
- break;
+ if (tem2 == def_arg2[1 - i]
+ || tem2 == def_arg2_alt[1 - i])
+ {
+ rotcnt = tem2;
+ break;
+ }
+ }
+ else
+ tem2 = NULL_TREE;
+
+ if (cdef_code[1 - i] == BIT_AND_EXPR
+ && tree_fits_shwi_p (cdef_arg2[1 - i])
+ && tree_to_shwi (cdef_arg2[1 - i])
+ == TYPE_PRECISION (rtype) - 1
+ && TREE_CODE (cdef_arg1[1 - i]) == SSA_NAME)
+ {
+ if (tem == cdef_arg1[1 - i]
+ || tem2 == cdef_arg1[1 - i])
+ {
+ rotcnt = def_arg2[1 - i];
+ break;
+ }
+ tree tem3;
+ defcodefor_name (cdef_arg1[1 - i], &code, &tem3, NULL);
+ if (CONVERT_EXPR_CODE_P (code)
+ && INTEGRAL_TYPE_P (TREE_TYPE (tem3))
+ && TYPE_PRECISION (TREE_TYPE (tem3))
+ > floor_log2 (TYPE_PRECISION (rtype))
+ && type_has_mode_precision_p (TREE_TYPE (tem3)))
+ {
+ if (tem == tem3 || tem2 == tem3)
+ {
+ rotcnt = def_arg2[1 - i];
+ break;
+ }
+ }
}
}
}
diff --git a/gcc/tree-ssa-ifcombine.c b/gcc/tree-ssa-ifcombine.c
index a211335..06d2269 100644
--- a/gcc/tree-ssa-ifcombine.c
+++ b/gcc/tree-ssa-ifcombine.c
@@ -358,10 +358,7 @@ update_profile_after_ifcombine (basic_block inner_cond_bb,
outer_cond_bb->(outer_to_inner)->inner_cond_bb->(inner_taken)
and probability of inner_not_taken updated. */
- outer_to_inner->count = outer_cond_bb->count;
inner_cond_bb->count = outer_cond_bb->count;
- inner_taken->count += outer2->count;
- outer2->count = profile_count::zero ();
inner_taken->probability = outer2->probability + outer_to_inner->probability
* inner_taken->probability;
diff --git a/gcc/tree-ssa-loop-im.c b/gcc/tree-ssa-loop-im.c
index 503e662..a1b8a00 100644
--- a/gcc/tree-ssa-loop-im.c
+++ b/gcc/tree-ssa-loop-im.c
@@ -1815,9 +1815,9 @@ execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag,
if (flag_probability.initialized_p ())
;
- else if (ncount == nbbs && count_sum > 0 && preheader->count >= count_sum)
+ else if (ncount == nbbs && count_sum > 0 && preheader->count () >= count_sum)
{
- flag_probability = count_sum.probability_in (preheader->count);
+ flag_probability = count_sum.probability_in (preheader->count ());
if (flag_probability > cap)
flag_probability = cap;
}
@@ -1881,13 +1881,11 @@ execute_sm_if_changed (edge ex, tree mem, tree tmp_var, tree flag,
edge e2 = make_edge (new_bb, then_bb,
EDGE_TRUE_VALUE | (irr ? EDGE_IRREDUCIBLE_LOOP : 0));
e2->probability = flag_probability;
- e2->count = then_bb->count;
e1->flags |= EDGE_FALSE_VALUE | (irr ? EDGE_IRREDUCIBLE_LOOP : 0);
e1->flags &= ~EDGE_FALLTHRU;
e1->probability = flag_probability.invert ();
- e1->count = new_bb->count - then_bb->count;
then_old_edge = make_single_succ_edge (then_bb, old_dest,
EDGE_FALLTHRU | (irr ? EDGE_IRREDUCIBLE_LOOP : 0));
diff --git a/gcc/tree-ssa-loop-ivcanon.c b/gcc/tree-ssa-loop-ivcanon.c
index efb199a..743bf1a 100644
--- a/gcc/tree-ssa-loop-ivcanon.c
+++ b/gcc/tree-ssa-loop-ivcanon.c
@@ -530,7 +530,6 @@ remove_exits_and_undefined_stmts (struct loop *loop, unsigned int npeeled)
if (!loop_exit_edge_p (loop, exit_edge))
exit_edge = EDGE_SUCC (bb, 1);
exit_edge->probability = profile_probability::always ();
- exit_edge->count = exit_edge->src->count;
gcc_checking_assert (loop_exit_edge_p (loop, exit_edge));
gcond *cond_stmt = as_a <gcond *> (elt->stmt);
if (exit_edge->flags & EDGE_TRUE_VALUE)
@@ -643,7 +642,6 @@ unloop_loops (bitmap loop_closed_ssa_invalidated,
stmt = gimple_build_call (builtin_decl_implicit (BUILT_IN_UNREACHABLE), 0);
latch_edge = make_edge (latch, create_basic_block (NULL, NULL, latch), flags);
latch_edge->probability = profile_probability::never ();
- latch_edge->count = profile_count::zero ();
latch_edge->flags |= flags;
latch_edge->goto_locus = locus;
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index bbea619..793e66f 100644
--- a/gcc/tree-ssa-loop-ivopts.c
+++ b/gcc/tree-ssa-loop-ivopts.c
@@ -1550,9 +1550,6 @@ record_invariant (struct ivopts_data *data, tree op, bool nonlinear_use)
bitmap_set_bit (data->relevant, SSA_NAME_VERSION (op));
}
-static tree
-strip_offset (tree expr, unsigned HOST_WIDE_INT *offset);
-
/* Record a group of TYPE. */
static struct iv_group *
@@ -2160,8 +2157,8 @@ constant_multiple_of (tree top, tree bot, widest_int *mul)
if (TREE_CODE (bot) != INTEGER_CST)
return false;
- p0 = widest_int::from (top, SIGNED);
- p1 = widest_int::from (bot, SIGNED);
+ p0 = widest_int::from (wi::to_wide (top), SIGNED);
+ p1 = widest_int::from (wi::to_wide (bot), SIGNED);
if (p1 == 0)
return false;
*mul = wi::sext (wi::divmod_trunc (p0, p1, SIGNED, &res), precision);
@@ -2863,7 +2860,7 @@ strip_offset_1 (tree expr, bool inside_addr, bool top_compref,
/* Strips constant offsets from EXPR and stores them to OFFSET. */
-static tree
+tree
strip_offset (tree expr, unsigned HOST_WIDE_INT *offset)
{
HOST_WIDE_INT off;
@@ -3140,7 +3137,7 @@ add_autoinc_candidates (struct ivopts_data *data, tree base, tree step,
statement. */
if (use_bb->loop_father != data->current_loop
|| !dominated_by_p (CDI_DOMINATORS, data->current_loop->latch, use_bb)
- || stmt_could_throw_p (use->stmt)
+ || stmt_can_throw_internal (use->stmt)
|| !cst_and_fits_in_hwi (step))
return;
diff --git a/gcc/tree-ssa-loop-ivopts.h b/gcc/tree-ssa-loop-ivopts.h
index f8f31e9..bd92051 100644
--- a/gcc/tree-ssa-loop-ivopts.h
+++ b/gcc/tree-ssa-loop-ivopts.h
@@ -28,6 +28,7 @@ extern void dump_cand (FILE *, struct iv_cand *);
extern bool contains_abnormal_ssa_name_p (tree);
extern struct loop *outermost_invariant_loop_for_expr (struct loop *, tree);
extern bool expr_invariant_in_loop_p (struct loop *, tree);
+extern tree strip_offset (tree, unsigned HOST_WIDE_INT *);
bool may_be_nonaddressable_p (tree expr);
void tree_ssa_iv_optimize (void);
diff --git a/gcc/tree-ssa-loop-manip.c b/gcc/tree-ssa-loop-manip.c
index d6ba305..5794dae 100644
--- a/gcc/tree-ssa-loop-manip.c
+++ b/gcc/tree-ssa-loop-manip.c
@@ -690,48 +690,59 @@ rewrite_virtuals_into_loop_closed_ssa (struct loop *loop)
rewrite_into_loop_closed_ssa_1 (NULL, 0, SSA_OP_VIRTUAL_USES, loop);
}
-/* Check invariants of the loop closed ssa form for the USE in BB. */
+/* Check invariants of the loop closed ssa form for the def in DEF_BB. */
static void
-check_loop_closed_ssa_use (basic_block bb, tree use)
+check_loop_closed_ssa_def (basic_block def_bb, tree def)
{
- gimple *def;
- basic_block def_bb;
+ use_operand_p use_p;
+ imm_use_iterator iterator;
+ FOR_EACH_IMM_USE_FAST (use_p, iterator, def)
+ {
+ if (is_gimple_debug (USE_STMT (use_p)))
+ continue;
- if (TREE_CODE (use) != SSA_NAME || virtual_operand_p (use))
- return;
+ basic_block use_bb = gimple_bb (USE_STMT (use_p));
+ if (is_a <gphi *> (USE_STMT (use_p)))
+ use_bb = EDGE_PRED (use_bb, PHI_ARG_INDEX_FROM_USE (use_p))->src;
- def = SSA_NAME_DEF_STMT (use);
- def_bb = gimple_bb (def);
- gcc_assert (!def_bb
- || flow_bb_inside_loop_p (def_bb->loop_father, bb));
+ gcc_assert (flow_bb_inside_loop_p (def_bb->loop_father, use_bb));
+ }
}
-/* Checks invariants of loop closed ssa form in statement STMT in BB. */
+/* Checks invariants of loop closed ssa form in BB. */
static void
-check_loop_closed_ssa_stmt (basic_block bb, gimple *stmt)
+check_loop_closed_ssa_bb (basic_block bb)
{
- ssa_op_iter iter;
- tree var;
+ for (gphi_iterator bsi = gsi_start_phis (bb); !gsi_end_p (bsi);
+ gsi_next (&bsi))
+ {
+ gphi *phi = bsi.phi ();
- if (is_gimple_debug (stmt))
- return;
+ if (!virtual_operand_p (PHI_RESULT (phi)))
+ check_loop_closed_ssa_def (bb, PHI_RESULT (phi));
+ }
- FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_USE)
- check_loop_closed_ssa_use (bb, var);
+ for (gimple_stmt_iterator bsi = gsi_start_nondebug_bb (bb); !gsi_end_p (bsi);
+ gsi_next_nondebug (&bsi))
+ {
+ ssa_op_iter iter;
+ tree var;
+ gimple *stmt = gsi_stmt (bsi);
+
+ FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_DEF)
+ check_loop_closed_ssa_def (bb, var);
+ }
}
/* Checks that invariants of the loop closed ssa form are preserved.
- Call verify_ssa when VERIFY_SSA_P is true. */
+ Call verify_ssa when VERIFY_SSA_P is true. Note all loops are checked
+ if LOOP is NULL, otherwise, only LOOP is checked. */
DEBUG_FUNCTION void
-verify_loop_closed_ssa (bool verify_ssa_p)
+verify_loop_closed_ssa (bool verify_ssa_p, struct loop *loop)
{
- basic_block bb;
- edge e;
- edge_iterator ei;
-
if (number_of_loops (cfun) <= 1)
return;
@@ -740,20 +751,22 @@ verify_loop_closed_ssa (bool verify_ssa_p)
timevar_push (TV_VERIFY_LOOP_CLOSED);
- FOR_EACH_BB_FN (bb, cfun)
+ if (loop == NULL)
{
- for (gphi_iterator bsi = gsi_start_phis (bb); !gsi_end_p (bsi);
- gsi_next (&bsi))
- {
- gphi *phi = bsi.phi ();
- FOR_EACH_EDGE (e, ei, bb->preds)
- check_loop_closed_ssa_use (e->src,
- PHI_ARG_DEF_FROM_EDGE (phi, e));
- }
+ basic_block bb;
- for (gimple_stmt_iterator bsi = gsi_start_bb (bb); !gsi_end_p (bsi);
- gsi_next (&bsi))
- check_loop_closed_ssa_stmt (bb, gsi_stmt (bsi));
+ FOR_EACH_BB_FN (bb, cfun)
+ if (bb->loop_father && bb->loop_father->num > 0)
+ check_loop_closed_ssa_bb (bb);
+ }
+ else
+ {
+ basic_block *bbs = get_loop_body (loop);
+
+ for (unsigned i = 0; i < loop->num_nodes; ++i)
+ check_loop_closed_ssa_bb (bbs[i]);
+
+ free (bbs);
}
timevar_pop (TV_VERIFY_LOOP_CLOSED);
@@ -1281,12 +1294,10 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
/* Set the probability of new exit to the same of the old one. Fix
the frequency of the latch block, by scaling it back by
1 - exit->probability. */
- new_exit->count = exit->count;
new_exit->probability = exit->probability;
new_nonexit = single_pred_edge (loop->latch);
new_nonexit->probability = exit->probability.invert ();
new_nonexit->flags = EDGE_TRUE_VALUE;
- new_nonexit->count -= exit->count;
if (new_nonexit->probability.initialized_p ())
scale_bbs_frequencies (&loop->latch, 1, new_nonexit->probability);
@@ -1358,7 +1369,7 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
exit edge. */
freq_h = loop->header->count;
- freq_e = (loop_preheader_edge (loop))->count;
+ freq_e = (loop_preheader_edge (loop))->count ();
/* Use frequency only if counts are zero. */
if (!(freq_h > 0) && !(freq_e > 0))
{
@@ -1377,17 +1388,15 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
exit_bb = single_pred (loop->latch);
new_exit = find_edge (exit_bb, rest);
- new_exit->count = loop_preheader_edge (loop)->count;
new_exit->probability = profile_probability::always ()
.apply_scale (1, new_est_niter + 1);
- rest->count += new_exit->count;
+ rest->count += new_exit->count ();
rest->frequency += EDGE_FREQUENCY (new_exit);
new_nonexit = single_pred_edge (loop->latch);
prob = new_nonexit->probability;
new_nonexit->probability = new_exit->probability.invert ();
- new_nonexit->count = exit_bb->count - new_exit->count;
prob = new_nonexit->probability / prob;
if (prob.initialized_p ())
scale_bbs_frequencies (&loop->latch, 1, prob);
@@ -1405,7 +1414,8 @@ tree_transform_and_unroll_loop (struct loop *loop, unsigned factor,
checking_verify_flow_info ();
checking_verify_loop_structure ();
- checking_verify_loop_closed_ssa (true);
+ checking_verify_loop_closed_ssa (true, loop);
+ checking_verify_loop_closed_ssa (true, new_loop);
}
/* Wrapper over tree_transform_and_unroll_loop for case we do not
diff --git a/gcc/tree-ssa-loop-manip.h b/gcc/tree-ssa-loop-manip.h
index a139050..3f5b3ee 100644
--- a/gcc/tree-ssa-loop-manip.h
+++ b/gcc/tree-ssa-loop-manip.h
@@ -28,13 +28,13 @@ extern void rewrite_into_loop_closed_ssa_1 (bitmap, unsigned, int,
struct loop *);
extern void rewrite_into_loop_closed_ssa (bitmap, unsigned);
extern void rewrite_virtuals_into_loop_closed_ssa (struct loop *);
-extern void verify_loop_closed_ssa (bool);
+extern void verify_loop_closed_ssa (bool, struct loop * = NULL);
static inline void
-checking_verify_loop_closed_ssa (bool verify_ssa_p)
+checking_verify_loop_closed_ssa (bool verify_ssa_p, struct loop *loop = NULL)
{
if (flag_checking)
- verify_loop_closed_ssa (verify_ssa_p);
+ verify_loop_closed_ssa (verify_ssa_p, loop);
}
extern basic_block split_loop_exit_edge (edge);
diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
index 27244eb..6efe67a 100644
--- a/gcc/tree-ssa-loop-niter.c
+++ b/gcc/tree-ssa-loop-niter.c
@@ -92,14 +92,14 @@ split_to_var_and_offset (tree expr, tree *var, mpz_t offset)
*var = op0;
/* Always sign extend the offset. */
- wi::to_mpz (op1, offset, SIGNED);
+ wi::to_mpz (wi::to_wide (op1), offset, SIGNED);
if (negate)
mpz_neg (offset, offset);
break;
case INTEGER_CST:
*var = build_int_cst_type (type, 0);
- wi::to_mpz (expr, offset, TYPE_SIGN (type));
+ wi::to_mpz (wi::to_wide (expr), offset, TYPE_SIGN (type));
break;
default:
@@ -164,7 +164,7 @@ refine_value_range_using_guard (tree type, tree var,
/* Case of comparing VAR with its below/up bounds. */
mpz_init (valc1);
- wi::to_mpz (c1, valc1, TYPE_SIGN (type));
+ wi::to_mpz (wi::to_wide (c1), valc1, TYPE_SIGN (type));
if (mpz_cmp (valc1, below) == 0)
cmp = GT_EXPR;
if (mpz_cmp (valc1, up) == 0)
@@ -178,9 +178,9 @@ refine_value_range_using_guard (tree type, tree var,
wide_int min = wi::min_value (type);
wide_int max = wi::max_value (type);
- if (wi::eq_p (c1, min))
+ if (wi::to_wide (c1) == min)
cmp = GT_EXPR;
- if (wi::eq_p (c1, max))
+ if (wi::to_wide (c1) == max)
cmp = LT_EXPR;
}
@@ -221,8 +221,8 @@ refine_value_range_using_guard (tree type, tree var,
/* Setup range information for varc1. */
if (integer_zerop (varc1))
{
- wi::to_mpz (integer_zero_node, minc1, TYPE_SIGN (type));
- wi::to_mpz (integer_zero_node, maxc1, TYPE_SIGN (type));
+ wi::to_mpz (0, minc1, TYPE_SIGN (type));
+ wi::to_mpz (0, maxc1, TYPE_SIGN (type));
}
else if (TREE_CODE (varc1) == SSA_NAME
&& INTEGRAL_TYPE_P (type)
@@ -903,7 +903,8 @@ number_of_iterations_ne_max (mpz_t bnd, bool no_overflow, tree c, tree s,
if (integer_onep (s)
|| (TREE_CODE (c) == INTEGER_CST
&& TREE_CODE (s) == INTEGER_CST
- && wi::mod_trunc (c, s, TYPE_SIGN (type)) == 0)
+ && wi::mod_trunc (wi::to_wide (c), wi::to_wide (s),
+ TYPE_SIGN (type)) == 0)
|| (TYPE_OVERFLOW_UNDEFINED (type)
&& multiple_of_p (type, c, s)))
{
@@ -922,7 +923,8 @@ number_of_iterations_ne_max (mpz_t bnd, bool no_overflow, tree c, tree s,
the whole # of iterations analysis will fail). */
if (!no_overflow)
{
- max = wi::mask <widest_int> (TYPE_PRECISION (type) - wi::ctz (s), false);
+ max = wi::mask <widest_int> (TYPE_PRECISION (type)
+ - wi::ctz (wi::to_wide (s)), false);
wi::to_mpz (max, bnd, UNSIGNED);
return;
}
@@ -938,13 +940,13 @@ number_of_iterations_ne_max (mpz_t bnd, bool no_overflow, tree c, tree s,
/* ... then we can strengthen this to C / S, and possibly we can use
the upper bound on C given by BNDS. */
if (TREE_CODE (c) == INTEGER_CST)
- wi::to_mpz (c, bnd, UNSIGNED);
+ wi::to_mpz (wi::to_wide (c), bnd, UNSIGNED);
else if (bnds_u_valid)
mpz_set (bnd, bnds->up);
}
mpz_init (d);
- wi::to_mpz (s, d, UNSIGNED);
+ wi::to_mpz (wi::to_wide (s), d, UNSIGNED);
mpz_fdiv_q (bnd, bnd, d);
mpz_clear (d);
}
@@ -1157,7 +1159,7 @@ number_of_iterations_lt_to_ne (tree type, affine_iv *iv0, affine_iv *iv1,
tmod = fold_convert (type1, mod);
mpz_init (mmod);
- wi::to_mpz (mod, mmod, UNSIGNED);
+ wi::to_mpz (wi::to_wide (mod), mmod, UNSIGNED);
mpz_neg (mmod, mmod);
/* If the induction variable does not overflow and the exit is taken,
@@ -1543,7 +1545,7 @@ number_of_iterations_lt (struct loop *loop, tree type, affine_iv *iv0,
mpz_init (mstep);
mpz_init (tmp);
- wi::to_mpz (step, mstep, UNSIGNED);
+ wi::to_mpz (wi::to_wide (step), mstep, UNSIGNED);
mpz_add (tmp, bnds->up, mstep);
mpz_sub_ui (tmp, tmp, 1);
mpz_fdiv_q (tmp, tmp, mstep);
@@ -3178,7 +3180,7 @@ get_cst_init_from_scev (tree var, wide_int *init, bool is_min)
if (is_min == tree_int_cst_sign_bit (iv.step))
return false;
- *init = iv.base;
+ *init = wi::to_wide (iv.base);
return true;
}
@@ -3225,7 +3227,7 @@ record_nonwrapping_iv (struct loop *loop, tree base, tree step, gimple *stmt,
&& INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
&& (get_range_info (orig_base, &min, &max) == VR_RANGE
|| get_cst_init_from_scev (orig_base, &max, false))
- && wi::gts_p (high, max))
+ && wi::gts_p (wi::to_wide (high), max))
base = wide_int_to_tree (unsigned_type, max);
else if (TREE_CODE (base) != INTEGER_CST
&& dominated_by_p (CDI_DOMINATORS,
@@ -3243,7 +3245,7 @@ record_nonwrapping_iv (struct loop *loop, tree base, tree step, gimple *stmt,
&& INTEGRAL_TYPE_P (TREE_TYPE (orig_base))
&& (get_range_info (orig_base, &min, &max) == VR_RANGE
|| get_cst_init_from_scev (orig_base, &min, true))
- && wi::gts_p (min, low))
+ && wi::gts_p (min, wi::to_wide (low)))
base = wide_int_to_tree (unsigned_type, min);
else if (TREE_CODE (base) != INTEGER_CST
&& dominated_by_p (CDI_DOMINATORS,
@@ -3442,7 +3444,8 @@ infer_loop_bounds_from_pointer_arith (struct loop *loop, gimple *stmt)
if (TYPE_PRECISION (type) != TYPE_PRECISION (TREE_TYPE (var)))
return;
- scev = instantiate_parameters (loop, analyze_scalar_evolution (loop, def));
+ struct loop *uloop = loop_containing_stmt (stmt);
+ scev = instantiate_parameters (loop, analyze_scalar_evolution (uloop, def));
if (chrec_contains_undetermined (scev))
return;
@@ -4499,19 +4502,15 @@ scev_var_range_cant_overflow (tree var, tree step, struct loop *loop)
MIN - type_MIN >= |step| ; if step < 0.
Or VAR must take value outside of value range, which is not true. */
- step_wi = step;
+ step_wi = wi::to_wide (step);
type = TREE_TYPE (var);
if (tree_int_cst_sign_bit (step))
{
- diff = lower_bound_in_type (type, type);
- diff = minv - diff;
+ diff = minv - wi::to_wide (lower_bound_in_type (type, type));
step_wi = - step_wi;
}
else
- {
- diff = upper_bound_in_type (type, type);
- diff = diff - maxv;
- }
+ diff = wi::to_wide (upper_bound_in_type (type, type)) - maxv;
return (wi::geu_p (diff, step_wi));
}
diff --git a/gcc/tree-ssa-loop-prefetch.c b/gcc/tree-ssa-loop-prefetch.c
index ecf14d1..67767e1 100644
--- a/gcc/tree-ssa-loop-prefetch.c
+++ b/gcc/tree-ssa-loop-prefetch.c
@@ -1632,7 +1632,8 @@ determine_loop_nest_reuse (struct loop *loop, struct mem_ref_group *refs,
for (gr = refs; gr; gr = gr->next)
for (ref = gr->refs; ref; ref = ref->next)
{
- dr = create_data_ref (nest, loop_containing_stmt (ref->stmt),
+ dr = create_data_ref (loop_preheader_edge (nest),
+ loop_containing_stmt (ref->stmt),
ref->mem, ref->stmt, !ref->write_p, false);
if (dr)
diff --git a/gcc/tree-ssa-loop-split.c b/gcc/tree-ssa-loop-split.c
index e454cc5..dcb7c1e 100644
--- a/gcc/tree-ssa-loop-split.c
+++ b/gcc/tree-ssa-loop-split.c
@@ -353,11 +353,8 @@ connect_loops (struct loop *loop1, struct loop *loop2)
new_e->flags |= EDGE_TRUE_VALUE;
}
- new_e->count = skip_bb->count;
new_e->probability = profile_probability::likely ();
- new_e->count = skip_e->count.apply_probability (PROB_LIKELY);
- skip_e->count -= new_e->count;
- skip_e->probability = profile_probability::unlikely ();
+ skip_e->probability = new_e->probability.invert ();
return new_e;
}
@@ -560,7 +557,6 @@ split_loop (struct loop *loop1, struct tree_niter_desc *niter)
initialize_original_copy_tables ();
basic_block cond_bb;
- /* FIXME: probabilities seems wrong here. */
struct loop *loop2 = loop_version (loop1, cond, &cond_bb,
profile_probability::always (),
profile_probability::always (),
diff --git a/gcc/tree-ssa-loop-unswitch.c b/gcc/tree-ssa-loop-unswitch.c
index 57aba4f..4287c10 100644
--- a/gcc/tree-ssa-loop-unswitch.c
+++ b/gcc/tree-ssa-loop-unswitch.c
@@ -853,16 +853,15 @@ hoist_guard (struct loop *loop, edge guard)
same average number of iterations regardless outcome of guard. */
new_edge->probability = guard->probability;
profile_count skip_count = guard->src->count > 0
- ? guard->count.apply_scale (pre_header->count,
+ ? guard->count ().apply_scale (pre_header->count,
guard->src->count)
- : guard->count.apply_probability (new_edge->probability);
+ : guard->count ().apply_probability (new_edge->probability);
- if (skip_count > e->count)
+ if (skip_count > e->count ())
{
fprintf (dump_file, " Capping count; expect profile inconsistency\n");
- skip_count = e->count;
+ skip_count = e->count ();
}
- new_edge->count = skip_count;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, " Estimated probability of skipping loop is ");
@@ -874,19 +873,14 @@ hoist_guard (struct loop *loop, edge guard)
First decrease count of path from newly hoisted loop guard
to loop header... */
- e->count -= skip_count;
e->probability = new_edge->probability.invert ();
- e->dest->count = e->count;
+ e->dest->count = e->count ();
e->dest->frequency = EDGE_FREQUENCY (e);
/* ... now update profile to represent that original guard will be optimized
away ... */
guard->probability = profile_probability::never ();
- guard->count = profile_count::zero ();
not_guard->probability = profile_probability::always ();
- /* This count is wrong (frequency of not_guard does not change),
- but will be scaled later. */
- not_guard->count = guard->src->count;
/* ... finally scale everything in the loop except for guarded basic blocks
where profile does not change. */
diff --git a/gcc/tree-ssa-math-opts.c b/gcc/tree-ssa-math-opts.c
index 818290c..17d62a8 100644
--- a/gcc/tree-ssa-math-opts.c
+++ b/gcc/tree-ssa-math-opts.c
@@ -2138,7 +2138,7 @@ find_bswap_or_nop_load (gimple *stmt, tree ref, struct symbolic_number *n)
if (wi::neg_p (bit_offset))
{
offset_int mask = wi::mask <offset_int> (LOG2_BITS_PER_UNIT, false);
- offset_int tem = bit_offset.and_not (mask);
+ offset_int tem = wi::bit_and_not (bit_offset, mask);
/* TEM is the bitpos rounded to BITS_PER_UNIT towards -Inf.
Subtract it to BIT_OFFSET and add it (scaled) to OFFSET. */
bit_offset -= tem;
diff --git a/gcc/tree-ssa-phionlycprop.c b/gcc/tree-ssa-phionlycprop.c
index 65af448..fe39aa7 100644
--- a/gcc/tree-ssa-phionlycprop.c
+++ b/gcc/tree-ssa-phionlycprop.c
@@ -298,7 +298,6 @@ propagate_rhs_into_lhs (gimple *stmt, tree lhs, tree rhs,
te->probability += e->probability;
- te->count += e->count;
remove_edge (e);
cfg_altered = true;
}
diff --git a/gcc/tree-ssa-phiopt.c b/gcc/tree-ssa-phiopt.c
index f5c07dc..6e0e186 100644
--- a/gcc/tree-ssa-phiopt.c
+++ b/gcc/tree-ssa-phiopt.c
@@ -375,7 +375,6 @@ replace_phi_edge_with_variable (basic_block cond_block,
EDGE_SUCC (cond_block, 0)->flags |= EDGE_FALLTHRU;
EDGE_SUCC (cond_block, 0)->flags &= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
EDGE_SUCC (cond_block, 0)->probability = profile_probability::always ();
- EDGE_SUCC (cond_block, 0)->count += EDGE_SUCC (cond_block, 1)->count;
block_to_remove = EDGE_SUCC (cond_block, 1)->dest;
}
@@ -385,7 +384,6 @@ replace_phi_edge_with_variable (basic_block cond_block,
EDGE_SUCC (cond_block, 1)->flags
&= ~(EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
EDGE_SUCC (cond_block, 1)->probability = profile_probability::always ();
- EDGE_SUCC (cond_block, 1)->count += EDGE_SUCC (cond_block, 0)->count;
block_to_remove = EDGE_SUCC (cond_block, 0)->dest;
}
@@ -995,11 +993,13 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
}
- /* Now optimize (x != 0) ? x + y : y to just y.
- The following condition is too restrictive, there can easily be another
- stmt in middle_bb, for instance a CONVERT_EXPR for the second argument. */
- gimple *assign = last_and_only_stmt (middle_bb);
- if (!assign || gimple_code (assign) != GIMPLE_ASSIGN
+ /* Now optimize (x != 0) ? x + y : y to just x + y. */
+ gsi = gsi_last_nondebug_bb (middle_bb);
+ if (gsi_end_p (gsi))
+ return 0;
+
+ gimple *assign = gsi_stmt (gsi);
+ if (!is_gimple_assign (assign)
|| gimple_assign_rhs_class (assign) != GIMPLE_BINARY_RHS
|| (!INTEGRAL_TYPE_P (TREE_TYPE (arg0))
&& !POINTER_TYPE_P (TREE_TYPE (arg0))))
@@ -1009,6 +1009,71 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
if (!gimple_seq_empty_p (phi_nodes (middle_bb)))
return 0;
+ /* Allow up to 2 cheap preparation statements that prepare argument
+ for assign, e.g.:
+ if (y_4 != 0)
+ goto <bb 3>;
+ else
+ goto <bb 4>;
+ <bb 3>:
+ _1 = (int) y_4;
+ iftmp.0_6 = x_5(D) r<< _1;
+ <bb 4>:
+ # iftmp.0_2 = PHI <iftmp.0_6(3), x_5(D)(2)>
+ or:
+ if (y_3(D) == 0)
+ goto <bb 4>;
+ else
+ goto <bb 3>;
+ <bb 3>:
+ y_4 = y_3(D) & 31;
+ _1 = (int) y_4;
+ _6 = x_5(D) r<< _1;
+ <bb 4>:
+ # _2 = PHI <x_5(D)(2), _6(3)> */
+ gimple *prep_stmt[2] = { NULL, NULL };
+ int prep_cnt;
+ for (prep_cnt = 0; ; prep_cnt++)
+ {
+ gsi_prev_nondebug (&gsi);
+ if (gsi_end_p (gsi))
+ break;
+
+ gimple *g = gsi_stmt (gsi);
+ if (gimple_code (g) == GIMPLE_LABEL)
+ break;
+
+ if (prep_cnt == 2 || !is_gimple_assign (g))
+ return 0;
+
+ tree lhs = gimple_assign_lhs (g);
+ tree rhs1 = gimple_assign_rhs1 (g);
+ use_operand_p use_p;
+ gimple *use_stmt;
+ if (TREE_CODE (lhs) != SSA_NAME
+ || TREE_CODE (rhs1) != SSA_NAME
+ || !INTEGRAL_TYPE_P (TREE_TYPE (lhs))
+ || !INTEGRAL_TYPE_P (TREE_TYPE (rhs1))
+ || !single_imm_use (lhs, &use_p, &use_stmt)
+ || use_stmt != (prep_cnt ? prep_stmt[prep_cnt - 1] : assign))
+ return 0;
+ switch (gimple_assign_rhs_code (g))
+ {
+ CASE_CONVERT:
+ break;
+ case PLUS_EXPR:
+ case BIT_AND_EXPR:
+ case BIT_IOR_EXPR:
+ case BIT_XOR_EXPR:
+ if (TREE_CODE (gimple_assign_rhs2 (g)) != INTEGER_CST)
+ return 0;
+ break;
+ default:
+ return 0;
+ }
+ prep_stmt[prep_cnt] = g;
+ }
+
/* Only transform if it removes the condition. */
if (!single_non_singleton_phi_for_edges (phi_nodes (gimple_bb (phi)), e0, e1))
return 0;
@@ -1019,7 +1084,7 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
&& profile_status_for_fn (cfun) != PROFILE_ABSENT
&& EDGE_PRED (middle_bb, 0)->probability < profile_probability::even ()
/* If assign is cheap, there is no point avoiding it. */
- && estimate_num_insns (assign, &eni_time_weights)
+ && estimate_num_insns (bb_seq (middle_bb), &eni_time_weights)
>= 3 * estimate_num_insns (cond, &eni_time_weights))
return 0;
@@ -1030,6 +1095,32 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
tree cond_lhs = gimple_cond_lhs (cond);
tree cond_rhs = gimple_cond_rhs (cond);
+ /* Propagate the cond_rhs constant through preparation stmts,
+ make sure UB isn't invoked while doing that. */
+ for (int i = prep_cnt - 1; i >= 0; --i)
+ {
+ gimple *g = prep_stmt[i];
+ tree grhs1 = gimple_assign_rhs1 (g);
+ if (!operand_equal_for_phi_arg_p (cond_lhs, grhs1))
+ return 0;
+ cond_lhs = gimple_assign_lhs (g);
+ cond_rhs = fold_convert (TREE_TYPE (grhs1), cond_rhs);
+ if (TREE_CODE (cond_rhs) != INTEGER_CST
+ || TREE_OVERFLOW (cond_rhs))
+ return 0;
+ if (gimple_assign_rhs_class (g) == GIMPLE_BINARY_RHS)
+ {
+ cond_rhs = int_const_binop (gimple_assign_rhs_code (g), cond_rhs,
+ gimple_assign_rhs2 (g));
+ if (TREE_OVERFLOW (cond_rhs))
+ return 0;
+ }
+ cond_rhs = fold_convert (TREE_TYPE (cond_lhs), cond_rhs);
+ if (TREE_CODE (cond_rhs) != INTEGER_CST
+ || TREE_OVERFLOW (cond_rhs))
+ return 0;
+ }
+
if (((code == NE_EXPR && e1 == false_edge)
|| (code == EQ_EXPR && e1 == true_edge))
&& arg0 == lhs
@@ -1071,7 +1162,15 @@ value_replacement (basic_block cond_bb, basic_block middle_bb,
duplicate_ssa_name_range_info (lhs, SSA_NAME_RANGE_TYPE (phires),
phires_range_info);
}
- gimple_stmt_iterator gsi_from = gsi_for_stmt (assign);
+ gimple_stmt_iterator gsi_from;
+ for (int i = prep_cnt - 1; i >= 0; --i)
+ {
+ tree plhs = gimple_assign_lhs (prep_stmt[i]);
+ SSA_NAME_RANGE_INFO (plhs) = NULL;
+ gsi_from = gsi_for_stmt (prep_stmt[i]);
+ gsi_move_before (&gsi_from, &gsi);
+ }
+ gsi_from = gsi_for_stmt (assign);
gsi_move_before (&gsi_from, &gsi);
replace_phi_edge_with_variable (cond_bb, e1, phi, lhs);
return 2;
@@ -1123,7 +1222,8 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
if (cmp == LT_EXPR)
{
bool overflow;
- wide_int alt = wi::sub (larger, 1, TYPE_SIGN (TREE_TYPE (larger)),
+ wide_int alt = wi::sub (wi::to_wide (larger), 1,
+ TYPE_SIGN (TREE_TYPE (larger)),
&overflow);
if (! overflow)
alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt);
@@ -1131,7 +1231,8 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
else
{
bool overflow;
- wide_int alt = wi::add (larger, 1, TYPE_SIGN (TREE_TYPE (larger)),
+ wide_int alt = wi::add (wi::to_wide (larger), 1,
+ TYPE_SIGN (TREE_TYPE (larger)),
&overflow);
if (! overflow)
alt_larger = wide_int_to_tree (TREE_TYPE (larger), alt);
@@ -1149,7 +1250,8 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
if (cmp == GT_EXPR)
{
bool overflow;
- wide_int alt = wi::add (smaller, 1, TYPE_SIGN (TREE_TYPE (smaller)),
+ wide_int alt = wi::add (wi::to_wide (smaller), 1,
+ TYPE_SIGN (TREE_TYPE (smaller)),
&overflow);
if (! overflow)
alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt);
@@ -1157,7 +1259,8 @@ minmax_replacement (basic_block cond_bb, basic_block middle_bb,
else
{
bool overflow;
- wide_int alt = wi::sub (smaller, 1, TYPE_SIGN (TREE_TYPE (smaller)),
+ wide_int alt = wi::sub (wi::to_wide (smaller), 1,
+ TYPE_SIGN (TREE_TYPE (smaller)),
&overflow);
if (! overflow)
alt_smaller = wide_int_to_tree (TREE_TYPE (smaller), alt);
@@ -1809,9 +1912,24 @@ cond_store_replacement (basic_block middle_bb, basic_block join_bb,
gsi_remove (&gsi, true);
release_defs (assign);
+ /* Make both store and load use alias-set zero as we have to
+ deal with the case of the store being a conditional change
+ of the dynamic type. */
+ lhs = unshare_expr (lhs);
+ tree *basep = &lhs;
+ while (handled_component_p (*basep))
+ basep = &TREE_OPERAND (*basep, 0);
+ if (TREE_CODE (*basep) == MEM_REF
+ || TREE_CODE (*basep) == TARGET_MEM_REF)
+ TREE_OPERAND (*basep, 1)
+ = fold_convert (ptr_type_node, TREE_OPERAND (*basep, 1));
+ else
+ *basep = build2 (MEM_REF, TREE_TYPE (*basep),
+ build_fold_addr_expr (*basep),
+ build_zero_cst (ptr_type_node));
+
/* 2) Insert a load from the memory of the store to the temporary
on the edge which did not contain the store. */
- lhs = unshare_expr (lhs);
name = make_temp_ssa_name (TREE_TYPE (lhs), NULL, "cstore");
new_stmt = gimple_build_assign (name, lhs);
gimple_set_location (new_stmt, locus);
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 364272d..7bf8701 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -537,7 +537,6 @@ static pre_expr bitmap_find_leader (bitmap_set_t, unsigned int);
static void bitmap_value_insert_into_set (bitmap_set_t, pre_expr);
static void bitmap_value_replace_in_set (bitmap_set_t, pre_expr);
static void bitmap_set_copy (bitmap_set_t, bitmap_set_t);
-static void bitmap_set_and (bitmap_set_t, bitmap_set_t);
static bool bitmap_set_contains_value (bitmap_set_t, unsigned int);
static void bitmap_insert_into_set (bitmap_set_t, pre_expr);
static bitmap_set_t bitmap_set_new (void);
@@ -720,14 +719,11 @@ sccvn_valnum_from_value_id (unsigned int val)
/* Remove an expression EXPR from a bitmapped set. */
static void
-bitmap_remove_from_set (bitmap_set_t set, pre_expr expr)
+bitmap_remove_expr_from_set (bitmap_set_t set, pre_expr expr)
{
unsigned int val = get_expr_value_id (expr);
- if (!value_id_constant_p (val))
- {
- bitmap_clear_bit (&set->values, val);
- bitmap_clear_bit (&set->expressions, get_expression_id (expr));
- }
+ bitmap_clear_bit (&set->values, val);
+ bitmap_clear_bit (&set->expressions, get_expression_id (expr));
}
/* Insert an expression EXPR into a bitmapped set. */
@@ -800,40 +796,10 @@ sorted_array_from_bitmap_set (bitmap_set_t set)
return result;
}
-/* Perform bitmapped set operation DEST &= ORIG. */
-
-static void
-bitmap_set_and (bitmap_set_t dest, bitmap_set_t orig)
-{
- bitmap_iterator bi;
- unsigned int i;
-
- if (dest != orig)
- {
- bitmap_and_into (&dest->values, &orig->values);
-
- unsigned int to_clear = -1U;
- FOR_EACH_EXPR_ID_IN_SET (dest, i, bi)
- {
- if (to_clear != -1U)
- {
- bitmap_clear_bit (&dest->expressions, to_clear);
- to_clear = -1U;
- }
- pre_expr expr = expression_for_id (i);
- unsigned int value_id = get_expr_value_id (expr);
- if (!bitmap_bit_p (&dest->values, value_id))
- to_clear = i;
- }
- if (to_clear != -1U)
- bitmap_clear_bit (&dest->expressions, to_clear);
- }
-}
-
/* Subtract all expressions contained in ORIG from DEST. */
static bitmap_set_t
-bitmap_set_subtract (bitmap_set_t dest, bitmap_set_t orig)
+bitmap_set_subtract_expressions (bitmap_set_t dest, bitmap_set_t orig)
{
bitmap_set_t result = bitmap_set_new ();
bitmap_iterator bi;
@@ -864,15 +830,15 @@ bitmap_set_subtract_values (bitmap_set_t a, bitmap_set_t b)
{
if (to_remove)
{
- bitmap_remove_from_set (a, to_remove);
+ bitmap_remove_expr_from_set (a, to_remove);
to_remove = NULL;
}
pre_expr expr = expression_for_id (i);
- if (bitmap_set_contains_value (b, get_expr_value_id (expr)))
+ if (bitmap_bit_p (&b->values, get_expr_value_id (expr)))
to_remove = expr;
}
if (to_remove)
- bitmap_remove_from_set (a, to_remove);
+ bitmap_remove_expr_from_set (a, to_remove);
}
@@ -884,9 +850,6 @@ bitmap_set_contains_value (bitmap_set_t set, unsigned int value_id)
if (value_id_constant_p (value_id))
return true;
- if (!set || bitmap_empty_p (&set->expressions))
- return false;
-
return bitmap_bit_p (&set->values, value_id);
}
@@ -896,44 +859,6 @@ bitmap_set_contains_expr (bitmap_set_t set, const pre_expr expr)
return bitmap_bit_p (&set->expressions, get_expression_id (expr));
}
-/* Replace an instance of value LOOKFOR with expression EXPR in SET. */
-
-static void
-bitmap_set_replace_value (bitmap_set_t set, unsigned int lookfor,
- const pre_expr expr)
-{
- bitmap exprset;
- unsigned int i;
- bitmap_iterator bi;
-
- if (value_id_constant_p (lookfor))
- return;
-
- if (!bitmap_set_contains_value (set, lookfor))
- return;
-
- /* The number of expressions having a given value is usually
- significantly less than the total number of expressions in SET.
- Thus, rather than check, for each expression in SET, whether it
- has the value LOOKFOR, we walk the reverse mapping that tells us
- what expressions have a given value, and see if any of those
- expressions are in our set. For large testcases, this is about
- 5-10x faster than walking the bitmap. If this is somehow a
- significant lose for some cases, we can choose which set to walk
- based on the set size. */
- exprset = value_expressions[lookfor];
- EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
- {
- if (bitmap_clear_bit (&set->expressions, i))
- {
- bitmap_set_bit (&set->expressions, get_expression_id (expr));
- return;
- }
- }
-
- gcc_unreachable ();
-}
-
/* Return true if two bitmap sets are equal. */
static bool
@@ -949,9 +874,33 @@ static void
bitmap_value_replace_in_set (bitmap_set_t set, pre_expr expr)
{
unsigned int val = get_expr_value_id (expr);
+ if (value_id_constant_p (val))
+ return;
if (bitmap_set_contains_value (set, val))
- bitmap_set_replace_value (set, val, expr);
+ {
+ /* The number of expressions having a given value is usually
+ significantly less than the total number of expressions in SET.
+ Thus, rather than check, for each expression in SET, whether it
+ has the value LOOKFOR, we walk the reverse mapping that tells us
+ what expressions have a given value, and see if any of those
+ expressions are in our set. For large testcases, this is about
+ 5-10x faster than walking the bitmap. If this is somehow a
+ significant lose for some cases, we can choose which set to walk
+ based on the set size. */
+ unsigned int i;
+ bitmap_iterator bi;
+ bitmap exprset = value_expressions[val];
+ EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
+ {
+ if (bitmap_clear_bit (&set->expressions, i))
+ {
+ bitmap_set_bit (&set->expressions, get_expression_id (expr));
+ return;
+ }
+ }
+ gcc_unreachable ();
+ }
else
bitmap_insert_into_set (set, expr);
}
@@ -2010,14 +1959,12 @@ valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr)
}
}
-/* Clean the set of expressions that are no longer valid in SET1 or
- SET2. This means expressions that are made up of values we have no
- leaders for in SET1 or SET2. This version is used for partial
- anticipation, which means it is not valid in either ANTIC_IN or
- PA_IN. */
+/* Clean the set of expressions SET1 that are no longer valid in SET1 or SET2.
+ This means expressions that are made up of values we have no leaders for
+ in SET1 or SET2. */
static void
-dependent_clean (bitmap_set_t set1, bitmap_set_t set2)
+clean (bitmap_set_t set1, bitmap_set_t set2 = NULL)
{
vec<pre_expr> exprs = sorted_array_from_bitmap_set (set1);
pre_expr expr;
@@ -2026,26 +1973,7 @@ dependent_clean (bitmap_set_t set1, bitmap_set_t set2)
FOR_EACH_VEC_ELT (exprs, i, expr)
{
if (!valid_in_sets (set1, set2, expr))
- bitmap_remove_from_set (set1, expr);
- }
- exprs.release ();
-}
-
-/* Clean the set of expressions that are no longer valid in SET. This
- means expressions that are made up of values we have no leaders for
- in SET. */
-
-static void
-clean (bitmap_set_t set)
-{
- vec<pre_expr> exprs = sorted_array_from_bitmap_set (set);
- pre_expr expr;
- int i;
-
- FOR_EACH_VEC_ELT (exprs, i, expr)
- {
- if (!valid_in_sets (set, NULL, expr))
- bitmap_remove_from_set (set, expr);
+ bitmap_remove_expr_from_set (set1, expr);
}
exprs.release ();
}
@@ -2065,7 +1993,7 @@ prune_clobbered_mems (bitmap_set_t set, basic_block block)
/* Remove queued expr. */
if (to_remove)
{
- bitmap_remove_from_set (set, to_remove);
+ bitmap_remove_expr_from_set (set, to_remove);
to_remove = NULL;
}
@@ -2100,7 +2028,7 @@ prune_clobbered_mems (bitmap_set_t set, basic_block block)
/* Remove queued expr. */
if (to_remove)
- bitmap_remove_from_set (set, to_remove);
+ bitmap_remove_expr_from_set (set, to_remove);
}
static sbitmap has_abnormal_preds;
@@ -2113,8 +2041,7 @@ static sbitmap has_abnormal_preds;
ANTIC_OUT[BLOCK] = phi_translate (ANTIC_IN[succ(BLOCK)])
ANTIC_IN[BLOCK] = clean(ANTIC_OUT[BLOCK] U EXP_GEN[BLOCK] - TMP_GEN[BLOCK])
-
- Note that clean() is deferred until after the iteration. */
+*/
static bool
compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
@@ -2182,17 +2109,54 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
phi_translate_set (ANTIC_OUT, ANTIC_IN (first), block, first);
+ /* If we have multiple successors we need to intersect the ANTIC_OUT
+ sets. For values that's a simple intersection but for
+ expressions it is a union. Given we want to have a single
+ expression per value in our sets we have to canonicalize.
+ Avoid randomness and running into cycles like for PR82129 and
+ canonicalize the expression we choose to the one with the
+ lowest id. This requires we actually compute the union first. */
FOR_EACH_VEC_ELT (worklist, i, bprime)
{
if (!gimple_seq_empty_p (phi_nodes (bprime)))
{
bitmap_set_t tmp = bitmap_set_new ();
phi_translate_set (tmp, ANTIC_IN (bprime), block, bprime);
- bitmap_set_and (ANTIC_OUT, tmp);
+ bitmap_and_into (&ANTIC_OUT->values, &tmp->values);
+ bitmap_ior_into (&ANTIC_OUT->expressions, &tmp->expressions);
bitmap_set_free (tmp);
}
else
- bitmap_set_and (ANTIC_OUT, ANTIC_IN (bprime));
+ {
+ bitmap_and_into (&ANTIC_OUT->values, &ANTIC_IN (bprime)->values);
+ bitmap_ior_into (&ANTIC_OUT->expressions,
+ &ANTIC_IN (bprime)->expressions);
+ }
+ }
+ if (! worklist.is_empty ())
+ {
+ /* Prune expressions not in the value set, canonicalizing to
+ expression with lowest ID. */
+ bitmap_iterator bi;
+ unsigned int i;
+ unsigned int to_clear = -1U;
+ bitmap seen_value = BITMAP_ALLOC (NULL);
+ FOR_EACH_EXPR_ID_IN_SET (ANTIC_OUT, i, bi)
+ {
+ if (to_clear != -1U)
+ {
+ bitmap_clear_bit (&ANTIC_OUT->expressions, to_clear);
+ to_clear = -1U;
+ }
+ pre_expr expr = expression_for_id (i);
+ unsigned int value_id = get_expr_value_id (expr);
+ if (!bitmap_bit_p (&ANTIC_OUT->values, value_id)
+ || !bitmap_set_bit (seen_value, value_id))
+ to_clear = i;
+ }
+ if (to_clear != -1U)
+ bitmap_clear_bit (&ANTIC_OUT->expressions, to_clear);
+ BITMAP_FREE (seen_value);
}
}
@@ -2201,11 +2165,11 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
prune_clobbered_mems (ANTIC_OUT, block);
/* Generate ANTIC_OUT - TMP_GEN. */
- S = bitmap_set_subtract (ANTIC_OUT, TMP_GEN (block));
+ S = bitmap_set_subtract_expressions (ANTIC_OUT, TMP_GEN (block));
/* Start ANTIC_IN with EXP_GEN - TMP_GEN. */
- ANTIC_IN (block) = bitmap_set_subtract (EXP_GEN (block),
- TMP_GEN (block));
+ ANTIC_IN (block) = bitmap_set_subtract_expressions (EXP_GEN (block),
+ TMP_GEN (block));
/* Then union in the ANTIC_OUT - TMP_GEN values,
to get ANTIC_OUT U EXP_GEN - TMP_GEN */
@@ -2213,8 +2177,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
bitmap_value_insert_into_set (ANTIC_IN (block),
expression_for_id (bii));
- /* clean (ANTIC_IN (block)) is defered to after the iteration converged
- because it can cause non-convergence, see for example PR81181. */
+ clean (ANTIC_IN (block));
if (!bitmap_set_equal (old, ANTIC_IN (block)))
changed = true;
@@ -2250,8 +2213,7 @@ compute_antic_aux (basic_block block, bool block_has_abnormal_pred_edge)
else if succs(BLOCK) == 1 then
PA_OUT[BLOCK] = phi_translate (PA_IN[succ(BLOCK)])
- PA_IN[BLOCK] = dependent_clean(PA_OUT[BLOCK] - TMP_GEN[BLOCK]
- - ANTIC_IN[BLOCK])
+ PA_IN[BLOCK] = clean(PA_OUT[BLOCK] - TMP_GEN[BLOCK] - ANTIC_IN[BLOCK])
*/
static void
@@ -2344,7 +2306,7 @@ compute_partial_antic_aux (basic_block block,
/* PA_IN starts with PA_OUT - TMP_GEN.
Then we subtract things from ANTIC_IN. */
- PA_IN (block) = bitmap_set_subtract (PA_OUT, TMP_GEN (block));
+ PA_IN (block) = bitmap_set_subtract_expressions (PA_OUT, TMP_GEN (block));
/* For partial antic, we want to put back in the phi results, since
we will properly avoid making them partially antic over backedges. */
@@ -2354,7 +2316,7 @@ compute_partial_antic_aux (basic_block block,
/* PA_IN[block] = PA_IN[block] - ANTIC_IN[block] */
bitmap_set_subtract_values (PA_IN (block), ANTIC_IN (block));
- dependent_clean (PA_IN (block), ANTIC_IN (block));
+ clean (PA_IN (block), ANTIC_IN (block));
maybe_dump_sets:
if (dump_file && (dump_flags & TDF_DETAILS))
@@ -2447,12 +2409,6 @@ compute_antic (void)
gcc_checking_assert (num_iterations < 500);
}
- /* We have to clean after the dataflow problem converged as cleaning
- can cause non-convergence because it is based on expressions
- rather than values. */
- FOR_EACH_BB_FN (block, cfun)
- clean (ANTIC_IN (block));
-
statistics_histogram_event (cfun, "compute_antic iterations",
num_iterations);
@@ -4020,21 +3976,25 @@ compute_avail (void)
{
ref->set = set;
if (ref1->opcode == MEM_REF)
- ref1->op0 = wide_int_to_tree (TREE_TYPE (ref2->op0),
- ref1->op0);
+ ref1->op0
+ = wide_int_to_tree (TREE_TYPE (ref2->op0),
+ wi::to_wide (ref1->op0));
else
- ref1->op2 = wide_int_to_tree (TREE_TYPE (ref2->op2),
- ref1->op2);
+ ref1->op2
+ = wide_int_to_tree (TREE_TYPE (ref2->op2),
+ wi::to_wide (ref1->op2));
}
else
{
ref->set = 0;
if (ref1->opcode == MEM_REF)
- ref1->op0 = wide_int_to_tree (ptr_type_node,
- ref1->op0);
+ ref1->op0
+ = wide_int_to_tree (ptr_type_node,
+ wi::to_wide (ref1->op0));
else
- ref1->op2 = wide_int_to_tree (ptr_type_node,
- ref1->op2);
+ ref1->op2
+ = wide_int_to_tree (ptr_type_node,
+ wi::to_wide (ref1->op2));
}
operands.release ();
diff --git a/gcc/tree-ssa-reassoc.c b/gcc/tree-ssa-reassoc.c
index 2fb6aef..cb438c7 100644
--- a/gcc/tree-ssa-reassoc.c
+++ b/gcc/tree-ssa-reassoc.c
@@ -495,10 +495,13 @@ sort_by_operand_rank (const void *pa, const void *pb)
const operand_entry *oea = *(const operand_entry *const *)pa;
const operand_entry *oeb = *(const operand_entry *const *)pb;
+ if (oeb->rank != oea->rank)
+ return oeb->rank > oea->rank ? 1 : -1;
+
/* It's nicer for optimize_expression if constants that are likely
- to fold when added/multiplied//whatever are put next to each
+ to fold when added/multiplied/whatever are put next to each
other. Since all constants have rank 0, order them by type. */
- if (oeb->rank == 0 && oea->rank == 0)
+ if (oea->rank == 0)
{
if (constant_type (oeb->op) != constant_type (oea->op))
return constant_type (oeb->op) - constant_type (oea->op);
@@ -508,50 +511,50 @@ sort_by_operand_rank (const void *pa, const void *pb)
return oeb->id > oea->id ? 1 : -1;
}
+ if (TREE_CODE (oea->op) != SSA_NAME)
+ {
+ if (TREE_CODE (oeb->op) != SSA_NAME)
+ return oeb->id > oea->id ? 1 : -1;
+ else
+ return 1;
+ }
+ else if (TREE_CODE (oeb->op) != SSA_NAME)
+ return -1;
+
/* Lastly, make sure the versions that are the same go next to each
other. */
- if (oeb->rank == oea->rank
- && TREE_CODE (oea->op) == SSA_NAME
- && TREE_CODE (oeb->op) == SSA_NAME)
+ if (SSA_NAME_VERSION (oeb->op) != SSA_NAME_VERSION (oea->op))
{
/* As SSA_NAME_VERSION is assigned pretty randomly, because we reuse
versions of removed SSA_NAMEs, so if possible, prefer to sort
based on basic block and gimple_uid of the SSA_NAME_DEF_STMT.
See PR60418. */
- if (!SSA_NAME_IS_DEFAULT_DEF (oea->op)
- && !SSA_NAME_IS_DEFAULT_DEF (oeb->op)
- && !oea->stmt_to_insert
- && !oeb->stmt_to_insert
- && SSA_NAME_VERSION (oeb->op) != SSA_NAME_VERSION (oea->op))
+ gimple *stmta = SSA_NAME_DEF_STMT (oea->op);
+ gimple *stmtb = SSA_NAME_DEF_STMT (oeb->op);
+ basic_block bba = gimple_bb (stmta);
+ basic_block bbb = gimple_bb (stmtb);
+ if (bbb != bba)
{
- gimple *stmta = SSA_NAME_DEF_STMT (oea->op);
- gimple *stmtb = SSA_NAME_DEF_STMT (oeb->op);
- basic_block bba = gimple_bb (stmta);
- basic_block bbb = gimple_bb (stmtb);
- if (bbb != bba)
- {
- if (bb_rank[bbb->index] != bb_rank[bba->index])
- return bb_rank[bbb->index] - bb_rank[bba->index];
- }
- else
- {
- bool da = reassoc_stmt_dominates_stmt_p (stmta, stmtb);
- bool db = reassoc_stmt_dominates_stmt_p (stmtb, stmta);
- if (da != db)
- return da ? 1 : -1;
- }
+ /* One of the SSA_NAMEs can be defined in oeN->stmt_to_insert
+ but the other might not. */
+ if (!bba)
+ return 1;
+ if (!bbb)
+ return -1;
+ /* If neither is, compare bb_rank. */
+ if (bb_rank[bbb->index] != bb_rank[bba->index])
+ return bb_rank[bbb->index] - bb_rank[bba->index];
}
- if (SSA_NAME_VERSION (oeb->op) != SSA_NAME_VERSION (oea->op))
- return SSA_NAME_VERSION (oeb->op) > SSA_NAME_VERSION (oea->op) ? 1 : -1;
- else
- return oeb->id > oea->id ? 1 : -1;
+ bool da = reassoc_stmt_dominates_stmt_p (stmta, stmtb);
+ bool db = reassoc_stmt_dominates_stmt_p (stmtb, stmta);
+ if (da != db)
+ return da ? 1 : -1;
+
+ return SSA_NAME_VERSION (oeb->op) > SSA_NAME_VERSION (oea->op) ? 1 : -1;
}
- if (oeb->rank != oea->rank)
- return oeb->rank > oea->rank ? 1 : -1;
- else
- return oeb->id > oea->id ? 1 : -1;
+ return oeb->id > oea->id ? 1 : -1;
}
/* Add an operand entry to *OPS for the tree operand OP. */
@@ -2379,7 +2382,16 @@ update_range_test (struct range_entry *range, struct range_entry *otherrange,
r = otherrange + i;
else
r = otherrangep[i];
- fprintf (dump_file, " and %c[", r->in_p ? '+' : '-');
+ if (r->exp
+ && r->exp != range->exp
+ && TREE_CODE (r->exp) == SSA_NAME)
+ {
+ fprintf (dump_file, " and ");
+ print_generic_expr (dump_file, r->exp);
+ }
+ else
+ fprintf (dump_file, " and");
+ fprintf (dump_file, " %c[", r->in_p ? '+' : '-');
print_generic_expr (dump_file, r->low);
fprintf (dump_file, ", ");
print_generic_expr (dump_file, r->high);
@@ -2880,6 +2892,134 @@ optimize_range_tests_to_bit_test (enum tree_code opcode, int first, int length,
return any_changes;
}
+/* Optimize x != 0 && y != 0 && z != 0 into (x | y | z) != 0
+ and similarly x != -1 && y != -1 && y != -1 into (x & y & z) != -1. */
+
+static bool
+optimize_range_tests_cmp_bitwise (enum tree_code opcode, int first, int length,
+ vec<operand_entry *> *ops,
+ struct range_entry *ranges)
+{
+ int i;
+ unsigned int b;
+ bool any_changes = false;
+ auto_vec<int, 128> buckets;
+ auto_vec<int, 32> chains;
+ auto_vec<struct range_entry *, 32> candidates;
+
+ for (i = first; i < length; i++)
+ {
+ if (ranges[i].exp == NULL_TREE
+ || TREE_CODE (ranges[i].exp) != SSA_NAME
+ || !ranges[i].in_p
+ || TYPE_PRECISION (TREE_TYPE (ranges[i].exp)) <= 1
+ || TREE_CODE (TREE_TYPE (ranges[i].exp)) == BOOLEAN_TYPE
+ || ranges[i].low == NULL_TREE
+ || ranges[i].low != ranges[i].high)
+ continue;
+
+ bool zero_p = integer_zerop (ranges[i].low);
+ if (!zero_p && !integer_all_onesp (ranges[i].low))
+ continue;
+
+ b = TYPE_PRECISION (TREE_TYPE (ranges[i].exp)) * 2 + !zero_p;
+ if (buckets.length () <= b)
+ buckets.safe_grow_cleared (b + 1);
+ if (chains.length () <= (unsigned) i)
+ chains.safe_grow (i + 1);
+ chains[i] = buckets[b];
+ buckets[b] = i + 1;
+ }
+
+ FOR_EACH_VEC_ELT (buckets, b, i)
+ if (i && chains[i - 1])
+ {
+ int j, k = i;
+ for (j = chains[i - 1]; j; j = chains[j - 1])
+ {
+ gimple *gk = SSA_NAME_DEF_STMT (ranges[k - 1].exp);
+ gimple *gj = SSA_NAME_DEF_STMT (ranges[j - 1].exp);
+ if (reassoc_stmt_dominates_stmt_p (gk, gj))
+ k = j;
+ }
+ tree type1 = TREE_TYPE (ranges[k - 1].exp);
+ tree type2 = NULL_TREE;
+ bool strict_overflow_p = false;
+ candidates.truncate (0);
+ for (j = i; j; j = chains[j - 1])
+ {
+ tree type = TREE_TYPE (ranges[j - 1].exp);
+ strict_overflow_p |= ranges[j - 1].strict_overflow_p;
+ if (j == k
+ || useless_type_conversion_p (type1, type))
+ ;
+ else if (type2 == NULL_TREE
+ || useless_type_conversion_p (type2, type))
+ {
+ if (type2 == NULL_TREE)
+ type2 = type;
+ candidates.safe_push (&ranges[j - 1]);
+ }
+ }
+ unsigned l = candidates.length ();
+ for (j = i; j; j = chains[j - 1])
+ {
+ tree type = TREE_TYPE (ranges[j - 1].exp);
+ if (j == k)
+ continue;
+ if (useless_type_conversion_p (type1, type))
+ ;
+ else if (type2 == NULL_TREE
+ || useless_type_conversion_p (type2, type))
+ continue;
+ candidates.safe_push (&ranges[j - 1]);
+ }
+ gimple_seq seq = NULL;
+ tree op = NULL_TREE;
+ unsigned int id;
+ struct range_entry *r;
+ candidates.safe_push (&ranges[k - 1]);
+ FOR_EACH_VEC_ELT (candidates, id, r)
+ {
+ gimple *g;
+ if (id == 0)
+ {
+ op = r->exp;
+ continue;
+ }
+ if (id == l)
+ {
+ g = gimple_build_assign (make_ssa_name (type1), NOP_EXPR, op);
+ gimple_seq_add_stmt_without_update (&seq, g);
+ op = gimple_assign_lhs (g);
+ }
+ tree type = TREE_TYPE (r->exp);
+ tree exp = r->exp;
+ if (id >= l && !useless_type_conversion_p (type1, type))
+ {
+ g = gimple_build_assign (make_ssa_name (type1), NOP_EXPR, exp);
+ gimple_seq_add_stmt_without_update (&seq, g);
+ exp = gimple_assign_lhs (g);
+ }
+ g = gimple_build_assign (make_ssa_name (id >= l ? type1 : type2),
+ (b & 1) ? BIT_AND_EXPR : BIT_IOR_EXPR,
+ op, exp);
+ gimple_seq_add_stmt_without_update (&seq, g);
+ op = gimple_assign_lhs (g);
+ }
+ candidates.pop ();
+ if (update_range_test (&ranges[k - 1], NULL, candidates.address (),
+ candidates.length (), opcode, ops, op,
+ seq, true, ranges[k - 1].low,
+ ranges[k - 1].low, strict_overflow_p))
+ any_changes = true;
+ else
+ gimple_seq_discard (seq);
+ }
+
+ return any_changes;
+}
+
/* Attempt to optimize for signed a and b where b is known to be >= 0:
a >= 0 && a < b into (unsigned) a < (unsigned) b
a >= 0 && a <= b into (unsigned) a <= (unsigned) b */
@@ -3202,6 +3342,8 @@ optimize_range_tests (enum tree_code opcode,
if (lshift_cheap_p (optimize_function_for_speed_p (cfun)))
any_changes |= optimize_range_tests_to_bit_test (opcode, first, length,
ops, ranges);
+ any_changes |= optimize_range_tests_cmp_bitwise (opcode, first, length,
+ ops, ranges);
any_changes |= optimize_range_tests_var_bound (opcode, first, length, ops,
ranges);
@@ -5768,7 +5910,7 @@ reassociate_bb (basic_block bb)
move it to the front. This helps ensure that we generate
(X & Y) & C rather than (X & C) & Y. The former will
often match a canonical bit test when we get to RTL. */
- if (ops.length () != 2
+ if (ops.length () > 2
&& (rhs_code == BIT_AND_EXPR
|| rhs_code == BIT_IOR_EXPR
|| rhs_code == BIT_XOR_EXPR)
@@ -5891,12 +6033,10 @@ branch_fixup (void)
edge etrue = make_edge (cond_bb, merge_bb, EDGE_TRUE_VALUE);
etrue->probability = profile_probability::even ();
- etrue->count = cond_bb->count.apply_scale (1, 2);
edge efalse = find_edge (cond_bb, then_bb);
efalse->flags = EDGE_FALSE_VALUE;
efalse->probability -= etrue->probability;
- efalse->count -= etrue->count;
- then_bb->count -= etrue->count;
+ then_bb->count -= etrue->count ();
tree othervar = NULL_TREE;
if (gimple_assign_rhs1 (use_stmt) == var)
diff --git a/gcc/tree-ssa-sccvn.c b/gcc/tree-ssa-sccvn.c
index 0b0c510..d27bcee 100644
--- a/gcc/tree-ssa-sccvn.c
+++ b/gcc/tree-ssa-sccvn.c
@@ -1167,7 +1167,7 @@ vn_reference_fold_indirect (vec<vn_reference_op_s> *ops,
gcc_checking_assert (addr_base && TREE_CODE (addr_base) != MEM_REF);
if (addr_base != TREE_OPERAND (op->op0, 0))
{
- offset_int off = offset_int::from (mem_op->op0, SIGNED);
+ offset_int off = offset_int::from (wi::to_wide (mem_op->op0), SIGNED);
off += addr_offset;
mem_op->op0 = wide_int_to_tree (TREE_TYPE (mem_op->op0), off);
op->op0 = build_fold_addr_expr (addr_base);
@@ -1202,7 +1202,7 @@ vn_reference_maybe_forwprop_address (vec<vn_reference_op_s> *ops,
&& code != POINTER_PLUS_EXPR)
return false;
- off = offset_int::from (mem_op->op0, SIGNED);
+ off = offset_int::from (wi::to_wide (mem_op->op0), SIGNED);
/* The only thing we have to do is from &OBJ.foo.bar add the offset
from .foo.bar to the preceding MEM_REF offset and replace the
@@ -1235,8 +1235,9 @@ vn_reference_maybe_forwprop_address (vec<vn_reference_op_s> *ops,
&& tem[tem.length () - 2].opcode == MEM_REF)
{
vn_reference_op_t new_mem_op = &tem[tem.length () - 2];
- new_mem_op->op0 = wide_int_to_tree (TREE_TYPE (mem_op->op0),
- new_mem_op->op0);
+ new_mem_op->op0
+ = wide_int_to_tree (TREE_TYPE (mem_op->op0),
+ wi::to_wide (new_mem_op->op0));
}
else
gcc_assert (tem.last ().opcode == STRING_CST);
@@ -3028,16 +3029,13 @@ vn_phi_eq (const_vn_phi_t const vp1, const_vn_phi_t const vp2)
return false;
/* Verify the controlling stmt is the same. */
- gimple *last1 = last_stmt (idom1);
- gimple *last2 = last_stmt (idom2);
- if (gimple_code (last1) != GIMPLE_COND
- || gimple_code (last2) != GIMPLE_COND)
+ gcond *last1 = safe_dyn_cast <gcond *> (last_stmt (idom1));
+ gcond *last2 = safe_dyn_cast <gcond *> (last_stmt (idom2));
+ if (! last1 || ! last2)
return false;
bool inverted_p;
- if (! cond_stmts_equal_p (as_a <gcond *> (last1),
- vp1->cclhs, vp1->ccrhs,
- as_a <gcond *> (last2),
- vp2->cclhs, vp2->ccrhs,
+ if (! cond_stmts_equal_p (last1, vp1->cclhs, vp1->ccrhs,
+ last2, vp2->cclhs, vp2->ccrhs,
&inverted_p))
return false;
@@ -3122,7 +3120,7 @@ vn_phi_lookup (gimple *phi)
vp1.ccrhs = NULL_TREE;
basic_block idom1 = get_immediate_dominator (CDI_DOMINATORS, vp1.block);
if (EDGE_COUNT (idom1->succs) == 2)
- if (gcond *last1 = dyn_cast <gcond *> (last_stmt (idom1)))
+ if (gcond *last1 = safe_dyn_cast <gcond *> (last_stmt (idom1)))
{
vp1.cclhs = vn_valueize (gimple_cond_lhs (last1));
vp1.ccrhs = vn_valueize (gimple_cond_rhs (last1));
@@ -3168,7 +3166,7 @@ vn_phi_insert (gimple *phi, tree result)
vp1->ccrhs = NULL_TREE;
basic_block idom1 = get_immediate_dominator (CDI_DOMINATORS, vp1->block);
if (EDGE_COUNT (idom1->succs) == 2)
- if (gcond *last1 = dyn_cast <gcond *> (last_stmt (idom1)))
+ if (gcond *last1 = safe_dyn_cast <gcond *> (last_stmt (idom1)))
{
vp1->cclhs = vn_valueize (gimple_cond_lhs (last1));
vp1->ccrhs = vn_valueize (gimple_cond_rhs (last1));
@@ -3358,6 +3356,12 @@ set_ssa_val_to (tree from, tree to)
if (currval != to
&& !operand_equal_p (currval, to, 0)
+ /* Different undefined SSA names are not actually different. See
+ PR82320 for a testcase were we'd otherwise not terminate iteration. */
+ && !(TREE_CODE (currval) == SSA_NAME
+ && TREE_CODE (to) == SSA_NAME
+ && ssa_undefined_value_p (currval, false)
+ && ssa_undefined_value_p (to, false))
/* ??? For addresses involving volatile objects or types operand_equal_p
does not reliably detect ADDR_EXPRs as equal. We know we are only
getting invariant gimple addresses here, so can use
@@ -3534,7 +3538,7 @@ valueized_wider_op (tree wide_type, tree op)
/* For constants simply extend it. */
if (TREE_CODE (op) == INTEGER_CST)
- return wide_int_to_tree (wide_type, op);
+ return wide_int_to_tree (wide_type, wi::to_wide (op));
return NULL_TREE;
}
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index 2cca970..89135ea 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -2849,41 +2849,33 @@ lookup_vi_for_tree (tree t)
static const char *
alias_get_name (tree decl)
{
- const char *res = NULL;
- char *temp;
-
- if (!dump_file)
- return "NULL";
-
- if (TREE_CODE (decl) == SSA_NAME)
- {
- res = get_name (decl);
- if (res)
- temp = xasprintf ("%s_%u", res, SSA_NAME_VERSION (decl));
- else
- temp = xasprintf ("_%u", SSA_NAME_VERSION (decl));
- res = ggc_strdup (temp);
- free (temp);
- }
- else if (DECL_P (decl))
+ const char *res = "NULL";
+ if (dump_file)
{
- if (DECL_ASSEMBLER_NAME_SET_P (decl))
- res = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
- else
+ char *temp = NULL;
+ if (TREE_CODE (decl) == SSA_NAME)
+ {
+ res = get_name (decl);
+ temp = xasprintf ("%s_%u", res ? res : "", SSA_NAME_VERSION (decl));
+ }
+ else if (HAS_DECL_ASSEMBLER_NAME_P (decl)
+ && DECL_ASSEMBLER_NAME_SET_P (decl))
+ res = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME_RAW (decl));
+ else if (DECL_P (decl))
{
res = get_name (decl);
if (!res)
- {
- temp = xasprintf ("D.%u", DECL_UID (decl));
- res = ggc_strdup (temp);
- free (temp);
- }
+ temp = xasprintf ("D.%u", DECL_UID (decl));
+ }
+
+ if (temp)
+ {
+ res = ggc_strdup (temp);
+ free (temp);
}
}
- if (res != NULL)
- return res;
- return "NULL";
+ return res;
}
/* Find the variable id for tree T in the map.
@@ -3098,7 +3090,7 @@ get_constraint_for_ptr_offset (tree ptr, tree offset,
else
{
/* Sign-extend the offset. */
- offset_int soffset = offset_int::from (offset, SIGNED);
+ offset_int soffset = offset_int::from (wi::to_wide (offset), SIGNED);
if (!wi::fits_shwi_p (soffset))
rhsoffset = UNKNOWN_OFFSET;
else
diff --git a/gcc/tree-ssa-tail-merge.c b/gcc/tree-ssa-tail-merge.c
index a65ff31..c10289a 100644
--- a/gcc/tree-ssa-tail-merge.c
+++ b/gcc/tree-ssa-tail-merge.c
@@ -1570,14 +1570,14 @@ replace_block_by (basic_block bb1, basic_block bb2)
making the bb count inconsistent with the edge weights. */
FOR_EACH_EDGE (e1, ei, bb1->succs)
{
- if (e1->count.initialized_p ())
- out_sum += e1->count;
+ if (e1->count ().initialized_p ())
+ out_sum += e1->count ();
out_freq_sum += EDGE_FREQUENCY (e1);
}
FOR_EACH_EDGE (e1, ei, bb2->succs)
{
- if (e1->count.initialized_p ())
- out_sum += e1->count;
+ if (e1->count ().initialized_p ())
+ out_sum += e1->count ();
out_freq_sum += EDGE_FREQUENCY (e1);
}
@@ -1585,10 +1585,9 @@ replace_block_by (basic_block bb1, basic_block bb2)
{
e2 = find_edge (bb2, e1->dest);
gcc_assert (e2);
- e2->count += e1->count;
- if (out_sum > 0 && e2->count.initialized_p ())
+ if (out_sum > 0 && e2->count ().initialized_p ())
{
- e2->probability = e2->count.probability_in (bb2->count);
+ e2->probability = e2->count ().probability_in (bb2->count);
}
else if (bb1->frequency && bb2->frequency)
e2->probability = e1->probability;
@@ -1599,7 +1598,7 @@ replace_block_by (basic_block bb1, basic_block bb2)
(GCOV_COMPUTE_SCALE (EDGE_FREQUENCY (e1)
+ EDGE_FREQUENCY (e2),
out_freq_sum));
- out_sum += e2->count;
+ out_sum += e2->count ();
}
bb2->frequency += bb1->frequency;
if (bb2->frequency > BB_FREQ_MAX)
diff --git a/gcc/tree-ssa-threadupdate.c b/gcc/tree-ssa-threadupdate.c
index 28c81a6..8681707 100644
--- a/gcc/tree-ssa-threadupdate.c
+++ b/gcc/tree-ssa-threadupdate.c
@@ -303,7 +303,6 @@ remove_ctrl_stmt_and_useless_edges (basic_block bb, basic_block dest_bb)
else
{
e->probability = profile_probability::always ();
- e->count = bb->count;
ei_next (&ei);
}
}
@@ -741,7 +740,7 @@ compute_path_counts (struct redirection_data *rd,
same last path edge in the case where the last edge has a nocopy
source block. */
gcc_assert (ein_path->last ()->e == elast);
- path_in_count += ein->count;
+ path_in_count += ein->count ();
path_in_freq += EDGE_FREQUENCY (ein);
}
else if (!ein_path)
@@ -749,7 +748,7 @@ compute_path_counts (struct redirection_data *rd,
/* Keep track of the incoming edges that are not on any jump-threading
path. These counts will still flow out of original path after all
jump threading is complete. */
- nonpath_count += ein->count;
+ nonpath_count += ein->count ();
}
}
@@ -789,7 +788,7 @@ compute_path_counts (struct redirection_data *rd,
for (unsigned int i = 1; i < path->length (); i++)
{
edge epath = (*path)[i]->e;
- profile_count cur_count = epath->count;
+ profile_count cur_count = epath->count ();
if ((*path)[i]->type == EDGE_COPY_SRC_JOINER_BLOCK)
{
has_joiner = true;
@@ -809,13 +808,13 @@ compute_path_counts (struct redirection_data *rd,
they are redirected by an invocation of this routine. */
&& !bitmap_bit_p (local_info->duplicate_blocks,
ein->src->index))
- nonpath_count += ein->count;
+ nonpath_count += ein->count ();
}
}
if (cur_count < path_out_count)
path_out_count = cur_count;
- if (epath->count < min_path_count)
- min_path_count = epath->count;
+ if (epath->count () < min_path_count)
+ min_path_count = epath->count ();
}
/* We computed path_out_count above assuming that this path targeted
@@ -830,12 +829,12 @@ compute_path_counts (struct redirection_data *rd,
(since any path through the joiner with a different elast will not
include a copy of this elast in its duplicated path).
So ensure that this path's path_out_count is at least the
- difference between elast->count and nonpath_count. Otherwise the edge
+ difference between elast->count () and nonpath_count. Otherwise the edge
counts after threading will not be sane. */
if (local_info->need_profile_correction
- && has_joiner && path_out_count < elast->count - nonpath_count)
+ && has_joiner && path_out_count < elast->count () - nonpath_count)
{
- path_out_count = elast->count - nonpath_count;
+ path_out_count = elast->count () - nonpath_count;
/* But neither can we go above the minimum count along the path
we are duplicating. This can be an issue due to profile
insanities coming in to this pass. */
@@ -858,17 +857,54 @@ static void
update_profile (edge epath, edge edup, profile_count path_in_count,
profile_count path_out_count, int path_in_freq)
{
+ if (!(path_in_count > 0))
+ return;
/* First update the duplicated block's count / frequency. */
if (edup)
{
basic_block dup_block = edup->src;
- gcc_assert (!dup_block->count.initialized_p ());
+
+ /* Edup's count is reduced by path_out_count. We need to redistribute
+ probabilities to the remaining edges. */
+
+ edge esucc;
+ edge_iterator ei;
+ profile_probability edup_prob
+ = path_out_count.probability_in (path_in_count);
+
+ /* Either scale up or down the remaining edges.
+ probabilities are always in range <0,1> and thus we can't do
+ both by same loop. */
+ if (edup->probability > edup_prob)
+ {
+ profile_probability rev_scale
+ = (profile_probability::always () - edup->probability)
+ / (profile_probability::always () - edup_prob);
+ FOR_EACH_EDGE (esucc, ei, dup_block->succs)
+ if (esucc != edup)
+ esucc->probability /= rev_scale;
+ }
+ else if (edup->probability < edup_prob)
+ {
+ profile_probability scale
+ = (profile_probability::always () - edup_prob)
+ / (profile_probability::always () - edup->probability);
+ FOR_EACH_EDGE (esucc, ei, dup_block->succs)
+ if (esucc != edup)
+ esucc->probability *= scale;
+ }
+ edup->probability = edup_prob;
+
+ /* FIXME once freqs_to_counts is dropped re-enable this check. */
+ gcc_assert (!dup_block->count.initialized_p () || 1);
gcc_assert (dup_block->frequency == 0);
dup_block->count = path_in_count;
dup_block->frequency = path_in_freq;
}
+ profile_count final_count = epath->count () - path_out_count;
+
/* Now update the original block's count and frequency in the
opposite manner - remove the counts/freq that will flow
into the duplicated block. Handle underflow due to precision/
@@ -883,107 +919,31 @@ update_profile (edge epath, edge edup, profile_count path_in_count,
out of it (in the joiner case this is the count along the duplicated path
out of the duplicated joiner). This count can then be removed from the
original path edge. */
- if (edup)
- edup->count = path_out_count;
- epath->count -= path_out_count;
- /* FIXME: can epath->count be legally uninitialized here? */
-}
-
-
-/* The duplicate and original joiner blocks may end up with different
- probabilities (different from both the original and from each other).
- Recompute the probabilities here once we have updated the edge
- counts and frequencies. */
-
-static void
-recompute_probabilities (basic_block bb)
-{
- edge esucc;
- edge_iterator ei;
- FOR_EACH_EDGE (esucc, ei, bb->succs)
- {
- if (!(bb->count > 0))
- continue;
-
- /* Prevent overflow computation due to insane profiles. */
- if (esucc->count < bb->count)
- esucc->probability = esucc->count.probability_in (bb->count).guessed ();
- else
- /* Can happen with missing/guessed probabilities, since we
- may determine that more is flowing along duplicated
- path than joiner succ probabilities allowed.
- Counts and freqs will be insane after jump threading,
- at least make sure probability is sane or we will
- get a flow verification error.
- Not much we can do to make counts/freqs sane without
- redoing the profile estimation. */
- esucc->probability = profile_probability::guessed_always ();
- }
-}
-
-
-/* Update the counts of the original and duplicated edges from a joiner
- that go off path, given that we have already determined that the
- duplicate joiner DUP_BB has incoming count PATH_IN_COUNT and
- outgoing count along the path PATH_OUT_COUNT. The original (on-)path
- edge from joiner is EPATH. */
-
-static void
-update_joiner_offpath_counts (edge epath, basic_block dup_bb,
- profile_count path_in_count,
- profile_count path_out_count)
-{
- /* Compute the count that currently flows off path from the joiner.
- In other words, the total count of joiner's out edges other than
- epath. Compute this by walking the successors instead of
- subtracting epath's count from the joiner bb count, since there
- are sometimes slight insanities where the total out edge count is
- larger than the bb count (possibly due to rounding/truncation
- errors). */
- profile_count total_orig_off_path_count = profile_count::zero ();
- edge enonpath;
- edge_iterator ei;
- FOR_EACH_EDGE (enonpath, ei, epath->src->succs)
+ if (epath->src->count > 0)
{
- if (enonpath == epath)
- continue;
- total_orig_off_path_count += enonpath->count;
- }
-
- /* For the path that we are duplicating, the amount that will flow
- off path from the duplicated joiner is the delta between the
- path's cumulative in count and the portion of that count we
- estimated above as flowing from the joiner along the duplicated
- path. */
- profile_count total_dup_off_path_count = path_in_count - path_out_count;
-
- /* Now do the actual updates of the off-path edges. */
- FOR_EACH_EDGE (enonpath, ei, epath->src->succs)
- {
- /* Look for edges going off of the threading path. */
- if (enonpath == epath)
- continue;
+ edge esucc;
+ edge_iterator ei;
+ profile_probability epath_prob = final_count.probability_in (epath->src->count);
- /* Find the corresponding edge out of the duplicated joiner. */
- edge enonpathdup = find_edge (dup_bb, enonpath->dest);
- gcc_assert (enonpathdup);
-
- /* We can't use the original probability of the joiner's out
- edges, since the probabilities of the original branch
- and the duplicated branches may vary after all threading is
- complete. But apportion the duplicated joiner's off-path
- total edge count computed earlier (total_dup_off_path_count)
- among the duplicated off-path edges based on their original
- ratio to the full off-path count (total_orig_off_path_count).
- */
- profile_probability scale
- = enonpath->count.probability_in (total_orig_off_path_count);
- /* Give the duplicated offpath edge a portion of the duplicated
- total. */
- enonpathdup->count = total_dup_off_path_count.apply_probability (scale);
- /* Now update the original offpath edge count, handling underflow
- due to rounding errors. */
- enonpath->count -= enonpathdup->count;
+ if (epath->probability > epath_prob)
+ {
+ profile_probability rev_scale
+ = (profile_probability::always () - epath->probability)
+ / (profile_probability::always () - epath_prob);
+ FOR_EACH_EDGE (esucc, ei, epath->src->succs)
+ if (esucc != epath)
+ esucc->probability /= rev_scale;
+ }
+ else if (epath->probability < epath_prob)
+ {
+ profile_probability scale
+ = (profile_probability::always () - epath_prob)
+ / (profile_probability::always () - epath->probability);
+ FOR_EACH_EDGE (esucc, ei, epath->src->succs)
+ if (esucc != epath)
+ esucc->probability *= scale;
+ }
+ epath->probability = epath_prob;
}
}
@@ -1002,7 +962,7 @@ estimated_freqs_path (struct redirection_data *rd)
bool non_zero_freq = false;
FOR_EACH_EDGE (ein, ei, e->dest->preds)
{
- if (ein->count > 0)
+ if (ein->count () > 0)
return false;
non_zero_freq |= ein->src->frequency != 0;
}
@@ -1016,7 +976,7 @@ estimated_freqs_path (struct redirection_data *rd)
edge esucc;
FOR_EACH_EDGE (esucc, ei, epath->src->succs)
{
- if (esucc->count > 0)
+ if (esucc->count () > 0)
return false;
non_zero_freq |= esucc->src->frequency != 0;
}
@@ -1042,34 +1002,19 @@ freqs_to_counts_path (struct redirection_data *rd)
vec<jump_thread_edge *> *path = THREAD_PATH (e);
edge ein;
edge_iterator ei;
- FOR_EACH_EDGE (ein, ei, e->dest->preds)
- {
- /* Scale up the frequency by REG_BR_PROB_BASE, to avoid rounding
- errors applying the probability when the frequencies are very
- small. */
- if (ein->probability.initialized_p ())
- ein->count = profile_count::from_gcov_type
- (apply_probability (ein->src->frequency * REG_BR_PROB_BASE,
- ein->probability
- .to_reg_br_prob_base ())).guessed ();
- else
- /* FIXME: this is hack; we should track uninitialized values. */
- ein->count = profile_count::zero ();
- }
+ FOR_EACH_EDGE (ein, ei, e->dest->preds)
+ ein->src->count = profile_count::from_gcov_type
+ (ein->src->frequency * REG_BR_PROB_BASE);
for (unsigned int i = 1; i < path->length (); i++)
{
edge epath = (*path)[i]->e;
- edge esucc;
/* Scale up the frequency by REG_BR_PROB_BASE, to avoid rounding
errors applying the edge probability when the frequencies are very
small. */
epath->src->count =
profile_count::from_gcov_type
(epath->src->frequency * REG_BR_PROB_BASE);
- FOR_EACH_EDGE (esucc, ei, epath->src->succs)
- esucc->count =
- esucc->src->count.apply_probability (esucc->probability);
}
}
@@ -1086,21 +1031,20 @@ clear_counts_path (struct redirection_data *rd)
{
edge e = rd->incoming_edges->e;
vec<jump_thread_edge *> *path = THREAD_PATH (e);
- edge ein, esucc;
- edge_iterator ei;
profile_count val = profile_count::uninitialized ();
if (profile_status_for_fn (cfun) == PROFILE_READ)
val = profile_count::zero ();
+ edge ein;
+ edge_iterator ei;
+
FOR_EACH_EDGE (ein, ei, e->dest->preds)
- ein->count = val;
+ ein->src->count = val;
/* First clear counts along original path. */
for (unsigned int i = 1; i < path->length (); i++)
{
edge epath = (*path)[i]->e;
- FOR_EACH_EDGE (esucc, ei, epath->src->succs)
- esucc->count = val;
epath->src->count = val;
}
/* Also need to clear the counts along duplicated path. */
@@ -1109,8 +1053,6 @@ clear_counts_path (struct redirection_data *rd)
basic_block dup = rd->dup_blocks[i];
if (!dup)
continue;
- FOR_EACH_EDGE (esucc, ei, dup->succs)
- esucc->count = val;
dup->count = val;
}
}
@@ -1230,17 +1172,6 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd,
update_profile (epath, e2, path_in_count, path_out_count,
path_in_freq);
- /* Next we need to update the counts of the original and duplicated
- edges from the joiner that go off path. */
- update_joiner_offpath_counts (epath, e2->src, path_in_count,
- path_out_count);
-
- /* Finally, we need to set the probabilities on the duplicated
- edges out of the duplicated joiner (e2->src). The probabilities
- along the original path will all be updated below after we finish
- processing the whole path. */
- recompute_probabilities (e2->src);
-
/* Record the frequency flowing to the downstream duplicated
path blocks. */
cur_path_freq = EDGE_FREQUENCY (e2);
@@ -1263,8 +1194,7 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd,
been updated at the end of that handling to the edge frequency
along the duplicated joiner path edge. */
update_profile (epath, EDGE_SUCC (rd->dup_blocks[count], 0),
- path_out_count, path_out_count,
- cur_path_freq);
+ path_out_count, path_out_count, cur_path_freq);
}
else
{
@@ -1294,14 +1224,6 @@ ssa_fix_duplicate_block_edges (struct redirection_data *rd,
}
}
- /* Now walk orig blocks and update their probabilities, since the
- counts and freqs should be updated properly by above loop. */
- for (unsigned int i = 1; i < path->length (); i++)
- {
- edge epath = (*path)[i]->e;
- recompute_probabilities (epath->src);
- }
-
/* Done with all profile and frequency updates, clear counts if they
were copied. */
if (do_freqs_to_counts)
@@ -2247,7 +2169,7 @@ duplicate_thread_path (edge entry, edge exit, basic_block *region,
invalidating the property that is propagated by executing all the blocks of
the jump-thread path in order. */
- curr_count = entry->count;
+ curr_count = entry->count ();
curr_freq = EDGE_FREQUENCY (entry);
for (i = 0; i < n_region; i++)
@@ -2300,7 +2222,7 @@ duplicate_thread_path (edge entry, edge exit, basic_block *region,
if (i + 1 != n_region)
{
curr_freq = EDGE_FREQUENCY (single_succ_edge (bb));
- curr_count = single_succ_edge (bb)->count;
+ curr_count = single_succ_edge (bb)->count ();
}
continue;
}
@@ -2331,7 +2253,7 @@ duplicate_thread_path (edge entry, edge exit, basic_block *region,
else
{
curr_freq = EDGE_FREQUENCY (e);
- curr_count = e->count;
+ curr_count = e->count ();
}
}
@@ -2353,7 +2275,6 @@ duplicate_thread_path (edge entry, edge exit, basic_block *region,
{
rescan_loop_exit (e, true, false);
e->probability = profile_probability::always ();
- e->count = region_copy[n_region - 1]->count;
}
/* Redirect the entry and add the phi node arguments. */
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 67f0d84..4096ded 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -1474,8 +1474,8 @@ is_pred_expr_subset_of (pred_info expr1, pred_info expr2)
code2 = invert_tree_comparison (code2, false);
if ((code1 == EQ_EXPR || code1 == BIT_AND_EXPR) && code2 == BIT_AND_EXPR)
- return wi::eq_p (expr1.pred_rhs,
- wi::bit_and (expr1.pred_rhs, expr2.pred_rhs));
+ return (wi::to_wide (expr1.pred_rhs)
+ == (wi::to_wide (expr1.pred_rhs) & wi::to_wide (expr2.pred_rhs)));
if (code1 != code2 && code2 != NE_EXPR)
return false;
diff --git a/gcc/tree-ssanames.c b/gcc/tree-ssanames.c
index 5c96075..6d344ad 100644
--- a/gcc/tree-ssanames.c
+++ b/gcc/tree-ssanames.c
@@ -454,8 +454,8 @@ set_nonzero_bits (tree name, const wide_int_ref &mask)
if (mask == -1)
return;
set_range_info_raw (name, VR_RANGE,
- TYPE_MIN_VALUE (TREE_TYPE (name)),
- TYPE_MAX_VALUE (TREE_TYPE (name)));
+ wi::to_wide (TYPE_MIN_VALUE (TREE_TYPE (name))),
+ wi::to_wide (TYPE_MAX_VALUE (TREE_TYPE (name))));
}
range_info_def *ri = SSA_NAME_RANGE_INFO (name);
ri->set_nonzero_bits (mask);
@@ -468,7 +468,7 @@ wide_int
get_nonzero_bits (const_tree name)
{
if (TREE_CODE (name) == INTEGER_CST)
- return name;
+ return wi::to_wide (name);
/* Use element_precision instead of TYPE_PRECISION so complex and
vector types get a non-zero precision. */
diff --git a/gcc/tree-switch-conversion.c b/gcc/tree-switch-conversion.c
index 6d7c2c4..a786377 100644
--- a/gcc/tree-switch-conversion.c
+++ b/gcc/tree-switch-conversion.c
@@ -107,8 +107,7 @@ hoist_edge_and_branch_if_true (gimple_stmt_iterator *gsip,
e_false->flags &= ~EDGE_FALLTHRU;
e_false->flags |= EDGE_FALSE_VALUE;
e_false->probability = e_true->probability.invert ();
- e_false->count = split_bb->count - e_true->count;
- new_bb->count = e_false->count;
+ new_bb->count = e_false->count ();
if (update_dominators)
{
@@ -239,9 +238,9 @@ case_bit_test_cmp (const void *p1, const void *p2)
const struct case_bit_test *const d1 = (const struct case_bit_test *) p1;
const struct case_bit_test *const d2 = (const struct case_bit_test *) p2;
- if (d2->target_edge->count < d1->target_edge->count)
+ if (d2->target_edge->count () < d1->target_edge->count ())
return -1;
- if (d2->target_edge->count > d1->target_edge->count)
+ if (d2->target_edge->count () > d1->target_edge->count ())
return 1;
if (d2->bits != d1->bits)
return d2->bits - d1->bits;
@@ -635,10 +634,10 @@ collect_switch_conv_info (gswitch *swtch, struct switch_conv_info *info)
= label_to_block (CASE_LABEL (gimple_switch_default_label (swtch)));
e_default = find_edge (info->switch_bb, info->default_bb);
info->default_prob = e_default->probability;
- info->default_count = e_default->count;
+ info->default_count = e_default->count ();
FOR_EACH_EDGE (e, ei, info->switch_bb->succs)
if (e != e_default)
- info->other_count += e->count;
+ info->other_count += e->count ();
/* Get upper and lower bounds of case values, and the covered range. */
min_case = gimple_switch_label (swtch, 1);
@@ -655,8 +654,7 @@ collect_switch_conv_info (gswitch *swtch, struct switch_conv_info *info)
for (i = 2; i < branch_num; i++)
{
tree elt = gimple_switch_label (swtch, i);
- wide_int w = last;
- if (w + 1 != CASE_LOW (elt))
+ if (wi::to_wide (last) + 1 != wi::to_wide (CASE_LOW (elt)))
{
info->contiguous_range = false;
break;
@@ -1065,7 +1063,7 @@ array_value_type (gswitch *swtch, tree type, int num,
if (TREE_CODE (elt->value) != INTEGER_CST)
return type;
- cst = elt->value;
+ cst = wi::to_wide (elt->value);
while (1)
{
unsigned int prec = GET_MODE_BITSIZE (mode);
@@ -1425,19 +1423,16 @@ gen_inbound_check (gswitch *swtch, struct switch_conv_info *info)
if (!info->default_case_nonstandard)
e01 = make_edge (bb0, bb1, EDGE_TRUE_VALUE);
e01->probability = info->default_prob.invert ();
- e01->count = info->other_count;
/* flags and profiles of the edge taking care of out-of-range values */
e02->flags &= ~EDGE_FALLTHRU;
e02->flags |= EDGE_FALSE_VALUE;
e02->probability = info->default_prob;
- e02->count = info->default_count;
bbf = info->final_bb;
e1f = make_edge (bb1, bbf, EDGE_FALLTHRU);
e1f->probability = profile_probability::always ();
- e1f->count = info->other_count;
if (info->default_case_nonstandard)
e2f = NULL;
@@ -1445,7 +1440,6 @@ gen_inbound_check (gswitch *swtch, struct switch_conv_info *info)
{
e2f = make_edge (bb2, bbf, EDGE_FALLTHRU);
e2f->probability = profile_probability::always ();
- e2f->count = info->default_count;
}
/* frequencies of the new BBs */
@@ -1778,11 +1772,12 @@ dump_case_nodes (FILE *f, case_node *root, int indent_step, int indent_level)
fputs (";; ", f);
fprintf (f, "%*s", indent_step * indent_level, "");
- print_dec (root->low, f, TYPE_SIGN (TREE_TYPE (root->low)));
+ print_dec (wi::to_wide (root->low), f, TYPE_SIGN (TREE_TYPE (root->low)));
if (!tree_int_cst_equal (root->low, root->high))
{
fprintf (f, " ... ");
- print_dec (root->high, f, TYPE_SIGN (TREE_TYPE (root->high)));
+ print_dec (wi::to_wide (root->high), f,
+ TYPE_SIGN (TREE_TYPE (root->high)));
}
fputs ("\n", f);
@@ -2113,7 +2108,7 @@ try_switch_expansion (gswitch *stmt)
original type. Make sure to drop overflow flags. */
low = fold_convert (index_type, low);
if (TREE_OVERFLOW (low))
- low = wide_int_to_tree (index_type, low);
+ low = wide_int_to_tree (index_type, wi::to_wide (low));
/* The canonical from of a case label in GIMPLE is that a simple case
has an empty CASE_HIGH. For the casesi and tablejump expanders,
@@ -2122,7 +2117,7 @@ try_switch_expansion (gswitch *stmt)
high = low;
high = fold_convert (index_type, high);
if (TREE_OVERFLOW (high))
- high = wide_int_to_tree (index_type, high);
+ high = wide_int_to_tree (index_type, wi::to_wide (high));
basic_block case_bb = label_to_block_fn (cfun, lab);
edge case_edge = find_edge (bb, case_bb);
diff --git a/gcc/tree-tailcall.c b/gcc/tree-tailcall.c
index c4b8cee..9bcd1d6 100644
--- a/gcc/tree-tailcall.c
+++ b/gcc/tree-tailcall.c
@@ -807,7 +807,6 @@ adjust_return_value (basic_block bb, tree m, tree a)
static void
decrease_profile (basic_block bb, profile_count count, int frequency)
{
- edge e;
bb->count = bb->count - count;
bb->frequency -= frequency;
if (bb->frequency < 0)
@@ -817,8 +816,6 @@ decrease_profile (basic_block bb, profile_count count, int frequency)
gcc_assert (!EDGE_COUNT (bb->succs));
return;
}
- e = single_succ_edge (bb);
- e->count -= count;
}
/* Returns true if argument PARAM of the tail recursive call needs to be copied
@@ -895,11 +892,11 @@ eliminate_tail_call (struct tailcall *t)
/* Number of executions of function has reduced by the tailcall. */
e = single_succ_edge (gsi_bb (t->call_gsi));
- decrease_profile (EXIT_BLOCK_PTR_FOR_FN (cfun), e->count, EDGE_FREQUENCY (e));
- decrease_profile (ENTRY_BLOCK_PTR_FOR_FN (cfun), e->count,
+ decrease_profile (EXIT_BLOCK_PTR_FOR_FN (cfun), e->count (), EDGE_FREQUENCY (e));
+ decrease_profile (ENTRY_BLOCK_PTR_FOR_FN (cfun), e->count (),
EDGE_FREQUENCY (e));
if (e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun))
- decrease_profile (e->dest, e->count, EDGE_FREQUENCY (e));
+ decrease_profile (e->dest, e->count (), EDGE_FREQUENCY (e));
/* Replace the call by a jump to the start of function. */
e = redirect_edge_and_branch (single_succ_edge (gsi_bb (t->call_gsi)),
diff --git a/gcc/tree-vect-data-refs.c b/gcc/tree-vect-data-refs.c
index cab2f2f..ca86498 100644
--- a/gcc/tree-vect-data-refs.c
+++ b/gcc/tree-vect-data-refs.c
@@ -775,6 +775,17 @@ vect_record_base_alignments (vec_info *vinfo)
}
}
+/* Return the target alignment for the vectorized form of DR. */
+
+static unsigned int
+vect_calculate_target_alignment (struct data_reference *dr)
+{
+ gimple *stmt = DR_STMT (dr);
+ stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+ tree vectype = STMT_VINFO_VECTYPE (stmt_info);
+ return targetm.vectorize.preferred_vector_alignment (vectype);
+}
+
/* Function vect_compute_data_ref_alignment
Compute the misalignment of the data reference DR.
@@ -811,6 +822,10 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
innermost_loop_behavior *drb = vect_dr_behavior (dr);
bool step_preserves_misalignment_p;
+ unsigned HOST_WIDE_INT vector_alignment
+ = vect_calculate_target_alignment (dr) / BITS_PER_UNIT;
+ DR_TARGET_ALIGNMENT (dr) = vector_alignment;
+
/* No step for BB vectorization. */
if (!loop)
{
@@ -823,43 +838,41 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
relative to the outer-loop (LOOP). This is ok only if the misalignment
stays the same throughout the execution of the inner-loop, which is why
we have to check that the stride of the dataref in the inner-loop evenly
- divides by the vector size. */
+ divides by the vector alignment. */
else if (nested_in_vect_loop_p (loop, stmt))
{
step_preserves_misalignment_p
- = (DR_STEP_ALIGNMENT (dr)
- % GET_MODE_SIZE (TYPE_MODE (vectype))) == 0;
+ = (DR_STEP_ALIGNMENT (dr) % vector_alignment) == 0;
if (dump_enabled_p ())
{
if (step_preserves_misalignment_p)
dump_printf_loc (MSG_NOTE, vect_location,
- "inner step divides the vector-size.\n");
+ "inner step divides the vector alignment.\n");
else
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "inner step doesn't divide the vector-size.\n");
+ "inner step doesn't divide the vector"
+ " alignment.\n");
}
}
/* Similarly we can only use base and misalignment information relative to
an innermost loop if the misalignment stays the same throughout the
execution of the loop. As above, this is the case if the stride of
- the dataref evenly divides by the vector size. */
+ the dataref evenly divides by the alignment. */
else
{
unsigned vf = LOOP_VINFO_VECT_FACTOR (loop_vinfo);
step_preserves_misalignment_p
- = ((DR_STEP_ALIGNMENT (dr) * vf)
- % GET_MODE_SIZE (TYPE_MODE (vectype))) == 0;
+ = ((DR_STEP_ALIGNMENT (dr) * vf) % vector_alignment) == 0;
if (!step_preserves_misalignment_p && dump_enabled_p ())
dump_printf_loc (MSG_MISSED_OPTIMIZATION, vect_location,
- "step doesn't divide the vector-size.\n");
+ "step doesn't divide the vector alignment.\n");
}
unsigned int base_alignment = drb->base_alignment;
unsigned int base_misalignment = drb->base_misalignment;
- unsigned HOST_WIDE_INT vector_alignment = TYPE_ALIGN_UNIT (vectype);
/* Calculate the maximum of the pooled base address alignment and the
alignment that we can compute for DR itself. */
@@ -955,7 +968,6 @@ vect_compute_data_ref_alignment (struct data_reference *dr)
return true;
}
-
/* Function vect_update_misalignment_for_peel.
Sets DR's misalignment
- to 0 if it has the same alignment as DR_PEEL,
@@ -975,8 +987,8 @@ vect_update_misalignment_for_peel (struct data_reference *dr,
unsigned int i;
vec<dr_p> same_aligned_drs;
struct data_reference *current_dr;
- int dr_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (DR_REF (dr))));
- int dr_peel_size = GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (DR_REF (dr_peel))));
+ int dr_size = vect_get_scalar_dr_size (dr);
+ int dr_peel_size = vect_get_scalar_dr_size (dr_peel);
stmt_vec_info stmt_info = vinfo_for_stmt (DR_STMT (dr));
stmt_vec_info peel_stmt_info = vinfo_for_stmt (DR_STMT (dr_peel));
@@ -1008,9 +1020,8 @@ vect_update_misalignment_for_peel (struct data_reference *dr,
{
bool negative = tree_int_cst_compare (DR_STEP (dr), size_zero_node) < 0;
int misal = DR_MISALIGNMENT (dr);
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
misal += negative ? -npeel * dr_size : npeel * dr_size;
- misal &= (TYPE_ALIGN (vectype) / BITS_PER_UNIT) - 1;
+ misal &= DR_TARGET_ALIGNMENT (dr) - 1;
SET_DR_MISALIGNMENT (dr, misal);
return;
}
@@ -1315,6 +1326,9 @@ vect_get_peeling_costs_all_drs (vec<data_reference_p> datarefs,
{
gimple *stmt = DR_STMT (dr);
stmt_vec_info stmt_info = vinfo_for_stmt (stmt);
+ if (!STMT_VINFO_RELEVANT_P (stmt_info))
+ continue;
+
/* For interleaving, only the alignment of the first access
matters. */
if (STMT_VINFO_GROUPED_ACCESS (stmt_info)
@@ -1658,17 +1672,17 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
{
if (known_alignment_for_access_p (dr))
{
- unsigned int npeel_tmp = 0;
+ unsigned int npeel_tmp = 0;
bool negative = tree_int_cst_compare (DR_STEP (dr),
size_zero_node) < 0;
- vectype = STMT_VINFO_VECTYPE (stmt_info);
- nelements = TYPE_VECTOR_SUBPARTS (vectype);
- mis = DR_MISALIGNMENT (dr) / GET_MODE_SIZE (TYPE_MODE (
- TREE_TYPE (DR_REF (dr))));
+ vectype = STMT_VINFO_VECTYPE (stmt_info);
+ nelements = TYPE_VECTOR_SUBPARTS (vectype);
+ unsigned int target_align = DR_TARGET_ALIGNMENT (dr);
+ unsigned int dr_size = vect_get_scalar_dr_size (dr);
+ mis = (negative ? DR_MISALIGNMENT (dr) : -DR_MISALIGNMENT (dr));
if (DR_MISALIGNMENT (dr) != 0)
- npeel_tmp = (negative ? (mis - nelements)
- : (nelements - mis)) & (nelements - 1);
+ npeel_tmp = (mis & (target_align - 1)) / dr_size;
/* For multiple types, it is possible that the bigger type access
will have more than one peeling option. E.g., a loop with two
@@ -1703,7 +1717,7 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
{
vect_peeling_hash_insert (&peeling_htab, loop_vinfo,
dr, npeel_tmp);
- npeel_tmp += nelements;
+ npeel_tmp += target_align / dr_size;
}
one_misalignment_known = true;
@@ -1924,7 +1938,6 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
stmt = DR_STMT (dr0);
stmt_info = vinfo_for_stmt (stmt);
vectype = STMT_VINFO_VECTYPE (stmt_info);
- nelements = TYPE_VECTOR_SUBPARTS (vectype);
if (known_alignment_for_access_p (dr0))
{
@@ -1937,10 +1950,10 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
updating DR_MISALIGNMENT values. The peeling factor is the
vectorization factor minus the misalignment as an element
count. */
- mis = DR_MISALIGNMENT (dr0);
- mis /= GET_MODE_SIZE (TYPE_MODE (TREE_TYPE (DR_REF (dr0))));
- npeel = ((negative ? mis - nelements : nelements - mis)
- & (nelements - 1));
+ mis = negative ? DR_MISALIGNMENT (dr0) : -DR_MISALIGNMENT (dr0);
+ unsigned int target_align = DR_TARGET_ALIGNMENT (dr0);
+ npeel = ((mis & (target_align - 1))
+ / vect_get_scalar_dr_size (dr0));
}
/* For interleaved data access every iteration accesses all the
@@ -1979,10 +1992,8 @@ vect_enhance_data_refs_alignment (loop_vec_info loop_vinfo)
unsigned max_peel = npeel;
if (max_peel == 0)
{
- gimple *dr_stmt = DR_STMT (dr0);
- stmt_vec_info vinfo = vinfo_for_stmt (dr_stmt);
- tree vtype = STMT_VINFO_VECTYPE (vinfo);
- max_peel = TYPE_VECTOR_SUBPARTS (vtype) - 1;
+ unsigned int target_align = DR_TARGET_ALIGNMENT (dr0);
+ max_peel = target_align / vect_get_scalar_dr_size (dr0) - 1;
}
if (max_peel > max_allowed_peel)
{
@@ -2204,8 +2215,10 @@ vect_find_same_alignment_drs (struct data_dependence_relation *ddr)
if (diff != 0)
{
/* Get the wider of the two alignments. */
- unsigned int align_a = TYPE_ALIGN_UNIT (STMT_VINFO_VECTYPE (stmtinfo_a));
- unsigned int align_b = TYPE_ALIGN_UNIT (STMT_VINFO_VECTYPE (stmtinfo_b));
+ unsigned int align_a = (vect_calculate_target_alignment (dra)
+ / BITS_PER_UNIT);
+ unsigned int align_b = (vect_calculate_target_alignment (drb)
+ / BITS_PER_UNIT);
unsigned int max_align = MAX (align_a, align_b);
/* Require the gap to be a multiple of the larger vector alignment. */
@@ -2714,43 +2727,30 @@ dr_group_sort_cmp (const void *dra_, const void *drb_)
return loopa->num < loopb->num ? -1 : 1;
/* Ordering of DRs according to base. */
- if (!operand_equal_p (DR_BASE_ADDRESS (dra), DR_BASE_ADDRESS (drb), 0))
- {
- cmp = data_ref_compare_tree (DR_BASE_ADDRESS (dra),
- DR_BASE_ADDRESS (drb));
- if (cmp != 0)
- return cmp;
- }
+ cmp = data_ref_compare_tree (DR_BASE_ADDRESS (dra),
+ DR_BASE_ADDRESS (drb));
+ if (cmp != 0)
+ return cmp;
/* And according to DR_OFFSET. */
- if (!dr_equal_offsets_p (dra, drb))
- {
- cmp = data_ref_compare_tree (DR_OFFSET (dra), DR_OFFSET (drb));
- if (cmp != 0)
- return cmp;
- }
+ cmp = data_ref_compare_tree (DR_OFFSET (dra), DR_OFFSET (drb));
+ if (cmp != 0)
+ return cmp;
/* Put reads before writes. */
if (DR_IS_READ (dra) != DR_IS_READ (drb))
return DR_IS_READ (dra) ? -1 : 1;
/* Then sort after access size. */
- if (!operand_equal_p (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dra))),
- TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (drb))), 0))
- {
- cmp = data_ref_compare_tree (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dra))),
- TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (drb))));
- if (cmp != 0)
- return cmp;
- }
+ cmp = data_ref_compare_tree (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dra))),
+ TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (drb))));
+ if (cmp != 0)
+ return cmp;
/* And after step. */
- if (!operand_equal_p (DR_STEP (dra), DR_STEP (drb), 0))
- {
- cmp = data_ref_compare_tree (DR_STEP (dra), DR_STEP (drb));
- if (cmp != 0)
- return cmp;
- }
+ cmp = data_ref_compare_tree (DR_STEP (dra), DR_STEP (drb));
+ if (cmp != 0)
+ return cmp;
/* Then sort after DR_INIT. In case of identical DRs sort after stmt UID. */
cmp = tree_int_cst_compare (DR_INIT (dra), DR_INIT (drb));
@@ -2822,9 +2822,9 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
and they are both either store or load (not load and store,
not masked loads or stores). */
if (DR_IS_READ (dra) != DR_IS_READ (drb)
- || !operand_equal_p (DR_BASE_ADDRESS (dra),
- DR_BASE_ADDRESS (drb), 0)
- || !dr_equal_offsets_p (dra, drb)
+ || data_ref_compare_tree (DR_BASE_ADDRESS (dra),
+ DR_BASE_ADDRESS (drb)) != 0
+ || data_ref_compare_tree (DR_OFFSET (dra), DR_OFFSET (drb)) != 0
|| !gimple_assign_single_p (DR_STMT (dra))
|| !gimple_assign_single_p (DR_STMT (drb)))
break;
@@ -2838,7 +2838,7 @@ vect_analyze_data_ref_accesses (vec_info *vinfo)
break;
/* Check that the data-refs have the same step. */
- if (!operand_equal_p (DR_STEP (dra), DR_STEP (drb), 0))
+ if (data_ref_compare_tree (DR_STEP (dra), DR_STEP (drb)) != 0)
break;
/* Do not place the same access in the interleaving chain twice. */
@@ -3998,16 +3998,15 @@ vect_get_new_ssa_name (tree type, enum vect_var_kind var_kind, const char *name)
/* Duplicate ptr info and set alignment/misaligment on NAME from DR. */
static void
-vect_duplicate_ssa_name_ptr_info (tree name, data_reference *dr,
- stmt_vec_info stmt_info)
+vect_duplicate_ssa_name_ptr_info (tree name, data_reference *dr)
{
duplicate_ssa_name_ptr_info (name, DR_PTR_INFO (dr));
- unsigned int align = TYPE_ALIGN_UNIT (STMT_VINFO_VECTYPE (stmt_info));
int misalign = DR_MISALIGNMENT (dr);
if (misalign == DR_MISALIGNMENT_UNKNOWN)
mark_ptr_info_alignment_unknown (SSA_NAME_PTR_INFO (name));
else
- set_ptr_info_alignment (SSA_NAME_PTR_INFO (name), align, misalign);
+ set_ptr_info_alignment (SSA_NAME_PTR_INFO (name),
+ DR_TARGET_ALIGNMENT (dr), misalign);
}
/* Function vect_create_addr_base_for_vector_ref.
@@ -4112,7 +4111,7 @@ vect_create_addr_base_for_vector_ref (gimple *stmt,
&& TREE_CODE (addr_base) == SSA_NAME
&& !SSA_NAME_PTR_INFO (addr_base))
{
- vect_duplicate_ssa_name_ptr_info (addr_base, dr, stmt_info);
+ vect_duplicate_ssa_name_ptr_info (addr_base, dr);
if (offset || byte_offset)
mark_ptr_info_alignment_unknown (SSA_NAME_PTR_INFO (addr_base));
}
@@ -4371,8 +4370,8 @@ vect_create_data_ref_ptr (gimple *stmt, tree aggr_type, struct loop *at_loop,
/* Copy the points-to information if it exists. */
if (DR_PTR_INFO (dr))
{
- vect_duplicate_ssa_name_ptr_info (indx_before_incr, dr, stmt_info);
- vect_duplicate_ssa_name_ptr_info (indx_after_incr, dr, stmt_info);
+ vect_duplicate_ssa_name_ptr_info (indx_before_incr, dr);
+ vect_duplicate_ssa_name_ptr_info (indx_after_incr, dr);
}
if (ptr_incr)
*ptr_incr = incr;
@@ -4401,8 +4400,8 @@ vect_create_data_ref_ptr (gimple *stmt, tree aggr_type, struct loop *at_loop,
/* Copy the points-to information if it exists. */
if (DR_PTR_INFO (dr))
{
- vect_duplicate_ssa_name_ptr_info (indx_before_incr, dr, stmt_info);
- vect_duplicate_ssa_name_ptr_info (indx_after_incr, dr, stmt_info);
+ vect_duplicate_ssa_name_ptr_info (indx_before_incr, dr);
+ vect_duplicate_ssa_name_ptr_info (indx_after_incr, dr);
}
if (ptr_incr)
*ptr_incr = incr;
@@ -5006,10 +5005,10 @@ vect_setup_realignment (gimple *stmt, gimple_stmt_iterator *gsi,
new_temp = copy_ssa_name (ptr);
else
new_temp = make_ssa_name (TREE_TYPE (ptr));
+ unsigned int align = DR_TARGET_ALIGNMENT (dr);
new_stmt = gimple_build_assign
(new_temp, BIT_AND_EXPR, ptr,
- build_int_cst (TREE_TYPE (ptr),
- -(HOST_WIDE_INT)TYPE_ALIGN_UNIT (vectype)));
+ build_int_cst (TREE_TYPE (ptr), -(HOST_WIDE_INT) align));
new_bb = gsi_insert_on_edge_immediate (pe, new_stmt);
gcc_assert (!new_bb);
data_ref
diff --git a/gcc/tree-vect-loop-manip.c b/gcc/tree-vect-loop-manip.c
index f78e4b4..d4c233e 100644
--- a/gcc/tree-vect-loop-manip.c
+++ b/gcc/tree-vect-loop-manip.c
@@ -117,8 +117,6 @@ rename_variables_in_bb (basic_block bb, bool rename_from_outer_loop)
|| single_pred (e->src) != outer_loop->header)
continue;
}
- else
- continue;
}
}
for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
@@ -496,7 +494,8 @@ slpeel_tree_duplicate_loop_to_edge_cfg (struct loop *loop,
loop_preheader_edge (new_loop)->src);
}
- for (unsigned i = 0; i < scalar_loop->num_nodes + 1; i++)
+ /* Skip new preheader since it's deleted if copy loop is added at entry. */
+ for (unsigned i = (at_exit ? 0 : 1); i < scalar_loop->num_nodes + 1; i++)
rename_variables_in_bb (new_bbs[i], duplicate_outer_loop);
if (scalar_loop != loop)
@@ -564,13 +563,10 @@ slpeel_add_loop_guard (basic_block guard_bb, tree cond,
/* Add new edge to connect guard block to the merge/loop-exit block. */
new_e = make_edge (guard_bb, guard_to, EDGE_TRUE_VALUE);
- new_e->count = guard_bb->count;
new_e->probability = probability;
- new_e->count = enter_e->count.apply_probability (probability);
if (irreducible_p)
new_e->flags |= EDGE_IRREDUCIBLE_LOOP;
- enter_e->count -= new_e->count;
enter_e->probability = probability.invert ();
set_immediate_dominator (CDI_DOMINATORS, guard_to, dom_bb);
@@ -956,8 +952,7 @@ vect_gen_prolog_loop_niters (loop_vec_info loop_vinfo,
gimple *dr_stmt = DR_STMT (dr);
stmt_vec_info stmt_info = vinfo_for_stmt (dr_stmt);
tree vectype = STMT_VINFO_VECTYPE (stmt_info);
- int vectype_align = TYPE_ALIGN (vectype) / BITS_PER_UNIT;
- int nelements = TYPE_VECTOR_SUBPARTS (vectype);
+ unsigned int target_align = DR_TARGET_ALIGNMENT (dr);
if (LOOP_VINFO_PEELING_FOR_ALIGNMENT (loop_vinfo) > 0)
{
@@ -978,32 +973,36 @@ vect_gen_prolog_loop_niters (loop_vec_info loop_vinfo,
tree start_addr = vect_create_addr_base_for_vector_ref (dr_stmt,
&stmts, offset);
tree type = unsigned_type_for (TREE_TYPE (start_addr));
- tree vectype_align_minus_1 = build_int_cst (type, vectype_align - 1);
- HOST_WIDE_INT elem_size =
- int_cst_value (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
+ tree target_align_minus_1 = build_int_cst (type, target_align - 1);
+ HOST_WIDE_INT elem_size
+ = int_cst_value (TYPE_SIZE_UNIT (TREE_TYPE (vectype)));
tree elem_size_log = build_int_cst (type, exact_log2 (elem_size));
- tree nelements_minus_1 = build_int_cst (type, nelements - 1);
- tree nelements_tree = build_int_cst (type, nelements);
- tree byte_misalign;
- tree elem_misalign;
-
- /* Create: byte_misalign = addr & (vectype_align - 1) */
- byte_misalign =
- fold_build2 (BIT_AND_EXPR, type, fold_convert (type, start_addr),
- vectype_align_minus_1);
-
- /* Create: elem_misalign = byte_misalign / element_size */
- elem_misalign =
- fold_build2 (RSHIFT_EXPR, type, byte_misalign, elem_size_log);
-
- /* Create: (niters_type) (nelements - elem_misalign)&(nelements - 1) */
+ HOST_WIDE_INT align_in_elems = target_align / elem_size;
+ tree align_in_elems_minus_1 = build_int_cst (type, align_in_elems - 1);
+ tree align_in_elems_tree = build_int_cst (type, align_in_elems);
+ tree misalign_in_bytes;
+ tree misalign_in_elems;
+
+ /* Create: misalign_in_bytes = addr & (target_align - 1). */
+ misalign_in_bytes
+ = fold_build2 (BIT_AND_EXPR, type, fold_convert (type, start_addr),
+ target_align_minus_1);
+
+ /* Create: misalign_in_elems = misalign_in_bytes / element_size. */
+ misalign_in_elems
+ = fold_build2 (RSHIFT_EXPR, type, misalign_in_bytes, elem_size_log);
+
+ /* Create: (niters_type) ((align_in_elems - misalign_in_elems)
+ & (align_in_elems - 1)). */
if (negative)
- iters = fold_build2 (MINUS_EXPR, type, elem_misalign, nelements_tree);
+ iters = fold_build2 (MINUS_EXPR, type, misalign_in_elems,
+ align_in_elems_tree);
else
- iters = fold_build2 (MINUS_EXPR, type, nelements_tree, elem_misalign);
- iters = fold_build2 (BIT_AND_EXPR, type, iters, nelements_minus_1);
+ iters = fold_build2 (MINUS_EXPR, type, align_in_elems_tree,
+ misalign_in_elems);
+ iters = fold_build2 (BIT_AND_EXPR, type, iters, align_in_elems_minus_1);
iters = fold_convert (niters_type, iters);
- *bound = nelements - 1;
+ *bound = align_in_elems - 1;
}
if (dump_enabled_p ())
@@ -1230,9 +1229,11 @@ vect_gen_vector_loop_niters (loop_vec_info loop_vinfo, tree niters,
/* Peeling algorithm guarantees that vector loop bound is at least ONE,
we set range information to make niters analyzer's life easier. */
if (stmts != NULL)
- set_range_info (niters_vector, VR_RANGE, build_int_cst (type, 1),
- fold_build2 (RSHIFT_EXPR, type,
- TYPE_MAX_VALUE (type), log_vf));
+ set_range_info (niters_vector, VR_RANGE,
+ wi::to_wide (build_int_cst (type, 1)),
+ wi::to_wide (fold_build2 (RSHIFT_EXPR, type,
+ TYPE_MAX_VALUE (type),
+ log_vf)));
}
*niters_vector_ptr = niters_vector;
@@ -1785,7 +1786,8 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
least VF, so set range information for newly generated var. */
if (new_var_p)
set_range_info (niters, VR_RANGE,
- build_int_cst (type, vf), TYPE_MAX_VALUE (type));
+ wi::to_wide (build_int_cst (type, vf)),
+ wi::to_wide (TYPE_MAX_VALUE (type)));
/* Prolog iterates at most bound_prolog times, latch iterates at
most bound_prolog - 1 times. */
@@ -1843,7 +1845,6 @@ vect_do_peeling (loop_vec_info loop_vinfo, tree niters, tree nitersm1,
a merge point of control flow. */
guard_to->frequency = guard_bb->frequency;
guard_to->count = guard_bb->count;
- single_succ_edge (guard_to)->count = guard_to->count;
/* Scale probability of epilog loop back.
FIXME: We should avoid scaling down and back up. Profile may
get lost if we scale down to 0. */
diff --git a/gcc/tree-vect-loop.c b/gcc/tree-vect-loop.c
index bf49e26..3b1f95f 100644
--- a/gcc/tree-vect-loop.c
+++ b/gcc/tree-vect-loop.c
@@ -4487,7 +4487,7 @@ vect_create_epilog_for_reduction (vec<tree> vect_defs, gimple *stmt,
gcc_assert (gimple_assign_rhs_code (vec_stmt) == VEC_COND_EXPR);
int scalar_precision
- = GET_MODE_PRECISION (TYPE_MODE (TREE_TYPE (vectype)));
+ = GET_MODE_PRECISION (SCALAR_TYPE_MODE (TREE_TYPE (vectype)));
tree cr_index_scalar_type = make_unsigned_type (scalar_precision);
tree cr_index_vector_type = build_vector_type
(cr_index_scalar_type, TYPE_VECTOR_SUBPARTS (vectype));
@@ -5836,9 +5836,12 @@ vectorizable_reduction (gimple *stmt, gimple_stmt_iterator *gsi,
reduc_index = i;
continue;
}
- else
+ else if (tem)
{
- if (!vectype_in)
+ /* To properly compute ncopies we are interested in the widest
+ input type in case we're looking at a widening accumulation. */
+ if (!vectype_in
+ || TYPE_VECTOR_SUBPARTS (vectype_in) > TYPE_VECTOR_SUBPARTS (tem))
vectype_in = tem;
}
@@ -7224,7 +7227,7 @@ scale_profile_for_vect_loop (struct loop *loop, unsigned vf)
edge preheader = loop_preheader_edge (loop);
/* Reduce loop iterations by the vectorization factor. */
gcov_type new_est_niter = niter_for_unrolled_loop (loop, vf);
- profile_count freq_h = loop->header->count, freq_e = preheader->count;
+ profile_count freq_h = loop->header->count, freq_e = preheader->count ();
/* Use frequency only if counts are zero. */
if (!(freq_h > 0) && !(freq_e > 0))
@@ -7244,16 +7247,13 @@ scale_profile_for_vect_loop (struct loop *loop, unsigned vf)
scale_loop_frequencies (loop, p);
}
- basic_block exit_bb = single_pred (loop->latch);
edge exit_e = single_exit (loop);
- exit_e->count = loop_preheader_edge (loop)->count;
exit_e->probability = profile_probability::always ()
.apply_scale (1, new_est_niter + 1);
edge exit_l = single_pred_edge (loop->latch);
profile_probability prob = exit_l->probability;
exit_l->probability = exit_e->probability.invert ();
- exit_l->count = exit_bb->count - exit_e->count;
if (prob.initialized_p () && exit_l->probability.initialized_p ())
scale_bbs_frequencies (&loop->latch, 1, exit_l->probability / prob);
}
diff --git a/gcc/tree-vect-patterns.c b/gcc/tree-vect-patterns.c
index cdad261..e4051b6 100644
--- a/gcc/tree-vect-patterns.c
+++ b/gcc/tree-vect-patterns.c
@@ -3643,7 +3643,7 @@ vect_recog_bool_pattern (vec<gimple *> *stmts, tree *type_in,
rhs_code = gimple_assign_rhs_code (last_stmt);
if (CONVERT_EXPR_CODE_P (rhs_code))
{
- if (TREE_CODE (TREE_TYPE (lhs)) != INTEGER_TYPE
+ if (! INTEGRAL_TYPE_P (TREE_TYPE (lhs))
|| TYPE_PRECISION (TREE_TYPE (lhs)) == 1)
return NULL;
vectype = get_vectype_for_scalar_type (TREE_TYPE (lhs));
@@ -3714,7 +3714,7 @@ vect_recog_bool_pattern (vec<gimple *> *stmts, tree *type_in,
vectorized matches the vector type of the result in
size and number of elements. */
unsigned prec
- = wi::udiv_trunc (TYPE_SIZE (vectype),
+ = wi::udiv_trunc (wi::to_wide (TYPE_SIZE (vectype)),
TYPE_VECTOR_SUBPARTS (vectype)).to_uhwi ();
tree type
= build_nonstandard_integer_type (prec,
diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
index 5e40a37..bc81b3d 100644
--- a/gcc/tree-vect-slp.c
+++ b/gcc/tree-vect-slp.c
@@ -1629,14 +1629,20 @@ vect_supported_load_permutation_p (slp_instance slp_instn)
return true;
}
- /* For loop vectorization verify we can generate the permutation. */
+ /* For loop vectorization verify we can generate the permutation. Be
+ conservative about the vectorization factor, there are permutations
+ that will use three vector inputs only starting from a specific factor
+ and the vectorization factor is not yet final.
+ ??? The SLP instance unrolling factor might not be the maximum one. */
unsigned n_perms;
+ unsigned test_vf
+ = least_common_multiple (SLP_INSTANCE_UNROLLING_FACTOR (slp_instn),
+ LOOP_VINFO_VECT_FACTOR
+ (STMT_VINFO_LOOP_VINFO (vinfo_for_stmt (stmt))));
FOR_EACH_VEC_ELT (SLP_INSTANCE_LOADS (slp_instn), i, node)
if (node->load_permutation.exists ()
- && !vect_transform_slp_perm_load
- (node, vNULL, NULL,
- SLP_INSTANCE_UNROLLING_FACTOR (slp_instn), slp_instn, true,
- &n_perms))
+ && !vect_transform_slp_perm_load (node, vNULL, NULL, test_vf,
+ slp_instn, true, &n_perms))
return false;
return true;
@@ -3613,6 +3619,7 @@ vect_transform_slp_perm_load (slp_tree node, vec<tree> dr_chain,
dump_gimple_stmt (MSG_MISSED_OPTIMIZATION, TDF_SLIM,
stmt, 0);
}
+ gcc_assert (analyze_only);
return false;
}
@@ -3636,6 +3643,7 @@ vect_transform_slp_perm_load (slp_tree node, vec<tree> dr_chain,
dump_printf (MSG_MISSED_OPTIMIZATION, "%d ", mask[i]);
dump_printf (MSG_MISSED_OPTIMIZATION, "}\n");
}
+ gcc_assert (analyze_only);
return false;
}
diff --git a/gcc/tree-vect-stmts.c b/gcc/tree-vect-stmts.c
index 8f0d3d0..7e5fe4c 100644
--- a/gcc/tree-vect-stmts.c
+++ b/gcc/tree-vect-stmts.c
@@ -95,6 +95,12 @@ record_stmt_cost (stmt_vector_for_cost *body_cost_vec, int count,
enum vect_cost_for_stmt kind, stmt_vec_info stmt_info,
int misalign, enum vect_cost_model_location where)
{
+ if ((kind == vector_load || kind == unaligned_load)
+ && STMT_VINFO_GATHER_SCATTER_P (stmt_info))
+ kind = vector_gather_load;
+ if ((kind == vector_store || kind == unaligned_store)
+ && STMT_VINFO_GATHER_SCATTER_P (stmt_info))
+ kind = vector_scatter_store;
if (body_cost_vec)
{
tree vectype = stmt_info ? stmt_vectype (stmt_info) : NULL_TREE;
@@ -1737,6 +1743,7 @@ get_group_load_store_type (gimple *stmt, tree vectype, bool slp,
loop_vec_info loop_vinfo = STMT_VINFO_LOOP_VINFO (stmt_info);
struct loop *loop = loop_vinfo ? LOOP_VINFO_LOOP (loop_vinfo) : NULL;
gimple *first_stmt = GROUP_FIRST_ELEMENT (stmt_info);
+ data_reference *first_dr = STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt));
unsigned int group_size = GROUP_SIZE (vinfo_for_stmt (first_stmt));
bool single_element_p = (stmt == first_stmt
&& !GROUP_NEXT_ELEMENT (stmt_info));
@@ -1780,10 +1787,13 @@ get_group_load_store_type (gimple *stmt, tree vectype, bool slp,
" non-consecutive accesses\n");
return false;
}
- /* If the access is aligned an overrun is fine. */
+ /* An overrun is fine if the trailing elements are smaller
+ than the alignment boundary B. Every vector access will
+ be a multiple of B and so we are guaranteed to access a
+ non-gap element in the same B-sized block. */
if (overrun_p
- && aligned_access_p
- (STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt))))
+ && gap < (vect_known_alignment_in_bytes (first_dr)
+ / vect_get_scalar_dr_size (first_dr)))
overrun_p = false;
if (overrun_p && !can_overrun_p)
{
@@ -1804,14 +1814,15 @@ get_group_load_store_type (gimple *stmt, tree vectype, bool slp,
/* If there is a gap at the end of the group then these optimizations
would access excess elements in the last iteration. */
bool would_overrun_p = (gap != 0);
- /* If the access is aligned an overrun is fine, but only if the
- overrun is not inside an unused vector (if the gap is as large
- or larger than a vector). */
+ /* An overrun is fine if the trailing elements are smaller than the
+ alignment boundary B. Every vector access will be a multiple of B
+ and so we are guaranteed to access a non-gap element in the
+ same B-sized block. */
if (would_overrun_p
- && gap < nunits
- && aligned_access_p
- (STMT_VINFO_DATA_REF (vinfo_for_stmt (first_stmt))))
+ && gap < (vect_known_alignment_in_bytes (first_dr)
+ / vect_get_scalar_dr_size (first_dr)))
would_overrun_p = false;
+
if (!STMT_VINFO_STRIDED_P (stmt_info)
&& (can_overrun_p || !would_overrun_p)
&& compare_step_with_zero (stmt) > 0)
@@ -2351,7 +2362,7 @@ vectorizable_mask_load_store (gimple *stmt, gimple_stmt_iterator *gsi,
TYPE_SIZE_UNIT (vectype));
}
- align = TYPE_ALIGN_UNIT (vectype);
+ align = DR_TARGET_ALIGNMENT (dr);
if (aligned_access_p (dr))
misalign = 0;
else if (DR_MISALIGNMENT (dr) == -1)
@@ -2404,7 +2415,7 @@ vectorizable_mask_load_store (gimple *stmt, gimple_stmt_iterator *gsi,
TYPE_SIZE_UNIT (vectype));
}
- align = TYPE_ALIGN_UNIT (vectype);
+ align = DR_TARGET_ALIGNMENT (dr);
if (aligned_access_p (dr))
misalign = 0;
else if (DR_MISALIGNMENT (dr) == -1)
@@ -5553,25 +5564,25 @@ vectorizable_operation (gimple *stmt, gimple_stmt_iterator *gsi,
return true;
}
-/* A helper function to ensure data reference DR's base alignment
- for STMT_INFO. */
+/* A helper function to ensure data reference DR's base alignment. */
static void
-ensure_base_align (stmt_vec_info stmt_info, struct data_reference *dr)
+ensure_base_align (struct data_reference *dr)
{
if (!dr->aux)
return;
if (DR_VECT_AUX (dr)->base_misaligned)
{
- tree vectype = STMT_VINFO_VECTYPE (stmt_info);
tree base_decl = DR_VECT_AUX (dr)->base_decl;
+ unsigned int align_base_to = DR_TARGET_ALIGNMENT (dr) * BITS_PER_UNIT;
+
if (decl_in_symtab_p (base_decl))
- symtab_node::get (base_decl)->increase_alignment (TYPE_ALIGN (vectype));
+ symtab_node::get (base_decl)->increase_alignment (align_base_to);
else
{
- SET_DECL_ALIGN (base_decl, TYPE_ALIGN (vectype));
+ SET_DECL_ALIGN (base_decl, align_base_to);
DECL_USER_ALIGN (base_decl) = 1;
}
DR_VECT_AUX (dr)->base_misaligned = false;
@@ -5723,10 +5734,9 @@ vectorizable_store (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
op = gimple_assign_rhs1 (stmt);
- /* In the case this is a store from a STRING_CST make sure
+ /* In the case this is a store from a constant make sure
native_encode_expr can handle it. */
- if (TREE_CODE (op) == STRING_CST
- && ! can_native_encode_string_p (op))
+ if (CONSTANT_CLASS_P (op) && native_encode_expr (op, NULL, 64) == 0)
return false;
if (!vect_is_simple_use (op, vinfo, &def_stmt, &dt, &rhs_vectype))
@@ -5775,7 +5785,7 @@ vectorizable_store (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
/* Transform. */
- ensure_base_align (stmt_info, dr);
+ ensure_base_align (dr);
if (memory_access_type == VMAT_GATHER_SCATTER)
{
@@ -6417,7 +6427,7 @@ vectorizable_store (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
dataref_offset
? dataref_offset
: build_int_cst (ref_type, 0));
- align = TYPE_ALIGN_UNIT (vectype);
+ align = DR_TARGET_ALIGNMENT (first_dr);
if (aligned_access_p (first_dr))
misalign = 0;
else if (DR_MISALIGNMENT (first_dr) == -1)
@@ -6813,7 +6823,7 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
/* Transform. */
- ensure_base_align (stmt_info, dr);
+ ensure_base_align (dr);
if (memory_access_type == VMAT_GATHER_SCATTER)
{
@@ -7512,7 +7522,7 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
dataref_offset
? dataref_offset
: build_int_cst (ref_type, 0));
- align = TYPE_ALIGN_UNIT (vectype);
+ align = DR_TARGET_ALIGNMENT (dr);
if (alignment_support_scheme == dr_aligned)
{
gcc_assert (aligned_access_p (first_dr));
@@ -7555,11 +7565,12 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
ptr = copy_ssa_name (dataref_ptr);
else
ptr = make_ssa_name (TREE_TYPE (dataref_ptr));
+ unsigned int align = DR_TARGET_ALIGNMENT (first_dr);
new_stmt = gimple_build_assign
(ptr, BIT_AND_EXPR, dataref_ptr,
build_int_cst
(TREE_TYPE (dataref_ptr),
- -(HOST_WIDE_INT)TYPE_ALIGN_UNIT (vectype)));
+ -(HOST_WIDE_INT) align));
vect_finish_stmt_generation (stmt, new_stmt, gsi);
data_ref
= build2 (MEM_REF, vectype, ptr,
@@ -7581,8 +7592,7 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
new_stmt = gimple_build_assign
(NULL_TREE, BIT_AND_EXPR, ptr,
build_int_cst
- (TREE_TYPE (ptr),
- -(HOST_WIDE_INT)TYPE_ALIGN_UNIT (vectype)));
+ (TREE_TYPE (ptr), -(HOST_WIDE_INT) align));
ptr = copy_ssa_name (ptr, new_stmt);
gimple_assign_set_lhs (new_stmt, ptr);
vect_finish_stmt_generation (stmt, new_stmt, gsi);
@@ -7592,20 +7602,22 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
break;
}
case dr_explicit_realign_optimized:
- if (TREE_CODE (dataref_ptr) == SSA_NAME)
- new_temp = copy_ssa_name (dataref_ptr);
- else
- new_temp = make_ssa_name (TREE_TYPE (dataref_ptr));
- new_stmt = gimple_build_assign
- (new_temp, BIT_AND_EXPR, dataref_ptr,
- build_int_cst
- (TREE_TYPE (dataref_ptr),
- -(HOST_WIDE_INT)TYPE_ALIGN_UNIT (vectype)));
- vect_finish_stmt_generation (stmt, new_stmt, gsi);
- data_ref
- = build2 (MEM_REF, vectype, new_temp,
- build_int_cst (ref_type, 0));
- break;
+ {
+ if (TREE_CODE (dataref_ptr) == SSA_NAME)
+ new_temp = copy_ssa_name (dataref_ptr);
+ else
+ new_temp = make_ssa_name (TREE_TYPE (dataref_ptr));
+ unsigned int align = DR_TARGET_ALIGNMENT (first_dr);
+ new_stmt = gimple_build_assign
+ (new_temp, BIT_AND_EXPR, dataref_ptr,
+ build_int_cst (TREE_TYPE (dataref_ptr),
+ -(HOST_WIDE_INT) align));
+ vect_finish_stmt_generation (stmt, new_stmt, gsi);
+ data_ref
+ = build2 (MEM_REF, vectype, new_temp,
+ build_int_cst (ref_type, 0));
+ break;
+ }
default:
gcc_unreachable ();
}
@@ -7706,11 +7718,9 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
if (group_gap_adj != 0 && ! slp_perm
&& group_elt == group_size - group_gap_adj)
{
- bool ovf;
- tree bump
- = wide_int_to_tree (sizetype,
- wi::smul (TYPE_SIZE_UNIT (elem_type),
- group_gap_adj, &ovf));
+ wide_int bump_val = (wi::to_wide (TYPE_SIZE_UNIT (elem_type))
+ * group_gap_adj);
+ tree bump = wide_int_to_tree (sizetype, bump_val);
dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi,
stmt, bump);
group_elt = 0;
@@ -7720,11 +7730,9 @@ vectorizable_load (gimple *stmt, gimple_stmt_iterator *gsi, gimple **vec_stmt,
elements loaded for a permuted SLP load. */
if (group_gap_adj != 0 && slp_perm)
{
- bool ovf;
- tree bump
- = wide_int_to_tree (sizetype,
- wi::smul (TYPE_SIZE_UNIT (elem_type),
- group_gap_adj, &ovf));
+ wide_int bump_val = (wi::to_wide (TYPE_SIZE_UNIT (elem_type))
+ * group_gap_adj);
+ tree bump = wide_int_to_tree (sizetype, bump_val);
dataref_ptr = bump_vector_ptr (dataref_ptr, ptr_incr, gsi,
stmt, bump);
}
diff --git a/gcc/tree-vectorizer.h b/gcc/tree-vectorizer.h
index d6753ff..06224f9 100644
--- a/gcc/tree-vectorizer.h
+++ b/gcc/tree-vectorizer.h
@@ -790,7 +790,11 @@ STMT_VINFO_BB_VINFO (stmt_vec_info stmt_vinfo)
#define STMT_SLP_TYPE(S) (S)->slp_type
struct dataref_aux {
+ /* The misalignment in bytes of the reference, or -1 if not known. */
int misalignment;
+ /* The byte alignment that we'd ideally like the reference to have,
+ and the value that misalignment is measured against. */
+ int target_alignment;
/* If true the alignment of base_decl needs to be increased. */
bool base_misaligned;
tree base_decl;
@@ -1037,7 +1041,11 @@ dr_misalignment (struct data_reference *dr)
#define SET_DR_MISALIGNMENT(DR, VAL) set_dr_misalignment (DR, VAL)
#define DR_MISALIGNMENT_UNKNOWN (-1)
-/* Return TRUE if the data access is aligned, and FALSE otherwise. */
+/* Only defined once DR_MISALIGNMENT is defined. */
+#define DR_TARGET_ALIGNMENT(DR) DR_VECT_AUX (DR)->target_alignment
+
+/* Return true if data access DR is aligned to its target alignment
+ (which may be less than a full vector). */
static inline bool
aligned_access_p (struct data_reference *data_ref_info)
@@ -1054,6 +1062,19 @@ known_alignment_for_access_p (struct data_reference *data_ref_info)
return (DR_MISALIGNMENT (data_ref_info) != DR_MISALIGNMENT_UNKNOWN);
}
+/* Return the minimum alignment in bytes that the vectorized version
+ of DR is guaranteed to have. */
+
+static inline unsigned int
+vect_known_alignment_in_bytes (struct data_reference *dr)
+{
+ if (DR_MISALIGNMENT (dr) == DR_MISALIGNMENT_UNKNOWN)
+ return TYPE_ALIGN_UNIT (TREE_TYPE (DR_REF (dr)));
+ if (DR_MISALIGNMENT (dr) == 0)
+ return DR_TARGET_ALIGNMENT (dr);
+ return DR_MISALIGNMENT (dr) & -DR_MISALIGNMENT (dr);
+}
+
/* Return the behavior of DR with respect to the vectorization context
(which for outer loop vectorization might not be the behavior recorded
in DR itself). */
@@ -1095,6 +1116,19 @@ vect_get_num_copies (loop_vec_info loop_vinfo, tree vectype)
/ TYPE_VECTOR_SUBPARTS (vectype));
}
+/* Return the size of the value accessed by unvectorized data reference DR.
+ This is only valid once STMT_VINFO_VECTYPE has been calculated for the
+ associated gimple statement, since that guarantees that DR accesses
+ either a scalar or a scalar equivalent. ("Scalar equivalent" here
+ includes things like V1SI, which can be vectorized in the same way
+ as a plain SI.) */
+
+inline unsigned int
+vect_get_scalar_dr_size (struct data_reference *dr)
+{
+ return tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (DR_REF (dr))));
+}
+
/* Source location */
extern source_location vect_location;
diff --git a/gcc/tree-vrp.c b/gcc/tree-vrp.c
index 221a07b..2c86b8e 100644
--- a/gcc/tree-vrp.c
+++ b/gcc/tree-vrp.c
@@ -1072,7 +1072,8 @@ compare_values_warnv (tree val1, tree val2, bool *strict_overflow_p)
if (!inv2)
inv2 = build_int_cst (TREE_TYPE (val2), 0);
- return wi::cmp (inv1, inv2, TYPE_SIGN (TREE_TYPE (val1)));
+ return wi::cmp (wi::to_wide (inv1), wi::to_wide (inv2),
+ TYPE_SIGN (TREE_TYPE (val1)));
}
const bool cst1 = is_gimple_min_invariant (val1);
@@ -1099,10 +1100,11 @@ compare_values_warnv (tree val1, tree val2, bool *strict_overflow_p)
/* Compute the difference between the constants. If it overflows or
underflows, this means that we can trivially compare the NAME with
it and, consequently, the two values with each other. */
- wide_int diff = wi::sub (cst, inv);
- if (wi::cmp (0, inv, sgn) != wi::cmp (diff, cst, sgn))
+ wide_int diff = wi::to_wide (cst) - wi::to_wide (inv);
+ if (wi::cmp (0, wi::to_wide (inv), sgn)
+ != wi::cmp (diff, wi::to_wide (cst), sgn))
{
- const int res = wi::cmp (cst, inv, sgn);
+ const int res = wi::cmp (wi::to_wide (cst), wi::to_wide (inv), sgn);
return cst1 ? res : -res;
}
@@ -1635,14 +1637,15 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2,
/* It's unclear from the C standard whether shifts can overflow.
The following code ignores overflow; perhaps a C standard
interpretation ruling is needed. */
- res = wi::rshift (val1, wval2, sign);
+ res = wi::rshift (wi::to_wide (val1), wval2, sign);
else
- res = wi::lshift (val1, wval2);
+ res = wi::lshift (wi::to_wide (val1), wval2);
break;
}
case MULT_EXPR:
- res = wi::mul (val1, val2, sign, &overflow);
+ res = wi::mul (wi::to_wide (val1),
+ wi::to_wide (val2), sign, &overflow);
break;
case TRUNC_DIV_EXPR:
@@ -1653,7 +1656,8 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2,
return res;
}
else
- res = wi::div_trunc (val1, val2, sign, &overflow);
+ res = wi::div_trunc (wi::to_wide (val1),
+ wi::to_wide (val2), sign, &overflow);
break;
case FLOOR_DIV_EXPR:
@@ -1662,7 +1666,8 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2,
*overflow_p = true;
return res;
}
- res = wi::div_floor (val1, val2, sign, &overflow);
+ res = wi::div_floor (wi::to_wide (val1),
+ wi::to_wide (val2), sign, &overflow);
break;
case CEIL_DIV_EXPR:
@@ -1671,7 +1676,8 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2,
*overflow_p = true;
return res;
}
- res = wi::div_ceil (val1, val2, sign, &overflow);
+ res = wi::div_ceil (wi::to_wide (val1),
+ wi::to_wide (val2), sign, &overflow);
break;
case ROUND_DIV_EXPR:
@@ -1680,7 +1686,8 @@ vrp_int_const_binop (enum tree_code code, tree val1, tree val2,
*overflow_p = 0;
return res;
}
- res = wi::div_round (val1, val2, sign, &overflow);
+ res = wi::div_round (wi::to_wide (val1),
+ wi::to_wide (val2), sign, &overflow);
break;
default:
@@ -1755,21 +1762,21 @@ zero_nonzero_bits_from_vr (const tree expr_type,
if (range_int_cst_singleton_p (vr))
{
- *may_be_nonzero = vr->min;
+ *may_be_nonzero = wi::to_wide (vr->min);
*must_be_nonzero = *may_be_nonzero;
}
else if (tree_int_cst_sgn (vr->min) >= 0
|| tree_int_cst_sgn (vr->max) < 0)
{
- wide_int xor_mask = wi::bit_xor (vr->min, vr->max);
- *may_be_nonzero = wi::bit_or (vr->min, vr->max);
- *must_be_nonzero = wi::bit_and (vr->min, vr->max);
+ wide_int xor_mask = wi::to_wide (vr->min) ^ wi::to_wide (vr->max);
+ *may_be_nonzero = wi::to_wide (vr->min) | wi::to_wide (vr->max);
+ *must_be_nonzero = wi::to_wide (vr->min) & wi::to_wide (vr->max);
if (xor_mask != 0)
{
wide_int mask = wi::mask (wi::floor_log2 (xor_mask), false,
may_be_nonzero->get_precision ());
*may_be_nonzero = *may_be_nonzero | mask;
- *must_be_nonzero = must_be_nonzero->and_not (mask);
+ *must_be_nonzero = wi::bit_and_not (*must_be_nonzero, mask);
}
}
@@ -1801,12 +1808,12 @@ ranges_from_anti_range (value_range *ar,
{
vr0->type = VR_RANGE;
vr0->min = vrp_val_min (type);
- vr0->max = wide_int_to_tree (type, wi::sub (ar->min, 1));
+ vr0->max = wide_int_to_tree (type, wi::to_wide (ar->min) - 1);
}
if (!vrp_val_is_max (ar->max))
{
vr1->type = VR_RANGE;
- vr1->min = wide_int_to_tree (type, wi::add (ar->max, 1));
+ vr1->min = wide_int_to_tree (type, wi::to_wide (ar->max) + 1);
vr1->max = vrp_val_max (type);
}
if (vr0->type == VR_UNDEFINED)
@@ -1851,8 +1858,7 @@ extract_range_from_multiplicative_op_1 (value_range *vr,
|| code == ROUND_DIV_EXPR
|| code == RSHIFT_EXPR
|| code == LSHIFT_EXPR);
- gcc_assert ((vr0->type == VR_RANGE
- || (code == MULT_EXPR && vr0->type == VR_ANTI_RANGE))
+ gcc_assert (vr0->type == VR_RANGE
&& vr0->type == vr1->type);
rtype = vr0->type;
@@ -2172,8 +2178,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
}
else
{
- type_min = vrp_val_min (expr_type);
- type_max = vrp_val_max (expr_type);
+ type_min = wi::to_wide (vrp_val_min (expr_type));
+ type_max = wi::to_wide (vrp_val_max (expr_type));
}
/* Combine the lower bounds, if any. */
@@ -2181,39 +2187,42 @@ extract_range_from_binary_expr_1 (value_range *vr,
{
if (minus_p)
{
- wmin = wi::sub (min_op0, min_op1);
+ wmin = wi::to_wide (min_op0) - wi::to_wide (min_op1);
/* Check for overflow. */
- if (wi::cmp (0, min_op1, sgn)
- != wi::cmp (wmin, min_op0, sgn))
- min_ovf = wi::cmp (min_op0, min_op1, sgn);
+ if (wi::cmp (0, wi::to_wide (min_op1), sgn)
+ != wi::cmp (wmin, wi::to_wide (min_op0), sgn))
+ min_ovf = wi::cmp (wi::to_wide (min_op0),
+ wi::to_wide (min_op1), sgn);
}
else
{
- wmin = wi::add (min_op0, min_op1);
+ wmin = wi::to_wide (min_op0) + wi::to_wide (min_op1);
/* Check for overflow. */
- if (wi::cmp (min_op1, 0, sgn)
- != wi::cmp (wmin, min_op0, sgn))
- min_ovf = wi::cmp (min_op0, wmin, sgn);
+ if (wi::cmp (wi::to_wide (min_op1), 0, sgn)
+ != wi::cmp (wmin, wi::to_wide (min_op0), sgn))
+ min_ovf = wi::cmp (wi::to_wide (min_op0), wmin, sgn);
}
}
else if (min_op0)
- wmin = min_op0;
+ wmin = wi::to_wide (min_op0);
else if (min_op1)
{
if (minus_p)
{
- wmin = wi::neg (min_op1);
+ wmin = -wi::to_wide (min_op1);
/* Check for overflow. */
- if (sgn == SIGNED && wi::neg_p (min_op1) && wi::neg_p (wmin))
+ if (sgn == SIGNED
+ && wi::neg_p (wi::to_wide (min_op1))
+ && wi::neg_p (wmin))
min_ovf = 1;
- else if (sgn == UNSIGNED && wi::ne_p (min_op1, 0))
+ else if (sgn == UNSIGNED && wi::to_wide (min_op1) != 0)
min_ovf = -1;
}
else
- wmin = min_op1;
+ wmin = wi::to_wide (min_op1);
}
else
wmin = wi::shwi (0, prec);
@@ -2223,38 +2232,41 @@ extract_range_from_binary_expr_1 (value_range *vr,
{
if (minus_p)
{
- wmax = wi::sub (max_op0, max_op1);
+ wmax = wi::to_wide (max_op0) - wi::to_wide (max_op1);
/* Check for overflow. */
- if (wi::cmp (0, max_op1, sgn)
- != wi::cmp (wmax, max_op0, sgn))
- max_ovf = wi::cmp (max_op0, max_op1, sgn);
+ if (wi::cmp (0, wi::to_wide (max_op1), sgn)
+ != wi::cmp (wmax, wi::to_wide (max_op0), sgn))
+ max_ovf = wi::cmp (wi::to_wide (max_op0),
+ wi::to_wide (max_op1), sgn);
}
else
{
- wmax = wi::add (max_op0, max_op1);
+ wmax = wi::to_wide (max_op0) + wi::to_wide (max_op1);
- if (wi::cmp (max_op1, 0, sgn)
- != wi::cmp (wmax, max_op0, sgn))
- max_ovf = wi::cmp (max_op0, wmax, sgn);
+ if (wi::cmp (wi::to_wide (max_op1), 0, sgn)
+ != wi::cmp (wmax, wi::to_wide (max_op0), sgn))
+ max_ovf = wi::cmp (wi::to_wide (max_op0), wmax, sgn);
}
}
else if (max_op0)
- wmax = max_op0;
+ wmax = wi::to_wide (max_op0);
else if (max_op1)
{
if (minus_p)
{
- wmax = wi::neg (max_op1);
+ wmax = -wi::to_wide (max_op1);
/* Check for overflow. */
- if (sgn == SIGNED && wi::neg_p (max_op1) && wi::neg_p (wmax))
+ if (sgn == SIGNED
+ && wi::neg_p (wi::to_wide (max_op1))
+ && wi::neg_p (wmax))
max_ovf = 1;
- else if (sgn == UNSIGNED && wi::ne_p (max_op1, 0))
+ else if (sgn == UNSIGNED && wi::to_wide (max_op1) != 0)
max_ovf = -1;
}
else
- wmax = max_op1;
+ wmax = wi::to_wide (max_op1);
}
else
wmax = wi::shwi (0, prec);
@@ -2462,9 +2474,14 @@ extract_range_from_binary_expr_1 (value_range *vr,
signop sign = TYPE_SIGN (expr_type);
unsigned int prec = TYPE_PRECISION (expr_type);
- if (range_int_cst_p (&vr0)
- && range_int_cst_p (&vr1)
- && TYPE_OVERFLOW_WRAPS (expr_type))
+ if (!range_int_cst_p (&vr0)
+ || !range_int_cst_p (&vr1))
+ {
+ set_value_range_to_varying (vr);
+ return;
+ }
+
+ if (TYPE_OVERFLOW_WRAPS (expr_type))
{
typedef FIXED_WIDE_INT (WIDE_INT_MAX_PRECISION * 2) vrp_int;
typedef generic_wide_int
@@ -2624,14 +2641,14 @@ extract_range_from_binary_expr_1 (value_range *vr,
{
low_bound = bound;
high_bound = complement;
- if (wi::ltu_p (vr0.max, low_bound))
+ if (wi::ltu_p (wi::to_wide (vr0.max), low_bound))
{
/* [5, 6] << [1, 2] == [10, 24]. */
/* We're shifting out only zeroes, the value increases
monotonically. */
in_bounds = true;
}
- else if (wi::ltu_p (high_bound, vr0.min))
+ else if (wi::ltu_p (high_bound, wi::to_wide (vr0.min)))
{
/* [0xffffff00, 0xffffffff] << [1, 2]
== [0xfffffc00, 0xfffffffe]. */
@@ -2645,8 +2662,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
/* [-1, 1] << [1, 2] == [-4, 4]. */
low_bound = complement;
high_bound = bound;
- if (wi::lts_p (vr0.max, high_bound)
- && wi::lts_p (low_bound, vr0.min))
+ if (wi::lts_p (wi::to_wide (vr0.max), high_bound)
+ && wi::lts_p (low_bound, wi::to_wide (vr0.min)))
{
/* For non-negative numbers, we're shifting out only
zeroes, the value increases monotonically.
@@ -2789,14 +2806,12 @@ extract_range_from_binary_expr_1 (value_range *vr,
signop sgn = TYPE_SIGN (expr_type);
unsigned int prec = TYPE_PRECISION (expr_type);
wide_int wmin, wmax, tmp;
- wide_int zero = wi::zero (prec);
- wide_int one = wi::one (prec);
if (vr1.type == VR_RANGE && !symbolic_range_p (&vr1))
{
- wmax = wi::sub (vr1.max, one);
+ wmax = wi::to_wide (vr1.max) - 1;
if (sgn == SIGNED)
{
- tmp = wi::sub (wi::minus_one (prec), vr1.min);
+ tmp = -1 - wi::to_wide (vr1.min);
wmax = wi::smax (wmax, tmp);
}
}
@@ -2805,28 +2820,28 @@ extract_range_from_binary_expr_1 (value_range *vr,
wmax = wi::max_value (prec, sgn);
/* X % INT_MIN may be INT_MAX. */
if (sgn == UNSIGNED)
- wmax = wmax - one;
+ wmax = wmax - 1;
}
if (sgn == UNSIGNED)
- wmin = zero;
+ wmin = wi::zero (prec);
else
{
wmin = -wmax;
if (vr0.type == VR_RANGE && TREE_CODE (vr0.min) == INTEGER_CST)
{
- tmp = vr0.min;
- if (wi::gts_p (tmp, zero))
- tmp = zero;
+ tmp = wi::to_wide (vr0.min);
+ if (wi::gts_p (tmp, 0))
+ tmp = wi::zero (prec);
wmin = wi::smax (wmin, tmp);
}
}
if (vr0.type == VR_RANGE && TREE_CODE (vr0.max) == INTEGER_CST)
{
- tmp = vr0.max;
+ tmp = wi::to_wide (vr0.max);
if (sgn == SIGNED && wi::neg_p (tmp))
- tmp = zero;
+ tmp = wi::zero (prec);
wmax = wi::min (wmax, tmp, sgn);
}
@@ -2871,7 +2886,7 @@ extract_range_from_binary_expr_1 (value_range *vr,
range. */
if (vr0p && range_int_cst_p (vr0p))
{
- wide_int w = vr1p->min;
+ wide_int w = wi::to_wide (vr1p->min);
int m = 0, n = 0;
if (code == BIT_IOR_EXPR)
w = ~w;
@@ -2887,7 +2902,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
m = wi::ctz (w) - n;
}
wide_int mask = wi::mask (m + n, true, w.get_precision ());
- if (wi::eq_p (mask & vr0p->min, mask & vr0p->max))
+ if ((mask & wi::to_wide (vr0p->min))
+ == (mask & wi::to_wide (vr0p->max)))
{
min = int_const_binop (code, vr0p->min, vr1p->min);
max = int_const_binop (code, vr0p->max, vr1p->min);
@@ -2910,16 +2926,20 @@ extract_range_from_binary_expr_1 (value_range *vr,
&& tree_int_cst_sgn (vr0.max) < 0
&& tree_int_cst_sgn (vr1.max) < 0)
{
- wmax = wi::min (wmax, vr0.max, TYPE_SIGN (expr_type));
- wmax = wi::min (wmax, vr1.max, TYPE_SIGN (expr_type));
+ wmax = wi::min (wmax, wi::to_wide (vr0.max),
+ TYPE_SIGN (expr_type));
+ wmax = wi::min (wmax, wi::to_wide (vr1.max),
+ TYPE_SIGN (expr_type));
}
/* If either input range contains only non-negative values
we can truncate the result range maximum to the respective
maximum of the input range. */
if (int_cst_range0 && tree_int_cst_sgn (vr0.min) >= 0)
- wmax = wi::min (wmax, vr0.max, TYPE_SIGN (expr_type));
+ wmax = wi::min (wmax, wi::to_wide (vr0.max),
+ TYPE_SIGN (expr_type));
if (int_cst_range1 && tree_int_cst_sgn (vr1.min) >= 0)
- wmax = wi::min (wmax, vr1.max, TYPE_SIGN (expr_type));
+ wmax = wi::min (wmax, wi::to_wide (vr1.max),
+ TYPE_SIGN (expr_type));
max = wide_int_to_tree (expr_type, wmax);
cmp = compare_values (min, max);
/* PR68217: In case of signed & sign-bit-CST should
@@ -2930,10 +2950,12 @@ extract_range_from_binary_expr_1 (value_range *vr,
= wi::set_bit_in_zero (TYPE_PRECISION (expr_type) - 1,
TYPE_PRECISION (expr_type));
if (!TYPE_UNSIGNED (expr_type)
- && ((value_range_constant_singleton (&vr0)
- && !wi::cmps (vr0.min, sign_bit))
- || (value_range_constant_singleton (&vr1)
- && !wi::cmps (vr1.min, sign_bit))))
+ && ((int_cst_range0
+ && value_range_constant_singleton (&vr0)
+ && !wi::cmps (wi::to_wide (vr0.min), sign_bit))
+ || (int_cst_range1
+ && value_range_constant_singleton (&vr1)
+ && !wi::cmps (wi::to_wide (vr1.min), sign_bit))))
{
min = TYPE_MIN_VALUE (expr_type);
max = build_int_cst (expr_type, 0);
@@ -2952,16 +2974,20 @@ extract_range_from_binary_expr_1 (value_range *vr,
&& tree_int_cst_sgn (vr0.min) >= 0
&& tree_int_cst_sgn (vr1.min) >= 0)
{
- wmin = wi::max (wmin, vr0.min, TYPE_SIGN (expr_type));
- wmin = wi::max (wmin, vr1.min, TYPE_SIGN (expr_type));
+ wmin = wi::max (wmin, wi::to_wide (vr0.min),
+ TYPE_SIGN (expr_type));
+ wmin = wi::max (wmin, wi::to_wide (vr1.min),
+ TYPE_SIGN (expr_type));
}
/* If either input range contains only negative values
we can truncate the minimum of the result range to the
respective minimum range. */
if (int_cst_range0 && tree_int_cst_sgn (vr0.max) < 0)
- wmin = wi::max (wmin, vr0.min, TYPE_SIGN (expr_type));
+ wmin = wi::max (wmin, wi::to_wide (vr0.min),
+ TYPE_SIGN (expr_type));
if (int_cst_range1 && tree_int_cst_sgn (vr1.max) < 0)
- wmin = wi::max (wmin, vr1.min, TYPE_SIGN (expr_type));
+ wmin = wi::max (wmin, wi::to_wide (vr1.min),
+ TYPE_SIGN (expr_type));
min = wide_int_to_tree (expr_type, wmin);
}
else if (code == BIT_XOR_EXPR)
@@ -2969,8 +2995,8 @@ extract_range_from_binary_expr_1 (value_range *vr,
wide_int result_zero_bits = ((must_be_nonzero0 & must_be_nonzero1)
| ~(may_be_nonzero0 | may_be_nonzero1));
wide_int result_one_bits
- = (must_be_nonzero0.and_not (may_be_nonzero1)
- | must_be_nonzero1.and_not (may_be_nonzero0));
+ = (wi::bit_and_not (must_be_nonzero0, may_be_nonzero1)
+ | wi::bit_and_not (must_be_nonzero1, may_be_nonzero0));
max = wide_int_to_tree (expr_type, ~result_zero_bits);
min = wide_int_to_tree (expr_type, result_one_bits);
/* If the range has all positive or all negative values the
@@ -4038,7 +4064,7 @@ adjust_range_with_scev (value_range *vr, struct loop *loop,
if (!overflow
&& wi::fits_to_tree_p (wtmp, TREE_TYPE (init))
&& (sgn == UNSIGNED
- || wi::gts_p (wtmp, 0) == wi::gts_p (step, 0)))
+ || wi::gts_p (wtmp, 0) == wi::gts_p (wi::to_wide (step), 0)))
{
tem = wide_int_to_tree (TREE_TYPE (init), wtmp);
extract_range_from_binary_expr (&maxvr, PLUS_EXPR,
@@ -4518,7 +4544,12 @@ build_assert_expr_for (tree cond, tree v)
operand of the ASSERT_EXPR. Create it so the new name and the old one
are registered in the replacement table so that we can fix the SSA web
after adding all the ASSERT_EXPRs. */
- create_new_def_for (v, assertion, NULL);
+ tree new_def = create_new_def_for (v, assertion, NULL);
+ /* Make sure we preserve abnormalness throughout an ASSERT_EXPR chain
+ given we have to be able to fully propagate those out to re-create
+ valid SSA when removing the asserts. */
+ if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (v))
+ SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_def) = 1;
return assertion;
}
@@ -4866,7 +4897,7 @@ masked_increment (const wide_int &val_in, const wide_int &mask,
if ((res & bit) == 0)
continue;
res = bit - 1;
- res = (val + bit).and_not (res);
+ res = wi::bit_and_not (val + bit, res);
res &= mask;
if (wi::gtu_p (res, val))
return res ^ sgnbit;
@@ -4955,9 +4986,9 @@ overflow_comparison_p_1 (enum tree_code code, tree op0, tree op1,
wide_int max = wi::max_value (TYPE_PRECISION (type), UNSIGNED);
tree inc = gimple_assign_rhs2 (op1_def);
if (reversed)
- *new_cst = wide_int_to_tree (type, max + inc);
+ *new_cst = wide_int_to_tree (type, max + wi::to_wide (inc));
else
- *new_cst = wide_int_to_tree (type, max - inc);
+ *new_cst = wide_int_to_tree (type, max - wi::to_wide (inc));
return true;
}
}
@@ -5279,15 +5310,15 @@ register_edge_assert_for_2 (tree name, edge e,
wide_int minval
= wi::min_value (prec, TYPE_SIGN (TREE_TYPE (val)));
new_val = val2;
- if (minval == new_val)
+ if (minval == wi::to_wide (new_val))
new_val = NULL_TREE;
}
else
{
wide_int maxval
= wi::max_value (prec, TYPE_SIGN (TREE_TYPE (val)));
- mask |= val2;
- if (mask == maxval)
+ mask |= wi::to_wide (val2);
+ if (wi::eq_p (mask, maxval))
new_val = NULL_TREE;
else
new_val = wide_int_to_tree (TREE_TYPE (val2), mask);
@@ -5362,8 +5393,8 @@ register_edge_assert_for_2 (tree name, edge e,
bool valid_p = false, valn, cst2n;
enum tree_code ccode = comp_code;
- valv = wide_int::from (val, nprec, UNSIGNED);
- cst2v = wide_int::from (cst2, nprec, UNSIGNED);
+ valv = wide_int::from (wi::to_wide (val), nprec, UNSIGNED);
+ cst2v = wide_int::from (wi::to_wide (cst2), nprec, UNSIGNED);
valn = wi::neg_p (valv, TYPE_SIGN (TREE_TYPE (val)));
cst2n = wi::neg_p (cst2v, TYPE_SIGN (TREE_TYPE (val)));
/* If CST2 doesn't have most significant bit set,
@@ -5660,9 +5691,10 @@ is_masked_range_test (tree name, tree valt, enum tree_code cond_code,
if (TREE_CODE (t) != SSA_NAME || TREE_CODE (maskt) != INTEGER_CST)
return false;
- wide_int mask = maskt;
+ wi::tree_to_wide_ref mask = wi::to_wide (maskt);
wide_int inv_mask = ~mask;
- wide_int val = valt; // Assume VALT is INTEGER_CST
+ /* Assume VALT is INTEGER_CST. */
+ wi::tree_to_wide_ref val = wi::to_wide (valt);
if ((inv_mask & (inv_mask + 1)) != 0
|| (val & mask) != val)
@@ -6011,7 +6043,8 @@ find_switch_asserts (basic_block bb, gswitch *last)
next_min = CASE_LOW (next_cl);
next_max = CASE_HIGH (next_cl);
- wide_int difference = wi::sub (next_min, max ? max : min);
+ wide_int difference = (wi::to_wide (next_min)
+ - wi::to_wide (max ? max : min));
if (wi::eq_p (difference, 1))
max = next_max ? next_max : next_min;
else
@@ -6942,7 +6975,8 @@ maybe_set_nonzero_bits (basic_block bb, tree var)
return;
}
cst = gimple_assign_rhs2 (stmt);
- set_nonzero_bits (var, wi::bit_and_not (get_nonzero_bits (var), cst));
+ set_nonzero_bits (var, wi::bit_and_not (get_nonzero_bits (var),
+ wi::to_wide (cst)));
}
/* Convert range assertion expressions into the implied copies and
@@ -7039,14 +7073,6 @@ remove_range_assertions (void)
FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
SET_USE (use_p, var);
}
- /* But do not propagate constants as that is invalid. */
- else if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (lhs))
- {
- gassign *ass = gimple_build_assign (lhs, var);
- gsi_replace (&si, ass, true);
- gsi_next (&si);
- continue;
- }
else
replace_uses_by (lhs, var);
@@ -7544,7 +7570,7 @@ vrp_evaluate_conditional_warnv_with_ops (enum tree_code code, tree op0,
B = A + 1; if (A < B) -> B = A + 1; if (B != 0)
B = A - 1; if (B > A) -> B = A - 1; if (A == 0)
B = A - 1; if (B < A) -> B = A - 1; if (A != 0) */
- else if (wi::eq_p (x, max - 1))
+ else if (wi::to_wide (x) == max - 1)
{
op0 = op1;
op1 = wide_int_to_tree (TREE_TYPE (op0), 0);
@@ -8655,7 +8681,7 @@ intersect_ranges (enum value_range_type *vr0type,
== TYPE_PRECISION (ptr_type_node))
&& TREE_CODE (vr1max) == INTEGER_CST
&& TREE_CODE (vr1min) == INTEGER_CST
- && (wi::clz (wi::sub (vr1max, vr1min))
+ && (wi::clz (wi::to_wide (vr1max) - wi::to_wide (vr1min))
< TYPE_PRECISION (TREE_TYPE (*vr0min)) / 2))
;
/* Else choose the range. */
@@ -9535,13 +9561,13 @@ simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
switch (gimple_assign_rhs_code (stmt))
{
case BIT_AND_EXPR:
- mask = may_be_nonzero0.and_not (must_be_nonzero1);
+ mask = wi::bit_and_not (may_be_nonzero0, must_be_nonzero1);
if (mask == 0)
{
op = op0;
break;
}
- mask = may_be_nonzero1.and_not (must_be_nonzero0);
+ mask = wi::bit_and_not (may_be_nonzero1, must_be_nonzero0);
if (mask == 0)
{
op = op1;
@@ -9549,13 +9575,13 @@ simplify_bit_ops_using_ranges (gimple_stmt_iterator *gsi, gimple *stmt)
}
break;
case BIT_IOR_EXPR:
- mask = may_be_nonzero0.and_not (must_be_nonzero1);
+ mask = wi::bit_and_not (may_be_nonzero0, must_be_nonzero1);
if (mask == 0)
{
op = op1;
break;
}
- mask = may_be_nonzero1.and_not (must_be_nonzero0);
+ mask = wi::bit_and_not (may_be_nonzero1, must_be_nonzero0);
if (mask == 0)
{
op = op0;
@@ -9676,7 +9702,8 @@ range_fits_type_p (value_range *vr, unsigned dest_precision, signop dest_sgn)
a signed wide_int, while a negative value cannot be represented
by an unsigned wide_int. */
if (src_sgn != dest_sgn
- && (wi::lts_p (vr->min, 0) || wi::lts_p (vr->max, 0)))
+ && (wi::lts_p (wi::to_wide (vr->min), 0)
+ || wi::lts_p (wi::to_wide (vr->max), 0)))
return false;
/* Then we can perform the conversion on both ends and compare
@@ -10272,7 +10299,7 @@ two_valued_val_range_p (tree var, tree *a, tree *b)
return false;
if (vr->type == VR_RANGE
- && wi::sub (vr->max, vr->min) == 1)
+ && wi::to_wide (vr->max) - wi::to_wide (vr->min) == 1)
{
*a = vr->min;
*b = vr->max;
@@ -10281,8 +10308,10 @@ two_valued_val_range_p (tree var, tree *a, tree *b)
/* ~[TYPE_MIN + 1, TYPE_MAX - 1] */
if (vr->type == VR_ANTI_RANGE
- && wi::sub (vr->min, vrp_val_min (TREE_TYPE (var))) == 1
- && wi::sub (vrp_val_max (TREE_TYPE (var)), vr->max) == 1)
+ && (wi::to_wide (vr->min)
+ - wi::to_wide (vrp_val_min (TREE_TYPE (var)))) == 1
+ && (wi::to_wide (vrp_val_max (TREE_TYPE (var)))
+ - wi::to_wide (vr->max)) == 1)
{
*a = vrp_val_min (TREE_TYPE (var));
*b = vrp_val_max (TREE_TYPE (var));
@@ -10847,8 +10876,9 @@ vrp_finalize (bool warn_array_bounds_p)
vr_value[i]->max) == 1)))
set_ptr_nonnull (name);
else if (!POINTER_TYPE_P (TREE_TYPE (name)))
- set_range_info (name, vr_value[i]->type, vr_value[i]->min,
- vr_value[i]->max);
+ set_range_info (name, vr_value[i]->type,
+ wi::to_wide (vr_value[i]->min),
+ wi::to_wide (vr_value[i]->max));
}
substitute_and_fold (op_with_constant_singleton_value_range, vrp_fold_stmt);
@@ -11044,8 +11074,9 @@ evrp_dom_walker::before_dom_children (basic_block bb)
|| vr_result.type == VR_ANTI_RANGE)
&& (TREE_CODE (vr_result.min) == INTEGER_CST)
&& (TREE_CODE (vr_result.max) == INTEGER_CST))
- set_range_info (lhs,
- vr_result.type, vr_result.min, vr_result.max);
+ set_range_info (lhs, vr_result.type,
+ wi::to_wide (vr_result.min),
+ wi::to_wide (vr_result.max));
}
else if (POINTER_TYPE_P (TREE_TYPE (lhs))
&& ((vr_result.type == VR_RANGE
@@ -11118,7 +11149,9 @@ evrp_dom_walker::before_dom_children (basic_block bb)
|| vr.type == VR_ANTI_RANGE)
&& (TREE_CODE (vr.min) == INTEGER_CST)
&& (TREE_CODE (vr.max) == INTEGER_CST))
- set_range_info (output, vr.type, vr.min, vr.max);
+ set_range_info (output, vr.type,
+ wi::to_wide (vr.min),
+ wi::to_wide (vr.max));
}
else if (POINTER_TYPE_P (TREE_TYPE (output))
&& ((vr.type == VR_RANGE
diff --git a/gcc/tree.c b/gcc/tree.c
index 788a84b..fa6fcb1 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -259,7 +259,7 @@ tree integer_types[itk_none];
bool int_n_enabled_p[NUM_INT_N_ENTS];
struct int_n_trees_t int_n_trees [NUM_INT_N_ENTS];
-unsigned char tree_contains_struct[MAX_TREE_CODES][64];
+bool tree_contains_struct[MAX_TREE_CODES][64];
/* Number of operands for each OpenMP clause. */
unsigned const char omp_clause_num_ops[] =
@@ -671,7 +671,7 @@ decl_assembler_name (tree decl)
{
if (!DECL_ASSEMBLER_NAME_SET_P (decl))
lang_hooks.set_decl_assembler_name (decl);
- return DECL_WITH_VIS_CHECK (decl)->decl_with_vis.assembler_name;
+ return DECL_ASSEMBLER_NAME_RAW (decl);
}
/* When the target supports COMDAT groups, this indicates which group the
@@ -763,40 +763,53 @@ tree_code_size (enum tree_code code)
switch (TREE_CODE_CLASS (code))
{
case tcc_declaration: /* A decl node */
- {
- switch (code)
- {
- case FIELD_DECL:
- return sizeof (struct tree_field_decl);
- case PARM_DECL:
- return sizeof (struct tree_parm_decl);
- case VAR_DECL:
- return sizeof (struct tree_var_decl);
- case LABEL_DECL:
- return sizeof (struct tree_label_decl);
- case RESULT_DECL:
- return sizeof (struct tree_result_decl);
- case CONST_DECL:
- return sizeof (struct tree_const_decl);
- case TYPE_DECL:
- return sizeof (struct tree_type_decl);
- case FUNCTION_DECL:
- return sizeof (struct tree_function_decl);
- case DEBUG_EXPR_DECL:
- return sizeof (struct tree_decl_with_rtl);
- case TRANSLATION_UNIT_DECL:
- return sizeof (struct tree_translation_unit_decl);
- case NAMESPACE_DECL:
- case IMPORTED_DECL:
- case NAMELIST_DECL:
- return sizeof (struct tree_decl_non_common);
- default:
- return lang_hooks.tree_size (code);
- }
- }
+ switch (code)
+ {
+ case FIELD_DECL: return sizeof (tree_field_decl);
+ case PARM_DECL: return sizeof (tree_parm_decl);
+ case VAR_DECL: return sizeof (tree_var_decl);
+ case LABEL_DECL: return sizeof (tree_label_decl);
+ case RESULT_DECL: return sizeof (tree_result_decl);
+ case CONST_DECL: return sizeof (tree_const_decl);
+ case TYPE_DECL: return sizeof (tree_type_decl);
+ case FUNCTION_DECL: return sizeof (tree_function_decl);
+ case DEBUG_EXPR_DECL: return sizeof (tree_decl_with_rtl);
+ case TRANSLATION_UNIT_DECL: return sizeof (tree_translation_unit_decl);
+ case NAMESPACE_DECL:
+ case IMPORTED_DECL:
+ case NAMELIST_DECL: return sizeof (tree_decl_non_common);
+ default:
+ gcc_checking_assert (code >= NUM_TREE_CODES);
+ return lang_hooks.tree_size (code);
+ }
case tcc_type: /* a type node */
- return sizeof (struct tree_type_non_common);
+ switch (code)
+ {
+ case OFFSET_TYPE:
+ case ENUMERAL_TYPE:
+ case BOOLEAN_TYPE:
+ case INTEGER_TYPE:
+ case REAL_TYPE:
+ case POINTER_TYPE:
+ case REFERENCE_TYPE:
+ case NULLPTR_TYPE:
+ case FIXED_POINT_TYPE:
+ case COMPLEX_TYPE:
+ case VECTOR_TYPE:
+ case ARRAY_TYPE:
+ case RECORD_TYPE:
+ case UNION_TYPE:
+ case QUAL_UNION_TYPE:
+ case VOID_TYPE:
+ case POINTER_BOUNDS_TYPE:
+ case FUNCTION_TYPE:
+ case METHOD_TYPE:
+ case LANG_TYPE: return sizeof (tree_type_non_common);
+ default:
+ gcc_checking_assert (code >= NUM_TREE_CODES);
+ return lang_hooks.tree_size (code);
+ }
case tcc_reference: /* a reference */
case tcc_expression: /* an expression */
@@ -810,14 +823,15 @@ tree_code_size (enum tree_code code)
case tcc_constant: /* a constant */
switch (code)
{
- case VOID_CST: return sizeof (struct tree_typed);
+ case VOID_CST: return sizeof (tree_typed);
case INTEGER_CST: gcc_unreachable ();
- case REAL_CST: return sizeof (struct tree_real_cst);
- case FIXED_CST: return sizeof (struct tree_fixed_cst);
- case COMPLEX_CST: return sizeof (struct tree_complex);
- case VECTOR_CST: return sizeof (struct tree_vector);
+ case REAL_CST: return sizeof (tree_real_cst);
+ case FIXED_CST: return sizeof (tree_fixed_cst);
+ case COMPLEX_CST: return sizeof (tree_complex);
+ case VECTOR_CST: return sizeof (tree_vector);
case STRING_CST: gcc_unreachable ();
default:
+ gcc_checking_assert (code >= NUM_TREE_CODES);
return lang_hooks.tree_size (code);
}
@@ -825,23 +839,24 @@ tree_code_size (enum tree_code code)
switch (code)
{
case IDENTIFIER_NODE: return lang_hooks.identifier_size;
- case TREE_LIST: return sizeof (struct tree_list);
+ case TREE_LIST: return sizeof (tree_list);
case ERROR_MARK:
- case PLACEHOLDER_EXPR: return sizeof (struct tree_common);
+ case PLACEHOLDER_EXPR: return sizeof (tree_common);
- case TREE_VEC:
+ case TREE_VEC: gcc_unreachable ();
case OMP_CLAUSE: gcc_unreachable ();
- case SSA_NAME: return sizeof (struct tree_ssa_name);
+ case SSA_NAME: return sizeof (tree_ssa_name);
- case STATEMENT_LIST: return sizeof (struct tree_statement_list);
+ case STATEMENT_LIST: return sizeof (tree_statement_list);
case BLOCK: return sizeof (struct tree_block);
- case CONSTRUCTOR: return sizeof (struct tree_constructor);
- case OPTIMIZATION_NODE: return sizeof (struct tree_optimization_option);
- case TARGET_OPTION_NODE: return sizeof (struct tree_target_option);
+ case CONSTRUCTOR: return sizeof (tree_constructor);
+ case OPTIMIZATION_NODE: return sizeof (tree_optimization_option);
+ case TARGET_OPTION_NODE: return sizeof (tree_target_option);
default:
+ gcc_checking_assert (code >= NUM_TREE_CODES);
return lang_hooks.tree_size (code);
}
@@ -1584,7 +1599,7 @@ cache_integer_cst (tree t)
case BOOLEAN_TYPE:
/* Cache false or true. */
limit = 2;
- if (wi::ltu_p (t, 2))
+ if (wi::ltu_p (wi::to_wide (t), 2))
ix = TREE_INT_CST_ELT (t, 0);
break;
@@ -1603,7 +1618,7 @@ cache_integer_cst (tree t)
if (tree_to_uhwi (t) < (unsigned HOST_WIDE_INT) INTEGER_SHARE_LIMIT)
ix = tree_to_uhwi (t);
}
- else if (wi::ltu_p (t, INTEGER_SHARE_LIMIT))
+ else if (wi::ltu_p (wi::to_wide (t), INTEGER_SHARE_LIMIT))
ix = tree_to_uhwi (t);
}
else
@@ -1613,14 +1628,14 @@ cache_integer_cst (tree t)
if (integer_minus_onep (t))
ix = 0;
- else if (!wi::neg_p (t))
+ else if (!wi::neg_p (wi::to_wide (t)))
{
if (prec < HOST_BITS_PER_WIDE_INT)
{
if (tree_to_shwi (t) < INTEGER_SHARE_LIMIT)
ix = tree_to_shwi (t) + 1;
}
- else if (wi::ltu_p (t, INTEGER_SHARE_LIMIT))
+ else if (wi::ltu_p (wi::to_wide (t), INTEGER_SHARE_LIMIT))
ix = tree_to_shwi (t) + 1;
}
}
@@ -1652,7 +1667,7 @@ cache_integer_cst (tree t)
/* If there is already an entry for the number verify it's the
same. */
if (*slot)
- gcc_assert (wi::eq_p (tree (*slot), t));
+ gcc_assert (wi::to_wide (tree (*slot)) == wi::to_wide (t));
else
/* Otherwise insert this one into the hash table. */
*slot = t;
@@ -1969,7 +1984,7 @@ real_value_from_int_cst (const_tree type, const_tree i)
bitwise comparisons to see if two values are the same. */
memset (&d, 0, sizeof d);
- real_from_integer (&d, type ? TYPE_MODE (type) : VOIDmode, i,
+ real_from_integer (&d, type ? TYPE_MODE (type) : VOIDmode, wi::to_wide (i),
TYPE_SIGN (TREE_TYPE (i)));
return d;
}
@@ -2331,7 +2346,7 @@ integer_zerop (const_tree expr)
switch (TREE_CODE (expr))
{
case INTEGER_CST:
- return wi::eq_p (expr, 0);
+ return wi::to_wide (expr) == 0;
case COMPLEX_CST:
return (integer_zerop (TREE_REALPART (expr))
&& integer_zerop (TREE_IMAGPART (expr)));
@@ -2410,7 +2425,8 @@ integer_all_onesp (const_tree expr)
else if (TREE_CODE (expr) != INTEGER_CST)
return 0;
- return wi::max_value (TYPE_PRECISION (TREE_TYPE (expr)), UNSIGNED) == expr;
+ return (wi::max_value (TYPE_PRECISION (TREE_TYPE (expr)), UNSIGNED)
+ == wi::to_wide (expr));
}
/* Return 1 if EXPR is the integer constant minus one. */
@@ -2439,7 +2455,7 @@ integer_pow2p (const_tree expr)
if (TREE_CODE (expr) != INTEGER_CST)
return 0;
- return wi::popcount (expr) == 1;
+ return wi::popcount (wi::to_wide (expr)) == 1;
}
/* Return 1 if EXPR is an integer constant other than zero or a
@@ -2449,7 +2465,7 @@ int
integer_nonzerop (const_tree expr)
{
return ((TREE_CODE (expr) == INTEGER_CST
- && !wi::eq_p (expr, 0))
+ && wi::to_wide (expr) != 0)
|| (TREE_CODE (expr) == COMPLEX_CST
&& (integer_nonzerop (TREE_REALPART (expr))
|| integer_nonzerop (TREE_IMAGPART (expr)))));
@@ -2485,7 +2501,7 @@ tree_log2 (const_tree expr)
if (TREE_CODE (expr) == COMPLEX_CST)
return tree_log2 (TREE_REALPART (expr));
- return wi::exact_log2 (expr);
+ return wi::exact_log2 (wi::to_wide (expr));
}
/* Similar, but return the largest integer Y such that 2 ** Y is less
@@ -2497,7 +2513,7 @@ tree_floor_log2 (const_tree expr)
if (TREE_CODE (expr) == COMPLEX_CST)
return tree_log2 (TREE_REALPART (expr));
- return wi::floor_log2 (expr);
+ return wi::floor_log2 (wi::to_wide (expr));
}
/* Return number of known trailing zero bits in EXPR, or, if the value of
@@ -2514,7 +2530,7 @@ tree_ctz (const_tree expr)
switch (TREE_CODE (expr))
{
case INTEGER_CST:
- ret1 = wi::ctz (expr);
+ ret1 = wi::ctz (wi::to_wide (expr));
return MIN (ret1, prec);
case SSA_NAME:
ret1 = wi::ctz (get_nonzero_bits (expr));
@@ -4679,7 +4695,7 @@ build_simple_mem_ref_loc (location_t loc, tree ptr)
offset_int
mem_ref_offset (const_tree t)
{
- return offset_int::from (TREE_OPERAND (t, 1), SIGNED);
+ return offset_int::from (wi::to_wide (TREE_OPERAND (t, 1)), SIGNED);
}
/* Return an invariant ADDR_EXPR of type TYPE taking the address of BASE
@@ -5821,11 +5837,10 @@ find_atomic_core_type (tree type)
tree base_atomic_type;
/* Only handle complete types. */
- if (TYPE_SIZE (type) == NULL_TREE)
+ if (!tree_fits_uhwi_p (TYPE_SIZE (type)))
return NULL_TREE;
- HOST_WIDE_INT type_size = tree_to_uhwi (TYPE_SIZE (type));
- switch (type_size)
+ switch (tree_to_uhwi (TYPE_SIZE (type)))
{
case 8:
base_atomic_type = atomicQI_type_node;
@@ -6615,7 +6630,7 @@ tree_int_cst_sign_bit (const_tree t)
{
unsigned bitno = TYPE_PRECISION (TREE_TYPE (t)) - 1;
- return wi::extract_uhwi (t, bitno, 1);
+ return wi::extract_uhwi (wi::to_wide (t), bitno, 1);
}
/* Return an indication of the sign of the integer constant T.
@@ -6625,11 +6640,11 @@ tree_int_cst_sign_bit (const_tree t)
int
tree_int_cst_sgn (const_tree t)
{
- if (wi::eq_p (t, 0))
+ if (wi::to_wide (t) == 0)
return 0;
else if (TYPE_UNSIGNED (TREE_TYPE (t)))
return 1;
- else if (wi::neg_p (t))
+ else if (wi::neg_p (wi::to_wide (t)))
return -1;
else
return 1;
@@ -7058,7 +7073,7 @@ add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
case INTEGER_CST:
gcc_checking_assert (!(flags & OEP_ADDRESS_OF));
for (i = 0; i < TREE_INT_CST_EXT_NUNITS (t); i++)
- hstate.add_wide_int (TREE_INT_CST_ELT (t, i));
+ hstate.add_hwi (TREE_INT_CST_ELT (t, i));
return;
case REAL_CST:
{
@@ -7093,7 +7108,7 @@ add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
}
case SSA_NAME:
/* We can just compare by pointer. */
- hstate.add_wide_int (SSA_NAME_VERSION (t));
+ hstate.add_hwi (SSA_NAME_VERSION (t));
return;
case PLACEHOLDER_EXPR:
/* The node itself doesn't matter. */
@@ -7151,7 +7166,7 @@ add_expr (const_tree t, inchash::hash &hstate, unsigned int flags)
if (tclass == tcc_declaration)
{
/* DECL's have a unique ID */
- hstate.add_wide_int (DECL_UID (t));
+ hstate.add_hwi (DECL_UID (t));
}
else if (tclass == tcc_comparison && !commutative_tree_code (code))
{
@@ -8292,7 +8307,7 @@ get_unwidened (tree op, tree for_type)
if (TREE_CODE (win) == INTEGER_CST)
{
tree wtype = TREE_TYPE (win);
- unsigned prec = wi::min_precision (win, TYPE_SIGN (wtype));
+ unsigned prec = wi::min_precision (wi::to_wide (win), TYPE_SIGN (wtype));
if (for_type)
prec = MAX (prec, final_prec);
if (prec < TYPE_PRECISION (wtype))
@@ -8413,7 +8428,7 @@ int_fits_type_p (const_tree c, const_tree type)
/* Non-standard boolean types can have arbitrary precision but various
transformations assume that they can only take values 0 and +/-1. */
if (TREE_CODE (type) == BOOLEAN_TYPE)
- return wi::fits_to_boolean_p (c, type);
+ return wi::fits_to_boolean_p (wi::to_wide (c), type);
retry:
type_low_bound = TYPE_MIN_VALUE (type);
@@ -8456,7 +8471,7 @@ retry:
/* Perform some generic filtering which may allow making a decision
even if the bounds are not constant. First, negative integers
never fit in unsigned types, */
- if (TYPE_UNSIGNED (type) && sgn_c == SIGNED && wi::neg_p (c))
+ if (TYPE_UNSIGNED (type) && sgn_c == SIGNED && wi::neg_p (wi::to_wide (c)))
return false;
/* Second, narrower types always fit in wider ones. */
@@ -8475,10 +8490,10 @@ retry:
possible that the value will not fit. The test below
fails if any bit is set between the sign bit of the
underlying mode and the top bit of the type. */
- if (wi::ne_p (wi::zext (c, prec - 1), c))
+ if (wi::zext (wi::to_wide (c), prec - 1) != wi::to_wide (c))
return false;
}
- else if (wi::neg_p (c))
+ else if (wi::neg_p (wi::to_wide (c)))
return false;
}
@@ -8494,7 +8509,7 @@ retry:
}
/* Or to fits_to_tree_p, if nothing else. */
- return wi::fits_to_tree_p (c, type);
+ return wi::fits_to_tree_p (wi::to_wide (c), type);
}
/* Stores bounds of an integer TYPE in MIN and MAX. If TYPE has non-constant
@@ -8507,7 +8522,7 @@ get_type_static_bounds (const_tree type, mpz_t min, mpz_t max)
{
if (!POINTER_TYPE_P (type) && TYPE_MIN_VALUE (type)
&& TREE_CODE (TYPE_MIN_VALUE (type)) == INTEGER_CST)
- wi::to_mpz (TYPE_MIN_VALUE (type), min, TYPE_SIGN (type));
+ wi::to_mpz (wi::to_wide (TYPE_MIN_VALUE (type)), min, TYPE_SIGN (type));
else
{
if (TYPE_UNSIGNED (type))
@@ -8521,7 +8536,7 @@ get_type_static_bounds (const_tree type, mpz_t min, mpz_t max)
if (!POINTER_TYPE_P (type) && TYPE_MAX_VALUE (type)
&& TREE_CODE (TYPE_MAX_VALUE (type)) == INTEGER_CST)
- wi::to_mpz (TYPE_MAX_VALUE (type), max, TYPE_SIGN (type));
+ wi::to_mpz (wi::to_wide (TYPE_MAX_VALUE (type)), max, TYPE_SIGN (type));
else
{
wide_int mn = wi::max_value (TYPE_PRECISION (type), TYPE_SIGN (type));
@@ -9960,6 +9975,13 @@ build_common_builtin_nodes (void)
"__builtin_alloca_with_align",
alloca_flags);
+ ftype = build_function_type_list (ptr_type_node, size_type_node,
+ size_type_node, size_type_node, NULL_TREE);
+ local_define_builtin ("__builtin_alloca_with_align_and_max", ftype,
+ BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX,
+ "__builtin_alloca_with_align_and_max",
+ alloca_flags);
+
ftype = build_function_type_list (void_type_node,
ptr_type_node, ptr_type_node,
ptr_type_node, NULL_TREE);
@@ -10701,6 +10723,33 @@ maybe_build_call_expr_loc (location_t loc, combined_fn fn, tree type,
}
}
+/* Return a function call to the appropriate builtin alloca variant.
+
+ SIZE is the size to be allocated. ALIGN, if non-zero, is the requested
+ alignment of the allocated area. MAX_SIZE, if non-negative, is an upper
+ bound for SIZE in case it is not a fixed value. */
+
+tree
+build_alloca_call_expr (tree size, unsigned int align, HOST_WIDE_INT max_size)
+{
+ if (max_size >= 0)
+ {
+ tree t = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX);
+ return
+ build_call_expr (t, 3, size, size_int (align), size_int (max_size));
+ }
+ else if (align > 0)
+ {
+ tree t = builtin_decl_explicit (BUILT_IN_ALLOCA_WITH_ALIGN);
+ return build_call_expr (t, 2, size, size_int (align));
+ }
+ else
+ {
+ tree t = builtin_decl_explicit (BUILT_IN_ALLOCA);
+ return build_call_expr (t, 1, size);
+ }
+}
+
/* Create a new constant string literal and return a char* pointer to it.
The STRING_CST value is the LEN characters at STR. */
tree
@@ -10932,7 +10981,7 @@ operand_equal_for_phi_arg_p (const_tree arg0, const_tree arg1)
tree
num_ending_zeros (const_tree x)
{
- return build_int_cst (TREE_TYPE (x), wi::ctz (x));
+ return build_int_cst (TREE_TYPE (x), wi::ctz (wi::to_wide (x)));
}
@@ -12356,7 +12405,7 @@ drop_tree_overflow (tree t)
/* For tree codes with a sharing machinery re-build the result. */
if (TREE_CODE (t) == INTEGER_CST)
- return wide_int_to_tree (TREE_TYPE (t), t);
+ return wide_int_to_tree (TREE_TYPE (t), wi::to_wide (t));
/* Otherwise, as all tcc_constants are possibly shared, copy the node
and drop the flag. */
@@ -12500,6 +12549,9 @@ array_at_struct_end_p (tree ref)
else
return false;
+ if (TREE_CODE (ref) == STRING_CST)
+ return false;
+
while (handled_component_p (ref))
{
/* If the reference chain contains a component reference to a
@@ -13529,7 +13581,7 @@ get_range_pos_neg (tree arg)
int cnt = 0;
if (TREE_CODE (arg) == INTEGER_CST)
{
- wide_int w = wi::sext (arg, prec);
+ wide_int w = wi::sext (wi::to_wide (arg), prec);
if (wi::neg_p (w))
return 2;
else
diff --git a/gcc/tree.def b/gcc/tree.def
index 9f80c4d..3d2bd95 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -982,8 +982,8 @@ DEFTREECODE (SCEV_KNOWN, "scev_known", tcc_expression, 0)
DEFTREECODE (SCEV_NOT_KNOWN, "scev_not_known", tcc_expression, 0)
/* Polynomial chains of recurrences.
- Under the form: cr = {CHREC_LEFT (cr), +, CHREC_RIGHT (cr)}. */
-DEFTREECODE (POLYNOMIAL_CHREC, "polynomial_chrec", tcc_expression, 3)
+ cr = {CHREC_LEFT (cr), +, CHREC_RIGHT (cr)}_CHREC_VARIABLE (cr). */
+DEFTREECODE (POLYNOMIAL_CHREC, "polynomial_chrec", tcc_expression, 2)
/* Used to chain children of container statements together.
Use the interface in tree-iterator.h to access this node. */
diff --git a/gcc/tree.h b/gcc/tree.h
index caa4a69..7214ae2 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -76,64 +76,43 @@ as_internal_fn (combined_fn code)
/* Macros for initializing `tree_contains_struct'. */
#define MARK_TS_BASE(C) \
- do { \
- tree_contains_struct[C][TS_BASE] = 1; \
- } while (0)
+ (tree_contains_struct[C][TS_BASE] = true)
#define MARK_TS_TYPED(C) \
- do { \
- MARK_TS_BASE (C); \
- tree_contains_struct[C][TS_TYPED] = 1; \
- } while (0)
+ (MARK_TS_BASE (C), \
+ tree_contains_struct[C][TS_TYPED] = true)
#define MARK_TS_COMMON(C) \
- do { \
- MARK_TS_TYPED (C); \
- tree_contains_struct[C][TS_COMMON] = 1; \
- } while (0)
+ (MARK_TS_TYPED (C), \
+ tree_contains_struct[C][TS_COMMON] = true)
#define MARK_TS_TYPE_COMMON(C) \
- do { \
- MARK_TS_COMMON (C); \
- tree_contains_struct[C][TS_TYPE_COMMON] = 1; \
- } while (0)
+ (MARK_TS_COMMON (C), \
+ tree_contains_struct[C][TS_TYPE_COMMON] = true)
#define MARK_TS_TYPE_WITH_LANG_SPECIFIC(C) \
- do { \
- MARK_TS_TYPE_COMMON (C); \
- tree_contains_struct[C][TS_TYPE_WITH_LANG_SPECIFIC] = 1; \
- } while (0)
+ (MARK_TS_TYPE_COMMON (C), \
+ tree_contains_struct[C][TS_TYPE_WITH_LANG_SPECIFIC] = true)
#define MARK_TS_DECL_MINIMAL(C) \
- do { \
- MARK_TS_COMMON (C); \
- tree_contains_struct[C][TS_DECL_MINIMAL] = 1; \
- } while (0)
+ (MARK_TS_COMMON (C), \
+ tree_contains_struct[C][TS_DECL_MINIMAL] = true)
#define MARK_TS_DECL_COMMON(C) \
- do { \
- MARK_TS_DECL_MINIMAL (C); \
- tree_contains_struct[C][TS_DECL_COMMON] = 1; \
- } while (0)
+ (MARK_TS_DECL_MINIMAL (C), \
+ tree_contains_struct[C][TS_DECL_COMMON] = true)
#define MARK_TS_DECL_WRTL(C) \
- do { \
- MARK_TS_DECL_COMMON (C); \
- tree_contains_struct[C][TS_DECL_WRTL] = 1; \
- } while (0)
+ (MARK_TS_DECL_COMMON (C), \
+ tree_contains_struct[C][TS_DECL_WRTL] = true)
#define MARK_TS_DECL_WITH_VIS(C) \
- do { \
- MARK_TS_DECL_WRTL (C); \
- tree_contains_struct[C][TS_DECL_WITH_VIS] = 1; \
- } while (0)
+ (MARK_TS_DECL_WRTL (C), \
+ tree_contains_struct[C][TS_DECL_WITH_VIS] = true)
#define MARK_TS_DECL_NON_COMMON(C) \
- do { \
- MARK_TS_DECL_WITH_VIS (C); \
- tree_contains_struct[C][TS_DECL_NON_COMMON] = 1; \
- } while (0)
-
+ (MARK_TS_DECL_WITH_VIS (C), \
+ tree_contains_struct[C][TS_DECL_NON_COMMON] = true)
/* Returns the string representing CLASS. */
@@ -1241,10 +1220,9 @@ extern void protected_set_expr_location (tree, location_t);
#define COND_EXPR_ELSE(NODE) (TREE_OPERAND (COND_EXPR_CHECK (NODE), 2))
/* Accessors for the chains of recurrences. */
-#define CHREC_VAR(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 0)
-#define CHREC_LEFT(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 1)
-#define CHREC_RIGHT(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 2)
-#define CHREC_VARIABLE(NODE) TREE_INT_CST_LOW (CHREC_VAR (NODE))
+#define CHREC_LEFT(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 0)
+#define CHREC_RIGHT(NODE) TREE_OPERAND (POLYNOMIAL_CHREC_CHECK (NODE), 1)
+#define CHREC_VARIABLE(NODE) POLYNOMIAL_CHREC_CHECK (NODE)->base.u.chrec_var
/* LABEL_EXPR accessor. This gives access to the label associated with
the given label expression. */
@@ -2418,6 +2396,18 @@ extern machine_mode vector_type_mode (const_tree);
#define DECL_FUNCTION_CODE(NODE) \
(FUNCTION_DECL_CHECK (NODE)->function_decl.function_code)
+/* Test if FCODE is a function code for an alloca operation. */
+#define ALLOCA_FUNCTION_CODE_P(FCODE) \
+ ((FCODE) == BUILT_IN_ALLOCA \
+ || (FCODE) == BUILT_IN_ALLOCA_WITH_ALIGN \
+ || (FCODE) == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX)
+
+/* Generate case for an alloca operation. */
+#define CASE_BUILT_IN_ALLOCA \
+ case BUILT_IN_ALLOCA: \
+ case BUILT_IN_ALLOCA_WITH_ALIGN: \
+ case BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX
+
#define DECL_FUNCTION_PERSONALITY(NODE) \
(FUNCTION_DECL_CHECK (NODE)->function_decl.personality)
@@ -2722,6 +2712,10 @@ extern void decl_value_expr_insert (tree, tree);
LTO compilation and C++. */
#define DECL_ASSEMBLER_NAME(NODE) decl_assembler_name (NODE)
+/* Raw accessor for DECL_ASSEMBLE_NAME. */
+#define DECL_ASSEMBLER_NAME_RAW(NODE) \
+ (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.assembler_name)
+
/* Return true if NODE is a NODE that can contain a DECL_ASSEMBLER_NAME.
This is true of all DECL nodes except FIELD_DECL. */
#define HAS_DECL_ASSEMBLER_NAME_P(NODE) \
@@ -2731,12 +2725,11 @@ extern void decl_value_expr_insert (tree, tree);
the NODE might still have a DECL_ASSEMBLER_NAME -- it just hasn't been set
yet. */
#define DECL_ASSEMBLER_NAME_SET_P(NODE) \
- (HAS_DECL_ASSEMBLER_NAME_P (NODE) \
- && DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.assembler_name != NULL_TREE)
+ (DECL_ASSEMBLER_NAME_RAW (NODE) != NULL_TREE)
/* Set the DECL_ASSEMBLER_NAME for NODE to NAME. */
#define SET_DECL_ASSEMBLER_NAME(NODE, NAME) \
- (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.assembler_name = (NAME))
+ (DECL_ASSEMBLER_NAME_RAW (NODE) = (NAME))
/* Copy the DECL_ASSEMBLER_NAME from DECL1 to DECL2. Note that if DECL1's
DECL_ASSEMBLER_NAME has not yet been set, using this macro will not cause
@@ -2748,10 +2741,7 @@ extern void decl_value_expr_insert (tree, tree);
which will try to set the DECL_ASSEMBLER_NAME for DECL1. */
#define COPY_DECL_ASSEMBLER_NAME(DECL1, DECL2) \
- (DECL_ASSEMBLER_NAME_SET_P (DECL1) \
- ? (void) SET_DECL_ASSEMBLER_NAME (DECL2, \
- DECL_ASSEMBLER_NAME (DECL1)) \
- : (void) 0)
+ SET_DECL_ASSEMBLER_NAME (DECL2, DECL_ASSEMBLER_NAME_RAW (DECL1))
/* Records the section name in a section attribute. Used to pass
the name from decl_attributes to make_function_rtl and make_decl_rtl. */
@@ -4072,6 +4062,7 @@ extern tree build_call_expr_internal_loc_array (location_t, enum internal_fn,
tree, int, const tree *);
extern tree maybe_build_call_expr_loc (location_t, combined_fn, tree,
int, ...);
+extern tree build_alloca_call_expr (tree, unsigned int, HOST_WIDE_INT);
extern tree build_string_literal (int, const char *);
/* Construct various nodes representing data types. */
@@ -5120,20 +5111,6 @@ extern bool anon_aggrname_p (const_tree);
/* The tree and const_tree overload templates. */
namespace wi
{
- template <>
- struct int_traits <const_tree>
- {
- static const enum precision_type precision_type = VAR_PRECISION;
- static const bool host_dependent_precision = false;
- static const bool is_sign_extended = false;
- static unsigned int get_precision (const_tree);
- static wi::storage_ref decompose (HOST_WIDE_INT *, unsigned int,
- const_tree);
- };
-
- template <>
- struct int_traits <tree> : public int_traits <const_tree> {};
-
template <int N>
class extended_tree
{
@@ -5157,41 +5134,115 @@ namespace wi
static const unsigned int precision = N;
};
- generic_wide_int <extended_tree <WIDE_INT_MAX_PRECISION> >
- to_widest (const_tree);
-
- generic_wide_int <extended_tree <ADDR_MAX_PRECISION> > to_offset (const_tree);
+ typedef const generic_wide_int <extended_tree <WIDE_INT_MAX_PRECISION> >
+ tree_to_widest_ref;
+ typedef const generic_wide_int <extended_tree <ADDR_MAX_PRECISION> >
+ tree_to_offset_ref;
+ typedef const generic_wide_int<wide_int_ref_storage<false, false> >
+ tree_to_wide_ref;
+ tree_to_widest_ref to_widest (const_tree);
+ tree_to_offset_ref to_offset (const_tree);
+ tree_to_wide_ref to_wide (const_tree);
wide_int to_wide (const_tree, unsigned int);
}
-inline unsigned int
-wi::int_traits <const_tree>::get_precision (const_tree tcst)
-{
- return TYPE_PRECISION (TREE_TYPE (tcst));
-}
+/* Refer to INTEGER_CST T as though it were a widest_int.
-/* Convert the tree_cst X into a wide_int of PRECISION. */
-inline wi::storage_ref
-wi::int_traits <const_tree>::decompose (HOST_WIDE_INT *,
- unsigned int precision, const_tree x)
-{
- return wi::storage_ref (&TREE_INT_CST_ELT (x, 0), TREE_INT_CST_NUNITS (x),
- precision);
-}
+ This function gives T's actual numerical value, influenced by the
+ signedness of its type. For example, a signed byte with just the
+ top bit set would be -128 while an unsigned byte with the same
+ bit pattern would be 128.
+
+ This is the right choice when operating on groups of INTEGER_CSTs
+ that might have different signedness or precision. It is also the
+ right choice in code that specifically needs an approximation of
+ infinite-precision arithmetic instead of normal modulo arithmetic.
+
+ The approximation of infinite precision is good enough for realistic
+ numbers of additions and subtractions of INTEGER_CSTs (where
+ "realistic" includes any number less than 1 << 31) but it cannot
+ represent the result of multiplying the two largest supported
+ INTEGER_CSTs. The overflow-checking form of wi::mul provides a way
+ of multiplying two arbitrary INTEGER_CSTs and checking that the
+ result is representable as a widest_int.
+
+ Note that any overflow checking done on these values is relative to
+ the range of widest_int rather than the range of a TREE_TYPE.
+
+ Calling this function should have no overhead in release builds,
+ so it is OK to call it several times for the same tree. If it is
+ useful for readability reasons to reduce the number of calls,
+ it is more efficient to use:
+
+ wi::tree_to_widest_ref wt = wi::to_widest (t);
-inline generic_wide_int <wi::extended_tree <WIDE_INT_MAX_PRECISION> >
+ instead of:
+
+ widest_int wt = wi::to_widest (t). */
+
+inline wi::tree_to_widest_ref
wi::to_widest (const_tree t)
{
return t;
}
-inline generic_wide_int <wi::extended_tree <ADDR_MAX_PRECISION> >
+/* Refer to INTEGER_CST T as though it were an offset_int.
+
+ This function is an optimisation of wi::to_widest for cases
+ in which T is known to be a bit or byte count in the range
+ (-(2 ^ (N + BITS_PER_UNIT)), 2 ^ (N + BITS_PER_UNIT)), where N is
+ the target's address size in bits.
+
+ This is the right choice when operating on bit or byte counts as
+ untyped numbers rather than M-bit values. The wi::to_widest comments
+ about addition, subtraction and multiplication apply here: sequences
+ of 1 << 31 additions and subtractions do not induce overflow, but
+ multiplying the largest sizes might. Again,
+
+ wi::tree_to_offset_ref wt = wi::to_offset (t);
+
+ is more efficient than:
+
+ offset_int wt = wi::to_offset (t). */
+
+inline wi::tree_to_offset_ref
wi::to_offset (const_tree t)
{
return t;
}
+/* Refer to INTEGER_CST T as though it were a wide_int.
+
+ In contrast to the approximation of infinite-precision numbers given
+ by wi::to_widest and wi::to_offset, this function treats T as a
+ signless collection of N bits, where N is the precision of T's type.
+ As with machine registers, signedness is determined by the operation
+ rather than the operands; for example, there is a distinction between
+ signed and unsigned division.
+
+ This is the right choice when operating on values with the same type
+ using normal modulo arithmetic. The overflow-checking forms of things
+ like wi::add check whether the result can be represented in T's type.
+
+ Calling this function should have no overhead in release builds,
+ so it is OK to call it several times for the same tree. If it is
+ useful for readability reasons to reduce the number of calls,
+ it is more efficient to use:
+
+ wi::tree_to_wide_ref wt = wi::to_wide (t);
+
+ instead of:
+
+ wide_int wt = wi::to_wide (t). */
+
+inline wi::tree_to_wide_ref
+wi::to_wide (const_tree t)
+{
+ return wi::storage_ref (&TREE_INT_CST_ELT (t, 0), TREE_INT_CST_NUNITS (t),
+ TYPE_PRECISION (TREE_TYPE (t)));
+}
+
/* Convert INTEGER_CST T to a wide_int of precision PREC, extending or
truncating as necessary. When extending, use sign extension if T's
type is signed and zero extension if T's type is unsigned. */
@@ -5199,7 +5250,7 @@ wi::to_offset (const_tree t)
inline wide_int
wi::to_wide (const_tree t, unsigned int prec)
{
- return wide_int::from (t, prec, TYPE_SIGN (TREE_TYPE (t)));
+ return wide_int::from (wi::to_wide (t), prec, TYPE_SIGN (TREE_TYPE (t)));
}
template <int N>
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 1030168..a6d446a 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -813,7 +813,6 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
/* Set up the fallthrough basic block. */
e = find_edge (cond_bb, fallthru_bb);
e->flags = EDGE_FALSE_VALUE;
- e->count = cond_bb->count;
e->probability = profile_probability::very_likely ();
/* Update dominance info for the newly created then_bb; note that
@@ -830,15 +829,17 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
enum built_in_function bcode
= (flag_sanitize_recover & ((check_align ? SANITIZE_ALIGNMENT : 0)
| (check_null ? SANITIZE_NULL : 0)))
- ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH
- : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT;
+ ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1
+ : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT;
tree fn = builtin_decl_implicit (bcode);
+ int align_log = tree_log2 (align);
tree data
= ubsan_create_data ("__ubsan_null_data", 1, &loc,
ubsan_type_descriptor (TREE_TYPE (ckind),
UBSAN_PRINT_POINTER),
NULL_TREE,
- align,
+ build_int_cst (unsigned_char_type_node,
+ MAX (align_log, 0)),
fold_convert (unsigned_char_type_node, ckind),
NULL_TREE);
data = build_fold_addr_expr_loc (loc, data);
@@ -882,7 +883,6 @@ ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
/* Set up the fallthrough basic block. */
e = find_edge (cond1_bb, cond2_bb);
e->flags = EDGE_FALSE_VALUE;
- e->count = cond1_bb->count;
e->probability = profile_probability::very_likely ();
/* Update dominance info. */
@@ -1001,14 +1001,14 @@ ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi)
ubsan_type_descriptor (TREE_TYPE (ptr),
UBSAN_PRINT_POINTER),
NULL_TREE,
- build_zero_cst (pointer_sized_int_node),
+ build_zero_cst (unsigned_char_type_node),
ckind,
NULL_TREE);
data = build_fold_addr_expr_loc (loc, data);
enum built_in_function bcode
= (flag_sanitize_recover & SANITIZE_OBJECT_SIZE)
- ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH
- : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_ABORT;
+ ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1
+ : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT;
tree p = make_ssa_name (pointer_sized_int_node);
g = gimple_build_assign (p, NOP_EXPR, ptr);
gimple_set_location (g, loc);
@@ -1073,7 +1073,6 @@ ubsan_expand_ptr_ifn (gimple_stmt_iterator *gsip)
e->flags = EDGE_FALSE_VALUE;
if (pos_neg != 3)
{
- e->count = cond_bb->count;
e->probability = profile_probability::very_likely ();
/* Connect 'then block' with the 'else block'. This is needed
@@ -1089,14 +1088,11 @@ ubsan_expand_ptr_ifn (gimple_stmt_iterator *gsip)
}
else
{
- profile_count count = cond_bb->count.apply_probability (PROB_EVEN);
- e->count = count;
e->probability = profile_probability::even ();
e = split_block (fallthru_bb, (gimple *) NULL);
cond_neg_bb = e->src;
fallthru_bb = e->dest;
- e->count = count;
e->probability = profile_probability::very_likely ();
e->flags = EDGE_FALSE_VALUE;
@@ -1107,14 +1103,12 @@ ubsan_expand_ptr_ifn (gimple_stmt_iterator *gsip)
add_bb_to_loop (cond_pos_bb, cond_bb->loop_father);
e = make_edge (cond_bb, cond_pos_bb, EDGE_TRUE_VALUE);
- e->count = count;
e->probability = profile_probability::even ();
e = make_edge (cond_pos_bb, then_bb, EDGE_TRUE_VALUE);
e->probability = profile_probability::very_unlikely ();
e = make_edge (cond_pos_bb, fallthru_bb, EDGE_FALSE_VALUE);
- e->count = count;
e->probability = profile_probability::very_likely ();
make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
@@ -1164,8 +1158,8 @@ ubsan_expand_ptr_ifn (gimple_stmt_iterator *gsip)
unlink_stmt_vdef (stmt);
if (TREE_CODE (off) == INTEGER_CST)
- g = gimple_build_cond (wi::neg_p (off) ? LT_EXPR : GE_EXPR, ptri,
- fold_build1 (NEGATE_EXPR, sizetype, off),
+ g = gimple_build_cond (wi::neg_p (wi::to_wide (off)) ? LT_EXPR : GE_EXPR,
+ ptri, fold_build1 (NEGATE_EXPR, sizetype, off),
NULL_TREE, NULL_TREE);
else if (pos_neg != 3)
g = gimple_build_cond (pos_neg == 1 ? LT_EXPR : GT_EXPR,
@@ -2024,15 +2018,18 @@ instrument_nonnull_return (gimple_stmt_iterator *gsi)
else
{
tree data = ubsan_create_data ("__ubsan_nonnull_return_data",
- 2, loc, NULL_TREE, NULL_TREE);
+ 1, &loc[1], NULL_TREE, NULL_TREE);
data = build_fold_addr_expr_loc (loc[0], data);
+ tree data2 = ubsan_create_data ("__ubsan_nonnull_return_data",
+ 1, &loc[0], NULL_TREE, NULL_TREE);
+ data2 = build_fold_addr_expr_loc (loc[0], data2);
enum built_in_function bcode
= (flag_sanitize_recover & SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
- ? BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN
- : BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_ABORT;
+ ? BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1
+ : BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT;
tree fn = builtin_decl_explicit (bcode);
- g = gimple_build_call (fn, 1, data);
+ g = gimple_build_call (fn, 2, data, data2);
}
gimple_set_location (g, loc[0]);
gsi_insert_before (gsi, g, GSI_SAME_STMT);
@@ -2216,6 +2213,72 @@ instrument_object_size (gimple_stmt_iterator *gsi, tree t, bool is_lhs)
gsi_insert_before (gsi, g, GSI_SAME_STMT);
}
+/* Instrument values passed to builtin functions. */
+
+static void
+instrument_builtin (gimple_stmt_iterator *gsi)
+{
+ gimple *stmt = gsi_stmt (*gsi);
+ location_t loc = gimple_location (stmt);
+ tree arg;
+ enum built_in_function fcode
+ = DECL_FUNCTION_CODE (gimple_call_fndecl (stmt));
+ int kind = 0;
+ switch (fcode)
+ {
+ CASE_INT_FN (BUILT_IN_CLZ):
+ kind = 1;
+ gcc_fallthrough ();
+ CASE_INT_FN (BUILT_IN_CTZ):
+ arg = gimple_call_arg (stmt, 0);
+ if (!integer_nonzerop (arg))
+ {
+ gimple *g;
+ if (!is_gimple_val (arg))
+ {
+ g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
+ gimple_set_location (g, loc);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ arg = gimple_assign_lhs (g);
+ }
+
+ basic_block then_bb, fallthru_bb;
+ *gsi = create_cond_insert_point (gsi, true, false, true,
+ &then_bb, &fallthru_bb);
+ g = gimple_build_cond (EQ_EXPR, arg,
+ build_zero_cst (TREE_TYPE (arg)),
+ NULL_TREE, NULL_TREE);
+ gimple_set_location (g, loc);
+ gsi_insert_after (gsi, g, GSI_NEW_STMT);
+
+ *gsi = gsi_after_labels (then_bb);
+ if (flag_sanitize_undefined_trap_on_error)
+ g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
+ else
+ {
+ tree t = build_int_cst (unsigned_char_type_node, kind);
+ tree data = ubsan_create_data ("__ubsan_builtin_data",
+ 1, &loc, NULL_TREE, t, NULL_TREE);
+ data = build_fold_addr_expr_loc (loc, data);
+ enum built_in_function bcode
+ = (flag_sanitize_recover & SANITIZE_BUILTIN)
+ ? BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN
+ : BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT;
+ tree fn = builtin_decl_explicit (bcode);
+
+ g = gimple_build_call (fn, 1, data);
+ }
+ gimple_set_location (g, loc);
+ gsi_insert_before (gsi, g, GSI_SAME_STMT);
+ ubsan_create_edge (g);
+ }
+ *gsi = gsi_for_stmt (stmt);
+ break;
+ default:
+ break;
+ }
+}
+
namespace {
const pass_data pass_data_ubsan =
@@ -2247,7 +2310,8 @@ public:
| SANITIZE_NONNULL_ATTRIBUTE
| SANITIZE_RETURNS_NONNULL_ATTRIBUTE
| SANITIZE_OBJECT_SIZE
- | SANITIZE_POINTER_OVERFLOW));
+ | SANITIZE_POINTER_OVERFLOW
+ | SANITIZE_BUILTIN));
}
virtual unsigned int execute (function *);
@@ -2312,6 +2376,13 @@ pass_ubsan::execute (function *fun)
bb = gimple_bb (stmt);
}
+ if (sanitize_flags_p (SANITIZE_BUILTIN, fun->decl)
+ && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
+ {
+ instrument_builtin (&gsi);
+ bb = gimple_bb (stmt);
+ }
+
if (sanitize_flags_p (SANITIZE_RETURNS_NONNULL_ATTRIBUTE, fun->decl)
&& gimple_code (stmt) == GIMPLE_RETURN)
{
diff --git a/gcc/unique-ptr-tests.cc b/gcc/unique-ptr-tests.cc
new file mode 100644
index 0000000..d275694
--- /dev/null
+++ b/gcc/unique-ptr-tests.cc
@@ -0,0 +1,234 @@
+/* Unit tests for unique-ptr.h.
+ Copyright (C) 2017 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
+<http://www.gnu.org/licenses/>. */
+
+#include "config.h"
+#define INCLUDE_UNIQUE_PTR
+#include "system.h"
+#include "coretypes.h"
+#include "selftest.h"
+
+#if CHECKING_P
+
+namespace selftest {
+
+namespace {
+
+/* A class for counting ctor and dtor invocations. */
+
+struct stats
+{
+ stats () : ctor_count (0), dtor_count (0) {}
+
+ int ctor_count;
+ int dtor_count;
+};
+
+/* A class that uses "stats" to track its ctor and dtor invocations. */
+
+class foo
+{
+public:
+ foo (stats &s) : m_s (s) { ++m_s.ctor_count; }
+ ~foo () { ++m_s.dtor_count; }
+
+ int example_method () const { return 42; }
+
+private:
+ foo (const foo&);
+ foo & operator= (const foo &);
+
+private:
+ stats &m_s;
+};
+
+/* A struct for testing unique_ptr<T[]>. */
+
+struct has_default_ctor
+{
+ has_default_ctor () : m_field (42) {}
+ int m_field;
+};
+
+/* A dummy struct for testing unique_xmalloc_ptr. */
+
+struct dummy
+{
+ int field;
+};
+
+} // anonymous namespace
+
+/* Verify that the default ctor inits ptrs to NULL. */
+
+static void
+test_null_ptr ()
+{
+ gnu::unique_ptr<void *> p;
+ ASSERT_EQ (NULL, p);
+
+ gnu::unique_xmalloc_ptr<void *> q;
+ ASSERT_EQ (NULL, q);
+}
+
+/* Verify that deletion happens when a unique_ptr goes out of scope. */
+
+static void
+test_implicit_deletion ()
+{
+ stats s;
+ ASSERT_EQ (0, s.ctor_count);
+ ASSERT_EQ (0, s.dtor_count);
+
+ {
+ gnu::unique_ptr<foo> f (new foo (s));
+ ASSERT_NE (NULL, f);
+ ASSERT_EQ (1, s.ctor_count);
+ ASSERT_EQ (0, s.dtor_count);
+ }
+
+ /* Verify that the foo was implicitly deleted. */
+ ASSERT_EQ (1, s.ctor_count);
+ ASSERT_EQ (1, s.dtor_count);
+}
+
+/* Verify that we can assign to a NULL unique_ptr. */
+
+static void
+test_overwrite_of_null ()
+{
+ stats s;
+ ASSERT_EQ (0, s.ctor_count);
+ ASSERT_EQ (0, s.dtor_count);
+
+ {
+ gnu::unique_ptr<foo> f;
+ ASSERT_EQ (NULL, f);
+ ASSERT_EQ (0, s.ctor_count);
+ ASSERT_EQ (0, s.dtor_count);
+
+ /* Overwrite with a non-NULL value. */
+ f = gnu::unique_ptr<foo> (new foo (s));
+ ASSERT_EQ (1, s.ctor_count);
+ ASSERT_EQ (0, s.dtor_count);
+ }
+
+ /* Verify that the foo is implicitly deleted. */
+ ASSERT_EQ (1, s.ctor_count);
+ ASSERT_EQ (1, s.dtor_count);
+}
+
+/* Verify that we can assign to a non-NULL unique_ptr. */
+
+static void
+test_overwrite_of_non_null ()
+{
+ stats s;
+ ASSERT_EQ (0, s.ctor_count);
+ ASSERT_EQ (0, s.dtor_count);
+
+ {
+ gnu::unique_ptr<foo> f (new foo (s));
+ ASSERT_NE (NULL, f);
+ ASSERT_EQ (1, s.ctor_count);
+ ASSERT_EQ (0, s.dtor_count);
+
+ /* Overwrite with a different value. */
+ f = gnu::unique_ptr<foo> (new foo (s));
+ ASSERT_EQ (2, s.ctor_count);
+ ASSERT_EQ (1, s.dtor_count);
+ }
+
+ /* Verify that the 2nd foo was implicitly deleted. */
+ ASSERT_EQ (2, s.ctor_count);
+ ASSERT_EQ (2, s.dtor_count);
+}
+
+/* Verify that unique_ptr's overloaded ops work. */
+
+static void
+test_overloaded_ops ()
+{
+ stats s;
+ gnu::unique_ptr<foo> f (new foo (s));
+ ASSERT_EQ (42, f->example_method ());
+ ASSERT_EQ (42, (*f).example_method ());
+ ASSERT_EQ (f, f);
+ ASSERT_NE (NULL, f.get ());
+
+ gnu::unique_ptr<foo> g (new foo (s));
+ ASSERT_NE (f, g);
+}
+
+/* Verify that the gnu::unique_ptr specialization for T[] works. */
+
+static void
+test_array_new ()
+{
+ const int num = 10;
+ gnu::unique_ptr<has_default_ctor[]> p (new has_default_ctor[num]);
+ ASSERT_NE (NULL, p.get ());
+ /* Verify that operator[] works, and that the default ctor was called
+ on each element. */
+ for (int i = 0; i < num; i++)
+ ASSERT_EQ (42, p[i].m_field);
+}
+
+/* Verify that gnu::unique_xmalloc_ptr works. */
+
+static void
+test_xmalloc ()
+{
+ gnu::unique_xmalloc_ptr<dummy> p (XNEW (dummy));
+ ASSERT_NE (NULL, p.get ());
+}
+
+/* Verify the gnu::unique_xmalloc_ptr specialization for T[]. */
+
+static void
+test_xmalloc_array ()
+{
+ const int num = 10;
+ gnu::unique_xmalloc_ptr<dummy[]> p (XNEWVEC (dummy, num));
+ ASSERT_NE (NULL, p.get ());
+
+ /* Verify that operator[] works. */
+ for (int i = 0; i < num; i++)
+ p[i].field = 42;
+ for (int i = 0; i < num; i++)
+ ASSERT_EQ (42, p[i].field);
+}
+
+/* Run all of the selftests within this file. */
+
+void
+unique_ptr_tests_cc_tests ()
+{
+ test_null_ptr ();
+ test_implicit_deletion ();
+ test_overwrite_of_null ();
+ test_overwrite_of_non_null ();
+ test_overloaded_ops ();
+ test_array_new ();
+ test_xmalloc ();
+ test_xmalloc_array ();
+}
+
+} // namespace selftest
+
+#endif /* #if CHECKING_P */
diff --git a/gcc/value-prof.c b/gcc/value-prof.c
index 23b8dc2..704900f 100644
--- a/gcc/value-prof.c
+++ b/gcc/value-prof.c
@@ -745,20 +745,16 @@ gimple_divmod_fixed_value (gassign *stmt, tree value, profile_probability prob,
e12->flags &= ~EDGE_FALLTHRU;
e12->flags |= EDGE_FALSE_VALUE;
e12->probability = prob;
- e12->count = profile_count::from_gcov_type (count);
e13 = make_edge (bb, bb3, EDGE_TRUE_VALUE);
e13->probability = prob.invert ();
- e13->count = profile_count::from_gcov_type (all - count);
remove_edge (e23);
e24 = make_edge (bb2, bb4, EDGE_FALLTHRU);
e24->probability = profile_probability::always ();
- e24->count = profile_count::from_gcov_type (count);
e34->probability = profile_probability::always ();
- e34->count = profile_count::from_gcov_type (all - count);
return tmp2;
}
@@ -910,20 +906,16 @@ gimple_mod_pow2 (gassign *stmt, profile_probability prob, gcov_type count, gcov_
e12->flags &= ~EDGE_FALLTHRU;
e12->flags |= EDGE_FALSE_VALUE;
e12->probability = prob;
- e12->count = profile_count::from_gcov_type (count);
e13 = make_edge (bb, bb3, EDGE_TRUE_VALUE);
e13->probability = prob.invert ();
- e13->count = profile_count::from_gcov_type (all - count);
remove_edge (e23);
e24 = make_edge (bb2, bb4, EDGE_FALLTHRU);
e24->probability = profile_probability::always ();
- e24->count = profile_count::from_gcov_type (count);
e34->probability = profile_probability::always ();
- e34->count = profile_count::from_gcov_type (all - count);
return result;
}
@@ -1076,26 +1068,21 @@ gimple_mod_subtract (gassign *stmt, profile_probability prob1,
e12->flags &= ~EDGE_FALLTHRU;
e12->flags |= EDGE_FALSE_VALUE;
e12->probability = prob1.invert ();
- e12->count = profile_count::from_gcov_type (all - count1);
e14 = make_edge (bb, bb4, EDGE_TRUE_VALUE);
e14->probability = prob1;
- e14->count = profile_count::from_gcov_type (count1);
if (ncounts) /* Assumed to be 0 or 1. */
{
e23->flags &= ~EDGE_FALLTHRU;
e23->flags |= EDGE_FALSE_VALUE;
- e23->count = profile_count::from_gcov_type (all - count1 - count2);
e23->probability = prob2.invert ();
e24 = make_edge (bb2, bb4, EDGE_TRUE_VALUE);
e24->probability = prob2;
- e24->count = profile_count::from_gcov_type (count2);
}
e34->probability = profile_probability::always ();
- e34->count = profile_count::from_gcov_type (all - count1 - count2);
return result;
}
@@ -1383,7 +1370,6 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node *direct_call,
if (e_ij != NULL)
{
e_ij->probability = profile_probability::always ();
- e_ij->count = all - count;
e_ij = single_pred_edge (split_edge (e_ij));
}
}
@@ -1395,25 +1381,18 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node *direct_call,
e_cd->flags = (e_cd->flags & ~EDGE_FALLTHRU) | EDGE_TRUE_VALUE;
e_cd->probability = prob;
- e_cd->count = count;
e_ci = make_edge (cond_bb, icall_bb, EDGE_FALSE_VALUE);
e_ci->probability = prob.invert ();
- e_ci->count = all - count;
remove_edge (e_di);
if (e_ij != NULL)
{
- if ((dflags & ECF_NORETURN) != 0)
- e_ij->count = all;
- else
+ if ((dflags & ECF_NORETURN) == 0)
{
e_dj = make_edge (dcall_bb, join_bb, EDGE_FALLTHRU);
e_dj->probability = profile_probability::always ();
- e_dj->count = count;
-
- e_ij->count = all - count;
}
e_ij->probability = profile_probability::always ();
}
@@ -1494,7 +1473,6 @@ gimple_ic (gcall *icall_stmt, struct cgraph_node *direct_call,
{
e = make_edge (dcall_bb, e_eh->dest, e_eh->flags);
e->probability = e_eh->probability;
- e->count = e_eh->count;
for (gphi_iterator psi = gsi_start_phis (e_eh->dest);
!gsi_end_p (psi); gsi_next (&psi))
{
@@ -1704,20 +1682,16 @@ gimple_stringop_fixed_value (gcall *vcall_stmt, tree icall_size, profile_probabi
e_ci->flags = (e_ci->flags & ~EDGE_FALLTHRU) | EDGE_TRUE_VALUE;
e_ci->probability = prob;
- e_ci->count = profile_count::from_gcov_type (count);
e_cv = make_edge (cond_bb, vcall_bb, EDGE_FALSE_VALUE);
e_cv->probability = prob.invert ();
- e_cv->count = profile_count::from_gcov_type (all - count);
remove_edge (e_iv);
e_ij = make_edge (icall_bb, join_bb, EDGE_FALLTHRU);
e_ij->probability = profile_probability::always ();
- e_ij->count = profile_count::from_gcov_type (count);
e_vj->probability = profile_probability::always ();
- e_vj->count = profile_count::from_gcov_type (all - count);
/* Insert PHI node for the call result if necessary. */
if (gimple_call_lhs (vcall_stmt)
diff --git a/gcc/varasm.c b/gcc/varasm.c
index 1c66c26..d324ca03 100644
--- a/gcc/varasm.c
+++ b/gcc/varasm.c
@@ -1055,7 +1055,7 @@ align_variable (tree decl, bool dont_output_data)
&& (in_lto_p || DECL_INITIAL (decl) != error_mark_node))
{
unsigned int const_align
- = CONSTANT_ALIGNMENT (DECL_INITIAL (decl), align);
+ = targetm.constant_alignment (DECL_INITIAL (decl), align);
/* Don't increase alignment too much for TLS variables - TLS
space is too precious. */
if (! DECL_THREAD_LOCAL_P (decl) || const_align <= BITS_PER_WORD)
@@ -1106,8 +1106,8 @@ get_variable_align (tree decl)
to mark offlined constructors. */
&& (in_lto_p || DECL_INITIAL (decl) != error_mark_node))
{
- unsigned int const_align = CONSTANT_ALIGNMENT (DECL_INITIAL (decl),
- align);
+ unsigned int const_align
+ = targetm.constant_alignment (DECL_INITIAL (decl), align);
/* Don't increase alignment too much for TLS variables - TLS space
is too precious. */
if (! DECL_THREAD_LOCAL_P (decl) || const_align <= BITS_PER_WORD)
@@ -2399,8 +2399,7 @@ incorporeal_function_p (tree decl)
const char *name;
if (DECL_BUILT_IN_CLASS (decl) == BUILT_IN_NORMAL
- && (DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA
- || DECL_FUNCTION_CODE (decl) == BUILT_IN_ALLOCA_WITH_ALIGN))
+ && ALLOCA_FUNCTION_CODE_P (DECL_FUNCTION_CODE (decl)))
return true;
name = IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl));
@@ -3326,12 +3325,10 @@ build_constant_desc (tree exp)
Instead we set the flag that will be recognized in make_decl_rtl. */
DECL_IN_CONSTANT_POOL (decl) = 1;
DECL_INITIAL (decl) = desc->value;
- /* ??? CONSTANT_ALIGNMENT hasn't been updated for vector types on most
- architectures so use DATA_ALIGNMENT as well, except for strings. */
+ /* ??? targetm.constant_alignment hasn't been updated for vector types on
+ most architectures so use DATA_ALIGNMENT as well, except for strings. */
if (TREE_CODE (exp) == STRING_CST)
- {
- SET_DECL_ALIGN (decl, CONSTANT_ALIGNMENT (exp, DECL_ALIGN (decl)));
- }
+ SET_DECL_ALIGN (decl, targetm.constant_alignment (exp, DECL_ALIGN (decl)));
else
align_variable (decl, 0);
@@ -3790,7 +3787,7 @@ force_const_mem (machine_mode mode, rtx x)
tree type = lang_hooks.types.type_for_mode (mode, 0);
if (type != NULL_TREE)
- align = CONSTANT_ALIGNMENT (make_tree (type, x), align);
+ align = targetm.constant_alignment (make_tree (type, x), align);
pool->offset += (align / BITS_PER_UNIT) - 1;
pool->offset &= ~ ((align / BITS_PER_UNIT) - 1);
diff --git a/gcc/vec.c b/gcc/vec.c
index d612703..9a80f34 100644
--- a/gcc/vec.c
+++ b/gcc/vec.c
@@ -31,6 +31,12 @@ along with GCC; see the file COPYING3. If not see
#include "coretypes.h"
#include "hash-table.h"
#include "selftest.h"
+#ifdef GENERATOR_FILE
+#include "errors.h"
+#else
+#include "input.h"
+#include "diagnostic-core.h"
+#endif
/* vNULL is an empty type with a template cast operation that returns
a zero-initialized vec<T, A, L> instance. Use this when you want
@@ -190,6 +196,93 @@ dump_vec_loc_statistics (void)
vec_mem_desc.dump (VEC_ORIGIN);
}
+#if CHECKING_P
+/* Report qsort comparator CMP consistency check failure with P1, P2, P3 as
+ witness elements. */
+ATTRIBUTE_NORETURN ATTRIBUTE_COLD
+static void
+qsort_chk_error (const void *p1, const void *p2, const void *p3,
+ int (*cmp) (const void *, const void *))
+{
+ if (!p3)
+ {
+ int r1 = cmp (p1, p2), r2 = cmp (p2, p1);
+ error ("qsort comparator not anti-commutative: %d, %d", r1, r2);
+ }
+ else if (p1 == p2)
+ {
+ int r = cmp (p1, p3);
+ error ("qsort comparator non-negative on sorted output: %d", r);
+ }
+ else
+ {
+ int r1 = cmp (p1, p2), r2 = cmp (p2, p3), r3 = cmp (p1, p3);
+ error ("qsort comparator not transitive: %d, %d, %d", r1, r2, r3);
+ }
+ internal_error ("qsort checking failed");
+}
+
+/* Wrapper around qsort with checking that CMP is consistent on given input.
+
+ Strictly speaking, passing invalid (non-transitive, non-anti-commutative)
+ comparators to libc qsort can result in undefined behavior. Therefore we
+ should ideally perform consistency checks prior to invoking qsort, but in
+ order to do that optimally we'd need to sort the array ourselves beforehand
+ with a sorting routine known to be "safe". Instead, we expect that most
+ implementations in practice will still produce some permutation of input
+ array even for invalid comparators, which enables us to perform checks on
+ the output array. */
+void
+qsort_chk (void *base, size_t n, size_t size,
+ int (*cmp)(const void *, const void *))
+{
+ (qsort) (base, n, size, cmp);
+#if 0
+#define LIM(n) (n)
+#else
+ /* Limit overall time complexity to O(n log n). */
+#define LIM(n) ((n) <= 16 ? (n) : 12 + floor_log2 (n))
+#endif
+#define ELT(i) ((const char *) base + (i) * size)
+#define CMP(i, j) cmp (ELT (i), ELT (j))
+#define ERR2(i, j) qsort_chk_error (ELT (i), ELT (j), NULL, cmp)
+#define ERR3(i, j, k) qsort_chk_error (ELT (i), ELT (j), ELT (k), cmp)
+ size_t i1, i2, i, j;
+ /* This outer loop iterates over maximum spans [i1, i2) such that
+ elements within each span compare equal to each other. */
+ for (i1 = 0; i1 < n; i1 = i2)
+ {
+ /* Position i2 one past last element that compares equal to i1'th. */
+ for (i2 = i1 + 1; i2 < n; i2++)
+ if (CMP (i1, i2))
+ break;
+ else if (CMP (i2, i1))
+ return ERR2 (i1, i2);
+ size_t lim1 = LIM (i2 - i1), lim2 = LIM (n - i2);
+ /* Verify that other pairs within current span compare equal. */
+ for (i = i1 + 1; i + 1 < i2; i++)
+ for (j = i + 1; j < i1 + lim1; j++)
+ if (CMP (i, j))
+ return ERR3 (i, i1, j);
+ else if (CMP (j, i))
+ return ERR2 (i, j);
+ /* Verify that elements within this span compare less than
+ elements beyond the span. */
+ for (i = i1; i < i2; i++)
+ for (j = i2; j < i2 + lim2; j++)
+ if (CMP (i, j) >= 0)
+ return ERR3 (i, i1, j);
+ else if (CMP (j, i) <= 0)
+ return ERR2 (i, j);
+ }
+#undef ERR3
+#undef ERR2
+#undef CMP
+#undef ELT
+#undef LIM
+}
+#endif /* #if CHECKING_P */
+
#ifndef GENERATOR_FILE
#if CHECKING_P
diff --git a/gcc/wide-int.cc b/gcc/wide-int.cc
index 71e24ec..1a1a68c 100644
--- a/gcc/wide-int.cc
+++ b/gcc/wide-int.cc
@@ -2146,6 +2146,39 @@ template void generic_wide_int <wide_int_ref_storage <true> >::dump () const;
template void offset_int::dump () const;
template void widest_int::dump () const;
+/* We could add all the above ::dump variants here, but wide_int and
+ widest_int should handle the common cases. Besides, you can always
+ call the dump method directly. */
+
+DEBUG_FUNCTION void
+debug (const wide_int &ref)
+{
+ ref.dump ();
+}
+
+DEBUG_FUNCTION void
+debug (const wide_int *ptr)
+{
+ if (ptr)
+ debug (*ptr);
+ else
+ fprintf (stderr, "<nil>\n");
+}
+
+DEBUG_FUNCTION void
+debug (const widest_int &ref)
+{
+ ref.dump ();
+}
+
+DEBUG_FUNCTION void
+debug (const widest_int *ptr)
+{
+ if (ptr)
+ debug (*ptr);
+ else
+ fprintf (stderr, "<nil>\n");
+}
#if CHECKING_P
diff --git a/gcc/wide-int.h b/gcc/wide-int.h
index 61d9aab..e17b016 100644
--- a/gcc/wide-int.h
+++ b/gcc/wide-int.h
@@ -150,15 +150,23 @@ along with GCC; see the file COPYING3. If not see
and in wider precisions.
There are constructors to create the various forms of wide_int from
- trees, rtl and constants. For trees you can simply say:
+ trees, rtl and constants. For trees the options are:
tree t = ...;
- wide_int x = t;
+ wi::to_wide (t) // Treat T as a wide_int
+ wi::to_offset (t) // Treat T as an offset_int
+ wi::to_widest (t) // Treat T as a widest_int
- However, a little more syntax is required for rtl constants since
- they do not have an explicit precision. To make an rtl into a
- wide_int, you have to pair it with a mode. The canonical way to do
- this is with rtx_mode_t as in:
+ All three are light-weight accessors that should have no overhead
+ in release builds. If it is useful for readability reasons to
+ store the result in a temporary variable, the preferred method is:
+
+ wi::tree_to_wide_ref twide = wi::to_wide (t);
+ wi::tree_to_offset_ref toffset = wi::to_offset (t);
+ wi::tree_to_widest_ref twidest = wi::to_widest (t);
+
+ To make an rtx into a wide_int, you have to pair it with a mode.
+ The canonical way to do this is with rtx_mode_t as in:
rtx r = ...
wide_int x = rtx_mode_t (r, mode);
@@ -175,23 +183,22 @@ along with GCC; see the file COPYING3. If not see
offset_int x = (int) c; // sign-extend C
widest_int x = (unsigned int) c; // zero-extend C
- It is also possible to do arithmetic directly on trees, rtxes and
+ It is also possible to do arithmetic directly on rtx_mode_ts and
constants. For example:
- wi::add (t1, t2); // add equal-sized INTEGER_CSTs t1 and t2
- wi::add (t1, 1); // add 1 to INTEGER_CST t1
- wi::add (r1, r2); // add equal-sized rtx constants r1 and r2
+ wi::add (r1, r2); // add equal-sized rtx_mode_ts r1 and r2
+ wi::add (r1, 1); // add 1 to rtx_mode_t r1
wi::lshift (1, 100); // 1 << 100 as a widest_int
Many binary operations place restrictions on the combinations of inputs,
using the following rules:
- - {tree, rtx, wide_int} op {tree, rtx, wide_int} -> wide_int
+ - {rtx, wide_int} op {rtx, wide_int} -> wide_int
The inputs must be the same precision. The result is a wide_int
of the same precision
- - {tree, rtx, wide_int} op (un)signed HOST_WIDE_INT -> wide_int
- (un)signed HOST_WIDE_INT op {tree, rtx, wide_int} -> wide_int
+ - {rtx, wide_int} op (un)signed HOST_WIDE_INT -> wide_int
+ (un)signed HOST_WIDE_INT op {rtx, wide_int} -> wide_int
The HOST_WIDE_INT is extended or truncated to the precision of
the other input. The result is a wide_int of the same precision
as that input.
@@ -262,11 +269,22 @@ along with GCC; see the file COPYING3. If not see
#define WI_BINARY_RESULT(T1, T2) \
typename wi::binary_traits <T1, T2>::result_type
+/* Likewise for binary operators, which excludes the case in which neither
+ T1 nor T2 is a wide-int-based type. */
+#define WI_BINARY_OPERATOR_RESULT(T1, T2) \
+ typename wi::binary_traits <T1, T2>::operator_result
+
/* The type of result produced by T1 << T2. Leads to substitution failure
if the operation isn't supported. Defined purely for brevity. */
#define WI_SIGNED_SHIFT_RESULT(T1, T2) \
typename wi::binary_traits <T1, T2>::signed_shift_result_type
+/* The type of result produced by a sign-agnostic binary predicate on
+ types T1 and T2. This is bool if wide-int operations make sense for
+ T1 and T2 and leads to substitution failure otherwise. */
+#define WI_BINARY_PREDICATE_RESULT(T1, T2) \
+ typename wi::binary_traits <T1, T2>::predicate_result
+
/* The type of result produced by a signed binary predicate on types T1 and T2.
This is bool if signed comparisons make sense for T1 and T2 and leads to
substitution failure otherwise. */
@@ -305,7 +323,9 @@ typedef generic_wide_int <wide_int_storage> wide_int;
typedef FIXED_WIDE_INT (ADDR_MAX_PRECISION) offset_int;
typedef FIXED_WIDE_INT (WIDE_INT_MAX_PRECISION) widest_int;
-template <bool SE>
+/* wi::storage_ref can be a reference to a primitive type,
+ so this is the conservatively-correct setting. */
+template <bool SE, bool HDP = true>
struct wide_int_ref_storage;
typedef generic_wide_int <wide_int_ref_storage <false> > wide_int_ref;
@@ -319,7 +339,8 @@ typedef generic_wide_int <wide_int_ref_storage <false> > wide_int_ref;
to use those. */
#define WIDE_INT_REF_FOR(T) \
generic_wide_int \
- <wide_int_ref_storage <wi::int_traits <T>::is_sign_extended> >
+ <wide_int_ref_storage <wi::int_traits <T>::is_sign_extended, \
+ wi::int_traits <T>::host_dependent_precision> >
namespace wi
{
@@ -382,12 +403,15 @@ namespace wi
struct binary_traits <T1, T2, FLEXIBLE_PRECISION, FLEXIBLE_PRECISION>
{
typedef widest_int result_type;
+ /* Don't define operators for this combination. */
};
template <typename T1, typename T2>
struct binary_traits <T1, T2, FLEXIBLE_PRECISION, VAR_PRECISION>
{
typedef wide_int result_type;
+ typedef result_type operator_result;
+ typedef bool predicate_result;
};
template <typename T1, typename T2>
@@ -397,6 +421,8 @@ namespace wi
so as not to confuse gengtype. */
typedef generic_wide_int < fixed_wide_int_storage
<int_traits <T2>::precision> > result_type;
+ typedef result_type operator_result;
+ typedef bool predicate_result;
typedef bool signed_predicate_result;
};
@@ -404,6 +430,8 @@ namespace wi
struct binary_traits <T1, T2, VAR_PRECISION, FLEXIBLE_PRECISION>
{
typedef wide_int result_type;
+ typedef result_type operator_result;
+ typedef bool predicate_result;
};
template <typename T1, typename T2>
@@ -413,6 +441,8 @@ namespace wi
so as not to confuse gengtype. */
typedef generic_wide_int < fixed_wide_int_storage
<int_traits <T1>::precision> > result_type;
+ typedef result_type operator_result;
+ typedef bool predicate_result;
typedef result_type signed_shift_result_type;
typedef bool signed_predicate_result;
};
@@ -420,11 +450,13 @@ namespace wi
template <typename T1, typename T2>
struct binary_traits <T1, T2, CONST_PRECISION, CONST_PRECISION>
{
+ STATIC_ASSERT (int_traits <T1>::precision == int_traits <T2>::precision);
/* Spelled out explicitly (rather than through FIXED_WIDE_INT)
so as not to confuse gengtype. */
- STATIC_ASSERT (int_traits <T1>::precision == int_traits <T2>::precision);
typedef generic_wide_int < fixed_wide_int_storage
<int_traits <T1>::precision> > result_type;
+ typedef result_type operator_result;
+ typedef bool predicate_result;
typedef result_type signed_shift_result_type;
typedef bool signed_predicate_result;
};
@@ -433,6 +465,8 @@ namespace wi
struct binary_traits <T1, T2, VAR_PRECISION, VAR_PRECISION>
{
typedef wide_int result_type;
+ typedef result_type operator_result;
+ typedef bool predicate_result;
};
}
@@ -675,18 +709,6 @@ public:
template <typename T>
generic_wide_int &operator = (const T &);
-#define BINARY_PREDICATE(OP, F) \
- template <typename T> \
- bool OP (const T &c) const { return wi::F (*this, c); }
-
-#define UNARY_OPERATOR(OP, F) \
- WI_UNARY_RESULT (generic_wide_int) OP () const { return wi::F (*this); }
-
-#define BINARY_OPERATOR(OP, F) \
- template <typename T> \
- WI_BINARY_RESULT (generic_wide_int, T) \
- OP (const T &c) const { return wi::F (*this, c); }
-
#define ASSIGNMENT_OPERATOR(OP, F) \
template <typename T> \
generic_wide_int &OP (const T &c) { return (*this = wi::F (*this, c)); }
@@ -699,18 +721,6 @@ public:
#define INCDEC_OPERATOR(OP, DELTA) \
generic_wide_int &OP () { *this += DELTA; return *this; }
- UNARY_OPERATOR (operator ~, bit_not)
- UNARY_OPERATOR (operator -, neg)
- BINARY_PREDICATE (operator ==, eq_p)
- BINARY_PREDICATE (operator !=, ne_p)
- BINARY_OPERATOR (operator &, bit_and)
- BINARY_OPERATOR (and_not, bit_and_not)
- BINARY_OPERATOR (operator |, bit_or)
- BINARY_OPERATOR (or_not, bit_or_not)
- BINARY_OPERATOR (operator ^, bit_xor)
- BINARY_OPERATOR (operator +, add)
- BINARY_OPERATOR (operator -, sub)
- BINARY_OPERATOR (operator *, mul)
ASSIGNMENT_OPERATOR (operator &=, bit_and)
ASSIGNMENT_OPERATOR (operator |=, bit_or)
ASSIGNMENT_OPERATOR (operator ^=, bit_xor)
@@ -722,9 +732,6 @@ public:
INCDEC_OPERATOR (operator ++, 1)
INCDEC_OPERATOR (operator --, -1)
-#undef BINARY_PREDICATE
-#undef UNARY_OPERATOR
-#undef BINARY_OPERATOR
#undef SHIFT_ASSIGNMENT_OPERATOR
#undef ASSIGNMENT_OPERATOR
#undef INCDEC_OPERATOR
@@ -932,7 +939,7 @@ decompose (HOST_WIDE_INT *, unsigned int precision,
/* Provide the storage for a wide_int_ref. This acts like a read-only
wide_int, with the optimization that VAL is normally a pointer to
another integer's storage, so that no array copy is needed. */
-template <bool SE>
+template <bool SE, bool HDP>
struct wide_int_ref_storage : public wi::storage_ref
{
private:
@@ -951,8 +958,8 @@ public:
};
/* Create a reference from an existing reference. */
-template <bool SE>
-inline wide_int_ref_storage <SE>::
+template <bool SE, bool HDP>
+inline wide_int_ref_storage <SE, HDP>::
wide_int_ref_storage (const wi::storage_ref &x)
: storage_ref (x)
{}
@@ -960,32 +967,30 @@ wide_int_ref_storage (const wi::storage_ref &x)
/* Create a reference to integer X in its natural precision. Note
that the natural precision is host-dependent for primitive
types. */
-template <bool SE>
+template <bool SE, bool HDP>
template <typename T>
-inline wide_int_ref_storage <SE>::wide_int_ref_storage (const T &x)
+inline wide_int_ref_storage <SE, HDP>::wide_int_ref_storage (const T &x)
: storage_ref (wi::int_traits <T>::decompose (scratch,
wi::get_precision (x), x))
{
}
/* Create a reference to integer X in precision PRECISION. */
-template <bool SE>
+template <bool SE, bool HDP>
template <typename T>
-inline wide_int_ref_storage <SE>::wide_int_ref_storage (const T &x,
- unsigned int precision)
+inline wide_int_ref_storage <SE, HDP>::
+wide_int_ref_storage (const T &x, unsigned int precision)
: storage_ref (wi::int_traits <T>::decompose (scratch, precision, x))
{
}
namespace wi
{
- template <bool SE>
- struct int_traits <wide_int_ref_storage <SE> >
+ template <bool SE, bool HDP>
+ struct int_traits <wide_int_ref_storage <SE, HDP> >
{
static const enum precision_type precision_type = VAR_PRECISION;
- /* wi::storage_ref can be a reference to a primitive type,
- so this is the conservatively-correct setting. */
- static const bool host_dependent_precision = true;
+ static const bool host_dependent_precision = HDP;
static const bool is_sign_extended = SE;
};
}
@@ -3123,6 +3128,45 @@ SIGNED_BINARY_PREDICATE (operator >=, ges_p)
#undef SIGNED_BINARY_PREDICATE
+#define UNARY_OPERATOR(OP, F) \
+ template<typename T> \
+ WI_UNARY_RESULT (generic_wide_int<T>) \
+ OP (const generic_wide_int<T> &x) \
+ { \
+ return wi::F (x); \
+ }
+
+#define BINARY_PREDICATE(OP, F) \
+ template<typename T1, typename T2> \
+ WI_BINARY_PREDICATE_RESULT (T1, T2) \
+ OP (const T1 &x, const T2 &y) \
+ { \
+ return wi::F (x, y); \
+ }
+
+#define BINARY_OPERATOR(OP, F) \
+ template<typename T1, typename T2> \
+ WI_BINARY_OPERATOR_RESULT (T1, T2) \
+ OP (const T1 &x, const T2 &y) \
+ { \
+ return wi::F (x, y); \
+ }
+
+UNARY_OPERATOR (operator ~, bit_not)
+UNARY_OPERATOR (operator -, neg)
+BINARY_PREDICATE (operator ==, eq_p)
+BINARY_PREDICATE (operator !=, ne_p)
+BINARY_OPERATOR (operator &, bit_and)
+BINARY_OPERATOR (operator |, bit_or)
+BINARY_OPERATOR (operator ^, bit_xor)
+BINARY_OPERATOR (operator +, add)
+BINARY_OPERATOR (operator -, sub)
+BINARY_OPERATOR (operator *, mul)
+
+#undef UNARY_OPERATOR
+#undef BINARY_PREDICATE
+#undef BINARY_OPERATOR
+
template <typename T1, typename T2>
inline WI_SIGNED_SHIFT_RESULT (T1, T2)
operator << (const T1 &x, const T2 &y)
diff --git a/include/ChangeLog b/include/ChangeLog
index 0221586..8ccc57a 100644
--- a/include/ChangeLog
+++ b/include/ChangeLog
@@ -1,3 +1,13 @@
+2017-10-23 David Malcolm <dmalcolm@redhat.com>
+
+ * unique-ptr.h: Make include of <memory> conditional on C++11 or
+ later.
+
+2017-10-16 Trevor Saunders <tbsaunde+gcc@tbsaunde.org>
+ David Malcolm <dmalcolm@redhat.com>
+
+ * unique-ptr.h: New file.
+
2017-09-15 Yao Qi <yao.qi@linaro.org>
Pedro Alves <palves@redhat.com>
diff --git a/include/unique-ptr.h b/include/unique-ptr.h
new file mode 100644
index 0000000..0b6f11a
--- /dev/null
+++ b/include/unique-ptr.h
@@ -0,0 +1,405 @@
+/* gnu::unique_ptr, a simple std::unique_ptr replacement for C++03.
+
+ Copyright (C) 2007-2016 Free Software Foundation, Inc.
+
+ This file is part of GCC.
+
+ 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, see <http://www.gnu.org/licenses/>. */
+
+/* gnu::unique_ptr defines a C++ owning smart pointer that exposes a
+ subset of the std::unique_ptr API.
+
+ In fact, when compiled with a C++11 compiler, gnu::unique_ptr
+ actually _is_ std::unique_ptr. When compiled with a C++03 compiler
+ OTOH, it's an hand coded std::unique_ptr emulation that assumes
+ code is correct and doesn't try to be too smart.
+
+ This supports custom deleters, but not _stateful_ deleters, so you
+ can't use those in C++11 mode either. Only the managed pointer is
+ stored in the smart pointer. That could be changed; it simply
+ wasn't found necessary.
+
+ At the end of the file you'll find a gnu::unique_ptr partial
+ specialization that uses a custom (stateless) deleter:
+ gnu::unique_xmalloc_ptr. That is used to manage pointers to
+ objects allocated with xmalloc.
+
+ The C++03 version was originally based on GCC 7.0's std::auto_ptr
+ and then heavily customized to behave more like C++11's
+ std::unique_ptr, but at this point, it no longer shares much at all
+ with the original file. But, that's the history and the reason for
+ the copyright's starting year.
+
+ The C++03 version lets you shoot yourself in the foot, since
+ similarly to std::auto_ptr, the copy constructor and assignment
+ operators actually move. Also, in the name of simplicity, no
+ effort is spent on using SFINAE to prevent invalid conversions,
+ etc. This is not really a problem, because the goal here is to
+ allow code that would be correct using std::unique_ptr to be
+ equally correct in C++03 mode, and, just as efficient. If client
+ code compiles correctly with a C++11 (or newer) compiler, we know
+ we're not doing anything invalid by mistake.
+
+ Usage notes:
+
+ - Putting gnu::unique_ptr in standard containers is not supported,
+ since C++03 containers are not move-aware (and our emulation
+ relies on copy actually moving).
+
+ - Since there's no nullptr in C++03, gnu::unique_ptr allows
+ implicit initialization and assignment from NULL instead.
+
+ - To check whether there's an associated managed object, all these
+ work as expected:
+
+ if (ptr)
+ if (!ptr)
+ if (ptr != NULL)
+ if (ptr == NULL)
+ if (NULL != ptr)
+ if (NULL == ptr)
+*/
+
+#ifndef GNU_UNIQUE_PTR_H
+#define GNU_UNIQUE_PTR_H 1
+
+#if __cplusplus >= 201103
+# include <memory>
+#endif
+
+namespace gnu
+{
+
+#if __cplusplus >= 201103
+
+/* In C++11 mode, all we need is import the standard
+ std::unique_ptr. */
+template<typename T> using unique_ptr = std::unique_ptr<T>;
+
+/* Pull in move as well. */
+using std::move;
+
+#else /* C++11 */
+
+/* Default destruction policy used by gnu::unique_ptr when no deleter
+ is specified. Uses delete. */
+
+template<typename T>
+struct default_delete
+{
+ void operator () (T *ptr) const { delete ptr; }
+};
+
+/* Specialization for arrays. Uses delete[]. */
+
+template<typename T>
+struct default_delete<T[]>
+{
+ void operator () (T *ptr) const { delete [] ptr; }
+};
+
+namespace detail
+{
+/* Type used to support implicit construction from NULL:
+
+ gnu::unique_ptr<foo> func (....)
+ {
+ return NULL;
+ }
+
+ and assignment from NULL:
+
+ gnu::unique_ptr<foo> ptr (....);
+ ...
+ ptr = NULL;
+
+ It is intentionally not defined anywhere. */
+struct nullptr_t;
+
+/* Base class of our unique_ptr emulation. Contains code common to
+ both unique_ptr<T, D> and unique_ptr<T[], D>. */
+
+template<typename T, typename D>
+class unique_ptr_base
+{
+public:
+ typedef T *pointer;
+ typedef T element_type;
+ typedef D deleter_type;
+
+ /* Takes ownership of a pointer. P is a pointer to an object of
+ element_type type. Defaults to NULL. */
+ explicit unique_ptr_base (element_type *p = NULL) throw () : m_ptr (p) {}
+
+ /* The "move" constructor. Really a copy constructor that actually
+ moves. Even though std::unique_ptr is not copyable, our little
+ simpler emulation allows it, because:
+
+ - There are no rvalue references in C++03. Our move emulation
+ instead relies on copy/assignment moving, like std::auto_ptr.
+ - RVO/NRVO requires an accessible copy constructor
+ */
+ unique_ptr_base (const unique_ptr_base &other) throw ()
+ : m_ptr (const_cast<unique_ptr_base &> (other).release ()) {}
+
+ /* Converting "move" constructor. Really an lvalue ref converting
+ constructor that actually moves. This allows constructs such as:
+
+ unique_ptr<Derived> func_returning_unique_ptr (.....);
+ ...
+ unique_ptr<Base> ptr = func_returning_unique_ptr (.....);
+ */
+ template<typename T1, typename D1>
+ unique_ptr_base (const unique_ptr_base<T1, D1> &other) throw ()
+ : m_ptr (const_cast<unique_ptr_base<T1, D1> &> (other).release ()) {}
+
+ /* The "move" assignment operator. Really an lvalue ref copy
+ assignment operator that actually moves. See comments above. */
+ unique_ptr_base &operator= (const unique_ptr_base &other) throw ()
+ {
+ reset (const_cast<unique_ptr_base &> (other).release ());
+ return *this;
+ }
+
+ /* Converting "move" assignment. Really an lvalue ref converting
+ copy assignment operator that moves. See comments above. */
+ template<typename T1, typename D1>
+ unique_ptr_base &operator= (const unique_ptr_base<T1, D1> &other) throw ()
+ {
+ reset (const_cast<unique_ptr_base<T1, D1> &> (other).release ());
+ return *this;
+ }
+
+ /* std::unique_ptr does not allow assignment, except from nullptr.
+ nullptr doesn't exist in C++03, so we allow assignment from NULL
+ instead [ptr = NULL;].
+ */
+ unique_ptr_base &operator= (detail::nullptr_t *) throw ()
+ {
+ reset ();
+ return *this;
+ }
+
+ ~unique_ptr_base () { call_deleter (); }
+
+ /* "explicit operator bool ()" emulation using the safe bool
+ idiom. */
+private:
+ typedef void (unique_ptr_base::*explicit_operator_bool) () const;
+ void this_type_does_not_support_comparisons () const {}
+
+public:
+ operator explicit_operator_bool () const
+ {
+ return (m_ptr != NULL
+ ? &unique_ptr_base::this_type_does_not_support_comparisons
+ : 0);
+ }
+
+ element_type *get () const throw () { return m_ptr; }
+
+ element_type *release () throw ()
+ {
+ pointer tmp = m_ptr;
+ m_ptr = NULL;
+ return tmp;
+ }
+
+ void reset (element_type *p = NULL) throw ()
+ {
+ if (p != m_ptr)
+ {
+ call_deleter ();
+ m_ptr = p;
+ }
+ }
+
+private:
+
+ /* Call the deleter. Note we assume the deleter is "stateless". */
+ void call_deleter ()
+ {
+ D d;
+
+ d (m_ptr);
+ }
+
+ element_type *m_ptr;
+};
+
+} /* namespace detail */
+
+/* Macro used to create a unique_ptr_base "partial specialization" --
+ a subclass that uses a specific deleter. Basically this re-defines
+ the necessary constructors. This is necessary because C++03
+ doesn't support inheriting constructors with "using". While at it,
+ we inherit the assignment operator. TYPE is the name of the type
+ being defined. Assumes that 'base_type' is a typedef of the
+ baseclass TYPE is inheriting from. */
+#define DEFINE_GNU_UNIQUE_PTR(TYPE) \
+public: \
+ explicit TYPE (T *p = NULL) throw () \
+ : base_type (p) {} \
+ \
+ TYPE (const TYPE &other) throw () : base_type (other) {} \
+ \
+ TYPE (detail::nullptr_t *) throw () : base_type (NULL) {} \
+ \
+ template<typename T1, typename D1> \
+ TYPE (const detail::unique_ptr_base<T1, D1> &other) throw () \
+ : base_type (other) {} \
+ \
+ using base_type::operator=;
+
+/* Define single-object gnu::unique_ptr. */
+
+template <typename T, typename D = default_delete<T> >
+class unique_ptr : public detail::unique_ptr_base<T, D>
+{
+ typedef detail::unique_ptr_base<T, D> base_type;
+
+ DEFINE_GNU_UNIQUE_PTR (unique_ptr)
+
+public:
+ /* Dereferencing. */
+ T &operator* () const throw () { return *this->get (); }
+ T *operator-> () const throw () { return this->get (); }
+};
+
+/* Define gnu::unique_ptr specialization for T[]. */
+
+template <typename T, typename D>
+class unique_ptr<T[], D> : public detail::unique_ptr_base<T, D>
+{
+ typedef detail::unique_ptr_base<T, D> base_type;
+
+ DEFINE_GNU_UNIQUE_PTR (unique_ptr)
+
+public:
+ /* Indexing operator. */
+ T &operator[] (size_t i) const { return this->get ()[i]; }
+};
+
+/* Comparison operators. */
+
+template <typename T, typename D,
+ typename U, typename E>
+inline bool
+operator== (const detail::unique_ptr_base<T, D> &x,
+ const detail::unique_ptr_base<U, E> &y)
+{ return x.get() == y.get(); }
+
+template <typename T, typename D,
+ typename U, typename E>
+inline bool
+operator!= (const detail::unique_ptr_base<T, D> &x,
+ const detail::unique_ptr_base<U, E> &y)
+{ return x.get() != y.get(); }
+
+template<typename T, typename D,
+ typename U, typename E>
+inline bool
+operator< (const detail::unique_ptr_base<T, D> &x,
+ const detail::unique_ptr_base<U, E> &y)
+{ return x.get() < y.get (); }
+
+template<typename T, typename D,
+ typename U, typename E>
+inline bool
+operator<= (const detail::unique_ptr_base<T, D> &x,
+ const detail::unique_ptr_base<U, E> &y)
+{ return !(y < x); }
+
+template<typename T, typename D,
+ typename U, typename E>
+inline bool
+operator> (const detail::unique_ptr_base<T, D> &x,
+ const detail::unique_ptr_base<U, E> &y)
+{ return y < x; }
+
+template<typename T, typename D,
+ typename U, typename E>
+inline bool
+operator>= (const detail::unique_ptr_base<T, D> &x,
+ const detail::unique_ptr_base<U, E> &y)
+{ return !(x < y); }
+
+/* std::move "emulation". This is as simple as it can be -- no
+ attempt is made to emulate rvalue references. Instead relies on
+ the fact that gnu::unique_ptr has move semantics like
+ std::auto_ptr. I.e., copy/assignment actually moves. */
+
+template<typename T, typename D>
+unique_ptr<T, D>
+move (unique_ptr<T, D> v)
+{
+ return v;
+}
+
+#endif /* C++11 */
+
+/* Define gnu::unique_xmalloc_ptr, a gnu::unique_ptr that manages
+ xmalloc'ed memory. */
+
+/* The deleter for gnu::unique_xmalloc_ptr. Uses free. */
+template <typename T>
+struct xmalloc_deleter
+{
+ void operator() (T *ptr) const { free (ptr); }
+};
+
+/* Same, for arrays. */
+template <typename T>
+struct xmalloc_deleter<T[]>
+{
+ void operator() (T *ptr) const { free (ptr); }
+};
+
+#if __cplusplus >= 201103
+
+/* In C++11, we just import the standard unique_ptr to our namespace
+ with a custom deleter. */
+
+template<typename T> using unique_xmalloc_ptr
+ = std::unique_ptr<T, xmalloc_deleter<T>>;
+
+#else /* C++11 */
+
+/* In C++03, we don't have template aliases, so we need to define a
+ subclass instead, and re-define the constructors, because C++03
+ doesn't support inheriting constructors either. */
+
+template <typename T>
+class unique_xmalloc_ptr : public unique_ptr<T, xmalloc_deleter<T> >
+{
+ typedef unique_ptr<T, xmalloc_deleter<T> > base_type;
+
+ DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr)
+};
+
+/* Define gnu::unique_xmalloc_ptr specialization for T[]. */
+
+template <typename T>
+class unique_xmalloc_ptr<T[]> : public unique_ptr<T[], xmalloc_deleter<T[]> >
+{
+ typedef unique_ptr<T[], xmalloc_deleter<T[]> > base_type;
+
+ DEFINE_GNU_UNIQUE_PTR (unique_xmalloc_ptr)
+};
+
+#endif /* C++11 */
+
+} /* namespace gnu */
+
+#endif /* GNU_UNIQUE_PTR_H */
diff --git a/libatomic/ChangeLog b/libatomic/ChangeLog
index 9e11b23..eed12e6 100644
--- a/libatomic/ChangeLog
+++ b/libatomic/ChangeLog
@@ -1,3 +1,18 @@
+2017-10-20 Richard Earnshaw <rearnsha@arm.com>
+
+ * Makefile.am: (IFUNC_OPTIONS): Set the architecture to
+ -march=armv7-a+fp on Linux/Arm.
+ * Makefile.in: Regenerated.
+
+2017-10-02 Martin Sebor <msebor@redhat.com>
+
+ PR c/81854
+ * acinclude.m4 (LIBAT_CHECK_IFUNC): Have ifunc resolver return
+ a function pointer rather than void* to avoid GCC 8 warnings.
+ * configure: Regenerate.
+ * libatomic_i.h: Declare ifunc resolvers to return function
+ pointers rather than void*.
+
2017-05-12 Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
* testsuite/lib/libatomic.exp: Load scanlang.exp.
diff --git a/libatomic/Makefile.am b/libatomic/Makefile.am
index d731406..9c45700 100644
--- a/libatomic/Makefile.am
+++ b/libatomic/Makefile.am
@@ -123,7 +123,7 @@ libatomic_la_LIBADD = $(foreach s,$(SIZES),$(addsuffix _$(s)_.lo,$(SIZEOBJS)))
## On a target-specific basis, include alternates to be selected by IFUNC.
if HAVE_IFUNC
if ARCH_ARM_LINUX
-IFUNC_OPTIONS = -march=armv7-a -DHAVE_KERNEL64
+IFUNC_OPTIONS = -march=armv7-a+fp -DHAVE_KERNEL64
libatomic_la_LIBADD += $(foreach s,$(SIZES),$(addsuffix _$(s)_1_.lo,$(SIZEOBJS)))
libatomic_la_LIBADD += $(addsuffix _8_2_.lo,$(SIZEOBJS))
endif
diff --git a/libatomic/Makefile.in b/libatomic/Makefile.in
index f6eeab3..0f0382e 100644
--- a/libatomic/Makefile.in
+++ b/libatomic/Makefile.in
@@ -346,7 +346,7 @@ M_SRC = $(firstword $(filter %/$(M_FILE), $(all_c_files)))
libatomic_la_LIBADD = $(foreach s,$(SIZES),$(addsuffix \
_$(s)_.lo,$(SIZEOBJS))) $(am__append_1) $(am__append_2) \
$(am__append_3)
-@ARCH_ARM_LINUX_TRUE@@HAVE_IFUNC_TRUE@IFUNC_OPTIONS = -march=armv7-a -DHAVE_KERNEL64
+@ARCH_ARM_LINUX_TRUE@@HAVE_IFUNC_TRUE@IFUNC_OPTIONS = -march=armv7-a+fp -DHAVE_KERNEL64
@ARCH_I386_TRUE@@HAVE_IFUNC_TRUE@IFUNC_OPTIONS = -march=i586
@ARCH_X86_64_TRUE@@HAVE_IFUNC_TRUE@IFUNC_OPTIONS = -mcx16
libatomic_convenience_la_SOURCES = $(libatomic_la_SOURCES)
diff --git a/libatomic/acinclude.m4 b/libatomic/acinclude.m4
index 485d731..383218f 100644
--- a/libatomic/acinclude.m4
+++ b/libatomic/acinclude.m4
@@ -195,7 +195,8 @@ AC_DEFUN([LIBAT_CHECK_IFUNC], [
CFLAGS="$CFLAGS -Werror"
AC_TRY_LINK([
int foo_alt(void) { return 0; }
- void *foo_sel(void) { return foo_alt; }
+ typedef int F (void);
+ F *foo_sel(void) { return foo_alt; }
int foo(void) __attribute__((ifunc("foo_sel")));],
[return foo();], libat_cv_have_ifunc=yes, libat_cv_have_ifunc=no)])
LIBAT_DEFINE_YESNO([HAVE_IFUNC], [$libat_cv_have_ifunc],
diff --git a/libatomic/configure b/libatomic/configure
index c05fc9d..e88a7b8 100755
--- a/libatomic/configure
+++ b/libatomic/configure
@@ -12333,6 +12333,7 @@ _ACEOF
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic_load/store for size 2" >&5
$as_echo_n "checking for __atomic_load/store for size 2... " >&6; }
if test "${libat_cv_have_at_ldst_2+set}" = set; then :
@@ -12400,6 +12401,7 @@ _ACEOF
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic_load/store for size 4" >&5
$as_echo_n "checking for __atomic_load/store for size 4... " >&6; }
if test "${libat_cv_have_at_ldst_4+set}" = set; then :
@@ -12467,6 +12469,7 @@ _ACEOF
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic_load/store for size 8" >&5
$as_echo_n "checking for __atomic_load/store for size 8... " >&6; }
if test "${libat_cv_have_at_ldst_8+set}" = set; then :
@@ -12534,6 +12537,7 @@ _ACEOF
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic_load/store for size 16" >&5
$as_echo_n "checking for __atomic_load/store for size 16... " >&6; }
if test "${libat_cv_have_at_ldst_16+set}" = set; then :
@@ -12602,6 +12606,7 @@ _ACEOF
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for __atomic_test_and_set for size 1" >&5
$as_echo_n "checking for __atomic_test_and_set for size 1... " >&6; }
if test "${libat_cv_have_at_tas_1+set}" = set; then :
@@ -14693,7 +14698,8 @@ else
/* end confdefs.h. */
int foo_alt(void) { return 0; }
- void *foo_sel(void) { return foo_alt; }
+ typedef int F (void);
+ F *foo_sel(void) { return foo_alt; }
int foo(void) __attribute__((ifunc("foo_sel")));
int
main ()
diff --git a/libatomic/libatomic_i.h b/libatomic/libatomic_i.h
index 4eb372a..2dad4a8 100644
--- a/libatomic/libatomic_i.h
+++ b/libatomic/libatomic_i.h
@@ -240,7 +240,7 @@ bool libat_is_lock_free (size_t, void *) MAN(is_lock_free);
# if IFUNC_NCOND(N) == 1
# define GEN_SELECTOR(X) \
extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \
- static void * C2(select_,X) (void) \
+ static typeof(C2(libat_,X)) * C2(select_,X) (void) \
{ \
if (IFUNC_COND_1) \
return C3(libat_,X,_i1); \
@@ -250,7 +250,7 @@ bool libat_is_lock_free (size_t, void *) MAN(is_lock_free);
# define GEN_SELECTOR(X) \
extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \
extern typeof(C2(libat_,X)) C3(libat_,X,_i2) HIDDEN; \
- static void * C2(select_,X) (void) \
+ static typeof(C2(libat_,X)) * C2(select_,X) (void) \
{ \
if (IFUNC_COND_1) \
return C3(libat_,X,_i1); \
@@ -263,7 +263,7 @@ bool libat_is_lock_free (size_t, void *) MAN(is_lock_free);
extern typeof(C2(libat_,X)) C3(libat_,X,_i1) HIDDEN; \
extern typeof(C2(libat_,X)) C3(libat_,X,_i2) HIDDEN; \
extern typeof(C2(libat_,X)) C3(libat_,X,_i3) HIDDEN; \
- static void * C2(select_,X) (void) \
+ static typeof(C2(libat_,X)) * C2(select_,X) (void) \
{ \
if (IFUNC_COND_1) \
return C3(libat_,X,_i1); \
diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog
index f3b7486..5540530 100644
--- a/libbacktrace/ChangeLog
+++ b/libbacktrace/ChangeLog
@@ -1,3 +1,141 @@
+2017-10-06 Ian Lance Taylor <iant@golang.org>
+
+ * ztest.c (test_large): Pass unsigned long *, not size_t *, to
+ zlib uncompress function.
+
+2017-10-05 Ian Lance Taylor <iant@golang.org>
+
+ * elf.c (elf_zlib_fetch): Change pval argument to uint64_t *.
+ Read a four byte integer.
+ (elf_zlib_inflate): Change val to uint64_t. Align pin to a 32-bit
+ boundary before ever calling elf_zlib_fetch.
+ * ztest.c (test_large): Simplify print statements a bit.
+
+2017-10-02 Ian Lance Taylor <iant@golang.org>
+
+ * ztest.c: #include <errno.h>.
+ (TEST_TIMING): Don't define, don't test.
+ (xclock_gettime, xclockid_t): Define if !HAVE_CLOCK_GETTIME.
+ (clockid_t, clock_gettime, CLOCK_REALTIME): Likewise.
+ (ZLIB_CLOCK_GETTIME_ARG): Define.
+ * configure.ac: Change clock_gettime_link to CLOCK_GETTIME_LINK.
+ * Makefile.am: Likewise.
+ * configure, Makefile.in: Rebuild.
+
+2017-10-02 Thomas Schwinge <thomas@codesourcery.com>
+
+ PR other/67165
+ * Makefile.am: Append the content of clock_gettime_link to
+ ztest_LDADD.
+ * configure.ac: Test for the case that clock_gettime is in librt.
+ * Makefile.in: Regenerate.
+ * configure: Likewise.
+
+ PR other/67165
+ * configure.ac: Check for clock_gettime.
+ * config.h.in: Regenerate.
+ * configure: Likewise.
+ * ztest.c (average_time, test_large): Conditionalize test timing
+ on clock_gettime availability.
+
+2017-09-29 Tony Reix <tony.reix@atos.net>
+
+ * xcoff.c: Initial support for DWARF debug sections in XCOFF.
+ (STYP_DWARF, SSUBTYP_DW*): Define.
+ (enum dwarf_section): Define.
+ (struct dwsect_info): Define.
+ (xcoff_add): Look for DWARF sections, pass them to
+ backtrace_dwarf_add.
+
+2017-09-28 Ian Lance Taylor <iant@golang.org>
+
+ PR other/67165
+ * elf.c (__builtin_prefetch): Define if not __GNUC__.
+ (unlikely): Define.
+ (SHF_UNCOMPRESSED, ELFCOMPRESS_ZLIB): Define.
+ (b_elf_chdr): Define type.
+ (enum debug_section): Add ZDEBUG_xxx values.
+ (debug_section_names): Add names for new sections.
+ (struct debug_section_info): Add compressed field.
+ (elf_zlib_failed, elf_zlib_fetch): New static functions.
+ (HUFFMAN_TABLE_SIZE, HUFFMAN_VALUE_MASK): Define.
+ (HUFFMAN_BITS_SHIFT, HUFFMAN_BITS_MASK): Define.
+ (HUFFMAN_SECONDARY_SHIFT): Define.
+ (ZDEBUG_TABLE_SIZE): Define.
+ (ZDEBUG_TABLE_CODELEN_OFFSET, ZDEBUG_TABLE_WORK_OFFSET): Define.
+ (final_next_secondary): New static variable if
+ BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE.
+ (elf_zlib_inflate_table): New static function.
+ (BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE): If define, define main
+ function to produce fixed Huffman table.
+ (elf_zlib_default_table): New static variable.
+ (elf_zlib_inflate): New static function.
+ (elf_zlib_verify_checksum): Likewise.
+ (elf_zlib_inflate_and_verify): Likewise.
+ (elf_uncompress_zdebug): Likewise.
+ (elf_uncompress_chdr): Likewise.
+ (backtrace_uncompress_zdebug): New extern function.
+ (elf_add): Look for .zdebug sections and SHF_COMPRESSED debug
+ sections, and uncompress them.
+ * internal.h (backtrace_compress_zdebug): Declare.
+ * ztest.c: New file.
+ * configure.ac: Check for -lz and check whether the linker
+ supports --compress-debug-sections.
+ * Makefile.am (ztest_SOURCES): New variable.
+ (ztest_CFLAGS, ztest_LDADD): New variables.
+ (check_PROGRAMS): Add ztest.
+ (ctestg_SOURCES): New variable.
+ (ctestg_CFLAGS, ctestg_LDFLAGS, ctestg_LDADD): New variables.
+ (ctesta_SOURCES): New variable.
+ (ctesta_CFLAGS, ctesta_LDFLAGS, ctesta_LDADD): New variables.
+ (check_PROGRAMS): Add ctestg and ctesta.
+ * configure, config.h.in, Makefile.in: Rebuild.
+
+2017-09-22 Ian Lance Taylor <iant@golang.org>
+
+ PR sanitizer/77631
+ * configure.ac: Check for lstat and readlink.
+ * elf.c (lstat, readlink): Provide dummy versions if real versions
+ are not available.
+ * configure, config.h.in: Rebuild.
+
+2017-09-21 Ian Lance Taylor <iant@google.com>
+
+ PR go/82284
+ * elf.c (backtrace_initialize): Set pd.exe_filename.
+
+2017-09-20 Ian Lance Taylor <iant@golang.org>
+ Denis Khalikov <d.khalikov@partner.samsung.com>
+
+ PR sanitizer/77631
+ Support for external debug info.
+ * elf.c: Include <errno.h>, <sys/stat.h>, <unistd.h>.
+ (S_ISLNK): Define if not defined.
+ (xstrnlen): Define if strnlen is not available.
+ (b_elf_note): Define type.
+ (NT_GNU_BUILD_ID): Define macro.
+ (elf_crc32, elf_crc32_file): New static functions.
+ (elf_is_symlink, elf_readlink): New static functions.
+ (elf_open_debugfile_by_buildid): New static function.
+ (elf_try_debugfile): New static function.
+ (elf_find_debugfile_by_debuglink): New static function.
+ (elf_open_debugfile_by_debuglink): New static function.
+ (elf_add): Add filename and debuginfo parameters. Adjust all
+ callers. Look for external debug info notes, and try to fetch
+ debug info from external file.
+ (struct phdr_data): Add exe_filename field.
+ (phdr_callback): Pass filename to elf_add.
+ (backtrace_initialize): Add filename parameter.
+ * internal.h (backtrace_initialize): Add filename parameter.
+ * fileline.c (fileline_initialize): Pass filename to
+ backtrace_initialize.
+ * pecoff.c (fileline_initialize): Add unused filename parameter.
+ * unknown.c (fileline_initialize): Likewise.
+ * xcoff.c (fileline_initialize): Likewise.
+ * configure.ac: Check for objcopy --add-gnu-debuglink.
+ * Makefile.am (dtest): New test target.
+ * configure, Makefile.in: Rebuild.
+
2017-09-12 Steve Ellcey <sellcey@cavium.com>
PR other/81096
diff --git a/libbacktrace/Makefile.am b/libbacktrace/Makefile.am
index 120beb1..7c0fab1 100644
--- a/libbacktrace/Makefile.am
+++ b/libbacktrace/Makefile.am
@@ -101,6 +101,17 @@ stest_LDADD = libbacktrace.la
check_PROGRAMS += stest
+ztest_SOURCES = ztest.c testlib.c
+ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
+ztest_LDADD = libbacktrace.la
+
+if HAVE_ZLIB
+ztest_LDADD += -lz
+endif
+ztest_LDADD += $(CLOCK_GETTIME_LINK)
+
+check_PROGRAMS += ztest
+
edtest_SOURCES = edtest.c edtest2_build.c testlib.c
edtest_LDADD = libbacktrace.la
@@ -122,6 +133,32 @@ ttest_LDADD = libbacktrace.la
endif HAVE_PTHREAD
+if HAVE_OBJCOPY_DEBUGLINK
+
+TESTS += dtest
+
+dtest: btest
+ $(OBJCOPY) --only-keep-debug btest btest.debug
+ $(OBJCOPY) --strip-debug --add-gnu-debuglink=btest.debug btest dtest
+
+endif HAVE_OBJCOPY_DEBUGLINK
+
+if HAVE_COMPRESSED_DEBUG
+
+ctestg_SOURCES = btest.c testlib.c
+ctestg_CFLAGS = $(AM_CFLAGS) -g
+ctestg_LDFLAGS = -Wl,--compress-debug-sections=zlib-gnu
+ctestg_LDADD = libbacktrace.la
+
+ctesta_SOURCES = btest.c testlib.c
+ctesta_CFLAGS = $(AM_CFLAGS) -g
+ctesta_LDFLAGS = -Wl,--compress-debug-sections=zlib-gabi
+ctesta_LDADD = libbacktrace.la
+
+check_PROGRAMS += ctestg ctesta
+
+endif
+
endif NATIVE
# We can't use automake's automatic dependency tracking, because it
diff --git a/libbacktrace/Makefile.in b/libbacktrace/Makefile.in
index 2d8c212..407098a 100644
--- a/libbacktrace/Makefile.in
+++ b/libbacktrace/Makefile.in
@@ -83,9 +83,12 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
target_triplet = @target@
-check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2)
-@NATIVE_TRUE@am__append_1 = btest stest edtest
-@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_2 = ttest
+check_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
+@NATIVE_TRUE@am__append_1 = btest stest ztest edtest
+@HAVE_ZLIB_TRUE@@NATIVE_TRUE@am__append_2 = -lz
+@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__append_3 = ttest
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@am__append_4 = dtest
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__append_5 = ctestg ctesta
subdir = .
DIST_COMMON = README ChangeLog $(srcdir)/Makefile.in \
$(srcdir)/Makefile.am $(top_srcdir)/configure \
@@ -115,8 +118,11 @@ am_libbacktrace_la_OBJECTS = atomic.lo dwarf.lo fileline.lo posix.lo \
print.lo sort.lo state.lo
libbacktrace_la_OBJECTS = $(am_libbacktrace_la_OBJECTS)
@NATIVE_TRUE@am__EXEEXT_1 = btest$(EXEEXT) stest$(EXEEXT) \
-@NATIVE_TRUE@ edtest$(EXEEXT)
+@NATIVE_TRUE@ ztest$(EXEEXT) edtest$(EXEEXT)
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@am__EXEEXT_2 = ttest$(EXEEXT)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am__EXEEXT_3 = \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctestg$(EXEEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta$(EXEEXT)
@NATIVE_TRUE@am_btest_OBJECTS = btest-btest.$(OBJEXT) \
@NATIVE_TRUE@ btest-testlib.$(OBJEXT)
btest_OBJECTS = $(am_btest_OBJECTS)
@@ -124,6 +130,22 @@ btest_OBJECTS = $(am_btest_OBJECTS)
btest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(btest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctesta_OBJECTS = ctesta-btest.$(OBJEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctesta-testlib.$(OBJEXT)
+ctesta_OBJECTS = $(am_ctesta_OBJECTS)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_DEPENDENCIES = \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ libbacktrace.la
+ctesta_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(ctesta_CFLAGS) $(CFLAGS) \
+ $(ctesta_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@am_ctestg_OBJECTS = ctestg-btest.$(OBJEXT) \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ ctestg-testlib.$(OBJEXT)
+ctestg_OBJECTS = $(am_ctestg_OBJECTS)
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_DEPENDENCIES = \
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ libbacktrace.la
+ctestg_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(ctestg_CFLAGS) $(CFLAGS) \
+ $(ctestg_LDFLAGS) $(LDFLAGS) -o $@
@NATIVE_TRUE@am_edtest_OBJECTS = edtest.$(OBJEXT) \
@NATIVE_TRUE@ edtest2_build.$(OBJEXT) testlib.$(OBJEXT)
edtest_OBJECTS = $(am_edtest_OBJECTS)
@@ -139,6 +161,14 @@ ttest_OBJECTS = $(am_ttest_OBJECTS)
ttest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(ttest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
+@NATIVE_TRUE@am_ztest_OBJECTS = ztest-ztest.$(OBJEXT) \
+@NATIVE_TRUE@ ztest-testlib.$(OBJEXT)
+ztest_OBJECTS = $(am_ztest_OBJECTS)
+@NATIVE_TRUE@ztest_DEPENDENCIES = libbacktrace.la \
+@NATIVE_TRUE@ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+ztest_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
+ --mode=link $(CCLD) $(ztest_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
+ $(LDFLAGS) -o $@
DEFAULT_INCLUDES = -I.@am__isrc@
depcomp =
am__depfiles_maybe =
@@ -152,8 +182,9 @@ LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) \
--mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(AM_LDFLAGS) \
$(LDFLAGS) -o $@
SOURCES = $(libbacktrace_la_SOURCES) $(EXTRA_libbacktrace_la_SOURCES) \
- $(btest_SOURCES) $(edtest_SOURCES) $(stest_SOURCES) \
- $(ttest_SOURCES)
+ $(btest_SOURCES) $(ctesta_SOURCES) $(ctestg_SOURCES) \
+ $(edtest_SOURCES) $(stest_SOURCES) $(ttest_SOURCES) \
+ $(ztest_SOURCES)
MULTISRCTOP =
MULTIBUILDTOP =
MULTIDIRS =
@@ -184,6 +215,7 @@ BACKTRACE_SUPPORTS_THREADS = @BACKTRACE_SUPPORTS_THREADS@
BACKTRACE_USES_MALLOC = @BACKTRACE_USES_MALLOC@
CC = @CC@
CFLAGS = @CFLAGS@
+CLOCK_GETTIME_LINK = @CLOCK_GETTIME_LINK@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -217,6 +249,7 @@ MAKEINFO = @MAKEINFO@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
+OBJCOPY = @OBJCOPY@
OBJDUMP = @OBJDUMP@
OBJEXT = @OBJEXT@
OTOOL = @OTOOL@
@@ -343,17 +376,29 @@ libbacktrace_la_LIBADD = \
$(ALLOC_FILE)
libbacktrace_la_DEPENDENCIES = $(libbacktrace_la_LIBADD)
-TESTS = $(check_PROGRAMS)
+TESTS = $(check_PROGRAMS) $(am__append_4)
@NATIVE_TRUE@btest_SOURCES = btest.c testlib.c
@NATIVE_TRUE@btest_CFLAGS = $(AM_CFLAGS) -g -O
@NATIVE_TRUE@btest_LDADD = libbacktrace.la
@NATIVE_TRUE@stest_SOURCES = stest.c
@NATIVE_TRUE@stest_LDADD = libbacktrace.la
+@NATIVE_TRUE@ztest_SOURCES = ztest.c testlib.c
+@NATIVE_TRUE@ztest_CFLAGS = -DSRCDIR=\"$(srcdir)\"
+@NATIVE_TRUE@ztest_LDADD = libbacktrace.la $(am__append_2) \
+@NATIVE_TRUE@ $(CLOCK_GETTIME_LINK)
@NATIVE_TRUE@edtest_SOURCES = edtest.c edtest2_build.c testlib.c
@NATIVE_TRUE@edtest_LDADD = libbacktrace.la
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_SOURCES = ttest.c testlib.c
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_CFLAGS = $(AM_CFLAGS) -pthread
@HAVE_PTHREAD_TRUE@@NATIVE_TRUE@ttest_LDADD = libbacktrace.la
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_SOURCES = btest.c testlib.c
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_CFLAGS = $(AM_CFLAGS) -g
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_LDFLAGS = -Wl,--compress-debug-sections=zlib-gnu
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctestg_LDADD = libbacktrace.la
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_SOURCES = btest.c testlib.c
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_CFLAGS = $(AM_CFLAGS) -g
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_LDFLAGS = -Wl,--compress-debug-sections=zlib-gabi
+@HAVE_COMPRESSED_DEBUG_TRUE@@NATIVE_TRUE@ctesta_LDADD = libbacktrace.la
# We can't use automake's automatic dependency tracking, because it
# breaks when using bootstrap-lean. Automatic dependency tracking
@@ -446,6 +491,12 @@ clean-checkPROGRAMS:
btest$(EXEEXT): $(btest_OBJECTS) $(btest_DEPENDENCIES) $(EXTRA_btest_DEPENDENCIES)
@rm -f btest$(EXEEXT)
$(btest_LINK) $(btest_OBJECTS) $(btest_LDADD) $(LIBS)
+ctesta$(EXEEXT): $(ctesta_OBJECTS) $(ctesta_DEPENDENCIES) $(EXTRA_ctesta_DEPENDENCIES)
+ @rm -f ctesta$(EXEEXT)
+ $(ctesta_LINK) $(ctesta_OBJECTS) $(ctesta_LDADD) $(LIBS)
+ctestg$(EXEEXT): $(ctestg_OBJECTS) $(ctestg_DEPENDENCIES) $(EXTRA_ctestg_DEPENDENCIES)
+ @rm -f ctestg$(EXEEXT)
+ $(ctestg_LINK) $(ctestg_OBJECTS) $(ctestg_LDADD) $(LIBS)
edtest$(EXEEXT): $(edtest_OBJECTS) $(edtest_DEPENDENCIES) $(EXTRA_edtest_DEPENDENCIES)
@rm -f edtest$(EXEEXT)
$(LINK) $(edtest_OBJECTS) $(edtest_LDADD) $(LIBS)
@@ -455,6 +506,9 @@ stest$(EXEEXT): $(stest_OBJECTS) $(stest_DEPENDENCIES) $(EXTRA_stest_DEPENDENCIE
ttest$(EXEEXT): $(ttest_OBJECTS) $(ttest_DEPENDENCIES) $(EXTRA_ttest_DEPENDENCIES)
@rm -f ttest$(EXEEXT)
$(ttest_LINK) $(ttest_OBJECTS) $(ttest_LDADD) $(LIBS)
+ztest$(EXEEXT): $(ztest_OBJECTS) $(ztest_DEPENDENCIES) $(EXTRA_ztest_DEPENDENCIES)
+ @rm -f ztest$(EXEEXT)
+ $(ztest_LINK) $(ztest_OBJECTS) $(ztest_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -483,6 +537,30 @@ btest-testlib.o: testlib.c
btest-testlib.obj: testlib.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(btest_CFLAGS) $(CFLAGS) -c -o btest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+ctesta-btest.o: btest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+ctesta-btest.obj: btest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+ctesta-testlib.o: testlib.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+ctesta-testlib.obj: testlib.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctesta_CFLAGS) $(CFLAGS) -c -o ctesta-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
+ctestg-btest.o: btest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_CFLAGS) $(CFLAGS) -c -o ctestg-btest.o `test -f 'btest.c' || echo '$(srcdir)/'`btest.c
+
+ctestg-btest.obj: btest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_CFLAGS) $(CFLAGS) -c -o ctestg-btest.obj `if test -f 'btest.c'; then $(CYGPATH_W) 'btest.c'; else $(CYGPATH_W) '$(srcdir)/btest.c'; fi`
+
+ctestg-testlib.o: testlib.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_CFLAGS) $(CFLAGS) -c -o ctestg-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+ctestg-testlib.obj: testlib.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ctestg_CFLAGS) $(CFLAGS) -c -o ctestg-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
ttest-ttest.o: ttest.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-ttest.o `test -f 'ttest.c' || echo '$(srcdir)/'`ttest.c
@@ -495,6 +573,18 @@ ttest-testlib.o: testlib.c
ttest-testlib.obj: testlib.c
$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ttest_CFLAGS) $(CFLAGS) -c -o ttest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+ztest-ztest.o: ztest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-ztest.o `test -f 'ztest.c' || echo '$(srcdir)/'`ztest.c
+
+ztest-ztest.obj: ztest.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-ztest.obj `if test -f 'ztest.c'; then $(CYGPATH_W) 'ztest.c'; else $(CYGPATH_W) '$(srcdir)/ztest.c'; fi`
+
+ztest-testlib.o: testlib.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-testlib.o `test -f 'testlib.c' || echo '$(srcdir)/'`testlib.c
+
+ztest-testlib.obj: testlib.c
+ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(ztest_CFLAGS) $(CFLAGS) -c -o ztest-testlib.obj `if test -f 'testlib.c'; then $(CYGPATH_W) 'testlib.c'; else $(CYGPATH_W) '$(srcdir)/testlib.c'; fi`
+
mostlyclean-libtool:
-rm -f *.lo
@@ -799,6 +889,10 @@ uninstall-am:
@NATIVE_TRUE@ cat $(srcdir)/edtest2.c > tmp-edtest2_build.c
@NATIVE_TRUE@ $(SHELL) $(srcdir)/../move-if-change tmp-edtest2_build.c edtest2_build.c
@NATIVE_TRUE@ echo timestamp > $@
+
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@dtest: btest
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@ $(OBJCOPY) --only-keep-debug btest btest.debug
+@HAVE_OBJCOPY_DEBUGLINK_TRUE@@NATIVE_TRUE@ $(OBJCOPY) --strip-debug --add-gnu-debuglink=btest.debug btest dtest
alloc.lo: config.h backtrace.h internal.h
backtrace.lo: config.h backtrace.h internal.h
btest.lo: (INCDIR)/filenames.h backtrace.h backtrace-supported.h
diff --git a/libbacktrace/config.h.in b/libbacktrace/config.h.in
index 9fc7715..c19b6e4 100644
--- a/libbacktrace/config.h.in
+++ b/libbacktrace/config.h.in
@@ -9,6 +9,9 @@
/* Define to 1 if you have the __atomic functions */
#undef HAVE_ATOMIC_FUNCTIONS
+/* Define to 1 if you have the `clock_gettime' function. */
+#undef HAVE_CLOCK_GETTIME
+
/* Define to 1 if you have the declaration of `strnlen', and to 0 if you
don't. */
#undef HAVE_DECL_STRNLEN
@@ -31,15 +34,24 @@
/* Define to 1 if you have the <inttypes.h> header file. */
#undef HAVE_INTTYPES_H
+/* Define to 1 if you have the `z' library (-lz). */
+#undef HAVE_LIBZ
+
/* Define to 1 if you have the <link.h> header file. */
#undef HAVE_LINK_H
/* Define if AIX loadquery is available. */
#undef HAVE_LOADQUERY
+/* Define to 1 if you have the `lstat' function. */
+#undef HAVE_LSTAT
+
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
+/* Define to 1 if you have the `readlink' function. */
+#undef HAVE_READLINK
+
/* Define to 1 if you have the <stdint.h> header file. */
#undef HAVE_STDINT_H
@@ -70,6 +82,9 @@
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
+/* Define if -lz is available. */
+#undef HAVE_ZLIB
+
/* Define to the sub-directory in which libtool stores uninstalled libraries.
*/
#undef LT_OBJDIR
diff --git a/libbacktrace/configure b/libbacktrace/configure
index 3576734..7ed9509 100755
--- a/libbacktrace/configure
+++ b/libbacktrace/configure
@@ -604,9 +604,17 @@ LTLIBOBJS
LIBOBJS
NATIVE_FALSE
NATIVE_TRUE
+HAVE_OBJCOPY_DEBUGLINK_FALSE
+HAVE_OBJCOPY_DEBUGLINK_TRUE
+OBJCOPY
+HAVE_COMPRESSED_DEBUG_FALSE
+HAVE_COMPRESSED_DEBUG_TRUE
+HAVE_ZLIB_FALSE
+HAVE_ZLIB_TRUE
HAVE_PTHREAD_FALSE
HAVE_PTHREAD_TRUE
PTHREAD_CFLAGS
+CLOCK_GETTIME_LINK
BACKTRACE_USES_MALLOC
ALLOC_FILE
VIEW_FILE
@@ -746,7 +754,8 @@ CFLAGS
LDFLAGS
LIBS
CPPFLAGS
-CPP'
+CPP
+OBJCOPY'
# Initialize some variables set by options.
@@ -1396,6 +1405,7 @@ Some influential environment variables:
CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I<include dir> if
you have headers in a nonstandard directory <include dir>
CPP C preprocessor
+ OBJCOPY location of objcopy
Use these variables to override the choices made by `configure' or to help
it to find libraries and programs with nonstandard names/locations.
@@ -11136,7 +11146,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11139 "configure"
+#line 11149 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11242,7 +11252,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11245 "configure"
+#line 11255 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -12703,6 +12713,19 @@ cat >>confdefs.h <<_ACEOF
#define HAVE_DECL_STRNLEN $ac_have_decl
_ACEOF
+for ac_func in lstat readlink
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
+eval as_val=\$$as_ac_var
+ if test "x$as_val" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
# Check for getexecname function.
if test -n "${with_target_subdir}"; then
@@ -12725,6 +12748,70 @@ $as_echo "#define HAVE_GETEXECNAME 1" >>confdefs.h
fi
+# Check for the clock_gettime function.
+for ac_func in clock_gettime
+do :
+ ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
+if test "x$ac_cv_func_clock_gettime" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_CLOCK_GETTIME 1
+_ACEOF
+
+fi
+done
+
+clock_gettime_link=
+# At least for glibc, clock_gettime is in librt. But don't
+# pull that in if it still doesn't give us the function we want. This
+# test is copied from libgomp, and modified to not link in -lrt as
+# we're using this for test timing only.
+if test "$ac_cv_func_clock_gettime" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+$as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+if test "${ac_cv_lib_rt_clock_gettime+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lrt $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* 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 clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_rt_clock_gettime=yes
+else
+ ac_cv_lib_rt_clock_gettime=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = x""yes; then :
+ CLOCK_GETTIME_LINK=-lrt
+
+$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
+
+fi
+
+fi
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -pthread is supported" >&5
$as_echo_n "checking whether -pthread is supported... " >&6; }
if test "${libgo_cv_lib_pthread+set}" = set; then :
@@ -12761,6 +12848,166 @@ else
fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for compress in -lz" >&5
+$as_echo_n "checking for compress in -lz... " >&6; }
+if test "${ac_cv_lib_z_compress+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lz $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* 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 compress ();
+int
+main ()
+{
+return compress ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_z_compress=yes
+else
+ ac_cv_lib_z_compress=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_z_compress" >&5
+$as_echo "$ac_cv_lib_z_compress" >&6; }
+if test "x$ac_cv_lib_z_compress" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LIBZ 1
+_ACEOF
+
+ LIBS="-lz $LIBS"
+
+fi
+
+if test $ac_cv_lib_z_compress = "yes"; then
+
+$as_echo "#define HAVE_ZLIB 1" >>confdefs.h
+
+fi
+ if test "$ac_cv_lib_z_compress" = yes; then
+ HAVE_ZLIB_TRUE=
+ HAVE_ZLIB_FALSE='#'
+else
+ HAVE_ZLIB_TRUE='#'
+ HAVE_ZLIB_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether --compress-debug-sections is supported" >&5
+$as_echo_n "checking whether --compress-debug-sections is supported... " >&6; }
+if test "${libgo_cv_ld_compress+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ LDFLAGS_hold=$LDFLAGS
+LDFLAGS="$LDFLAGS -Wl,--compress-debug-sections=zlib-gnu"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ libgo_cv_ld_compress=yes
+else
+ libgo_cv_ld_compress=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LDFLAGS=$LDFLAGS_hold
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgo_cv_ld_compress" >&5
+$as_echo "$libgo_cv_ld_compress" >&6; }
+ if test "$libgo_cv_ld_compress" = yes; then
+ HAVE_COMPRESSED_DEBUG_TRUE=
+ HAVE_COMPRESSED_DEBUG_FALSE='#'
+else
+ HAVE_COMPRESSED_DEBUG_TRUE='#'
+ HAVE_COMPRESSED_DEBUG_FALSE=
+fi
+
+
+
+# Extract the first word of "objcopy", so it can be a program name with args.
+set dummy objcopy; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_prog_OBJCOPY+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJCOPY"; then
+ ac_cv_prog_OBJCOPY="$OBJCOPY" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+ ac_cv_prog_OBJCOPY="objcopy"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJCOPY=$ac_cv_prog_OBJCOPY
+if test -n "$OBJCOPY"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJCOPY" >&5
+$as_echo "$OBJCOPY" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether objcopy supports debuglink" >&5
+$as_echo_n "checking whether objcopy supports debuglink... " >&6; }
+if test "${libbacktrace_cv_objcopy_debuglink+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "${with_target_subdir}"; then
+ libbacktrace_cv_objcopy_debuglink=no
+elif ${OBJCOPY} --add-gnu-debuglink=x /bin/ls /tmp/ls$$; then
+ rm -f /tmp/ls$$
+ libbacktrace_cv_objcopy_debuglink=yes
+else
+ libbacktrace_cv_objcopy_debuglink=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libbacktrace_cv_objcopy_debuglink" >&5
+$as_echo "$libbacktrace_cv_objcopy_debuglink" >&6; }
+ if test "$libbacktrace_cv_objcopy_debuglink" = yes; then
+ HAVE_OBJCOPY_DEBUGLINK_TRUE=
+ HAVE_OBJCOPY_DEBUGLINK_FALSE='#'
+else
+ HAVE_OBJCOPY_DEBUGLINK_TRUE='#'
+ HAVE_OBJCOPY_DEBUGLINK_FALSE=
+fi
+
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether tests can run" >&5
$as_echo_n "checking whether tests can run... " >&6; }
if test "${libbacktrace_cv_sys_native+set}" = set; then :
@@ -12927,6 +13174,18 @@ if test -z "${HAVE_PTHREAD_TRUE}" && test -z "${HAVE_PTHREAD_FALSE}"; then
as_fn_error "conditional \"HAVE_PTHREAD\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
fi
+if test -z "${HAVE_ZLIB_TRUE}" && test -z "${HAVE_ZLIB_FALSE}"; then
+ as_fn_error "conditional \"HAVE_ZLIB\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_COMPRESSED_DEBUG_TRUE}" && test -z "${HAVE_COMPRESSED_DEBUG_FALSE}"; then
+ as_fn_error "conditional \"HAVE_COMPRESSED_DEBUG\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_OBJCOPY_DEBUGLINK_TRUE}" && test -z "${HAVE_OBJCOPY_DEBUGLINK_FALSE}"; then
+ as_fn_error "conditional \"HAVE_OBJCOPY_DEBUGLINK\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
if test -z "${NATIVE_TRUE}" && test -z "${NATIVE_FALSE}"; then
as_fn_error "conditional \"NATIVE\" was never defined.
Usually this means the macro was only invoked conditionally." "$LINENO" 5
diff --git a/libbacktrace/configure.ac b/libbacktrace/configure.ac
index e644c7d..9bc1d0f 100644
--- a/libbacktrace/configure.ac
+++ b/libbacktrace/configure.ac
@@ -373,6 +373,7 @@ if test "$have_fcntl" = "yes"; then
fi
AC_CHECK_DECLS(strnlen)
+AC_CHECK_FUNCS(lstat readlink)
# Check for getexecname function.
if test -n "${with_target_subdir}"; then
@@ -387,6 +388,21 @@ if test "$have_getexecname" = "yes"; then
AC_DEFINE(HAVE_GETEXECNAME, 1, [Define if getexecname is available.])
fi
+# Check for the clock_gettime function.
+AC_CHECK_FUNCS(clock_gettime)
+clock_gettime_link=
+# At least for glibc, clock_gettime is in librt. But don't
+# pull that in if it still doesn't give us the function we want. This
+# test is copied from libgomp, and modified to not link in -lrt as
+# we're using this for test timing only.
+if test "$ac_cv_func_clock_gettime" = no; then
+ AC_CHECK_LIB(rt, clock_gettime,
+ [CLOCK_GETTIME_LINK=-lrt
+ AC_DEFINE(HAVE_CLOCK_GETTIME, 1,
+ [Define to 1 if you have the `clock_gettime' function.])])
+fi
+AC_SUBST(CLOCK_GETTIME_LINK)
+
dnl Test whether the compiler supports the -pthread option.
AC_CACHE_CHECK([whether -pthread is supported],
[libgo_cv_lib_pthread],
@@ -404,6 +420,37 @@ AC_SUBST(PTHREAD_CFLAGS)
AM_CONDITIONAL(HAVE_PTHREAD, test "$libgo_cv_lib_pthread" = yes)
+AC_CHECK_LIB([z], [compress], [])
+if test $ac_cv_lib_z_compress = "yes"; then
+ AC_DEFINE(HAVE_ZLIB, 1, [Define if -lz is available.])
+fi
+AM_CONDITIONAL(HAVE_ZLIB, test "$ac_cv_lib_z_compress" = yes)
+
+dnl Test whether the linker supports the --compress_debug_sections option.
+AC_CACHE_CHECK([whether --compress-debug-sections is supported],
+[libgo_cv_ld_compress],
+[LDFLAGS_hold=$LDFLAGS
+LDFLAGS="$LDFLAGS -Wl,--compress-debug-sections=zlib-gnu"
+AC_LINK_IFELSE([AC_LANG_PROGRAM(,)],
+[libgo_cv_ld_compress=yes],
+[libgo_cv_ld_compress=no])
+LDFLAGS=$LDFLAGS_hold])
+AM_CONDITIONAL(HAVE_COMPRESSED_DEBUG, test "$libgo_cv_ld_compress" = yes)
+
+AC_ARG_VAR(OBJCOPY, [location of objcopy])
+AC_CHECK_PROG(OBJCOPY, objcopy, objcopy,)
+AC_CACHE_CHECK([whether objcopy supports debuglink],
+[libbacktrace_cv_objcopy_debuglink],
+[if test -n "${with_target_subdir}"; then
+ libbacktrace_cv_objcopy_debuglink=no
+elif ${OBJCOPY} --add-gnu-debuglink=x /bin/ls /tmp/ls$$; then
+ rm -f /tmp/ls$$
+ libbacktrace_cv_objcopy_debuglink=yes
+else
+ libbacktrace_cv_objcopy_debuglink=no
+fi])
+AM_CONDITIONAL(HAVE_OBJCOPY_DEBUGLINK, test "$libbacktrace_cv_objcopy_debuglink" = yes)
+
AC_CACHE_CHECK([whether tests can run],
[libbacktrace_cv_sys_native],
[AC_RUN_IFELSE([AC_LANG_PROGRAM([], [return 0;])],
diff --git a/libbacktrace/elf.c b/libbacktrace/elf.c
index 1471007..06823fc 100644
--- a/libbacktrace/elf.c
+++ b/libbacktrace/elf.c
@@ -32,9 +32,12 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "config.h"
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
#ifdef HAVE_DL_ITERATE_PHDR
#include <link.h>
@@ -43,6 +46,71 @@ POSSIBILITY OF SUCH DAMAGE. */
#include "backtrace.h"
#include "internal.h"
+#ifndef S_ISLNK
+ #ifndef S_IFLNK
+ #define S_IFLNK 0120000
+ #endif
+ #ifndef S_IFMT
+ #define S_IFMT 0170000
+ #endif
+ #define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+
+#ifndef __GNUC__
+#define __builtin_prefetch(p, r, l)
+#define unlikely(x) (x)
+#else
+#define unlikely(x) __builtin_expect(!!(x), 0)
+#endif
+
+#if !defined(HAVE_DECL_STRNLEN) || !HAVE_DECL_STRNLEN
+
+/* If strnlen is not declared, provide our own version. */
+
+static size_t
+xstrnlen (const char *s, size_t maxlen)
+{
+ size_t i;
+
+ for (i = 0; i < maxlen; ++i)
+ if (s[i] == '\0')
+ break;
+ return i;
+}
+
+#define strnlen xstrnlen
+
+#endif
+
+#ifndef HAVE_LSTAT
+
+/* Dummy version of lstat for systems that don't have it. */
+
+static int
+xlstat (const char *path ATTRIBUTE_UNUSED, struct stat *st ATTRIBUTE_UNUSED)
+{
+ return -1;
+}
+
+#define lstat xlstat
+
+#endif
+
+#ifndef HAVE_READLINK
+
+/* Dummy version of readlink for systems that don't have it. */
+
+static ssize_t
+xreadlink (const char *path ATTRIBUTE_UNUSED, char *buf ATTRIBUTE_UNUSED,
+ size_t bufsz ATTRIBUTE_UNUSED)
+{
+ return -1;
+}
+
+#define readlink xreadlink
+
+#endif
+
#ifndef HAVE_DL_ITERATE_PHDR
/* Dummy version of dl_iterate_phdr for systems that don't have it. */
@@ -103,8 +171,11 @@ dl_iterate_phdr (int (*callback) (struct dl_phdr_info *,
#undef SHT_SYMTAB
#undef SHT_STRTAB
#undef SHT_DYNSYM
+#undef SHF_COMPRESSED
#undef STT_OBJECT
#undef STT_FUNC
+#undef NT_GNU_BUILD_ID
+#undef ELFCOMPRESS_ZLIB
/* Basic types. */
@@ -195,6 +266,8 @@ typedef struct {
#define SHT_STRTAB 3
#define SHT_DYNSYM 11
+#define SHF_COMPRESSED 0x800
+
#if BACKTRACE_ELF_SIZE == 32
typedef struct
@@ -224,6 +297,39 @@ typedef struct
#define STT_OBJECT 1
#define STT_FUNC 2
+typedef struct
+{
+ uint32_t namesz;
+ uint32_t descsz;
+ uint32_t type;
+ char name[1];
+} b_elf_note;
+
+#define NT_GNU_BUILD_ID 3
+
+#if BACKTRACE_ELF_SIZE == 32
+
+typedef struct
+{
+ b_elf_word ch_type; /* Compresstion algorithm */
+ b_elf_word ch_size; /* Uncompressed size */
+ b_elf_word ch_addralign; /* Alignment for uncompressed data */
+} b_elf_chdr; /* Elf_Chdr */
+
+#else /* BACKTRACE_ELF_SIZE != 32 */
+
+typedef struct
+{
+ b_elf_word ch_type; /* Compression algorithm */
+ b_elf_word ch_reserved; /* Reserved */
+ b_elf_xword ch_size; /* Uncompressed size */
+ b_elf_xword ch_addralign; /* Alignment for uncompressed data */
+} b_elf_chdr; /* Elf_Chdr */
+
+#endif /* BACKTRACE_ELF_SIZE != 32 */
+
+#define ELFCOMPRESS_ZLIB 1
+
/* An index of ELF sections we care about. */
enum debug_section
@@ -233,6 +339,15 @@ enum debug_section
DEBUG_ABBREV,
DEBUG_RANGES,
DEBUG_STR,
+
+ /* The old style compressed sections. This list must correspond to
+ the list of normal debug sections. */
+ ZDEBUG_INFO,
+ ZDEBUG_LINE,
+ ZDEBUG_ABBREV,
+ ZDEBUG_RANGES,
+ ZDEBUG_STR,
+
DEBUG_MAX
};
@@ -244,7 +359,12 @@ static const char * const debug_section_names[DEBUG_MAX] =
".debug_line",
".debug_abbrev",
".debug_ranges",
- ".debug_str"
+ ".debug_str",
+ ".zdebug_info",
+ ".zdebug_line",
+ ".zdebug_abbrev",
+ ".zdebug_ranges",
+ ".zdebug_str"
};
/* Information we gather for the sections we care about. */
@@ -257,6 +377,8 @@ struct debug_section_info
size_t size;
/* Section contents, after read from file. */
const unsigned char *data;
+ /* Whether the SHF_COMPRESSED flag is set for the section. */
+ int compressed;
};
/* Information we keep for an ELF symbol. */
@@ -283,6 +405,102 @@ struct elf_syminfo_data
size_t count;
};
+/* Compute the CRC-32 of BUF/LEN. This uses the CRC used for
+ .gnu_debuglink files. */
+
+static uint32_t
+elf_crc32 (uint32_t crc, const unsigned char *buf, size_t len)
+{
+ static const uint32_t crc32_table[256] =
+ {
+ 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
+ 0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
+ 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
+ 0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
+ 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
+ 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
+ 0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
+ 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
+ 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
+ 0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
+ 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
+ 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
+ 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
+ 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
+ 0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
+ 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
+ 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
+ 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
+ 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
+ 0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
+ 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
+ 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
+ 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
+ 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
+ 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
+ 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
+ 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
+ 0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
+ 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
+ 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
+ 0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
+ 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
+ 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
+ 0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
+ 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
+ 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
+ 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
+ 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
+ 0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
+ 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
+ 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
+ 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
+ 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
+ 0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
+ 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
+ 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
+ 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
+ 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
+ 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
+ 0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
+ 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
+ 0x2d02ef8d
+ };
+ const unsigned char *end;
+
+ crc = ~crc;
+ for (end = buf + len; buf < end; ++ buf)
+ crc = crc32_table[(crc ^ *buf) & 0xff] ^ (crc >> 8);
+ return ~crc;
+}
+
+/* Return the CRC-32 of the entire file open at DESCRIPTOR. */
+
+static uint32_t
+elf_crc32_file (struct backtrace_state *state, int descriptor,
+ backtrace_error_callback error_callback, void *data)
+{
+ struct stat st;
+ struct backtrace_view file_view;
+ uint32_t ret;
+
+ if (fstat (descriptor, &st) < 0)
+ {
+ error_callback (data, "fstat", errno);
+ return 0;
+ }
+
+ if (!backtrace_get_view (state, descriptor, 0, st.st_size, error_callback,
+ data, &file_view))
+ return 0;
+
+ ret = elf_crc32 (0, (const unsigned char *) file_view.data, st.st_size);
+
+ backtrace_release_view (state, &file_view, error_callback, data);
+
+ return ret;
+}
+
/* A dummy callback function used when we can't find any debug info. */
static int
@@ -510,6 +728,1803 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
callback (data, addr, sym->name, sym->address, sym->size);
}
+/* Return whether FILENAME is a symlink. */
+
+static int
+elf_is_symlink (const char *filename)
+{
+ struct stat st;
+
+ if (lstat (filename, &st) < 0)
+ return 0;
+ return S_ISLNK (st.st_mode);
+}
+
+/* Return the results of reading the symlink FILENAME in a buffer
+ allocated by backtrace_alloc. Return the length of the buffer in
+ *LEN. */
+
+static char *
+elf_readlink (struct backtrace_state *state, const char *filename,
+ backtrace_error_callback error_callback, void *data,
+ size_t *plen)
+{
+ size_t len;
+ char *buf;
+
+ len = 128;
+ while (1)
+ {
+ ssize_t rl;
+
+ buf = backtrace_alloc (state, len, error_callback, data);
+ if (buf == NULL)
+ return NULL;
+ rl = readlink (filename, buf, len);
+ if (rl < 0)
+ {
+ backtrace_free (state, buf, len, error_callback, data);
+ return NULL;
+ }
+ if ((size_t) rl < len - 1)
+ {
+ buf[rl] = '\0';
+ *plen = len;
+ return buf;
+ }
+ backtrace_free (state, buf, len, error_callback, data);
+ len *= 2;
+ }
+}
+
+/* Open a separate debug info file, using the build ID to find it.
+ Returns an open file descriptor, or -1.
+
+ The GDB manual says that the only place gdb looks for a debug file
+ when the build ID is known is in /usr/lib/debug/.build-id. */
+
+static int
+elf_open_debugfile_by_buildid (struct backtrace_state *state,
+ const char *buildid_data, size_t buildid_size,
+ backtrace_error_callback error_callback,
+ void *data)
+{
+ const char * const prefix = "/usr/lib/debug/.build-id/";
+ const size_t prefix_len = strlen (prefix);
+ const char * const suffix = ".debug";
+ const size_t suffix_len = strlen (suffix);
+ size_t len;
+ char *bd_filename;
+ char *t;
+ size_t i;
+ int ret;
+ int does_not_exist;
+
+ len = prefix_len + buildid_size * 2 + suffix_len + 2;
+ bd_filename = backtrace_alloc (state, len, error_callback, data);
+ if (bd_filename == NULL)
+ return -1;
+
+ t = bd_filename;
+ memcpy (t, prefix, prefix_len);
+ t += prefix_len;
+ for (i = 0; i < buildid_size; i++)
+ {
+ unsigned char b;
+ unsigned char nib;
+
+ b = (unsigned char) buildid_data[i];
+ nib = (b & 0xf0) >> 4;
+ *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10;
+ nib = b & 0x0f;
+ *t++ = nib < 10 ? '0' + nib : 'a' + nib - 10;
+ if (i == 0)
+ *t++ = '/';
+ }
+ memcpy (t, suffix, suffix_len);
+ t[suffix_len] = '\0';
+
+ ret = backtrace_open (bd_filename, error_callback, data, &does_not_exist);
+
+ backtrace_free (state, bd_filename, len, error_callback, data);
+
+ /* gdb checks that the debuginfo file has the same build ID note.
+ That seems kind of pointless to me--why would it have the right
+ name but not the right build ID?--so skipping the check. */
+
+ return ret;
+}
+
+/* Try to open a file whose name is PREFIX (length PREFIX_LEN)
+ concatenated with PREFIX2 (length PREFIX2_LEN) concatenated with
+ DEBUGLINK_NAME. Returns an open file descriptor, or -1. */
+
+static int
+elf_try_debugfile (struct backtrace_state *state, const char *prefix,
+ size_t prefix_len, const char *prefix2, size_t prefix2_len,
+ const char *debuglink_name,
+ backtrace_error_callback error_callback, void *data)
+{
+ size_t debuglink_len;
+ size_t try_len;
+ char *try;
+ int does_not_exist;
+ int ret;
+
+ debuglink_len = strlen (debuglink_name);
+ try_len = prefix_len + prefix2_len + debuglink_len + 1;
+ try = backtrace_alloc (state, try_len, error_callback, data);
+ if (try == NULL)
+ return -1;
+
+ memcpy (try, prefix, prefix_len);
+ memcpy (try + prefix_len, prefix2, prefix2_len);
+ memcpy (try + prefix_len + prefix2_len, debuglink_name, debuglink_len);
+ try[prefix_len + prefix2_len + debuglink_len] = '\0';
+
+ ret = backtrace_open (try, error_callback, data, &does_not_exist);
+
+ backtrace_free (state, try, try_len, error_callback, data);
+
+ return ret;
+}
+
+/* Find a separate debug info file, using the debuglink section data
+ to find it. Returns an open file descriptor, or -1. */
+
+static int
+elf_find_debugfile_by_debuglink (struct backtrace_state *state,
+ const char *filename,
+ const char *debuglink_name,
+ backtrace_error_callback error_callback,
+ void *data)
+{
+ int ret;
+ char *alc;
+ size_t alc_len;
+ const char *slash;
+ int ddescriptor;
+ const char *prefix;
+ size_t prefix_len;
+
+ /* Resolve symlinks in FILENAME. Since FILENAME is fairly likely to
+ be /proc/self/exe, symlinks are common. We don't try to resolve
+ the whole path name, just the base name. */
+ ret = -1;
+ alc = NULL;
+ alc_len = 0;
+ while (elf_is_symlink (filename))
+ {
+ char *new_buf;
+ size_t new_len;
+
+ new_buf = elf_readlink (state, filename, error_callback, data, &new_len);
+ if (new_buf == NULL)
+ break;
+
+ if (new_buf[0] == '/')
+ filename = new_buf;
+ else
+ {
+ slash = strrchr (filename, '/');
+ if (slash == NULL)
+ filename = new_buf;
+ else
+ {
+ size_t clen;
+ char *c;
+
+ slash++;
+ clen = slash - filename + strlen (new_buf) + 1;
+ c = backtrace_alloc (state, clen, error_callback, data);
+ if (c == NULL)
+ goto done;
+
+ memcpy (c, filename, slash - filename);
+ memcpy (c + (slash - filename), new_buf, strlen (new_buf));
+ c[slash - filename + strlen (new_buf)] = '\0';
+ backtrace_free (state, new_buf, new_len, error_callback, data);
+ filename = c;
+ new_buf = c;
+ new_len = clen;
+ }
+ }
+
+ if (alc != NULL)
+ backtrace_free (state, alc, alc_len, error_callback, data);
+ alc = new_buf;
+ alc_len = new_len;
+ }
+
+ /* Look for DEBUGLINK_NAME in the same directory as FILENAME. */
+
+ slash = strrchr (filename, '/');
+ if (slash == NULL)
+ {
+ prefix = "";
+ prefix_len = 0;
+ }
+ else
+ {
+ slash++;
+ prefix = filename;
+ prefix_len = slash - filename;
+ }
+
+ ddescriptor = elf_try_debugfile (state, prefix, prefix_len, "", 0,
+ debuglink_name, error_callback, data);
+ if (ddescriptor >= 0)
+ {
+ ret = ddescriptor;
+ goto done;
+ }
+
+ /* Look for DEBUGLINK_NAME in a .debug subdirectory of FILENAME. */
+
+ ddescriptor = elf_try_debugfile (state, prefix, prefix_len, ".debug/",
+ strlen (".debug/"), debuglink_name,
+ error_callback, data);
+ if (ddescriptor >= 0)
+ {
+ ret = ddescriptor;
+ goto done;
+ }
+
+ /* Look for DEBUGLINK_NAME in /usr/lib/debug. */
+
+ ddescriptor = elf_try_debugfile (state, "/usr/lib/debug/",
+ strlen ("/usr/lib/debug/"), prefix,
+ prefix_len, debuglink_name,
+ error_callback, data);
+ if (ddescriptor >= 0)
+ ret = ddescriptor;
+
+ done:
+ if (alc != NULL && alc_len > 0)
+ backtrace_free (state, alc, alc_len, error_callback, data);
+ return ret;
+}
+
+/* Open a separate debug info file, using the debuglink section data
+ to find it. Returns an open file descriptor, or -1. */
+
+static int
+elf_open_debugfile_by_debuglink (struct backtrace_state *state,
+ const char *filename,
+ const char *debuglink_name,
+ uint32_t debuglink_crc,
+ backtrace_error_callback error_callback,
+ void *data)
+{
+ int ddescriptor;
+ uint32_t got_crc;
+
+ ddescriptor = elf_find_debugfile_by_debuglink (state, filename,
+ debuglink_name,
+ error_callback, data);
+ if (ddescriptor < 0)
+ return -1;
+
+ got_crc = elf_crc32_file (state, ddescriptor, error_callback, data);
+ if (got_crc != debuglink_crc)
+ {
+ backtrace_close (ddescriptor, error_callback, data);
+ return -1;
+ }
+
+ return ddescriptor;
+}
+
+/* A function useful for setting a breakpoint for an inflation failure
+ when this code is compiled with -g. */
+
+static void
+elf_zlib_failed(void)
+{
+}
+
+/* *PVAL is the current value being read from the stream, and *PBITS
+ is the number of valid bits. Ensure that *PVAL holds at least 15
+ bits by reading additional bits from *PPIN, up to PINEND, as
+ needed. Updates *PPIN, *PVAL and *PBITS. Returns 1 on success, 0
+ on error. */
+
+static int
+elf_zlib_fetch (const unsigned char **ppin, const unsigned char *pinend,
+ uint64_t *pval, unsigned int *pbits)
+{
+ unsigned int bits;
+ const unsigned char *pin;
+ uint64_t val;
+ uint32_t next;
+
+ bits = *pbits;
+ if (bits >= 15)
+ return 1;
+ pin = *ppin;
+ val = *pval;
+
+ if (unlikely (pinend - pin < 4))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* We've ensured that PIN is aligned. */
+ next = *(const uint32_t *)pin;
+
+#if __BYTE_ORDER == __ORDER_BIG_ENDIAN
+ next = __builtin_bswap32 (next);
+#endif
+
+ val |= (uint64_t)next << bits;
+ bits += 32;
+ pin += 4;
+
+ /* We will need the next four bytes soon. */
+ __builtin_prefetch (pin, 0, 0);
+
+ *ppin = pin;
+ *pval = val;
+ *pbits = bits;
+ return 1;
+}
+
+/* Huffman code tables, like the rest of the zlib format, are defined
+ by RFC 1951. We store a Huffman code table as a series of tables
+ stored sequentially in memory. Each entry in a table is 16 bits.
+ The first, main, table has 256 entries. It is followed by a set of
+ secondary tables of length 2 to 128 entries. The maximum length of
+ a code sequence in the deflate format is 15 bits, so that is all we
+ need. Each secondary table has an index, which is the offset of
+ the table in the overall memory storage.
+
+ The deflate format says that all codes of a given bit length are
+ lexicographically consecutive. Perhaps we could have 130 values
+ that require a 15-bit code, perhaps requiring three secondary
+ tables of size 128. I don't know if this is actually possible, but
+ it suggests that the maximum size required for secondary tables is
+ 3 * 128 + 3 * 64 ... == 768. The zlib enough program reports 660
+ as the maximum. We permit 768, since in addition to the 256 for
+ the primary table, with two bytes per entry, and with the two
+ tables we need, that gives us a page.
+
+ A single table entry needs to store a value or (for the main table
+ only) the index and size of a secondary table. Values range from 0
+ to 285, inclusive. Secondary table indexes, per above, range from
+ 0 to 510. For a value we need to store the number of bits we need
+ to determine that value (one value may appear multiple times in the
+ table), which is 1 to 8. For a secondary table we need to store
+ the number of bits used to index into the table, which is 1 to 7.
+ And of course we need 1 bit to decide whether we have a value or a
+ secondary table index. So each entry needs 9 bits for value/table
+ index, 3 bits for size, 1 bit what it is. For simplicity we use 16
+ bits per entry. */
+
+/* Number of entries we allocate to for one code table. We get a page
+ for the two code tables we need. */
+
+#define HUFFMAN_TABLE_SIZE (1024)
+
+/* Bit masks and shifts for the values in the table. */
+
+#define HUFFMAN_VALUE_MASK 0x01ff
+#define HUFFMAN_BITS_SHIFT 9
+#define HUFFMAN_BITS_MASK 0x7
+#define HUFFMAN_SECONDARY_SHIFT 12
+
+/* For working memory while inflating we need two code tables, we need
+ an array of code lengths (max value 15, so we use unsigned char),
+ and an array of unsigned shorts used while building a table. The
+ latter two arrays must be large enough to hold the maximum number
+ of code lengths, which RFC 1951 defines as 286 + 30. */
+
+#define ZDEBUG_TABLE_SIZE \
+ (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \
+ + (286 + 30) * sizeof (uint16_t) \
+ + (286 + 30) * sizeof (unsigned char))
+
+#define ZDEBUG_TABLE_CODELEN_OFFSET \
+ (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t) \
+ + (286 + 30) * sizeof (uint16_t))
+
+#define ZDEBUG_TABLE_WORK_OFFSET \
+ (2 * HUFFMAN_TABLE_SIZE * sizeof (uint16_t))
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+
+/* Used by the main function that generates the fixed table to learn
+ the table size. */
+static size_t final_next_secondary;
+
+#endif
+
+/* Build a Huffman code table from an array of lengths in CODES of
+ length CODES_LEN. The table is stored into *TABLE. ZDEBUG_TABLE
+ is the same as for elf_zlib_inflate, used to find some work space.
+ Returns 1 on success, 0 on error. */
+
+static int
+elf_zlib_inflate_table (unsigned char *codes, size_t codes_len,
+ uint16_t *zdebug_table, uint16_t *table)
+{
+ uint16_t count[16];
+ uint16_t start[16];
+ uint16_t prev[16];
+ uint16_t firstcode[7];
+ uint16_t *next;
+ size_t i;
+ size_t j;
+ unsigned int code;
+ size_t next_secondary;
+
+ /* Count the number of code of each length. Set NEXT[val] to be the
+ next value after VAL with the same bit length. */
+
+ next = (uint16_t *) (((unsigned char *) zdebug_table)
+ + ZDEBUG_TABLE_WORK_OFFSET);
+
+ memset (&count[0], 0, 16 * sizeof (uint16_t));
+ for (i = 0; i < codes_len; ++i)
+ {
+ if (unlikely (codes[i] >= 16))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (count[codes[i]] == 0)
+ {
+ start[codes[i]] = i;
+ prev[codes[i]] = i;
+ }
+ else
+ {
+ next[prev[codes[i]]] = i;
+ prev[codes[i]] = i;
+ }
+
+ ++count[codes[i]];
+ }
+
+ /* For each length, fill in the table for the codes of that
+ length. */
+
+ memset (table, 0, HUFFMAN_TABLE_SIZE * sizeof (uint16_t));
+
+ /* Handle the values that do not require a secondary table. */
+
+ code = 0;
+ for (j = 1; j <= 8; ++j)
+ {
+ unsigned int jcnt;
+ unsigned int val;
+
+ jcnt = count[j];
+ if (jcnt == 0)
+ continue;
+
+ if (unlikely (jcnt > (1U << j)))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* There are JCNT values that have this length, the values
+ starting from START[j] continuing through NEXT[VAL]. Those
+ values are assigned consecutive values starting at CODE. */
+
+ val = start[j];
+ for (i = 0; i < jcnt; ++i)
+ {
+ uint16_t tval;
+ size_t ind;
+ unsigned int incr;
+
+ /* In the compressed bit stream, the value VAL is encoded as
+ J bits with the value C. */
+
+ if (unlikely ((val & ~HUFFMAN_VALUE_MASK) != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ tval = val | ((j - 1) << HUFFMAN_BITS_SHIFT);
+
+ /* The table lookup uses 8 bits. If J is less than 8, we
+ don't know what the other bits will be. We need to fill
+ in all possibilities in the table. Since the Huffman
+ code is unambiguous, those entries can't be used for any
+ other code. */
+
+ for (ind = code; ind < 0x100; ind += 1 << j)
+ {
+ if (unlikely (table[ind] != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ table[ind] = tval;
+ }
+
+ /* Advance to the next value with this length. */
+ if (i + 1 < jcnt)
+ val = next[val];
+
+ /* The Huffman codes are stored in the bitstream with the
+ most significant bit first, as is required to make them
+ unambiguous. The effect is that when we read them from
+ the bitstream we see the bit sequence in reverse order:
+ the most significant bit of the Huffman code is the least
+ significant bit of the value we read from the bitstream.
+ That means that to make our table lookups work, we need
+ to reverse the bits of CODE. Since reversing bits is
+ tedious and in general requires using a table, we instead
+ increment CODE in reverse order. That is, if the number
+ of bits we are currently using, here named J, is 3, we
+ count as 000, 100, 010, 110, 001, 101, 011, 111, which is
+ to say the numbers from 0 to 7 but with the bits
+ reversed. Going to more bits, aka incrementing J,
+ effectively just adds more zero bits as the beginning,
+ and as such does not change the numeric value of CODE.
+
+ To increment CODE of length J in reverse order, find the
+ most significant zero bit and set it to one while
+ clearing all higher bits. In other words, add 1 modulo
+ 2^J, only reversed. */
+
+ incr = 1U << (j - 1);
+ while ((code & incr) != 0)
+ incr >>= 1;
+ if (incr == 0)
+ code = 0;
+ else
+ {
+ code &= incr - 1;
+ code += incr;
+ }
+ }
+ }
+
+ /* Handle the values that require a secondary table. */
+
+ /* Set FIRSTCODE, the number at which the codes start, for each
+ length. */
+
+ for (j = 9; j < 16; j++)
+ {
+ unsigned int jcnt;
+ unsigned int k;
+
+ jcnt = count[j];
+ if (jcnt == 0)
+ continue;
+
+ /* There are JCNT values that have this length, the values
+ starting from START[j]. Those values are assigned
+ consecutive values starting at CODE. */
+
+ firstcode[j - 9] = code;
+
+ /* Reverse add JCNT to CODE modulo 2^J. */
+ for (k = 0; k < j; ++k)
+ {
+ if ((jcnt & (1U << k)) != 0)
+ {
+ unsigned int m;
+ unsigned int bit;
+
+ bit = 1U << (j - k - 1);
+ for (m = 0; m < j - k; ++m, bit >>= 1)
+ {
+ if ((code & bit) == 0)
+ {
+ code += bit;
+ break;
+ }
+ code &= ~bit;
+ }
+ jcnt &= ~(1U << k);
+ }
+ }
+ if (unlikely (jcnt != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ }
+
+ /* For J from 9 to 15, inclusive, we store COUNT[J] consecutive
+ values starting at START[J] with consecutive codes starting at
+ FIRSTCODE[J - 9]. In the primary table we need to point to the
+ secondary table, and the secondary table will be indexed by J - 9
+ bits. We count down from 15 so that we install the larger
+ secondary tables first, as the smaller ones may be embedded in
+ the larger ones. */
+
+ next_secondary = 0; /* Index of next secondary table (after primary). */
+ for (j = 15; j >= 9; j--)
+ {
+ unsigned int jcnt;
+ unsigned int val;
+ size_t primary; /* Current primary index. */
+ size_t secondary; /* Offset to current secondary table. */
+ size_t secondary_bits; /* Bit size of current secondary table. */
+
+ jcnt = count[j];
+ if (jcnt == 0)
+ continue;
+
+ val = start[j];
+ code = firstcode[j - 9];
+ primary = 0x100;
+ secondary = 0;
+ secondary_bits = 0;
+ for (i = 0; i < jcnt; ++i)
+ {
+ uint16_t tval;
+ size_t ind;
+ unsigned int incr;
+
+ if ((code & 0xff) != primary)
+ {
+ uint16_t tprimary;
+
+ /* Fill in a new primary table entry. */
+
+ primary = code & 0xff;
+
+ tprimary = table[primary];
+ if (tprimary == 0)
+ {
+ /* Start a new secondary table. */
+
+ if (unlikely ((next_secondary & HUFFMAN_VALUE_MASK)
+ != next_secondary))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ secondary = next_secondary;
+ secondary_bits = j - 8;
+ next_secondary += 1 << secondary_bits;
+ table[primary] = (secondary
+ + ((j - 8) << HUFFMAN_BITS_SHIFT)
+ + (1U << HUFFMAN_SECONDARY_SHIFT));
+ }
+ else
+ {
+ /* There is an existing entry. It had better be a
+ secondary table with enough bits. */
+ if (unlikely ((tprimary & (1U << HUFFMAN_SECONDARY_SHIFT))
+ == 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ secondary = tprimary & HUFFMAN_VALUE_MASK;
+ secondary_bits = ((tprimary >> HUFFMAN_BITS_SHIFT)
+ & HUFFMAN_BITS_MASK);
+ if (unlikely (secondary_bits < j - 8))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ }
+ }
+
+ /* Fill in secondary table entries. */
+
+ tval = val | ((j - 8) << HUFFMAN_BITS_SHIFT);
+
+ for (ind = code >> 8;
+ ind < (1U << secondary_bits);
+ ind += 1U << (j - 8))
+ {
+ if (unlikely (table[secondary + 0x100 + ind] != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ table[secondary + 0x100 + ind] = tval;
+ }
+
+ if (i + 1 < jcnt)
+ val = next[val];
+
+ incr = 1U << (j - 1);
+ while ((code & incr) != 0)
+ incr >>= 1;
+ if (incr == 0)
+ code = 0;
+ else
+ {
+ code &= incr - 1;
+ code += incr;
+ }
+ }
+ }
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+ final_next_secondary = next_secondary;
+#endif
+
+ return 1;
+}
+
+#ifdef BACKTRACE_GENERATE_FIXED_HUFFMAN_TABLE
+
+/* Used to generate the fixed Huffman table for block type 1. */
+
+#include <stdio.h>
+
+static uint16_t table[ZDEBUG_TABLE_SIZE];
+static unsigned char codes[287];
+
+int
+main ()
+{
+ size_t i;
+
+ for (i = 0; i <= 143; ++i)
+ codes[i] = 8;
+ for (i = 144; i <= 255; ++i)
+ codes[i] = 9;
+ for (i = 256; i <= 279; ++i)
+ codes[i] = 7;
+ for (i = 280; i <= 287; ++i)
+ codes[i] = 8;
+ if (!elf_zlib_inflate_table (&codes[0], 287, &table[0], &table[0]))
+ {
+ fprintf (stderr, "elf_zlib_inflate_table failed\n");
+ exit (EXIT_FAILURE);
+ }
+
+ printf ("static const uint16_t elf_zlib_default_table[%#zx] =\n",
+ final_next_secondary + 0x100);
+ printf ("{\n");
+ for (i = 0; i < final_next_secondary + 0x100; i += 8)
+ {
+ size_t j;
+
+ printf (" ");
+ for (j = i; j < final_next_secondary + 0x100 && j < i + 8; ++j)
+ printf (" %#x,", table[j]);
+ printf ("\n");
+ }
+ printf ("};\n");
+ return 0;
+}
+
+#endif
+
+/* The fixed table generated by the #ifdef'ed out main function
+ above. */
+
+static const uint16_t elf_zlib_default_table[0x170] =
+{
+ 0xd00, 0xe50, 0xe10, 0xf18, 0xd10, 0xe70, 0xe30, 0x1232,
+ 0xd08, 0xe60, 0xe20, 0x1212, 0xe00, 0xe80, 0xe40, 0x1252,
+ 0xd04, 0xe58, 0xe18, 0x1202, 0xd14, 0xe78, 0xe38, 0x1242,
+ 0xd0c, 0xe68, 0xe28, 0x1222, 0xe08, 0xe88, 0xe48, 0x1262,
+ 0xd02, 0xe54, 0xe14, 0xf1c, 0xd12, 0xe74, 0xe34, 0x123a,
+ 0xd0a, 0xe64, 0xe24, 0x121a, 0xe04, 0xe84, 0xe44, 0x125a,
+ 0xd06, 0xe5c, 0xe1c, 0x120a, 0xd16, 0xe7c, 0xe3c, 0x124a,
+ 0xd0e, 0xe6c, 0xe2c, 0x122a, 0xe0c, 0xe8c, 0xe4c, 0x126a,
+ 0xd01, 0xe52, 0xe12, 0xf1a, 0xd11, 0xe72, 0xe32, 0x1236,
+ 0xd09, 0xe62, 0xe22, 0x1216, 0xe02, 0xe82, 0xe42, 0x1256,
+ 0xd05, 0xe5a, 0xe1a, 0x1206, 0xd15, 0xe7a, 0xe3a, 0x1246,
+ 0xd0d, 0xe6a, 0xe2a, 0x1226, 0xe0a, 0xe8a, 0xe4a, 0x1266,
+ 0xd03, 0xe56, 0xe16, 0xf1e, 0xd13, 0xe76, 0xe36, 0x123e,
+ 0xd0b, 0xe66, 0xe26, 0x121e, 0xe06, 0xe86, 0xe46, 0x125e,
+ 0xd07, 0xe5e, 0xe1e, 0x120e, 0xd17, 0xe7e, 0xe3e, 0x124e,
+ 0xd0f, 0xe6e, 0xe2e, 0x122e, 0xe0e, 0xe8e, 0xe4e, 0x126e,
+ 0xd00, 0xe51, 0xe11, 0xf19, 0xd10, 0xe71, 0xe31, 0x1234,
+ 0xd08, 0xe61, 0xe21, 0x1214, 0xe01, 0xe81, 0xe41, 0x1254,
+ 0xd04, 0xe59, 0xe19, 0x1204, 0xd14, 0xe79, 0xe39, 0x1244,
+ 0xd0c, 0xe69, 0xe29, 0x1224, 0xe09, 0xe89, 0xe49, 0x1264,
+ 0xd02, 0xe55, 0xe15, 0xf1d, 0xd12, 0xe75, 0xe35, 0x123c,
+ 0xd0a, 0xe65, 0xe25, 0x121c, 0xe05, 0xe85, 0xe45, 0x125c,
+ 0xd06, 0xe5d, 0xe1d, 0x120c, 0xd16, 0xe7d, 0xe3d, 0x124c,
+ 0xd0e, 0xe6d, 0xe2d, 0x122c, 0xe0d, 0xe8d, 0xe4d, 0x126c,
+ 0xd01, 0xe53, 0xe13, 0xf1b, 0xd11, 0xe73, 0xe33, 0x1238,
+ 0xd09, 0xe63, 0xe23, 0x1218, 0xe03, 0xe83, 0xe43, 0x1258,
+ 0xd05, 0xe5b, 0xe1b, 0x1208, 0xd15, 0xe7b, 0xe3b, 0x1248,
+ 0xd0d, 0xe6b, 0xe2b, 0x1228, 0xe0b, 0xe8b, 0xe4b, 0x1268,
+ 0xd03, 0xe57, 0xe17, 0x1200, 0xd13, 0xe77, 0xe37, 0x1240,
+ 0xd0b, 0xe67, 0xe27, 0x1220, 0xe07, 0xe87, 0xe47, 0x1260,
+ 0xd07, 0xe5f, 0xe1f, 0x1210, 0xd17, 0xe7f, 0xe3f, 0x1250,
+ 0xd0f, 0xe6f, 0xe2f, 0x1230, 0xe0f, 0xe8f, 0xe4f, 0,
+ 0x290, 0x291, 0x292, 0x293, 0x294, 0x295, 0x296, 0x297,
+ 0x298, 0x299, 0x29a, 0x29b, 0x29c, 0x29d, 0x29e, 0x29f,
+ 0x2a0, 0x2a1, 0x2a2, 0x2a3, 0x2a4, 0x2a5, 0x2a6, 0x2a7,
+ 0x2a8, 0x2a9, 0x2aa, 0x2ab, 0x2ac, 0x2ad, 0x2ae, 0x2af,
+ 0x2b0, 0x2b1, 0x2b2, 0x2b3, 0x2b4, 0x2b5, 0x2b6, 0x2b7,
+ 0x2b8, 0x2b9, 0x2ba, 0x2bb, 0x2bc, 0x2bd, 0x2be, 0x2bf,
+ 0x2c0, 0x2c1, 0x2c2, 0x2c3, 0x2c4, 0x2c5, 0x2c6, 0x2c7,
+ 0x2c8, 0x2c9, 0x2ca, 0x2cb, 0x2cc, 0x2cd, 0x2ce, 0x2cf,
+ 0x2d0, 0x2d1, 0x2d2, 0x2d3, 0x2d4, 0x2d5, 0x2d6, 0x2d7,
+ 0x2d8, 0x2d9, 0x2da, 0x2db, 0x2dc, 0x2dd, 0x2de, 0x2df,
+ 0x2e0, 0x2e1, 0x2e2, 0x2e3, 0x2e4, 0x2e5, 0x2e6, 0x2e7,
+ 0x2e8, 0x2e9, 0x2ea, 0x2eb, 0x2ec, 0x2ed, 0x2ee, 0x2ef,
+ 0x2f0, 0x2f1, 0x2f2, 0x2f3, 0x2f4, 0x2f5, 0x2f6, 0x2f7,
+ 0x2f8, 0x2f9, 0x2fa, 0x2fb, 0x2fc, 0x2fd, 0x2fe, 0x2ff,
+};
+
+/* Inflate a zlib stream from PIN/SIN to POUT/SOUT. Return 1 on
+ success, 0 on some error parsing the stream. */
+
+static int
+elf_zlib_inflate (const unsigned char *pin, size_t sin, uint16_t *zdebug_table,
+ unsigned char *pout, size_t sout)
+{
+ unsigned char *porigout;
+ const unsigned char *pinend;
+ unsigned char *poutend;
+
+ /* We can apparently see multiple zlib streams concatenated
+ together, so keep going as long as there is something to read.
+ The last 4 bytes are the checksum. */
+ porigout = pout;
+ pinend = pin + sin;
+ poutend = pout + sout;
+ while ((pinend - pin) > 4)
+ {
+ uint64_t val;
+ unsigned int bits;
+ int last;
+
+ /* Read the two byte zlib header. */
+
+ if (unlikely ((pin[0] & 0xf) != 8)) /* 8 is zlib encoding. */
+ {
+ /* Unknown compression method. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ if (unlikely ((pin[0] >> 4) > 7))
+ {
+ /* Window size too large. Other than this check, we don't
+ care about the window size. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ if (unlikely ((pin[1] & 0x20) != 0))
+ {
+ /* Stream expects a predefined dictionary, but we have no
+ dictionary. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ val = (pin[0] << 8) | pin[1];
+ if (unlikely (val % 31 != 0))
+ {
+ /* Header check failure. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ pin += 2;
+
+ /* Align PIN to a 32-bit boundary. */
+
+ val = 0;
+ bits = 0;
+ while ((((uintptr_t) pin) & 3) != 0)
+ {
+ val |= (uint64_t)*pin << bits;
+ bits += 8;
+ ++pin;
+ }
+
+ /* Read blocks until one is marked last. */
+
+ last = 0;
+
+ while (!last)
+ {
+ unsigned int type;
+ const uint16_t *tlit;
+ const uint16_t *tdist;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ last = val & 1;
+ type = (val >> 1) & 3;
+ val >>= 3;
+ bits -= 3;
+
+ if (unlikely (type == 3))
+ {
+ /* Invalid block type. */
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (type == 0)
+ {
+ uint16_t len;
+ uint16_t lenc;
+
+ /* An uncompressed block. */
+
+ /* If we've read ahead more than a byte, back up. */
+ while (bits > 8)
+ {
+ --pin;
+ bits -= 8;
+ }
+
+ val = 0;
+ bits = 0;
+ if (unlikely ((pinend - pin) < 4))
+ {
+ /* Missing length. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ len = pin[0] | (pin[1] << 8);
+ lenc = pin[2] | (pin[3] << 8);
+ pin += 4;
+ lenc = ~lenc;
+ if (unlikely (len != lenc))
+ {
+ /* Corrupt data. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ if (unlikely (len > (unsigned int) (pinend - pin)
+ || len > (unsigned int) (poutend - pout)))
+ {
+ /* Not enough space in buffers. */
+ elf_zlib_failed ();
+ return 0;
+ }
+ memcpy (pout, pin, len);
+ pout += len;
+ pin += len;
+
+ /* Align PIN. */
+ while ((((uintptr_t) pin) & 3) != 0)
+ {
+ val |= (uint64_t)*pin << bits;
+ bits += 8;
+ ++pin;
+ }
+
+ /* Go around to read the next block. */
+ continue;
+ }
+
+ if (type == 1)
+ {
+ tlit = elf_zlib_default_table;
+ tdist = elf_zlib_default_table;
+ }
+ else
+ {
+ unsigned int nlit;
+ unsigned int ndist;
+ unsigned int nclen;
+ unsigned char codebits[19];
+ unsigned char *plenbase;
+ unsigned char *plen;
+ unsigned char *plenend;
+
+ /* Read a Huffman encoding table. The various magic
+ numbers here are from RFC 1951. */
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ nlit = (val & 0x1f) + 257;
+ val >>= 5;
+ ndist = (val & 0x1f) + 1;
+ val >>= 5;
+ nclen = (val & 0xf) + 4;
+ val >>= 4;
+ bits -= 14;
+ if (unlikely (nlit > 286 || ndist > 30))
+ {
+ /* Values out of range. */
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* Read and build the table used to compress the
+ literal, length, and distance codes. */
+
+ memset(&codebits[0], 0, 19);
+
+ /* There are always at least 4 elements in the
+ table. */
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ codebits[16] = val & 7;
+ codebits[17] = (val >> 3) & 7;
+ codebits[18] = (val >> 6) & 7;
+ codebits[0] = (val >> 9) & 7;
+ val >>= 12;
+ bits -= 12;
+
+ if (nclen == 4)
+ goto codebitsdone;
+
+ codebits[8] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 5)
+ goto codebitsdone;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ codebits[7] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 6)
+ goto codebitsdone;
+
+ codebits[9] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 7)
+ goto codebitsdone;
+
+ codebits[6] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 8)
+ goto codebitsdone;
+
+ codebits[10] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 9)
+ goto codebitsdone;
+
+ codebits[5] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 10)
+ goto codebitsdone;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ codebits[11] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 11)
+ goto codebitsdone;
+
+ codebits[4] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 12)
+ goto codebitsdone;
+
+ codebits[12] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 13)
+ goto codebitsdone;
+
+ codebits[3] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 14)
+ goto codebitsdone;
+
+ codebits[13] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 15)
+ goto codebitsdone;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ codebits[2] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 16)
+ goto codebitsdone;
+
+ codebits[14] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 17)
+ goto codebitsdone;
+
+ codebits[1] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ if (nclen == 18)
+ goto codebitsdone;
+
+ codebits[15] = val & 7;
+ val >>= 3;
+ bits -= 3;
+
+ codebitsdone:
+
+ if (!elf_zlib_inflate_table (codebits, 19, zdebug_table,
+ zdebug_table))
+ return 0;
+
+ /* Read the compressed bit lengths of the literal,
+ length, and distance codes. We have allocated space
+ at the end of zdebug_table to hold them. */
+
+ plenbase = (((unsigned char *) zdebug_table)
+ + ZDEBUG_TABLE_CODELEN_OFFSET);
+ plen = plenbase;
+ plenend = plen + nlit + ndist;
+ while (plen < plenend)
+ {
+ uint16_t t;
+ unsigned int b;
+ uint16_t v;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ t = zdebug_table[val & 0xff];
+
+ /* The compression here uses bit lengths up to 7, so
+ a secondary table is never necessary. */
+ if (unlikely ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) != 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ val >>= b + 1;
+ bits -= b + 1;
+
+ v = t & HUFFMAN_VALUE_MASK;
+ if (v < 16)
+ *plen++ = v;
+ else if (v == 16)
+ {
+ unsigned int c;
+ unsigned int prev;
+
+ /* Copy previous entry 3 to 6 times. */
+
+ if (unlikely (plen == plenbase))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* We used up to 7 bits since the last
+ elf_zlib_fetch, so we have at least 8 bits
+ available here. */
+
+ c = 3 + (val & 0x3);
+ val >>= 2;
+ bits -= 2;
+ if (unlikely ((unsigned int) (plenend - plen) < c))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ prev = plen[-1];
+ switch (c)
+ {
+ case 6:
+ *plen++ = prev;
+ /* fallthrough */
+ case 5:
+ *plen++ = prev;
+ /* fallthrough */
+ case 4:
+ *plen++ = prev;
+ }
+ *plen++ = prev;
+ *plen++ = prev;
+ *plen++ = prev;
+ }
+ else if (v == 17)
+ {
+ unsigned int c;
+
+ /* Store zero 3 to 10 times. */
+
+ /* We used up to 7 bits since the last
+ elf_zlib_fetch, so we have at least 8 bits
+ available here. */
+
+ c = 3 + (val & 0x7);
+ val >>= 3;
+ bits -= 3;
+ if (unlikely ((unsigned int) (plenend - plen) < c))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ switch (c)
+ {
+ case 10:
+ *plen++ = 0;
+ /* fallthrough */
+ case 9:
+ *plen++ = 0;
+ /* fallthrough */
+ case 8:
+ *plen++ = 0;
+ /* fallthrough */
+ case 7:
+ *plen++ = 0;
+ /* fallthrough */
+ case 6:
+ *plen++ = 0;
+ /* fallthrough */
+ case 5:
+ *plen++ = 0;
+ /* fallthrough */
+ case 4:
+ *plen++ = 0;
+ }
+ *plen++ = 0;
+ *plen++ = 0;
+ *plen++ = 0;
+ }
+ else if (v == 18)
+ {
+ unsigned int c;
+
+ /* Store zero 11 to 138 times. */
+
+ /* We used up to 7 bits since the last
+ elf_zlib_fetch, so we have at least 8 bits
+ available here. */
+
+ c = 11 + (val & 0x7f);
+ val >>= 7;
+ bits -= 7;
+ if (unlikely ((unsigned int) (plenend - plen) < c))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ memset (plen, 0, c);
+ plen += c;
+ }
+ else
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ }
+
+ /* Make sure that the stop code can appear. */
+
+ plen = plenbase;
+ if (unlikely (plen[256] == 0))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ /* Build the decompression tables. */
+
+ if (!elf_zlib_inflate_table (plen, nlit, zdebug_table,
+ zdebug_table))
+ return 0;
+ if (!elf_zlib_inflate_table (plen + nlit, ndist, zdebug_table,
+ zdebug_table + HUFFMAN_TABLE_SIZE))
+ return 0;
+ tlit = zdebug_table;
+ tdist = zdebug_table + HUFFMAN_TABLE_SIZE;
+ }
+
+ /* Inflate values until the end of the block. This is the
+ main loop of the inflation code. */
+
+ while (1)
+ {
+ uint16_t t;
+ unsigned int b;
+ uint16_t v;
+ unsigned int lit;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ t = tlit[val & 0xff];
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ v = t & HUFFMAN_VALUE_MASK;
+
+ if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0)
+ {
+ lit = v;
+ val >>= b + 1;
+ bits -= b + 1;
+ }
+ else
+ {
+ t = tlit[v + 0x100 + ((val >> 8) & ((1U << b) - 1))];
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ lit = t & HUFFMAN_VALUE_MASK;
+ val >>= b + 8;
+ bits -= b + 8;
+ }
+
+ if (lit < 256)
+ {
+ if (unlikely (pout == poutend))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ *pout++ = lit;
+
+ /* We will need to write the next byte soon. We ask
+ for high temporal locality because we will write
+ to the whole cache line soon. */
+ __builtin_prefetch (pout, 1, 3);
+ }
+ else if (lit == 256)
+ {
+ /* The end of the block. */
+ break;
+ }
+ else
+ {
+ unsigned int dist;
+ unsigned int len;
+
+ /* Convert lit into a length. */
+
+ if (lit < 265)
+ len = lit - 257 + 3;
+ else if (lit == 285)
+ len = 258;
+ else if (unlikely (lit > 285))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ else
+ {
+ unsigned int extra;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ /* This is an expression for the table of length
+ codes in RFC 1951 3.2.5. */
+ lit -= 265;
+ extra = (lit >> 2) + 1;
+ len = (lit & 3) << extra;
+ len += 11;
+ len += ((1U << (extra - 1)) - 1) << 3;
+ len += val & ((1U << extra) - 1);
+ val >>= extra;
+ bits -= extra;
+ }
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ t = tdist[val & 0xff];
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ v = t & HUFFMAN_VALUE_MASK;
+
+ if ((t & (1U << HUFFMAN_SECONDARY_SHIFT)) == 0)
+ {
+ dist = v;
+ val >>= b + 1;
+ bits -= b + 1;
+ }
+ else
+ {
+ t = tdist[v + 0x100 + ((val >> 8) & ((1U << b) - 1))];
+ b = (t >> HUFFMAN_BITS_SHIFT) & HUFFMAN_BITS_MASK;
+ dist = t & HUFFMAN_VALUE_MASK;
+ val >>= b + 8;
+ bits -= b + 8;
+ }
+
+ /* Convert dist to a distance. */
+
+ if (dist == 0)
+ {
+ /* A distance of 1. A common case, meaning
+ repeat the last character LEN times. */
+
+ if (unlikely (pout == porigout))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (unlikely ((unsigned int) (poutend - pout) < len))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ memset (pout, pout[-1], len);
+ pout += len;
+ }
+ else if (unlikely (dist > 29))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+ else
+ {
+ if (dist < 4)
+ dist = dist + 1;
+ else
+ {
+ unsigned int extra;
+
+ if (!elf_zlib_fetch (&pin, pinend, &val, &bits))
+ return 0;
+
+ /* This is an expression for the table of
+ distance codes in RFC 1951 3.2.5. */
+ dist -= 4;
+ extra = (dist >> 1) + 1;
+ dist = (dist & 1) << extra;
+ dist += 5;
+ dist += ((1U << (extra - 1)) - 1) << 2;
+ dist += val & ((1U << extra) - 1);
+ val >>= extra;
+ bits -= extra;
+ }
+
+ /* Go back dist bytes, and copy len bytes from
+ there. */
+
+ if (unlikely ((unsigned int) (pout - porigout) < dist))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (unlikely ((unsigned int) (poutend - pout) < len))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ if (dist >= len)
+ {
+ memcpy (pout, pout - dist, len);
+ pout += len;
+ }
+ else
+ {
+ while (len > 0)
+ {
+ unsigned int copy;
+
+ copy = len < dist ? len : dist;
+ memcpy (pout, pout - dist, copy);
+ len -= copy;
+ pout += copy;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* We should have filled the output buffer. */
+ if (unlikely (pout != poutend))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Verify the zlib checksum. The checksum is in the 4 bytes at
+ CHECKBYTES, and the uncompressed data is at UNCOMPRESSED /
+ UNCOMPRESSED_SIZE. Returns 1 on success, 0 on failure. */
+
+static int
+elf_zlib_verify_checksum (const unsigned char *checkbytes,
+ const unsigned char *uncompressed,
+ size_t uncompressed_size)
+{
+ unsigned int i;
+ unsigned int cksum;
+ const unsigned char *p;
+ uint32_t s1;
+ uint32_t s2;
+ size_t hsz;
+
+ cksum = 0;
+ for (i = 0; i < 4; i++)
+ cksum = (cksum << 8) | checkbytes[i];
+
+ s1 = 1;
+ s2 = 0;
+
+ /* Minimize modulo operations. */
+
+ p = uncompressed;
+ hsz = uncompressed_size;
+ while (hsz >= 5552)
+ {
+ for (i = 0; i < 5552; i += 16)
+ {
+ /* Manually unroll loop 16 times. */
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ }
+ hsz -= 5552;
+ s1 %= 65521;
+ s2 %= 65521;
+ }
+
+ while (hsz >= 16)
+ {
+ /* Manually unroll loop 16 times. */
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+
+ hsz -= 16;
+ }
+
+ for (i = 0; i < hsz; ++i)
+ {
+ s1 = s1 + *p++;
+ s2 = s2 + s1;
+ }
+
+ s1 %= 65521;
+ s2 %= 65521;
+
+ if (unlikely ((s2 << 16) + s1 != cksum))
+ {
+ elf_zlib_failed ();
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Inflate a zlib stream from PIN/SIN to POUT/SOUT, and verify the
+ checksum. Return 1 on success, 0 on error. */
+
+static int
+elf_zlib_inflate_and_verify (const unsigned char *pin, size_t sin,
+ uint16_t *zdebug_table, unsigned char *pout,
+ size_t sout)
+{
+ if (!elf_zlib_inflate (pin, sin, zdebug_table, pout, sout))
+ return 0;
+ if (!elf_zlib_verify_checksum (pin + sin - 4, pout, sout))
+ return 0;
+ return 1;
+}
+
+/* Uncompress the old compressed debug format, the one emitted by
+ --compress-debug-sections=zlib-gnu. The compressed data is in
+ COMPRESSED / COMPRESSED_SIZE, and the function writes to
+ *UNCOMPRESSED / *UNCOMPRESSED_SIZE. ZDEBUG_TABLE is work space to
+ hold Huffman tables. Returns 0 on error, 1 on successful
+ decompression or if something goes wrong. In general we try to
+ carry on, by returning 1, even if we can't decompress. */
+
+static int
+elf_uncompress_zdebug (struct backtrace_state *state,
+ const unsigned char *compressed, size_t compressed_size,
+ uint16_t *zdebug_table,
+ backtrace_error_callback error_callback, void *data,
+ unsigned char **uncompressed, size_t *uncompressed_size)
+{
+ size_t sz;
+ size_t i;
+ unsigned char *po;
+
+ *uncompressed = NULL;
+ *uncompressed_size = 0;
+
+ /* The format starts with the four bytes ZLIB, followed by the 8
+ byte length of the uncompressed data in big-endian order,
+ followed by a zlib stream. */
+
+ if (compressed_size < 12 || memcmp (compressed, "ZLIB", 4) != 0)
+ return 1;
+
+ sz = 0;
+ for (i = 0; i < 8; i++)
+ sz = (sz << 8) | compressed[i + 4];
+
+ if (*uncompressed != NULL && *uncompressed_size >= sz)
+ po = *uncompressed;
+ else
+ {
+ po = (unsigned char *) backtrace_alloc (state, sz, error_callback, data);
+ if (po == NULL)
+ return 0;
+ }
+
+ if (!elf_zlib_inflate_and_verify (compressed + 12, compressed_size - 12,
+ zdebug_table, po, sz))
+ return 1;
+
+ *uncompressed = po;
+ *uncompressed_size = sz;
+
+ return 1;
+}
+
+/* Uncompress the new compressed debug format, the official standard
+ ELF approach emitted by --compress-debug-sections=zlib-gabi. The
+ compressed data is in COMPRESSED / COMPRESSED_SIZE, and the
+ function writes to *UNCOMPRESSED / *UNCOMPRESSED_SIZE.
+ ZDEBUG_TABLE is work space as for elf_uncompress_zdebug. Returns 0
+ on error, 1 on successful decompression or if something goes wrong.
+ In general we try to carry on, by returning 1, even if we can't
+ decompress. */
+
+static int
+elf_uncompress_chdr (struct backtrace_state *state,
+ const unsigned char *compressed, size_t compressed_size,
+ uint16_t *zdebug_table,
+ backtrace_error_callback error_callback, void *data,
+ unsigned char **uncompressed, size_t *uncompressed_size)
+{
+ const b_elf_chdr *chdr;
+ unsigned char *po;
+
+ *uncompressed = NULL;
+ *uncompressed_size = 0;
+
+ /* The format starts with an ELF compression header. */
+ if (compressed_size < sizeof (b_elf_chdr))
+ return 1;
+
+ chdr = (const b_elf_chdr *) compressed;
+
+ if (chdr->ch_type != ELFCOMPRESS_ZLIB)
+ {
+ /* Unsupported compression algorithm. */
+ return 1;
+ }
+
+ if (*uncompressed != NULL && *uncompressed_size >= chdr->ch_size)
+ po = *uncompressed;
+ else
+ {
+ po = (unsigned char *) backtrace_alloc (state, chdr->ch_size,
+ error_callback, data);
+ if (po == NULL)
+ return 0;
+ }
+
+ if (!elf_zlib_inflate_and_verify (compressed + sizeof (b_elf_chdr),
+ compressed_size - sizeof (b_elf_chdr),
+ zdebug_table, po, chdr->ch_size))
+ return 1;
+
+ *uncompressed = po;
+ *uncompressed_size = chdr->ch_size;
+
+ return 1;
+}
+
+/* This function is a hook for testing the zlib support. It is only
+ used by tests. */
+
+int
+backtrace_uncompress_zdebug (struct backtrace_state *state,
+ const unsigned char *compressed,
+ size_t compressed_size,
+ backtrace_error_callback error_callback,
+ void *data, unsigned char **uncompressed,
+ size_t *uncompressed_size)
+{
+ uint16_t *zdebug_table;
+ int ret;
+
+ zdebug_table = ((uint16_t *) backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+ error_callback, data));
+ if (zdebug_table == NULL)
+ return 0;
+ ret = elf_uncompress_zdebug (state, compressed, compressed_size,
+ zdebug_table, error_callback, data,
+ uncompressed, uncompressed_size);
+ backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,
+ error_callback, data);
+ return ret;
+}
+
/* Add the backtrace data for one ELF file. Returns 1 on success,
0 on failure (in both cases descriptor is closed) or -1 if exe
is non-zero and the ELF file is ET_DYN, which tells the caller that
@@ -517,9 +2532,10 @@ elf_syminfo (struct backtrace_state *state, uintptr_t addr,
base_address is determined. */
static int
-elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
- backtrace_error_callback error_callback, void *data,
- fileline *fileline_fn, int *found_sym, int *found_dwarf, int exe)
+elf_add (struct backtrace_state *state, const char *filename, int descriptor,
+ uintptr_t base_address, backtrace_error_callback error_callback,
+ void *data, fileline *fileline_fn, int *found_sym, int *found_dwarf,
+ int exe, int debuginfo)
{
struct backtrace_view ehdr_view;
b_elf_ehdr ehdr;
@@ -543,10 +2559,20 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
int symtab_view_valid;
struct backtrace_view strtab_view;
int strtab_view_valid;
+ struct backtrace_view buildid_view;
+ int buildid_view_valid;
+ const char *buildid_data;
+ uint32_t buildid_size;
+ struct backtrace_view debuglink_view;
+ int debuglink_view_valid;
+ const char *debuglink_name;
+ uint32_t debuglink_crc;
off_t min_offset;
off_t max_offset;
struct backtrace_view debug_view;
int debug_view_valid;
+ unsigned int using_debug_view;
+ uint16_t *zdebug_table;
*found_sym = 0;
*found_dwarf = 0;
@@ -555,6 +2581,12 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
names_view_valid = 0;
symtab_view_valid = 0;
strtab_view_valid = 0;
+ buildid_view_valid = 0;
+ buildid_data = NULL;
+ buildid_size = 0;
+ debuglink_view_valid = 0;
+ debuglink_name = NULL;
+ debuglink_crc = 0;
debug_view_valid = 0;
if (!backtrace_get_view (state, descriptor, 0, sizeof ehdr, error_callback,
@@ -704,14 +2736,65 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
{
sections[j].offset = shdr->sh_offset;
sections[j].size = shdr->sh_size;
+ sections[j].compressed = (shdr->sh_flags & SHF_COMPRESSED) != 0;
break;
}
}
+
+ /* Read the build ID if present. This could check for any
+ SHT_NOTE section with the right note name and type, but gdb
+ looks for a specific section name. */
+ if (!debuginfo
+ && !buildid_view_valid
+ && strcmp (name, ".note.gnu.build-id") == 0)
+ {
+ const b_elf_note *note;
+
+ if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ &buildid_view))
+ goto fail;
+
+ buildid_view_valid = 1;
+ note = (const b_elf_note *) buildid_view.data;
+ if (note->type == NT_GNU_BUILD_ID
+ && note->namesz == 4
+ && strncmp (note->name, "GNU", 4) == 0
+ && shdr->sh_size < 12 + ((note->namesz + 3) & ~ 3) + note->descsz)
+ {
+ buildid_data = &note->name[0] + ((note->namesz + 3) & ~ 3);
+ buildid_size = note->descsz;
+ }
+ }
+
+ /* Read the debuglink file if present. */
+ if (!debuginfo
+ && !debuglink_view_valid
+ && strcmp (name, ".gnu_debuglink") == 0)
+ {
+ const char *debuglink_data;
+ size_t crc_offset;
+
+ if (!backtrace_get_view (state, descriptor, shdr->sh_offset,
+ shdr->sh_size, error_callback, data,
+ &debuglink_view))
+ goto fail;
+
+ debuglink_view_valid = 1;
+ debuglink_data = (const char *) debuglink_view.data;
+ crc_offset = strnlen (debuglink_data, shdr->sh_size);
+ crc_offset = (crc_offset + 3) & ~3;
+ if (crc_offset + 4 <= shdr->sh_size)
+ {
+ debuglink_name = debuglink_data;
+ debuglink_crc = *(const uint32_t*)(debuglink_data + crc_offset);
+ }
+ }
}
if (symtab_shndx == 0)
symtab_shndx = dynsym_shndx;
- if (symtab_shndx != 0)
+ if (symtab_shndx != 0 && !debuginfo)
{
const b_elf_shdr *symtab_shdr;
unsigned int strtab_shndx;
@@ -757,19 +2840,65 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
/* We no longer need the symbol table, but we hold on to the
string table permanently. */
backtrace_release_view (state, &symtab_view, error_callback, data);
+ symtab_view_valid = 0;
*found_sym = 1;
elf_add_syminfo_data (state, sdata);
}
- /* FIXME: Need to handle compressed debug sections. */
-
backtrace_release_view (state, &shdrs_view, error_callback, data);
shdrs_view_valid = 0;
backtrace_release_view (state, &names_view, error_callback, data);
names_view_valid = 0;
+ /* If the debug info is in a separate file, read that one instead. */
+
+ if (buildid_data != NULL)
+ {
+ int d;
+
+ d = elf_open_debugfile_by_buildid (state, buildid_data, buildid_size,
+ error_callback, data);
+ if (d >= 0)
+ {
+ backtrace_release_view (state, &buildid_view, error_callback, data);
+ if (debuglink_view_valid)
+ backtrace_release_view (state, &debuglink_view, error_callback,
+ data);
+ return elf_add (state, NULL, d, base_address, error_callback, data,
+ fileline_fn, found_sym, found_dwarf, 0, 1);
+ }
+ }
+
+ if (buildid_view_valid)
+ {
+ backtrace_release_view (state, &buildid_view, error_callback, data);
+ buildid_view_valid = 0;
+ }
+
+ if (debuglink_name != NULL)
+ {
+ int d;
+
+ d = elf_open_debugfile_by_debuglink (state, filename, debuglink_name,
+ debuglink_crc, error_callback,
+ data);
+ if (d >= 0)
+ {
+ backtrace_release_view (state, &debuglink_view, error_callback,
+ data);
+ return elf_add (state, NULL, d, base_address, error_callback, data,
+ fileline_fn, found_sym, found_dwarf, 0, 1);
+ }
+ }
+
+ if (debuglink_view_valid)
+ {
+ backtrace_release_view (state, &debuglink_view, error_callback, data);
+ debuglink_view_valid = 0;
+ }
+
/* Read all the debug sections in a single view, since they are
probably adjacent in the file. We never release this view. */
@@ -805,13 +2934,94 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
goto fail;
descriptor = -1;
+ using_debug_view = 0;
for (i = 0; i < (int) DEBUG_MAX; ++i)
{
if (sections[i].size == 0)
sections[i].data = NULL;
else
- sections[i].data = ((const unsigned char *) debug_view.data
- + (sections[i].offset - min_offset));
+ {
+ sections[i].data = ((const unsigned char *) debug_view.data
+ + (sections[i].offset - min_offset));
+ if (i < ZDEBUG_INFO)
+ ++using_debug_view;
+ }
+ }
+
+ /* Uncompress the old format (--compress-debug-sections=zlib-gnu). */
+
+ zdebug_table = NULL;
+ for (i = 0; i < ZDEBUG_INFO; ++i)
+ {
+ struct debug_section_info *pz;
+
+ pz = &sections[i + ZDEBUG_INFO - DEBUG_INFO];
+ if (sections[i].size == 0 && pz->size > 0)
+ {
+ unsigned char *uncompressed_data;
+ size_t uncompressed_size;
+
+ if (zdebug_table == NULL)
+ {
+ zdebug_table = ((uint16_t *)
+ backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+ error_callback, data));
+ if (zdebug_table == NULL)
+ goto fail;
+ }
+
+ uncompressed_data = NULL;
+ uncompressed_size = 0;
+ if (!elf_uncompress_zdebug (state, pz->data, pz->size, zdebug_table,
+ error_callback, data,
+ &uncompressed_data, &uncompressed_size))
+ goto fail;
+ sections[i].data = uncompressed_data;
+ sections[i].size = uncompressed_size;
+ sections[i].compressed = 0;
+ }
+ }
+
+ /* Uncompress the official ELF format
+ (--compress-debug-sections=zlib-gabi). */
+ for (i = 0; i < ZDEBUG_INFO; ++i)
+ {
+ unsigned char *uncompressed_data;
+ size_t uncompressed_size;
+
+ if (sections[i].size == 0 || !sections[i].compressed)
+ continue;
+
+ if (zdebug_table == NULL)
+ {
+ zdebug_table = ((uint16_t *)
+ backtrace_alloc (state, ZDEBUG_TABLE_SIZE,
+ error_callback, data));
+ if (zdebug_table == NULL)
+ goto fail;
+ }
+
+ uncompressed_data = NULL;
+ uncompressed_size = 0;
+ if (!elf_uncompress_chdr (state, sections[i].data, sections[i].size,
+ zdebug_table, error_callback, data,
+ &uncompressed_data, &uncompressed_size))
+ goto fail;
+ sections[i].data = uncompressed_data;
+ sections[i].size = uncompressed_size;
+ sections[i].compressed = 0;
+
+ --using_debug_view;
+ }
+
+ if (zdebug_table != NULL)
+ backtrace_free (state, zdebug_table, ZDEBUG_TABLE_SIZE,
+ error_callback, data);
+
+ if (debug_view_valid && using_debug_view == 0)
+ {
+ backtrace_release_view (state, &debug_view, error_callback, data);
+ debug_view_valid = 0;
}
if (!backtrace_dwarf_add (state, base_address,
@@ -842,6 +3052,10 @@ elf_add (struct backtrace_state *state, int descriptor, uintptr_t base_address,
backtrace_release_view (state, &symtab_view, error_callback, data);
if (strtab_view_valid)
backtrace_release_view (state, &strtab_view, error_callback, data);
+ if (debuglink_view_valid)
+ backtrace_release_view (state, &debuglink_view, error_callback, data);
+ if (buildid_view_valid)
+ backtrace_release_view (state, &buildid_view, error_callback, data);
if (debug_view_valid)
backtrace_release_view (state, &debug_view, error_callback, data);
if (descriptor != -1)
@@ -859,6 +3073,7 @@ struct phdr_data
fileline *fileline_fn;
int *found_sym;
int *found_dwarf;
+ const char *exe_filename;
int exe_descriptor;
};
@@ -873,6 +3088,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
void *pdata)
{
struct phdr_data *pd = (struct phdr_data *) pdata;
+ const char *filename;
int descriptor;
int does_not_exist;
fileline elf_fileline_fn;
@@ -885,6 +3101,7 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
{
if (pd->exe_descriptor == -1)
return 0;
+ filename = pd->exe_filename;
descriptor = pd->exe_descriptor;
pd->exe_descriptor = -1;
}
@@ -896,14 +3113,16 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
pd->exe_descriptor = -1;
}
+ filename = info->dlpi_name;
descriptor = backtrace_open (info->dlpi_name, pd->error_callback,
pd->data, &does_not_exist);
if (descriptor < 0)
return 0;
}
- if (elf_add (pd->state, descriptor, info->dlpi_addr, pd->error_callback,
- pd->data, &elf_fileline_fn, pd->found_sym, &found_dwarf, 0))
+ if (elf_add (pd->state, filename, descriptor, info->dlpi_addr,
+ pd->error_callback, pd->data, &elf_fileline_fn, pd->found_sym,
+ &found_dwarf, 0, 0))
{
if (found_dwarf)
{
@@ -920,8 +3139,8 @@ phdr_callback (struct dl_phdr_info *info, size_t size ATTRIBUTE_UNUSED,
sections. */
int
-backtrace_initialize (struct backtrace_state *state, int descriptor,
- backtrace_error_callback error_callback,
+backtrace_initialize (struct backtrace_state *state, const char *filename,
+ int descriptor, backtrace_error_callback error_callback,
void *data, fileline *fileline_fn)
{
int ret;
@@ -930,8 +3149,8 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
fileline elf_fileline_fn = elf_nodebug;
struct phdr_data pd;
- ret = elf_add (state, descriptor, 0, error_callback, data, &elf_fileline_fn,
- &found_sym, &found_dwarf, 1);
+ ret = elf_add (state, filename, descriptor, 0, error_callback, data,
+ &elf_fileline_fn, &found_sym, &found_dwarf, 1, 0);
if (!ret)
return 0;
@@ -941,6 +3160,7 @@ backtrace_initialize (struct backtrace_state *state, int descriptor,
pd.fileline_fn = &elf_fileline_fn;
pd.found_sym = &found_sym;
pd.found_dwarf = &found_dwarf;
+ pd.exe_filename = filename;
pd.exe_descriptor = ret < 0 ? descriptor : -1;
dl_iterate_phdr (phdr_callback, (void *) &pd);
diff --git a/libbacktrace/fileline.c b/libbacktrace/fileline.c
index 6812058..babbe53 100644
--- a/libbacktrace/fileline.c
+++ b/libbacktrace/fileline.c
@@ -58,6 +58,7 @@ fileline_initialize (struct backtrace_state *state,
int pass;
int called_error_callback;
int descriptor;
+ const char *filename;
char buf[64];
if (!state->threaded)
@@ -84,7 +85,6 @@ fileline_initialize (struct backtrace_state *state,
called_error_callback = 0;
for (pass = 0; pass < 5; ++pass)
{
- const char *filename;
int does_not_exist;
switch (pass)
@@ -140,8 +140,8 @@ fileline_initialize (struct backtrace_state *state,
if (!failed)
{
- if (!backtrace_initialize (state, descriptor, error_callback, data,
- &fileline_fn))
+ if (!backtrace_initialize (state, filename, descriptor, error_callback,
+ data, &fileline_fn))
failed = 1;
}
diff --git a/libbacktrace/internal.h b/libbacktrace/internal.h
index 89b7bf7..0617996 100644
--- a/libbacktrace/internal.h
+++ b/libbacktrace/internal.h
@@ -268,6 +268,7 @@ extern int backtrace_vector_release (struct backtrace_state *state,
appropriate one. */
extern int backtrace_initialize (struct backtrace_state *state,
+ const char *filename,
int descriptor,
backtrace_error_callback error_callback,
void *data,
@@ -291,4 +292,13 @@ extern int backtrace_dwarf_add (struct backtrace_state *state,
backtrace_error_callback error_callback,
void *data, fileline *fileline_fn);
+/* A test-only hook for elf_uncompress_zdebug. */
+
+extern int backtrace_uncompress_zdebug (struct backtrace_state *,
+ const unsigned char *compressed,
+ size_t compressed_size,
+ backtrace_error_callback, void *data,
+ unsigned char **uncompressed,
+ size_t *uncompressed_size);
+
#endif
diff --git a/libbacktrace/pecoff.c b/libbacktrace/pecoff.c
index 78152c3..2204dd0 100644
--- a/libbacktrace/pecoff.c
+++ b/libbacktrace/pecoff.c
@@ -890,7 +890,8 @@ coff_add (struct backtrace_state *state, int descriptor,
sections. */
int
-backtrace_initialize (struct backtrace_state *state, int descriptor,
+backtrace_initialize (struct backtrace_state *state,
+ const char *filename ATTRIBUTE_UNUSED, int descriptor,
backtrace_error_callback error_callback,
void *data, fileline *fileline_fn)
{
diff --git a/libbacktrace/unknown.c b/libbacktrace/unknown.c
index 867755b..5df6d15 100644
--- a/libbacktrace/unknown.c
+++ b/libbacktrace/unknown.c
@@ -54,6 +54,7 @@ unknown_fileline (struct backtrace_state *state ATTRIBUTE_UNUSED,
int
backtrace_initialize (struct backtrace_state *state ATTRIBUTE_UNUSED,
+ const char *filename ATTRIBUTE_UNUSED,
int descriptor ATTRIBUTE_UNUSED,
backtrace_error_callback error_callback ATTRIBUTE_UNUSED,
void *data ATTRIBUTE_UNUSED, fileline *fileline_fn)
diff --git a/libbacktrace/xcoff.c b/libbacktrace/xcoff.c
index b3d7e24..f84bf26 100644
--- a/libbacktrace/xcoff.c
+++ b/libbacktrace/xcoff.c
@@ -124,9 +124,16 @@ typedef struct {
#endif /* BACKTRACE_XCOFF_SIZE != 32 */
+#define STYP_DWARF 0x10 /* DWARF debugging section. */
#define STYP_TEXT 0x20 /* Executable text (code) section. */
#define STYP_OVRFLO 0x8000 /* Line-number field overflow section. */
+#define SSUBTYP_DWINFO 0x10000 /* DWARF info section. */
+#define SSUBTYP_DWLINE 0x20000 /* DWARF line-number section. */
+#define SSUBTYP_DWARNGE 0x50000 /* DWARF aranges section. */
+#define SSUBTYP_DWABREV 0x60000 /* DWARF abbreviation section. */
+#define SSUBTYP_DWSTR 0x70000 /* DWARF strings section. */
+
/* XCOFF symbol. */
#define SYMNMLEN 8
@@ -367,6 +374,29 @@ struct xcoff_fileline_data
struct xcoff_line_vector vec;
};
+/* An index of DWARF sections we care about. */
+
+enum dwarf_section
+{
+ DWSECT_INFO,
+ DWSECT_LINE,
+ DWSECT_ABBREV,
+ DWSECT_RANGES,
+ DWSECT_STR,
+ DWSECT_MAX
+};
+
+/* Information we gather for the DWARF sections we care about. */
+
+struct dwsect_info
+{
+ /* Section file offset. */
+ off_t offset;
+ /* Section size. */
+ size_t size;
+ /* Section contents, after read from file. */
+ const unsigned char *data;
+};
/* A dummy callback function used when we can't find any debug info. */
@@ -1056,12 +1086,16 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
struct backtrace_view linenos_view;
struct backtrace_view syms_view;
struct backtrace_view str_view;
+ struct backtrace_view dwarf_view;
b_xcoff_filhdr fhdr;
const b_xcoff_scnhdr *sects;
const b_xcoff_scnhdr *stext;
uint64_t lnnoptr;
uint32_t nlnno;
off_t str_off;
+ off_t min_offset;
+ off_t max_offset;
+ struct dwsect_info dwsect[DWSECT_MAX];
size_t sects_size;
size_t syms_size;
int32_t str_size;
@@ -1069,6 +1103,7 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
int linenos_view_valid;
int syms_view_valid;
int str_view_valid;
+ int dwarf_view_valid;
int magic_ok;
int i;
@@ -1078,6 +1113,9 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
linenos_view_valid = 0;
syms_view_valid = 0;
str_view_valid = 0;
+ dwarf_view_valid = 0;
+
+ str_size = 0;
/* Map the XCOFF file header. */
if (!backtrace_get_view (state, descriptor, offset, sizeof (b_xcoff_filhdr),
@@ -1092,7 +1130,7 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
if (!magic_ok)
{
if (exe)
- error_callback (data, "executable file is not XCOFF", 0);
+ error_callback (data, "executable file is not XCOFF", 0);
goto fail;
}
@@ -1114,8 +1152,8 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
/* FIXME: assumes only one .text section. */
for (i = 0; i < fhdr.f_nscns; ++i)
- if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
- break;
+ if ((sects[i].s_flags & 0xffff) == STYP_TEXT)
+ break;
if (i == fhdr.f_nscns)
goto fail;
@@ -1134,12 +1172,12 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
/* Find the matching .ovrflo section. */
for (i = 0; i < fhdr.f_nscns; ++i)
{
- if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO)
- && sects[i].s_nlnno == sntext)
- {
- nlnno = sects[i].s_vaddr;
- break;
- }
+ if (((sects[i].s_flags & 0xffff) == STYP_OVRFLO)
+ && sects[i].s_nlnno == sntext)
+ {
+ nlnno = sects[i].s_vaddr;
+ break;
+ }
}
}
#endif
@@ -1194,9 +1232,91 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
xcoff_add_syminfo_data (state, sdata);
}
- /* Read the line number entries. */
+ /* Read all the DWARF sections in a single view, since they are
+ probably adjacent in the file. We never release this view. */
+
+ min_offset = 0;
+ max_offset = 0;
+ memset (dwsect, 0, sizeof dwsect);
+ for (i = 0; i < fhdr.f_nscns; ++i)
+ {
+ off_t end;
+ int idx;
+
+ if ((sects[i].s_flags & 0xffff) != STYP_DWARF
+ || sects[i].s_size == 0)
+ continue;
+ /* Map DWARF section to array index. */
+ switch (sects[i].s_flags & 0xffff0000)
+ {
+ case SSUBTYP_DWINFO:
+ idx = DWSECT_INFO;
+ break;
+ case SSUBTYP_DWLINE:
+ idx = DWSECT_LINE;
+ break;
+ case SSUBTYP_DWABREV:
+ idx = DWSECT_ABBREV;
+ break;
+ case SSUBTYP_DWARNGE:
+ idx = DWSECT_RANGES;
+ break;
+ case SSUBTYP_DWSTR:
+ idx = DWSECT_STR;
+ break;
+ default:
+ continue;
+ }
+ if (min_offset == 0 || (off_t) sects[i].s_scnptr < min_offset)
+ min_offset = sects[i].s_scnptr;
+ end = sects[i].s_scnptr + sects[i].s_size;
+ if (end > max_offset)
+ max_offset = end;
+ dwsect[idx].offset = sects[i].s_scnptr;
+ dwsect[idx].size = sects[i].s_size;
+ }
+ if (min_offset != 0 && max_offset != 0)
+ {
+ if (!backtrace_get_view (state, descriptor, offset + min_offset,
+ max_offset - min_offset,
+ error_callback, data, &dwarf_view))
+ goto fail;
+ dwarf_view_valid = 1;
+
+ for (i = 0; i < (int) DWSECT_MAX; ++i)
+ {
+ if (dwsect[i].offset == 0)
+ dwsect[i].data = NULL;
+ else
+ dwsect[i].data = ((const unsigned char *) dwarf_view.data
+ + (dwsect[i].offset - min_offset));
+ }
+
+ if (!backtrace_dwarf_add (state, 0,
+ dwsect[DWSECT_INFO].data,
+ dwsect[DWSECT_INFO].size,
+#if BACKTRACE_XCOFF_SIZE == 32
+ /* XXX workaround for broken lineoff */
+ dwsect[DWSECT_LINE].data - 4,
+#else
+ /* XXX workaround for broken lineoff */
+ dwsect[DWSECT_LINE].data - 12,
+#endif
+ dwsect[DWSECT_LINE].size,
+ dwsect[DWSECT_ABBREV].data,
+ dwsect[DWSECT_ABBREV].size,
+ dwsect[DWSECT_RANGES].data,
+ dwsect[DWSECT_RANGES].size,
+ dwsect[DWSECT_STR].data,
+ dwsect[DWSECT_STR].size,
+ 1, /* big endian */
+ error_callback, data, fileline_fn))
+ goto fail;
+ }
+
+ /* Read the XCOFF line number entries if DWARF sections not found. */
- if (fhdr.f_symptr != 0 && lnnoptr != 0)
+ if (!dwarf_view_valid && fhdr.f_symptr != 0 && lnnoptr != 0)
{
size_t linenos_size = (size_t) nlnno * LINESZ;
@@ -1239,6 +1359,8 @@ xcoff_add (struct backtrace_state *state, int descriptor, off_t offset,
backtrace_release_view (state, &syms_view, error_callback, data);
if (linenos_view_valid)
backtrace_release_view (state, &linenos_view, error_callback, data);
+ if (dwarf_view_valid)
+ backtrace_release_view (state, &dwarf_view, error_callback, data);
if (descriptor != -1 && offset == 0)
backtrace_close (descriptor, error_callback, data);
return 0;
@@ -1434,7 +1556,8 @@ xcoff_add_shared_libs (struct backtrace_state *state,
Returns 1 on success, 0 on failure. */
int
-backtrace_initialize (struct backtrace_state *state, int descriptor,
+backtrace_initialize (struct backtrace_state *state,
+ const char *filename ATTRIBUTE_UNUSED, int descriptor,
backtrace_error_callback error_callback,
void *data, fileline *fileline_fn)
{
diff --git a/libbacktrace/ztest.c b/libbacktrace/ztest.c
new file mode 100644
index 0000000..9ce4b21
--- /dev/null
+++ b/libbacktrace/ztest.c
@@ -0,0 +1,474 @@
+/* ztest.c -- Test for libbacktrace inflate code.
+ Copyright (C) 2017 Free Software Foundation, Inc.
+ Written by Ian Lance Taylor, Google.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ (1) Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ (2) Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ (3) The name of the author may not be used to
+ endorse or promote products derived from this software without
+ specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE. */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_ZLIB
+#include <zlib.h>
+#endif
+
+#include "backtrace.h"
+#include "backtrace-supported.h"
+
+#include "internal.h"
+#include "testlib.h"
+
+#ifndef HAVE_CLOCK_GETTIME
+
+typedef int xclockid_t;
+
+static int
+xclock_gettime (xclockid_t id ATTRIBUTE_UNUSED,
+ struct timespec *ts ATTRIBUTE_UNUSED)
+{
+ errno = EINVAL;
+ return -1;
+}
+
+#define clockid_t xclockid_t
+#define clock_gettime xclock_gettime
+#undef CLOCK_REALTIME
+#define CLOCK_REALTIME 0
+
+#endif /* !defined(HAVE_CLOCK_GETTIME) */
+
+#ifdef CLOCK_PROCESS_CPUTIME_ID
+#define ZLIB_CLOCK_GETTIME_ARG CLOCK_PROCESS_CPUTIME_ID
+#else
+#define ZLIB_CLOCK_GETTIME_ARG CLOCK_REALTIME
+#endif
+
+/* Some tests for the local zlib inflation code. */
+
+struct zlib_test
+{
+ const char *name;
+ const char *uncompressed;
+ const char *compressed;
+ size_t compressed_len;
+};
+
+/* Error callback. */
+
+static void
+error_callback_compress (void *vdata, const char *msg, int errnum)
+{
+ fprintf (stderr, "%s", msg);
+ if (errnum > 0)
+ fprintf (stderr, ": %s", strerror (errnum));
+ fprintf (stderr, "\n");
+ exit (EXIT_FAILURE);
+}
+
+static const struct zlib_test tests[] =
+{
+ {
+ "empty",
+ "",
+ "\x78\x9c\x03\x00\x00\x00\x00\x01",
+ 8,
+ },
+ {
+ "hello",
+ "hello, world\n",
+ ("\x78\x9c\xca\x48\xcd\xc9\xc9\xd7\x51\x28\xcf"
+ "\x2f\xca\x49\xe1\x02\x04\x00\x00\xff\xff\x21\xe7\x04\x93"),
+ 25,
+ },
+ {
+ "goodbye",
+ "goodbye, world",
+ ("\x78\x9c\x4b\xcf\xcf\x4f\x49\xaa"
+ "\x4c\xd5\x51\x28\xcf\x2f\xca\x49"
+ "\x01\x00\x28\xa5\x05\x5e"),
+ 22,
+ }
+};
+
+/* Test the hand coded samples. */
+
+static void
+test_samples (struct backtrace_state *state)
+{
+ size_t i;
+
+ for (i = 0; i < sizeof tests / sizeof tests[0]; ++i)
+ {
+ char *p;
+ size_t v;
+ size_t j;
+ unsigned char *uncompressed;
+ size_t uncompressed_len;
+
+ p = malloc (12 + tests[i].compressed_len);
+ memcpy (p, "ZLIB", 4);
+ v = strlen (tests[i].uncompressed);
+ for (j = 0; j < 8; ++j)
+ p[j + 4] = (v >> ((7 - j) * 8)) & 0xff;
+ memcpy (p + 12, tests[i].compressed, tests[i].compressed_len);
+ uncompressed = NULL;
+ uncompressed_len = 0;
+ if (!backtrace_uncompress_zdebug (state, (unsigned char *) p,
+ tests[i].compressed_len + 12,
+ error_callback_compress, NULL,
+ &uncompressed, &uncompressed_len))
+ {
+ fprintf (stderr, "test %s: uncompress failed\n", tests[i].name);
+ ++failures;
+ }
+ else
+ {
+ if (uncompressed_len != v)
+ {
+ fprintf (stderr,
+ "test %s: got uncompressed length %zu, want %zu\n",
+ tests[i].name, uncompressed_len, v);
+ ++failures;
+ }
+ else if (memcmp (tests[i].uncompressed, uncompressed, v) != 0)
+ {
+ size_t j;
+
+ fprintf (stderr, "test %s: uncompressed data mismatch\n",
+ tests[i].name);
+ for (j = 0; j < v; ++j)
+ if (tests[i].uncompressed[j] != uncompressed[j])
+ fprintf (stderr, " %zu: got %#x want %#x\n", j,
+ uncompressed[j], tests[i].uncompressed[j]);
+ ++failures;
+ }
+ else
+ printf ("PASS: inflate %s\n", tests[i].name);
+
+ backtrace_free (state, uncompressed, uncompressed_len,
+ error_callback_compress, NULL);
+ }
+ }
+}
+
+#ifdef HAVE_ZLIB
+
+/* Given a set of TRIALS timings, discard the lowest and highest
+ values and return the mean average of the rest. */
+
+static size_t
+average_time (const size_t *times, size_t trials)
+{
+ size_t imax;
+ size_t max;
+ size_t imin;
+ size_t min;
+ size_t i;
+ size_t sum;
+
+ imin = 0;
+ imax = 0;
+ min = times[0];
+ max = times[0];
+ for (i = 1; i < trials; ++i)
+ {
+ if (times[i] < min)
+ {
+ imin = i;
+ min = times[i];
+ }
+ if (times[i] > max)
+ {
+ imax = i;
+ max = times[i];
+ }
+ }
+
+ sum = 0;
+ for (i = 0; i < trials; ++i)
+ {
+ if (i != imax && i != imin)
+ sum += times[i];
+ }
+ return sum / (trials - 2);
+}
+
+#endif
+
+/* Test a larger text, if available. */
+
+static void
+test_large (struct backtrace_state *state)
+{
+#ifdef HAVE_ZLIB
+ unsigned char *orig_buf;
+ size_t orig_bufsize;
+ size_t i;
+ char *compressed_buf;
+ size_t compressed_bufsize;
+ unsigned long compress_sizearg;
+ unsigned char *uncompressed_buf;
+ size_t uncompressed_bufsize;
+ int r;
+ clockid_t cid;
+ struct timespec ts1;
+ struct timespec ts2;
+ size_t ctime;
+ size_t ztime;
+ const size_t trials = 16;
+ size_t ctimes[16];
+ size_t ztimes[16];
+ static const char * const names[] = {
+ "Mark.Twain-Tom.Sawyer.txt",
+ "../libgo/go/compress/testdata/Mark.Twain-Tom.Sawyer.txt"
+ };
+
+ orig_buf = NULL;
+ orig_bufsize = 0;
+ uncompressed_buf = NULL;
+ compressed_buf = NULL;
+
+ for (i = 0; i < sizeof names / sizeof names[0]; ++i)
+ {
+ size_t len;
+ char *namebuf;
+ FILE *e;
+ struct stat st;
+ char *rbuf;
+ size_t got;
+
+ len = strlen (SRCDIR) + strlen (names[i]) + 2;
+ namebuf = malloc (len);
+ if (namebuf == NULL)
+ {
+ perror ("malloc");
+ goto fail;
+ }
+ snprintf (namebuf, len, "%s/%s", SRCDIR, names[i]);
+ e = fopen (namebuf, "r");
+ free (namebuf);
+ if (e == NULL)
+ continue;
+ if (fstat (fileno (e), &st) < 0)
+ {
+ perror ("fstat");
+ fclose (e);
+ continue;
+ }
+ rbuf = malloc (st.st_size);
+ if (rbuf == NULL)
+ {
+ perror ("malloc");
+ goto fail;
+ }
+ got = fread (rbuf, 1, st.st_size, e);
+ fclose (e);
+ if (got > 0)
+ {
+ orig_buf = rbuf;
+ orig_bufsize = got;
+ break;
+ }
+ free (rbuf);
+ }
+
+ if (orig_buf == NULL)
+ {
+ /* We couldn't find an input file. */
+ printf ("UNSUPPORTED: inflate large\n");
+ return;
+ }
+
+ compressed_bufsize = compressBound (orig_bufsize) + 12;
+ compressed_buf = malloc (compressed_bufsize);
+ if (compressed_buf == NULL)
+ {
+ perror ("malloc");
+ goto fail;
+ }
+
+ compress_sizearg = compressed_bufsize - 12;
+ r = compress (compressed_buf + 12, &compress_sizearg,
+ orig_buf, orig_bufsize);
+ if (r != Z_OK)
+ {
+ fprintf (stderr, "zlib compress failed: %d\n", r);
+ goto fail;
+ }
+
+ compressed_bufsize = compress_sizearg + 12;
+
+ /* Prepare the header that our library expects. */
+ memcpy (compressed_buf, "ZLIB", 4);
+ for (i = 0; i < 8; ++i)
+ compressed_buf[i + 4] = (orig_bufsize >> ((7 - i) * 8)) & 0xff;
+
+ uncompressed_buf = malloc (orig_bufsize);
+ if (uncompressed_buf == NULL)
+ {
+ perror ("malloc");
+ goto fail;
+ }
+ uncompressed_bufsize = orig_bufsize;
+
+ if (!backtrace_uncompress_zdebug (state, compressed_buf, compressed_bufsize,
+ error_callback_compress, NULL,
+ &uncompressed_buf, &uncompressed_bufsize))
+ {
+ fprintf (stderr, "inflate large: backtrace_uncompress_zdebug failed\n");
+ goto fail;
+ }
+
+ if (uncompressed_bufsize != orig_bufsize)
+ {
+ fprintf (stderr,
+ "inflate large: got uncompressed length %zu, want %zu\n",
+ uncompressed_bufsize, orig_bufsize);
+ goto fail;
+ }
+
+ if (memcmp (uncompressed_buf, orig_buf, uncompressed_bufsize) != 0)
+ {
+ fprintf (stderr, "inflate large: uncompressed data mismatch\n");
+ goto fail;
+ }
+
+ printf ("PASS: inflate large\n");
+
+ for (i = 0; i < trials; ++i)
+ {
+ unsigned long uncompress_sizearg;
+
+ cid = ZLIB_CLOCK_GETTIME_ARG;
+ if (clock_gettime (cid, &ts1) < 0)
+ {
+ if (errno == EINVAL)
+ return;
+ perror ("clock_gettime");
+ return;
+ }
+
+ if (!backtrace_uncompress_zdebug (state, compressed_buf,
+ compressed_bufsize,
+ error_callback_compress, NULL,
+ &uncompressed_buf,
+ &uncompressed_bufsize))
+ {
+ fprintf (stderr,
+ ("inflate large: "
+ "benchmark backtrace_uncompress_zdebug failed\n"));
+ return;
+ }
+
+ if (clock_gettime (cid, &ts2) < 0)
+ {
+ perror ("clock_gettime");
+ return;
+ }
+
+ ctime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
+ ctime += ts2.tv_nsec - ts1.tv_nsec;
+ ctimes[i] = ctime;
+
+ if (clock_gettime (cid, &ts1) < 0)
+ {
+ perror("clock_gettime");
+ return;
+ }
+
+ uncompress_sizearg = uncompressed_bufsize;
+ r = uncompress (uncompressed_buf, &uncompress_sizearg,
+ compressed_buf + 12, compressed_bufsize - 12);
+
+ if (clock_gettime (cid, &ts2) < 0)
+ {
+ perror ("clock_gettime");
+ return;
+ }
+
+ if (r != Z_OK)
+ {
+ fprintf (stderr,
+ "inflate large: benchmark zlib uncompress failed: %d\n",
+ r);
+ return;
+ }
+
+ ztime = (ts2.tv_sec - ts1.tv_sec) * 1000000000;
+ ztime += ts2.tv_nsec - ts1.tv_nsec;
+ ztimes[i] = ztime;
+ }
+
+ /* Toss the highest and lowest times and average the rest. */
+ ctime = average_time (ctimes, trials);
+ ztime = average_time (ztimes, trials);
+
+ printf ("backtrace: %zu ns\n", ctime);
+ printf ("zlib : %zu ns\n", ztime);
+ printf ("ratio : %g\n", (double) ztime / (double) ctime);
+
+ return;
+
+ fail:
+ printf ("FAIL: inflate large\n");
+ ++failures;
+
+ if (orig_buf != NULL)
+ free (orig_buf);
+ if (compressed_buf != NULL)
+ free (compressed_buf);
+ if (uncompressed_buf != NULL)
+ free (uncompressed_buf);
+
+#else /* !HAVE_ZLIB */
+
+ printf ("UNSUPPORTED: inflate large\n");
+
+#endif /* !HAVE_ZLIB */
+}
+
+int
+main (int argc ATTRIBUTE_UNUSED, char **argv)
+{
+ struct backtrace_state *state;
+
+ state = backtrace_create_state (argv[0], BACKTRACE_SUPPORTS_THREADS,
+ error_callback_create, NULL);
+
+ test_samples (state);
+ test_large (state);
+
+ exit (failures != 0 ? EXIT_FAILURE : EXIT_SUCCESS);
+}
diff --git a/libcc1/ChangeLog b/libcc1/ChangeLog
index 4d8f40c..ea7a1ae 100644
--- a/libcc1/ChangeLog
+++ b/libcc1/ChangeLog
@@ -1,3 +1,8 @@
+2017-10-04 Nathan Sidwell <nathan@acm.org>
+
+ * libcp1plugin.cc (supplement_binding): Don't use
+ maybe_remove_implicit_alias.
+
2017-07-20 Nathan Sidwell <nathan@acm.org>
Remove TYPE_METHODS.
diff --git a/libcc1/libcp1plugin.cc b/libcc1/libcp1plugin.cc
index d7bf5a2..12ea4ed 100644
--- a/libcc1/libcp1plugin.cc
+++ b/libcc1/libcp1plugin.cc
@@ -422,12 +422,6 @@ supplement_binding (cxx_binding *binding, tree decl)
region to refer only to the namespace to which it already
refers. */
ok = false;
- else if (maybe_remove_implicit_alias (bval))
- {
- /* There was a mangling compatibility alias using this mangled name,
- but now we have a real decl that wants to use it instead. */
- binding->value = decl;
- }
else
{
// _1: diagnose_name_conflict (decl, bval);
diff --git a/libcpp/ChangeLog b/libcpp/ChangeLog
index 0621074..f2c0d4d 100644
--- a/libcpp/ChangeLog
+++ b/libcpp/ChangeLog
@@ -1,3 +1,8 @@
+2017-10-10 Nathan Sidwell <nathan@acm.org>
+
+ PR preprocessor/82506
+ * macro.c (cpp_quote_string): Escape raw LFs.
+
2017-09-15 Andrew Sutton <andrew.n.sutton@gmail.com>
Jakub Jelinek <jakub@redhat.com>
diff --git a/libcpp/macro.c b/libcpp/macro.c
index de18c22..fab1cb0 100644
--- a/libcpp/macro.c
+++ b/libcpp/macro.c
@@ -502,13 +502,21 @@ cpp_quote_string (uchar *dest, const uchar *src, unsigned int len)
{
uchar c = *src++;
- if (c == '\\' || c == '"')
+ switch (c)
{
+ case '\n':
+ /* Naked LF can appear in raw string literals */
+ c = 'n';
+ /* FALLTHROUGH */
+
+ case '\\':
+ case '"':
*dest++ = '\\';
+ /* FALLTHROUGH */
+
+ default:
*dest++ = c;
}
- else
- *dest++ = c;
}
return dest;
diff --git a/libffi/ChangeLog b/libffi/ChangeLog
index e73b93b..f7de950 100644
--- a/libffi/ChangeLog
+++ b/libffi/ChangeLog
@@ -1,3 +1,20 @@
+2017-08-31 Tony Reix <tony.reix@atos.net>
+
+ * src/powerpc/aix.S (ffi_call_AIX): Add debugging pseudo-op and
+ labels for EH.
+ (ffi_call_go_AIX): New function.
+ (_GLOBAL__F_libffi_src_powerpc_aix): New EH frame.
+ * src/powerpc/aix_closure.S (ffi_closure_ASM): Add debugging
+ pseudo-op and labels for EH.
+ (ffi_go_closure_ASM): New function.
+ (_GLOBAL__F_libffi_src_powerpc_aix_closure): New EH frame.
+ * src/powrpc/ffi_darwin.c (ffi_call_go): New function.
+ (ffi_prep_go_closure): New function.
+ (ffi_closure_helper_common): Rename from ffi_closure_helper_DARWIN.
+ (ffi_closure_helper_DARWIN): Call ffi_closure_helper_common.
+ (ffi_go_closure_helper_DARWIN): Call ffi_closure_helper_common.
+ * src/powerpc/ffitarget.h (FFI_GO_CLOSURES): Define.
+
2017-01-21 Jakub Jelinek <jakub@redhat.com>
PR other/79046
diff --git a/libffi/src/powerpc/aix.S b/libffi/src/powerpc/aix.S
index 349e78c..7ba5415 100644
--- a/libffi/src/powerpc/aix.S
+++ b/libffi/src/powerpc/aix.S
@@ -106,6 +106,10 @@ ffi_call_AIX:
.llong .ffi_call_AIX, TOC[tc0], 0
.csect .text[PR]
.ffi_call_AIX:
+ .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0
+ .bf __LINE__
+ .line 1
+LFB..0:
/* Save registers we use. */
mflr r0
@@ -115,8 +119,10 @@ ffi_call_AIX:
std r31, -8(r1)
std r0, 16(r1)
+LCFI..0:
mr r28, r1 /* our AP. */
stdux r1, r1, r4
+LCFI..1:
/* Save arguments over call... */
mr r31, r5 /* flags, */
@@ -202,12 +208,16 @@ L(fp_return_value):
L(float_return_value):
stfs f1, 0(r30)
b L(done_return_value)
-
+LFE..0:
#else /* ! __64BIT__ */
.long .ffi_call_AIX, TOC[tc0], 0
.csect .text[PR]
.ffi_call_AIX:
+ .function .ffi_call_AIX,.ffi_call_AIX,16,044,LFE..0-LFB..0
+ .bf __LINE__
+ .line 1
+LFB..0:
/* Save registers we use. */
mflr r0
@@ -217,8 +227,10 @@ L(float_return_value):
stw r31, -4(r1)
stw r0, 8(r1)
+LCFI..0:
mr r28, r1 /* out AP. */
stwux r1, r1, r4
+LCFI..1:
/* Save arguments over call... */
mr r31, r5 /* flags, */
@@ -304,11 +316,144 @@ L(fp_return_value):
L(float_return_value):
stfs f1, 0(r30)
b L(done_return_value)
+LFE..0:
#endif
+ .ef __LINE__
.long 0
.byte 0,0,0,1,128,4,0,0
/* END(ffi_call_AIX) */
+ /* void ffi_call_go_AIX(extended_cif *ecif, unsigned long bytes,
+ * unsigned int flags, unsigned int *rvalue,
+ * void (*fn)(),
+ * void (*prep_args)(extended_cif*, unsigned *const),
+ * void *closure);
+ * r3=ecif, r4=bytes, r5=flags, r6=rvalue, r7=fn, r8=prep_args, r9=closure
+ */
+
+.csect .text[PR]
+ .align 2
+ .globl ffi_call_go_AIX
+ .globl .ffi_call_go_AIX
+.csect ffi_call_go_AIX[DS]
+ffi_call_go_AIX:
+#ifdef __64BIT__
+ .llong .ffi_call_go_AIX, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_call_go_AIX:
+ .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1
+ .bf __LINE__
+ .line 1
+LFB..1:
+ /* Save registers we use. */
+ mflr r0
+
+ std r28,-32(r1)
+ std r29,-24(r1)
+ std r30,-16(r1)
+ std r31, -8(r1)
+
+ std r9, 8(r1) /* closure, saved in cr field. */
+ std r0, 16(r1)
+LCFI..2:
+ mr r28, r1 /* our AP. */
+ stdux r1, r1, r4
+LCFI..3:
+
+ /* Save arguments over call... */
+ mr r31, r5 /* flags, */
+ mr r30, r6 /* rvalue, */
+ mr r29, r7 /* function address, */
+ std r2, 40(r1)
+
+ /* Call ffi_prep_args. */
+ mr r4, r1
+ bl .ffi_prep_args
+ nop
+
+ /* Now do the call. */
+ ld r0, 0(r29)
+ ld r2, 8(r29)
+ ld r11, 8(r28) /* closure */
+ /* Set up cr1 with bits 4-7 of the flags. */
+ mtcrf 0x40, r31
+ mtctr r0
+ /* Load all those argument registers. */
+ /* We have set up a nice stack frame, just load it into registers. */
+ ld r3, 40+(1*8)(r1)
+ ld r4, 40+(2*8)(r1)
+ ld r5, 40+(3*8)(r1)
+ ld r6, 40+(4*8)(r1)
+ nop
+ ld r7, 40+(5*8)(r1)
+ ld r8, 40+(6*8)(r1)
+ ld r9, 40+(7*8)(r1)
+ ld r10,40+(8*8)(r1)
+
+ b L1
+LFE..1:
+#else /* ! __64BIT__ */
+
+ .long .ffi_call_go_AIX, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_call_go_AIX:
+ .function .ffi_call_go_AIX,.ffi_call_go_AIX,16,044,LFE..1-LFB..1
+ .bf __LINE__
+ .line 1
+ /* Save registers we use. */
+LFB..1:
+ mflr r0
+
+ stw r28,-16(r1)
+ stw r29,-12(r1)
+ stw r30, -8(r1)
+ stw r31, -4(r1)
+
+ stw r9, 4(r1) /* closure, saved in cr field. */
+ stw r0, 8(r1)
+LCFI..2:
+ mr r28, r1 /* out AP. */
+ stwux r1, r1, r4
+LCFI..3:
+
+ /* Save arguments over call... */
+ mr r31, r5 /* flags, */
+ mr r30, r6 /* rvalue, */
+ mr r29, r7 /* function address, */
+ stw r2, 20(r1)
+
+ /* Call ffi_prep_args. */
+ mr r4, r1
+ bl .ffi_prep_args
+ nop
+
+ /* Now do the call. */
+ lwz r0, 0(r29)
+ lwz r2, 4(r29)
+ lwz r11, 4(r28) /* closure */
+ /* Set up cr1 with bits 4-7 of the flags. */
+ mtcrf 0x40, r31
+ mtctr r0
+ /* Load all those argument registers. */
+ /* We have set up a nice stack frame, just load it into registers. */
+ lwz r3, 20+(1*4)(r1)
+ lwz r4, 20+(2*4)(r1)
+ lwz r5, 20+(3*4)(r1)
+ lwz r6, 20+(4*4)(r1)
+ nop
+ lwz r7, 20+(5*4)(r1)
+ lwz r8, 20+(6*4)(r1)
+ lwz r9, 20+(7*4)(r1)
+ lwz r10,20+(8*4)(r1)
+
+ b L1
+LFE..1:
+#endif
+ .ef __LINE__
+ .long 0
+ .byte 0,0,0,1,128,4,0,0
+/* END(ffi_call_go_AIX) */
+
.csect .text[PR]
.align 2
.globl ffi_call_DARWIN
@@ -326,3 +471,96 @@ ffi_call_DARWIN:
.long 0
.byte 0,0,0,0,0,0,0,0
/* END(ffi_call_DARWIN) */
+
+/* EH frame stuff. */
+
+#define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */
+#ifdef __64BIT__
+#define PTRSIZE 8
+#define LOG2_PTRSIZE 3
+#define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */
+#define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */
+#else
+#define PTRSIZE 4
+#define LOG2_PTRSIZE 2
+#define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */
+#define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */
+#endif
+ .csect _unwind.ro_[RO],4
+ .align LOG2_PTRSIZE
+ .globl _GLOBAL__F_libffi_src_powerpc_aix
+_GLOBAL__F_libffi_src_powerpc_aix:
+Lframe..1:
+ .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */
+LSCIE..1:
+ .vbyte 4,0 /* CIE Identifier Tag */
+ .byte 0x3 /* CIE Version */
+ .byte "zR" /* CIE Augmentation */
+ .byte 0
+ .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
+ .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */
+ .byte 0x41 /* CIE RA Column */
+ .byte 0x1 /* uleb128 0x1; Augmentation size */
+ .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .byte 0x1 /* uleb128 0x1; Register r1 */
+ .byte 0 /* uleb128 0x0; Offset 0 */
+ .align LOG2_PTRSIZE
+LECIE..1:
+LSFDE..1:
+ .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */
+LASFDE..1:
+ .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */
+ .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */
+ .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */
+ .byte 0 /* uleb128 0x0; Augmentation size */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..0-LFB..0
+ .byte 0x11 /* DW_CFA_def_offset_extended_sf */
+ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */
+ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */
+ .byte 0x9f /* DW_CFA_offset Register r31 */
+ .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */
+ .byte 0x9e /* DW_CFA_offset Register r30 */
+ .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */
+ .byte 0x9d /* DW_CFA_offset Register r29 */
+ .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */
+ .byte 0x9c /* DW_CFA_offset Register r28 */
+ .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..1-LCFI..0
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0x1c /* uleb128 28; Register r28 */
+ .align LOG2_PTRSIZE
+LEFDE..1:
+LSFDE..2:
+ .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */
+LASFDE..2:
+ .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */
+ .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */
+ .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */
+ .byte 0 /* uleb128 0x0; Augmentation size */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..2-LFB..1
+ .byte 0x11 /* DW_CFA_def_offset_extended_sf */
+ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */
+ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */
+ .byte 0x9f /* DW_CFA_offset Register r31 */
+ .byte 0x1 /* uleb128 0x1; Offset 1 (-4/-8) */
+ .byte 0x9e /* DW_CFA_offset Register r30 */
+ .byte 0x2 /* uleb128 0x2; Offset 2 (-8/-16) */
+ .byte 0x9d /* DW_CFA_offset Register r29 */
+ .byte 0x3 /* uleb128 0x3; Offset 3 (-12/-24) */
+ .byte 0x9c /* DW_CFA_offset Register r28 */
+ .byte 0x4 /* uleb128 0x4; Offset 4 (-16/-32) */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..3-LCFI..2
+ .byte 0xd /* DW_CFA_def_cfa_register */
+ .byte 0x1c /* uleb128 28; Register r28 */
+ .align LOG2_PTRSIZE
+LEFDE..2:
+ .vbyte 4,0 /* End of FDEs */
+
+ .csect .text[PR]
+ .ref _GLOBAL__F_libffi_src_powerpc_aix /* Prevents garbage collection by AIX linker */
+
diff --git a/libffi/src/powerpc/aix_closure.S b/libffi/src/powerpc/aix_closure.S
index aabd3c3..132c785 100644
--- a/libffi/src/powerpc/aix_closure.S
+++ b/libffi/src/powerpc/aix_closure.S
@@ -80,6 +80,7 @@
.set f21,21
.extern .ffi_closure_helper_DARWIN
+ .extern .ffi_go_closure_helper_DARWIN
#define LIBFFI_ASM
#define JUMPTARGET(name) name
@@ -101,6 +102,10 @@ ffi_closure_ASM:
.llong .ffi_closure_ASM, TOC[tc0], 0
.csect .text[PR]
.ffi_closure_ASM:
+ .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0
+ .bf __LINE__
+ .line 1
+LFB..0:
/* we want to build up an area for the parameters passed */
/* in registers (both floating point and integer) */
@@ -117,8 +122,7 @@ ffi_closure_ASM:
std r9, 48+(6*8)(r1)
std r10, 48+(7*8)(r1)
std r0, 16(r1) /* save the return address */
-
-
+LCFI..0:
/* 48 Bytes (Linkage Area) */
/* 64 Bytes (params) */
/* 16 Bytes (result) */
@@ -128,6 +132,7 @@ ffi_closure_ASM:
stdu r1, -240(r1) /* skip over caller save area
keep stack aligned to 16 */
+LCFI..1:
/* next save fpr 1 to fpr 13 (aligned to 8) */
stfd f1, 128+(0*8)(r1)
@@ -161,6 +166,8 @@ ffi_closure_ASM:
bl .ffi_closure_helper_DARWIN
nop
+.Ldoneclosure:
+
/* now r3 contains the return type */
/* so use it to look up in a table */
/* so we know how to deal with each type */
@@ -270,12 +277,17 @@ L..finish:
mtlr r0
addi r1, r1, 240
blr
+LFE..0:
#else /* ! __64BIT__ */
.long .ffi_closure_ASM, TOC[tc0], 0
.csect .text[PR]
.ffi_closure_ASM:
+ .function .ffi_closure_ASM,.ffi_closure_ASM,16,044,LFE..0-LFB..0
+ .bf __LINE__
+ .line 1
+LFB..0:
/* we want to build up an area for the parameters passed */
/* in registers (both floating point and integer) */
@@ -292,7 +304,7 @@ L..finish:
stw r9, 24+(6*4)(r1)
stw r10, 24+(7*4)(r1)
stw r0, 8(r1)
-
+LCFI..0:
/* 24 Bytes (Linkage Area) */
/* 32 Bytes (params) */
/* 16 Bytes (result) */
@@ -301,6 +313,7 @@ L..finish:
stwu r1, -176(r1) /* skip over caller save area
keep stack aligned to 16 */
+LCFI..1:
/* next save fpr 1 to fpr 13 (aligned to 8) */
stfd f1, 72+(0*8)(r1)
@@ -334,6 +347,8 @@ L..finish:
bl .ffi_closure_helper_DARWIN
nop
+.Ldoneclosure:
+
/* now r3 contains the return type */
/* so use it to look up in a table */
/* so we know how to deal with each type */
@@ -443,5 +458,237 @@ L..60:
L..finish:
addi r1, r1, 176
blr
+LFE..0:
#endif
+ .ef __LINE__
/* END(ffi_closure_ASM) */
+
+
+.csect .text[PR]
+ .align 2
+ .globl ffi_go_closure_ASM
+ .globl .ffi_go_closure_ASM
+.csect ffi_go_closure_ASM[DS]
+ffi_go_closure_ASM:
+#ifdef __64BIT__
+ .llong .ffi_go_closure_ASM, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_go_closure_ASM:
+ .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1
+ .bf __LINE__
+ .line 1
+LFB..1:
+/* we want to build up an area for the parameters passed */
+/* in registers (both floating point and integer) */
+
+ /* we store gpr 3 to gpr 10 (aligned to 4)
+ in the parents outgoing area */
+ std r3, 48+(0*8)(r1)
+ std r4, 48+(1*8)(r1)
+ std r5, 48+(2*8)(r1)
+ std r6, 48+(3*8)(r1)
+ mflr r0
+
+ std r7, 48+(4*8)(r1)
+ std r8, 48+(5*8)(r1)
+ std r9, 48+(6*8)(r1)
+ std r10, 48+(7*8)(r1)
+ std r0, 16(r1) /* save the return address */
+LCFI..2:
+ /* 48 Bytes (Linkage Area) */
+ /* 64 Bytes (params) */
+ /* 16 Bytes (result) */
+ /* 104 Bytes (13*8 from FPR) */
+ /* 8 Bytes (alignment) */
+ /* 240 Bytes */
+
+ stdu r1, -240(r1) /* skip over caller save area
+ keep stack aligned to 16 */
+LCFI..3:
+
+ /* next save fpr 1 to fpr 13 (aligned to 8) */
+ stfd f1, 128+(0*8)(r1)
+ stfd f2, 128+(1*8)(r1)
+ stfd f3, 128+(2*8)(r1)
+ stfd f4, 128+(3*8)(r1)
+ stfd f5, 128+(4*8)(r1)
+ stfd f6, 128+(5*8)(r1)
+ stfd f7, 128+(6*8)(r1)
+ stfd f8, 128+(7*8)(r1)
+ stfd f9, 128+(8*8)(r1)
+ stfd f10, 128+(9*8)(r1)
+ stfd f11, 128+(10*8)(r1)
+ stfd f12, 128+(11*8)(r1)
+ stfd f13, 128+(12*8)(r1)
+
+ /* set up registers for the routine that actually does the work */
+ mr r3, r11 /* go closure */
+
+ /* now load up the pointer to the result storage */
+ addi r4, r1, 112
+
+ /* now load up the pointer to the saved gpr registers */
+ addi r5, r1, 288
+
+ /* now load up the pointer to the saved fpr registers */
+ addi r6, r1, 128
+
+ /* make the call */
+ bl .ffi_go_closure_helper_DARWIN
+ nop
+
+ b .Ldoneclosure
+LFE..1:
+
+#else /* ! __64BIT__ */
+
+ .long .ffi_go_closure_ASM, TOC[tc0], 0
+ .csect .text[PR]
+.ffi_go_closure_ASM:
+ .function .ffi_go_closure_ASM,.ffi_go_closure_ASM,16,044,LFE..1-LFB..1
+ .bf __LINE__
+ .line 1
+LFB..1:
+/* we want to build up an area for the parameters passed */
+/* in registers (both floating point and integer) */
+
+ /* we store gpr 3 to gpr 10 (aligned to 4)
+ in the parents outgoing area */
+ stw r3, 24+(0*4)(r1)
+ stw r4, 24+(1*4)(r1)
+ stw r5, 24+(2*4)(r1)
+ stw r6, 24+(3*4)(r1)
+ mflr r0
+
+ stw r7, 24+(4*4)(r1)
+ stw r8, 24+(5*4)(r1)
+ stw r9, 24+(6*4)(r1)
+ stw r10, 24+(7*4)(r1)
+ stw r0, 8(r1)
+LCFI..2:
+ /* 24 Bytes (Linkage Area) */
+ /* 32 Bytes (params) */
+ /* 16 Bytes (result) */
+ /* 104 Bytes (13*8 from FPR) */
+ /* 176 Bytes */
+
+ stwu r1, -176(r1) /* skip over caller save area
+ keep stack aligned to 16 */
+LCFI..3:
+
+ /* next save fpr 1 to fpr 13 (aligned to 8) */
+ stfd f1, 72+(0*8)(r1)
+ stfd f2, 72+(1*8)(r1)
+ stfd f3, 72+(2*8)(r1)
+ stfd f4, 72+(3*8)(r1)
+ stfd f5, 72+(4*8)(r1)
+ stfd f6, 72+(5*8)(r1)
+ stfd f7, 72+(6*8)(r1)
+ stfd f8, 72+(7*8)(r1)
+ stfd f9, 72+(8*8)(r1)
+ stfd f10, 72+(9*8)(r1)
+ stfd f11, 72+(10*8)(r1)
+ stfd f12, 72+(11*8)(r1)
+ stfd f13, 72+(12*8)(r1)
+
+ /* set up registers for the routine that actually does the work */
+ mr r3, 11 /* go closure */
+
+ /* now load up the pointer to the result storage */
+ addi r4, r1, 56
+
+ /* now load up the pointer to the saved gpr registers */
+ addi r5, r1, 200
+
+ /* now load up the pointer to the saved fpr registers */
+ addi r6, r1, 72
+
+ /* make the call */
+ bl .ffi_go_closure_helper_DARWIN
+ nop
+
+ b .Ldoneclosure
+LFE..1:
+#endif
+ .ef __LINE__
+/* END(ffi_go_closure_ASM) */
+
+/* EH frame stuff. */
+
+#define LR_REGNO 0x41 /* Link Register (65), see rs6000.md */
+#ifdef __64BIT__
+#define PTRSIZE 8
+#define LOG2_PTRSIZE 3
+#define CFA_OFFSET 0xf0,0x01 /* LEB128 240 */
+#define FDE_ENCODING 0x1c /* DW_EH_PE_pcrel|DW_EH_PE_sdata8 */
+#define EH_DATA_ALIGN_FACT 0x78 /* LEB128 -8 */
+#else
+#define PTRSIZE 4
+#define LOG2_PTRSIZE 2
+#define CFA_OFFSET 0xb0,0x01 /* LEB128 176 */
+#define FDE_ENCODING 0x1b /* DW_EH_PE_pcrel|DW_EH_PE_sdata4 */
+#define EH_DATA_ALIGN_FACT 0x7c /* LEB128 -4 */
+#endif
+
+ .csect _unwind.ro_[RO],4
+ .align LOG2_PTRSIZE
+ .globl _GLOBAL__F_libffi_src_powerpc_aix_closure
+_GLOBAL__F_libffi_src_powerpc_aix_closure:
+Lframe..1:
+ .vbyte 4,LECIE..1-LSCIE..1 /* CIE Length */
+LSCIE..1:
+ .vbyte 4,0 /* CIE Identifier Tag */
+ .byte 0x3 /* CIE Version */
+ .byte "zR" /* CIE Augmentation */
+ .byte 0
+ .byte 0x1 /* uleb128 0x1; CIE Code Alignment Factor */
+ .byte EH_DATA_ALIGN_FACT /* leb128 -4/-8; CIE Data Alignment Factor */
+ .byte LR_REGNO /* CIE RA Column */
+ .byte 0x1 /* uleb128 0x1; Augmentation size */
+ .byte FDE_ENCODING /* FDE Encoding (pcrel|sdata4/8) */
+ .byte 0xc /* DW_CFA_def_cfa */
+ .byte 0x1 /* uleb128 0x1; Register r1 */
+ .byte 0 /* uleb128 0x0; Offset 0 */
+ .align LOG2_PTRSIZE
+LECIE..1:
+LSFDE..1:
+ .vbyte 4,LEFDE..1-LASFDE..1 /* FDE Length */
+LASFDE..1:
+ .vbyte 4,LASFDE..1-Lframe..1 /* FDE CIE offset */
+ .vbyte PTRSIZE,LFB..0-$ /* FDE initial location */
+ .vbyte PTRSIZE,LFE..0-LFB..0 /* FDE address range */
+ .byte 0 /* uleb128 0x0; Augmentation size */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..1-LCFI..0
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte CFA_OFFSET /* uleb128 176/240 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..0-LFB..0
+ .byte 0x11 /* DW_CFA_offset_extended_sf */
+ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */
+ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */
+ .align LOG2_PTRSIZE
+LEFDE..1:
+LSFDE..2:
+ .vbyte 4,LEFDE..2-LASFDE..2 /* FDE Length */
+LASFDE..2:
+ .vbyte 4,LASFDE..2-Lframe..1 /* FDE CIE offset */
+ .vbyte PTRSIZE,LFB..1-$ /* FDE initial location */
+ .vbyte PTRSIZE,LFE..1-LFB..1 /* FDE address range */
+ .byte 0 /* uleb128 0x0; Augmentation size */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..3-LCFI..2
+ .byte 0xe /* DW_CFA_def_cfa_offset */
+ .byte CFA_OFFSET /* uleb128 176/240 */
+ .byte 0x4 /* DW_CFA_advance_loc4 */
+ .vbyte 4,LCFI..2-LFB..1
+ .byte 0x11 /* DW_CFA_offset_extended_sf */
+ .byte LR_REGNO /* uleb128 LR_REGNO; Register LR */
+ .byte 0x7e /* leb128 -2; Offset -2 (8/16) */
+ .align LOG2_PTRSIZE
+LEFDE..2:
+ .vbyte 4,0 /* End of FDEs */
+
+ .csect .text[PR]
+ .ref _GLOBAL__F_libffi_src_powerpc_aix_closure /* Prevents garbage collection by AIX linker */
+
diff --git a/libffi/src/powerpc/ffi_darwin.c b/libffi/src/powerpc/ffi_darwin.c
index cf6fb6d4..6588e3c 100644
--- a/libffi/src/powerpc/ffi_darwin.c
+++ b/libffi/src/powerpc/ffi_darwin.c
@@ -33,6 +33,7 @@
#include <stdlib.h>
extern void ffi_closure_ASM (void);
+extern void ffi_go_closure_ASM (void);
enum {
/* The assembly depends on these exact flags.
@@ -908,6 +909,9 @@ ffi_prep_cif_machdep (ffi_cif *cif)
extern void ffi_call_AIX(extended_cif *, long, unsigned, unsigned *,
void (*fn)(void), void (*fn2)(void));
+extern void ffi_call_go_AIX(extended_cif *, long, unsigned, unsigned *,
+ void (*fn)(void), void (*fn2)(void), void *closure);
+
extern void ffi_call_DARWIN(extended_cif *, long, unsigned, unsigned *,
void (*fn)(void), void (*fn2)(void), ffi_type*);
@@ -946,6 +950,38 @@ ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
}
}
+void
+ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
+ void *closure)
+{
+ extended_cif ecif;
+
+ ecif.cif = cif;
+ ecif.avalue = avalue;
+
+ /* If the return value is a struct and we don't have a return
+ value address then we need to make one. */
+
+ if ((rvalue == NULL) &&
+ (cif->rtype->type == FFI_TYPE_STRUCT))
+ {
+ ecif.rvalue = alloca (cif->rtype->size);
+ }
+ else
+ ecif.rvalue = rvalue;
+
+ switch (cif->abi)
+ {
+ case FFI_AIX:
+ ffi_call_go_AIX(&ecif, -(long)cif->bytes, cif->flags, ecif.rvalue, fn,
+ FFI_FN(ffi_prep_args), closure);
+ break;
+ default:
+ FFI_ASSERT(0);
+ break;
+ }
+}
+
static void flush_icache(char *);
static void flush_range(char *, int);
@@ -1074,6 +1110,30 @@ ffi_prep_closure_loc (ffi_closure* closure,
return FFI_OK;
}
+ffi_status
+ffi_prep_go_closure (ffi_go_closure* closure,
+ ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*))
+{
+ switch (cif->abi)
+ {
+ case FFI_AIX:
+
+ FFI_ASSERT (cif->abi == FFI_AIX);
+
+ closure->tramp = (void *)ffi_go_closure_ASM;
+ closure->cif = cif;
+ closure->fun = fun;
+ return FFI_OK;
+
+ // For now, ffi_prep_go_closure is only implemented for AIX, not for Darwin
+ default:
+ return FFI_BAD_ABI;
+ break;
+ }
+ return FFI_OK;
+}
+
static void
flush_icache(char *addr)
{
@@ -1108,6 +1168,10 @@ ffi_type *
ffi_closure_helper_DARWIN (ffi_closure *, void *,
unsigned long *, ffi_dblfl *);
+ffi_type *
+ffi_go_closure_helper_DARWIN (ffi_go_closure*, void *,
+ unsigned long *, ffi_dblfl *);
+
/* Basically the trampoline invokes ffi_closure_ASM, and on
entry, r11 holds the address of the closure.
After storing the registers that could possibly contain
@@ -1115,8 +1179,10 @@ ffi_closure_helper_DARWIN (ffi_closure *, void *,
up space for a return value, ffi_closure_ASM invokes the
following helper function to do most of the work. */
-ffi_type *
-ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
+static ffi_type *
+ffi_closure_helper_common (ffi_cif* cif,
+ void (*fun)(ffi_cif*, void*, void**, void*),
+ void *user_data, void *rvalue,
unsigned long *pgr, ffi_dblfl *pfr)
{
/* rvalue is the pointer to space for return value in closure assembly
@@ -1134,14 +1200,12 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
void ** avalue;
ffi_type ** arg_types;
long i, avn;
- ffi_cif * cif;
ffi_dblfl * end_pfr = pfr + NUM_FPR_ARG_REGISTERS;
unsigned size_al;
#if defined(POWERPC_DARWIN64)
unsigned fpsused = 0;
#endif
- cif = closure->cif;
avalue = alloca (cif->nargs * sizeof(void *));
if (cif->rtype->type == FFI_TYPE_STRUCT)
@@ -1352,8 +1416,25 @@ ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
i++;
}
- (closure->fun) (cif, rvalue, avalue, closure->user_data);
+ (fun) (cif, rvalue, avalue, user_data);
/* Tell ffi_closure_ASM to perform return type promotions. */
return cif->rtype;
}
+
+ffi_type *
+ffi_closure_helper_DARWIN (ffi_closure *closure, void *rvalue,
+ unsigned long *pgr, ffi_dblfl *pfr)
+{
+ return ffi_closure_helper_common (closure->cif, closure->fun,
+ closure->user_data, rvalue, pgr, pfr);
+}
+
+ffi_type *
+ffi_go_closure_helper_DARWIN (ffi_go_closure *closure, void *rvalue,
+ unsigned long *pgr, ffi_dblfl *pfr)
+{
+ return ffi_closure_helper_common (closure->cif, closure->fun,
+ closure, rvalue, pgr, pfr);
+}
+
diff --git a/libffi/src/powerpc/ffitarget.h b/libffi/src/powerpc/ffitarget.h
index 0f66d31..90aa36b 100644
--- a/libffi/src/powerpc/ffitarget.h
+++ b/libffi/src/powerpc/ffitarget.h
@@ -142,6 +142,9 @@ typedef enum ffi_abi {
# define FFI_TARGET_SPECIFIC_VARIADIC 1
# define FFI_EXTRA_CIF_FIELDS unsigned nfixedargs
#endif
+#if defined (POWERPC_AIX)
+# define FFI_GO_CLOSURES 1
+#endif
/* ppc_closure.S and linux64_closure.S expect this. */
#define FFI_PPC_TYPE_LAST FFI_TYPE_POINTER
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index b548922..f137fdf 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,30 +1,75 @@
+2017-10-23 Sebastian Perta <sebastian.perta@renesas.com>
+
+ * config/rl78/subdi3.S: New assembly file.
+ * config/rl78/t-rl78: Added subdi3.S to LIB2ADD.
+
+2017-10-13 Sebastian Perta <sebastian.perta@renesas.com>
+
+ * config/rl78/adddi3.S: New assembly file.
+ * config/rl78/t-rl78: Added adddi3.S to LIB2ADD.
+
+2017-10-13 Jakub Jelinek <jakub@redhat.com>
+
+ PR target/82274
+ * libgcc2.c (__mulvDI3): If both operands have
+ the same highpart of -1 and the topmost bit of lowpart is 0,
+ multiplication overflows even if both lowparts are 0.
+
+2017-09-28 James Bowman <james.bowman@ftdichip.com>
+
+ * config/ft32/crti-hw.S: Add watchdog vector, FT930 IRQ support.
+
+2017-09-26 Joseph Myers <joseph@codesourcery.com>
+
+ * config/microblaze/crti.S, config/microblaze/crtn.S,
+ config/microblaze/divsi3.S, config/microblaze/moddi3.S,
+ config/microblaze/modsi3.S, config/microblaze/muldi3_hard.S,
+ config/microblaze/mulsi3.S,
+ config/microblaze/stack_overflow_exit.S,
+ config/microblaze/udivsi3.S, config/microblaze/umodsi3.S,
+ config/pa/milli64.S: Add .note.GNU-stack section.
+
+2017-09-23 Daniel Santos <daniel.santos@pobox.com>
+
+ * configure.ac: Add Check for HAVE_AS_AVX.
+ * config.in: Regenerate.
+ * configure: Likewise.
+ * config/i386/i386-asm.h: Include auto-target.h from libgcc.
+ (SSE_SAVE, SSE_RESTORE): Emit .byte sequence for !HAVE_AS_AVX.
+ Correct out-of-date comments.
+
+2017-09-20 Sebastian Peryt <sebastian.peryt@intel.com>
+
+ * config/i386/cpuinfo.h (processor_types): Add INTEL_KNM.
+ * config/i386/cpuinfo.c (get_intel_cpu): Detect Knights Mill.
+
2017-09-17 Daniel Santos <daniel.santos@pobox.com>
- config/i386/i386-asm.h (PASTE2): New macro.
+ * config/i386/i386-asm.h (PASTE2): New macro.
(ASMNAME): Modify to use PASTE2.
(MS2SYSV_STUB_PREFIX): New macro for isa prefix.
(MS2SYSV_STUB_BEGIN, MS2SYSV_STUB_END): New macros for stub headers.
- config/i386/resms64.S: Rename to a header file, use MS2SYSV_STUB_BEGIN
+ * config/i386/resms64.S: Rename to a header file, use MS2SYSV_STUB_BEGIN
instead of HIDDEN_FUNC and MS2SYSV_STUB_END instead of FUNC_END.
- config/i386/resms64f.S: Likewise.
- config/i386/resms64fx.S: Likewise.
- config/i386/resms64x.S: Likewise.
- config/i386/savms64.S: Likewise.
- config/i386/savms64f.S: Likewise.
- config/i386/avx_resms64.S: New file that only defines a macro and
+ * config/i386/resms64f.S: Likewise.
+ * config/i386/resms64fx.S: Likewise.
+ * config/i386/resms64x.S: Likewise.
+ * config/i386/savms64.S: Likewise.
+ * config/i386/savms64f.S: Likewise.
+ * config/i386/avx_resms64.S: New file that only defines a macro and
includes it's corresponding header file.
- config/i386/avx_resms64f.S: Likewise.
- config/i386/avx_resms64fx.S: Likewise.
- config/i386/avx_resms64x.S: Likewise.
- config/i386/avx_savms64.S: Likewise.
- config/i386/avx_savms64f.S: Likewise.
- config/i386/sse_resms64.S: Likewise.
- config/i386/sse_resms64f.S: Likewise.
- config/i386/sse_resms64fx.S: Likewise.
- config/i386/sse_resms64x.S: Likewise.
- config/i386/sse_savms64.S: Likewise.
- config/i386/sse_savms64f.S: Likewise.
- config/i386/t-msabi: Modified to add avx and sse versions of stubs.
+ * config/i386/avx_resms64f.S: Likewise.
+ * config/i386/avx_resms64fx.S: Likewise.
+ * config/i386/avx_resms64x.S: Likewise.
+ * config/i386/avx_savms64.S: Likewise.
+ * config/i386/avx_savms64f.S: Likewise.
+ * config/i386/sse_resms64.S: Likewise.
+ * config/i386/sse_resms64f.S: Likewise.
+ * config/i386/sse_resms64fx.S: Likewise.
+ * config/i386/sse_resms64x.S: Likewise.
+ * config/i386/sse_savms64.S: Likewise.
+ * config/i386/sse_savms64f.S: Likewise.
+ * config/i386/t-msabi: Modified to add avx and sse versions of stubs.
2017-09-01 Olivier Hainque <hainque@adacore.com>
diff --git a/libgcc/config.in b/libgcc/config.in
index 7de22ee..f9fb253 100644
--- a/libgcc/config.in
+++ b/libgcc/config.in
@@ -1,5 +1,8 @@
/* config.in. Generated from configure.ac by autoheader. */
+/* Define to 1 if the assembler supports AVX. */
+#undef HAVE_AS_AVX
+
/* Define to 1 if the target assembler supports thread-local storage. */
#undef HAVE_CC_TLS
diff --git a/libgcc/config/ft32/crti-hw.S b/libgcc/config/ft32/crti-hw.S
index c2951fc..8ee1d38 100644
--- a/libgcc/config/ft32/crti-hw.S
+++ b/libgcc/config/ft32/crti-hw.S
@@ -1,8 +1,8 @@
.global _start
_start:
# START Interrupt Vector Table [[
- jmp __PMSIZE-4
- jmp watchdog_init
+ jmp __PMSIZE-4 # RESET Vector
+ jmp interrupt_33 # Watchdog reset vector
jmp interrupt_0
jmp interrupt_1
jmp interrupt_2
@@ -35,24 +35,29 @@ _start:
jmp interrupt_29
jmp interrupt_30
jmp interrupt_31
- jmp __PMSIZE-8
+ jmp __PMSIZE-8 # Interrupt vector 32 (NMI)
# ]] END Interrupt Vector Table
codestart:
jmp init
-
+
.global _exithook
_exithook: # Debugger uses '_exithook' at 0x90 to catch program exit
return
-
-watchdog_init:
- ldk $r0,1
+
init:
ldk $sp,__RAMSIZE
# Disable all interrupts
- ldk $r4,0x80
- sta.b 0x100e3,$r4
-
+ lda $r1,0x10000
+ lshr $r1,$r1,20
+ cmp $r1,0x90
+ ldk $r1,0x100e3 # FT900 IRQ Control Register
+ jmpc z,1f
+ ldk $r1,0x10123 # FT930 IRQ Control Register
+1:
+ ldk $r4,0x80
+ sti.b $r1,0,$r4
+
# Initialize DATA by copying from program memory
ldk.l $r4,__data_load_start
ldk.l $r1,__data_load_end
@@ -139,6 +144,7 @@ interrupt_\i:
inth 30
inth 31
inth 32
+ inth 33
# On entry: r0, already saved, holds the handler function
interrupt_common:
@@ -182,7 +188,7 @@ nullvector:
.section .data
.global vector_table
vector_table:
- .rept 33
+ .rept 34
.long nullvector
.endr
diff --git a/libgcc/config/i386/cpuinfo.c b/libgcc/config/i386/cpuinfo.c
index b008fb6..c2ab8be 100644
--- a/libgcc/config/i386/cpuinfo.c
+++ b/libgcc/config/i386/cpuinfo.c
@@ -137,6 +137,10 @@ get_intel_cpu (unsigned int family, unsigned int model, unsigned int brand_id)
/* Knights Landing. */
__cpu_model.__cpu_type = INTEL_KNL;
break;
+ case 0x85:
+ /* Knights Mill. */
+ __cpu_model.__cpu_type = INTEL_KNM;
+ break;
case 0x1a:
case 0x1e:
case 0x1f:
diff --git a/libgcc/config/i386/cpuinfo.h b/libgcc/config/i386/cpuinfo.h
index 872b45e..3978401 100644
--- a/libgcc/config/i386/cpuinfo.h
+++ b/libgcc/config/i386/cpuinfo.h
@@ -47,6 +47,7 @@ enum processor_types
AMD_BTVER1,
AMD_BTVER2,
AMDFAM17H,
+ INTEL_KNM,
CPU_TYPE_MAX
};
diff --git a/libgcc/config/i386/i386-asm.h b/libgcc/config/i386/i386-asm.h
index 424e0f7..aad1a75 100644
--- a/libgcc/config/i386/i386-asm.h
+++ b/libgcc/config/i386/i386-asm.h
@@ -26,6 +26,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
#ifndef I386_ASM_H
#define I386_ASM_H
+#include "auto-target.h"
#include "auto-host.h"
#define PASTE2(a, b) PASTE2a(a, b)
@@ -69,13 +70,15 @@ ASMNAME(fn):
#ifdef MS2SYSV_STUB_AVX
# define MS2SYSV_STUB_PREFIX __avx_
-# define MOVAPS vmovaps
+# ifdef HAVE_AS_AVX
+# define MOVAPS vmovaps
+# endif
#elif defined(MS2SYSV_STUB_SSE)
# define MS2SYSV_STUB_PREFIX __sse_
# define MOVAPS movaps
#endif
-#if defined (MS2SYSV_STUB_PREFIX) && defined (MOVAPS)
+#ifdef MS2SYSV_STUB_PREFIX
# define MS2SYSV_STUB_BEGIN(base_name) \
HIDDEN_FUNC(PASTE2(MS2SYSV_STUB_PREFIX, base_name))
@@ -83,8 +86,10 @@ ASMNAME(fn):
# define MS2SYSV_STUB_END(base_name) \
FUNC_END(PASTE2(MS2SYSV_STUB_PREFIX, base_name))
-/* Save SSE registers 6-15. off is the offset of rax to get to xmm6. */
-# define SSE_SAVE \
+/* If expanding for sse or avx and we have assembler support. */
+# ifdef MOVAPS
+/* Save SSE registers 6-15 using rax as the base address. */
+# define SSE_SAVE \
MOVAPS %xmm15,-0x30(%rax); \
MOVAPS %xmm14,-0x20(%rax); \
MOVAPS %xmm13,-0x10(%rax); \
@@ -96,8 +101,8 @@ ASMNAME(fn):
MOVAPS %xmm7, 0x50(%rax); \
MOVAPS %xmm6, 0x60(%rax)
-/* Restore SSE registers 6-15. off is the offset of rsi to get to xmm6. */
-# define SSE_RESTORE \
+/* Restore SSE registers 6-15 using rsi as the base address. */
+# define SSE_RESTORE \
MOVAPS -0x30(%rsi), %xmm15; \
MOVAPS -0x20(%rsi), %xmm14; \
MOVAPS -0x10(%rsi), %xmm13; \
@@ -108,6 +113,31 @@ ASMNAME(fn):
MOVAPS 0x40(%rsi), %xmm8 ; \
MOVAPS 0x50(%rsi), %xmm7 ; \
MOVAPS 0x60(%rsi), %xmm6
-
-#endif /* defined (MS2SYSV_STUB_ISA) && defined (MOVAPS) */
+# else /* MOVAPS */
+/* If the assembler doesn't support AVX then directly emit machine code
+ for the instructions above. */
+# define SSE_SAVE \
+ .byte 0xc5, 0x78, 0x29, 0x78, 0xd0; /* vmovaps %xmm15,-0x30(%rax) */ \
+ .byte 0xc5, 0x78, 0x29, 0x70, 0xe0; /* vmovaps %xmm14,-0x20(%rax) */ \
+ .byte 0xc5, 0x78, 0x29, 0x68, 0xf0; /* vmovaps %xmm13,-0x10(%rax) */ \
+ .byte 0xc5, 0x78, 0x29, 0x20; /* vmovaps %xmm12, (%rax) */ \
+ .byte 0xc5, 0x78, 0x29, 0x58, 0x10; /* vmovaps %xmm11, 0x10(%rax) */ \
+ .byte 0xc5, 0x78, 0x29, 0x50, 0x20; /* vmovaps %xmm10, 0x20(%rax) */ \
+ .byte 0xc5, 0x78, 0x29, 0x48, 0x30; /* vmovaps %xmm9, 0x30(%rax) */ \
+ .byte 0xc5, 0x78, 0x29, 0x40, 0x40; /* vmovaps %xmm8, 0x40(%rax) */ \
+ .byte 0xc5, 0xf8, 0x29, 0x78, 0x50; /* vmovaps %xmm7, 0x50(%rax) */ \
+ .byte 0xc5, 0xf8, 0x29, 0x70, 0x60; /* vmovaps %xmm6, 0x60(%rax) */
+# define SSE_RESTORE \
+ .byte 0xc5, 0x78, 0x28, 0x7e, 0xd0; /* vmovaps -0x30(%rsi),%xmm15 */ \
+ .byte 0xc5, 0x78, 0x28, 0x76, 0xe0; /* vmovaps -0x20(%rsi),%xmm14 */ \
+ .byte 0xc5, 0x78, 0x28, 0x6e, 0xf0; /* vmovaps -0x10(%rsi),%xmm13 */ \
+ .byte 0xc5, 0x78, 0x28, 0x26; /* vmovaps (%rsi),%xmm12 */ \
+ .byte 0xc5, 0x78, 0x28, 0x5e, 0x10; /* vmovaps 0x10(%rsi),%xmm11 */ \
+ .byte 0xc5, 0x78, 0x28, 0x56, 0x20; /* vmovaps 0x20(%rsi),%xmm10 */ \
+ .byte 0xc5, 0x78, 0x28, 0x4e, 0x30; /* vmovaps 0x30(%rsi),%xmm9 */ \
+ .byte 0xc5, 0x78, 0x28, 0x46, 0x40; /* vmovaps 0x40(%rsi),%xmm8 */ \
+ .byte 0xc5, 0xf8, 0x28, 0x7e, 0x50; /* vmovaps 0x50(%rsi),%xmm7 */ \
+ .byte 0xc5, 0xf8, 0x28, 0x76, 0x60; /* vmovaps 0x60(%rsi),%xmm6 */
+# endif /* MOVAPS */
+#endif /* MS2SYSV_STUB_PREFIX */
#endif /* I386_ASM_H */
diff --git a/libgcc/config/microblaze/crti.S b/libgcc/config/microblaze/crti.S
index 61626e2..7356163 100644
--- a/libgcc/config/microblaze/crti.S
+++ b/libgcc/config/microblaze/crti.S
@@ -24,6 +24,12 @@
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.section .init, "ax"
.global __init
diff --git a/libgcc/config/microblaze/crtn.S b/libgcc/config/microblaze/crtn.S
index 3b9bf7e..c784ed4 100644
--- a/libgcc/config/microblaze/crtn.S
+++ b/libgcc/config/microblaze/crtn.S
@@ -24,6 +24,12 @@
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.section .init, "ax"
lw r15, r0, r1
rtsd r15, 8
diff --git a/libgcc/config/microblaze/divsi3.S b/libgcc/config/microblaze/divsi3.S
index 42f9cb2..0cd14b3 100644
--- a/libgcc/config/microblaze/divsi3.S
+++ b/libgcc/config/microblaze/divsi3.S
@@ -32,6 +32,12 @@
#
#######################################
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.globl __divsi3
.ent __divsi3
.type __divsi3,@function
diff --git a/libgcc/config/microblaze/moddi3.S b/libgcc/config/microblaze/moddi3.S
index bcea079..7d2a31d 100644
--- a/libgcc/config/microblaze/moddi3.S
+++ b/libgcc/config/microblaze/moddi3.S
@@ -30,6 +30,12 @@
#######################################
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.globl __moddi3
.ent __moddi3
__moddi3:
diff --git a/libgcc/config/microblaze/modsi3.S b/libgcc/config/microblaze/modsi3.S
index eb671a1..118b18d 100644
--- a/libgcc/config/microblaze/modsi3.S
+++ b/libgcc/config/microblaze/modsi3.S
@@ -32,6 +32,12 @@
#
#######################################
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.globl __modsi3
.ent __modsi3
.type __modsi3,@function
diff --git a/libgcc/config/microblaze/muldi3_hard.S b/libgcc/config/microblaze/muldi3_hard.S
index f2188c6..d9f1806 100644
--- a/libgcc/config/microblaze/muldi3_hard.S
+++ b/libgcc/config/microblaze/muldi3_hard.S
@@ -47,6 +47,12 @@
#
#######################################
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.globl muldi3_hardproc
.ent muldi3_hardproc
muldi3_hardproc:
diff --git a/libgcc/config/microblaze/mulsi3.S b/libgcc/config/microblaze/mulsi3.S
index f126b56..3d33522 100644
--- a/libgcc/config/microblaze/mulsi3.S
+++ b/libgcc/config/microblaze/mulsi3.S
@@ -32,6 +32,12 @@
#
#######################################
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.globl __mulsi3
.ent __mulsi3
.type __mulsi3,@function
diff --git a/libgcc/config/microblaze/stack_overflow_exit.S b/libgcc/config/microblaze/stack_overflow_exit.S
index 63319de..5f6be94 100644
--- a/libgcc/config/microblaze/stack_overflow_exit.S
+++ b/libgcc/config/microblaze/stack_overflow_exit.S
@@ -33,6 +33,12 @@
#
#######################################
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.globl _stack_overflow_error
.data
.align 2
diff --git a/libgcc/config/microblaze/udivsi3.S b/libgcc/config/microblaze/udivsi3.S
index 2e08fb2..f01c027 100644
--- a/libgcc/config/microblaze/udivsi3.S
+++ b/libgcc/config/microblaze/udivsi3.S
@@ -32,6 +32,12 @@
#
#######################################
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.globl __udivsi3
.ent __udivsi3
.type __udivsi3,@function
diff --git a/libgcc/config/microblaze/umodsi3.S b/libgcc/config/microblaze/umodsi3.S
index b230a8c..a91eae7 100644
--- a/libgcc/config/microblaze/umodsi3.S
+++ b/libgcc/config/microblaze/umodsi3.S
@@ -32,6 +32,12 @@
#
#######################################
+/* An executable stack is *not* required for these functions. */
+#ifdef __linux__
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
.globl __umodsi3
.ent __umodsi3
.type __umodsi3,@function
diff --git a/libgcc/config/pa/milli64.S b/libgcc/config/pa/milli64.S
index cfd4d83..4690dd1 100644
--- a/libgcc/config/pa/milli64.S
+++ b/libgcc/config/pa/milli64.S
@@ -25,6 +25,12 @@ a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
+/* An executable stack is *not* required for these functions. */
+#if defined(__ELF__) && defined(__linux__)
+.section .note.GNU-stack,"",%progbits
+.previous
+#endif
+
#ifdef pa64
.level 2.0w
#endif
diff --git a/libgcc/config/rl78/adddi3.S b/libgcc/config/rl78/adddi3.S
new file mode 100644
index 0000000..c805055
--- /dev/null
+++ b/libgcc/config/rl78/adddi3.S
@@ -0,0 +1,58 @@
+; Copyright (C) 2017 Free Software Foundation, Inc.
+; Contributed by Sebastian Perta.
+;
+; 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, 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
+; <http://www.gnu.org/licenses/>.
+
+
+#include "vregs.h"
+
+ .text
+
+START_FUNC ___adddi3
+
+ movw hl, sp ; use HL-based addressing (allows for direct addw)
+
+ movw ax, [hl+4]
+ addw ax, [hl+12]
+ movw r8, ax
+
+ mov a, [hl+6] ; middle bytes of the result are determined using 8-bit
+ addc a, [hl+14] ; ADDC insns which both account for and update the carry bit
+ mov r10, a ; (no ADDWC instruction is available)
+ mov a, [hl+7]
+ addc a, [hl+15]
+ mov r11, a
+
+ mov a, [hl+8]
+ addc a, [hl+16]
+ mov r12, a
+ mov a, [hl+9]
+ addc a, [hl+17]
+ mov r13, a
+
+ movw ax, [hl+10]
+ sknc ; account for the possible carry from the
+ incw ax ; latest 8-bit operation
+ addw ax, [hl+18]
+ movw r14, ax
+
+ ret
+
+END_FUNC ___adddi3
diff --git a/libgcc/config/rl78/subdi3.S b/libgcc/config/rl78/subdi3.S
new file mode 100644
index 0000000..f6fcaba
--- /dev/null
+++ b/libgcc/config/rl78/subdi3.S
@@ -0,0 +1,58 @@
+; Copyright (C) 2017 Free Software Foundation, Inc.
+; Contributed by Sebastian Perta.
+;
+; 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, 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
+; <http://www.gnu.org/licenses/>.
+
+
+#include "vregs.h"
+
+ .text
+
+START_FUNC ___subdi3
+
+ movw hl, sp ; use HL-based addressing (allows for direct subw)
+
+ movw ax, [hl+4]
+ subw ax, [hl+12]
+ movw r8, ax
+
+ mov a, [hl+6] ; middle bytes of the result are determined using 8-bit
+ subc a, [hl+14] ; SUBC insns which both account for and update the carry bit
+ mov r10, a ; (no SUBWC instruction is available)
+ mov a, [hl+7]
+ subc a, [hl+15]
+ mov r11, a
+
+ mov a, [hl+8]
+ subc a, [hl+16]
+ mov r12, a
+ mov a, [hl+9]
+ subc a, [hl+17]
+ mov r13, a
+
+ movw ax, [hl+10]
+ sknc ; account for the possible carry from the
+ decw ax ; latest 8-bit operation
+ subw ax, [hl+18]
+ movw r14, ax
+
+ ret
+
+END_FUNC ___subdi3
diff --git a/libgcc/config/rl78/t-rl78 b/libgcc/config/rl78/t-rl78
index 6e48a85..e035d58 100644
--- a/libgcc/config/rl78/t-rl78
+++ b/libgcc/config/rl78/t-rl78
@@ -30,7 +30,9 @@ LIB2ADD = \
$(srcdir)/config/rl78/bit-count.S \
$(srcdir)/config/rl78/fpbit-sf.S \
$(srcdir)/config/rl78/fpmath-sf.S \
- $(srcdir)/config/rl78/cmpsi2.S
+ $(srcdir)/config/rl78/cmpsi2.S \
+ $(srcdir)/config/rl78/adddi3.S \
+ $(srcdir)/config/rl78/subdi3.S
LIB2FUNCS_EXCLUDE = _clzhi2 _clzsi2 _ctzhi2 _ctzsi2 \
_popcounthi2 _popcountsi2 \
diff --git a/libgcc/configure b/libgcc/configure
index 15d34b2..63c50c0 100644
--- a/libgcc/configure
+++ b/libgcc/configure
@@ -5212,6 +5212,45 @@ if test "$enable_tls $gcc_cv_use_emutls" = "yes yes"; then
fi
+
+
+case "${target}" in
+i[34567]86-*-* | x86_64-*-*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the assembler supports AVX" >&5
+$as_echo_n "checking if the assembler supports AVX... " >&6; }
+if test "${libgcc_cv_as_avx+set}" = set; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+asm("vzeroupper");
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ libgcc_cv_as_avx=yes
+else
+ libgcc_cv_as_avx=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $libgcc_cv_as_avx" >&5
+$as_echo "$libgcc_cv_as_avx" >&6; }
+ if test x$libgcc_cv_as_avx = xyes; then
+
+$as_echo "#define HAVE_AS_AVX 1" >>confdefs.h
+
+ fi
+ ;;
+esac
+
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for init priority support" >&5
$as_echo_n "checking for init priority support... " >&6; }
if test "${libgcc_cv_init_priority+set}" = set; then :
diff --git a/libgcc/configure.ac b/libgcc/configure.ac
index da49971..dd60b01 100644
--- a/libgcc/configure.ac
+++ b/libgcc/configure.ac
@@ -506,6 +506,22 @@ if test "$enable_tls $gcc_cv_use_emutls" = "yes yes"; then
fi
AC_SUBST(set_use_emutls)
+dnl Check if as supports AVX instructions.
+AC_DEFUN([LIBGCC_CHECK_AS_AVX], [
+case "${target}" in
+i[[34567]]86-*-* | x86_64-*-*)
+ AC_CACHE_CHECK([if the assembler supports AVX], libgcc_cv_as_avx, [
+ AC_TRY_COMPILE([], [asm("vzeroupper");],
+ [libgcc_cv_as_avx=yes], [libgcc_cv_as_avx=no])
+ ])
+ if test x$libgcc_cv_as_avx = xyes; then
+ AC_DEFINE(HAVE_AS_AVX, 1, [Define to 1 if the assembler supports AVX.])
+ fi
+ ;;
+esac])
+LIBGCC_CHECK_AS_AVX
+
+dnl Check if as supports RTM instructions.
AC_CACHE_CHECK(for init priority support, libgcc_cv_init_priority, [
AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,
[[void ip (void) __attribute__ ((constructor (1)));]])],
diff --git a/libgcc/libgcc2.c b/libgcc/libgcc2.c
index 5d3c69f..83f865a 100644
--- a/libgcc/libgcc2.c
+++ b/libgcc/libgcc2.c
@@ -375,7 +375,8 @@ __mulvDI3 (DWtype u, DWtype v)
}
else
{
- if (uu.s.high == (Wtype) -1 && vv.s.high == (Wtype) - 1)
+ if ((uu.s.high & vv.s.high) == (Wtype) -1
+ && (uu.s.low | vv.s.low) != 0)
{
DWunion ww = {.ll = (UDWtype) (UWtype) uu.s.low
* (UDWtype) (UWtype) vv.s.low};
diff --git a/libgfortran/ChangeLog b/libgfortran/ChangeLog
index 3dd2718..ef9ef19 100644
--- a/libgfortran/ChangeLog
+++ b/libgfortran/ChangeLog
@@ -1,3 +1,14 @@
+2017-10-10 Thomas Koenig <tkoenig@gcc.gnu.org>
+
+ PR libfortran/82233
+ * intrinsics/execute_command_line.c (execute_command_line):
+ No call to runtime_error if cmdstat is present.
+
+2017-09-24 Dominique d'Humieres <dominiq@lps.ens.fr>
+
+ PR libgfortran/79612
+ * runtime/bounds.c: Use GFC_ASSERT.
+
2017-09-10 Paul Thomas <pault@gcc.gnu.org>
PR fortran/34640
diff --git a/libgfortran/intrinsics/execute_command_line.c b/libgfortran/intrinsics/execute_command_line.c
index 339d1bb..31ab36d 100644
--- a/libgfortran/intrinsics/execute_command_line.c
+++ b/libgfortran/intrinsics/execute_command_line.c
@@ -125,15 +125,9 @@ execute_command_line (const char *command, bool wait, int *exitstat,
free (cmd);
/* Now copy back to the Fortran string if needed. */
- if (cmdstat && *cmdstat > EXEC_NOERROR)
- {
- if (cmdmsg)
- fstrcpy (cmdmsg, cmdmsg_len, cmdmsg_values[*cmdstat],
+ if (cmdstat && *cmdstat > EXEC_NOERROR && cmdmsg)
+ fstrcpy (cmdmsg, cmdmsg_len, cmdmsg_values[*cmdstat],
strlen (cmdmsg_values[*cmdstat]));
- else
- runtime_error ("Failure in EXECUTE_COMMAND_LINE: %s",
- cmdmsg_values[*cmdstat]);
- }
}
diff --git a/libgfortran/runtime/bounds.c b/libgfortran/runtime/bounds.c
index ffa0962..376b9d7 100644
--- a/libgfortran/runtime/bounds.c
+++ b/libgfortran/runtime/bounds.c
@@ -40,9 +40,8 @@ bounds_iforeach_return (array_t *retarray, array_t *array, const char *name)
ret_rank = GFC_DESCRIPTOR_RANK (retarray);
- if (ret_rank != 1)
- runtime_error ("Incorrect rank of return array in %s intrinsic:"
- "is %ld, should be 1", name, (long int) ret_rank);
+ /* ret_rank should always be 1, otherwise there is an internal error */
+ GFC_ASSERT(ret_rank == 1);
rank = GFC_DESCRIPTOR_RANK (array);
ret_extent = GFC_DESCRIPTOR_EXTENT(retarray,0);
diff --git a/libgo/Makefile.am b/libgo/Makefile.am
index 2376130..bd0bbdd 100644
--- a/libgo/Makefile.am
+++ b/libgo/Makefile.am
@@ -217,7 +217,8 @@ toolexeclibgodebug_DATA = \
debug/gosym.gox \
debug/macho.gox \
debug/pe.gox \
- debug/plan9obj.gox
+ debug/plan9obj.gox \
+ debug/xcoff.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
@@ -395,6 +396,13 @@ toolexeclibgounicode_DATA = \
unicode/utf16.gox \
unicode/utf8.gox
+# Some packages are only needed for tests, so unlike the other
+# internal packages nothing will explicitly depend on them.
+# Force them to be built.
+noinst_DATA = \
+ internal/testenv.gox \
+ net/internal/socktest.gox
+
if LIBGO_IS_RTEMS
rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
else
@@ -573,7 +581,7 @@ s-runtime-inc: runtime.lo Makefile
rm -f runtime.inc.tmp2 runtime.inc.tmp3
$(STAMP) $@
-noinst_DATA = zstdpkglist.go zdefaultcc.go
+noinst_DATA += zstdpkglist.go zdefaultcc.go
# Generate the list of go std packages that were included in libgo
zstdpkglist.go: s-zstdpkglist; @true
@@ -715,6 +723,7 @@ PACKAGES = \
debug/macho \
debug/pe \
debug/plan9obj \
+ debug/xcoff \
encoding \
encoding/ascii85 \
encoding/asn1 \
@@ -924,6 +933,12 @@ libgotool_a_SOURCES =
libgotool_a_DEPENDENCIES = $(addsuffix .lo,$(GOTOOL_PACKAGES))
libgotool_a_LIBADD = $(addsuffix .o,$(GOTOOL_PACKAGES))
+define STATIC_template
+$(subst -,_,$(subst .,_,$(subst /,_,$(1))))_GOCFLAGS = -static
+endef
+
+$(foreach package,$(GOTOOL_PACKAGES),$(eval $(call STATIC_template,$(package).lo)))
+
# Make sure runtime.inc is built before compiling any .c file.
$(libgo_la_OBJECTS): runtime.inc
$(libgo_llgo_la_OBJECTS): runtime.inc
@@ -1280,6 +1295,7 @@ TEST_PACKAGES = \
debug/macho/check \
debug/pe/check \
debug/plan9obj/check \
+ debug/xcoff/check \
encoding/ascii85/check \
encoding/asn1/check \
encoding/base32/check \
diff --git a/libgo/Makefile.in b/libgo/Makefile.in
index 5f7adb2..064df58 100644
--- a/libgo/Makefile.in
+++ b/libgo/Makefile.in
@@ -612,7 +612,8 @@ toolexeclibgodebug_DATA = \
debug/gosym.gox \
debug/macho.gox \
debug/pe.gox \
- debug/plan9obj.gox
+ debug/plan9obj.gox \
+ debug/xcoff.gox
toolexeclibgoencodingdir = $(toolexeclibgodir)/encoding
toolexeclibgoencoding_DATA = \
@@ -765,6 +766,12 @@ toolexeclibgounicode_DATA = \
unicode/utf16.gox \
unicode/utf8.gox
+
+# Some packages are only needed for tests, so unlike the other
+# internal packages nothing will explicitly depend on them.
+# Force them to be built.
+noinst_DATA = internal/testenv.gox net/internal/socktest.gox \
+ zstdpkglist.go zdefaultcc.go
@LIBGO_IS_RTEMS_FALSE@rtems_task_variable_add_file =
@LIBGO_IS_RTEMS_TRUE@rtems_task_variable_add_file = runtime/rtems-task-variable-add.c
@LIBGO_IS_AIX_FALSE@@LIBGO_IS_DARWIN_FALSE@@LIBGO_IS_FREEBSD_FALSE@@LIBGO_IS_IRIX_FALSE@@LIBGO_IS_LINUX_FALSE@@LIBGO_IS_NETBSD_FALSE@@LIBGO_IS_SOLARIS_FALSE@runtime_getncpu_file = runtime/getncpu-none.c
@@ -817,7 +824,6 @@ runtime_files = \
GCCGO_INSTALL_NAME := $(shell echo gccgo|sed '$(program_transform_name)')
GCC_INSTALL_NAME := $(shell echo gcc|sed '$(program_transform_name)')
GXX_INSTALL_NAME := $(shell echo g++|sed '$(program_transform_name)')
-noinst_DATA = zstdpkglist.go zdefaultcc.go
@LIBGO_IS_LINUX_FALSE@syscall_epoll_file =
@LIBGO_IS_LINUX_TRUE@syscall_epoll_file = epoll.go
SYSINFO_FLAGS = \
@@ -868,6 +874,7 @@ PACKAGES = \
debug/macho \
debug/pe \
debug/plan9obj \
+ debug/xcoff \
encoding \
encoding/ascii85 \
encoding/asn1 \
@@ -1293,6 +1300,7 @@ TEST_PACKAGES = \
debug/macho/check \
debug/pe/check \
debug/plan9obj/check \
+ debug/xcoff/check \
encoding/ascii85/check \
encoding/asn1/check \
encoding/base32/check \
@@ -3248,6 +3256,12 @@ s-epoll: Makefile
$(SHELL) $(srcdir)/mvifdiff.sh epoll.go.tmp epoll.go
$(STAMP) $@
+define STATIC_template
+$(subst -,_,$(subst .,_,$(subst /,_,$(1))))_GOCFLAGS = -static
+endef
+
+$(foreach package,$(GOTOOL_PACKAGES),$(eval $(call STATIC_template,$(package).lo)))
+
# Make sure runtime.inc is built before compiling any .c file.
$(libgo_la_OBJECTS): runtime.inc
$(libgo_llgo_la_OBJECTS): runtime.inc
diff --git a/libgo/go/cmd/cgo/gcc.go b/libgo/go/cmd/cgo/gcc.go
index 03239a0..5453d1c 100644
--- a/libgo/go/cmd/cgo/gcc.go
+++ b/libgo/go/cmd/cgo/gcc.go
@@ -13,6 +13,7 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
+ "debug/xcoff"
"encoding/binary"
"errors"
"flag"
@@ -1289,6 +1290,10 @@ func (p *Package) gccMachine() []string {
return []string{"-mabi=64"}
case "mips", "mipsle":
return []string{"-mabi=32"}
+ case "ppc64":
+ if goos == "aix" {
+ return []string{"-maix64"}
+ }
}
return nil
}
@@ -1616,7 +1621,79 @@ func (p *Package) gccDebug(stdin []byte, nnames int) (d *dwarf.Data, ints []int6
return d, ints, floats, strs
}
- fatalf("cannot parse gcc output %s as ELF, Mach-O, PE object", gccTmp())
+ if f, err := xcoff.Open(gccTmp()); err == nil {
+ defer f.Close()
+ d, err := f.DWARF()
+ if err != nil {
+ fatalf("cannot load DWARF output from %s: %v", gccTmp(), err)
+ }
+ bo := binary.BigEndian
+ for _, s := range f.Symbols {
+ switch {
+ case isDebugInts(s.Name):
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ ints = make([]int64, len(data)/8)
+ for i := range ints {
+ ints[i] = int64(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ case isDebugFloats(s.Name):
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ floats = make([]float64, len(data)/8)
+ for i := range floats {
+ floats[i] = math.Float64frombits(bo.Uint64(data[i*8:]))
+ }
+ }
+ }
+ }
+ default:
+ if n := indexOfDebugStr(s.Name); n != -1 {
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ strdata[n] = string(data)
+ }
+ }
+ }
+ break
+ }
+ if n := indexOfDebugStrlen(s.Name); n != -1 {
+ if i := int(s.SectionNumber) - 1; 0 <= i && i < len(f.Sections) {
+ sect := f.Sections[i]
+ if s.Value < sect.Size {
+ if sdat, err := sect.Data(); err == nil {
+ data := sdat[s.Value:]
+ strlen := bo.Uint64(data[:8])
+ if strlen > (1<<(uint(p.IntSize*8)-1) - 1) { // greater than MaxInt?
+ fatalf("string literal too big")
+ }
+ strlens[n] = int(strlen)
+ }
+ }
+ }
+ break
+ }
+ }
+ }
+
+ buildStrings()
+
+ return d, ints, floats, strs
+ }
+
+ fatalf("cannot parse gcc output %s as ELF, Mach-O, PE, XCOFF object", gccTmp())
panic("not reached")
}
diff --git a/libgo/go/cmd/cgo/out.go b/libgo/go/cmd/cgo/out.go
index c4ff07d..72dd884 100644
--- a/libgo/go/cmd/cgo/out.go
+++ b/libgo/go/cmd/cgo/out.go
@@ -9,6 +9,7 @@ import (
"debug/elf"
"debug/macho"
"debug/pe"
+ "debug/xcoff"
"fmt"
"go/ast"
"go/printer"
@@ -324,7 +325,25 @@ func dynimport(obj string) {
return
}
- fatalf("cannot parse %s as ELF, Mach-O or PE", obj)
+ if f, err := xcoff.Open(obj); err == nil {
+ sym, err := f.ImportedSymbols()
+ if err != nil {
+ fatalf("cannot load imported symbols from XCOFF file %s: %v", obj, err)
+ }
+ for _, s := range sym {
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic %s %s %q\n", s.Name, s.Name, s.Library)
+ }
+ lib, err := f.ImportedLibraries()
+ if err != nil {
+ fatalf("cannot load imported libraries from XCOFF file %s: %v", obj, err)
+ }
+ for _, l := range lib {
+ fmt.Fprintf(stdout, "//go:cgo_import_dynamic _ _ %q\n", l)
+ }
+ return
+ }
+
+ fatalf("cannot parse %s as ELF, Mach-O, PE or XCOFF", obj)
}
// Construct a gcc struct matching the gc argument frame.
diff --git a/libgo/go/cmd/go/internal/base/signal_unix.go b/libgo/go/cmd/go/internal/base/signal_unix.go
index 4ca3da9..b90f3a2 100644
--- a/libgo/go/cmd/go/internal/base/signal_unix.go
+++ b/libgo/go/cmd/go/internal/base/signal_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package base
diff --git a/libgo/go/cmd/go/internal/work/build.go b/libgo/go/cmd/go/internal/work/build.go
index de8c493..562730b 100644
--- a/libgo/go/cmd/go/internal/work/build.go
+++ b/libgo/go/cmd/go/internal/work/build.go
@@ -9,6 +9,7 @@ import (
"bytes"
"container/heap"
"debug/elf"
+ "debug/xcoff"
"errors"
"flag"
"fmt"
@@ -745,9 +746,13 @@ func (b *Builder) Init() {
func readpkglist(shlibpath string) (pkgs []*load.Package) {
var stk load.ImportStack
if cfg.BuildToolchainName == "gccgo" {
- f, _ := elf.Open(shlibpath)
- sect := f.Section(".go_export")
- data, _ := sect.Data()
+ var data []byte
+ if f, err := elf.Open(shlibpath); err == nil {
+ sect := f.Section(".go_export")
+ data, _ = sect.Data()
+ } else if f, err := xcoff.Open(shlibpath); err == nil {
+ data = f.CSect(".go_export")
+ }
scanner := bufio.NewScanner(bytes.NewBuffer(data))
for scanner.Scan() {
t := scanner.Text()
@@ -1815,6 +1820,7 @@ func (b *Builder) cover(a *Action, dst, src string, perm os.FileMode, varName st
var objectMagic = [][]byte{
{'!', '<', 'a', 'r', 'c', 'h', '>', '\n'}, // Package archive
+ {'<', 'b', 'i', 'g', 'a', 'f', '>', '\n'}, // Package archive (AIX format)
{'\x7F', 'E', 'L', 'F'}, // ELF
{0xFE, 0xED, 0xFA, 0xCE}, // Mach-O big-endian 32-bit
{0xFE, 0xED, 0xFA, 0xCF}, // Mach-O big-endian 64-bit
@@ -1824,6 +1830,8 @@ var objectMagic = [][]byte{
{0x00, 0x00, 0x01, 0xEB}, // Plan 9 i386
{0x00, 0x00, 0x8a, 0x97}, // Plan 9 amd64
{0x00, 0x00, 0x06, 0x47}, // Plan 9 arm
+ {0x01, 0xDF}, // XCOFF32
+ {0x01, 0xF7}, // XCOFF64
}
func isObject(s string) bool {
@@ -3308,6 +3316,10 @@ func (b *Builder) gccArchArgs() []string {
return []string{"-mabi=64"}
case "mips", "mipsle":
return []string{"-mabi=32", "-march=mips32"}
+ case "ppc64":
+ if cfg.Goos == "aix" {
+ return []string{"-maix64"}
+ }
}
return nil
}
diff --git a/libgo/go/debug/dwarf/entry.go b/libgo/go/debug/dwarf/entry.go
index 80bf14c..ffa61c28 100644
--- a/libgo/go/debug/dwarf/entry.go
+++ b/libgo/go/debug/dwarf/entry.go
@@ -33,13 +33,13 @@ type abbrevTable map[uint32]abbrev
// ParseAbbrev returns the abbreviation table that starts at byte off
// in the .debug_abbrev section.
-func (d *Data) parseAbbrev(off uint32, vers int) (abbrevTable, error) {
+func (d *Data) parseAbbrev(off uint64, vers int) (abbrevTable, error) {
if m, ok := d.abbrevCache[off]; ok {
return m, nil
}
data := d.abbrev
- if off > uint32(len(data)) {
+ if off > uint64(len(data)) {
data = nil
} else {
data = data[off:]
diff --git a/libgo/go/debug/dwarf/entry_test.go b/libgo/go/debug/dwarf/entry_test.go
index 58a5d57..58f3023 100644
--- a/libgo/go/debug/dwarf/entry_test.go
+++ b/libgo/go/debug/dwarf/entry_test.go
@@ -135,3 +135,63 @@ func TestReaderRanges(t *testing.T) {
t.Errorf("saw only %d subprograms, expected %d", i, len(subprograms))
}
}
+
+func Test64Bit(t *testing.T) {
+ // I don't know how to generate a 64-bit DWARF debug
+ // compilation unit except by using XCOFF, so this is
+ // hand-written.
+ tests := []struct {
+ name string
+ info []byte
+ }{
+ {
+ "32-bit little",
+ []byte{0x30, 0, 0, 0, // comp unit length
+ 4, 0, // DWARF version 4
+ 0, 0, 0, 0, // abbrev offset
+ 8, // address size
+ 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ {
+ "64-bit little",
+ []byte{0xff, 0xff, 0xff, 0xff, // 64-bit DWARF
+ 0x30, 0, 0, 0, 0, 0, 0, 0, // comp unit length
+ 4, 0, // DWARF version 4
+ 0, 0, 0, 0, 0, 0, 0, 0, // abbrev offset
+ 8, // address size
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ {
+ "64-bit big",
+ []byte{0xff, 0xff, 0xff, 0xff, // 64-bit DWARF
+ 0, 0, 0, 0, 0, 0, 0, 0x30, // comp unit length
+ 0, 4, // DWARF version 4
+ 0, 0, 0, 0, 0, 0, 0, 0, // abbrev offset
+ 8, // address size
+ 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ },
+ },
+ }
+
+ for _, test := range tests {
+ _, err := New(nil, nil, nil, test.info, nil, nil, nil, nil)
+ if err != nil {
+ t.Errorf("%s: %v", test.name, err)
+ }
+ }
+}
diff --git a/libgo/go/debug/dwarf/open.go b/libgo/go/debug/dwarf/open.go
index 0e9c01c..9381869 100644
--- a/libgo/go/debug/dwarf/open.go
+++ b/libgo/go/debug/dwarf/open.go
@@ -23,7 +23,7 @@ type Data struct {
str []byte
// parsed data
- abbrevCache map[uint32]abbrevTable
+ abbrevCache map[uint64]abbrevTable
order binary.ByteOrder
typeCache map[Offset]Type
typeSigs map[uint64]*typeUnit
@@ -33,7 +33,7 @@ type Data struct {
// New returns a new Data object initialized from the given parameters.
// Rather than calling this function directly, clients should typically use
// the DWARF method of the File type of the appropriate package debug/elf,
-// debug/macho, or debug/pe.
+// debug/macho, debug/pe, or debug/xcoff.
//
// The []byte arguments are the data from the corresponding debug section
// in the object file; for example, for an ELF object, abbrev is the contents of
@@ -48,17 +48,26 @@ func New(abbrev, aranges, frame, info, line, pubnames, ranges, str []byte) (*Dat
pubnames: pubnames,
ranges: ranges,
str: str,
- abbrevCache: make(map[uint32]abbrevTable),
+ abbrevCache: make(map[uint64]abbrevTable),
typeCache: make(map[Offset]Type),
typeSigs: make(map[uint64]*typeUnit),
}
// Sniff .debug_info to figure out byte order.
- // bytes 4:6 are the version, a tiny 16-bit number (1, 2, 3).
+ // 32-bit DWARF: 4 byte length, 2 byte version.
+ // 64-bit DWARf: 4 bytes of 0xff, 8 byte length, 2 byte version.
if len(d.info) < 6 {
return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
}
- x, y := d.info[4], d.info[5]
+ offset := 4
+ if d.info[0] == 0xff && d.info[1] == 0xff && d.info[2] == 0xff && d.info[3] == 0xff {
+ if len(d.info) < 14 {
+ return nil, DecodeError{"info", Offset(len(d.info)), "too short"}
+ }
+ offset = 12
+ }
+ // Fetch the version, a tiny 16-bit number (1, 2, 3, 4, 5).
+ x, y := d.info[offset], d.info[offset+1]
switch {
case x == 0 && y == 0:
return nil, DecodeError{"info", 4, "unsupported version 0"}
diff --git a/libgo/go/debug/dwarf/typeunit.go b/libgo/go/debug/dwarf/typeunit.go
index 652e02d..76b357c 100644
--- a/libgo/go/debug/dwarf/typeunit.go
+++ b/libgo/go/debug/dwarf/typeunit.go
@@ -38,16 +38,11 @@ func (d *Data) parseTypes(name string, types []byte) error {
b.error("unsupported DWARF version " + strconv.Itoa(vers))
return b.err
}
- var ao uint32
+ var ao uint64
if !dwarf64 {
- ao = b.uint32()
+ ao = uint64(b.uint32())
} else {
- ao64 := b.uint64()
- if ao64 != uint64(uint32(ao64)) {
- b.error("type unit abbrev offset overflow")
- return b.err
- }
- ao = uint32(ao64)
+ ao = b.uint64()
}
atable, err := d.parseAbbrev(ao, vers)
if err != nil {
diff --git a/libgo/go/debug/dwarf/unit.go b/libgo/go/debug/dwarf/unit.go
index e45aed7..98024ca 100644
--- a/libgo/go/debug/dwarf/unit.go
+++ b/libgo/go/debug/dwarf/unit.go
@@ -61,13 +61,20 @@ func (d *Data) parseUnits() ([]unit, error) {
u.base = b.off
var n Offset
n, u.is64 = b.unitLength()
+ dataOff := b.off
vers := b.uint16()
if vers != 2 && vers != 3 && vers != 4 {
b.error("unsupported DWARF version " + strconv.Itoa(int(vers)))
break
}
u.vers = int(vers)
- atable, err := d.parseAbbrev(b.uint32(), u.vers)
+ var abbrevOff uint64
+ if u.is64 {
+ abbrevOff = b.uint64()
+ } else {
+ abbrevOff = uint64(b.uint32())
+ }
+ atable, err := d.parseAbbrev(abbrevOff, u.vers)
if err != nil {
if b.err == nil {
b.err = err
@@ -77,7 +84,7 @@ func (d *Data) parseUnits() ([]unit, error) {
u.atable = atable
u.asize = int(b.uint8())
u.off = b.off
- u.data = b.bytes(int(n - (2 + 4 + 1)))
+ u.data = b.bytes(int(n - (b.off - dataOff)))
}
if b.err != nil {
return nil, b.err
diff --git a/libgo/go/debug/elf/file.go b/libgo/go/debug/elf/file.go
index c493f2a..b415bb1 100644
--- a/libgo/go/debug/elf/file.go
+++ b/libgo/go/debug/elf/file.go
@@ -600,6 +600,8 @@ func (f *File) applyRelocations(dst []byte, rels []byte) error {
return f.applyRelocationsMIPS64(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_S390:
return f.applyRelocationss390x(dst, rels)
+ case f.Class == ELFCLASS32 && (f.Machine == EM_SPARC || f.Machine == EM_SPARC32PLUS):
+ return f.applyRelocationsSPARC(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_SPARCV9:
return f.applyRelocationsSPARC64(dst, rels)
case f.Class == ELFCLASS64 && f.Machine == EM_ALPHA:
@@ -1006,6 +1008,46 @@ func (f *File) applyRelocationss390x(dst []byte, rels []byte) error {
return nil
}
+func (f *File) applyRelocationsSPARC(dst []byte, rels []byte) error {
+ // 12 is the size of Rela32.
+ if len(rels)%12 != 0 {
+ return errors.New("length of relocation section is not a multiple of 12")
+ }
+
+ symbols, _, err := f.getSymbols(SHT_SYMTAB)
+ if err != nil {
+ return err
+ }
+
+ b := bytes.NewReader(rels)
+ var rela Rela32
+
+ for b.Len() > 0 {
+ binary.Read(b, f.ByteOrder, &rela)
+ symNo := rela.Info >> 32
+ t := R_SPARC(rela.Info & 0xff)
+
+ if symNo == 0 || symNo > uint32(len(symbols)) {
+ continue
+ }
+ sym := &symbols[symNo-1]
+ if SymType(sym.Info&0xf) != STT_SECTION {
+ // We don't handle non-section relocations for now.
+ continue
+ }
+
+ switch t {
+ case R_SPARC_32, R_SPARC_UA32:
+ if rela.Off+4 >= uint32(len(dst)) || rela.Addend < 0 {
+ continue
+ }
+ f.ByteOrder.PutUint32(dst[rela.Off:rela.Off+4], uint32(rela.Addend))
+ }
+ }
+
+ return nil
+}
+
func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
// 24 is the size of Rela64.
if len(rels)%24 != 0 {
diff --git a/libgo/go/debug/xcoff/file.go b/libgo/go/debug/xcoff/file.go
new file mode 100644
index 0000000..2958610
--- /dev/null
+++ b/libgo/go/debug/xcoff/file.go
@@ -0,0 +1,539 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package xcoff implements access to XCOFF (Extended Common Object File Format) files.
+package xcoff
+
+import (
+ "debug/dwarf"
+ "encoding/binary"
+ "fmt"
+ "io"
+ "os"
+ "strings"
+)
+
+// Information we store about an XCOFF section header.
+type SectionHeader struct {
+ Name string
+ VirtualAddress uint64
+ Size uint64
+ Type uint32
+}
+type Section struct {
+ SectionHeader
+ io.ReaderAt
+ sr *io.SectionReader
+}
+
+// Information we store about an XCOFF symbol.
+type AuxiliaryCSect struct {
+ Length int64
+ StorageMappingClass int
+ SymbolType int
+}
+type Symbol struct {
+ Name string
+ Value uint64
+ SectionNumber int
+ StorageClass int
+ AuxCSect AuxiliaryCSect
+}
+
+// Information we store about an imported XCOFF symbol.
+type ImportedSymbol struct {
+ Name string
+ Library string
+}
+
+// A File represents an open XCOFF file.
+type FileHeader struct {
+ TargetMachine uint16
+}
+type File struct {
+ FileHeader
+ Sections []*Section
+ Symbols []*Symbol
+ StringTable []byte
+ LibraryPaths []string
+
+ closer io.Closer
+}
+
+// Open opens the named file using os.Open and prepares it for use as an XCOFF binary.
+func Open(name string) (*File, error) {
+ f, err := os.Open(name)
+ if err != nil {
+ return nil, err
+ }
+ ff, err := NewFile(f)
+ if err != nil {
+ f.Close()
+ return nil, err
+ }
+ ff.closer = f
+ return ff, nil
+}
+
+// Close closes the File.
+// If the File was created using NewFile directly instead of Open,
+// Close has no effect.
+func (f *File) Close() error {
+ var err error
+ if f.closer != nil {
+ err = f.closer.Close()
+ f.closer = nil
+ }
+ return err
+}
+
+// SectionByType returns the first section in f with the
+// given type, or nil if there is no such section.
+func (f *File) SectionByType(typ uint32) *Section {
+ for _, s := range f.Sections {
+ if s.Type == typ {
+ return s
+ }
+ }
+ return nil
+}
+
+// cstring converts ASCII byte sequence b to string.
+// It stops once it finds 0 or reaches end of b.
+func cstring(b []byte) string {
+ var i int
+ for i = 0; i < len(b) && b[i] != 0; i++ {
+ }
+ return string(b[:i])
+}
+
+// getString extracts a string from an XCOFF string table.
+func getString(st []byte, offset uint32) (string, bool) {
+ if offset < 4 || int(offset) >= len(st) {
+ return "", false
+ }
+ return cstring(st[offset:]), true
+}
+
+// NewFile creates a new File for accessing an XCOFF binary in an underlying reader.
+func NewFile(r io.ReaderAt) (*File, error) {
+ sr := io.NewSectionReader(r, 0, 1<<63-1)
+ // Read XCOFF target machine
+ var magic uint16
+ if err := binary.Read(sr, binary.BigEndian, &magic); err != nil {
+ return nil, err
+ }
+ if magic != U802TOCMAGIC && magic != U64_TOCMAGIC {
+ return nil, fmt.Errorf("unrecognised XCOFF magic", magic)
+ }
+
+ f := new(File)
+ f.TargetMachine = magic
+
+ // Read XCOFF file header
+ sr.Seek(0, io.SeekStart)
+ var nscns uint16
+ var symptr uint64
+ var nsyms int32
+ var opthdr uint16
+ var hdrsz int
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ fhdr := new(FileHeader32)
+ if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
+ return nil, err
+ }
+ nscns = fhdr.Fnscns
+ symptr = uint64(fhdr.Fsymptr)
+ nsyms = fhdr.Fnsyms
+ opthdr = fhdr.Fopthdr
+ hdrsz = FILHSZ_32
+ case U64_TOCMAGIC:
+ fhdr := new(FileHeader64)
+ if err := binary.Read(sr, binary.BigEndian, fhdr); err != nil {
+ return nil, err
+ }
+ nscns = fhdr.Fnscns
+ symptr = fhdr.Fsymptr
+ nsyms = fhdr.Fnsyms
+ opthdr = fhdr.Fopthdr
+ hdrsz = FILHSZ_64
+ }
+
+ if symptr == 0 || nsyms <= 0 {
+ return nil, fmt.Errorf("no symbol table")
+ }
+
+ // Read string table (located right after symbol table).
+ offset := symptr + uint64(nsyms)*SYMESZ
+ sr.Seek(int64(offset), io.SeekStart)
+ // The first 4 bytes contain the length (in bytes).
+ var l uint32
+ binary.Read(sr, binary.BigEndian, &l)
+ if l > 4 {
+ sr.Seek(int64(offset), io.SeekStart)
+ f.StringTable = make([]byte, l)
+ io.ReadFull(sr, f.StringTable)
+ }
+
+ // Read section headers
+ sr.Seek(int64(hdrsz)+int64(opthdr), io.SeekStart)
+ f.Sections = make([]*Section, nscns)
+ for i := 0; i < int(nscns); i++ {
+ var scnptr uint64
+ s := new(Section)
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ shdr := new(SectionHeader32)
+ if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
+ return nil, err
+ }
+ s.Name = cstring(shdr.Sname[:])
+ s.VirtualAddress = uint64(shdr.Svaddr)
+ s.Size = uint64(shdr.Ssize)
+ scnptr = uint64(shdr.Sscnptr)
+ s.Type = shdr.Sflags
+ case U64_TOCMAGIC:
+ shdr := new(SectionHeader64)
+ if err := binary.Read(sr, binary.BigEndian, shdr); err != nil {
+ return nil, err
+ }
+ s.Name = cstring(shdr.Sname[:])
+ s.VirtualAddress = shdr.Svaddr
+ s.Size = shdr.Ssize
+ scnptr = shdr.Sscnptr
+ s.Type = shdr.Sflags
+ }
+ r2 := r
+ if scnptr == 0 { // .bss must have all 0s
+ r2 = zeroReaderAt{}
+ }
+ s.sr = io.NewSectionReader(r2, int64(scnptr), int64(s.Size))
+ s.ReaderAt = s.sr
+ f.Sections[i] = s
+ }
+
+ // Read symbol table
+ sr.Seek(int64(symptr), io.SeekStart)
+ f.Symbols = make([]*Symbol, 0)
+ for i := 0; i < int(nsyms); i++ {
+ var numaux int
+ var ok bool
+ sym := new(Symbol)
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ se := new(SymEnt32)
+ if err := binary.Read(sr, binary.BigEndian, se); err != nil {
+ return nil, err
+ }
+ numaux = int(se.Nnumaux)
+ sym.SectionNumber = int(se.Nscnum)
+ sym.StorageClass = int(se.Nsclass)
+ sym.Value = uint64(se.Nvalue)
+ zeroes := binary.BigEndian.Uint32(se.Nname[:4])
+ if zeroes != 0 {
+ sym.Name = cstring(se.Nname[:])
+ } else {
+ offset := binary.BigEndian.Uint32(se.Nname[4:])
+ sym.Name, ok = getString(f.StringTable, offset)
+ if !ok {
+ goto skip
+ }
+ }
+ case U64_TOCMAGIC:
+ se := new(SymEnt64)
+ if err := binary.Read(sr, binary.BigEndian, se); err != nil {
+ return nil, err
+ }
+ numaux = int(se.Nnumaux)
+ sym.SectionNumber = int(se.Nscnum)
+ sym.StorageClass = int(se.Nsclass)
+ sym.Value = se.Nvalue
+ sym.Name, ok = getString(f.StringTable, se.Noffset)
+ if !ok {
+ goto skip
+ }
+ }
+ if sym.StorageClass != C_EXT && sym.StorageClass != C_WEAKEXT && sym.StorageClass != C_HIDEXT {
+ goto skip
+ }
+ // Must have at least one csect auxiliary entry.
+ if numaux < 1 || i+numaux >= int(nsyms) {
+ goto skip
+ }
+ if sym.SectionNumber < 1 || sym.SectionNumber > int(nscns) {
+ goto skip
+ }
+ sym.Value -= f.Sections[sym.SectionNumber-1].VirtualAddress
+
+ // Read csect auxiliary entry (by convention, it is the last).
+ sr.Seek(int64((numaux-1)*SYMESZ), io.SeekCurrent)
+ i += numaux
+ numaux = 0
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ aux := new(AuxCSect32)
+ if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
+ return nil, err
+ }
+ sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
+ sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
+ sym.AuxCSect.Length = int64(aux.Xscnlen)
+ case U64_TOCMAGIC:
+ aux := new(AuxCSect64)
+ if err := binary.Read(sr, binary.BigEndian, aux); err != nil {
+ return nil, err
+ }
+ sym.AuxCSect.SymbolType = int(aux.Xsmtyp & 0x7)
+ sym.AuxCSect.StorageMappingClass = int(aux.Xsmclas)
+ sym.AuxCSect.Length = int64(aux.Xscnlenhi)<<32 | int64(aux.Xscnlenlo)
+ }
+
+ f.Symbols = append(f.Symbols, sym)
+ skip:
+ i += numaux // Skip auxiliary entries
+ sr.Seek(int64(numaux)*SYMESZ, io.SeekCurrent)
+ }
+
+ return f, nil
+}
+
+// zeroReaderAt is ReaderAt that reads 0s.
+type zeroReaderAt struct{}
+
+// ReadAt writes len(p) 0s into p.
+func (w zeroReaderAt) ReadAt(p []byte, off int64) (n int, err error) {
+ for i := range p {
+ p[i] = 0
+ }
+ return len(p), nil
+}
+
+// Data reads and returns the contents of the XCOFF section s.
+func (s *Section) Data() ([]byte, error) {
+ dat := make([]byte, s.sr.Size())
+ n, err := s.sr.ReadAt(dat, 0)
+ if n == len(dat) {
+ err = nil
+ }
+ return dat[0:n], err
+}
+
+// CSect reads and returns the contents of a csect.
+func (f *File) CSect(name string) []byte {
+ for _, sym := range f.Symbols {
+ if sym.Name == name && sym.AuxCSect.SymbolType == XTY_SD {
+ if i := sym.SectionNumber - 1; 0 <= i && i < len(f.Sections) {
+ s := f.Sections[i]
+ if sym.Value+uint64(sym.AuxCSect.Length) <= s.Size {
+ dat := make([]byte, sym.AuxCSect.Length)
+ _, err := s.sr.ReadAt(dat, int64(sym.Value))
+ if err != nil {
+ return nil
+ }
+ return dat
+ }
+ }
+ break
+ }
+ }
+ return nil
+}
+
+func (f *File) DWARF() (*dwarf.Data, error) {
+ // There are many other DWARF sections, but these
+ // are the ones the debug/dwarf package uses.
+ // Don't bother loading others.
+ var subtypes = [...]uint32{SSUBTYP_DWABREV, SSUBTYP_DWINFO, SSUBTYP_DWLINE, SSUBTYP_DWARNGE, SSUBTYP_DWSTR}
+ var dat [len(subtypes)][]byte
+ for i, subtype := range subtypes {
+ s := f.SectionByType(STYP_DWARF | subtype)
+ if s != nil {
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+ dat[i] = b
+ }
+ }
+
+ abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
+ return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+}
+
+// Read a loader section import file IDs.
+func (f *File) readImportIDs(s *Section) ([]string, error) {
+ // Read loader header
+ s.sr.Seek(0, io.SeekStart)
+ var istlen uint32
+ var nimpid int32
+ var impoff uint64
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ lhdr := new(LoaderHeader32)
+ if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
+ return nil, err
+ }
+ istlen = lhdr.Listlen
+ nimpid = lhdr.Lnimpid
+ impoff = uint64(lhdr.Limpoff)
+ case U64_TOCMAGIC:
+ lhdr := new(LoaderHeader64)
+ if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
+ return nil, err
+ }
+ istlen = lhdr.Listlen
+ nimpid = lhdr.Lnimpid
+ impoff = lhdr.Limpoff
+ }
+
+ // Read loader import file ID table
+ s.sr.Seek(int64(impoff), io.SeekStart)
+ table := make([]byte, istlen)
+ io.ReadFull(s.sr, table)
+
+ offset := 0
+ // First import file ID is the default LIBPATH value
+ libpath := cstring(table[offset:])
+ f.LibraryPaths = strings.Split(libpath, ":")
+ offset += len(libpath) + 3 // 3 null bytes
+ all := make([]string, 0)
+ for i := 1; i < int(nimpid); i++ {
+ impidpath := cstring(table[offset:])
+ offset += len(impidpath) + 1
+ impidbase := cstring(table[offset:])
+ offset += len(impidbase) + 1
+ impidmem := cstring(table[offset:])
+ offset += len(impidmem) + 1
+ var path string
+ if len(impidpath) > 0 {
+ path = impidpath + "/" + impidbase
+ } else {
+ path = impidbase
+ }
+ all = append(all, path)
+ }
+
+ return all, nil
+}
+
+// ImportedSymbols returns the names of all symbols
+// referred to by the binary f that are expected to be
+// satisfied by other libraries at dynamic load time.
+// It does not return weak symbols.
+func (f *File) ImportedSymbols() ([]ImportedSymbol, error) {
+ s := f.SectionByType(STYP_LOADER)
+ if s == nil {
+ return nil, nil
+ }
+ // Read loader header
+ s.sr.Seek(0, io.SeekStart)
+ var stlen uint32
+ var stoff uint64
+ var nsyms int32
+ var symoff uint64
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ lhdr := new(LoaderHeader32)
+ if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
+ return nil, err
+ }
+ stlen = lhdr.Lstlen
+ stoff = uint64(lhdr.Lstoff)
+ nsyms = lhdr.Lnsyms
+ symoff = LDHDRSZ_32
+ case U64_TOCMAGIC:
+ lhdr := new(LoaderHeader64)
+ if err := binary.Read(s.sr, binary.BigEndian, lhdr); err != nil {
+ return nil, err
+ }
+ stlen = lhdr.Lstlen
+ stoff = lhdr.Lstoff
+ nsyms = lhdr.Lnsyms
+ symoff = lhdr.Lsymoff
+ }
+
+ // Read loader section string table
+ s.sr.Seek(int64(stoff), io.SeekStart)
+ st := make([]byte, stlen)
+ io.ReadFull(s.sr, st)
+
+ // Read imported libraries
+ libs, err := f.readImportIDs(s)
+ if err != nil {
+ return nil, err
+ }
+
+ // Read loader symbol table
+ s.sr.Seek(int64(symoff), io.SeekStart)
+ all := make([]ImportedSymbol, 0)
+ for i := 0; i < int(nsyms); i++ {
+ var name string
+ var ifile int32
+ var ok bool
+ switch f.TargetMachine {
+ case U802TOCMAGIC:
+ ldsym := new(LoaderSymbol32)
+ if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
+ return nil, err
+ }
+ if ldsym.Lsmtype&0x40 == 0 {
+ continue // Imported symbols only
+ }
+ zeroes := binary.BigEndian.Uint32(ldsym.Lname[:4])
+ if zeroes != 0 {
+ name = cstring(ldsym.Lname[:])
+ } else {
+ offset := binary.BigEndian.Uint32(ldsym.Lname[4:])
+ name, ok = getString(st, offset)
+ if !ok {
+ continue
+ }
+ }
+ ifile = ldsym.Lifile
+ case U64_TOCMAGIC:
+ ldsym := new(LoaderSymbol64)
+ if err := binary.Read(s.sr, binary.BigEndian, ldsym); err != nil {
+ return nil, err
+ }
+ if ldsym.Lsmtype&0x40 == 0 {
+ continue // Imported symbols only
+ }
+ name, ok = getString(st, ldsym.Loffset)
+ if !ok {
+ continue
+ }
+ ifile = ldsym.Lifile
+ }
+ var sym ImportedSymbol
+ sym.Name = name
+ if ifile >= 1 && int(ifile) <= len(libs) {
+ sym.Library = libs[ifile-1]
+ }
+ all = append(all, sym)
+ }
+
+ return all, nil
+}
+
+// ImportedLibraries returns the names of all libraries
+// referred to by the binary f that are expected to be
+// linked with the binary at dynamic link time.
+func (f *File) ImportedLibraries() ([]string, error) {
+ s := f.SectionByType(STYP_LOADER)
+ if s == nil {
+ return nil, nil
+ }
+ all, err := f.readImportIDs(s)
+ return all, err
+}
+
+// FormatError is unused.
+// The type is retained for compatibility.
+type FormatError struct {
+}
+
+func (e *FormatError) Error() string {
+ return "unknown error"
+}
diff --git a/libgo/go/debug/xcoff/file_test.go b/libgo/go/debug/xcoff/file_test.go
new file mode 100644
index 0000000..115ce30
--- /dev/null
+++ b/libgo/go/debug/xcoff/file_test.go
@@ -0,0 +1,150 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xcoff
+
+import (
+ "reflect"
+ "testing"
+)
+
+type fileTest struct {
+ file string
+ hdr FileHeader
+ sections []*SectionHeader
+ needed []string
+}
+
+var fileTests = []fileTest{
+ {
+ "testdata/gcc-ppc32-aix-exec",
+ FileHeader{U802TOCMAGIC},
+ []*SectionHeader{
+ {".text", 0x10000150, 0x00000bbd, STYP_TEXT},
+ {".data", 0x20000d0d, 0x0000042b, STYP_DATA},
+ {".bss", 0x20001138, 0x00000218, STYP_BSS},
+ {".loader", 0x00000000, 0x000004b3, STYP_LOADER},
+ {".debug", 0x00000000, 0x0000751e, STYP_DEBUG},
+ },
+ []string{"libc.a"},
+ },
+ {
+ "testdata/gcc-ppc64-aix-exec",
+ FileHeader{U64_TOCMAGIC},
+ []*SectionHeader{
+ {".text", 0x10000240, 0x00000afd, STYP_TEXT},
+ {".data", 0x20000d3d, 0x000002e3, STYP_DATA},
+ {".bss", 0x20001020, 0x00000428, STYP_BSS},
+ {".loader", 0x00000000, 0x00000535, STYP_LOADER},
+ {".debug", 0x00000000, 0x00008238, STYP_DEBUG},
+ },
+ []string{"libc.a"},
+ },
+ {
+ "testdata/xlc-ppc32-aix-exec",
+ FileHeader{U802TOCMAGIC},
+ []*SectionHeader{
+ {".text", 0x10000150, 0x00000372, STYP_TEXT},
+ {".data", 0x200004c2, 0x0000032e, STYP_DATA},
+ {".bss", 0x200007f0, 0x00000004, STYP_BSS},
+ {".loader", 0x00000000, 0x0000029d, STYP_LOADER},
+ {".debug", 0x00000000, 0x0000008f, STYP_DEBUG},
+ },
+ []string{"libc.a"},
+ },
+ {
+ "testdata/xlc-ppc64-aix-exec",
+ FileHeader{U64_TOCMAGIC},
+ []*SectionHeader{
+ {".text", 0x100000240, 0x00000326, STYP_TEXT},
+ {".data", 0x110000566, 0x00000182, STYP_DATA},
+ {".bss", 0x1100006e8, 0x00000008, STYP_BSS},
+ {".loader", 0x00000000, 0x0000029b, STYP_LOADER},
+ {".debug", 0x00000000, 0x000000ea, STYP_DEBUG},
+ },
+ []string{"libc.a"},
+ },
+ {
+ "testdata/gcc-ppc32-aix-dwarf2-exec",
+ FileHeader{U802TOCMAGIC},
+ []*SectionHeader{
+ {".text", 0x10000290, 0x00000bbd, STYP_TEXT},
+ {".data", 0x20000e4d, 0x00000437, STYP_DATA},
+ {".bss", 0x20001284, 0x0000021c, STYP_BSS},
+ {".loader", 0x00000000, 0x000004b3, STYP_LOADER},
+ {".dwline", 0x00000000, 0x000000df, STYP_DWARF | SSUBTYP_DWLINE},
+ {".dwinfo", 0x00000000, 0x00000314, STYP_DWARF | SSUBTYP_DWINFO},
+ {".dwabrev", 0x00000000, 0x000000d6, STYP_DWARF | SSUBTYP_DWABREV},
+ {".dwarnge", 0x00000000, 0x00000020, STYP_DWARF | SSUBTYP_DWARNGE},
+ {".dwloc", 0x00000000, 0x00000074, STYP_DWARF | SSUBTYP_DWLOC},
+ {".debug", 0x00000000, 0x00005e4f, STYP_DEBUG},
+ },
+ []string{"libc.a"},
+ },
+ {
+ "testdata/gcc-ppc64-aix-dwarf2-exec",
+ FileHeader{U64_TOCMAGIC},
+ []*SectionHeader{
+ {".text", 0x10000480, 0x00000afd, STYP_TEXT},
+ {".data", 0x20000f7d, 0x000002f3, STYP_DATA},
+ {".bss", 0x20001270, 0x00000428, STYP_BSS},
+ {".loader", 0x00000000, 0x00000535, STYP_LOADER},
+ {".dwline", 0x00000000, 0x000000b4, STYP_DWARF | SSUBTYP_DWLINE},
+ {".dwinfo", 0x00000000, 0x0000036a, STYP_DWARF | SSUBTYP_DWINFO},
+ {".dwabrev", 0x00000000, 0x000000b5, STYP_DWARF | SSUBTYP_DWABREV},
+ {".dwarnge", 0x00000000, 0x00000040, STYP_DWARF | SSUBTYP_DWARNGE},
+ {".dwloc", 0x00000000, 0x00000062, STYP_DWARF | SSUBTYP_DWLOC},
+ {".debug", 0x00000000, 0x00006605, STYP_DEBUG},
+ },
+ []string{"libc.a"},
+ },
+}
+
+func TestOpen(t *testing.T) {
+ for i := range fileTests {
+ tt := &fileTests[i]
+
+ f, err := Open(tt.file)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !reflect.DeepEqual(f.FileHeader, tt.hdr) {
+ t.Errorf("open %s:\n\thave %#v\n\twant %#v\n", tt.file, f.FileHeader, tt.hdr)
+ continue
+ }
+
+ for i, sh := range f.Sections {
+ if i >= len(tt.sections) {
+ break
+ }
+ have := &sh.SectionHeader
+ want := tt.sections[i]
+ if !reflect.DeepEqual(have, want) {
+ t.Errorf("open %s, section %d:\n\thave %#v\n\twant %#v\n", tt.file, i, have, want)
+ }
+ }
+ tn := len(tt.sections)
+ fn := len(f.Sections)
+ if tn != fn {
+ t.Errorf("open %s: len(Sections) = %d, want %d", tt.file, fn, tn)
+ }
+ tl := tt.needed
+ fl, err := f.ImportedLibraries()
+ if err != nil {
+ t.Error(err)
+ }
+ if !reflect.DeepEqual(tl, fl) {
+ t.Errorf("open %s: loader import = %v, want %v", tt.file, tl, fl)
+ }
+ }
+}
+
+func TestOpenFailure(t *testing.T) {
+ filename := "file.go" // not an XCOFF object file
+ _, err := Open(filename) // don't crash
+ if err == nil {
+ t.Errorf("open %s: succeeded unexpectedly", filename)
+ }
+}
diff --git a/libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec b/libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
new file mode 100644
index 0000000..810e21a
--- /dev/null
+++ b/libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-dwarf2-exec
Binary files differ
diff --git a/libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec b/libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec
new file mode 100644
index 0000000..6e44041
--- /dev/null
+++ b/libgo/go/debug/xcoff/testdata/gcc-ppc32-aix-exec
Binary files differ
diff --git a/libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec b/libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
new file mode 100644
index 0000000..707d01e
--- /dev/null
+++ b/libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec
Binary files differ
diff --git a/libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec b/libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec
new file mode 100644
index 0000000..82ffdaf
--- /dev/null
+++ b/libgo/go/debug/xcoff/testdata/gcc-ppc64-aix-exec
Binary files differ
diff --git a/libgo/go/debug/xcoff/testdata/hello.c b/libgo/go/debug/xcoff/testdata/hello.c
new file mode 100644
index 0000000..34d9ee7
--- /dev/null
+++ b/libgo/go/debug/xcoff/testdata/hello.c
@@ -0,0 +1,7 @@
+#include <stdio.h>
+
+void
+main(int argc, char *argv[])
+{
+ printf("hello, world\n");
+}
diff --git a/libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec b/libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec
new file mode 100644
index 0000000..e076f81
--- /dev/null
+++ b/libgo/go/debug/xcoff/testdata/xlc-ppc32-aix-exec
Binary files differ
diff --git a/libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec b/libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec
new file mode 100644
index 0000000..26041dc
--- /dev/null
+++ b/libgo/go/debug/xcoff/testdata/xlc-ppc64-aix-exec
Binary files differ
diff --git a/libgo/go/debug/xcoff/xcoff.go b/libgo/go/debug/xcoff/xcoff.go
new file mode 100644
index 0000000..8d76bf3
--- /dev/null
+++ b/libgo/go/debug/xcoff/xcoff.go
@@ -0,0 +1,262 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package xcoff
+
+// File Header.
+type FileHeader32 struct {
+ Fmagic uint16 // Target machine
+ Fnscns uint16 // Number of sections
+ Ftimedat int32 // Time and date of file creation
+ Fsymptr uint32 // Byte offset to symbol table start
+ Fnsyms int32 // Number of entries in symbol table
+ Fopthdr uint16 // Number of bytes in optional header
+ Fflags uint16 // Flags
+}
+
+type FileHeader64 struct {
+ Fmagic uint16 // Target machine
+ Fnscns uint16 // Number of sections
+ Ftimedat int32 // Time and date of file creation
+ Fsymptr uint64 // Byte offset to symbol table start
+ Fopthdr uint16 // Number of bytes in optional header
+ Fflags uint16 // Flags
+ Fnsyms int32 // Number of entries in symbol table
+}
+
+const (
+ FILHSZ_32 = 20
+ FILHSZ_64 = 24
+)
+const (
+ U802TOCMAGIC = 0737 // AIX 32-bit XCOFF
+ U64_TOCMAGIC = 0767 // AIX 64-bit XCOFF
+)
+
+// Flags that describe the type of the object file.
+const (
+ F_RELFLG = 0x0001
+ F_EXEC = 0x0002
+ F_LNNO = 0x0004
+ F_FDPR_PROF = 0x0010
+ F_FDPR_OPTI = 0x0020
+ F_DSA = 0x0040
+ F_VARPG = 0x0100
+ F_DYNLOAD = 0x1000
+ F_SHROBJ = 0x2000
+ F_LOADONLY = 0x4000
+)
+
+// Section Header.
+type SectionHeader32 struct {
+ Sname [8]byte // Section name
+ Spaddr uint32 // Physical address
+ Svaddr uint32 // Virtual address
+ Ssize uint32 // Section size
+ Sscnptr uint32 // Offset in file to raw data for section
+ Srelptr uint32 // Offset in file to relocation entries for section
+ Slnnoptr uint32 // Offset in file to line number entries for section
+ Snreloc uint16 // Number of relocation entries
+ Snlnno uint16 // Number of line number entries
+ Sflags uint32 // Flags to define the section type
+}
+
+type SectionHeader64 struct {
+ Sname [8]byte // Section name
+ Spaddr uint64 // Physical address
+ Svaddr uint64 // Virtual address
+ Ssize uint64 // Section size
+ Sscnptr uint64 // Offset in file to raw data for section
+ Srelptr uint64 // Offset in file to relocation entries for section
+ Slnnoptr uint64 // Offset in file to line number entries for section
+ Snreloc uint32 // Number of relocation entries
+ Snlnno uint32 // Number of line number entries
+ Sflags uint32 // Flags to define the section type
+ Spad uint32 // Needs to be 72 bytes long
+}
+
+// Flags defining the section type.
+const (
+ STYP_DWARF = 0x0010
+ STYP_TEXT = 0x0020
+ STYP_DATA = 0x0040
+ STYP_BSS = 0x0080
+ STYP_EXCEPT = 0x0100
+ STYP_INFO = 0x0200
+ STYP_TDATA = 0x0400
+ STYP_TBSS = 0x0800
+ STYP_LOADER = 0x1000
+ STYP_DEBUG = 0x2000
+ STYP_TYPCHK = 0x4000
+ STYP_OVRFLO = 0x8000
+)
+const (
+ SSUBTYP_DWINFO = 0x10000 // DWARF info section
+ SSUBTYP_DWLINE = 0x20000 // DWARF line-number section
+ SSUBTYP_DWPBNMS = 0x30000 // DWARF public names section
+ SSUBTYP_DWPBTYP = 0x40000 // DWARF public types section
+ SSUBTYP_DWARNGE = 0x50000 // DWARF aranges section
+ SSUBTYP_DWABREV = 0x60000 // DWARF abbreviation section
+ SSUBTYP_DWSTR = 0x70000 // DWARF strings section
+ SSUBTYP_DWRNGES = 0x80000 // DWARF ranges section
+ SSUBTYP_DWLOC = 0x90000 // DWARF location lists section
+ SSUBTYP_DWFRAME = 0xA0000 // DWARF frames section
+ SSUBTYP_DWMAC = 0xB0000 // DWARF macros section
+)
+
+// Symbol Table Entry.
+type SymEnt32 struct {
+ Nname [8]byte // Symbol name
+ Nvalue uint32 // Symbol value
+ Nscnum int16 // Section number of symbol
+ Ntype uint16 // Basic and derived type specification
+ Nsclass int8 // Storage class of symbol
+ Nnumaux int8 // Number of auxiliary entries
+}
+
+type SymEnt64 struct {
+ Nvalue uint64 // Symbol value
+ Noffset uint32 // Offset of the name in string table or .debug section
+ Nscnum int16 // Section number of symbol
+ Ntype uint16 // Basic and derived type specification
+ Nsclass int8 // Storage class of symbol
+ Nnumaux int8 // Number of auxiliary entries
+}
+
+const SYMESZ = 18
+
+// Storage Class.
+const (
+ C_NULL = 0 // Symbol table entry marked for deletion
+ C_EXT = 2 // External symbol
+ C_STAT = 3 // Static symbol
+ C_BLOCK = 100 // Beginning or end of inner block
+ C_FCN = 101 // Beginning or end of function
+ C_FILE = 103 // Source file name and compiler information
+ C_HIDEXT = 107 // Unnamed external symbol
+ C_BINCL = 108 // Beginning of include file
+ C_EINCL = 109 // End of include file
+ C_WEAKEXT = 111 // Weak external symbol
+ C_DWARF = 112 // DWARF symbol
+ C_GSYM = 128 // Global variable
+ C_LSYM = 129 // Automatic variable allocated on stack
+ C_PSYM = 130 // Argument to subroutine allocated on stack
+ C_RSYM = 131 // Register variable
+ C_RPSYM = 132 // Argument to function or procedure stored in register
+ C_STSYM = 133 // Statically allocated symbol
+ C_BCOMM = 135 // Beginning of common block
+ C_ECOML = 136 // Local member of common block
+ C_ECOMM = 137 // End of common block
+ C_DECL = 140 // Declaration of object
+ C_ENTRY = 141 // Alternate entry
+ C_FUN = 142 // Function or procedure
+ C_BSTAT = 143 // Beginning of static block
+ C_ESTAT = 144 // End of static block
+ C_GTLS = 145 // Global thread-local variable
+ C_STTLS = 146 // Static thread-local variable
+)
+
+// csect Auxiliary Entry.
+type AuxCSect32 struct {
+ Xscnlen int32 // Length or symbol table index
+ Xparmhash uint32 // Offset of parameter type-check string
+ Xsnhash uint16 // .typchk section number
+ Xsmtyp uint8 // Symbol alignment and type
+ Xsmclas uint8 // Storage-mapping class
+ Xstab uint32 // Reserved
+ Xsnstab uint16 // Reserved
+}
+
+type AuxCSect64 struct {
+ Xscnlenlo uint32 // Lower 4 bytes of length or symbol table index
+ Xparmhash uint32 // Offset of parameter type-check string
+ Xsnhash uint16 // .typchk section number
+ Xsmtyp uint8 // Symbol alignment and type
+ Xsmclas uint8 // Storage-mapping class
+ Xscnlenhi int32 // Upper 4 bytes of length or symbol table index
+ Xpad uint8 // Unused
+ Xauxtype uint8 // Type of auxiliary entry
+}
+
+// Symbol type field.
+const (
+ XTY_ER = 0 // External reference
+ XTY_SD = 1 // Section definition
+ XTY_LD = 2 // Label definition
+ XTY_CM = 3 // Common csect definition
+)
+
+// Storage-mapping class.
+const (
+ XMC_PR = 0 // Program code
+ XMC_RO = 1 // Read-only constant
+ XMC_DB = 2 // Debug dictionary table
+ XMC_TC = 3 // TOC entry
+ XMC_UA = 4 // Unclassified
+ XMC_RW = 5 // Read/Write data
+ XMC_GL = 6 // Global linkage
+ XMC_XO = 7 // Extended operation
+ XMC_SV = 8 // 32-bit supervisor call descriptor
+ XMC_BS = 9 // BSS class
+ XMC_DS = 10 // Function descriptor
+ XMC_UC = 11 // Unnamed FORTRAN common
+ XMC_TC0 = 15 // TOC anchor
+ XMC_TD = 16 // Scalar data entry in the TOC
+ XMC_SV64 = 17 // 64-bit supervisor call descriptor
+ XMC_SV3264 = 18 // Supervisor call descriptor for both 32-bit and 64-bit
+ XMC_TL = 20 // Read/Write thread-local data
+ XMC_UL = 21 // Read/Write thread-local data (.tbss)
+ XMC_TE = 22 // TOC entry
+)
+
+// Loader Header.
+type LoaderHeader32 struct {
+ Lversion int32 // Loader section version number
+ Lnsyms int32 // Number of symbol table entries
+ Lnreloc int32 // Number of relocation table entries
+ Listlen uint32 // Length of import file ID string table
+ Lnimpid int32 // Number of import file IDs
+ Limpoff uint32 // Offset to start of import file IDs
+ Lstlen uint32 // Length of string table
+ Lstoff uint32 // Offset to start of string table
+}
+
+type LoaderHeader64 struct {
+ Lversion int32 // Loader section version number
+ Lnsyms int32 // Number of symbol table entries
+ Lnreloc int32 // Number of relocation table entries
+ Listlen uint32 // Length of import file ID string table
+ Lnimpid int32 // Number of import file IDs
+ Lstlen uint32 // Length of string table
+ Limpoff uint64 // Offset to start of import file IDs
+ Lstoff uint64 // Offset to start of string table
+ Lsymoff uint64 // Offset to start of symbol table
+ Lrldoff uint64 // Offset to start of relocation entries
+}
+
+const (
+ LDHDRSZ_32 = 32
+ LDHDRSZ_64 = 56
+)
+
+// Loader Symbol.
+type LoaderSymbol32 struct {
+ Lname [8]byte // Symbol name or byte offset into string table
+ Lvalue uint32 // Address field
+ Lscnum int16 // Section number containing symbol
+ Lsmtype int8 // Symbol type, export, import flags
+ Lsmclas int8 // Symbol storage class
+ Lifile int32 // Import file ID; ordinal of import file IDs
+ Lparm uint32 // Parameter type-check field
+}
+
+type LoaderSymbol64 struct {
+ Lvalue uint64 // Address field
+ Loffset uint32 // Byte offset into string table of symbol name
+ Lscnum int16 // Section number containing symbol
+ Lsmtype int8 // Symbol type, export, import flags
+ Lsmclas int8 // Symbol storage class
+ Lifile int32 // Import file ID; ordinal of import file IDs
+ Lparm uint32 // Parameter type-check field
+}
diff --git a/libgo/go/go/build/deps_test.go b/libgo/go/go/build/deps_test.go
index 87abfba..655c37c 100644
--- a/libgo/go/go/build/deps_test.go
+++ b/libgo/go/go/build/deps_test.go
@@ -221,7 +221,7 @@ var pkgDeps = map[string][]string{
"go/constant": {"L4", "go/token", "math/big"},
"go/importer": {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
"go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
- "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "text/scanner"},
+ "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "debug/xcoff", "go/constant", "go/token", "go/types", "text/scanner"},
"go/internal/srcimporter": {"L4", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
"go/types": {"L4", "GOPARSER", "container/heap", "go/constant"},
@@ -243,6 +243,7 @@ var pkgDeps = map[string][]string{
"debug/macho": {"L4", "OS", "debug/dwarf"},
"debug/pe": {"L4", "OS", "debug/dwarf"},
"debug/plan9obj": {"L4", "OS"},
+ "debug/xcoff": {"L4", "OS", "debug/dwarf"},
"encoding": {"L4"},
"encoding/ascii85": {"L4"},
"encoding/asn1": {"L4", "math/big"},
diff --git a/libgo/go/go/internal/gccgoimporter/importer.go b/libgo/go/go/internal/gccgoimporter/importer.go
index a22d8fe..ee573ff 100644
--- a/libgo/go/go/internal/gccgoimporter/importer.go
+++ b/libgo/go/go/internal/gccgoimporter/importer.go
@@ -8,12 +8,14 @@ package gccgoimporter // import "go/internal/gccgoimporter"
import (
"bytes"
"debug/elf"
+ "debug/xcoff"
"fmt"
"go/types"
"io"
"os"
"os/exec"
"path/filepath"
+ "runtime"
"strings"
)
@@ -66,11 +68,12 @@ const (
gccgov2Magic = "v2;\n"
goimporterMagic = "\n$$ "
archiveMagic = "!<ar"
+ aixbigafMagic = "<big"
)
-// Opens the export data file at the given path. If this is an ELF file,
+// Opens the export data file at the given path. If this is an object file,
// searches for and opens the .go_export section. If this is an archive,
-// reads the export data from the first member, which is assumed to be an ELF file.
+// reads the export data from the first member, which is assumed to be an object file.
// This is intended to replicate the logic in gofrontend.
func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err error) {
f, err := os.Open(fpath)
@@ -90,43 +93,58 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e
return
}
- var elfreader io.ReaderAt
+ var objreader io.ReaderAt
switch string(magic[:]) {
case gccgov1Magic, gccgov2Magic, goimporterMagic:
// Raw export data.
reader = f
return
- case archiveMagic:
+ case archiveMagic, aixbigafMagic:
// TODO(pcc): Read the archive directly instead of using "ar".
f.Close()
closer = nil
cmd := exec.Command("ar", "p", fpath)
+ if runtime.GOOS == "aix" && runtime.GOARCH == "ppc64" {
+ // AIX puts both 32-bit and 64-bit objects in the same archive.
+ // Tell the AIX "ar" command to only care about 64-bit objects.
+ cmd.Env = append(os.Environ(), "OBJECT_MODE=64")
+ }
var out []byte
out, err = cmd.Output()
if err != nil {
return
}
- elfreader = bytes.NewReader(out)
+ objreader = bytes.NewReader(out)
default:
- elfreader = f
+ objreader = f
}
- ef, err := elf.NewFile(elfreader)
- if err != nil {
+ ef, err := elf.NewFile(objreader)
+ if err == nil {
+ sec := ef.Section(".go_export")
+ if sec == nil {
+ err = fmt.Errorf("%s: .go_export section not found", fpath)
+ return
+ }
+ reader = sec.Open()
return
}
- sec := ef.Section(".go_export")
- if sec == nil {
- err = fmt.Errorf("%s: .go_export section not found", fpath)
+ xf, err := xcoff.NewFile(objreader)
+ if err == nil {
+ sdat := xf.CSect(".go_export")
+ if sdat == nil {
+ err = fmt.Errorf("%s: .go_export section not found", fpath)
+ return
+ }
+ reader = bytes.NewReader(sdat)
return
}
- reader = sec.Open()
return
}
diff --git a/libgo/go/internal/poll/export_posix_test.go b/libgo/go/internal/poll/export_posix_test.go
index 73b2c11..6b9bb8b 100644
--- a/libgo/go/internal/poll/export_posix_test.go
+++ b/libgo/go/internal/poll/export_posix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
// Export guts for testing on posix.
// Since testing imports os and os imports internal/poll,
diff --git a/libgo/go/internal/poll/fd_poll_runtime.go b/libgo/go/internal/poll/fd_poll_runtime.go
index bfbe3c7..9de8af1 100644
--- a/libgo/go/internal/poll/fd_poll_runtime.go
+++ b/libgo/go/internal/poll/fd_poll_runtime.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd windows solaris
package poll
diff --git a/libgo/go/internal/poll/fd_posix.go b/libgo/go/internal/poll/fd_posix.go
index e0e634c..4e6e355 100644
--- a/libgo/go/internal/poll/fd_posix.go
+++ b/libgo/go/internal/poll/fd_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package poll
diff --git a/libgo/go/internal/poll/fd_posix_test.go b/libgo/go/internal/poll/fd_posix_test.go
index cbe015e..246d498 100644
--- a/libgo/go/internal/poll/fd_posix_test.go
+++ b/libgo/go/internal/poll/fd_posix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package poll_test
diff --git a/libgo/go/internal/poll/fd_unix.go b/libgo/go/internal/poll/fd_unix.go
index c40c701..0b43a19 100644
--- a/libgo/go/internal/poll/fd_unix.go
+++ b/libgo/go/internal/poll/fd_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package poll
diff --git a/libgo/go/internal/poll/hook_unix.go b/libgo/go/internal/poll/hook_unix.go
index 85e102d..4cf36cc 100644
--- a/libgo/go/internal/poll/hook_unix.go
+++ b/libgo/go/internal/poll/hook_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package poll
diff --git a/libgo/go/internal/poll/sockopt.go b/libgo/go/internal/poll/sockopt.go
index f86ce70..bb5ea02 100644
--- a/libgo/go/internal/poll/sockopt.go
+++ b/libgo/go/internal/poll/sockopt.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris windows
package poll
diff --git a/libgo/go/internal/poll/sockoptip.go b/libgo/go/internal/poll/sockoptip.go
index 5d5dff6..ae59b0c 100644
--- a/libgo/go/internal/poll/sockoptip.go
+++ b/libgo/go/internal/poll/sockoptip.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd windows
+// +build aix darwin dragonfly freebsd linux netbsd openbsd windows
package poll
diff --git a/libgo/go/internal/poll/sys_cloexec.go b/libgo/go/internal/poll/sys_cloexec.go
index 9ed35bd..fb5f2bc 100644
--- a/libgo/go/internal/poll/sys_cloexec.go
+++ b/libgo/go/internal/poll/sys_cloexec.go
@@ -5,7 +5,7 @@
// This file implements sysSocket and accept for platforms that do not
// provide a fast path for setting SetNonblock and CloseOnExec.
-// +build darwin nacl netbsd openbsd solaris
+// +build aix darwin nacl netbsd openbsd solaris
package poll
diff --git a/libgo/go/net/error_posix.go b/libgo/go/net/error_posix.go
index dd9754c..d0ffaae 100644
--- a/libgo/go/net/error_posix.go
+++ b/libgo/go/net/error_posix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris windows
package net
diff --git a/libgo/go/net/sock_posix.go b/libgo/go/net/sock_posix.go
index a30efe2..4733c42 100644
--- a/libgo/go/net/sock_posix.go
+++ b/libgo/go/net/sock_posix.go
@@ -182,7 +182,10 @@ func (fd *netFD) listenStream(laddr sockaddr, backlog int) error {
if err := fd.init(); err != nil {
return err
}
- lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
+ lsa, err := syscall.Getsockname(fd.pfd.Sysfd)
+ if err != nil {
+ return os.NewSyscallError("getsockname", err)
+ }
fd.setAddr(fd.addrFunc()(lsa), nil)
return nil
}
@@ -221,7 +224,10 @@ func (fd *netFD) listenDatagram(laddr sockaddr) error {
if err := fd.init(); err != nil {
return err
}
- lsa, _ := syscall.Getsockname(fd.pfd.Sysfd)
+ lsa, err := syscall.Getsockname(fd.pfd.Sysfd)
+ if err != nil {
+ return os.NewSyscallError("getsockname", err)
+ }
fd.setAddr(fd.addrFunc()(lsa), nil)
return nil
}
diff --git a/libgo/go/os/user/cgo_lookup_unix.go b/libgo/go/os/user/cgo_lookup_unix.go
index 8881366..9670ada 100644
--- a/libgo/go/os/user/cgo_lookup_unix.go
+++ b/libgo/go/os/user/cgo_lookup_unix.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd !android,linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd !android,linux netbsd openbsd solaris
// +build cgo
package user
diff --git a/libgo/go/runtime/export_unix_test.go b/libgo/go/runtime/export_unix_test.go
index 54d5770..eecdfb7 100644
--- a/libgo/go/runtime/export_unix_test.go
+++ b/libgo/go/runtime/export_unix_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux netbsd openbsd solaris
package runtime
diff --git a/libgo/go/runtime/netpoll_aix.go b/libgo/go/runtime/netpoll_aix.go
index 8c8e188..b4962cc 100644
--- a/libgo/go/runtime/netpoll_aix.go
+++ b/libgo/go/runtime/netpoll_aix.go
@@ -64,14 +64,14 @@ func netpollinit() {
var p [2]int32
if ps = pollset_create(-1); ps < 0 {
- throw("netpollinit: failed to create pollset")
+ throw("runtime: netpollinit failed to create pollset")
}
// It is not possible to add or remove descriptors from
// the pollset while pollset_poll is active.
// We use a pipe to wakeup pollset_poll when the pollset
// needs to be updated.
if err := libc_pipe(&p[0]); err < 0 {
- throw("netpollinit: failed to create pipe")
+ throw("runtime: netpollinit failed to create pipe")
}
rdwake = p[0]
wrwake = p[1]
@@ -90,12 +90,17 @@ func netpollinit() {
pctl.fd = rdwake
pctl.events = _POLLIN
if pollset_ctl(ps, &pctl, 1) != 0 {
- throw("netpollinit: failed to register pipe")
+ throw("runtime: netpollinit failed to register pipe")
}
mpfds = make(map[int32]*pollDesc)
}
+func netpolldescriptor() uintptr {
+ // ps is not a real file descriptor.
+ return ^uintptr(0)
+}
+
func netpollopen(fd uintptr, pd *pollDesc) int32 {
// pollset_ctl will block if pollset_poll is active
// so wakeup pollset_poll first.
@@ -144,7 +149,7 @@ func netpollclose(fd uintptr) int32 {
}
func netpollarm(pd *pollDesc, mode int) {
- throw("unused")
+ throw("runtime: unused")
}
func netpoll(block bool) *g {
@@ -168,7 +173,7 @@ retry:
if nfound < 0 {
e := errno()
if e != _EINTR {
- throw("pollset_poll failed")
+ throw("runtime: pollset_poll failed")
}
goto retry
}
diff --git a/libgo/go/syscall/dirent.go b/libgo/go/syscall/dirent.go
index 4db2d43..a09bf05 100644
--- a/libgo/go/syscall/dirent.go
+++ b/libgo/go/syscall/dirent.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd linux nacl netbsd openbsd solaris
package syscall
diff --git a/libgo/go/syscall/forkpipe_bsd.go b/libgo/go/syscall/forkpipe_bsd.go
index 28897bf..d479284 100644
--- a/libgo/go/syscall/forkpipe_bsd.go
+++ b/libgo/go/syscall/forkpipe_bsd.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin dragonfly netbsd openbsd solaris
+// +build aix darwin dragonfly netbsd openbsd solaris
package syscall
diff --git a/libgo/go/syscall/libcall_aix.go b/libgo/go/syscall/libcall_aix.go
index 992eeb4..072f92a 100644
--- a/libgo/go/syscall/libcall_aix.go
+++ b/libgo/go/syscall/libcall_aix.go
@@ -6,6 +6,136 @@
package syscall
+import (
+ "unsafe"
+)
+
+//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
+//open64at(dirfd _C_int, path *byte, flags _C_int, mode Mode_t) _C_int
+
+//sys ptrace(request int, id int, addr uintptr, data int, buff uintptr) (val int)
+//ptrace(request _C_int, id int, addr uintptr, data _C_int, buff *byte) _C_int
+
+//sys ptrace64(request int, id int64, addr int64, data int, buff uintptr) (err error)
+//ptrace64(request _C_int, id int64, addr int64, data _C_int, buff *byte) _C_int
+
func raw_ptrace(request int, pid int, addr *byte, data *byte) Errno {
+ if request == _PTRACE_TRACEME {
+ // Convert to AIX ptrace call.
+ err := ptrace64(_PT_TRACE_ME, 0, 0, 0, 0)
+ if err != nil {
+ return err.(Errno)
+ }
+ return 0
+ }
return ENOSYS
}
+
+func ptracePeek(pid int, addr uintptr, out []byte) (count int, err error) {
+ n := 0
+ for len(out) > 0 {
+ bsize := len(out)
+ if bsize > 1024 {
+ bsize = 1024
+ }
+ err = ptrace64(_PT_READ_BLOCK, int64(pid), int64(addr), bsize, uintptr(unsafe.Pointer(&out[0])))
+ if err != nil {
+ return 0, err
+ }
+ addr += uintptr(bsize)
+ n += bsize
+ out = out[n:]
+ }
+ return n, nil
+}
+
+func PtracePeekText(pid int, addr uintptr, out []byte) (count int, err error) {
+ return ptracePeek(pid, addr, out)
+}
+
+func PtracePeekData(pid int, addr uintptr, out []byte) (count int, err error) {
+ return ptracePeek(pid, addr, out)
+}
+
+func ptracePoke(pid int, addr uintptr, data []byte) (count int, err error) {
+ n := 0
+ for len(data) > 0 {
+ bsize := len(data)
+ if bsize > 1024 {
+ bsize = 1024
+ }
+ err = ptrace64(_PT_WRITE_BLOCK, int64(pid), int64(addr), bsize, uintptr(unsafe.Pointer(&data[0])))
+ if err != nil {
+ return 0, err
+ }
+ addr += uintptr(bsize)
+ n += bsize
+ data = data[n:]
+ }
+ return n, nil
+}
+
+func PtracePokeText(pid int, addr uintptr, data []byte) (count int, err error) {
+ return ptracePoke(pid, addr, data)
+}
+
+func PtracePokeData(pid int, addr uintptr, data []byte) (count int, err error) {
+ return ptracePoke(pid, addr, data)
+}
+
+func PtraceCont(pid int, signal int) (err error) {
+ return ptrace64(_PT_CONTINUE, int64(pid), 1, signal, 0)
+}
+
+func PtraceSingleStep(pid int) (err error) { return ptrace64(_PT_STEP, int64(pid), 1, 0, 0) }
+
+func PtraceAttach(pid int) (err error) { return ptrace64(_PT_ATTACH, int64(pid), 0, 0, 0) }
+
+func PtraceDetach(pid int) (err error) { return ptrace64(_PT_DETACH, int64(pid), 0, 0, 0) }
+
+//sys reboot(how int) (err error)
+//__linux_reboot(how _C_int) _C_int
+func Reboot(how int) (err error) {
+ return reboot(how)
+}
+
+//sys Acct(path string) (err error)
+//acct(path *byte) _C_int
+
+//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
+//faccessat(dirfd _C_int, pathname *byte, mode _C_int, flags _C_int) _C_int
+
+//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
+//fchmodat(dirfd _C_int, pathname *byte, mode Mode_t, flags _C_int) _C_int
+
+//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
+//fchownat(dirfd _C_int, path *byte, owner Uid_t, group Gid_t, flags _C_int) _C_int
+
+//sys Fstatfs(fd int, buf *Statfs_t) (err error)
+//fstatfs64(fd _C_int, buf *Statfs_t) _C_int
+
+//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
+//mkdirat(dirfd _C_int, path *byte, mode Mode_t) _C_int
+
+//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
+//mknodat(dirfd _C_int, path *byte, mode Mode_t, dev _dev_t) _C_int
+
+//sys getdirent(fd int, buf []byte) (n int, err error)
+//getdirent64(fd _C_int, buf *byte, nbyte Size_t) _C_int
+
+func ReadDirent(fd int, buf []byte) (n int, err error) {
+ return getdirent(fd, buf)
+}
+
+//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
+//renameat(olddirfd _C_int, oldpath *byte, newdirfd _C_int, newpath *byte) _C_int
+
+//sys Statfs(path string, buf *Statfs_t) (err error)
+//statfs64(path *byte, buf *Statfs_t) _C_int
+
+//sys unlinkat(dirfd int, path string, flags int) (err error)
+//unlinkat(dirfd _C_int, path *byte, flags _C_int) _C_int
+
+func Unlinkat(dirfd int, path string) (err error) {
+ return unlinkat(dirfd, path, 0)
+}
diff --git a/libgo/go/syscall/socket_aix.go b/libgo/go/syscall/socket_aix.go
new file mode 100644
index 0000000..40cf423
--- /dev/null
+++ b/libgo/go/syscall/socket_aix.go
@@ -0,0 +1,89 @@
+// socket_aix.go -- Socket handling specific to AIX.
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+const SizeofSockaddrInet4 = 16
+const SizeofSockaddrInet6 = 28
+const SizeofSockaddrUnix = 1025
+
+type RawSockaddrInet4 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Addr [4]byte /* in_addr */
+ Zero [8]uint8
+}
+
+func (sa *RawSockaddrInet4) setLen() Socklen_t {
+ sa.Len = SizeofSockaddrInet4
+ return SizeofSockaddrInet4
+}
+
+type RawSockaddrInet6 struct {
+ Len uint8
+ Family uint8
+ Port uint16
+ Flowinfo uint32
+ Addr [16]byte /* in6_addr */
+ Scope_id uint32
+}
+
+func (sa *RawSockaddrInet6) setLen() Socklen_t {
+ sa.Len = SizeofSockaddrInet6
+ return SizeofSockaddrInet6
+}
+
+type RawSockaddrUnix struct {
+ Len uint8
+ Family uint8
+ Path [1023]int8
+}
+
+func (sa *RawSockaddrUnix) setLen(n int) {
+ sa.Len = uint8(3 + n) // 2 for Family, Len; 1 for NUL.
+}
+
+func (sa *RawSockaddrUnix) getLen() (int, error) {
+ // Some versions of AIX have a bug in getsockname (see IV78655).
+ // We can't rely on sa.Len being set correctly.
+ n := SizeofSockaddrUnix - 3 // substract leading Family, Len, terminating NUL.
+ for i := 0; i < n; i++ {
+ if sa.Path[i] == 0 {
+ n = i
+ break
+ }
+ }
+ return n, nil
+}
+
+func (sa *RawSockaddrUnix) adjustAbstract(sl Socklen_t) Socklen_t {
+ return sl
+}
+
+type RawSockaddr struct {
+ Len uint8
+ Family uint8
+ Data [14]int8
+}
+
+// BindToDevice binds the socket associated with fd to device.
+func BindToDevice(fd int, device string) (err error) {
+ return ENOSYS
+}
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, error) {
+ return nil, EAFNOSUPPORT
+}
+
+func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
+ var value IPv6MTUInfo
+ vallen := Socklen_t(SizeofIPv6MTUInfo)
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
+ return &value, err
+}
diff --git a/libgo/go/syscall/socket_bsd.go b/libgo/go/syscall/socket_bsd.go
index ecdab06..cf3fc4f 100644
--- a/libgo/go/syscall/socket_bsd.go
+++ b/libgo/go/syscall/socket_bsd.go
@@ -4,7 +4,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build aix darwin dragonfly freebsd openbsd netbsd
+// +build darwin dragonfly freebsd openbsd netbsd
package syscall
diff --git a/libgo/go/syscall/syscall_aix.go b/libgo/go/syscall/syscall_aix.go
new file mode 100644
index 0000000..c2554eb
--- /dev/null
+++ b/libgo/go/syscall/syscall_aix.go
@@ -0,0 +1,19 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+func direntIno(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
+}
+
+func direntReclen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
+}
+
+func direntNamlen(buf []byte) (uint64, bool) {
+ return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
+}
diff --git a/libgo/go/syscall/syscall_aix_ppc.go b/libgo/go/syscall/syscall_aix_ppc.go
new file mode 100644
index 0000000..83ed1e6
--- /dev/null
+++ b/libgo/go/syscall/syscall_aix_ppc.go
@@ -0,0 +1,49 @@
+// syscall_aix_ppc.go -- AIX 32-bit specific support
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+// AIX does not define a specific structure but instead uses separate
+// ptrace calls for the different registers.
+type PtraceRegs struct {
+ Gpr [32]uint32
+ Iar uint32
+ Msr uint32
+ Cr uint32
+ Lr uint32
+ Ctr uint32
+ Xer uint32
+}
+
+func (r *PtraceRegs) PC() uint64 { return uint64(r.Iar) }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Iar = uint32(pc) }
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
+ ptrace(_PT_REGSET, pid, uintptr(unsafe.Pointer(&regsout.Gpr[0])), 0, 0)
+ regsout.Iar = uint32(ptrace(_PT_READ_GPR, pid, 128, 0, 0))
+ regsout.Msr = uint32(ptrace(_PT_READ_GPR, pid, 129, 0, 0))
+ regsout.Cr = uint32(ptrace(_PT_READ_GPR, pid, 130, 0, 0))
+ regsout.Lr = uint32(ptrace(_PT_READ_GPR, pid, 131, 0, 0))
+ regsout.Ctr = uint32(ptrace(_PT_READ_GPR, pid, 132, 0, 0))
+ regsout.Xer = uint32(ptrace(_PT_READ_GPR, pid, 133, 0, 0))
+ return nil
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
+ for i := 0; i < len(regs.Gpr); i++ {
+ ptrace(_PT_WRITE_GPR, pid, uintptr(i), int(regs.Gpr[i]), 0)
+ }
+ ptrace(_PT_WRITE_GPR, pid, 128, int(regs.Iar), 0)
+ ptrace(_PT_WRITE_GPR, pid, 129, int(regs.Msr), 0)
+ ptrace(_PT_WRITE_GPR, pid, 130, int(regs.Cr), 0)
+ ptrace(_PT_WRITE_GPR, pid, 131, int(regs.Lr), 0)
+ ptrace(_PT_WRITE_GPR, pid, 132, int(regs.Ctr), 0)
+ ptrace(_PT_WRITE_GPR, pid, 133, int(regs.Xer), 0)
+ return nil
+}
diff --git a/libgo/go/syscall/syscall_aix_ppc64.go b/libgo/go/syscall/syscall_aix_ppc64.go
new file mode 100644
index 0000000..82388ca
--- /dev/null
+++ b/libgo/go/syscall/syscall_aix_ppc64.go
@@ -0,0 +1,49 @@
+// syscall_aix_ppc64.go -- AIX 64-bit specific support
+
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall
+
+import "unsafe"
+
+// AIX does not define a specific structure but instead uses separate
+// ptrace calls for the different registers.
+type PtraceRegs struct {
+ Gpr [32]uint64
+ Iar uint64
+ Msr uint64
+ Cr uint64
+ Lr uint64
+ Ctr uint64
+ Xer uint64
+}
+
+func (r *PtraceRegs) PC() uint64 { return r.Iar }
+
+func (r *PtraceRegs) SetPC(pc uint64) { r.Iar = pc }
+
+func PtraceGetRegs(pid int, regsout *PtraceRegs) (err error) {
+ ptrace64(_PT_REGSET, int64(pid), int64(uintptr(unsafe.Pointer(&regsout.Gpr[0]))), 0, 0)
+ ptrace64(_PT_READ_GPR, int64(pid), 128, 0, uintptr(unsafe.Pointer(&regsout.Iar)))
+ ptrace64(_PT_READ_GPR, int64(pid), 129, 0, uintptr(unsafe.Pointer(&regsout.Msr)))
+ ptrace64(_PT_READ_GPR, int64(pid), 130, 0, uintptr(unsafe.Pointer(&regsout.Cr)))
+ ptrace64(_PT_READ_GPR, int64(pid), 131, 0, uintptr(unsafe.Pointer(&regsout.Lr)))
+ ptrace64(_PT_READ_GPR, int64(pid), 132, 0, uintptr(unsafe.Pointer(&regsout.Ctr)))
+ ptrace64(_PT_READ_GPR, int64(pid), 133, 0, uintptr(unsafe.Pointer(&regsout.Xer)))
+ return nil
+}
+
+func PtraceSetRegs(pid int, regs *PtraceRegs) (err error) {
+ for i := 0; i < len(regs.Gpr); i++ {
+ ptrace64(_PT_WRITE_GPR, int64(pid), int64(i), 0, uintptr(unsafe.Pointer(&regs.Gpr[i])))
+ }
+ ptrace64(_PT_WRITE_GPR, int64(pid), 128, 0, uintptr(unsafe.Pointer(&regs.Iar)))
+ ptrace64(_PT_WRITE_GPR, int64(pid), 129, 0, uintptr(unsafe.Pointer(&regs.Msr)))
+ ptrace64(_PT_WRITE_GPR, int64(pid), 130, 0, uintptr(unsafe.Pointer(&regs.Cr)))
+ ptrace64(_PT_WRITE_GPR, int64(pid), 131, 0, uintptr(unsafe.Pointer(&regs.Lr)))
+ ptrace64(_PT_WRITE_GPR, int64(pid), 132, 0, uintptr(unsafe.Pointer(&regs.Ctr)))
+ ptrace64(_PT_WRITE_GPR, int64(pid), 133, 0, uintptr(unsafe.Pointer(&regs.Xer)))
+ return nil
+}
diff --git a/libgo/mkrsysinfo.sh b/libgo/mkrsysinfo.sh
index 44a3a6b..aee0163 100755
--- a/libgo/mkrsysinfo.sh
+++ b/libgo/mkrsysinfo.sh
@@ -23,6 +23,7 @@ grep -v '^// ' gen-sysinfo.go | \
grep -v '^type _timespec_t ' | \
grep -v '^type _timespec ' | \
grep -v '^type _epoll_' | \
+ grep -v '^type _*locale[_ ]' | \
grep -v 'in6_addr' | \
grep -v 'sockaddr_in6' | \
sed -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1timeval\2/g' \
diff --git a/libgo/mksysinfo.sh b/libgo/mksysinfo.sh
index 54978b9..cbe5b97 100755
--- a/libgo/mksysinfo.sh
+++ b/libgo/mksysinfo.sh
@@ -34,6 +34,7 @@ grep -v '^// ' gen-sysinfo.go | \
grep -v '^type _timespec ' | \
grep -v '^type _timestruc_t ' | \
grep -v '^type _epoll_' | \
+ grep -v '^type _*locale[_ ]' | \
grep -v 'in6_addr' | \
grep -v 'sockaddr_in6' | \
sed -e 's/\([^a-zA-Z0-9_]\)_timeval\([^a-zA-Z0-9_]\)/\1Timeval\2/g' \
@@ -485,6 +486,7 @@ fi | sed -e 's/type _dirent64/type Dirent/' \
-e 's/d_name/Name/' \
-e 's/]int8/]byte/' \
-e 's/d_ino/Ino/' \
+ -e 's/d_namlen/Namlen/' \
-e 's/d_off/Off/' \
-e 's/d_reclen/Reclen/' \
-e 's/d_type/Type/' \
diff --git a/libgo/runtime/go-caller.c b/libgo/runtime/go-caller.c
index 360bae6..ee8abdc 100644
--- a/libgo/runtime/go-caller.c
+++ b/libgo/runtime/go-caller.c
@@ -159,7 +159,7 @@ syminfo_callback (void *data, uintptr_t pc __attribute__ ((unused)),
/* Set *VAL to the value of the symbol for PC. */
static _Bool
-__go_symbol_value (uintptr_t pc, uintptr_t *val)
+__go_symbol_value (uintptr pc, uintptr *val)
{
*val = 0;
backtrace_syminfo (__go_get_backtrace_state (), pc, syminfo_callback,
diff --git a/libgo/runtime/proc.c b/libgo/runtime/proc.c
index e591824..d6e42e6 100644
--- a/libgo/runtime/proc.c
+++ b/libgo/runtime/proc.c
@@ -179,7 +179,7 @@ fixcontext(ucontext_t* c)
// So we make the field larger in runtime2.go and pick an appropriate
// offset within the field here.
static ucontext_t*
-ucontext_arg(uintptr* go_ucontext)
+ucontext_arg(uintptr_t* go_ucontext)
{
uintptr_t p = (uintptr_t)go_ucontext;
size_t align = __alignof__(ucontext_t);
diff --git a/libgomp/ChangeLog b/libgomp/ChangeLog
index 0c8832c..35a2374 100644
--- a/libgomp/ChangeLog
+++ b/libgomp/ChangeLog
@@ -1,3 +1,95 @@
+2017-10-17 Thomas Schwinge <thomas@codesourcery.com>
+
+ * testsuite/libgomp.oacc-fortran/declare-1.f90: Restore "dg-do
+ run" directive.
+ * testsuite/libgomp.oacc-fortran/declare-2.f90: Likewise.
+ * testsuite/libgomp.oacc-fortran/declare-3.f90: Likewise.
+ * testsuite/libgomp.oacc-fortran/declare-4.f90: Likewise.
+ * testsuite/libgomp.oacc-fortran/declare-5.f90: Likewise.
+
+2017-10-16 Tom de Vries <tom@codesourcery.com>
+
+ * testsuite/libgomp.oacc-c-c++-common/declare-1.c: Don't require
+ openacc_nvidia_accel_selected.
+ * testsuite/libgomp.oacc-c-c++-common/declare-2.c: Same.
+ * testsuite/libgomp.oacc-c-c++-common/declare-4.c: Same.
+ * testsuite/libgomp.oacc-fortran/declare-2.f90: Same.
+ * testsuite/libgomp.oacc-fortran/declare-4.f90: Same
+ * testsuite/libgomp.oacc-fortran/declare-5.f90: Same.
+ * testsuite/libgomp.oacc-c-c++-common/declare-5.c: Don't require
+ openacc_nvidia_accel_selected. Skip for shared memory device.
+ * testsuite/libgomp.oacc-fortran/declare-1.f90: Same.
+ * testsuite/libgomp.oacc-fortran/declare-3.f90: Same.
+
+2017-10-09 Martin Jambor <mjambor@suse.cz>
+
+ PR hsa/82416
+ * testsuite/libgomp.hsa.c/pr82416.c: New test.
+
+2017-10-07 Tom de Vries <tom@codesourcery.com>
+
+ * testsuite/libgomp.oacc-fortran/firstprivate-1.f90 (firstprivate):
+ Remove acc_device_nvidia references.
+ * testsuite/libgomp.oacc-fortran/parallel-reduction.f90 (reduction):
+ Same.
+
+2017-10-05 Tom de Vries <tom@codesourcery.com>
+
+ * testsuite/libgomp.oacc-c-c++-common/loop-red-g-1.c (main): Remove
+ vector_length(32) clause from acc parallel directive.
+ * testsuite/libgomp.oacc-c-c++-common/routine-g-1.c (main): Same.
+
+2017-10-04 Tom de Vries <tom@codesourcery.com>
+
+ * testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-3.c
+ (main): Reduce sum of arr elements. Assert that hres is exactly
+ representable in 32-bit floating point.
+ * testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-4.c
+ (main): Reduce sum of arr elements. Assert that hres and hmres are
+ exactly representable in 32-bit floating point.
+ * testsuite/libgomp.oacc-c-c++-common/reduction-7.c (gwv_np_4): Same.
+
+2017-09-28 Tom de Vries <tom@codesourcery.com>
+
+ * testsuite/libgomp.c++/for-12.C: Remove superfluous -fopenmp option
+ setting.
+ * testsuite/libgomp.c++/pr69393.C: Same.
+ * testsuite/libgomp.c++/taskloop-1.C: Same.
+ * testsuite/libgomp.c++/taskloop-3.C: Same.
+ * testsuite/libgomp.c++/taskloop-4.C: Same.
+ * testsuite/libgomp.c/for-4.c: Same.
+ * testsuite/libgomp.c/pr66199-3.c: Same.
+ * testsuite/libgomp.c/pr66199-4.c: Same.
+ * testsuite/libgomp.c/pr66199-6.c: Same.
+ * testsuite/libgomp.c/taskloop-1.c: Same.
+ * testsuite/libgomp.c/taskloop-3.c: Same.
+ * testsuite/libgomp.c/taskloop-4.c: Same.
+ * testsuite/libgomp.fortran/aligned1.f03: Same.
+ * testsuite/libgomp.fortran/condinc1.f: Same.
+ * testsuite/libgomp.fortran/condinc3.f90: Same.
+ * testsuite/libgomp.fortran/crayptr1.f90: Same.
+ * testsuite/libgomp.fortran/crayptr2.f90: Same.
+ * testsuite/libgomp.fortran/crayptr3.f90: Same.
+ * testsuite/libgomp.fortran/omp_cond1.f: Same.
+ * testsuite/libgomp.fortran/omp_cond3.F90: Same.
+ * testsuite/libgomp.fortran/pr66199-1.f90: Same.
+ * testsuite/libgomp.fortran/pr66199-2.f90: Same.
+ * testsuite/libgomp.fortran/recursion1.f90: Same.
+ * testsuite/libgomp.fortran/target2.f90: Same.
+ * testsuite/libgomp.fortran/target5.f90: Same.
+ * testsuite/libgomp.fortran/task3.f90: Same.
+
+2017-09-28 Tom de Vries <tom@codesourcery.com>
+
+ * testsuite/libgomp.oacc-c-c++-common/loop-g-1.c (main): Remove
+ vector_length(32) clause from acc parallel directive.
+ * testsuite/libgomp.oacc-c-c++-common/loop-g-2.c (main): Same.
+
+2017-09-27 Tom de Vries <tom@codesourcery.com>
+
+ * testsuite/libgomp.oacc-c-c++-common/parallel-reduction.c (main):
+ Remove acc_device_nvidia references.
+
2017-09-16 Tom de Vries <tom@codesourcery.com>
PR c/81875
diff --git a/libgomp/testsuite/libgomp.c++/for-12.C b/libgomp/testsuite/libgomp.c++/for-12.C
index ea32192..295b12f 100644
--- a/libgomp/testsuite/libgomp.c++/for-12.C
+++ b/libgomp/testsuite/libgomp.c++/for-12.C
@@ -1,5 +1,3 @@
-/* { dg-options "-fopenmp" } */
-
extern "C" void abort (void);
#define M(x, y, z) O(x, y, z)
diff --git a/libgomp/testsuite/libgomp.c++/pr69393.C b/libgomp/testsuite/libgomp.c++/pr69393.C
index e3f0de1..02605e0 100644
--- a/libgomp/testsuite/libgomp.c++/pr69393.C
+++ b/libgomp/testsuite/libgomp.c++/pr69393.C
@@ -1,6 +1,6 @@
// { dg-do run }
// { dg-require-effective-target lto }
-// { dg-options "-flto -g -fopenmp" }
+// { dg-options "-flto -g" }
int e = 5;
diff --git a/libgomp/testsuite/libgomp.c++/taskloop-1.C b/libgomp/testsuite/libgomp.c++/taskloop-1.C
index 66f8e0b..7fc6e46 100644
--- a/libgomp/testsuite/libgomp.c++/taskloop-1.C
+++ b/libgomp/testsuite/libgomp.c++/taskloop-1.C
@@ -1,4 +1,4 @@
// { dg-do run }
-// { dg-options "-O2 -fopenmp" }
+// { dg-options "-O2" }
#include "../libgomp.c/taskloop-1.c"
diff --git a/libgomp/testsuite/libgomp.c++/taskloop-3.C b/libgomp/testsuite/libgomp.c++/taskloop-3.C
index bfd793c..c08a045 100644
--- a/libgomp/testsuite/libgomp.c++/taskloop-3.C
+++ b/libgomp/testsuite/libgomp.c++/taskloop-3.C
@@ -1,4 +1,4 @@
// { dg-do run }
-// { dg-options "-O2 -fopenmp" }
+// { dg-options "-O2" }
#include "../libgomp.c/taskloop-3.c"
diff --git a/libgomp/testsuite/libgomp.c++/taskloop-4.C b/libgomp/testsuite/libgomp.c++/taskloop-4.C
index 937cfcc..3783717 100644
--- a/libgomp/testsuite/libgomp.c++/taskloop-4.C
+++ b/libgomp/testsuite/libgomp.c++/taskloop-4.C
@@ -1,4 +1,4 @@
// { dg-do run }
-// { dg-options "-O2 -fopenmp" }
+// { dg-options "-O2" }
#include "../libgomp.c/taskloop-4.c"
diff --git a/libgomp/testsuite/libgomp.c/for-4.c b/libgomp/testsuite/libgomp.c/for-4.c
index ef5465e..14f900b 100644
--- a/libgomp/testsuite/libgomp.c/for-4.c
+++ b/libgomp/testsuite/libgomp.c/for-4.c
@@ -1,4 +1,4 @@
-/* { dg-options "-std=gnu99 -fopenmp" } */
+/* { dg-options "-std=gnu99" } */
extern void abort (void);
diff --git a/libgomp/testsuite/libgomp.c/pr66199-3.c b/libgomp/testsuite/libgomp.c/pr66199-3.c
index fe0ccb4..ffe2858 100644
--- a/libgomp/testsuite/libgomp.c/pr66199-3.c
+++ b/libgomp/testsuite/libgomp.c/pr66199-3.c
@@ -1,6 +1,6 @@
/* PR middle-end/66199 */
/* { dg-do run } */
-/* { dg-options "-O2 -fopenmp" } */
+/* { dg-options "-O2" } */
int u[1024], v[1024], w[1024];
diff --git a/libgomp/testsuite/libgomp.c/pr66199-4.c b/libgomp/testsuite/libgomp.c/pr66199-4.c
index a9b1bb8..6ffa2e5 100644
--- a/libgomp/testsuite/libgomp.c/pr66199-4.c
+++ b/libgomp/testsuite/libgomp.c/pr66199-4.c
@@ -1,6 +1,6 @@
/* PR middle-end/66199 */
/* { dg-do run } */
-/* { dg-options "-O2 -fopenmp" } */
+/* { dg-options "-O2" } */
#pragma omp declare target
int u[1024], v[1024], w[1024];
diff --git a/libgomp/testsuite/libgomp.c/pr66199-6.c b/libgomp/testsuite/libgomp.c/pr66199-6.c
index 6790f7d..14f8610 100644
--- a/libgomp/testsuite/libgomp.c/pr66199-6.c
+++ b/libgomp/testsuite/libgomp.c/pr66199-6.c
@@ -1,6 +1,6 @@
/* PR middle-end/66199 */
/* { dg-do run } */
-/* { dg-options "-O2 -fopenmp" } */
+/* { dg-options "-O2" } */
#pragma omp declare target
int u[1024], v[1024], w[1024];
diff --git a/libgomp/testsuite/libgomp.c/taskloop-1.c b/libgomp/testsuite/libgomp.c/taskloop-1.c
index 21551f2..edc7058 100644
--- a/libgomp/testsuite/libgomp.c/taskloop-1.c
+++ b/libgomp/testsuite/libgomp.c/taskloop-1.c
@@ -1,5 +1,5 @@
/* { dg-do run } */
-/* { dg-options "-O2 -fopenmp -std=c99" } */
+/* { dg-options "-O2 -std=c99" } */
int q, r, e;
diff --git a/libgomp/testsuite/libgomp.c/taskloop-3.c b/libgomp/testsuite/libgomp.c/taskloop-3.c
index 5356d7f..9c8c49c 100644
--- a/libgomp/testsuite/libgomp.c/taskloop-3.c
+++ b/libgomp/testsuite/libgomp.c/taskloop-3.c
@@ -1,5 +1,5 @@
/* { dg-do run } */
-/* { dg-options "-O2 -fopenmp -std=c99" } */
+/* { dg-options "-O2 -std=c99" } */
int g;
int a[1024];
diff --git a/libgomp/testsuite/libgomp.c/taskloop-4.c b/libgomp/testsuite/libgomp.c/taskloop-4.c
index a69be19..4ac1b5a 100644
--- a/libgomp/testsuite/libgomp.c/taskloop-4.c
+++ b/libgomp/testsuite/libgomp.c/taskloop-4.c
@@ -1,5 +1,5 @@
/* { dg-do run } */
-/* { dg-options "-O2 -fopenmp" } */
+/* { dg-options "-O2" } */
int u[64], v;
diff --git a/libgomp/testsuite/libgomp.fortran/aligned1.f03 b/libgomp/testsuite/libgomp.fortran/aligned1.f03
index 67a9ab4..2db03e1 100644
--- a/libgomp/testsuite/libgomp.fortran/aligned1.f03
+++ b/libgomp/testsuite/libgomp.fortran/aligned1.f03
@@ -1,5 +1,5 @@
! { dg-do run }
-! { dg-options "-fopenmp -fcray-pointer" }
+! { dg-options "-fcray-pointer" }
use iso_c_binding, only : c_ptr, c_ptrdiff_t, c_loc
interface
diff --git a/libgomp/testsuite/libgomp.fortran/condinc1.f b/libgomp/testsuite/libgomp.fortran/condinc1.f
index d94fe8d..6d05635 100644
--- a/libgomp/testsuite/libgomp.fortran/condinc1.f
+++ b/libgomp/testsuite/libgomp.fortran/condinc1.f
@@ -1,4 +1,3 @@
-! { dg-options "-fopenmp" }
program condinc1
logical l
l = .false.
diff --git a/libgomp/testsuite/libgomp.fortran/condinc3.f90 b/libgomp/testsuite/libgomp.fortran/condinc3.f90
index 16b937a..7c24303 100644
--- a/libgomp/testsuite/libgomp.fortran/condinc3.f90
+++ b/libgomp/testsuite/libgomp.fortran/condinc3.f90
@@ -1,4 +1,3 @@
- ! { dg-options "-fopenmp" }
program condinc3
logical l
l = .false.
diff --git a/libgomp/testsuite/libgomp.fortran/crayptr1.f90 b/libgomp/testsuite/libgomp.fortran/crayptr1.f90
index 57c59f7..fb9495e 100644
--- a/libgomp/testsuite/libgomp.fortran/crayptr1.f90
+++ b/libgomp/testsuite/libgomp.fortran/crayptr1.f90
@@ -1,5 +1,5 @@
! { dg-do run }
-! { dg-options "-fopenmp -fcray-pointer" }
+! { dg-options "-fcray-pointer" }
use omp_lib
integer :: a, b, c, p
diff --git a/libgomp/testsuite/libgomp.fortran/crayptr2.f90 b/libgomp/testsuite/libgomp.fortran/crayptr2.f90
index c88cc7a..7e69b87 100644
--- a/libgomp/testsuite/libgomp.fortran/crayptr2.f90
+++ b/libgomp/testsuite/libgomp.fortran/crayptr2.f90
@@ -1,5 +1,5 @@
! { dg-do run }
-! { dg-options "-fopenmp -fcray-pointer" }
+! { dg-options "-fcray-pointer" }
! { dg-require-effective-target tls_runtime }
use omp_lib
diff --git a/libgomp/testsuite/libgomp.fortran/crayptr3.f90 b/libgomp/testsuite/libgomp.fortran/crayptr3.f90
index 9777c6b..5b3de65 100644
--- a/libgomp/testsuite/libgomp.fortran/crayptr3.f90
+++ b/libgomp/testsuite/libgomp.fortran/crayptr3.f90
@@ -1,5 +1,5 @@
! { dg-do run }
-! { dg-options "-fopenmp -fcray-pointer" }
+! { dg-options "-fcray-pointer" }
use omp_lib
integer :: a, b, c, i, p
diff --git a/libgomp/testsuite/libgomp.fortran/omp_cond1.f b/libgomp/testsuite/libgomp.fortran/omp_cond1.f
index b557d90..f51e868 100644
--- a/libgomp/testsuite/libgomp.fortran/omp_cond1.f
+++ b/libgomp/testsuite/libgomp.fortran/omp_cond1.f
@@ -1,5 +1,4 @@
C Test conditional compilation in fixed form if -fopenmp
-! { dg-options "-fopenmp" }
10 foo = 2
&56
if (foo.ne.256) call abort
diff --git a/libgomp/testsuite/libgomp.fortran/omp_cond3.F90 b/libgomp/testsuite/libgomp.fortran/omp_cond3.F90
index 6c4e36e..fe8c783 100644
--- a/libgomp/testsuite/libgomp.fortran/omp_cond3.F90
+++ b/libgomp/testsuite/libgomp.fortran/omp_cond3.F90
@@ -1,5 +1,4 @@
! Test conditional compilation in free form if -fopenmp
-! { dg-options "-fopenmp" }
10 foo = 2&
&56
if (foo.ne.256) call abort
diff --git a/libgomp/testsuite/libgomp.fortran/pr66199-1.f90 b/libgomp/testsuite/libgomp.fortran/pr66199-1.f90
index 0cd232f..55ad627 100644
--- a/libgomp/testsuite/libgomp.fortran/pr66199-1.f90
+++ b/libgomp/testsuite/libgomp.fortran/pr66199-1.f90
@@ -1,6 +1,6 @@
! PR middle-end/66199
! { dg-do run }
-! { dg-options "-O2 -fopenmp" }
+! { dg-options "-O2" }
integer :: u(1024), v(1024), w(1024), a, b, c, d, e, a1, b1, a2, b2, d1, d2
a = 1
diff --git a/libgomp/testsuite/libgomp.fortran/pr66199-2.f90 b/libgomp/testsuite/libgomp.fortran/pr66199-2.f90
index e17ab96..0cc0fa5 100644
--- a/libgomp/testsuite/libgomp.fortran/pr66199-2.f90
+++ b/libgomp/testsuite/libgomp.fortran/pr66199-2.f90
@@ -1,6 +1,6 @@
! PR middle-end/66199
! { dg-do run }
-! { dg-options "-O2 -fopenmp" }
+! { dg-options "-O2" }
integer :: u(1024), v(1024), w(1024), a, b, c, d, e, a1, b1, a2, b2, d1, d2
a = 1
diff --git a/libgomp/testsuite/libgomp.fortran/recursion1.f90 b/libgomp/testsuite/libgomp.fortran/recursion1.f90
index 35cb878..0cae261 100644
--- a/libgomp/testsuite/libgomp.fortran/recursion1.f90
+++ b/libgomp/testsuite/libgomp.fortran/recursion1.f90
@@ -1,5 +1,5 @@
! { dg-do run }
-! { dg-options "-fopenmp -fcheck=recursion" }
+! { dg-options "-fcheck=recursion" }
!
! PR 42517: Bogus runtime error with -fopenmp -fcheck=recursion
!
diff --git a/libgomp/testsuite/libgomp.fortran/target2.f90 b/libgomp/testsuite/libgomp.fortran/target2.f90
index 42f704f..40b7b0b 100644
--- a/libgomp/testsuite/libgomp.fortran/target2.f90
+++ b/libgomp/testsuite/libgomp.fortran/target2.f90
@@ -1,5 +1,5 @@
! { dg-do run }
-! { dg-options "-fopenmp -ffree-line-length-160" }
+! { dg-options "-ffree-line-length-160" }
module target2
contains
diff --git a/libgomp/testsuite/libgomp.fortran/target5.f90 b/libgomp/testsuite/libgomp.fortran/target5.f90
index c46faf2..4aad88e 100644
--- a/libgomp/testsuite/libgomp.fortran/target5.f90
+++ b/libgomp/testsuite/libgomp.fortran/target5.f90
@@ -1,5 +1,4 @@
! { dg-do compile }
-! { dg-options "-fopenmp" }
integer :: r
r = 0
diff --git a/libgomp/testsuite/libgomp.fortran/task3.f90 b/libgomp/testsuite/libgomp.fortran/task3.f90
index 30ff980..83b0e9f 100644
--- a/libgomp/testsuite/libgomp.fortran/task3.f90
+++ b/libgomp/testsuite/libgomp.fortran/task3.f90
@@ -1,5 +1,4 @@
! { dg-do run }
-! { dg-options "-fopenmp" }
!
! PR fortran/47886
!
diff --git a/libgomp/testsuite/libgomp.hsa.c/pr82416.c b/libgomp/testsuite/libgomp.hsa.c/pr82416.c
new file mode 100644
index 0000000..b89d421
--- /dev/null
+++ b/libgomp/testsuite/libgomp.hsa.c/pr82416.c
@@ -0,0 +1,37 @@
+char __attribute__ ((noipa))
+toup (char X)
+{
+ if (X >= 97 && X <= 122)
+ return X - 32;
+ else
+ return X;
+}
+
+char __attribute__ ((noipa))
+target_toup (char X)
+{
+ char r;
+#pragma omp target map(to:X) map(from:r)
+ {
+ if (X >= 97 && X <= 122)
+ r = X - 32;
+ else
+ r = X;
+ }
+ return r;
+}
+
+int main (int argc, char **argv)
+{
+ char a = 'a';
+ if (toup (a) != target_toup (a))
+ __builtin_abort ();
+ a = 'Z';
+ if (toup (a) != target_toup (a))
+ __builtin_abort ();
+ a = 5;
+ if (toup (a) != target_toup (a))
+ __builtin_abort ();
+
+ return 0;
+}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-1.c
index c63a68d..bc72617 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-1.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-1.c
@@ -1,5 +1,3 @@
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
#include <openacc.h>
#include <stdlib.h>
#include <stdio.h>
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-2.c
index 2078a33..d212458 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-2.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-2.c
@@ -1,5 +1,3 @@
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
#include <stdlib.h>
#define N 16
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-4.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-4.c
index 36bf0eb..ca48e80 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-4.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-4.c
@@ -1,5 +1,3 @@
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
-
#include <stdlib.h>
#include <openacc.h>
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-5.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-5.c
index 38c5de0..229e96c 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-5.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/declare-5.c
@@ -1,4 +1,4 @@
-/* { dg-do run { target openacc_nvidia_accel_selected } } */
+/* { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } } */
#include <stdio.h>
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-1.c
index 7bff6cd..ae1d588 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-1.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-1.c
@@ -15,7 +15,7 @@ int main ()
for (ix = 0; ix < N;ix++)
ary[ix] = -1;
-#pragma acc parallel num_gangs(32) vector_length(32) copy(ary) copy(ondev)
+#pragma acc parallel num_gangs(32) copy(ary) copy(ondev)
{
#pragma acc loop gang
for (unsigned ix = 0; ix < N; ix++)
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-2.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-2.c
index 92b82a0..c06d861 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-2.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-g-2.c
@@ -15,7 +15,7 @@ int main ()
for (ix = 0; ix < N;ix++)
ary[ix] = -1;
-#pragma acc parallel num_gangs(32) vector_length(32) copy(ary) copy(ondev)
+#pragma acc parallel num_gangs(32) copy(ary) copy(ondev)
{
#pragma acc loop gang (static:1)
for (unsigned ix = 0; ix < N; ix++)
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-red-g-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-red-g-1.c
index d241d41..929e01c 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-red-g-1.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/loop-red-g-1.c
@@ -11,7 +11,7 @@ int main ()
int ondev = 0;
int t = 0, h = 0;
-#pragma acc parallel num_gangs(32) vector_length(32) copy(ondev)
+#pragma acc parallel num_gangs(32) copy(ondev)
{
#pragma acc loop gang reduction (+:t)
for (unsigned ix = 0; ix < N; ix++)
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-3.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-3.c
index 8d85fed..6369d7f 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-3.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-3.c
@@ -11,7 +11,7 @@ main (int argc, char *argv[])
float res = 0, hres = 0;
for (i = 0; i < 32768; i++)
- arr[i] = i;
+ arr[i] = i % (32768 / 64);
#pragma acc parallel num_gangs(32) num_workers(32) vector_length(32) \
reduction(+:res) copy(res)
@@ -36,6 +36,7 @@ main (int argc, char *argv[])
hres += arr[j * 1024 + (1023 - i)];
}
+ assert (hres <= 16777216);
assert (res == hres);
return 0;
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-4.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-4.c
index 1904b4a..140c322 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-4.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/par-loop-comb-reduction-4.c
@@ -11,7 +11,7 @@ main (int argc, char *argv[])
float res = 0, mres = 0, hres = 0, hmres = 0;
for (i = 0; i < 32768; i++)
- arr[i] = i;
+ arr[i] = i % (32768 / 64);
#pragma acc parallel num_gangs(32) num_workers(32) vector_length(32) \
reduction(+:res) reduction(max:mres) copy(res, mres)
@@ -48,7 +48,10 @@ main (int argc, char *argv[])
hmres = arr[j * 1024 + (1023 - i)];
}
+ assert (hres <= 16777216);
assert (res == hres);
+
+ assert (hmres <= 16777216);
assert (mres == hmres);
return 0;
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/parallel-reduction.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/parallel-reduction.c
index b2c60e5..077571f 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/parallel-reduction.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/parallel-reduction.c
@@ -21,7 +21,7 @@ main ()
}
}
- if (acc_get_device_type () != acc_device_nvidia)
+ if (acc_get_device_type () == acc_device_host)
{
if (s1 != 1)
abort ();
@@ -41,7 +41,7 @@ main ()
s2 += N;
}
- if (acc_get_device_type () != acc_device_nvidia)
+ if (acc_get_device_type () == acc_device_host)
{
if (s1 != 1)
abort ();
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/reduction-7.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/reduction-7.c
index cc3cd07..c4940b8 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/reduction-7.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/reduction-7.c
@@ -183,7 +183,7 @@ void gwv_np_4()
float res = 0, mres = 0, hres = 0, hmres = 0;
for (i = 0; i < 32768; i++)
- arr[i] = i;
+ arr[i] = i % (32768 / 64);
#pragma acc parallel num_gangs(32) num_workers(32) vector_length(32)
{
@@ -219,7 +219,10 @@ void gwv_np_4()
hmres = arr[j * 1024 + (1023 - i)];
}
+ assert (hres <= 16777216);
assert (res == hres);
+
+ assert (hmres <= 16777216);
assert (mres == hmres);
}
diff --git a/libgomp/testsuite/libgomp.oacc-c-c++-common/routine-g-1.c b/libgomp/testsuite/libgomp.oacc-c-c++-common/routine-g-1.c
index 9d14c3b..b6ab713 100644
--- a/libgomp/testsuite/libgomp.oacc-c-c++-common/routine-g-1.c
+++ b/libgomp/testsuite/libgomp.oacc-c-c++-common/routine-g-1.c
@@ -36,7 +36,7 @@ int main ()
for (ix = 0; ix < N;ix++)
ary[ix] = -1;
-#pragma acc parallel num_gangs(32) vector_length(32) copy(ary) copy(ondev)
+#pragma acc parallel num_gangs(32) copy(ary) copy(ondev)
{
ondev = __builtin_acc_on_device (5);
gang (ary);
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/declare-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/declare-1.f90
index 2d4b707..b502df4 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/declare-1.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/declare-1.f90
@@ -1,4 +1,5 @@
-! { dg-do run { target openacc_nvidia_accel_selected } }
+! { dg-do run }
+! { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } }
! Tests to exercise the declare directive along with
! the clauses: copy
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/declare-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/declare-2.f90
index 2aa7907..0e759dd 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/declare-2.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/declare-2.f90
@@ -1,4 +1,4 @@
-! { dg-do run { target openacc_nvidia_accel_selected } }
+! { dg-do run }
module globalvars
implicit none
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/declare-3.f90 b/libgomp/testsuite/libgomp.oacc-fortran/declare-3.f90
index 3a6b420..16164cd 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/declare-3.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/declare-3.f90
@@ -1,4 +1,5 @@
-! { dg-do run { target openacc_nvidia_accel_selected } }
+! { dg-do run }
+! { dg-skip-if "" { *-*-* } { "-DACC_MEM_SHARED=1" } }
module globalvars
implicit none
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/declare-4.f90 b/libgomp/testsuite/libgomp.oacc-fortran/declare-4.f90
index 226264e..6c4e7c5 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/declare-4.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/declare-4.f90
@@ -1,4 +1,4 @@
-! { dg-do run { target openacc_nvidia_accel_selected } }
+! { dg-do run }
module vars
implicit none
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/declare-5.f90 b/libgomp/testsuite/libgomp.oacc-fortran/declare-5.f90
index bcd9c9c..4f5c8f0 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/declare-5.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/declare-5.f90
@@ -1,4 +1,4 @@
-! { dg-do run { target openacc_nvidia_accel_selected } }
+! { dg-do run }
module vars
implicit none
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/firstprivate-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/firstprivate-1.f90
index d3f9093..3866096 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/firstprivate-1.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/firstprivate-1.f90
@@ -5,7 +5,7 @@ program firstprivate
integer :: a, b(Nupper), c, d, n
include "openacc_lib.h"
- if (acc_get_device_type () .eq. acc_device_nvidia) then
+ if (acc_get_device_type () .ne. acc_device_host) then
n = Nupper
else
n = 1
diff --git a/libgomp/testsuite/libgomp.oacc-fortran/parallel-reduction.f90 b/libgomp/testsuite/libgomp.oacc-fortran/parallel-reduction.f90
index 31db7e1..d0559a2 100644
--- a/libgomp/testsuite/libgomp.oacc-fortran/parallel-reduction.f90
+++ b/libgomp/testsuite/libgomp.oacc-fortran/parallel-reduction.f90
@@ -15,7 +15,7 @@ program reduction
s2 = s2 + 1
!$acc end parallel
- if (acc_get_device_type () .eq. acc_device_nvidia) then
+ if (acc_get_device_type () .ne. acc_device_host) then
if (s1 .ne. n) call abort
if (s2 .ne. n) call abort
else
@@ -29,7 +29,7 @@ program reduction
s2 = 0
call redsub (s1, s2, n)
- if (acc_get_device_type () .eq. acc_device_nvidia) then
+ if (acc_get_device_type () .ne. acc_device_host) then
if (s1 .ne. n) call abort
else
if (s2 .ne. 1) call abort
diff --git a/libhsail-rt/ChangeLog b/libhsail-rt/ChangeLog
index 31ffff6..53d3634 100644
--- a/libhsail-rt/ChangeLog
+++ b/libhsail-rt/ChangeLog
@@ -1,3 +1,15 @@
+2017-09-27 Pekka Jääskeläinen <pekka.jaaskelainen@parmance.com>
+
+ * include/internal/phsa-rt.h: Support for improved group segment
+ handling with a stack-like allocation scheme.
+ * include/internal/workitems.h: Likewise.
+ * rt/workitems.c: Likewise.
+
+2017-09-25 Pekka Jääskeläinen <pekka.jaaskelainen@parmance.com>
+
+ * rt/workitems.c: Assume the host runtime allocates the work group
+ memory.
+
2017-05-03 Pekka Jääskeläinen <pekka.jaaskelainen@parmance.com>
* rt/workitems.c: Removed a leftover comment.
diff --git a/libhsail-rt/include/internal/phsa-rt.h b/libhsail-rt/include/internal/phsa-rt.h
index d47cbfcd..13349e7 100644
--- a/libhsail-rt/include/internal/phsa-rt.h
+++ b/libhsail-rt/include/internal/phsa-rt.h
@@ -42,7 +42,8 @@ typedef void (*gccbrigKernelLauncherFunc) (void *context, void *);
/* Pointer type for kernel functions produced by gccbrig from the HSAIL.
This is private from outside the device binary and only called by
the launcher. */
-typedef void (*gccbrigKernelFunc) (unsigned char *, void *, void *, void *);
+typedef void (*gccbrigKernelFunc) (unsigned char *, void *, void *, uint32_t,
+ void *);
/* Context data that is passed to the kernel function, initialized
by the runtime to the current launch information. The data is
diff --git a/libhsail-rt/include/internal/workitems.h b/libhsail-rt/include/internal/workitems.h
index e7d386d..2abfc61 100644
--- a/libhsail-rt/include/internal/workitems.h
+++ b/libhsail-rt/include/internal/workitems.h
@@ -63,6 +63,11 @@ typedef struct
to the work-group. */
void *group_base_ptr;
+ /* The offset in the group memory for the kernel local group variables.
+ To support module scope group variables, there might be need to preseve
+ room for them in the beginning of the group segment. */
+ uint32_t initial_group_offset;
+
/* Similarly to the private segment that gets space allocated for all
WIs in the work-group. */
void *private_base_ptr;
diff --git a/libhsail-rt/rt/workitems.c b/libhsail-rt/rt/workitems.c
index e2c2373..b24fc10 100644
--- a/libhsail-rt/rt/workitems.c
+++ b/libhsail-rt/rt/workitems.c
@@ -113,7 +113,7 @@ phsa_work_item_thread (int arg0, int arg1)
&& wi->z < __hsail_currentworkgroupsize (2, wi))
{
l_data->kernel (l_data->kernarg_addr, wi, wg->group_base_ptr,
- wg->private_base_ptr);
+ wg->initial_group_offset, wg->private_base_ptr);
#ifdef DEBUG_PHSA_RT
printf ("done.\n");
#endif
@@ -221,7 +221,8 @@ phsa_work_item_thread (int arg0, int arg1)
static void
phsa_execute_wi_gang (PHSAKernelLaunchData *context, void *group_base_ptr,
- size_t wg_size_x, size_t wg_size_y, size_t wg_size_z)
+ uint32_t group_local_offset, size_t wg_size_x,
+ size_t wg_size_y, size_t wg_size_z)
{
PHSAWorkItem *wi_threads = NULL;
PHSAWorkGroup wg;
@@ -247,6 +248,7 @@ phsa_execute_wi_gang (PHSAKernelLaunchData *context, void *group_base_ptr,
wg.alloca_stack_p = wg.private_segment_total_size;
wg.alloca_frame_p = wg.alloca_stack_p;
+ wg.initial_group_offset = group_local_offset;
#ifdef EXECUTE_WGS_BACKWARDS
wg.x = context->wg_max_x - 1;
@@ -313,19 +315,12 @@ phsa_execute_wi_gang (PHSAKernelLaunchData *context, void *group_base_ptr,
them execute all the WGs, including a potential partial WG. */
static void
-phsa_spawn_work_items (PHSAKernelLaunchData *context, void *group_base_ptr)
+phsa_spawn_work_items (PHSAKernelLaunchData *context, void *group_base_ptr,
+ uint32_t group_local_offset)
{
hsa_kernel_dispatch_packet_t *dp = context->dp;
size_t x, y, z;
- /* TO DO: host-side memory management of group and private segment
- memory. Agents in general are less likely to support efficient dynamic mem
- allocation. */
- if (dp->group_segment_size > 0
- && posix_memalign (&group_base_ptr, PRIVATE_SEGMENT_ALIGN,
- dp->group_segment_size) != 0)
- phsa_fatal_error (3);
-
context->group_segment_start_addr = (size_t) group_base_ptr;
/* HSA seems to allow the WG size to be larger than the grid size. We need to
@@ -369,11 +364,8 @@ phsa_spawn_work_items (PHSAKernelLaunchData *context, void *group_base_ptr)
dp->grid_size_y, dp->grid_size_z);
#endif
- phsa_execute_wi_gang (context, group_base_ptr, sat_wg_size_x, sat_wg_size_y,
- sat_wg_size_z);
-
- if (dp->group_segment_size > 0)
- free (group_base_ptr);
+ phsa_execute_wi_gang (context, group_base_ptr, group_local_offset,
+ sat_wg_size_x, sat_wg_size_y, sat_wg_size_z);
}
#endif
@@ -385,19 +377,12 @@ phsa_spawn_work_items (PHSAKernelLaunchData *context, void *group_base_ptr)
execute massive numbers of work-items in a non-SPMD machine than fibers
(easily 100x faster). */
static void
-phsa_execute_work_groups (PHSAKernelLaunchData *context, void *group_base_ptr)
+phsa_execute_work_groups (PHSAKernelLaunchData *context, void *group_base_ptr,
+ uint32_t group_local_offset)
{
hsa_kernel_dispatch_packet_t *dp = context->dp;
size_t x, y, z, wg_x, wg_y, wg_z;
- /* TODO: host-side memory management of group and private segment
- memory. Agents in general are less likely to support efficient dynamic mem
- allocation. */
- if (dp->group_segment_size > 0
- && posix_memalign (&group_base_ptr, GROUP_SEGMENT_ALIGN,
- dp->group_segment_size) != 0)
- phsa_fatal_error (3);
-
context->group_segment_start_addr = (size_t) group_base_ptr;
/* HSA seems to allow the WG size to be larger than the grid size. We need
@@ -481,7 +466,7 @@ phsa_execute_work_groups (PHSAKernelLaunchData *context, void *group_base_ptr)
wi.wg->z = wg_z;
context->kernel (context->kernarg_addr, &wi, group_base_ptr,
- private_base_ptr);
+ group_local_offset, private_base_ptr);
#if defined (BENCHMARK_PHSA_RT)
wg_count++;
@@ -509,10 +494,6 @@ phsa_execute_work_groups (PHSAKernelLaunchData *context, void *group_base_ptr)
printf ("### %lu WIs executed in %lu s (%lu WIs / s)\n", wi_total,
(uint64_t) spent_time_sec, (uint64_t) wis_per_sec);
#endif
-
- if (dp->group_segment_size > 0)
- free (group_base_ptr);
-
free (private_base_ptr);
private_base_ptr = NULL;
}
@@ -550,19 +531,20 @@ phsa_execute_work_groups (PHSAKernelLaunchData *context, void *group_base_ptr)
void
__hsail_launch_kernel (gccbrigKernelFunc kernel, PHSAKernelLaunchData *context,
- void *group_base_ptr)
+ void *group_base_ptr, uint32_t group_local_offset)
{
context->kernel = kernel;
- phsa_spawn_work_items (context, group_base_ptr);
+ phsa_spawn_work_items (context, group_base_ptr, group_local_offset);
}
#endif
void
__hsail_launch_wg_function (gccbrigKernelFunc kernel,
- PHSAKernelLaunchData *context, void *group_base_ptr)
+ PHSAKernelLaunchData *context, void *group_base_ptr,
+ uint32_t group_local_offset)
{
context->kernel = kernel;
- phsa_execute_work_groups (context, group_base_ptr);
+ phsa_execute_work_groups (context, group_base_ptr, group_local_offset);
}
uint32_t
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog
index 7a49a6a..eb3cbc1 100644
--- a/libiberty/ChangeLog
+++ b/libiberty/ChangeLog
@@ -1,3 +1,47 @@
+2017-10-24 Alan Modra <amodra@gmail.com>
+
+ PR lto/82687
+ PR lto/82575
+ * simple-object-elf.c (simple_object_elf_copy_lto_debug_sections):
+ Only make __gnu_lto symbols hidden.
+
+2017-10-20 Alan Modra <amodra@gmail.com>
+
+ PR lto/82575
+ * simple-object-elf.c (simple_object_elf_copy_lto_debug_sections):
+ Make discarded non-local symbols weak and hidden.
+
+2017-10-18 Jakub Jelinek <jakub@redhat.com>
+
+ PR lto/82598
+ * simple-object.c (handle_lto_debug_sections): Copy over also
+ .note.GNU-stack section with unchanged name.
+ * simple-object-elf.c (SHF_EXECINSTR): Define.
+ (simple_object_elf_copy_lto_debug_section): Drop SHF_EXECINSTR bit
+ on .note.GNU-stack section.
+
+2017-09-25 Nathan Sidwell <nathan@acm.org>
+
+ PR demangler/82195
+ * cp-demangle.c (d_encoding): Strip return type when name is a
+ LOCAL_NAME.
+ (d_local_name): Strip return type of enclosing TYPED_NAME.
+ * testsuite/demangle-expected: Add and adjust tests.
+
+2017-09-21 Nathan Sidwell <nathan@acm.org>
+
+ PR demangler/82195
+ * cp-demangle.c (d_name): Revert addition of 'toplevel' parm.
+ (has_return_type): Recurse for DEMANGLE_COMPONENT_LOCAL_NAME.
+ (d_encoding): Revert d_name change. Use is_fnqual_component_type
+ to strip modifiers that do not belong.
+ (d_special_name, d_class_enum_type): Revert d_name call change.
+ (d_expresion_1): Commonize DEMANGLE_COMPONENT_UNARY building.
+ (d_local_name): Revert parsing of a function type.
+ (d_print_comp_inner): An inner LOCAL_NAME might contain a
+ TEMPLATE.
+ * testsuite/demangle-expected: Add & adjust tests
+
2017-09-15 Nathan Sidwell <nathan@acm.org>
PR demangler/82195
diff --git a/libiberty/cp-demangle.c b/libiberty/cp-demangle.c
index c330052..8e64347 100644
--- a/libiberty/cp-demangle.c
+++ b/libiberty/cp-demangle.c
@@ -425,7 +425,7 @@ is_ctor_dtor_or_conversion (struct demangle_component *);
static struct demangle_component *d_encoding (struct d_info *, int);
-static struct demangle_component *d_name (struct d_info *, int);
+static struct demangle_component *d_name (struct d_info *);
static struct demangle_component *d_nested_name (struct d_info *);
@@ -484,7 +484,7 @@ static struct demangle_component *d_expression (struct d_info *);
static struct demangle_component *d_expr_primary (struct d_info *);
-static struct demangle_component *d_local_name (struct d_info *, int);
+static struct demangle_component *d_local_name (struct d_info *);
static int d_discriminator (struct d_info *);
@@ -1259,6 +1259,8 @@ has_return_type (struct demangle_component *dc)
{
default:
return 0;
+ case DEMANGLE_COMPONENT_LOCAL_NAME:
+ return has_return_type (d_right (dc));
case DEMANGLE_COMPONENT_TEMPLATE:
return ! is_ctor_dtor_or_conversion (d_left (dc));
FNQUAL_COMPONENT_CASE:
@@ -1301,25 +1303,22 @@ static struct demangle_component *
d_encoding (struct d_info *di, int top_level)
{
char peek = d_peek_char (di);
+ struct demangle_component *dc;
if (peek == 'G' || peek == 'T')
- return d_special_name (di);
+ dc = d_special_name (di);
else
{
- struct demangle_component *dc, *dcr;
-
- dc = d_name (di, top_level);
+ dc = d_name (di);
- if (dc != NULL && top_level && (di->options & DMGL_PARAMS) == 0)
+ if (!dc)
+ /* Failed already. */;
+ else if (top_level && (di->options & DMGL_PARAMS) == 0)
{
/* Strip off any initial CV-qualifiers, as they really apply
to the `this' parameter, and they were not output by the
v2 demangler without DMGL_PARAMS. */
- while (dc->type == DEMANGLE_COMPONENT_RESTRICT_THIS
- || dc->type == DEMANGLE_COMPONENT_VOLATILE_THIS
- || dc->type == DEMANGLE_COMPONENT_CONST_THIS
- || dc->type == DEMANGLE_COMPONENT_REFERENCE_THIS
- || dc->type == DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS)
+ while (is_fnqual_component_type (dc->type))
dc = d_left (dc);
/* If the top level is a DEMANGLE_COMPONENT_LOCAL_NAME, then
@@ -1327,22 +1326,37 @@ d_encoding (struct d_info *di, int top_level)
really apply here; this happens when parsing a class
which is local to a function. */
if (dc->type == DEMANGLE_COMPONENT_LOCAL_NAME)
+ while (is_fnqual_component_type (d_right (dc)->type))
+ d_right (dc) = d_left (d_right (dc));
+ }
+ else
+ {
+ peek = d_peek_char (di);
+ if (peek != '\0' && peek != 'E')
{
- dcr = d_right (dc);
- while (is_fnqual_component_type (dcr->type))
- dcr = d_left (dcr);
- dc->u.s_binary.right = dcr;
- }
+ struct demangle_component *ftype;
- return dc;
+ ftype = d_bare_function_type (di, has_return_type (dc));
+ if (ftype)
+ {
+ /* If this is a non-top-level local-name, clear the
+ return type, so it doesn't confuse the user by
+ being confused with the return type of whaever
+ this is nested within. */
+ if (!top_level && dc->type == DEMANGLE_COMPONENT_LOCAL_NAME
+ && ftype->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ d_left (ftype) = NULL;
+
+ dc = d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME,
+ dc, ftype);
+ }
+ else
+ dc = NULL;
+ }
}
-
- peek = d_peek_char (di);
- if (dc == NULL || peek == '\0' || peek == 'E')
- return dc;
- dcr = d_bare_function_type (di, has_return_type (dc));
- return d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME, dc, dcr);
}
+
+ return dc;
}
/* <tagged-name> ::= <name> B <source-name> */
@@ -1383,7 +1397,7 @@ d_abi_tags (struct d_info *di, struct demangle_component *dc)
*/
static struct demangle_component *
-d_name (struct d_info *di, int top_level)
+d_name (struct d_info *di)
{
char peek = d_peek_char (di);
struct demangle_component *dc;
@@ -1394,7 +1408,7 @@ d_name (struct d_info *di, int top_level)
return d_nested_name (di);
case 'Z':
- return d_local_name (di, top_level);
+ return d_local_name (di);
case 'U':
return d_unqualified_name (di);
@@ -2079,11 +2093,11 @@ d_special_name (struct d_info *di)
case 'H':
return d_make_comp (di, DEMANGLE_COMPONENT_TLS_INIT,
- d_name (di, 0), NULL);
+ d_name (di), NULL);
case 'W':
return d_make_comp (di, DEMANGLE_COMPONENT_TLS_WRAPPER,
- d_name (di, 0), NULL);
+ d_name (di), NULL);
default:
return NULL;
@@ -2095,11 +2109,11 @@ d_special_name (struct d_info *di)
{
case 'V':
return d_make_comp (di, DEMANGLE_COMPONENT_GUARD,
- d_name (di, 0), NULL);
+ d_name (di), NULL);
case 'R':
{
- struct demangle_component *name = d_name (di, 0);
+ struct demangle_component *name = d_name (di);
return d_make_comp (di, DEMANGLE_COMPONENT_REFTEMP, name,
d_number_component (di));
}
@@ -2935,7 +2949,7 @@ d_bare_function_type (struct d_info *di, int has_return_type)
static struct demangle_component *
d_class_enum_type (struct d_info *di)
{
- return d_name (di, 0);
+ return d_name (di);
}
/* <array-type> ::= A <(positive dimension) number> _ <(element) type>
@@ -3380,13 +3394,10 @@ d_expression_1 (struct d_info *di)
if (suffix)
/* Indicate the suffix variant for d_print_comp. */
- return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
- d_make_comp (di,
- DEMANGLE_COMPONENT_BINARY_ARGS,
- operand, operand));
- else
- return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op,
- operand);
+ operand = d_make_comp (di, DEMANGLE_COMPONENT_BINARY_ARGS,
+ operand, operand);
+
+ return d_make_comp (di, DEMANGLE_COMPONENT_UNARY, op, operand);
}
case 2:
{
@@ -3568,7 +3579,7 @@ d_expr_primary (struct d_info *di)
*/
static struct demangle_component *
-d_local_name (struct d_info *di, int top_level)
+d_local_name (struct d_info *di)
{
struct demangle_component *function;
struct demangle_component *name;
@@ -3577,6 +3588,8 @@ d_local_name (struct d_info *di, int top_level)
return NULL;
function = d_encoding (di, 0);
+ if (!function)
+ return NULL;
if (! d_check_char (di, 'E'))
return NULL;
@@ -3601,7 +3614,7 @@ d_local_name (struct d_info *di, int top_level)
return NULL;
}
- name = d_name (di, 0);
+ name = d_name (di);
if (name
/* Lambdas and unnamed types have internal discriminators
@@ -3609,18 +3622,6 @@ d_local_name (struct d_info *di, int top_level)
&& name->type != DEMANGLE_COMPONENT_LAMBDA
&& name->type != DEMANGLE_COMPONENT_UNNAMED_TYPE)
{
- if (!top_level
- && d_peek_char (di) != 0 /* Not end of string. */
- && d_peek_char (di) != 'E' /* Not end of nested encoding. */
- && d_peek_char (di) != '_') /* Not discriminator. */
- {
- struct demangle_component *args;
-
- args = d_bare_function_type (di, has_return_type (name));
- name = d_make_comp (di, DEMANGLE_COMPONENT_TYPED_NAME,
- name, args);
- }
-
/* Read and ignore an optional discriminator. */
if (! d_discriminator (di))
return NULL;
@@ -3630,6 +3631,13 @@ d_local_name (struct d_info *di, int top_level)
name = d_make_default_arg (di, num, name);
}
+ /* Elide the return type of the containing function so as to not
+ confuse the user thinking it is the return type of whatever local
+ function we might be containing. */
+ if (function->type == DEMANGLE_COMPONENT_TYPED_NAME
+ && d_right (function)->type == DEMANGLE_COMPONENT_FUNCTION_TYPE)
+ d_left (d_right (function)) = NULL;
+
return d_make_comp (di, DEMANGLE_COMPONENT_LOCAL_NAME, function, name);
}
@@ -4710,32 +4718,21 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
return;
}
- /* If typed_name is a template, then it applies to the
- function type as well. */
- if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
- {
- dpt.next = dpi->templates;
- dpi->templates = &dpt;
- dpt.template_decl = typed_name;
- }
-
/* If typed_name is a DEMANGLE_COMPONENT_LOCAL_NAME, then
there may be CV-qualifiers on its right argument which
- really apply here; this happens when parsing a class which
+ really apply here; this happens when parsing a class that
is local to a function. */
if (typed_name->type == DEMANGLE_COMPONENT_LOCAL_NAME)
{
- struct demangle_component *local_name;
-
- local_name = d_right (typed_name);
- if (local_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
- local_name = local_name->u.s_unary_num.sub;
- if (local_name == NULL)
+ typed_name = d_right (typed_name);
+ if (typed_name->type == DEMANGLE_COMPONENT_DEFAULT_ARG)
+ typed_name = typed_name->u.s_unary_num.sub;
+ if (typed_name == NULL)
{
d_print_error (dpi);
return;
}
- while (is_fnqual_component_type (local_name->type))
+ while (is_fnqual_component_type (typed_name->type))
{
if (i >= sizeof adpm / sizeof adpm[0])
{
@@ -4747,15 +4744,24 @@ d_print_comp_inner (struct d_print_info *dpi, int options,
adpm[i].next = &adpm[i - 1];
dpi->modifiers = &adpm[i];
- adpm[i - 1].mod = local_name;
+ adpm[i - 1].mod = typed_name;
adpm[i - 1].printed = 0;
adpm[i - 1].templates = dpi->templates;
++i;
- local_name = d_left (local_name);
+ typed_name = d_left (typed_name);
}
}
+ /* If typed_name is a template, then it applies to the
+ function type as well. */
+ if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
+ {
+ dpt.next = dpi->templates;
+ dpi->templates = &dpt;
+ dpt.template_decl = typed_name;
+ }
+
d_print_comp (dpi, options, d_right (dc));
if (typed_name->type == DEMANGLE_COMPONENT_TEMPLATE)
diff --git a/libiberty/simple-object-elf.c b/libiberty/simple-object-elf.c
index 7eb3df8..14f7105 100644
--- a/libiberty/simple-object-elf.c
+++ b/libiberty/simple-object-elf.c
@@ -196,6 +196,7 @@ typedef struct {
/* Values for sh_flags field. */
+#define SHF_EXECINSTR 0x00000004 /* Executable section. */
#define SHF_EXCLUDE 0x80000000 /* Link editor is to exclude this
section from executable and
shared library that it builds
@@ -235,8 +236,10 @@ typedef struct
#define STB_LOCAL 0 /* Local symbol */
#define STB_GLOBAL 1 /* Global symbol */
+#define STB_WEAK 2 /* Weak global */
#define STV_DEFAULT 0 /* Visibility is specified by binding type */
+#define STV_HIDDEN 2 /* Can only be seen inside currect component */
/* Functions to fetch and store different ELF types, depending on the
endianness and size. */
@@ -1085,6 +1088,7 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
off_t shstroff;
unsigned char *names;
unsigned int i;
+ int changed;
int *pfnret;
const char **pfnname;
@@ -1158,7 +1162,6 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
/* Mark sections as preserved that are required by to be preserved
sections. */
- int changed;
do
{
changed = 0;
@@ -1346,9 +1349,6 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
and __gnu_lto_slim which otherwise cause endless
LTO plugin invocation. */
if (st_shndx == SHN_COMMON)
- /* Setting st_name to "" seems to work to purge
- COMMON symbols (in addition to setting their
- size to zero). */
discard = 1;
/* We also need to remove symbols refering to sections
we'll eventually remove as with fat LTO objects
@@ -1364,18 +1364,37 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
{
/* Make discarded symbols undefined and unnamed
in case it is local. */
- if (ELF_ST_BIND (*st_info) == STB_LOCAL)
+ int bind = ELF_ST_BIND (*st_info);
+ int other = STV_DEFAULT;
+ size_t st_name;
+
+ if (bind == STB_LOCAL)
ELF_SET_FIELD (type_functions, ei_class, Sym,
ent, st_name, Elf_Word, 0);
+ else
+ {
+ bind = STB_WEAK;
+ st_name = ELF_FETCH_FIELD (type_functions, ei_class,
+ Sym, ent, st_name,
+ Elf_Word);
+ if (st_name < strsz)
+ {
+ char *p = strings + st_name;
+ if (p[0] == '_'
+ && p[1] == '_'
+ && strncmp (p + (p[2] == '_'),
+ "__gnu_lto_", 10) == 0)
+ other = STV_HIDDEN;
+ }
+ }
+ *st_other = other;
+ *st_info = ELF_ST_INFO (bind, STT_NOTYPE);
ELF_SET_FIELD (type_functions, ei_class, Sym,
ent, st_value, Elf_Addr, 0);
ELF_SET_FIELD (type_functions, ei_class, Sym,
ent, st_size, Elf_Word, 0);
ELF_SET_FIELD (type_functions, ei_class, Sym,
ent, st_shndx, Elf_Half, SHN_UNDEF);
- *st_info = ELF_ST_INFO (ELF_ST_BIND (*st_info),
- STT_NOTYPE);
- *st_other = STV_DEFAULT;
}
}
XDELETEVEC (strings);
@@ -1403,7 +1422,14 @@ simple_object_elf_copy_lto_debug_sections (simple_object_read *sobj,
flags = ELF_FETCH_FIELD (type_functions, ei_class, Shdr,
shdr, sh_flags, Elf_Addr);
if (ret == 0)
- flags &= ~SHF_EXCLUDE;
+ {
+ /* The debugobj doesn't contain any code, thus no trampolines.
+ Even when the original object needs trampolines, debugobj
+ doesn't. */
+ if (strcmp (name, ".note.GNU-stack") == 0)
+ flags &= ~SHF_EXECINSTR;
+ flags &= ~SHF_EXCLUDE;
+ }
else if (ret == -1)
flags = SHF_EXCLUDE;
ELF_SET_FIELD (type_functions, ei_class, Shdr,
diff --git a/libiberty/simple-object.c b/libiberty/simple-object.c
index 553e90f..19d222f 100644
--- a/libiberty/simple-object.c
+++ b/libiberty/simple-object.c
@@ -273,6 +273,9 @@ handle_lto_debug_sections (const char **name)
*name = *name + sizeof (".gnu.lto_") - 1;
return 1;
}
+ /* Copy over .note.GNU-stack section under the same name if present. */
+ else if (strcmp (*name, ".note.GNU-stack") == 0)
+ return 1;
return 0;
}
diff --git a/libiberty/testsuite/demangle-expected b/libiberty/testsuite/demangle-expected
index c1a9a73..b62561c 100644
--- a/libiberty/testsuite/demangle-expected
+++ b/libiberty/testsuite/demangle-expected
@@ -3817,14 +3817,14 @@ C::f<int>
# Another case where we got member function qualifiers wrong.
--format=gnu-v3 --no-params
_ZZ3BBdI3FooEvvENK3Fob3FabEv
-void BBd<Foo>()::Fob::Fab() const
-void BBd<Foo>()::Fob::Fab
+BBd<Foo>()::Fob::Fab() const
+BBd<Foo>()::Fob::Fab
#
# The same idea one level deeper.
--format=gnu-v3 --no-params
_ZZZ3BBdI3FooEvvENK3Fob3FabEvENK3Gob3GabEv
-void BBd<Foo>()::Fob::Fab() const::Gob::Gab() const
-void BBd<Foo>()::Fob::Fab() const::Gob::Gab
+BBd<Foo>()::Fob::Fab() const::Gob::Gab() const
+BBd<Foo>()::Fob::Fab() const::Gob::Gab
#
# Yet another member function qualifier problem.
--format=gnu-v3 --no-params
@@ -4445,7 +4445,7 @@ void f<int>()
# https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c3
--format=gnu-v3
_ZSt7forwardIRN1x14refobjiteratorINS0_3refINS0_4mime30multipart_section_processorObjIZ15get_body_parserIZZN14mime_processor21make_section_iteratorERKNS2_INS3_10sectionObjENS0_10ptrrefBaseEEEbENKUlvE_clEvEUlSB_bE_ZZNS6_21make_section_iteratorESB_bENKSC_clEvEUlSB_E0_ENS1_INS2_INS0_20outputrefiteratorObjIiEES8_EEEERKSsSB_OT_OT0_EUlmE_NS3_32make_multipart_default_discarderISP_EEEES8_EEEEEOT_RNSt16remove_referenceISW_E4typeE
-x::refobjiterator<x::ref<x::mime::multipart_section_processorObj<x::refobjiterator<x::ref<x::outputrefiteratorObj<int>, x::ptrrefBase> > get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> >, x::ptrrefBase> >& std::forward<x::refobjiterator<x::ref<x::mime::multipart_section_processorObj<x::refobjiterator<x::ref<x::outputrefiteratorObj<int>, x::ptrrefBase> > get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> >, x::ptrrefBase> >&>(std::remove_reference<x::mime::multipart_section_processorObj<x::refobjiterator<x::ref<x::outputrefiteratorObj<int>, x::ptrrefBase> > get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> > >::type&)
+x::refobjiterator<x::ref<x::mime::multipart_section_processorObj<get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> >, x::ptrrefBase> >& std::forward<x::refobjiterator<x::ref<x::mime::multipart_section_processorObj<get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> >, x::ptrrefBase> >&>(std::remove_reference<x::mime::multipart_section_processorObj<get_body_parser<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}>(std::string const&, x::ref<x::mime::sectionObj, x::ptrrefBase> const&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&, mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&)#2}&&)::{lambda(unsigned long)#1}, x::mime::make_multipart_default_discarder<mime_processor::make_section_iterator(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)::{lambda()#1}::operator()() const::{lambda(x::ref<x::mime::sectionObj, x::ptrrefBase> const&, bool)#1}&&> > >::type&)
#
--format=gnu-v3 --no-params
_ZNK7strings8internal8SplitterINS_9delimiter5AnyOfENS_9SkipEmptyEEcvT_ISt6vectorI12basic_stringIcSt11char_traitsIcESaIcEESaISD_EEvEEv
@@ -4469,28 +4469,28 @@ A::operator C<int><C>
# https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c16
--format=gnu-v3
_ZN3mdr16in_cached_threadIRZNK4cudr6GPUSet17parallel_for_eachIZN5tns3d20shape_representation7compute7GPUImpl7executeERKNS_1AINS_7ptr_refIKjEELl3ELl3ENS_8c_strideILl1ELl0EEEEERKNS8_INS9_IjEELl4ELl1ESD_EEEUliRKNS1_7ContextERNS7_5StateEE_JSt6vectorISO_SaISO_EEEEEvOT_DpRT0_EUlSP_E_JSt17reference_wrapperISO_EEEENS_12ScopedFutureIDTclfp_spcl7forwardISW_Efp0_EEEEESV_DpOSW_
-mdr::ScopedFuture<decltype ({parm#1}(((forward<void cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}&&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&>)({parm#2}))...))> mdr::in_cached_thread<void cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(void cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}&&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&, std::reference_wrapper<tns3d::shape_representation::compute::GPUImpl::State> >(void cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}&&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&, (void cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}&&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&&&)...)
+mdr::ScopedFuture<decltype ({parm#1}(((forward<cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}&&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&>)({parm#2}))...))> mdr::in_cached_thread<cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}&&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&, std::reference_wrapper<tns3d::shape_representation::compute::GPUImpl::State> >(cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}&&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&, (cudr::GPUSet::parallel_for_each<tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> > >(tns3d::shape_representation::compute::GPUImpl::execute(mdr::A<mdr::ptr_ref<unsigned int const>, 3l, 3l, mdr::c_stride<1l, 0l> > const&, mdr::A<mdr::ptr_ref<unsigned int>, 4l, 1l, mdr::c_stride<1l, 0l> > const&)::{lambda(int, cudr::Context const&, tns3d::shape_representation::compute::GPUImpl::State&)#1}&&, std::vector<tns3d::shape_representation::compute::GPUImpl::State, std::allocator<tns3d::shape_representation::compute::GPUImpl::State> >&) const::{lambda(tns3d::shape_representation::compute::GPUImpl::State&)#1}&&&)...)
# https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c18
--format=gnu-v3
_ZNSt9_Any_data9_M_accessIPZN13ThreadManager10futureTaskISt5_BindIFSt7_Mem_fnIM6RunnerFvvEEPS5_EEEEvOT_EUlvE_EERSC_v
-void ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)>&&)::{lambda()#1}*& std::_Any_data::_M_access<void ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(void ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
+ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)>&&)::{lambda()#1}*& std::_Any_data::_M_access<ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(ThreadManager::futureTask<std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)> >(std::_Bind<std::_Mem_fn<void (Runner::*)()> (Runner*)>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
# https://sourceware.org/bugzilla/show_bug.cgi?id=14963#c24
# aka https://sourceware.org/bugzilla/show_bug.cgi?id=16593
--format=gnu-v3
_ZNSt9_Any_data9_M_accessIPZN3sel8Selector6SetObjI3FooJPKcMS4_FviEEEEvRT_DpT0_EUlvE_EESA_v
-void sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(Foo&, char const*, void (Foo::*)(int))::{lambda()#1}*& std::_Any_data::_M_access<void sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(void sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(Foo&, char const*, void (Foo::*)(int))::{lambda()#1}*&, char const*, void (Foo::*)(int))::{lambda()#1}*>()
+sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(Foo&, char const*, void (Foo::*)(int))::{lambda()#1}*& std::_Any_data::_M_access<sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(sel::Selector::SetObj<Foo, char const*, void (Foo::*)(int)>(Foo&, char const*, void (Foo::*)(int))::{lambda()#1}*&, char const*, void (Foo::*)(int))::{lambda()#1}*>()
# https://sourceware.org/bugzilla/show_bug.cgi?id=16752#c1
--format=gnu-v3
_ZNSt9_Any_data9_M_accessIPZN13ThreadManager7newTaskIRSt5_BindIFSt7_Mem_fnIM5DiaryFivEEPS5_EEIEEESt6futureINSt9result_ofIFT_DpT0_EE4typeEEOSF_DpOSG_EUlvE_EERSF_v
-std::future<std::result_of<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>& ()>::type> ThreadManager::newTask<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&>(std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&)::{lambda()#1}*& std::_Any_data::_M_access<std::future<std::result_of<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>& ()>::type> ThreadManager::newTask<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&>(std::future<std::result_of<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>& ()>::type> ThreadManager::newTask<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&>(std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&)::{lambda()#1}*&&)::{lambda()#1}*>()
+ThreadManager::newTask<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&>(std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&)::{lambda()#1}*& std::_Any_data::_M_access<ThreadManager::newTask<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&>(ThreadManager::newTask<std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&>(std::_Bind<std::_Mem_fn<int (Diary::*)()> (Diary*)>&)::{lambda()#1}*&&)::{lambda()#1}*>()
# https://sourceware.org/bugzilla/show_bug.cgi?id=16752#c6
--format=gnu-v3
_ZNSt9_Any_data9_M_accessIPZN6cereal18polymorphic_detail15getInputBindingINS1_16JSONInputArchiveEEENS1_6detail15InputBindingMapIT_E11SerializersERS7_jEUlPvRSt10unique_ptrIvNS5_12EmptyDeleterIvEEEE0_EESA_v
-cereal::detail::InputBindingMap<cereal::JSONInputArchive>::Serializers cereal::polymorphic_detail::getInputBinding<cereal::JSONInputArchive>(cereal::JSONInputArchive&, unsigned int)::{lambda(void*, std::unique_ptr<void, cereal::detail::EmptyDeleter<void> >&)#2}*& std::_Any_data::_M_access<cereal::detail::InputBindingMap<cereal::JSONInputArchive>::Serializers cereal::polymorphic_detail::getInputBinding<cereal::JSONInputArchive>(cereal::detail::InputBindingMap<cereal::JSONInputArchive>::Serializers cereal::polymorphic_detail::getInputBinding<cereal::JSONInputArchive>(cereal::JSONInputArchive&, unsigned int)::{lambda(void*, std::unique_ptr<void, cereal::detail::EmptyDeleter<void> >&)#2}*&, unsigned int)::{lambda(void*, std::unique_ptr<void, cereal::detail::EmptyDeleter<void> >&)#2}*>()
+cereal::polymorphic_detail::getInputBinding<cereal::JSONInputArchive>(cereal::JSONInputArchive&, unsigned int)::{lambda(void*, std::unique_ptr<void, cereal::detail::EmptyDeleter<void> >&)#2}*& std::_Any_data::_M_access<cereal::polymorphic_detail::getInputBinding<cereal::JSONInputArchive>(cereal::polymorphic_detail::getInputBinding<cereal::JSONInputArchive>(cereal::JSONInputArchive&, unsigned int)::{lambda(void*, std::unique_ptr<void, cereal::detail::EmptyDeleter<void> >&)#2}*&, unsigned int)::{lambda(void*, std::unique_ptr<void, cereal::detail::EmptyDeleter<void> >&)#2}*>()
# https://sourceware.org/bugzilla/show_bug.cgi?id=16845#c2
--format=gnu-v3
_ZNSt9_Any_data9_M_accessIPZ4postISt8functionIFvvEEEvOT_EUlvE_EERS5_v
-void post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<void post<std::function<void ()> >(void post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
+post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*& std::_Any_data::_M_access<post<std::function<void ()> >(post<std::function<void ()> >(std::function<void ()>&&)::{lambda()#1}*&&)::{lambda()#1}*>()
#
--format=auto --no-params
_Z3xxxDFyuVb
@@ -4525,7 +4525,7 @@ void function_temp<int>(A<sizeof ((int)(999))>)
#
--format=gnu-v3
_Z7ZipWithI7QStringS0_5QListZN4oral6detail16AdaptCreateTableI7AccountEES0_RKNS3_16CachedFieldsDataEEUlRKS0_SA_E_ET1_IDTclfp1_cvT__EcvT0__EEEERKT1_ISC_ERKT1_ISD_ET2_
-QList<decltype ({parm#3}((QString)(), (QString)()))> ZipWith<QString, QString, QList, QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1}>(QList<QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1}> const&, QList<QList> const&, QString oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1})
+QList<decltype ({parm#3}((QString)(), (QString)()))> ZipWith<QString, QString, QList, oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1}>(QList<oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1}> const&, QList<QList> const&, oral::detail::AdaptCreateTable<Account>(oral::detail::CachedFieldsData const&)::{lambda(QString const&, QString const&)#1})
#
# These three are symbols generated by g++'s testsuite, which triggered the same bug as above.
--format=gnu-v3
@@ -4665,7 +4665,7 @@ _Z3eatIPiZ3FoovEUlPT_PT0_E4_EvRS1_RS3_
void eat<int*, Foo()::{lambda(auto:1*, auto:2*)#6}>(int*&, Foo()::{lambda(auto:1*, auto:2*)#6}&)
_Z3eatIPiZ3BarIsEvvEUlPsPT_PT0_E0_EvRS3_RS5_
-void eat<int*, void Bar<short>()::{lambda(short*, auto:1*, auto:2*)#2}>(int*&, void Bar<short>()::{lambda(short*, auto:1*, auto:2*)#2}&)
+void eat<int*, Bar<short>()::{lambda(short*, auto:1*, auto:2*)#2}>(int*&, Bar<short>()::{lambda(short*, auto:1*, auto:2*)#2}&)
# PR 77489
_ZZ3foovE8localVar_9
@@ -4739,14 +4739,28 @@ __thunk_4294967297__$_1x
# demangler/82195 members of lambdas
--no-params
_ZZZ3FoovENKUlT_E_clIiEEfS_EN5Local2fnEv
-Foo()::float {lambda(auto:1)#1}::operator()<int>(int) const::Local::fn()
-Foo()::float {lambda(auto:1)#1}::operator()<int>(int) const::Local::fn
+Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::Local::fn()
+Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::Local::fn
--no-params
_Z7CaptureIZZ3FoovENKUlT_E_clIiEEvS0_EUlvE_EvOS0_
-void Capture<Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>(Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}&&)
-Capture<Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>
+void Capture<Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>(Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}&&)
+Capture<Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>
--no-params
_Z4FrobIZZ3FoovENKUlT_E_clIiEEvS0_EUlvE_Evv
-void Frob<Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>()
-Frob<Foo()::void {lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>
-#
+void Frob<Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>()
+Frob<Foo()::{lambda(auto:1)#1}::operator()<int>(int) const::{lambda()#1}>
+# A lambda {local-class::member-fn}
+--no-params
+_ZZ3FoovENKUlT_E_clIiEEfS_
+float Foo()::{lambda(auto:1)#1}::operator()<int>(int) const
+Foo()::{lambda(auto:1)#1}::operator()<int>
+# template-fn {local-class::member-fn}
+--no-params
+_ZZ3FooIiEfvEN1X2fnEv
+Foo<int>()::X::fn()
+Foo<int>()::X::fn
+# template-fn generic-lambda local-class::member-fn
+--no-params
+_ZZZ3FooIiEfvENKUlT_E_clIcEEDaS0_EN1X2fnEv
+Foo<int>()::{lambda(auto:1)#1}::operator()<char>(char) const::X::fn()
+Foo<int>()::{lambda(auto:1)#1}::operator()<char>(char) const::X::fn
diff --git a/libsanitizer/ChangeLog b/libsanitizer/ChangeLog
index 5c20f7d..63e7131 100644
--- a/libsanitizer/ChangeLog
+++ b/libsanitizer/ChangeLog
@@ -1,3 +1,49 @@
+2017-10-20 Jakub Jelinek <jakub@redhat.com>
+
+ PR sanitizer/82595
+ * lsan/lsan.h (__lsan_init): Add SANITIZER_INTERFACE_ATTRIBUTE.
+ * lsan/Makefile.am (nodist_toolexeclib_HEADERS): Add
+ liblsan_preinit.o.
+ (lsan_files): Remove lsan_preinit.cc.
+ (liblsan_preinit.o): New rule.
+ * lsan/Makefile.in: Regenerated.
+
+2017-10-19 Jakub Jelinek <jakub@redhat.com>
+
+ * All source files: Merge from upstream 315899.
+ * asan/Makefile.am (nodist_saninclude_HEADERS): Add
+ include/sanitizer/tsan_interface.h.
+ * asan/libtool-version: Bump the libasan SONAME.
+ * lsan/Makefile.am (sanitizer_lsan_files): Add lsan_common_mac.cc.
+ (lsan_files): Add lsan_linux.cc, lsan_mac.cc and lsan_malloc_mac.cc.
+ * sanitizer_common/Makefile.am (sanitizer_common_files): Add
+ sancov_flags.cc, sanitizer_allocator_checks.cc,
+ sanitizer_coverage_libcdep_new.cc, sanitizer_errno.cc,
+ sanitizer_file.cc, sanitizer_mac_libcdep.cc and
+ sanitizer_stoptheworld_mac.cc. Remove sanitizer_coverage_libcdep.cc
+ and sanitizer_coverage_mapping_libcdep.cc.
+ * tsan/Makefile.am (tsan_files): Add tsan_external.cc.
+ * ubsan/Makefile.am (DEFS): Add -DUBSAN_CAN_USE_CXXABI=1.
+ (ubsan_files): Add ubsan_init_standalone.cc and
+ ubsan_signals_standalone.cc.
+ * ubsan/libtool-version: Bump the libubsan SONAME.
+ * asan/Makefile.in: Regenerate.
+ * lsan/Makefile.in: Regenerate.
+ * sanitizer_common/Makefile.in: Regenerate.
+ * tsan/Makefile.in: Regenerate.
+ * ubsan/Makefile.in: Regenerate.
+
+2017-10-05 H.J. Lu <hongjiu.lu@intel.com>
+
+ PR sanitizer/82379
+ * configure.tgt (SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS): Set
+ to sanitizer_linux_x86_64.lo if __x86_64__ is defined by $CC.
+
+2017-10-02 Jakub Jelinek <jakub@redhat.com>
+
+ * libbacktrace/backtrace-rename.h (backtrace_uncompress_zdebug):
+ Define.
+
2017-08-07 Jakub Jelinek <jakub@redhat.com>
* include/system/sys/ptrace.h: New file.
diff --git a/libsanitizer/MERGE b/libsanitizer/MERGE
index 21c2f39..c92f8264 100644
--- a/libsanitizer/MERGE
+++ b/libsanitizer/MERGE
@@ -1,4 +1,4 @@
-285547
+315899
The first line of this file holds the svn revision number of the
last merge done from the master library sources.
diff --git a/libsanitizer/Makefile.am b/libsanitizer/Makefile.am
index 6afb2b0..018f0b0 100644
--- a/libsanitizer/Makefile.am
+++ b/libsanitizer/Makefile.am
@@ -17,7 +17,8 @@ endif
SUBDIRS += lsan asan ubsan
nodist_saninclude_HEADERS += \
include/sanitizer/lsan_interface.h \
- include/sanitizer/asan_interface.h
+ include/sanitizer/asan_interface.h \
+ include/sanitizer/tsan_interface.h
if TSAN_SUPPORTED
SUBDIRS += tsan
endif
diff --git a/libsanitizer/Makefile.in b/libsanitizer/Makefile.in
index 1f4bb8c..fd0f7fd 100644
--- a/libsanitizer/Makefile.in
+++ b/libsanitizer/Makefile.in
@@ -54,7 +54,8 @@ host_triplet = @host@
target_triplet = @target@
@SANITIZER_SUPPORTED_TRUE@am__append_1 = include/sanitizer/common_interface_defs.h \
@SANITIZER_SUPPORTED_TRUE@ include/sanitizer/lsan_interface.h \
-@SANITIZER_SUPPORTED_TRUE@ include/sanitizer/asan_interface.h
+@SANITIZER_SUPPORTED_TRUE@ include/sanitizer/asan_interface.h \
+@SANITIZER_SUPPORTED_TRUE@ include/sanitizer/tsan_interface.h
@SANITIZER_SUPPORTED_TRUE@@USING_MAC_INTERPOSE_FALSE@am__append_2 = interception
@LIBBACKTRACE_SUPPORTED_TRUE@@SANITIZER_SUPPORTED_TRUE@am__append_3 = libbacktrace
@SANITIZER_SUPPORTED_TRUE@@TSAN_SUPPORTED_TRUE@am__append_4 = tsan
diff --git a/libsanitizer/asan/Makefile.am b/libsanitizer/asan/Makefile.am
index 43377a9..709b6c8 100644
--- a/libsanitizer/asan/Makefile.am
+++ b/libsanitizer/asan/Makefile.am
@@ -25,6 +25,7 @@ asan_files = \
asan_flags.cc \
asan_globals.cc \
asan_interceptors.cc \
+ asan_interceptors_memintrinsics.cc \
asan_linux.cc \
asan_mac.cc \
asan_malloc_linux.cc \
@@ -36,6 +37,7 @@ asan_files = \
asan_posix.cc \
asan_report.cc \
asan_rtl.cc \
+ asan_shadow_setup.cc \
asan_stack.cc \
asan_stats.cc \
asan_suppressions.cc \
diff --git a/libsanitizer/asan/Makefile.in b/libsanitizer/asan/Makefile.in
index 4dad60b..db3c3ce 100644
--- a/libsanitizer/asan/Makefile.in
+++ b/libsanitizer/asan/Makefile.in
@@ -114,12 +114,13 @@ libasan_la_DEPENDENCIES = \
am__objects_1 = asan_activation.lo asan_allocator.lo asan_debugging.lo \
asan_descriptions.lo asan_errors.lo asan_fake_stack.lo \
asan_flags.lo asan_globals.lo asan_interceptors.lo \
- asan_linux.lo asan_mac.lo asan_malloc_linux.lo \
- asan_malloc_mac.lo asan_malloc_win.lo asan_memory_profile.lo \
- asan_new_delete.lo asan_poisoning.lo asan_posix.lo \
- asan_report.lo asan_rtl.lo asan_stack.lo asan_stats.lo \
- asan_suppressions.lo asan_thread.lo asan_win.lo \
- asan_win_dll_thunk.lo asan_win_dynamic_runtime_thunk.lo
+ asan_interceptors_memintrinsics.lo asan_linux.lo asan_mac.lo \
+ asan_malloc_linux.lo asan_malloc_mac.lo asan_malloc_win.lo \
+ asan_memory_profile.lo asan_new_delete.lo asan_poisoning.lo \
+ asan_posix.lo asan_report.lo asan_rtl.lo asan_shadow_setup.lo \
+ asan_stack.lo asan_stats.lo asan_suppressions.lo \
+ asan_thread.lo asan_win.lo asan_win_dll_thunk.lo \
+ asan_win_dynamic_runtime_thunk.lo
am_libasan_la_OBJECTS = $(am__objects_1)
libasan_la_OBJECTS = $(am_libasan_la_OBJECTS)
libasan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -317,6 +318,7 @@ asan_files = \
asan_flags.cc \
asan_globals.cc \
asan_interceptors.cc \
+ asan_interceptors_memintrinsics.cc \
asan_linux.cc \
asan_mac.cc \
asan_malloc_linux.cc \
@@ -328,6 +330,7 @@ asan_files = \
asan_posix.cc \
asan_report.cc \
asan_rtl.cc \
+ asan_shadow_setup.cc \
asan_stack.cc \
asan_stats.cc \
asan_suppressions.cc \
@@ -466,6 +469,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_flags.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_globals.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_interceptors.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_interceptors_memintrinsics.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_malloc_linux.Plo@am__quote@
@@ -477,6 +481,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_posix.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_report.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_rtl.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_shadow_setup.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stack.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_stats.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/asan_suppressions.Plo@am__quote@
diff --git a/libsanitizer/asan/asan_activation.cc b/libsanitizer/asan/asan_activation.cc
index ecd767c..599e56b 100644
--- a/libsanitizer/asan/asan_activation.cc
+++ b/libsanitizer/asan/asan_activation.cc
@@ -75,13 +75,16 @@ static struct AsanDeactivatedFlags {
void Print() {
Report(
- "quarantine_size_mb %d, max_redzone %d, poison_heap %d, "
- "malloc_context_size %d, alloc_dealloc_mismatch %d, "
- "allocator_may_return_null %d, coverage %d, coverage_dir %s\n",
- allocator_options.quarantine_size_mb, allocator_options.max_redzone,
- poison_heap, malloc_context_size,
+ "quarantine_size_mb %d, thread_local_quarantine_size_kb %d, "
+ "max_redzone %d, poison_heap %d, malloc_context_size %d, "
+ "alloc_dealloc_mismatch %d, allocator_may_return_null %d, coverage %d, "
+ "coverage_dir %s, allocator_release_to_os_interval_ms %d\n",
+ allocator_options.quarantine_size_mb,
+ allocator_options.thread_local_quarantine_size_kb,
+ allocator_options.max_redzone, poison_heap, malloc_context_size,
allocator_options.alloc_dealloc_mismatch,
- allocator_options.may_return_null, coverage, coverage_dir);
+ allocator_options.may_return_null, coverage, coverage_dir,
+ allocator_options.release_to_os_interval_ms);
}
} asan_deactivated_flags;
@@ -101,10 +104,10 @@ void AsanDeactivate() {
// Deactivate the runtime.
SetCanPoisonMemory(false);
SetMallocContextSize(1);
- ReInitializeCoverage(false, nullptr);
AllocatorOptions disabled = asan_deactivated_flags.allocator_options;
disabled.quarantine_size_mb = 0;
+ disabled.thread_local_quarantine_size_kb = 0;
disabled.min_redzone = 16; // Redzone must be at least 16 bytes long.
disabled.max_redzone = 16;
disabled.alloc_dealloc_mismatch = false;
@@ -124,8 +127,6 @@ void AsanActivate() {
SetCanPoisonMemory(asan_deactivated_flags.poison_heap);
SetMallocContextSize(asan_deactivated_flags.malloc_context_size);
- ReInitializeCoverage(asan_deactivated_flags.coverage,
- asan_deactivated_flags.coverage_dir);
ReInitializeAllocator(asan_deactivated_flags.allocator_options);
asan_is_deactivated = false;
diff --git a/libsanitizer/asan/asan_activation_flags.inc b/libsanitizer/asan/asan_activation_flags.inc
index 4bab382..e71abb9 100644
--- a/libsanitizer/asan/asan_activation_flags.inc
+++ b/libsanitizer/asan/asan_activation_flags.inc
@@ -22,6 +22,7 @@
ASAN_ACTIVATION_FLAG(int, redzone)
ASAN_ACTIVATION_FLAG(int, max_redzone)
ASAN_ACTIVATION_FLAG(int, quarantine_size_mb)
+ASAN_ACTIVATION_FLAG(int, thread_local_quarantine_size_kb)
ASAN_ACTIVATION_FLAG(bool, alloc_dealloc_mismatch)
ASAN_ACTIVATION_FLAG(bool, poison_heap)
@@ -31,3 +32,4 @@ COMMON_ACTIVATION_FLAG(bool, coverage)
COMMON_ACTIVATION_FLAG(const char *, coverage_dir)
COMMON_ACTIVATION_FLAG(int, verbosity)
COMMON_ACTIVATION_FLAG(bool, help)
+COMMON_ACTIVATION_FLAG(s32, allocator_release_to_os_interval_ms)
diff --git a/libsanitizer/asan/asan_allocator.cc b/libsanitizer/asan/asan_allocator.cc
index d3ddb90..1b46546 100644
--- a/libsanitizer/asan/asan_allocator.cc
+++ b/libsanitizer/asan/asan_allocator.cc
@@ -19,7 +19,9 @@
#include "asan_report.h"
#include "asan_stack.h"
#include "asan_thread.h"
+#include "sanitizer_common/sanitizer_allocator_checks.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_list.h"
@@ -158,7 +160,11 @@ struct QuarantineCallback {
}
void *Allocate(uptr size) {
- return get_allocator().Allocate(cache_, size, 1, false);
+ void *res = get_allocator().Allocate(cache_, size, 1);
+ // TODO(alekseys): Consider making quarantine OOM-friendly.
+ if (UNLIKELY(!res))
+ return DieOnFailure::OnOOM();
+ return res;
}
void Deallocate(void *p) {
@@ -205,25 +211,27 @@ QuarantineCache *GetQuarantineCache(AsanThreadLocalMallocStorage *ms) {
void AllocatorOptions::SetFrom(const Flags *f, const CommonFlags *cf) {
quarantine_size_mb = f->quarantine_size_mb;
+ thread_local_quarantine_size_kb = f->thread_local_quarantine_size_kb;
min_redzone = f->redzone;
max_redzone = f->max_redzone;
may_return_null = cf->allocator_may_return_null;
alloc_dealloc_mismatch = f->alloc_dealloc_mismatch;
+ release_to_os_interval_ms = cf->allocator_release_to_os_interval_ms;
}
void AllocatorOptions::CopyTo(Flags *f, CommonFlags *cf) {
f->quarantine_size_mb = quarantine_size_mb;
+ f->thread_local_quarantine_size_kb = thread_local_quarantine_size_kb;
f->redzone = min_redzone;
f->max_redzone = max_redzone;
cf->allocator_may_return_null = may_return_null;
f->alloc_dealloc_mismatch = alloc_dealloc_mismatch;
+ cf->allocator_release_to_os_interval_ms = release_to_os_interval_ms;
}
struct Allocator {
static const uptr kMaxAllowedMallocSize =
FIRST_32_SECOND_64(3UL << 30, 1ULL << 40);
- static const uptr kMaxThreadLocalQuarantine =
- FIRST_32_SECOND_64(1 << 18, 1 << 20);
AsanAllocator allocator;
AsanQuarantine quarantine;
@@ -231,6 +239,8 @@ struct Allocator {
AllocatorCache fallback_allocator_cache;
QuarantineCache fallback_quarantine_cache;
+ atomic_uint8_t rss_limit_exceeded;
+
// ------------------- Options --------------------------
atomic_uint16_t min_redzone;
atomic_uint16_t max_redzone;
@@ -252,7 +262,7 @@ struct Allocator {
void SharedInitCode(const AllocatorOptions &options) {
CheckOptions(options);
quarantine.Init((uptr)options.quarantine_size_mb << 20,
- kMaxThreadLocalQuarantine);
+ (uptr)options.thread_local_quarantine_size_kb << 10);
atomic_store(&alloc_dealloc_mismatch, options.alloc_dealloc_mismatch,
memory_order_release);
atomic_store(&min_redzone, options.min_redzone, memory_order_release);
@@ -260,35 +270,45 @@ struct Allocator {
}
void Initialize(const AllocatorOptions &options) {
- allocator.Init(options.may_return_null);
+ SetAllocatorMayReturnNull(options.may_return_null);
+ allocator.Init(options.release_to_os_interval_ms);
SharedInitCode(options);
}
+ bool RssLimitExceeded() {
+ return atomic_load(&rss_limit_exceeded, memory_order_relaxed);
+ }
+
+ void SetRssLimitExceeded(bool limit_exceeded) {
+ atomic_store(&rss_limit_exceeded, limit_exceeded, memory_order_relaxed);
+ }
+
void RePoisonChunk(uptr chunk) {
- // This could a user-facing chunk (with redzones), or some internal
+ // This could be a user-facing chunk (with redzones), or some internal
// housekeeping chunk, like TransferBatch. Start by assuming the former.
AsanChunk *ac = GetAsanChunk((void *)chunk);
uptr allocated_size = allocator.GetActuallyAllocatedSize((void *)ac);
uptr beg = ac->Beg();
uptr end = ac->Beg() + ac->UsedSize(true);
uptr chunk_end = chunk + allocated_size;
- if (chunk < beg && beg < end && end <= chunk_end) {
- // Looks like a valid AsanChunk. Or maybe not. Be conservative and only
- // poison the redzones.
+ if (chunk < beg && beg < end && end <= chunk_end &&
+ ac->chunk_state == CHUNK_ALLOCATED) {
+ // Looks like a valid AsanChunk in use, poison redzones only.
PoisonShadow(chunk, beg - chunk, kAsanHeapLeftRedzoneMagic);
uptr end_aligned_down = RoundDownTo(end, SHADOW_GRANULARITY);
FastPoisonShadowPartialRightRedzone(
end_aligned_down, end - end_aligned_down,
chunk_end - end_aligned_down, kAsanHeapLeftRedzoneMagic);
} else {
- // This can not be an AsanChunk. Poison everything. It may be reused as
- // AsanChunk later.
+ // This is either not an AsanChunk or freed or quarantined AsanChunk.
+ // In either case, poison everything.
PoisonShadow(chunk, allocated_size, kAsanHeapLeftRedzoneMagic);
}
}
void ReInitialize(const AllocatorOptions &options) {
- allocator.SetMayReturnNull(options.may_return_null);
+ SetAllocatorMayReturnNull(options.may_return_null);
+ allocator.SetReleaseToOSIntervalMs(options.release_to_os_interval_ms);
SharedInitCode(options);
// Poison all existing allocation's redzones.
@@ -305,11 +325,13 @@ struct Allocator {
void GetOptions(AllocatorOptions *options) const {
options->quarantine_size_mb = quarantine.GetSize() >> 20;
+ options->thread_local_quarantine_size_kb = quarantine.GetCacheSize() >> 10;
options->min_redzone = atomic_load(&min_redzone, memory_order_acquire);
options->max_redzone = atomic_load(&max_redzone, memory_order_acquire);
- options->may_return_null = allocator.MayReturnNull();
+ options->may_return_null = AllocatorMayReturnNull();
options->alloc_dealloc_mismatch =
atomic_load(&alloc_dealloc_mismatch, memory_order_acquire);
+ options->release_to_os_interval_ms = allocator.ReleaseToOSIntervalMs();
}
// -------------------- Helper methods. -------------------------
@@ -356,6 +378,8 @@ struct Allocator {
AllocType alloc_type, bool can_fill) {
if (UNLIKELY(!asan_inited))
AsanInitFromRtl();
+ if (RssLimitExceeded())
+ return AsanAllocator::FailureHandler::OnOOM();
Flags &fl = *flags();
CHECK(stack);
const uptr min_alignment = SHADOW_GRANULARITY;
@@ -388,24 +412,21 @@ struct Allocator {
if (size > kMaxAllowedMallocSize || needed_size > kMaxAllowedMallocSize) {
Report("WARNING: AddressSanitizer failed to allocate 0x%zx bytes\n",
(void*)size);
- return allocator.ReturnNullOrDieOnBadRequest();
+ return AsanAllocator::FailureHandler::OnBadRequest();
}
AsanThread *t = GetCurrentThread();
void *allocated;
- bool check_rss_limit = true;
if (t) {
AllocatorCache *cache = GetAllocatorCache(&t->malloc_storage());
- allocated =
- allocator.Allocate(cache, needed_size, 8, false, check_rss_limit);
+ allocated = allocator.Allocate(cache, needed_size, 8);
} else {
SpinMutexLock l(&fallback_mutex);
AllocatorCache *cache = &fallback_allocator_cache;
- allocated =
- allocator.Allocate(cache, needed_size, 8, false, check_rss_limit);
+ allocated = allocator.Allocate(cache, needed_size, 8);
}
-
- if (!allocated) return allocator.ReturnNullOrDieOnOOM();
+ if (!allocated)
+ return nullptr;
if (*(u8 *)MEM_TO_SHADOW((uptr)allocated) == 0 && CanPoisonMemory()) {
// Heap poisoning is enabled, but the allocator provides an unpoisoned
@@ -507,8 +528,7 @@ struct Allocator {
// Expects the chunk to already be marked as quarantined by using
// AtomicallySetQuarantineFlagIfAllocated.
- void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack,
- AllocType alloc_type) {
+ void QuarantineChunk(AsanChunk *m, void *ptr, BufferedStackTrace *stack) {
CHECK_EQ(m->chunk_state, CHUNK_QUARANTINE);
CHECK_GE(m->alloc_tid, 0);
if (SANITIZER_WORDSIZE == 64) // On 32-bits this resides in user area.
@@ -516,6 +536,18 @@ struct Allocator {
AsanThread *t = GetCurrentThread();
m->free_tid = t ? t->tid() : 0;
m->free_context_id = StackDepotPut(*stack);
+
+ Flags &fl = *flags();
+ if (fl.max_free_fill_size > 0) {
+ // We have to skip the chunk header, it contains free_context_id.
+ uptr scribble_start = (uptr)m + kChunkHeaderSize + kChunkHeader2Size;
+ if (m->UsedSize() >= kChunkHeader2Size) { // Skip Header2 in user area.
+ uptr size_to_fill = m->UsedSize() - kChunkHeader2Size;
+ size_to_fill = Min(size_to_fill, (uptr)fl.max_free_fill_size);
+ REAL(memset)((void *)scribble_start, fl.free_fill_byte, size_to_fill);
+ }
+ }
+
// Poison the region.
PoisonShadow(m->Beg(),
RoundUpTo(m->UsedSize(), SHADOW_GRANULARITY),
@@ -547,7 +579,17 @@ struct Allocator {
uptr chunk_beg = p - kChunkHeaderSize;
AsanChunk *m = reinterpret_cast<AsanChunk *>(chunk_beg);
+ // On Windows, uninstrumented DLLs may allocate memory before ASan hooks
+ // malloc. Don't report an invalid free in this case.
+ if (SANITIZER_WINDOWS &&
+ !get_allocator().PointerIsMine(ptr)) {
+ if (!IsSystemHeapAddress(p))
+ ReportFreeNotMalloced(p, stack);
+ return;
+ }
+
ASAN_FREE_HOOK(ptr);
+
// Must mark the chunk as quarantined before any changes to its metadata.
// Do not quarantine given chunk if we failed to set CHUNK_QUARANTINE flag.
if (!AtomicallySetQuarantineFlagIfAllocated(m, ptr, stack)) return;
@@ -564,7 +606,7 @@ struct Allocator {
ReportNewDeleteSizeMismatch(p, delete_size, stack);
}
- QuarantineChunk(m, ptr, stack, alloc_type);
+ QuarantineChunk(m, ptr, stack);
}
void *Reallocate(void *old_ptr, uptr new_size, BufferedStackTrace *stack) {
@@ -593,8 +635,8 @@ struct Allocator {
}
void *Calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
- if (CallocShouldReturnNullDueToOverflow(size, nmemb))
- return allocator.ReturnNullOrDieOnBadRequest();
+ if (CheckForCallocOverflow(size, nmemb))
+ return AsanAllocator::FailureHandler::OnBadRequest();
void *ptr = Allocate(nmemb * size, 8, stack, FROM_MALLOC, false);
// If the memory comes from the secondary allocator no need to clear it
// as it comes directly from mmap.
@@ -674,6 +716,7 @@ struct Allocator {
void PrintStats() {
allocator.PrintStats();
+ quarantine.PrintStats();
}
void ForceLock() {
@@ -685,8 +728,6 @@ struct Allocator {
fallback_mutex.Unlock();
allocator.ForceUnlock();
}
-
- void ReleaseToOS() { allocator.ReleaseToOS(); }
};
static Allocator instance(LINKER_INITIALIZED);
@@ -695,18 +736,21 @@ static AsanAllocator &get_allocator() {
return instance.allocator;
}
-bool AsanChunkView::IsValid() {
+bool AsanChunkView::IsValid() const {
return chunk_ && chunk_->chunk_state != CHUNK_AVAILABLE;
}
-bool AsanChunkView::IsAllocated() {
+bool AsanChunkView::IsAllocated() const {
return chunk_ && chunk_->chunk_state == CHUNK_ALLOCATED;
}
-uptr AsanChunkView::Beg() { return chunk_->Beg(); }
-uptr AsanChunkView::End() { return Beg() + UsedSize(); }
-uptr AsanChunkView::UsedSize() { return chunk_->UsedSize(); }
-uptr AsanChunkView::AllocTid() { return chunk_->alloc_tid; }
-uptr AsanChunkView::FreeTid() { return chunk_->free_tid; }
-AllocType AsanChunkView::GetAllocType() {
+bool AsanChunkView::IsQuarantined() const {
+ return chunk_ && chunk_->chunk_state == CHUNK_QUARANTINE;
+}
+uptr AsanChunkView::Beg() const { return chunk_->Beg(); }
+uptr AsanChunkView::End() const { return Beg() + UsedSize(); }
+uptr AsanChunkView::UsedSize() const { return chunk_->UsedSize(); }
+uptr AsanChunkView::AllocTid() const { return chunk_->alloc_tid; }
+uptr AsanChunkView::FreeTid() const { return chunk_->free_tid; }
+AllocType AsanChunkView::GetAllocType() const {
return (AllocType)chunk_->alloc_type;
}
@@ -717,22 +761,19 @@ static StackTrace GetStackTraceFromId(u32 id) {
return res;
}
-u32 AsanChunkView::GetAllocStackId() { return chunk_->alloc_context_id; }
-u32 AsanChunkView::GetFreeStackId() { return chunk_->free_context_id; }
+u32 AsanChunkView::GetAllocStackId() const { return chunk_->alloc_context_id; }
+u32 AsanChunkView::GetFreeStackId() const { return chunk_->free_context_id; }
-StackTrace AsanChunkView::GetAllocStack() {
+StackTrace AsanChunkView::GetAllocStack() const {
return GetStackTraceFromId(GetAllocStackId());
}
-StackTrace AsanChunkView::GetFreeStack() {
+StackTrace AsanChunkView::GetFreeStack() const {
return GetStackTraceFromId(GetFreeStackId());
}
-void ReleaseToOS() { instance.ReleaseToOS(); }
-
void InitializeAllocator(const AllocatorOptions &options) {
instance.Initialize(options);
- SetAllocatorReleaseToOSCallback(ReleaseToOS);
}
void ReInitializeAllocator(const AllocatorOptions &options) {
@@ -758,11 +799,6 @@ void PrintInternalAllocatorStats() {
instance.PrintStats();
}
-void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
- AllocType alloc_type) {
- return instance.Allocate(size, alignment, stack, alloc_type, true);
-}
-
void asan_free(void *ptr, BufferedStackTrace *stack, AllocType alloc_type) {
instance.Deallocate(ptr, 0, stack, alloc_type);
}
@@ -773,40 +809,63 @@ void asan_sized_free(void *ptr, uptr size, BufferedStackTrace *stack,
}
void *asan_malloc(uptr size, BufferedStackTrace *stack) {
- return instance.Allocate(size, 8, stack, FROM_MALLOC, true);
+ return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true));
}
void *asan_calloc(uptr nmemb, uptr size, BufferedStackTrace *stack) {
- return instance.Calloc(nmemb, size, stack);
+ return SetErrnoOnNull(instance.Calloc(nmemb, size, stack));
}
void *asan_realloc(void *p, uptr size, BufferedStackTrace *stack) {
if (!p)
- return instance.Allocate(size, 8, stack, FROM_MALLOC, true);
+ return SetErrnoOnNull(instance.Allocate(size, 8, stack, FROM_MALLOC, true));
if (size == 0) {
- instance.Deallocate(p, 0, stack, FROM_MALLOC);
- return nullptr;
+ if (flags()->allocator_frees_and_returns_null_on_realloc_zero) {
+ instance.Deallocate(p, 0, stack, FROM_MALLOC);
+ return nullptr;
+ }
+ // Allocate a size of 1 if we shouldn't free() on Realloc to 0
+ size = 1;
}
- return instance.Reallocate(p, size, stack);
+ return SetErrnoOnNull(instance.Reallocate(p, size, stack));
}
void *asan_valloc(uptr size, BufferedStackTrace *stack) {
- return instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true);
+ return SetErrnoOnNull(
+ instance.Allocate(size, GetPageSizeCached(), stack, FROM_MALLOC, true));
}
void *asan_pvalloc(uptr size, BufferedStackTrace *stack) {
uptr PageSize = GetPageSizeCached();
- size = RoundUpTo(size, PageSize);
- if (size == 0) {
- // pvalloc(0) should allocate one page.
- size = PageSize;
+ if (UNLIKELY(CheckForPvallocOverflow(size, PageSize))) {
+ errno = errno_ENOMEM;
+ return AsanAllocator::FailureHandler::OnBadRequest();
}
- return instance.Allocate(size, PageSize, stack, FROM_MALLOC, true);
+ // pvalloc(0) should allocate one page.
+ size = size ? RoundUpTo(size, PageSize) : PageSize;
+ return SetErrnoOnNull(
+ instance.Allocate(size, PageSize, stack, FROM_MALLOC, true));
+}
+
+void *asan_memalign(uptr alignment, uptr size, BufferedStackTrace *stack,
+ AllocType alloc_type) {
+ if (UNLIKELY(!IsPowerOfTwo(alignment))) {
+ errno = errno_EINVAL;
+ return AsanAllocator::FailureHandler::OnBadRequest();
+ }
+ return SetErrnoOnNull(
+ instance.Allocate(size, alignment, stack, alloc_type, true));
}
int asan_posix_memalign(void **memptr, uptr alignment, uptr size,
BufferedStackTrace *stack) {
+ if (UNLIKELY(!CheckPosixMemalignAlignment(alignment))) {
+ AsanAllocator::FailureHandler::OnBadRequest();
+ return errno_EINVAL;
+ }
void *ptr = instance.Allocate(size, alignment, stack, FROM_MALLOC, true);
+ if (UNLIKELY(!ptr))
+ return errno_ENOMEM;
CHECK(IsAligned((uptr)ptr, alignment));
*memptr = ptr;
return 0;
@@ -834,8 +893,8 @@ void asan_mz_force_unlock() {
instance.ForceUnlock();
}
-void AsanSoftRssLimitExceededCallback(bool exceeded) {
- instance.allocator.SetRssLimitIsExceeded(exceeded);
+void AsanSoftRssLimitExceededCallback(bool limit_exceeded) {
+ instance.SetRssLimitExceeded(limit_exceeded);
}
} // namespace __asan
@@ -952,15 +1011,13 @@ uptr __sanitizer_get_allocated_size(const void *p) {
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default (no-op) implementation of malloc hooks.
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_malloc_hook(void *ptr, uptr size) {
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_malloc_hook,
+ void *ptr, uptr size) {
(void)ptr;
(void)size;
}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_free_hook(void *ptr) {
+
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_free_hook, void *ptr) {
(void)ptr;
}
-} // extern "C"
#endif
diff --git a/libsanitizer/asan/asan_allocator.h b/libsanitizer/asan/asan_allocator.h
index 7eeddad..63260ff 100644
--- a/libsanitizer/asan/asan_allocator.h
+++ b/libsanitizer/asan/asan_allocator.h
@@ -31,10 +31,12 @@ struct AsanChunk;
struct AllocatorOptions {
u32 quarantine_size_mb;
+ u32 thread_local_quarantine_size_kb;
u16 min_redzone;
u16 max_redzone;
u8 may_return_null;
u8 alloc_dealloc_mismatch;
+ s32 release_to_os_interval_ms;
void SetFrom(const Flags *f, const CommonFlags *cf);
void CopyTo(Flags *f, CommonFlags *cf);
@@ -47,28 +49,29 @@ void GetAllocatorOptions(AllocatorOptions *options);
class AsanChunkView {
public:
explicit AsanChunkView(AsanChunk *chunk) : chunk_(chunk) {}
- bool IsValid(); // Checks if AsanChunkView points to a valid allocated
- // or quarantined chunk.
- bool IsAllocated(); // Checks if the memory is currently allocated.
- uptr Beg(); // First byte of user memory.
- uptr End(); // Last byte of user memory.
- uptr UsedSize(); // Size requested by the user.
- uptr AllocTid();
- uptr FreeTid();
+ bool IsValid() const; // Checks if AsanChunkView points to a valid
+ // allocated or quarantined chunk.
+ bool IsAllocated() const; // Checks if the memory is currently allocated.
+ bool IsQuarantined() const; // Checks if the memory is currently quarantined.
+ uptr Beg() const; // First byte of user memory.
+ uptr End() const; // Last byte of user memory.
+ uptr UsedSize() const; // Size requested by the user.
+ uptr AllocTid() const;
+ uptr FreeTid() const;
bool Eq(const AsanChunkView &c) const { return chunk_ == c.chunk_; }
- u32 GetAllocStackId();
- u32 GetFreeStackId();
- StackTrace GetAllocStack();
- StackTrace GetFreeStack();
- AllocType GetAllocType();
- bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) {
+ u32 GetAllocStackId() const;
+ u32 GetFreeStackId() const;
+ StackTrace GetAllocStack() const;
+ StackTrace GetFreeStack() const;
+ AllocType GetAllocType() const;
+ bool AddrIsInside(uptr addr, uptr access_size, sptr *offset) const {
if (addr >= Beg() && (addr + access_size) <= End()) {
*offset = addr - Beg();
return true;
}
return false;
}
- bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) {
+ bool AddrIsAtLeft(uptr addr, uptr access_size, sptr *offset) const {
(void)access_size;
if (addr < Beg()) {
*offset = Beg() - addr;
@@ -76,7 +79,7 @@ class AsanChunkView {
}
return false;
}
- bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) {
+ bool AddrIsAtRight(uptr addr, uptr access_size, sptr *offset) const {
if (addr + access_size > End()) {
*offset = addr - End();
return true;
@@ -114,7 +117,11 @@ struct AsanMapUnmapCallback {
};
#if SANITIZER_CAN_USE_ALLOCATOR64
-# if defined(__powerpc64__)
+# if SANITIZER_FUCHSIA
+const uptr kAllocatorSpace = ~(uptr)0;
+const uptr kAllocatorSize = 0x40000000000ULL; // 4T.
+typedef DefaultSizeClassMap SizeClassMap;
+# elif defined(__powerpc64__)
const uptr kAllocatorSpace = 0xa0000000000ULL;
const uptr kAllocatorSize = 0x20000000000ULL; // 2T.
typedef DefaultSizeClassMap SizeClassMap;
@@ -156,10 +163,17 @@ typedef FlatByteMap<kNumRegions> ByteMap;
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
# endif
typedef CompactSizeClassMap SizeClassMap;
-typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE, 16,
- SizeClassMap, kRegionSizeLog,
- ByteMap,
- AsanMapUnmapCallback> PrimaryAllocator;
+struct AP32 {
+ static const uptr kSpaceBeg = 0;
+ static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
+ static const uptr kMetadataSize = 16;
+ typedef __asan::SizeClassMap SizeClassMap;
+ static const uptr kRegionSizeLog = __asan::kRegionSizeLog;
+ typedef __asan::ByteMap ByteMap;
+ typedef AsanMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+typedef SizeClassAllocator32<AP32> PrimaryAllocator;
#endif // SANITIZER_CAN_USE_ALLOCATOR64
static const uptr kNumberOfSizeClasses = SizeClassMap::kNumClasses;
diff --git a/libsanitizer/asan/asan_descriptions.cc b/libsanitizer/asan/asan_descriptions.cc
index 35d1619..d46962a 100644
--- a/libsanitizer/asan/asan_descriptions.cc
+++ b/libsanitizer/asan/asan_descriptions.cc
@@ -148,7 +148,7 @@ static void PrintHeapChunkAccess(uptr addr, const ChunkAccess &descr) {
str.append(" %zu-byte region [%p,%p)\n", descr.chunk_size,
(void *)descr.chunk_begin,
(void *)(descr.chunk_begin + descr.chunk_size));
- str.append("%s", d.EndLocation());
+ str.append("%s", d.Default());
Printf("%s", str.data());
}
@@ -250,12 +250,15 @@ static void PrintAccessAndVarIntersection(const StackVarDescr &var, uptr addr,
str.append("%c", var.name_pos[i]);
}
str.append("'");
+ if (var.line > 0) {
+ str.append(" (line %d)", var.line);
+ }
if (pos_descr) {
Decorator d;
// FIXME: we may want to also print the size of the access here,
// but in case of accesses generated by memset it may be confusing.
str.append("%s <== Memory access at offset %zd %s this variable%s\n",
- d.Location(), addr, pos_descr, d.EndLocation());
+ d.Location(), addr, pos_descr, d.Default());
} else {
str.append("\n");
}
@@ -290,7 +293,7 @@ static void DescribeAddressRelativeToGlobal(uptr addr, uptr access_size,
MaybeDemangleGlobalName(g.name));
PrintGlobalLocation(&str, g);
str.append("' (0x%zx) of size %zu\n", g.beg, g.size);
- str.append("%s", d.EndLocation());
+ str.append("%s", d.Default());
PrintGlobalNameIfASCII(&str, g);
Printf("%s", str.data());
}
@@ -338,10 +341,10 @@ void StackAddressDescription::Print() const {
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
if (!frame_descr) {
- Printf("%s\n", d.EndLocation());
+ Printf("%s\n", d.Default());
return;
}
- Printf(" at offset %zu in frame%s\n", offset, d.EndLocation());
+ Printf(" at offset %zu in frame%s\n", offset, d.Default());
// Now we print the frame where the alloca has happened.
// We print this frame as a stack trace with one element.
@@ -350,7 +353,7 @@ void StackAddressDescription::Print() const {
// previously. That's unfortunate, but I have no better solution,
// especially given that the alloca may be from entirely different place
// (e.g. use-after-scope, or different thread's stack).
- Printf("%s", d.EndLocation());
+ Printf("%s", d.Default());
StackTrace alloca_stack(&frame_pc, 1);
alloca_stack.Print();
@@ -400,18 +403,18 @@ void HeapAddressDescription::Print() const {
Printf("%sfreed by thread T%d%s here:%s\n", d.Allocation(),
free_thread->tid,
ThreadNameWithParenthesis(free_thread, tname, sizeof(tname)),
- d.EndAllocation());
+ d.Default());
StackTrace free_stack = GetStackTraceFromId(free_stack_id);
free_stack.Print();
Printf("%spreviously allocated by thread T%d%s here:%s\n", d.Allocation(),
alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
- d.EndAllocation());
+ d.Default());
} else {
Printf("%sallocated by thread T%d%s here:%s\n", d.Allocation(),
alloc_thread->tid,
ThreadNameWithParenthesis(alloc_thread, tname, sizeof(tname)),
- d.EndAllocation());
+ d.Default());
}
alloc_stack.Print();
DescribeThread(GetCurrentThread());
diff --git a/libsanitizer/asan/asan_descriptions.h b/libsanitizer/asan/asan_descriptions.h
index 584b9ba..0fbb531 100644
--- a/libsanitizer/asan/asan_descriptions.h
+++ b/libsanitizer/asan/asan_descriptions.h
@@ -32,11 +32,8 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
public:
Decorator() : SanitizerCommonDecorator() {}
const char *Access() { return Blue(); }
- const char *EndAccess() { return Default(); }
const char *Location() { return Green(); }
- const char *EndLocation() { return Default(); }
const char *Allocation() { return Magenta(); }
- const char *EndAllocation() { return Default(); }
const char *ShadowByte(u8 byte) {
switch (byte) {
@@ -70,9 +67,6 @@ class Decorator : public __sanitizer::SanitizerCommonDecorator {
return Default();
}
}
- const char *EndShadowByte() { return Default(); }
- const char *MemoryByte() { return Magenta(); }
- const char *EndMemoryByte() { return Default(); }
};
enum ShadowKind : u8 {
diff --git a/libsanitizer/asan/asan_errors.cc b/libsanitizer/asan/asan_errors.cc
index 73c4cca..b469b16 100644
--- a/libsanitizer/asan/asan_errors.cc
+++ b/libsanitizer/asan/asan_errors.cc
@@ -20,64 +20,27 @@
namespace __asan {
-void ErrorStackOverflow::Print() {
- Decorator d;
- Printf("%s", d.Warning());
- Report(
- "ERROR: AddressSanitizer: stack-overflow on address %p"
- " (pc %p bp %p sp %p T%d)\n",
- (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid);
- Printf("%s", d.EndWarning());
- scariness.Print();
- BufferedStackTrace stack;
- GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
- common_flags()->fast_unwind_on_fatal);
- stack.Print();
- ReportErrorSummary("stack-overflow", &stack);
-}
-
-static void MaybeDumpInstructionBytes(uptr pc) {
- if (!flags()->dump_instruction_bytes || (pc < GetPageSizeCached())) return;
- InternalScopedString str(1024);
- str.append("First 16 instruction bytes at pc: ");
- if (IsAccessibleMemoryRange(pc, 16)) {
- for (int i = 0; i < 16; ++i) {
- PrintMemoryByte(&str, "", ((u8 *)pc)[i], /*in_shadow*/ false, " ");
- }
- str.append("\n");
- } else {
- str.append("unaccessible\n");
- }
- Report("%s", str.data());
+static void OnStackUnwind(const SignalContext &sig,
+ const void *callback_context,
+ BufferedStackTrace *stack) {
+ bool fast = common_flags()->fast_unwind_on_fatal;
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
+ // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
+ // yields the call stack of the signal's handler and not of the code
+ // that raised the signal (as it does on Linux).
+ fast = true;
+#endif
+ // Tests and maybe some users expect that scariness is going to be printed
+ // just before the stack. As only asan has scariness score we have no
+ // corresponding code in the sanitizer_common and we use this callback to
+ // print it.
+ static_cast<const ScarinessScoreBase *>(callback_context)->Print();
+ GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp,
+ sig.context, fast);
}
void ErrorDeadlySignal::Print() {
- Decorator d;
- Printf("%s", d.Warning());
- const char *description = DescribeSignalOrException(signo);
- Report(
- "ERROR: AddressSanitizer: %s on unknown address %p (pc %p bp %p sp %p "
- "T%d)\n",
- description, (void *)addr, (void *)pc, (void *)bp, (void *)sp, tid);
- Printf("%s", d.EndWarning());
- if (pc < GetPageSizeCached()) Report("Hint: pc points to the zero page.\n");
- if (is_memory_access) {
- const char *access_type =
- write_flag == SignalContext::WRITE
- ? "WRITE"
- : (write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
- Report("The signal is caused by a %s memory access.\n", access_type);
- if (addr < GetPageSizeCached())
- Report("Hint: address points to the zero page.\n");
- }
- scariness.Print();
- BufferedStackTrace stack;
- GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, context,
- common_flags()->fast_unwind_on_fatal);
- stack.Print();
- MaybeDumpInstructionBytes(pc);
- Printf("AddressSanitizer can not provide additional info.\n");
- ReportErrorSummary(description, &stack);
+ ReportDeadlySignal(signal, tid, &OnStackUnwind, &scariness);
}
void ErrorDoubleFree::Print() {
@@ -85,17 +48,17 @@ void ErrorDoubleFree::Print() {
Printf("%s", d.Warning());
char tname[128];
Report(
- "ERROR: AddressSanitizer: attempting double-free on %p in "
+ "ERROR: AddressSanitizer: attempting %s on %p in "
"thread T%d%s:\n",
- addr_description.addr, tid,
+ scariness.GetDescription(), addr_description.addr, tid,
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
scariness.Print();
GET_STACK_TRACE_FATAL(second_free_stack->trace[0],
second_free_stack->top_frame_bp);
stack.Print();
addr_description.Print();
- ReportErrorSummary("double-free", &stack);
+ ReportErrorSummary(scariness.GetDescription(), &stack);
}
void ErrorNewDeleteSizeMismatch::Print() {
@@ -103,11 +66,11 @@ void ErrorNewDeleteSizeMismatch::Print() {
Printf("%s", d.Warning());
char tname[128];
Report(
- "ERROR: AddressSanitizer: new-delete-type-mismatch on %p in thread "
+ "ERROR: AddressSanitizer: %s on %p in thread "
"T%d%s:\n",
- addr_description.addr, tid,
+ scariness.GetDescription(), addr_description.addr, tid,
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
- Printf("%s object passed to delete has wrong type:\n", d.EndWarning());
+ Printf("%s object passed to delete has wrong type:\n", d.Default());
Printf(
" size of the allocated type: %zd bytes;\n"
" size of the deallocated type: %zd bytes.\n",
@@ -117,7 +80,7 @@ void ErrorNewDeleteSizeMismatch::Print() {
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
stack.Print();
addr_description.Print();
- ReportErrorSummary("new-delete-type-mismatch", &stack);
+ ReportErrorSummary(scariness.GetDescription(), &stack);
Report(
"HINT: if you don't care about these errors you may set "
"ASAN_OPTIONS=new_delete_type_mismatch=0\n");
@@ -132,13 +95,13 @@ void ErrorFreeNotMalloced::Print() {
"which was not malloc()-ed: %p in thread T%d%s\n",
addr_description.Address(), tid,
ThreadNameWithParenthesis(tid, tname, sizeof(tname)));
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
CHECK_GT(free_stack->size, 0);
scariness.Print();
GET_STACK_TRACE_FATAL(free_stack->trace[0], free_stack->top_frame_bp);
stack.Print();
addr_description.Print();
- ReportErrorSummary("bad-free", &stack);
+ ReportErrorSummary(scariness.GetDescription(), &stack);
}
void ErrorAllocTypeMismatch::Print() {
@@ -149,16 +112,17 @@ void ErrorAllocTypeMismatch::Print() {
CHECK_NE(alloc_type, dealloc_type);
Decorator d;
Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: alloc-dealloc-mismatch (%s vs %s) on %p\n",
+ Report("ERROR: AddressSanitizer: %s (%s vs %s) on %p\n",
+ scariness.GetDescription(),
alloc_names[alloc_type], dealloc_names[dealloc_type],
addr_description.addr);
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
CHECK_GT(dealloc_stack->size, 0);
scariness.Print();
GET_STACK_TRACE_FATAL(dealloc_stack->trace[0], dealloc_stack->top_frame_bp);
stack.Print();
addr_description.Print();
- ReportErrorSummary("alloc-dealloc-mismatch", &stack);
+ ReportErrorSummary(scariness.GetDescription(), &stack);
Report(
"HINT: if you don't care about these errors you may set "
"ASAN_OPTIONS=alloc_dealloc_mismatch=0\n");
@@ -171,10 +135,10 @@ void ErrorMallocUsableSizeNotOwned::Print() {
"ERROR: AddressSanitizer: attempting to call malloc_usable_size() for "
"pointer which is not owned: %p\n",
addr_description.Address());
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
stack->Print();
addr_description.Print();
- ReportErrorSummary("bad-malloc_usable_size", stack);
+ ReportErrorSummary(scariness.GetDescription(), stack);
}
void ErrorSanitizerGetAllocatedSizeNotOwned::Print() {
@@ -184,10 +148,10 @@ void ErrorSanitizerGetAllocatedSizeNotOwned::Print() {
"ERROR: AddressSanitizer: attempting to call "
"__sanitizer_get_allocated_size() for pointer which is not owned: %p\n",
addr_description.Address());
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
stack->Print();
addr_description.Print();
- ReportErrorSummary("bad-__sanitizer_get_allocated_size", stack);
+ ReportErrorSummary(scariness.GetDescription(), stack);
}
void ErrorStringFunctionMemoryRangesOverlap::Print() {
@@ -201,7 +165,7 @@ void ErrorStringFunctionMemoryRangesOverlap::Print() {
bug_type, addr1_description.Address(),
addr1_description.Address() + length1, addr2_description.Address(),
addr2_description.Address() + length2);
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
scariness.Print();
stack->Print();
addr1_description.Print();
@@ -212,13 +176,13 @@ void ErrorStringFunctionMemoryRangesOverlap::Print() {
void ErrorStringFunctionSizeOverflow::Print() {
Decorator d;
Printf("%s", d.Warning());
- const char *bug_type = "negative-size-param";
- Report("ERROR: AddressSanitizer: %s: (size=%zd)\n", bug_type, size);
- Printf("%s", d.EndWarning());
+ Report("ERROR: AddressSanitizer: %s: (size=%zd)\n",
+ scariness.GetDescription(), size);
+ Printf("%s", d.Default());
scariness.Print();
stack->Print();
addr_description.Print();
- ReportErrorSummary(bug_type, stack);
+ ReportErrorSummary(scariness.GetDescription(), stack);
}
void ErrorBadParamsToAnnotateContiguousContainer::Print() {
@@ -234,14 +198,15 @@ void ErrorBadParamsToAnnotateContiguousContainer::Print() {
if (!IsAligned(beg, granularity))
Report("ERROR: beg is not aligned by %d\n", granularity);
stack->Print();
- ReportErrorSummary("bad-__sanitizer_annotate_contiguous_container", stack);
+ ReportErrorSummary(scariness.GetDescription(), stack);
}
void ErrorODRViolation::Print() {
Decorator d;
Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: odr-violation (%p):\n", global1.beg);
- Printf("%s", d.EndWarning());
+ Report("ERROR: AddressSanitizer: %s (%p):\n", scariness.GetDescription(),
+ global1.beg);
+ Printf("%s", d.Default());
InternalScopedString g1_loc(256), g2_loc(256);
PrintGlobalLocation(&g1_loc, global1);
PrintGlobalLocation(&g2_loc, global2);
@@ -260,23 +225,22 @@ void ErrorODRViolation::Print() {
"HINT: if you don't care about these errors you may set "
"ASAN_OPTIONS=detect_odr_violation=0\n");
InternalScopedString error_msg(256);
- error_msg.append("odr-violation: global '%s' at %s",
+ error_msg.append("%s: global '%s' at %s", scariness.GetDescription(),
MaybeDemangleGlobalName(global1.name), g1_loc.data());
ReportErrorSummary(error_msg.data());
}
void ErrorInvalidPointerPair::Print() {
- const char *bug_type = "invalid-pointer-pair";
Decorator d;
Printf("%s", d.Warning());
- Report("ERROR: AddressSanitizer: invalid-pointer-pair: %p %p\n",
+ Report("ERROR: AddressSanitizer: %s: %p %p\n", scariness.GetDescription(),
addr1_description.Address(), addr2_description.Address());
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
GET_STACK_TRACE_FATAL(pc, bp);
stack.Print();
addr1_description.Print();
addr2_description.Print();
- ReportErrorSummary(bug_type, &stack);
+ ReportErrorSummary(scariness.GetDescription(), &stack);
}
static bool AdjacentShadowValuesAreFullyPoisoned(u8 *s) {
@@ -470,13 +434,13 @@ void ErrorGeneric::Print() {
uptr addr = addr_description.Address();
Report("ERROR: AddressSanitizer: %s on address %p at pc %p bp %p sp %p\n",
bug_descr, (void *)addr, pc, bp, sp);
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
char tname[128];
Printf("%s%s of size %zu at %p thread T%d%s%s\n", d.Access(),
access_size ? (is_write ? "WRITE" : "READ") : "ACCESS", access_size,
(void *)addr, tid,
- ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.EndAccess());
+ ThreadNameWithParenthesis(tid, tname, sizeof(tname)), d.Default());
scariness.Print();
GET_STACK_TRACE_FATAL(pc, bp);
diff --git a/libsanitizer/asan/asan_errors.h b/libsanitizer/asan/asan_errors.h
index 6262dcf..ea8fd01 100644
--- a/libsanitizer/asan/asan_errors.h
+++ b/libsanitizer/asan/asan_errors.h
@@ -25,61 +25,28 @@ struct ErrorBase {
u32 tid;
};
-struct ErrorStackOverflow : ErrorBase {
- uptr addr, pc, bp, sp;
- // ErrorStackOverflow never owns the context.
- void *context;
- // VS2013 doesn't implement unrestricted unions, so we need a trivial default
- // constructor
- ErrorStackOverflow() = default;
- ErrorStackOverflow(u32 tid, const SignalContext &sig)
- : ErrorBase(tid),
- addr(sig.addr),
- pc(sig.pc),
- bp(sig.bp),
- sp(sig.sp),
- context(sig.context) {
- scariness.Clear();
- scariness.Scare(10, "stack-overflow");
- }
- void Print();
-};
-
struct ErrorDeadlySignal : ErrorBase {
- uptr addr, pc, bp, sp;
- // ErrorDeadlySignal never owns the context.
- void *context;
- int signo;
- SignalContext::WriteFlag write_flag;
- bool is_memory_access;
+ SignalContext signal;
// VS2013 doesn't implement unrestricted unions, so we need a trivial default
// constructor
ErrorDeadlySignal() = default;
- ErrorDeadlySignal(u32 tid, const SignalContext &sig, int signo_)
- : ErrorBase(tid),
- addr(sig.addr),
- pc(sig.pc),
- bp(sig.bp),
- sp(sig.sp),
- context(sig.context),
- signo(signo_),
- write_flag(sig.write_flag),
- is_memory_access(sig.is_memory_access) {
+ ErrorDeadlySignal(u32 tid, const SignalContext &sig)
+ : ErrorBase(tid), signal(sig) {
scariness.Clear();
- if (is_memory_access) {
- if (addr < GetPageSizeCached()) {
- scariness.Scare(10, "null-deref");
- } else if (addr == pc) {
- scariness.Scare(60, "wild-jump");
- } else if (write_flag == SignalContext::WRITE) {
- scariness.Scare(30, "wild-addr-write");
- } else if (write_flag == SignalContext::READ) {
- scariness.Scare(20, "wild-addr-read");
- } else {
- scariness.Scare(25, "wild-addr");
- }
- } else {
+ if (signal.IsStackOverflow()) {
+ scariness.Scare(10, "stack-overflow");
+ } else if (!signal.is_memory_access) {
scariness.Scare(10, "signal");
+ } else if (signal.addr < GetPageSizeCached()) {
+ scariness.Scare(10, "null-deref");
+ } else if (signal.addr == signal.pc) {
+ scariness.Scare(60, "wild-jump");
+ } else if (signal.write_flag == SignalContext::WRITE) {
+ scariness.Scare(30, "wild-addr-write");
+ } else if (signal.write_flag == SignalContext::READ) {
+ scariness.Scare(20, "wild-addr-read");
+ } else {
+ scariness.Scare(25, "wild-addr");
}
}
void Print();
@@ -170,6 +137,7 @@ struct ErrorMallocUsableSizeNotOwned : ErrorBase {
stack(stack_),
addr_description(addr, /*shouldLockThreadRegistry=*/false) {
scariness.Clear();
+ scariness.Scare(10, "bad-malloc_usable_size");
}
void Print();
};
@@ -187,6 +155,7 @@ struct ErrorSanitizerGetAllocatedSizeNotOwned : ErrorBase {
stack(stack_),
addr_description(addr, /*shouldLockThreadRegistry=*/false) {
scariness.Clear();
+ scariness.Scare(10, "bad-__sanitizer_get_allocated_size");
}
void Print();
};
@@ -256,7 +225,10 @@ struct ErrorBadParamsToAnnotateContiguousContainer : ErrorBase {
beg(beg_),
end(end_),
old_mid(old_mid_),
- new_mid(new_mid_) {}
+ new_mid(new_mid_) {
+ scariness.Clear();
+ scariness.Scare(10, "bad-__sanitizer_annotate_contiguous_container");
+ }
void Print();
};
@@ -272,7 +244,10 @@ struct ErrorODRViolation : ErrorBase {
global1(*g1),
global2(*g2),
stack_id1(stack_id1_),
- stack_id2(stack_id2_) {}
+ stack_id2(stack_id2_) {
+ scariness.Clear();
+ scariness.Scare(10, "odr-violation");
+ }
void Print();
};
@@ -290,7 +265,10 @@ struct ErrorInvalidPointerPair : ErrorBase {
bp(bp_),
sp(sp_),
addr1_description(p1, 1, /*shouldLockThreadRegistry=*/false),
- addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {}
+ addr2_description(p2, 1, /*shouldLockThreadRegistry=*/false) {
+ scariness.Clear();
+ scariness.Scare(10, "invalid-pointer-pair");
+ }
void Print();
};
@@ -311,7 +289,6 @@ struct ErrorGeneric : ErrorBase {
// clang-format off
#define ASAN_FOR_EACH_ERROR_KIND(macro) \
- macro(StackOverflow) \
macro(DeadlySignal) \
macro(DoubleFree) \
macro(NewDeleteSizeMismatch) \
@@ -348,6 +325,7 @@ struct ErrorDescription {
// We can add a wrapper around it to make it "more c++-like", but that would
// add a lot of code and the benefit wouldn't be that big.
union {
+ ErrorBase Base;
ASAN_FOR_EACH_ERROR_KIND(ASAN_ERROR_DESCRIPTION_MEMBER)
};
diff --git a/libsanitizer/asan/asan_fake_stack.cc b/libsanitizer/asan/asan_fake_stack.cc
index bf7566a..3140f9a 100644
--- a/libsanitizer/asan/asan_fake_stack.cc
+++ b/libsanitizer/asan/asan_fake_stack.cc
@@ -169,7 +169,7 @@ void FakeStack::ForEachFakeFrame(RangeIteratorCallback callback, void *arg) {
}
}
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
static THREADLOCAL FakeStack *fake_stack_tls;
FakeStack *GetTLSFakeStack() {
@@ -181,7 +181,7 @@ void SetTLSFakeStack(FakeStack *fs) {
#else
FakeStack *GetTLSFakeStack() { return 0; }
void SetTLSFakeStack(FakeStack *fs) { }
-#endif // SANITIZER_LINUX && !SANITIZER_ANDROID
+#endif // (SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_FUCHSIA
static FakeStack *GetFakeStack() {
AsanThread *t = GetCurrentThread();
diff --git a/libsanitizer/asan/asan_flags.cc b/libsanitizer/asan/asan_flags.cc
index c18174b..0c83dac 100644
--- a/libsanitizer/asan/asan_flags.cc
+++ b/libsanitizer/asan/asan_flags.cc
@@ -59,7 +59,7 @@ void InitializeFlags() {
{
CommonFlags cf;
cf.CopyFrom(*common_flags());
- cf.detect_leaks = CAN_SANITIZE_LEAKS;
+ cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS;
cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH");
cf.malloc_context_size = kDefaultMallocContextSize;
cf.intercept_tls_get_addr = true;
@@ -93,6 +93,18 @@ void InitializeFlags() {
RegisterCommonFlags(&ubsan_parser);
#endif
+ if (SANITIZER_MAC) {
+ // Support macOS MallocScribble and MallocPreScribble:
+ // <https://developer.apple.com/library/content/documentation/Performance/
+ // Conceptual/ManagingMemory/Articles/MallocDebug.html>
+ if (GetEnv("MallocScribble")) {
+ f->max_free_fill_size = 0x1000;
+ }
+ if (GetEnv("MallocPreScribble")) {
+ f->malloc_fill_byte = 0xaa;
+ }
+ }
+
// Override from ASan compile definition.
const char *asan_compile_def = MaybeUseAsanDefaultOptionsCompileDefinition();
asan_parser.ParseString(asan_compile_def);
@@ -104,6 +116,10 @@ void InitializeFlags() {
const char *ubsan_default_options = __ubsan::MaybeCallUbsanDefaultOptions();
ubsan_parser.ParseString(ubsan_default_options);
#endif
+#if CAN_SANITIZE_LEAKS
+ const char *lsan_default_options = __lsan::MaybeCallLsanDefaultOptions();
+ lsan_parser.ParseString(lsan_default_options);
+#endif
// Override from command line.
asan_parser.ParseString(GetEnv("ASAN_OPTIONS"));
@@ -154,9 +170,24 @@ void InitializeFlags() {
f->quarantine_size_mb = f->quarantine_size >> 20;
if (f->quarantine_size_mb < 0) {
const int kDefaultQuarantineSizeMb =
- (ASAN_LOW_MEMORY) ? 1UL << 6 : 1UL << 8;
+ (ASAN_LOW_MEMORY) ? 1UL << 4 : 1UL << 8;
f->quarantine_size_mb = kDefaultQuarantineSizeMb;
}
+ if (f->thread_local_quarantine_size_kb < 0) {
+ const u32 kDefaultThreadLocalQuarantineSizeKb =
+ // It is not advised to go lower than 64Kb, otherwise quarantine batches
+ // pushed from thread local quarantine to global one will create too
+ // much overhead. One quarantine batch size is 8Kb and it holds up to
+ // 1021 chunk, which amounts to 1/8 memory overhead per batch when
+ // thread local quarantine is set to 64Kb.
+ (ASAN_LOW_MEMORY) ? 1 << 6 : FIRST_32_SECOND_64(1 << 8, 1 << 10);
+ f->thread_local_quarantine_size_kb = kDefaultThreadLocalQuarantineSizeKb;
+ }
+ if (f->thread_local_quarantine_size_kb == 0 && f->quarantine_size_mb > 0) {
+ Report("%s: thread_local_quarantine_size_kb can be set to 0 only when "
+ "quarantine_size_mb is set to 0\n", SanitizerToolName);
+ Die();
+ }
if (!f->replace_str && common_flags()->intercept_strlen) {
Report("WARNING: strlen interceptor is enabled even though replace_str=0. "
"Use intercept_strlen=0 to disable it.");
@@ -165,13 +196,14 @@ void InitializeFlags() {
Report("WARNING: strchr* interceptors are enabled even though "
"replace_str=0. Use intercept_strchr=0 to disable them.");
}
+ if (!f->replace_str && common_flags()->intercept_strndup) {
+ Report("WARNING: strndup* interceptors are enabled even though "
+ "replace_str=0. Use intercept_strndup=0 to disable them.");
+ }
}
} // namespace __asan
-#if !SANITIZER_SUPPORTS_WEAK_HOOKS
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-const char* __asan_default_options() { return ""; }
-} // extern "C"
-#endif
+SANITIZER_INTERFACE_WEAK_DEF(const char*, __asan_default_options, void) {
+ return "";
+}
diff --git a/libsanitizer/asan/asan_flags.inc b/libsanitizer/asan/asan_flags.inc
index 34493ee..3784f06 100644
--- a/libsanitizer/asan/asan_flags.inc
+++ b/libsanitizer/asan/asan_flags.inc
@@ -21,6 +21,12 @@ ASAN_FLAG(int, quarantine_size_mb, -1,
"Size (in Mb) of quarantine used to detect use-after-free "
"errors. Lower value may reduce memory usage but increase the "
"chance of false negatives.")
+ASAN_FLAG(int, thread_local_quarantine_size_kb, -1,
+ "Size (in Kb) of thread local quarantine used to detect "
+ "use-after-free errors. Lower value may reduce memory usage but "
+ "increase the chance of false negatives. It is not advised to go "
+ "lower than 64Kb, otherwise frequent transfers to global quarantine "
+ "might affect performance.")
ASAN_FLAG(int, redzone, 16,
"Minimal size (in bytes) of redzones around heap objects. "
"Requirement: redzone >= 16, is a power of two.")
@@ -55,8 +61,14 @@ ASAN_FLAG(
int, max_malloc_fill_size, 0x1000, // By default, fill only the first 4K.
"ASan allocator flag. max_malloc_fill_size is the maximal amount of "
"bytes that will be filled with malloc_fill_byte on malloc.")
+ASAN_FLAG(
+ int, max_free_fill_size, 0,
+ "ASan allocator flag. max_free_fill_size is the maximal amount of "
+ "bytes that will be filled with free_fill_byte during free.")
ASAN_FLAG(int, malloc_fill_byte, 0xbe,
"Value used to fill the newly allocated memory.")
+ASAN_FLAG(int, free_fill_byte, 0x55,
+ "Value used to fill deallocated memory.")
ASAN_FLAG(bool, allow_user_poisoning, true,
"If set, user may manually mark memory regions as poisoned or "
"unpoisoned.")
@@ -65,6 +77,10 @@ ASAN_FLAG(
"Number of seconds to sleep between printing an error report and "
"terminating the program. Useful for debugging purposes (e.g. when one "
"needs to attach gdb).")
+ASAN_FLAG(
+ int, sleep_after_init, 0,
+ "Number of seconds to sleep after AddressSanitizer is initialized. "
+ "Useful for debugging purposes (e.g. when one needs to attach gdb).")
ASAN_FLAG(bool, check_malloc_usable_size, true,
"Allows the users to work around the bug in Nvidia drivers prior to "
"295.*.")
@@ -129,11 +145,16 @@ ASAN_FLAG(int, detect_odr_violation, 2,
"If >=2, detect violation of One-Definition-Rule (ODR); "
"If ==1, detect ODR-violation only if the two variables "
"have different sizes")
-ASAN_FLAG(bool, dump_instruction_bytes, false,
- "If true, dump 16 bytes starting at the instruction that caused SEGV")
ASAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
ASAN_FLAG(bool, halt_on_error, true,
"Crash the program after printing the first error report "
"(WARNING: USE AT YOUR OWN RISK!)")
ASAN_FLAG(bool, use_odr_indicator, false,
"Use special ODR indicator symbol for ODR violation detection")
+ASAN_FLAG(bool, allocator_frees_and_returns_null_on_realloc_zero, true,
+ "realloc(p, 0) is equivalent to free(p) by default (Same as the "
+ "POSIX standard). If set to false, realloc(p, 0) will return a "
+ "pointer to an allocated space which can not be used.")
+ASAN_FLAG(bool, verify_asan_link_order, true,
+ "Check position of ASan runtime in library list (needs to be disabled"
+ " when other library has to be preloaded system-wide)")
diff --git a/libsanitizer/asan/asan_fuchsia.cc b/libsanitizer/asan/asan_fuchsia.cc
new file mode 100644
index 0000000..6b1b489
--- /dev/null
+++ b/libsanitizer/asan/asan_fuchsia.cc
@@ -0,0 +1,216 @@
+//===-- asan_fuchsia.cc --------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Fuchsia-specific details.
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_fuchsia.h"
+#if SANITIZER_FUCHSIA
+
+#include "asan_interceptors.h"
+#include "asan_internal.h"
+#include "asan_stack.h"
+#include "asan_thread.h"
+
+#include <limits.h>
+#include <zircon/sanitizer.h>
+#include <zircon/syscalls.h>
+#include <zircon/threads.h>
+
+namespace __asan {
+
+// The system already set up the shadow memory for us.
+// __sanitizer::GetMaxVirtualAddress has already been called by
+// AsanInitInternal->InitializeHighMemEnd (asan_rtl.cc).
+// Just do some additional sanity checks here.
+void InitializeShadowMemory() {
+ if (Verbosity()) PrintAddressSpaceLayout();
+
+ // Make sure SHADOW_OFFSET doesn't use __asan_shadow_memory_dynamic_address.
+ __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
+ DCHECK(kLowShadowBeg != kDefaultShadowSentinel);
+ __asan_shadow_memory_dynamic_address = kLowShadowBeg;
+
+ CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
+ CHECK_EQ(kHighMemEnd, __sanitizer::ShadowBounds.memory_limit - 1);
+ CHECK_EQ(kHighMemBeg, __sanitizer::ShadowBounds.shadow_limit);
+ CHECK_EQ(kHighShadowBeg, __sanitizer::ShadowBounds.shadow_base);
+ CHECK_EQ(kShadowGapEnd, __sanitizer::ShadowBounds.shadow_base - 1);
+ CHECK_EQ(kLowShadowEnd, 0);
+ CHECK_EQ(kLowShadowBeg, 0);
+}
+
+void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
+ UNIMPLEMENTED();
+}
+
+void AsanCheckDynamicRTPrereqs() {}
+void AsanCheckIncompatibleRT() {}
+void InitializeAsanInterceptors() {}
+
+void *AsanDoesNotSupportStaticLinkage() { return nullptr; }
+
+void InitializePlatformExceptionHandlers() {}
+void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+ UNIMPLEMENTED();
+}
+
+// We can use a plain thread_local variable for TSD.
+static thread_local void *per_thread;
+
+void *AsanTSDGet() { return per_thread; }
+
+void AsanTSDSet(void *tsd) { per_thread = tsd; }
+
+// There's no initialization needed, and the passed-in destructor
+// will never be called. Instead, our own thread destruction hook
+// (below) will call AsanThread::TSDDtor directly.
+void AsanTSDInit(void (*destructor)(void *tsd)) {
+ DCHECK(destructor == &PlatformTSDDtor);
+}
+
+void PlatformTSDDtor(void *tsd) { UNREACHABLE(__func__); }
+
+static inline size_t AsanThreadMmapSize() {
+ return RoundUpTo(sizeof(AsanThread), PAGE_SIZE);
+}
+
+struct AsanThread::InitOptions {
+ uptr stack_bottom, stack_size;
+};
+
+// Shared setup between thread creation and startup for the initial thread.
+static AsanThread *CreateAsanThread(StackTrace *stack, u32 parent_tid,
+ uptr user_id, bool detached,
+ const char *name, uptr stack_bottom,
+ uptr stack_size) {
+ // In lieu of AsanThread::Create.
+ AsanThread *thread = (AsanThread *)MmapOrDie(AsanThreadMmapSize(), __func__);
+
+ AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
+ u32 tid =
+ asanThreadRegistry().CreateThread(user_id, detached, parent_tid, &args);
+ asanThreadRegistry().SetThreadName(tid, name);
+
+ // On other systems, AsanThread::Init() is called from the new
+ // thread itself. But on Fuchsia we already know the stack address
+ // range beforehand, so we can do most of the setup right now.
+ const AsanThread::InitOptions options = {stack_bottom, stack_size};
+ thread->Init(&options);
+
+ return thread;
+}
+
+// This gets the same arguments passed to Init by CreateAsanThread, above.
+// We're in the creator thread before the new thread is actually started,
+// but its stack address range is already known. We don't bother tracking
+// the static TLS address range because the system itself already uses an
+// ASan-aware allocator for that.
+void AsanThread::SetThreadStackAndTls(const AsanThread::InitOptions *options) {
+ DCHECK_NE(GetCurrentThread(), this);
+ DCHECK_NE(GetCurrentThread(), nullptr);
+ CHECK_NE(options->stack_bottom, 0);
+ CHECK_NE(options->stack_size, 0);
+ stack_bottom_ = options->stack_bottom;
+ stack_top_ = options->stack_bottom + options->stack_size;
+}
+
+// Called by __asan::AsanInitInternal (asan_rtl.c).
+AsanThread *CreateMainThread() {
+ thrd_t self = thrd_current();
+ char name[ZX_MAX_NAME_LEN];
+ CHECK_NE(__sanitizer::MainThreadStackBase, 0);
+ CHECK_GT(__sanitizer::MainThreadStackSize, 0);
+ AsanThread *t = CreateAsanThread(
+ nullptr, 0, reinterpret_cast<uptr>(self), true,
+ _zx_object_get_property(thrd_get_zx_handle(self), ZX_PROP_NAME, name,
+ sizeof(name)) == ZX_OK
+ ? name
+ : nullptr,
+ __sanitizer::MainThreadStackBase, __sanitizer::MainThreadStackSize);
+ SetCurrentThread(t);
+ return t;
+}
+
+// This is called before each thread creation is attempted. So, in
+// its first call, the calling thread is the initial and sole thread.
+static void *BeforeThreadCreateHook(uptr user_id, bool detached,
+ const char *name, uptr stack_bottom,
+ uptr stack_size) {
+ EnsureMainThreadIDIsCorrect();
+ // Strict init-order checking is thread-hostile.
+ if (flags()->strict_init_order) StopInitOrderChecking();
+
+ GET_STACK_TRACE_THREAD;
+ u32 parent_tid = GetCurrentTidOrInvalid();
+
+ return CreateAsanThread(&stack, parent_tid, user_id, detached, name,
+ stack_bottom, stack_size);
+}
+
+// This is called after creating a new thread (in the creating thread),
+// with the pointer returned by BeforeThreadCreateHook (above).
+static void ThreadCreateHook(void *hook, bool aborted) {
+ AsanThread *thread = static_cast<AsanThread *>(hook);
+ if (!aborted) {
+ // The thread was created successfully.
+ // ThreadStartHook is already running in the new thread.
+ } else {
+ // The thread wasn't created after all.
+ // Clean up everything we set up in BeforeThreadCreateHook.
+ asanThreadRegistry().FinishThread(thread->tid());
+ UnmapOrDie(thread, AsanThreadMmapSize());
+ }
+}
+
+// This is called in the newly-created thread before it runs anything else,
+// with the pointer returned by BeforeThreadCreateHook (above).
+// cf. asan_interceptors.cc:asan_thread_start
+static void ThreadStartHook(void *hook, uptr os_id) {
+ AsanThread *thread = static_cast<AsanThread *>(hook);
+ SetCurrentThread(thread);
+
+ // In lieu of AsanThread::ThreadStart.
+ asanThreadRegistry().StartThread(thread->tid(), os_id, /*workerthread*/ false,
+ nullptr);
+}
+
+// Each thread runs this just before it exits,
+// with the pointer returned by BeforeThreadCreateHook (above).
+// All per-thread destructors have already been called.
+static void ThreadExitHook(void *hook, uptr os_id) {
+ AsanThread::TSDDtor(per_thread);
+}
+
+} // namespace __asan
+
+// These are declared (in extern "C") by <zircon/sanitizer.h>.
+// The system runtime will call our definitions directly.
+
+void *__sanitizer_before_thread_create_hook(thrd_t thread, bool detached,
+ const char *name, void *stack_base,
+ size_t stack_size) {
+ return __asan::BeforeThreadCreateHook(
+ reinterpret_cast<uptr>(thread), detached, name,
+ reinterpret_cast<uptr>(stack_base), stack_size);
+}
+
+void __sanitizer_thread_create_hook(void *hook, thrd_t thread, int error) {
+ __asan::ThreadCreateHook(hook, error != thrd_success);
+}
+
+void __sanitizer_thread_start_hook(void *hook, thrd_t self) {
+ __asan::ThreadStartHook(hook, reinterpret_cast<uptr>(self));
+}
+
+void __sanitizer_thread_exit_hook(void *hook, thrd_t self) {
+ __asan::ThreadExitHook(hook, reinterpret_cast<uptr>(self));
+}
+
+#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/asan/asan_globals.cc b/libsanitizer/asan/asan_globals.cc
index f229292..c33b0ac 100644
--- a/libsanitizer/asan/asan_globals.cc
+++ b/libsanitizer/asan/asan_globals.cc
@@ -311,6 +311,26 @@ void __asan_unregister_image_globals(uptr *flag) {
*flag = 0;
}
+void __asan_register_elf_globals(uptr *flag, void *start, void *stop) {
+ if (*flag) return;
+ if (!start) return;
+ CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
+ __asan_global *globals_start = (__asan_global*)start;
+ __asan_global *globals_stop = (__asan_global*)stop;
+ __asan_register_globals(globals_start, globals_stop - globals_start);
+ *flag = 1;
+}
+
+void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop) {
+ if (!*flag) return;
+ if (!start) return;
+ CHECK_EQ(0, ((uptr)stop - (uptr)start) % sizeof(__asan_global));
+ __asan_global *globals_start = (__asan_global*)start;
+ __asan_global *globals_stop = (__asan_global*)stop;
+ __asan_unregister_globals(globals_start, globals_stop - globals_start);
+ *flag = 0;
+}
+
// Register an array of globals.
void __asan_register_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return;
@@ -327,8 +347,26 @@ void __asan_register_globals(__asan_global *globals, uptr n) {
Printf("=== ID %d; %p %p\n", stack_id, &globals[0], &globals[n - 1]);
}
for (uptr i = 0; i < n; i++) {
+ if (SANITIZER_WINDOWS && globals[i].beg == 0) {
+ // The MSVC incremental linker may pad globals out to 256 bytes. As long
+ // as __asan_global is less than 256 bytes large and its size is a power
+ // of two, we can skip over the padding.
+ static_assert(
+ sizeof(__asan_global) < 256 &&
+ (sizeof(__asan_global) & (sizeof(__asan_global) - 1)) == 0,
+ "sizeof(__asan_global) incompatible with incremental linker padding");
+ // If these are padding bytes, the rest of the global should be zero.
+ CHECK(globals[i].size == 0 && globals[i].size_with_redzone == 0 &&
+ globals[i].name == nullptr && globals[i].module_name == nullptr &&
+ globals[i].odr_indicator == 0);
+ continue;
+ }
RegisterGlobal(&globals[i]);
}
+
+ // Poison the metadata. It should not be accessible to user code.
+ PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global),
+ kAsanGlobalRedzoneMagic);
}
// Unregister an array of globals.
@@ -337,8 +375,16 @@ void __asan_unregister_globals(__asan_global *globals, uptr n) {
if (!flags()->report_globals) return;
BlockingMutexLock lock(&mu_for_globals);
for (uptr i = 0; i < n; i++) {
+ if (SANITIZER_WINDOWS && globals[i].beg == 0) {
+ // Skip globals that look like padding from the MSVC incremental linker.
+ // See comment in __asan_register_globals.
+ continue;
+ }
UnregisterGlobal(&globals[i]);
}
+
+ // Unpoison the metadata.
+ PoisonShadow(reinterpret_cast<uptr>(globals), n * sizeof(__asan_global), 0);
}
// This method runs immediately prior to dynamic initialization in each TU,
diff --git a/libsanitizer/asan/asan_globals_win.cc b/libsanitizer/asan/asan_globals_win.cc
new file mode 100644
index 0000000..118c0ac
--- /dev/null
+++ b/libsanitizer/asan/asan_globals_win.cc
@@ -0,0 +1,60 @@
+//===-- asan_globals_win.cc -----------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Global registration code that is linked into every Windows DLL and EXE.
+//
+//===----------------------------------------------------------------------===//
+
+#include "asan_interface_internal.h"
+#if SANITIZER_WINDOWS
+
+namespace __asan {
+
+#pragma section(".ASAN$GA", read, write) // NOLINT
+#pragma section(".ASAN$GZ", read, write) // NOLINT
+extern "C" __declspec(allocate(".ASAN$GA"))
+__asan_global __asan_globals_start = {};
+extern "C" __declspec(allocate(".ASAN$GZ"))
+__asan_global __asan_globals_end = {};
+#pragma comment(linker, "/merge:.ASAN=.data")
+
+static void call_on_globals(void (*hook)(__asan_global *, uptr)) {
+ __asan_global *start = &__asan_globals_start + 1;
+ __asan_global *end = &__asan_globals_end;
+ uptr bytediff = (uptr)end - (uptr)start;
+ if (bytediff % sizeof(__asan_global) != 0) {
+#ifdef SANITIZER_DLL_THUNK
+ __debugbreak();
+#else
+ CHECK("corrupt asan global array");
+#endif
+ }
+ // We know end >= start because the linker sorts the portion after the dollar
+ // sign alphabetically.
+ uptr n = end - start;
+ hook(start, n);
+}
+
+static void register_dso_globals() {
+ call_on_globals(&__asan_register_globals);
+}
+
+static void unregister_dso_globals() {
+ call_on_globals(&__asan_unregister_globals);
+}
+
+// Register globals
+#pragma section(".CRT$XCU", long, read) // NOLINT
+#pragma section(".CRT$XTX", long, read) // NOLINT
+extern "C" __declspec(allocate(".CRT$XCU"))
+void (*const __asan_dso_reg_hook)() = &register_dso_globals;
+extern "C" __declspec(allocate(".CRT$XTX"))
+void (*const __asan_dso_unreg_hook)() = &unregister_dso_globals;
+
+} // namespace __asan
+
+#endif // SANITIZER_WINDOWS
diff --git a/libsanitizer/asan/asan_interceptors.cc b/libsanitizer/asan/asan_interceptors.cc
index 743abe5..a8f4b72 100644
--- a/libsanitizer/asan/asan_interceptors.cc
+++ b/libsanitizer/asan/asan_interceptors.cc
@@ -22,6 +22,11 @@
#include "lsan/lsan_common.h"
#include "sanitizer_common/sanitizer_libc.h"
+// There is no general interception at all on Fuchsia.
+// Only the functions in asan_interceptors_memintrinsics.cc are
+// really defined to replace libc functions.
+#if !SANITIZER_FUCHSIA
+
#if SANITIZER_POSIX
#include "sanitizer_common/sanitizer_posix.h"
#endif
@@ -34,56 +39,6 @@
namespace __asan {
-// Return true if we can quickly decide that the region is unpoisoned.
-static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
- if (size == 0) return true;
- if (size <= 32)
- return !AddressIsPoisoned(beg) &&
- !AddressIsPoisoned(beg + size - 1) &&
- !AddressIsPoisoned(beg + size / 2);
- return false;
-}
-
-struct AsanInterceptorContext {
- const char *interceptor_name;
-};
-
-// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
-// and ASAN_WRITE_RANGE as macro instead of function so
-// that no extra frames are created, and stack trace contains
-// relevant information only.
-// We check all shadow bytes.
-#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
- uptr __offset = (uptr)(offset); \
- uptr __size = (uptr)(size); \
- uptr __bad = 0; \
- if (__offset > __offset + __size) { \
- GET_STACK_TRACE_FATAL_HERE; \
- ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
- } \
- if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
- (__bad = __asan_region_is_poisoned(__offset, __size))) { \
- AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
- bool suppressed = false; \
- if (_ctx) { \
- suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
- if (!suppressed && HaveStackTraceBasedSuppressions()) { \
- GET_STACK_TRACE_FATAL_HERE; \
- suppressed = IsStackTraceSuppressed(&stack); \
- } \
- } \
- if (!suppressed) { \
- GET_CURRENT_PC_BP_SP; \
- ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
- } \
- } \
- } while (0)
-
-#define ASAN_READ_RANGE(ctx, offset, size) \
- ACCESS_MEMORY_RANGE(ctx, offset, size, false)
-#define ASAN_WRITE_RANGE(ctx, offset, size) \
- ACCESS_MEMORY_RANGE(ctx, offset, size, true)
-
#define ASAN_READ_STRING_OF_LEN(ctx, s, len, n) \
ASAN_READ_RANGE((ctx), (s), \
common_flags()->strict_string_checks ? (len) + 1 : (n))
@@ -91,23 +46,6 @@ struct AsanInterceptorContext {
#define ASAN_READ_STRING(ctx, s, n) \
ASAN_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
-// Behavior of functions like "memcpy" or "strcpy" is undefined
-// if memory intervals overlap. We report error in this case.
-// Macro is used to avoid creation of new frames.
-static inline bool RangesOverlap(const char *offset1, uptr length1,
- const char *offset2, uptr length2) {
- return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
-}
-#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
- const char *offset1 = (const char*)_offset1; \
- const char *offset2 = (const char*)_offset2; \
- if (RangesOverlap(offset1, length1, offset2, length2)) { \
- GET_STACK_TRACE_FATAL_HERE; \
- ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
- offset2, length2, &stack); \
- } \
-} while (0)
-
static inline uptr MaybeRealStrnlen(const char *s, uptr maxlen) {
#if SANITIZER_INTERCEPT_STRNLEN
if (REAL(strnlen)) {
@@ -124,6 +62,10 @@ void SetThreadName(const char *name) {
}
int OnExit() {
+ if (CAN_SANITIZE_LEAKS && common_flags()->detect_leaks &&
+ __lsan::HasReportedLeaks()) {
+ return common_flags()->exitcode;
+ }
// FIXME: ask frontend whether we need to return failure.
return 0;
}
@@ -181,13 +123,14 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
// Strict init-order checking is dlopen-hostile:
// https://github.com/google/sanitizers/issues/178
#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \
- if (flags()->strict_init_order) { \
- StopInitOrderChecking(); \
- }
+ do { \
+ if (flags()->strict_init_order) \
+ StopInitOrderChecking(); \
+ CheckNoDeepBind(filename, flag); \
+ } while (false)
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) OnExit()
-#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle) \
- CoverageUpdateMapping()
-#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED() CoverageUpdateMapping()
+#define COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, handle)
+#define COMMON_INTERCEPTOR_LIBRARY_UNLOADED()
#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (!asan_inited)
#define COMMON_INTERCEPTOR_GET_TLS_RANGE(begin, end) \
if (AsanThread *t = GetCurrentThread()) { \
@@ -196,11 +139,27 @@ DECLARE_REAL_AND_INTERCEPTOR(void, free, void *)
} else { \
*begin = *end = 0; \
}
-// Asan needs custom handling of these:
-#undef SANITIZER_INTERCEPT_MEMSET
-#undef SANITIZER_INTERCEPT_MEMMOVE
-#undef SANITIZER_INTERCEPT_MEMCPY
+
+#define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size) \
+ do { \
+ ASAN_INTERCEPTOR_ENTER(ctx, memmove); \
+ ASAN_MEMMOVE_IMPL(ctx, to, from, size); \
+ } while (false)
+
+#define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size) \
+ do { \
+ ASAN_INTERCEPTOR_ENTER(ctx, memcpy); \
+ ASAN_MEMCPY_IMPL(ctx, to, from, size); \
+ } while (false)
+
+#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size) \
+ do { \
+ ASAN_INTERCEPTOR_ENTER(ctx, memset); \
+ ASAN_MEMSET_IMPL(ctx, block, c, size); \
+ } while (false)
+
#include "sanitizer_common/sanitizer_common_interceptors.inc"
+#include "sanitizer_common/sanitizer_signal_interceptors.inc"
// Syscall interceptors don't have contexts, we don't support suppressions
// for them.
@@ -282,48 +241,6 @@ INTERCEPTOR(int, pthread_join, void *t, void **arg) {
DEFINE_REAL_PTHREAD_FUNCTIONS
#endif // ASAN_INTERCEPT_PTHREAD_CREATE
-#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
-
-#if SANITIZER_ANDROID
-INTERCEPTOR(void*, bsd_signal, int signum, void *handler) {
- if (!IsHandledDeadlySignal(signum) ||
- common_flags()->allow_user_segv_handler) {
- return REAL(bsd_signal)(signum, handler);
- }
- return 0;
-}
-#endif
-
-INTERCEPTOR(void*, signal, int signum, void *handler) {
- if (!IsHandledDeadlySignal(signum) ||
- common_flags()->allow_user_segv_handler) {
- return REAL(signal)(signum, handler);
- }
- return nullptr;
-}
-
-INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
- struct sigaction *oldact) {
- if (!IsHandledDeadlySignal(signum) ||
- common_flags()->allow_user_segv_handler) {
- return REAL(sigaction)(signum, act, oldact);
- }
- return 0;
-}
-
-namespace __sanitizer {
-int real_sigaction(int signum, const void *act, void *oldact) {
- return REAL(sigaction)(signum, (const struct sigaction *)act,
- (struct sigaction *)oldact);
-}
-} // namespace __sanitizer
-
-#elif SANITIZER_POSIX
-// We need to have defined REAL(sigaction) on posix systems.
-DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
- struct sigaction *oldact)
-#endif // ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
-
#if ASAN_INTERCEPT_SWAPCONTEXT
static void ClearShadowMemoryForContextStack(uptr stack, uptr ssize) {
// Align to page size.
@@ -360,6 +277,11 @@ INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp,
}
#endif // ASAN_INTERCEPT_SWAPCONTEXT
+#if SANITIZER_NETBSD
+#define longjmp __longjmp14
+#define siglongjmp __siglongjmp14
+#endif
+
INTERCEPTOR(void, longjmp, void *env, int val) {
__asan_handle_no_return();
REAL(longjmp)(env, val);
@@ -372,6 +294,13 @@ INTERCEPTOR(void, _longjmp, void *env, int val) {
}
#endif
+#if ASAN_INTERCEPT___LONGJMP_CHK
+INTERCEPTOR(void, __longjmp_chk, void *env, int val) {
+ __asan_handle_no_return();
+ REAL(__longjmp_chk)(env, val);
+}
+#endif
+
#if ASAN_INTERCEPT_SIGLONGJMP
INTERCEPTOR(void, siglongjmp, void *env, int val) {
__asan_handle_no_return();
@@ -387,90 +316,6 @@ INTERCEPTOR(void, __cxa_throw, void *a, void *b, void *c) {
}
#endif
-// memcpy is called during __asan_init() from the internals of printf(...).
-// We do not treat memcpy with to==from as a bug.
-// See http://llvm.org/bugs/show_bug.cgi?id=11763.
-#define ASAN_MEMCPY_IMPL(ctx, to, from, size) do { \
- if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
- if (asan_init_is_running) { \
- return REAL(memcpy)(to, from, size); \
- } \
- ENSURE_ASAN_INITED(); \
- if (flags()->replace_intrin) { \
- if (to != from) { \
- CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
- } \
- ASAN_READ_RANGE(ctx, from, size); \
- ASAN_WRITE_RANGE(ctx, to, size); \
- } \
- return REAL(memcpy)(to, from, size); \
- } while (0)
-
-
-void *__asan_memcpy(void *to, const void *from, uptr size) {
- ASAN_MEMCPY_IMPL(nullptr, to, from, size);
-}
-
-// memset is called inside Printf.
-#define ASAN_MEMSET_IMPL(ctx, block, c, size) do { \
- if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
- if (asan_init_is_running) { \
- return REAL(memset)(block, c, size); \
- } \
- ENSURE_ASAN_INITED(); \
- if (flags()->replace_intrin) { \
- ASAN_WRITE_RANGE(ctx, block, size); \
- } \
- return REAL(memset)(block, c, size); \
- } while (0)
-
-void *__asan_memset(void *block, int c, uptr size) {
- ASAN_MEMSET_IMPL(nullptr, block, c, size);
-}
-
-#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) do { \
- if (UNLIKELY(!asan_inited)) \
- return internal_memmove(to, from, size); \
- ENSURE_ASAN_INITED(); \
- if (flags()->replace_intrin) { \
- ASAN_READ_RANGE(ctx, from, size); \
- ASAN_WRITE_RANGE(ctx, to, size); \
- } \
- return internal_memmove(to, from, size); \
- } while (0)
-
-void *__asan_memmove(void *to, const void *from, uptr size) {
- ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
-}
-
-INTERCEPTOR(void*, memmove, void *to, const void *from, uptr size) {
- void *ctx;
- ASAN_INTERCEPTOR_ENTER(ctx, memmove);
- ASAN_MEMMOVE_IMPL(ctx, to, from, size);
-}
-
-INTERCEPTOR(void*, memcpy, void *to, const void *from, uptr size) {
- void *ctx;
- ASAN_INTERCEPTOR_ENTER(ctx, memcpy);
-#if !SANITIZER_MAC
- ASAN_MEMCPY_IMPL(ctx, to, from, size);
-#else
- // At least on 10.7 and 10.8 both memcpy() and memmove() are being replaced
- // with WRAP(memcpy). As a result, false positives are reported for memmove()
- // calls. If we just disable error reporting with
- // ASAN_OPTIONS=replace_intrin=0, memmove() is still replaced with
- // internal_memcpy(), which may lead to crashes, see
- // http://llvm.org/bugs/show_bug.cgi?id=16362.
- ASAN_MEMMOVE_IMPL(ctx, to, from, size);
-#endif // !SANITIZER_MAC
-}
-
-INTERCEPTOR(void*, memset, void *block, int c, uptr size) {
- void *ctx;
- ASAN_INTERCEPTOR_ENTER(ctx, memset);
- ASAN_MEMSET_IMPL(ctx, block, c, size);
-}
-
#if ASAN_INTERCEPT_INDEX
# if ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX
INTERCEPTOR(char*, index, const char *string, int c)
@@ -580,17 +425,6 @@ INTERCEPTOR(char*, __strdup, const char *s) {
}
#endif // ASAN_INTERCEPT___STRDUP
-INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
- void *ctx;
- ASAN_INTERCEPTOR_ENTER(ctx, wcslen);
- SIZE_T length = internal_wcslen(s);
- if (!asan_init_is_running) {
- ENSURE_ASAN_INITED();
- ASAN_READ_RANGE(ctx, s, (length + 1) * sizeof(wchar_t));
- }
- return length;
-}
-
INTERCEPTOR(char*, strncpy, char *to, const char *from, uptr size) {
void *ctx;
ASAN_INTERCEPTOR_ENTER(ctx, strncpy);
@@ -707,9 +541,7 @@ INTERCEPTOR(int, __cxa_atexit, void (*func)(void *), void *arg,
#if ASAN_INTERCEPT_FORK
INTERCEPTOR(int, fork, void) {
ENSURE_ASAN_INITED();
- if (common_flags()->coverage) CovBeforeFork();
int pid = REAL(fork)();
- if (common_flags()->coverage) CovAfterFork(pid);
return pid;
}
#endif // ASAN_INTERCEPT_FORK
@@ -721,22 +553,11 @@ void InitializeAsanInterceptors() {
CHECK(!was_called_once);
was_called_once = true;
InitializeCommonInterceptors();
-
- // Intercept mem* functions.
- ASAN_INTERCEPT_FUNC(memmove);
- ASAN_INTERCEPT_FUNC(memset);
- if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
- // In asan, REAL(memmove) is not used, but it is used in msan.
- ASAN_INTERCEPT_FUNC(memcpy);
- } else {
- ASSIGN_REAL(memcpy, memmove);
- }
- CHECK(REAL(memcpy));
+ InitializeSignalInterceptors();
// Intercept str* functions.
ASAN_INTERCEPT_FUNC(strcat); // NOLINT
ASAN_INTERCEPT_FUNC(strcpy); // NOLINT
- ASAN_INTERCEPT_FUNC(wcslen);
ASAN_INTERCEPT_FUNC(strncat);
ASAN_INTERCEPT_FUNC(strncpy);
ASAN_INTERCEPT_FUNC(strdup);
@@ -755,21 +576,18 @@ void InitializeAsanInterceptors() {
ASAN_INTERCEPT_FUNC(strtoll);
#endif
- // Intecept signal- and jump-related functions.
+ // Intecept jump-related functions.
ASAN_INTERCEPT_FUNC(longjmp);
-#if ASAN_INTERCEPT_SIGNAL_AND_SIGACTION
- ASAN_INTERCEPT_FUNC(sigaction);
-#if SANITIZER_ANDROID
- ASAN_INTERCEPT_FUNC(bsd_signal);
-#endif
- ASAN_INTERCEPT_FUNC(signal);
-#endif
+
#if ASAN_INTERCEPT_SWAPCONTEXT
ASAN_INTERCEPT_FUNC(swapcontext);
#endif
#if ASAN_INTERCEPT__LONGJMP
ASAN_INTERCEPT_FUNC(_longjmp);
#endif
+#if ASAN_INTERCEPT___LONGJMP_CHK
+ ASAN_INTERCEPT_FUNC(__longjmp_chk);
+#endif
#if ASAN_INTERCEPT_SIGLONGJMP
ASAN_INTERCEPT_FUNC(siglongjmp);
#endif
@@ -804,3 +622,5 @@ void InitializeAsanInterceptors() {
}
} // namespace __asan
+
+#endif // !SANITIZER_FUCHSIA
diff --git a/libsanitizer/asan/asan_interceptors.h b/libsanitizer/asan/asan_interceptors.h
index 7053bb7..e20d1af 100644
--- a/libsanitizer/asan/asan_interceptors.h
+++ b/libsanitizer/asan/asan_interceptors.h
@@ -13,9 +13,30 @@
#define ASAN_INTERCEPTORS_H
#include "asan_internal.h"
+#include "asan_interceptors_memintrinsics.h"
#include "interception/interception.h"
#include "sanitizer_common/sanitizer_platform_interceptors.h"
+namespace __asan {
+
+void InitializeAsanInterceptors();
+void InitializePlatformInterceptors();
+
+#define ENSURE_ASAN_INITED() \
+ do { \
+ CHECK(!asan_init_is_running); \
+ if (UNLIKELY(!asan_inited)) { \
+ AsanInitFromRtl(); \
+ } \
+ } while (0)
+
+} // namespace __asan
+
+// There is no general interception at all on Fuchsia.
+// Only the functions in asan_interceptors_memintrinsics.h are
+// really defined to replace libc functions.
+#if !SANITIZER_FUCHSIA
+
// Use macro to describe if specific function should be
// intercepted on a given platform.
#if !SANITIZER_WINDOWS
@@ -32,7 +53,7 @@
# define ASAN_INTERCEPT_FORK 0
#endif
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 1
#else
# define ASAN_USE_ALIAS_ATTRIBUTE_FOR_INDEX 0
@@ -45,15 +66,15 @@
#endif
#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 1
+# define ASAN_INTERCEPT_SIGLONGJMP 1
#else
-# define ASAN_INTERCEPT_SIGNAL_AND_SIGACTION 0
+# define ASAN_INTERCEPT_SIGLONGJMP 0
#endif
-#if !SANITIZER_WINDOWS
-# define ASAN_INTERCEPT_SIGLONGJMP 1
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+# define ASAN_INTERCEPT___LONGJMP_CHK 1
#else
-# define ASAN_INTERCEPT_SIGLONGJMP 0
+# define ASAN_INTERCEPT___LONGJMP_CHK 0
#endif
// Android bug: https://code.google.com/p/android/issues/detail?id=61799
@@ -77,8 +98,6 @@
#endif
DECLARE_REAL(int, memcmp, const void *a1, const void *a2, uptr size)
-DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
-DECLARE_REAL(void*, memset, void *block, int c, uptr size)
DECLARE_REAL(char*, strchr, const char *str, int c)
DECLARE_REAL(SIZE_T, strlen, const char *s)
DECLARE_REAL(char*, strncpy, char *to, const char *from, uptr size)
@@ -105,18 +124,6 @@ DECLARE_REAL(int, sigaction, int signum, const struct sigaction *act,
#define ASAN_INTERCEPT_FUNC(name)
#endif // SANITIZER_MAC
-namespace __asan {
-
-void InitializeAsanInterceptors();
-void InitializePlatformInterceptors();
-
-#define ENSURE_ASAN_INITED() do { \
- CHECK(!asan_init_is_running); \
- if (UNLIKELY(!asan_inited)) { \
- AsanInitFromRtl(); \
- } \
-} while (0)
-
-} // namespace __asan
+#endif // !SANITIZER_FUCHSIA
#endif // ASAN_INTERCEPTORS_H
diff --git a/libsanitizer/asan/asan_interceptors_memintrinsics.cc b/libsanitizer/asan/asan_interceptors_memintrinsics.cc
new file mode 100644
index 0000000..16de54c
--- /dev/null
+++ b/libsanitizer/asan/asan_interceptors_memintrinsics.cc
@@ -0,0 +1,42 @@
+//===-- asan_interceptors_memintrinsics.cc --------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan versions of memcpy, memmove, and memset.
+//===---------------------------------------------------------------------===//
+
+#include "asan_interceptors_memintrinsics.h"
+#include "asan_report.h"
+#include "asan_stack.h"
+#include "asan_suppressions.h"
+
+using namespace __asan; // NOLINT
+
+void *__asan_memcpy(void *to, const void *from, uptr size) {
+ ASAN_MEMCPY_IMPL(nullptr, to, from, size);
+}
+
+void *__asan_memset(void *block, int c, uptr size) {
+ ASAN_MEMSET_IMPL(nullptr, block, c, size);
+}
+
+void *__asan_memmove(void *to, const void *from, uptr size) {
+ ASAN_MEMMOVE_IMPL(nullptr, to, from, size);
+}
+
+#if SANITIZER_FUCHSIA
+
+// Fuchsia doesn't use sanitizer_common_interceptors.inc, but the only
+// things there it wants are these three. Just define them as aliases
+// here rather than repeating the contents.
+
+decltype(memcpy) memcpy[[gnu::alias("__asan_memcpy")]];
+decltype(memmove) memmove[[gnu::alias("__asan_memmove")]];
+decltype(memset) memset[[gnu::alias("__asan_memset")]];
+
+#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/asan/asan_interceptors_memintrinsics.h b/libsanitizer/asan/asan_interceptors_memintrinsics.h
new file mode 100644
index 0000000..1dc4d64
--- /dev/null
+++ b/libsanitizer/asan/asan_interceptors_memintrinsics.h
@@ -0,0 +1,146 @@
+//===-- asan_interceptors_memintrinsics.h -----------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// ASan-private header for asan_memintrin.cc
+//===---------------------------------------------------------------------===//
+#ifndef ASAN_MEMINTRIN_H
+#define ASAN_MEMINTRIN_H
+
+#include "asan_interface_internal.h"
+#include "asan_internal.h"
+#include "asan_mapping.h"
+#include "interception/interception.h"
+
+DECLARE_REAL(void*, memcpy, void *to, const void *from, uptr size)
+DECLARE_REAL(void*, memset, void *block, int c, uptr size)
+
+namespace __asan {
+
+// Return true if we can quickly decide that the region is unpoisoned.
+// We assume that a redzone is at least 16 bytes.
+static inline bool QuickCheckForUnpoisonedRegion(uptr beg, uptr size) {
+ if (size == 0) return true;
+ if (size <= 32)
+ return !AddressIsPoisoned(beg) &&
+ !AddressIsPoisoned(beg + size - 1) &&
+ !AddressIsPoisoned(beg + size / 2);
+ if (size <= 64)
+ return !AddressIsPoisoned(beg) &&
+ !AddressIsPoisoned(beg + size / 4) &&
+ !AddressIsPoisoned(beg + size - 1) &&
+ !AddressIsPoisoned(beg + 3 * size / 4) &&
+ !AddressIsPoisoned(beg + size / 2);
+ return false;
+}
+
+struct AsanInterceptorContext {
+ const char *interceptor_name;
+};
+
+// We implement ACCESS_MEMORY_RANGE, ASAN_READ_RANGE,
+// and ASAN_WRITE_RANGE as macro instead of function so
+// that no extra frames are created, and stack trace contains
+// relevant information only.
+// We check all shadow bytes.
+#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite) do { \
+ uptr __offset = (uptr)(offset); \
+ uptr __size = (uptr)(size); \
+ uptr __bad = 0; \
+ if (__offset > __offset + __size) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
+ } \
+ if (!QuickCheckForUnpoisonedRegion(__offset, __size) && \
+ (__bad = __asan_region_is_poisoned(__offset, __size))) { \
+ AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx; \
+ bool suppressed = false; \
+ if (_ctx) { \
+ suppressed = IsInterceptorSuppressed(_ctx->interceptor_name); \
+ if (!suppressed && HaveStackTraceBasedSuppressions()) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ suppressed = IsStackTraceSuppressed(&stack); \
+ } \
+ } \
+ if (!suppressed) { \
+ GET_CURRENT_PC_BP_SP; \
+ ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false);\
+ } \
+ } \
+ } while (0)
+
+// memcpy is called during __asan_init() from the internals of printf(...).
+// We do not treat memcpy with to==from as a bug.
+// See http://llvm.org/bugs/show_bug.cgi?id=11763.
+#define ASAN_MEMCPY_IMPL(ctx, to, from, size) \
+ do { \
+ if (UNLIKELY(!asan_inited)) return internal_memcpy(to, from, size); \
+ if (asan_init_is_running) { \
+ return REAL(memcpy)(to, from, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ if (to != from) { \
+ CHECK_RANGES_OVERLAP("memcpy", to, size, from, size); \
+ } \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return REAL(memcpy)(to, from, size); \
+ } while (0)
+
+// memset is called inside Printf.
+#define ASAN_MEMSET_IMPL(ctx, block, c, size) \
+ do { \
+ if (UNLIKELY(!asan_inited)) return internal_memset(block, c, size); \
+ if (asan_init_is_running) { \
+ return REAL(memset)(block, c, size); \
+ } \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_WRITE_RANGE(ctx, block, size); \
+ } \
+ return REAL(memset)(block, c, size); \
+ } while (0)
+
+#define ASAN_MEMMOVE_IMPL(ctx, to, from, size) \
+ do { \
+ if (UNLIKELY(!asan_inited)) return internal_memmove(to, from, size); \
+ ENSURE_ASAN_INITED(); \
+ if (flags()->replace_intrin) { \
+ ASAN_READ_RANGE(ctx, from, size); \
+ ASAN_WRITE_RANGE(ctx, to, size); \
+ } \
+ return internal_memmove(to, from, size); \
+ } while (0)
+
+#define ASAN_READ_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, false)
+#define ASAN_WRITE_RANGE(ctx, offset, size) \
+ ACCESS_MEMORY_RANGE(ctx, offset, size, true)
+
+// Behavior of functions like "memcpy" or "strcpy" is undefined
+// if memory intervals overlap. We report error in this case.
+// Macro is used to avoid creation of new frames.
+static inline bool RangesOverlap(const char *offset1, uptr length1,
+ const char *offset2, uptr length2) {
+ return !((offset1 + length1 <= offset2) || (offset2 + length2 <= offset1));
+}
+#define CHECK_RANGES_OVERLAP(name, _offset1, length1, _offset2, length2) do { \
+ const char *offset1 = (const char*)_offset1; \
+ const char *offset2 = (const char*)_offset2; \
+ if (RangesOverlap(offset1, length1, offset2, length2)) { \
+ GET_STACK_TRACE_FATAL_HERE; \
+ ReportStringFunctionMemoryRangesOverlap(name, offset1, length1, \
+ offset2, length2, &stack); \
+ } \
+} while (0)
+
+} // namespace __asan
+
+#endif // ASAN_MEMINTRIN_H
diff --git a/libsanitizer/asan/asan_interface.inc b/libsanitizer/asan/asan_interface.inc
new file mode 100644
index 0000000..b2fcde1
--- /dev/null
+++ b/libsanitizer/asan/asan_interface.inc
@@ -0,0 +1,167 @@
+//===-- asan_interface.inc ------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Asan interface list.
+//===----------------------------------------------------------------------===//
+INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
+INTERFACE_FUNCTION(__asan_address_is_poisoned)
+INTERFACE_FUNCTION(__asan_after_dynamic_init)
+INTERFACE_FUNCTION(__asan_alloca_poison)
+INTERFACE_FUNCTION(__asan_allocas_unpoison)
+INTERFACE_FUNCTION(__asan_before_dynamic_init)
+INTERFACE_FUNCTION(__asan_describe_address)
+INTERFACE_FUNCTION(__asan_exp_load1)
+INTERFACE_FUNCTION(__asan_exp_load2)
+INTERFACE_FUNCTION(__asan_exp_load4)
+INTERFACE_FUNCTION(__asan_exp_load8)
+INTERFACE_FUNCTION(__asan_exp_load16)
+INTERFACE_FUNCTION(__asan_exp_loadN)
+INTERFACE_FUNCTION(__asan_exp_store1)
+INTERFACE_FUNCTION(__asan_exp_store2)
+INTERFACE_FUNCTION(__asan_exp_store4)
+INTERFACE_FUNCTION(__asan_exp_store8)
+INTERFACE_FUNCTION(__asan_exp_store16)
+INTERFACE_FUNCTION(__asan_exp_storeN)
+INTERFACE_FUNCTION(__asan_get_alloc_stack)
+INTERFACE_FUNCTION(__asan_get_current_fake_stack)
+INTERFACE_FUNCTION(__asan_get_free_stack)
+INTERFACE_FUNCTION(__asan_get_report_access_size)
+INTERFACE_FUNCTION(__asan_get_report_access_type)
+INTERFACE_FUNCTION(__asan_get_report_address)
+INTERFACE_FUNCTION(__asan_get_report_bp)
+INTERFACE_FUNCTION(__asan_get_report_description)
+INTERFACE_FUNCTION(__asan_get_report_pc)
+INTERFACE_FUNCTION(__asan_get_report_sp)
+INTERFACE_FUNCTION(__asan_get_shadow_mapping)
+INTERFACE_FUNCTION(__asan_handle_no_return)
+INTERFACE_FUNCTION(__asan_init)
+INTERFACE_FUNCTION(__asan_load_cxx_array_cookie)
+INTERFACE_FUNCTION(__asan_load1)
+INTERFACE_FUNCTION(__asan_load2)
+INTERFACE_FUNCTION(__asan_load4)
+INTERFACE_FUNCTION(__asan_load8)
+INTERFACE_FUNCTION(__asan_load16)
+INTERFACE_FUNCTION(__asan_loadN)
+INTERFACE_FUNCTION(__asan_load1_noabort)
+INTERFACE_FUNCTION(__asan_load2_noabort)
+INTERFACE_FUNCTION(__asan_load4_noabort)
+INTERFACE_FUNCTION(__asan_load8_noabort)
+INTERFACE_FUNCTION(__asan_load16_noabort)
+INTERFACE_FUNCTION(__asan_loadN_noabort)
+INTERFACE_FUNCTION(__asan_locate_address)
+INTERFACE_FUNCTION(__asan_memcpy)
+INTERFACE_FUNCTION(__asan_memmove)
+INTERFACE_FUNCTION(__asan_memset)
+INTERFACE_FUNCTION(__asan_poison_cxx_array_cookie)
+INTERFACE_FUNCTION(__asan_poison_intra_object_redzone)
+INTERFACE_FUNCTION(__asan_poison_memory_region)
+INTERFACE_FUNCTION(__asan_poison_stack_memory)
+INTERFACE_FUNCTION(__asan_print_accumulated_stats)
+INTERFACE_FUNCTION(__asan_region_is_poisoned)
+INTERFACE_FUNCTION(__asan_register_globals)
+INTERFACE_FUNCTION(__asan_register_elf_globals)
+INTERFACE_FUNCTION(__asan_register_image_globals)
+INTERFACE_FUNCTION(__asan_report_error)
+INTERFACE_FUNCTION(__asan_report_exp_load1)
+INTERFACE_FUNCTION(__asan_report_exp_load2)
+INTERFACE_FUNCTION(__asan_report_exp_load4)
+INTERFACE_FUNCTION(__asan_report_exp_load8)
+INTERFACE_FUNCTION(__asan_report_exp_load16)
+INTERFACE_FUNCTION(__asan_report_exp_load_n)
+INTERFACE_FUNCTION(__asan_report_exp_store1)
+INTERFACE_FUNCTION(__asan_report_exp_store2)
+INTERFACE_FUNCTION(__asan_report_exp_store4)
+INTERFACE_FUNCTION(__asan_report_exp_store8)
+INTERFACE_FUNCTION(__asan_report_exp_store16)
+INTERFACE_FUNCTION(__asan_report_exp_store_n)
+INTERFACE_FUNCTION(__asan_report_load1)
+INTERFACE_FUNCTION(__asan_report_load2)
+INTERFACE_FUNCTION(__asan_report_load4)
+INTERFACE_FUNCTION(__asan_report_load8)
+INTERFACE_FUNCTION(__asan_report_load16)
+INTERFACE_FUNCTION(__asan_report_load_n)
+INTERFACE_FUNCTION(__asan_report_load1_noabort)
+INTERFACE_FUNCTION(__asan_report_load2_noabort)
+INTERFACE_FUNCTION(__asan_report_load4_noabort)
+INTERFACE_FUNCTION(__asan_report_load8_noabort)
+INTERFACE_FUNCTION(__asan_report_load16_noabort)
+INTERFACE_FUNCTION(__asan_report_load_n_noabort)
+INTERFACE_FUNCTION(__asan_report_present)
+INTERFACE_FUNCTION(__asan_report_store1)
+INTERFACE_FUNCTION(__asan_report_store2)
+INTERFACE_FUNCTION(__asan_report_store4)
+INTERFACE_FUNCTION(__asan_report_store8)
+INTERFACE_FUNCTION(__asan_report_store16)
+INTERFACE_FUNCTION(__asan_report_store_n)
+INTERFACE_FUNCTION(__asan_report_store1_noabort)
+INTERFACE_FUNCTION(__asan_report_store2_noabort)
+INTERFACE_FUNCTION(__asan_report_store4_noabort)
+INTERFACE_FUNCTION(__asan_report_store8_noabort)
+INTERFACE_FUNCTION(__asan_report_store16_noabort)
+INTERFACE_FUNCTION(__asan_report_store_n_noabort)
+INTERFACE_FUNCTION(__asan_set_death_callback)
+INTERFACE_FUNCTION(__asan_set_error_report_callback)
+INTERFACE_FUNCTION(__asan_set_shadow_00)
+INTERFACE_FUNCTION(__asan_set_shadow_f1)
+INTERFACE_FUNCTION(__asan_set_shadow_f2)
+INTERFACE_FUNCTION(__asan_set_shadow_f3)
+INTERFACE_FUNCTION(__asan_set_shadow_f5)
+INTERFACE_FUNCTION(__asan_set_shadow_f8)
+INTERFACE_FUNCTION(__asan_stack_free_0)
+INTERFACE_FUNCTION(__asan_stack_free_1)
+INTERFACE_FUNCTION(__asan_stack_free_2)
+INTERFACE_FUNCTION(__asan_stack_free_3)
+INTERFACE_FUNCTION(__asan_stack_free_4)
+INTERFACE_FUNCTION(__asan_stack_free_5)
+INTERFACE_FUNCTION(__asan_stack_free_6)
+INTERFACE_FUNCTION(__asan_stack_free_7)
+INTERFACE_FUNCTION(__asan_stack_free_8)
+INTERFACE_FUNCTION(__asan_stack_free_9)
+INTERFACE_FUNCTION(__asan_stack_free_10)
+INTERFACE_FUNCTION(__asan_stack_malloc_0)
+INTERFACE_FUNCTION(__asan_stack_malloc_1)
+INTERFACE_FUNCTION(__asan_stack_malloc_2)
+INTERFACE_FUNCTION(__asan_stack_malloc_3)
+INTERFACE_FUNCTION(__asan_stack_malloc_4)
+INTERFACE_FUNCTION(__asan_stack_malloc_5)
+INTERFACE_FUNCTION(__asan_stack_malloc_6)
+INTERFACE_FUNCTION(__asan_stack_malloc_7)
+INTERFACE_FUNCTION(__asan_stack_malloc_8)
+INTERFACE_FUNCTION(__asan_stack_malloc_9)
+INTERFACE_FUNCTION(__asan_stack_malloc_10)
+INTERFACE_FUNCTION(__asan_store1)
+INTERFACE_FUNCTION(__asan_store2)
+INTERFACE_FUNCTION(__asan_store4)
+INTERFACE_FUNCTION(__asan_store8)
+INTERFACE_FUNCTION(__asan_store16)
+INTERFACE_FUNCTION(__asan_storeN)
+INTERFACE_FUNCTION(__asan_store1_noabort)
+INTERFACE_FUNCTION(__asan_store2_noabort)
+INTERFACE_FUNCTION(__asan_store4_noabort)
+INTERFACE_FUNCTION(__asan_store8_noabort)
+INTERFACE_FUNCTION(__asan_store16_noabort)
+INTERFACE_FUNCTION(__asan_storeN_noabort)
+INTERFACE_FUNCTION(__asan_unpoison_intra_object_redzone)
+INTERFACE_FUNCTION(__asan_unpoison_memory_region)
+INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
+INTERFACE_FUNCTION(__asan_unregister_globals)
+INTERFACE_FUNCTION(__asan_unregister_elf_globals)
+INTERFACE_FUNCTION(__asan_unregister_image_globals)
+INTERFACE_FUNCTION(__asan_version_mismatch_check_v8)
+INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
+INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
+INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
+INTERFACE_FUNCTION(__sanitizer_ptr_sub)
+INTERFACE_FUNCTION(__sanitizer_start_switch_fiber)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
+INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
+INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
+INTERFACE_WEAK_FUNCTION(__asan_default_options)
+INTERFACE_WEAK_FUNCTION(__asan_default_suppressions)
+INTERFACE_WEAK_FUNCTION(__asan_on_error)
diff --git a/libsanitizer/asan/asan_interface_internal.h b/libsanitizer/asan/asan_interface_internal.h
index 05605a8..be9605d 100644
--- a/libsanitizer/asan/asan_interface_internal.h
+++ b/libsanitizer/asan/asan_interface_internal.h
@@ -65,6 +65,11 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_unregister_image_globals(uptr *flag);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_register_elf_globals(uptr *flag, void *start, void *stop);
+ SANITIZER_INTERFACE_ATTRIBUTE
+ void __asan_unregister_elf_globals(uptr *flag, void *start, void *stop);
+
// These two functions should be called by the instrumented code.
// 'globals' is an array of structures describing 'n' globals.
SANITIZER_INTERFACE_ATTRIBUTE
@@ -163,12 +168,12 @@ extern "C" {
void __asan_set_error_report_callback(void (*callback)(const char*));
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ void __asan_on_error();
+ void __asan_on_error();
SANITIZER_INTERFACE_ATTRIBUTE void __asan_print_accumulated_stats();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ const char* __asan_default_options();
+ const char* __asan_default_options();
SANITIZER_INTERFACE_ATTRIBUTE
extern uptr __asan_shadow_memory_dynamic_address;
@@ -240,6 +245,9 @@ extern "C" {
void __asan_alloca_poison(uptr addr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE
void __asan_allocas_unpoison(uptr top, uptr bottom);
+
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ const char* __asan_default_suppressions();
} // extern "C"
#endif // ASAN_INTERFACE_INTERNAL_H
diff --git a/libsanitizer/asan/asan_internal.h b/libsanitizer/asan/asan_internal.h
index 15a28ff..a3fe755 100644
--- a/libsanitizer/asan/asan_internal.h
+++ b/libsanitizer/asan/asan_internal.h
@@ -34,7 +34,7 @@
// If set, values like allocator chunk size, as well as defaults for some flags
// will be changed towards less memory overhead.
#ifndef ASAN_LOW_MEMORY
-# if SANITIZER_IOS || (SANITIZER_WORDSIZE == 32)
+# if SANITIZER_IOS || SANITIZER_ANDROID
# define ASAN_LOW_MEMORY 1
# else
# define ASAN_LOW_MEMORY 0
@@ -62,21 +62,29 @@ void AsanInitFromRtl();
// asan_win.cc
void InitializePlatformExceptionHandlers();
-
-// asan_win.cc / asan_posix.cc
-const char *DescribeSignalOrException(int signo);
+// Returns whether an address is a valid allocated system heap block.
+// 'addr' must point to the beginning of the block.
+bool IsSystemHeapAddress(uptr addr);
// asan_rtl.cc
+void PrintAddressSpaceLayout();
void NORETURN ShowStatsAndAbort();
+// asan_shadow_setup.cc
+void InitializeShadowMemory();
+
// asan_malloc_linux.cc / asan_malloc_mac.cc
void ReplaceSystemMalloc();
// asan_linux.cc / asan_mac.cc / asan_win.cc
+uptr FindDynamicShadowStart();
void *AsanDoesNotSupportStaticLinkage();
void AsanCheckDynamicRTPrereqs();
void AsanCheckIncompatibleRT();
+// asan_thread.cc
+AsanThread *CreateMainThread();
+
// Support function for __asan_(un)register_image_globals. Searches for the
// loaded image containing `needle' and then enumerates all global metadata
// structures declared in that image, applying `op' (e.g.,
@@ -101,17 +109,6 @@ void *AsanDlSymNext(const char *sym);
void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name);
-// Platform-specific options.
-#if SANITIZER_MAC
-bool PlatformHasDifferentMemcpyAndMemmove();
-# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
- (PlatformHasDifferentMemcpyAndMemmove())
-#elif SANITIZER_WINDOWS64
-# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
-#else
-# define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
-#endif // SANITIZER_MAC
-
// Add convenient macro for interface functions that may be represented as
// weak hooks.
#define ASAN_MALLOC_HOOK(ptr, size) \
diff --git a/libsanitizer/asan/asan_linux.cc b/libsanitizer/asan/asan_linux.cc
index 9f058df..a43243e 100644
--- a/libsanitizer/asan/asan_linux.cc
+++ b/libsanitizer/asan/asan_linux.cc
@@ -11,7 +11,7 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#include "asan_interceptors.h"
#include "asan_internal.h"
@@ -40,6 +40,10 @@
#if SANITIZER_ANDROID || SANITIZER_FREEBSD
#include <ucontext.h>
extern "C" void* _DYNAMIC;
+#elif SANITIZER_NETBSD
+#include <link_elf.h>
+#include <ucontext.h>
+extern Elf_Dyn _DYNAMIC;
#else
#include <sys/ucontext.h>
#include <link.h>
@@ -68,12 +72,18 @@ namespace __asan {
void InitializePlatformInterceptors() {}
void InitializePlatformExceptionHandlers() {}
+bool IsSystemHeapAddress (uptr addr) { return false; }
void *AsanDoesNotSupportStaticLinkage() {
// This will fail to link with -static.
return &_DYNAMIC; // defined in link.h
}
+uptr FindDynamicShadowStart() {
+ UNREACHABLE("FindDynamicShadowStart is not available");
+ return 0;
+}
+
void AsanApplyToGlobals(globals_op_fptr op, const void *needle) {
UNIMPLEMENTED();
}
@@ -93,6 +103,15 @@ static int FindFirstDSOCallback(struct dl_phdr_info *info, size_t size,
if (internal_strncmp(info->dlpi_name, "linux-", sizeof("linux-") - 1) == 0)
return 0;
+#if SANITIZER_NETBSD
+ // Ignore first entry (the main program)
+ char **p = (char **)data;
+ if (!(*p)) {
+ *p = (char *)-1;
+ return 0;
+ }
+#endif
+
*(const char **)data = info->dlpi_name;
return 1;
}
@@ -108,7 +127,7 @@ static void ReportIncompatibleRT() {
}
void AsanCheckDynamicRTPrereqs() {
- if (!ASAN_DYNAMIC)
+ if (!ASAN_DYNAMIC || !flags()->verify_asan_link_order)
return;
// Ensure that dynamic RT is the first DSO in the list
@@ -137,9 +156,9 @@ void AsanCheckIncompatibleRT() {
// system libraries, causing crashes later in ASan initialization.
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
char filename[128];
- while (proc_maps.Next(nullptr, nullptr, nullptr, filename,
- sizeof(filename), nullptr)) {
- if (IsDynamicRTName(filename)) {
+ MemoryMappedSegment segment(filename, sizeof(filename));
+ while (proc_maps.Next(&segment)) {
+ if (IsDynamicRTName(segment.filename)) {
Report("Your application is linked against "
"incompatible ASan runtimes.\n");
Die();
@@ -171,4 +190,4 @@ void *AsanDlSymNext(const char *sym) {
} // namespace __asan
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
diff --git a/libsanitizer/asan/asan_mac.cc b/libsanitizer/asan/asan_mac.cc
index 4bf79be..45c66d8 100644
--- a/libsanitizer/asan/asan_mac.cc
+++ b/libsanitizer/asan/asan_mac.cc
@@ -46,21 +46,36 @@ namespace __asan {
void InitializePlatformInterceptors() {}
void InitializePlatformExceptionHandlers() {}
-
-bool PlatformHasDifferentMemcpyAndMemmove() {
- // On OS X 10.7 memcpy() and memmove() are both resolved
- // into memmove$VARIANT$sse42.
- // See also https://github.com/google/sanitizers/issues/34.
- // TODO(glider): need to check dynamically that memcpy() and memmove() are
- // actually the same function.
- return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
-}
+bool IsSystemHeapAddress (uptr addr) { return false; }
// No-op. Mac does not support static linkage anyway.
void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
+uptr FindDynamicShadowStart() {
+ uptr granularity = GetMmapGranularity();
+ uptr alignment = 8 * granularity;
+ uptr left_padding = granularity;
+ uptr space_size = kHighShadowEnd + left_padding;
+
+ uptr largest_gap_found = 0;
+ uptr shadow_start = FindAvailableMemoryRange(space_size, alignment,
+ granularity, &largest_gap_found);
+ // If the shadow doesn't fit, restrict the address space to make it fit.
+ if (shadow_start == 0) {
+ uptr new_max_vm = RoundDownTo(largest_gap_found << SHADOW_SCALE, alignment);
+ RestrictMemoryToMaxAddress(new_max_vm);
+ kHighMemEnd = new_max_vm - 1;
+ space_size = kHighShadowEnd + left_padding;
+ shadow_start =
+ FindAvailableMemoryRange(space_size, alignment, granularity, nullptr);
+ }
+ CHECK_NE((uptr)0, shadow_start);
+ CHECK(IsAligned(shadow_start, alignment));
+ return shadow_start;
+}
+
// No-op. Mac does not support static linkage anyway.
void AsanCheckDynamicRTPrereqs() {}
@@ -145,7 +160,8 @@ void asan_register_worker_thread(int parent_tid, StackTrace *stack) {
t = AsanThread::Create(/* start_routine */ nullptr, /* arg */ nullptr,
parent_tid, stack, /* detached */ true);
t->Init();
- asanThreadRegistry().StartThread(t->tid(), 0, 0);
+ asanThreadRegistry().StartThread(t->tid(), GetTid(),
+ /* workerthread */ true, 0);
SetCurrentThread(t);
}
}
diff --git a/libsanitizer/asan/asan_malloc_linux.cc b/libsanitizer/asan/asan_malloc_linux.cc
index cc50a38..19f45fc 100644
--- a/libsanitizer/asan/asan_malloc_linux.cc
+++ b/libsanitizer/asan/asan_malloc_linux.cc
@@ -13,7 +13,8 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \
+ SANITIZER_NETBSD
#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "asan_allocator.h"
@@ -28,9 +29,9 @@ static uptr allocated_for_dlsym;
static const uptr kDlsymAllocPoolSize = 1024;
static uptr alloc_memory_for_dlsym[kDlsymAllocPoolSize];
-static bool IsInDlsymAllocPool(const void *ptr) {
+static INLINE bool IsInDlsymAllocPool(const void *ptr) {
uptr off = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
- return off < sizeof(alloc_memory_for_dlsym);
+ return off < allocated_for_dlsym * sizeof(alloc_memory_for_dlsym[0]);
}
static void *AllocateFromLocalPool(uptr size_in_bytes) {
@@ -41,6 +42,26 @@ static void *AllocateFromLocalPool(uptr size_in_bytes) {
return mem;
}
+static INLINE bool MaybeInDlsym() {
+ // Fuchsia doesn't use dlsym-based interceptors.
+ return !SANITIZER_FUCHSIA && asan_init_is_running;
+}
+
+static void *ReallocFromLocalPool(void *ptr, uptr size) {
+ const uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
+ const uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
+ void *new_ptr;
+ if (UNLIKELY(MaybeInDlsym())) {
+ new_ptr = AllocateFromLocalPool(size);
+ } else {
+ ENSURE_ASAN_INITED();
+ GET_STACK_TRACE_MALLOC;
+ new_ptr = asan_malloc(size, &stack);
+ }
+ internal_memcpy(new_ptr, ptr, copy_size);
+ return new_ptr;
+}
+
INTERCEPTOR(void, free, void *ptr) {
GET_STACK_TRACE_FREE;
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
@@ -48,63 +69,61 @@ INTERCEPTOR(void, free, void *ptr) {
asan_free(ptr, &stack, FROM_MALLOC);
}
+#if SANITIZER_INTERCEPT_CFREE
INTERCEPTOR(void, cfree, void *ptr) {
GET_STACK_TRACE_FREE;
if (UNLIKELY(IsInDlsymAllocPool(ptr)))
return;
asan_free(ptr, &stack, FROM_MALLOC);
}
+#endif // SANITIZER_INTERCEPT_CFREE
INTERCEPTOR(void*, malloc, uptr size) {
- if (UNLIKELY(!asan_inited))
+ if (UNLIKELY(MaybeInDlsym()))
// Hack: dlsym calls malloc before REAL(malloc) is retrieved from dlsym.
return AllocateFromLocalPool(size);
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
}
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
- if (UNLIKELY(!asan_inited))
+ if (UNLIKELY(MaybeInDlsym()))
// Hack: dlsym calls calloc before REAL(calloc) is retrieved from dlsym.
return AllocateFromLocalPool(nmemb * size);
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
return asan_calloc(nmemb, size, &stack);
}
INTERCEPTOR(void*, realloc, void *ptr, uptr size) {
+ if (UNLIKELY(IsInDlsymAllocPool(ptr)))
+ return ReallocFromLocalPool(ptr, size);
+ if (UNLIKELY(MaybeInDlsym()))
+ return AllocateFromLocalPool(size);
+ ENSURE_ASAN_INITED();
GET_STACK_TRACE_MALLOC;
- if (UNLIKELY(IsInDlsymAllocPool(ptr))) {
- uptr offset = (uptr)ptr - (uptr)alloc_memory_for_dlsym;
- uptr copy_size = Min(size, kDlsymAllocPoolSize - offset);
- void *new_ptr;
- if (UNLIKELY(!asan_inited)) {
- new_ptr = AllocateFromLocalPool(size);
- } else {
- copy_size = size;
- new_ptr = asan_malloc(copy_size, &stack);
- }
- internal_memcpy(new_ptr, ptr, copy_size);
- return new_ptr;
- }
return asan_realloc(ptr, size, &stack);
}
+#if SANITIZER_INTERCEPT_MEMALIGN
INTERCEPTOR(void*, memalign, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC;
return asan_memalign(boundary, size, &stack, FROM_MALLOC);
}
-INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
- GET_STACK_TRACE_MALLOC;
- return asan_memalign(boundary, size, &stack, FROM_MALLOC);
-}
-
INTERCEPTOR(void*, __libc_memalign, uptr boundary, uptr size) {
GET_STACK_TRACE_MALLOC;
void *res = asan_memalign(boundary, size, &stack, FROM_MALLOC);
DTLS_on_libc_memalign(res, size);
return res;
}
+#endif // SANITIZER_INTERCEPT_MEMALIGN
+
+INTERCEPTOR(void*, aligned_alloc, uptr boundary, uptr size) {
+ GET_STACK_TRACE_MALLOC;
+ return asan_memalign(boundary, size, &stack, FROM_MALLOC);
+}
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
GET_CURRENT_PC_BP_SP;
@@ -112,6 +131,7 @@ INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
return asan_malloc_usable_size(ptr, pc, bp);
}
+#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
// We avoid including malloc.h for portability reasons.
// man mallinfo says the fields are "long", but the implementation uses int.
// It doesn't matter much -- we just need to make sure that the libc's mallinfo
@@ -129,6 +149,7 @@ INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
INTERCEPTOR(int, mallopt, int cmd, int value) {
return -1;
}
+#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
GET_STACK_TRACE_MALLOC;
@@ -141,10 +162,12 @@ INTERCEPTOR(void*, valloc, uptr size) {
return asan_valloc(size, &stack);
}
+#if SANITIZER_INTERCEPT_PVALLOC
INTERCEPTOR(void*, pvalloc, uptr size) {
GET_STACK_TRACE_MALLOC;
return asan_pvalloc(size, &stack);
}
+#endif // SANITIZER_INTERCEPT_PVALLOC
INTERCEPTOR(void, malloc_stats, void) {
__asan_print_accumulated_stats();
@@ -210,4 +233,5 @@ void ReplaceSystemMalloc() {
} // namespace __asan
#endif // SANITIZER_ANDROID
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX ||
+ // SANITIZER_NETBSD
diff --git a/libsanitizer/asan/asan_malloc_win.cc b/libsanitizer/asan/asan_malloc_win.cc
index f38cd05..017481d 100644
--- a/libsanitizer/asan/asan_malloc_win.cc
+++ b/libsanitizer/asan/asan_malloc_win.cc
@@ -54,11 +54,6 @@ void _free_base(void *ptr) {
}
ALLOCATION_FUNCTION_ATTRIBUTE
-void cfree(void *ptr) {
- CHECK(!"cfree() should not be used on Windows");
-}
-
-ALLOCATION_FUNCTION_ATTRIBUTE
void *malloc(size_t size) {
GET_STACK_TRACE_MALLOC;
return asan_malloc(size, &stack);
@@ -103,7 +98,7 @@ void *realloc(void *ptr, size_t size) {
ALLOCATION_FUNCTION_ATTRIBUTE
void *_realloc_dbg(void *ptr, size_t size, int) {
- CHECK(!"_realloc_dbg should not exist!");
+ UNREACHABLE("_realloc_dbg should not exist!");
return 0;
}
diff --git a/libsanitizer/asan/asan_mapping.h b/libsanitizer/asan/asan_mapping.h
index b9fa5f7..5496df6 100644
--- a/libsanitizer/asan/asan_mapping.h
+++ b/libsanitizer/asan/asan_mapping.h
@@ -113,6 +113,13 @@
// || `[0x40000000, 0x47ffffff]` || LowShadow ||
// || `[0x00000000, 0x3fffffff]` || LowMem ||
//
+// Shadow mapping on NetBSD/x86-64 with SHADOW_OFFSET == 0x400000000000:
+// || `[0x4feffffffe01, 0x7f7ffffff000]` || HighMem ||
+// || `[0x49fdffffffc0, 0x4feffffffe00]` || HighShadow ||
+// || `[0x480000000000, 0x49fdffffffbf]` || ShadowGap ||
+// || `[0x400000000000, 0x47ffffffffff]` || LowShadow ||
+// || `[0x000000000000, 0x3fffffffffff]` || LowMem ||
+//
// Default Windows/i386 mapping:
// (the exact location of HighShadow/HighMem may vary depending
// on WoW64, /LARGEADDRESSAWARE, etc).
@@ -138,12 +145,14 @@ static const u64 kPPC64_ShadowOffset64 = 1ULL << 41;
static const u64 kSystemZ_ShadowOffset64 = 1ULL << 52;
static const u64 kFreeBSD_ShadowOffset32 = 1ULL << 30; // 0x40000000
static const u64 kFreeBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
+static const u64 kNetBSD_ShadowOffset64 = 1ULL << 46; // 0x400000000000
static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
#define SHADOW_SCALE kDefaultShadowScale
-
-#if SANITIZER_WORDSIZE == 32
+#if SANITIZER_FUCHSIA
+# define SHADOW_OFFSET (0)
+#elif SANITIZER_WORDSIZE == 32
# if SANITIZER_ANDROID
# define SHADOW_OFFSET (0)
# elif defined(__mips__)
@@ -176,6 +185,8 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
# define SHADOW_OFFSET kSystemZ_ShadowOffset64
# elif SANITIZER_FREEBSD
# define SHADOW_OFFSET kFreeBSD_ShadowOffset64
+# elif SANITIZER_NETBSD
+# define SHADOW_OFFSET kNetBSD_ShadowOffset64
# elif SANITIZER_MAC
# define SHADOW_OFFSET kDefaultShadowOffset64
# elif defined(__mips64)
@@ -189,7 +200,6 @@ static const u64 kWindowsShadowOffset32 = 3ULL << 28; // 0x30000000
#define SHADOW_GRANULARITY (1ULL << SHADOW_SCALE)
#define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET))
-#define SHADOW_TO_MEM(shadow) (((shadow) - SHADOW_OFFSET) << SHADOW_SCALE)
#define kLowMemBeg 0
#define kLowMemEnd (SHADOW_OFFSET ? SHADOW_OFFSET - 1 : 0)
diff --git a/libsanitizer/asan/asan_memory_profile.cc b/libsanitizer/asan/asan_memory_profile.cc
index 5a25785..42d07c7 100644
--- a/libsanitizer/asan/asan_memory_profile.cc
+++ b/libsanitizer/asan/asan_memory_profile.cc
@@ -30,69 +30,99 @@ struct AllocationSite {
class HeapProfile {
public:
HeapProfile() : allocations_(1024) {}
- void Insert(u32 id, uptr size) {
- total_allocated_ += size;
- total_count_++;
- // Linear lookup will be good enough for most cases (although not all).
- for (uptr i = 0; i < allocations_.size(); i++) {
- if (allocations_[i].id == id) {
- allocations_[i].total_size += size;
- allocations_[i].count++;
- return;
- }
+
+ void ProcessChunk(const AsanChunkView& cv) {
+ if (cv.IsAllocated()) {
+ total_allocated_user_size_ += cv.UsedSize();
+ total_allocated_count_++;
+ u32 id = cv.GetAllocStackId();
+ if (id)
+ Insert(id, cv.UsedSize());
+ } else if (cv.IsQuarantined()) {
+ total_quarantined_user_size_ += cv.UsedSize();
+ total_quarantined_count_++;
+ } else {
+ total_other_count_++;
}
- allocations_.push_back({id, size, 1});
}
- void Print(uptr top_percent) {
+ void Print(uptr top_percent, uptr max_number_of_contexts) {
InternalSort(&allocations_, allocations_.size(),
[](const AllocationSite &a, const AllocationSite &b) {
return a.total_size > b.total_size;
});
- CHECK(total_allocated_);
+ CHECK(total_allocated_user_size_);
uptr total_shown = 0;
- Printf("Live Heap Allocations: %zd bytes from %zd allocations; "
- "showing top %zd%%\n", total_allocated_, total_count_, top_percent);
- for (uptr i = 0; i < allocations_.size(); i++) {
+ Printf("Live Heap Allocations: %zd bytes in %zd chunks; quarantined: "
+ "%zd bytes in %zd chunks; %zd other chunks; total chunks: %zd; "
+ "showing top %zd%% (at most %zd unique contexts)\n",
+ total_allocated_user_size_, total_allocated_count_,
+ total_quarantined_user_size_, total_quarantined_count_,
+ total_other_count_, total_allocated_count_ +
+ total_quarantined_count_ + total_other_count_, top_percent,
+ max_number_of_contexts);
+ for (uptr i = 0; i < Min(allocations_.size(), max_number_of_contexts);
+ i++) {
auto &a = allocations_[i];
Printf("%zd byte(s) (%zd%%) in %zd allocation(s)\n", a.total_size,
- a.total_size * 100 / total_allocated_, a.count);
+ a.total_size * 100 / total_allocated_user_size_, a.count);
StackDepotGet(a.id).Print();
total_shown += a.total_size;
- if (total_shown * 100 / total_allocated_ > top_percent)
+ if (total_shown * 100 / total_allocated_user_size_ > top_percent)
break;
}
}
private:
- uptr total_allocated_ = 0;
- uptr total_count_ = 0;
+ uptr total_allocated_user_size_ = 0;
+ uptr total_allocated_count_ = 0;
+ uptr total_quarantined_user_size_ = 0;
+ uptr total_quarantined_count_ = 0;
+ uptr total_other_count_ = 0;
InternalMmapVector<AllocationSite> allocations_;
+
+ void Insert(u32 id, uptr size) {
+ // Linear lookup will be good enough for most cases (although not all).
+ for (uptr i = 0; i < allocations_.size(); i++) {
+ if (allocations_[i].id == id) {
+ allocations_[i].total_size += size;
+ allocations_[i].count++;
+ return;
+ }
+ }
+ allocations_.push_back({id, size, 1});
+ }
};
static void ChunkCallback(uptr chunk, void *arg) {
- HeapProfile *hp = reinterpret_cast<HeapProfile*>(arg);
- AsanChunkView cv = FindHeapChunkByAllocBeg(chunk);
- if (!cv.IsAllocated()) return;
- u32 id = cv.GetAllocStackId();
- if (!id) return;
- hp->Insert(id, cv.UsedSize());
+ reinterpret_cast<HeapProfile*>(arg)->ProcessChunk(
+ FindHeapChunkByAllocBeg(chunk));
}
static void MemoryProfileCB(const SuspendedThreadsList &suspended_threads_list,
void *argument) {
HeapProfile hp;
__lsan::ForEachChunk(ChunkCallback, &hp);
- hp.Print(reinterpret_cast<uptr>(argument));
+ uptr *Arg = reinterpret_cast<uptr*>(argument);
+ hp.Print(Arg[0], Arg[1]);
+
+ if (Verbosity())
+ __asan_print_accumulated_stats();
}
} // namespace __asan
+#endif // CAN_SANITIZE_LEAKS
+
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_print_memory_profile(uptr top_percent) {
- __sanitizer::StopTheWorld(__asan::MemoryProfileCB, (void*)top_percent);
+void __sanitizer_print_memory_profile(uptr top_percent,
+ uptr max_number_of_contexts) {
+#if CAN_SANITIZE_LEAKS
+ uptr Arg[2];
+ Arg[0] = top_percent;
+ Arg[1] = max_number_of_contexts;
+ __sanitizer::StopTheWorld(__asan::MemoryProfileCB, Arg);
+#endif // CAN_SANITIZE_LEAKS
}
} // extern "C"
-
-#endif // CAN_SANITIZE_LEAKS
diff --git a/libsanitizer/asan/asan_new_delete.cc b/libsanitizer/asan/asan_new_delete.cc
index 2c4642c..e95b528 100644
--- a/libsanitizer/asan/asan_new_delete.cc
+++ b/libsanitizer/asan/asan_new_delete.cc
@@ -23,22 +23,26 @@
// dllexport would normally do. We need to export them in order to make the
// VS2015 dynamic CRT (MD) work.
#if SANITIZER_WINDOWS
-# define CXX_OPERATOR_ATTRIBUTE
-# ifdef _WIN64
-# pragma comment(linker, "/export:??2@YAPEAX_K@Z") // operator new
-# pragma comment(linker, "/export:??3@YAXPEAX@Z") // operator delete
-# pragma comment(linker, "/export:??3@YAXPEAX_K@Z") // sized operator delete
-# pragma comment(linker, "/export:??_U@YAPEAX_K@Z") // operator new[]
-# pragma comment(linker, "/export:??_V@YAXPEAX@Z") // operator delete[]
-# else
-# pragma comment(linker, "/export:??2@YAPAXI@Z") // operator new
-# pragma comment(linker, "/export:??3@YAXPAX@Z") // operator delete
-# pragma comment(linker, "/export:??3@YAXPAXI@Z") // sized operator delete
-# pragma comment(linker, "/export:??_U@YAPAXI@Z") // operator new[]
-# pragma comment(linker, "/export:??_V@YAXPAX@Z") // operator delete[]
-# endif
+#define CXX_OPERATOR_ATTRIBUTE
+#define COMMENT_EXPORT(sym) __pragma(comment(linker, "/export:" sym))
+#ifdef _WIN64
+COMMENT_EXPORT("??2@YAPEAX_K@Z") // operator new
+COMMENT_EXPORT("??2@YAPEAX_KAEBUnothrow_t@std@@@Z") // operator new nothrow
+COMMENT_EXPORT("??3@YAXPEAX@Z") // operator delete
+COMMENT_EXPORT("??3@YAXPEAX_K@Z") // sized operator delete
+COMMENT_EXPORT("??_U@YAPEAX_K@Z") // operator new[]
+COMMENT_EXPORT("??_V@YAXPEAX@Z") // operator delete[]
#else
-# define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
+COMMENT_EXPORT("??2@YAPAXI@Z") // operator new
+COMMENT_EXPORT("??2@YAPAXIABUnothrow_t@std@@@Z") // operator new nothrow
+COMMENT_EXPORT("??3@YAXPAX@Z") // operator delete
+COMMENT_EXPORT("??3@YAXPAXI@Z") // sized operator delete
+COMMENT_EXPORT("??_U@YAPAXI@Z") // operator new[]
+COMMENT_EXPORT("??_V@YAXPAX@Z") // operator delete[]
+#endif
+#undef COMMENT_EXPORT
+#else
+#define CXX_OPERATOR_ATTRIBUTE INTERCEPTOR_ATTRIBUTE
#endif
using namespace __asan; // NOLINT
@@ -61,12 +65,17 @@ struct nothrow_t {};
enum class align_val_t: size_t {};
} // namespace std
-#define OPERATOR_NEW_BODY(type) \
+// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
+#define OPERATOR_NEW_BODY(type, nothrow) \
GET_STACK_TRACE_MALLOC;\
- return asan_memalign(0, size, &stack, type);
-#define OPERATOR_NEW_BODY_ALIGN(type) \
+ void *res = asan_memalign(0, size, &stack, type);\
+ if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
+ return res;
+#define OPERATOR_NEW_BODY_ALIGN(type, nothrow) \
GET_STACK_TRACE_MALLOC;\
- return asan_memalign((uptr)align, size, &stack, type);
+ void *res = asan_memalign((uptr)align, size, &stack, type);\
+ if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM();\
+ return res;
// On OS X it's not enough to just provide our own 'operator new' and
// 'operator delete' implementations, because they're going to be in the
@@ -77,40 +86,42 @@ enum class align_val_t: size_t {};
// OS X we need to intercept them using their mangled names.
#if !SANITIZER_MAC
CXX_OPERATOR_ATTRIBUTE
-void *operator new(size_t size) { OPERATOR_NEW_BODY(FROM_NEW); }
+void *operator new(size_t size)
+{ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE
-void *operator new[](size_t size) { OPERATOR_NEW_BODY(FROM_NEW_BR); }
+void *operator new[](size_t size)
+{ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::nothrow_t const&)
-{ OPERATOR_NEW_BODY(FROM_NEW); }
+{ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::nothrow_t const&)
-{ OPERATOR_NEW_BODY(FROM_NEW_BR); }
+{ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::align_val_t align)
-{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); }
+{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, false /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::align_val_t align)
-{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); }
+{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, false /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE
void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
-{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW); }
+{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW, true /*nothrow*/); }
CXX_OPERATOR_ATTRIBUTE
void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
-{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR); }
+{ OPERATOR_NEW_BODY_ALIGN(FROM_NEW_BR, true /*nothrow*/); }
#else // SANITIZER_MAC
INTERCEPTOR(void *, _Znwm, size_t size) {
- OPERATOR_NEW_BODY(FROM_NEW);
+ OPERATOR_NEW_BODY(FROM_NEW, false /*nothrow*/);
}
INTERCEPTOR(void *, _Znam, size_t size) {
- OPERATOR_NEW_BODY(FROM_NEW_BR);
+ OPERATOR_NEW_BODY(FROM_NEW_BR, false /*nothrow*/);
}
INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
- OPERATOR_NEW_BODY(FROM_NEW);
+ OPERATOR_NEW_BODY(FROM_NEW, true /*nothrow*/);
}
INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&) {
- OPERATOR_NEW_BODY(FROM_NEW_BR);
+ OPERATOR_NEW_BODY(FROM_NEW_BR, true /*nothrow*/);
}
#endif
diff --git a/libsanitizer/asan/asan_poisoning.cc b/libsanitizer/asan/asan_poisoning.cc
index 8fe2bd4..15cd8ea 100644
--- a/libsanitizer/asan/asan_poisoning.cc
+++ b/libsanitizer/asan/asan_poisoning.cc
@@ -62,12 +62,9 @@ struct ShadowSegmentEndpoint {
};
void FlushUnneededASanShadowMemory(uptr p, uptr size) {
- // Since asan's mapping is compacting, the shadow chunk may be
- // not page-aligned, so we only flush the page-aligned portion.
- uptr page_size = GetPageSizeCached();
- uptr shadow_beg = RoundUpTo(MemToShadow(p), page_size);
- uptr shadow_end = RoundDownTo(MemToShadow(p + size), page_size);
- ReleaseMemoryToOS(shadow_beg, shadow_end - shadow_beg);
+ // Since asan's mapping is compacting, the shadow chunk may be
+ // not page-aligned, so we only flush the page-aligned portion.
+ ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size));
}
void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) {
@@ -410,7 +407,7 @@ const void *__sanitizer_contiguous_container_find_bad_address(
// ending with end.
uptr kMaxRangeToCheck = 32;
uptr r1_beg = beg;
- uptr r1_end = Min(end + kMaxRangeToCheck, mid);
+ uptr r1_end = Min(beg + kMaxRangeToCheck, mid);
uptr r2_beg = Max(beg, mid - kMaxRangeToCheck);
uptr r2_end = Min(end, mid + kMaxRangeToCheck);
uptr r3_beg = Max(end - kMaxRangeToCheck, mid);
diff --git a/libsanitizer/asan/asan_poisoning.h b/libsanitizer/asan/asan_poisoning.h
index 4ddcbc3..942e741 100644
--- a/libsanitizer/asan/asan_poisoning.h
+++ b/libsanitizer/asan/asan_poisoning.h
@@ -44,8 +44,11 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size,
// for mapping shadow and zeroing out pages doesn't "just work", so we should
// probably provide higher-level interface for these operations.
// For now, just memset on Windows.
- if (value ||
- SANITIZER_WINDOWS == 1 ||
+ if (value || SANITIZER_WINDOWS == 1 ||
+ // TODO(mcgrathr): Fuchsia doesn't allow the shadow mapping to be
+ // changed at all. It doesn't currently have an efficient means
+ // to zero a bunch of pages, but maybe we should add one.
+ SANITIZER_FUCHSIA == 1 ||
shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) {
REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg);
} else {
@@ -84,8 +87,8 @@ ALWAYS_INLINE void FastPoisonShadowPartialRightRedzone(
}
}
-// Calls __sanitizer::ReleaseMemoryToOS() on
-// [MemToShadow(p), MemToShadow(p+size)] with proper rounding.
+// Calls __sanitizer::ReleaseMemoryPagesToOS() on
+// [MemToShadow(p), MemToShadow(p+size)].
void FlushUnneededASanShadowMemory(uptr p, uptr size);
} // namespace __asan
diff --git a/libsanitizer/asan/asan_posix.cc b/libsanitizer/asan/asan_posix.cc
index 532afb3..e113c02 100644
--- a/libsanitizer/asan/asan_posix.cc
+++ b/libsanitizer/asan/asan_posix.cc
@@ -31,72 +31,10 @@
namespace __asan {
-const char *DescribeSignalOrException(int signo) {
- switch (signo) {
- case SIGFPE:
- return "FPE";
- case SIGILL:
- return "ILL";
- case SIGABRT:
- return "ABRT";
- default:
- return "SEGV";
- }
-}
-
void AsanOnDeadlySignal(int signo, void *siginfo, void *context) {
- ScopedDeadlySignal signal_scope(GetCurrentThread());
- int code = (int)((siginfo_t*)siginfo)->si_code;
- // Write the first message using fd=2, just in case.
- // It may actually fail to write in case stderr is closed.
- internal_write(2, "ASAN:DEADLYSIGNAL\n", 18);
- SignalContext sig = SignalContext::Create(siginfo, context);
-
- // Access at a reasonable offset above SP, or slightly below it (to account
- // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
- // probably a stack overflow.
-#ifdef __s390__
- // On s390, the fault address in siginfo points to start of the page, not
- // to the precise word that was accessed. Mask off the low bits of sp to
- // take it into account.
- bool IsStackAccess = sig.addr >= (sig.sp & ~0xFFF) &&
- sig.addr < sig.sp + 0xFFFF;
-#else
- bool IsStackAccess = sig.addr + 512 > sig.sp && sig.addr < sig.sp + 0xFFFF;
-#endif
-
-#if __powerpc__
- // Large stack frames can be allocated with e.g.
- // lis r0,-10000
- // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
- // If the store faults then sp will not have been updated, so test above
- // will not work, becase the fault address will be more than just "slightly"
- // below sp.
- if (!IsStackAccess && IsAccessibleMemoryRange(sig.pc, 4)) {
- u32 inst = *(unsigned *)sig.pc;
- u32 ra = (inst >> 16) & 0x1F;
- u32 opcd = inst >> 26;
- u32 xo = (inst >> 1) & 0x3FF;
- // Check for store-with-update to sp. The instructions we accept are:
- // stbu rs,d(ra) stbux rs,ra,rb
- // sthu rs,d(ra) sthux rs,ra,rb
- // stwu rs,d(ra) stwux rs,ra,rb
- // stdu rs,ds(ra) stdux rs,ra,rb
- // where ra is r1 (the stack pointer).
- if (ra == 1 &&
- (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
- (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
- IsStackAccess = true;
- }
-#endif // __powerpc__
-
- // We also check si_code to filter out SEGV caused by something else other
- // then hitting the guard page or unmapped memory, like, for example,
- // unaligned memory access.
- if (IsStackAccess && (code == si_SEGV_MAPERR || code == si_SEGV_ACCERR))
- ReportStackOverflow(sig);
- else
- ReportDeadlySignal(signo, sig);
+ StartReportDeadlySignal();
+ SignalContext sig(siginfo, context);
+ ReportDeadlySignal(sig);
}
// ---------------------- TSD ---------------- {{{1
diff --git a/libsanitizer/asan/asan_report.cc b/libsanitizer/asan/asan_report.cc
index 84d6764..51bad6e 100644
--- a/libsanitizer/asan/asan_report.cc
+++ b/libsanitizer/asan/asan_report.cc
@@ -58,9 +58,8 @@ void PrintMemoryByte(InternalScopedString *str, const char *before, u8 byte,
bool in_shadow, const char *after) {
Decorator d;
str->append("%s%s%x%x%s%s", before,
- in_shadow ? d.ShadowByte(byte) : d.MemoryByte(),
- byte >> 4, byte & 15,
- in_shadow ? d.EndShadowByte() : d.EndMemoryByte(), after);
+ in_shadow ? d.ShadowByte(byte) : d.MemoryByte(), byte >> 4,
+ byte & 15, d.Default(), after);
}
static void PrintZoneForPointer(uptr ptr, uptr zone_ptr,
@@ -86,7 +85,8 @@ bool ParseFrameDescription(const char *frame_descr,
char *p;
// This string is created by the compiler and has the following form:
// "n alloc_1 alloc_2 ... alloc_n"
- // where alloc_i looks like "offset size len ObjectName".
+ // where alloc_i looks like "offset size len ObjectName"
+ // or "offset size len ObjectName:line".
uptr n_objects = (uptr)internal_simple_strtoll(frame_descr, &p, 10);
if (n_objects == 0)
return false;
@@ -99,7 +99,14 @@ bool ParseFrameDescription(const char *frame_descr,
return false;
}
p++;
- StackVarDescr var = {beg, size, p, len};
+ char *colon_pos = internal_strchr(p, ':');
+ uptr line = 0;
+ uptr name_len = len;
+ if (colon_pos != nullptr && colon_pos < p + len) {
+ name_len = colon_pos - p;
+ line = (uptr)internal_simple_strtoll(colon_pos + 1, nullptr, 10);
+ }
+ StackVarDescr var = {beg, size, p, name_len, line};
vars->push_back(var);
p += len;
}
@@ -113,53 +120,15 @@ bool ParseFrameDescription(const char *frame_descr,
// immediately after printing error report.
class ScopedInErrorReport {
public:
- explicit ScopedInErrorReport(bool fatal = false) {
- halt_on_error_ = fatal || flags()->halt_on_error;
-
- if (lock_.TryLock()) {
- StartReporting();
- return;
- }
-
- // ASan found two bugs in different threads simultaneously.
-
- u32 current_tid = GetCurrentTidOrInvalid();
- if (reporting_thread_tid_ == current_tid ||
- reporting_thread_tid_ == kInvalidTid) {
- // This is either asynch signal or nested error during error reporting.
- // Fail simple to avoid deadlocks in Report().
-
- // Can't use Report() here because of potential deadlocks
- // in nested signal handlers.
- const char msg[] = "AddressSanitizer: nested bug in the same thread, "
- "aborting.\n";
- WriteToFile(kStderrFd, msg, sizeof(msg));
-
- internal__exit(common_flags()->exitcode);
- }
-
- if (halt_on_error_) {
- // Do not print more than one report, otherwise they will mix up.
- // Error reporting functions shouldn't return at this situation, as
- // they are effectively no-returns.
-
- Report("AddressSanitizer: while reporting a bug found another one. "
- "Ignoring.\n");
-
- // Sleep long enough to make sure that the thread which started
- // to print an error report will finish doing it.
- SleepForSeconds(Max(100, flags()->sleep_before_dying + 1));
-
- // If we're still not dead for some reason, use raw _exit() instead of
- // Die() to bypass any additional checks.
- internal__exit(common_flags()->exitcode);
- } else {
- // The other thread will eventually finish reporting
- // so it's safe to wait
- lock_.Lock();
- }
-
- StartReporting();
+ explicit ScopedInErrorReport(bool fatal = false)
+ : halt_on_error_(fatal || flags()->halt_on_error) {
+ // Make sure the registry and sanitizer report mutexes are locked while
+ // we're printing an error report.
+ // We can lock them only here to avoid self-deadlock in case of
+ // recursive reports.
+ asanThreadRegistry().Lock();
+ Printf(
+ "=================================================================\n");
}
~ScopedInErrorReport() {
@@ -177,6 +146,8 @@ class ScopedInErrorReport {
if (common_flags()->print_cmdline)
PrintCmdline();
+ if (common_flags()->print_module_map == 2) PrintModuleMap();
+
// Copy the message buffer so that we could start logging without holding a
// lock that gets aquired during printing.
InternalScopedBuffer<char> buffer_copy(kErrorMessageBufferSize);
@@ -192,14 +163,19 @@ class ScopedInErrorReport {
error_report_callback(buffer_copy.data());
}
+ if (halt_on_error_ && common_flags()->abort_on_error) {
+ // On Android the message is truncated to 512 characters.
+ // FIXME: implement "compact" error format, possibly without, or with
+ // highly compressed stack traces?
+ // FIXME: or just use the summary line as abort message?
+ SetAbortMessage(buffer_copy.data());
+ }
+
// In halt_on_error = false mode, reset the current error object (before
// unlocking).
if (!halt_on_error_)
internal_memset(&current_error_, 0, sizeof(current_error_));
- CommonSanitizerReportMutex.Unlock();
- reporting_thread_tid_ = kInvalidTid;
- lock_.Unlock();
if (halt_on_error_) {
Report("ABORTING\n");
Die();
@@ -217,39 +193,18 @@ class ScopedInErrorReport {
}
private:
- void StartReporting() {
- // Make sure the registry and sanitizer report mutexes are locked while
- // we're printing an error report.
- // We can lock them only here to avoid self-deadlock in case of
- // recursive reports.
- asanThreadRegistry().Lock();
- CommonSanitizerReportMutex.Lock();
- reporting_thread_tid_ = GetCurrentTidOrInvalid();
- Printf("===================================================="
- "=============\n");
- }
-
- static StaticSpinMutex lock_;
- static u32 reporting_thread_tid_;
+ ScopedErrorReportLock error_report_lock_;
// Error currently being reported. This enables the destructor to interact
// with the debugger and point it to an error description.
static ErrorDescription current_error_;
bool halt_on_error_;
};
-StaticSpinMutex ScopedInErrorReport::lock_;
-u32 ScopedInErrorReport::reporting_thread_tid_ = kInvalidTid;
ErrorDescription ScopedInErrorReport::current_error_;
-void ReportStackOverflow(const SignalContext &sig) {
+void ReportDeadlySignal(const SignalContext &sig) {
ScopedInErrorReport in_report(/*fatal*/ true);
- ErrorStackOverflow error(GetCurrentTidOrInvalid(), sig);
- in_report.ReportError(error);
-}
-
-void ReportDeadlySignal(int signo, const SignalContext &sig) {
- ScopedInErrorReport in_report(/*fatal*/ true);
- ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig, signo);
+ ErrorDeadlySignal error(GetCurrentTidOrInvalid(), sig);
in_report.ReportError(error);
}
@@ -425,7 +380,7 @@ void __asan_describe_address(uptr addr) {
}
int __asan_report_present() {
- return ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric;
+ return ScopedInErrorReport::CurrentError().kind != kErrorKindInvalid;
}
uptr __asan_get_report_pc() {
@@ -447,9 +402,11 @@ uptr __asan_get_report_sp() {
}
uptr __asan_get_report_address() {
- if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
- return ScopedInErrorReport::CurrentError()
- .Generic.addr_description.Address();
+ ErrorDescription &err = ScopedInErrorReport::CurrentError();
+ if (err.kind == kErrorKindGeneric)
+ return err.Generic.addr_description.Address();
+ else if (err.kind == kErrorKindDoubleFree)
+ return err.DoubleFree.addr_description.addr;
return 0;
}
@@ -468,7 +425,7 @@ uptr __asan_get_report_access_size() {
const char *__asan_get_report_description() {
if (ScopedInErrorReport::CurrentError().kind == kErrorKindGeneric)
return ScopedInErrorReport::CurrentError().Generic.bug_descr;
- return nullptr;
+ return ScopedInErrorReport::CurrentError().Base.scariness.GetDescription();
}
extern "C" {
@@ -482,9 +439,6 @@ void __sanitizer_ptr_cmp(void *a, void *b) {
}
} // extern "C"
-#if !SANITIZER_SUPPORTS_WEAK_HOOKS
// Provide default implementation of __asan_on_error that does nothing
// and may be overriden by user.
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE NOINLINE
-void __asan_on_error() {}
-#endif
+SANITIZER_INTERFACE_WEAK_DEF(void, __asan_on_error, void) {}
diff --git a/libsanitizer/asan/asan_report.h b/libsanitizer/asan/asan_report.h
index 111b840..5d47712 100644
--- a/libsanitizer/asan/asan_report.h
+++ b/libsanitizer/asan/asan_report.h
@@ -21,6 +21,7 @@ struct StackVarDescr {
uptr size;
const char *name_pos;
uptr name_len;
+ uptr line;
};
// Returns the number of globals close to the provided address and copies
@@ -43,8 +44,7 @@ bool ParseFrameDescription(const char *frame_descr,
// Different kinds of error reports.
void ReportGenericError(uptr pc, uptr bp, uptr sp, uptr addr, bool is_write,
uptr access_size, u32 exp, bool fatal);
-void ReportStackOverflow(const SignalContext &sig);
-void ReportDeadlySignal(int signo, const SignalContext &sig);
+void ReportDeadlySignal(const SignalContext &sig);
void ReportNewDeleteSizeMismatch(uptr addr, uptr delete_size,
BufferedStackTrace *free_stack);
void ReportDoubleFree(uptr addr, BufferedStackTrace *free_stack);
diff --git a/libsanitizer/asan/asan_rtl.cc b/libsanitizer/asan/asan_rtl.cc
index 38009d2..3905658 100644
--- a/libsanitizer/asan/asan_rtl.cc
+++ b/libsanitizer/asan/asan_rtl.cc
@@ -44,6 +44,7 @@ static void AsanDie() {
// Don't die twice - run a busy loop.
while (1) { }
}
+ if (common_flags()->print_module_map >= 1) PrintModuleMap();
if (flags()->sleep_before_dying) {
Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying);
SleepForSeconds(flags()->sleep_before_dying);
@@ -81,26 +82,6 @@ void ShowStatsAndAbort() {
Die();
}
-// ---------------------- mmap -------------------- {{{1
-// Reserve memory range [beg, end].
-// We need to use inclusive range because end+1 may not be representable.
-void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
- CHECK_EQ((beg % GetMmapGranularity()), 0);
- CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
- uptr size = end - beg + 1;
- DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
- void *res = MmapFixedNoReserve(beg, size, name);
- if (res != (void*)beg) {
- Report("ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
- "Perhaps you're using ulimit -v\n", size);
- Abort();
- }
- if (common_flags()->no_huge_pages_for_shadow)
- NoHugePagesInRegion(beg, size);
- if (common_flags()->use_madv_dontdump)
- DontDumpShadowMemory(beg, size);
-}
-
// --------------- LowLevelAllocateCallbac ---------- {{{1
static void OnLowLevelAllocate(uptr ptr, uptr size) {
PoisonShadow(ptr, size, kAsanInternalHeapMagic);
@@ -332,46 +313,7 @@ static void InitializeHighMemEnd() {
CHECK_EQ((kHighMemBeg % GetMmapGranularity()), 0);
}
-static void ProtectGap(uptr addr, uptr size) {
- if (!flags()->protect_shadow_gap) {
- // The shadow gap is unprotected, so there is a chance that someone
- // is actually using this memory. Which means it needs a shadow...
- uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
- uptr GapShadowEnd =
- RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
- if (Verbosity())
- Printf("protect_shadow_gap=0:"
- " not protecting shadow gap, allocating gap's shadow\n"
- "|| `[%p, %p]` || ShadowGap's shadow ||\n", GapShadowBeg,
- GapShadowEnd);
- ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
- "unprotected gap shadow");
- return;
- }
- void *res = MmapFixedNoAccess(addr, size, "shadow gap");
- if (addr == (uptr)res)
- return;
- // A few pages at the start of the address space can not be protected.
- // But we really want to protect as much as possible, to prevent this memory
- // being returned as a result of a non-FIXED mmap().
- if (addr == kZeroBaseShadowStart) {
- uptr step = GetMmapGranularity();
- while (size > step && addr < kZeroBaseMaxShadowStart) {
- addr += step;
- size -= step;
- void *res = MmapFixedNoAccess(addr, size, "shadow gap");
- if (addr == (uptr)res)
- return;
- }
- }
-
- Report("ERROR: Failed to protect the shadow gap. "
- "ASan cannot proceed correctly. ABORTING.\n");
- DumpProcessMap();
- Die();
-}
-
-static void PrintAddressSpaceLayout() {
+void PrintAddressSpaceLayout() {
Printf("|| `[%p, %p]` || HighMem ||\n",
(void*)kHighMemBeg, (void*)kHighMemEnd);
Printf("|| `[%p, %p]` || HighShadow ||\n",
@@ -408,6 +350,8 @@ static void PrintAddressSpaceLayout() {
Printf("redzone=%zu\n", (uptr)flags()->redzone);
Printf("max_redzone=%zu\n", (uptr)flags()->max_redzone);
Printf("quarantine_size_mb=%zuM\n", (uptr)flags()->quarantine_size_mb);
+ Printf("thread_local_quarantine_size_kb=%zuK\n",
+ (uptr)flags()->thread_local_quarantine_size_kb);
Printf("malloc_context_size=%zu\n",
(uptr)common_flags()->malloc_context_size);
@@ -472,78 +416,9 @@ static void AsanInitInternal() {
ReplaceSystemMalloc();
- // Set the shadow memory address to uninitialized.
- __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
-
- uptr shadow_start = kLowShadowBeg;
- // Detect if a dynamic shadow address must used and find a available location
- // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
- // expands to |__asan_shadow_memory_dynamic_address| which is
- // |kDefaultShadowSentinel|.
- if (shadow_start == kDefaultShadowSentinel) {
- __asan_shadow_memory_dynamic_address = 0;
- CHECK_EQ(0, kLowShadowBeg);
-
- uptr granularity = GetMmapGranularity();
- uptr alignment = 8 * granularity;
- uptr left_padding = granularity;
- uptr space_size = kHighShadowEnd + left_padding;
-
- shadow_start = FindAvailableMemoryRange(space_size, alignment, granularity);
- CHECK_NE((uptr)0, shadow_start);
- CHECK(IsAligned(shadow_start, alignment));
- }
- // Update the shadow memory address (potentially) used by instrumentation.
- __asan_shadow_memory_dynamic_address = shadow_start;
-
- if (kLowShadowBeg)
- shadow_start -= GetMmapGranularity();
- bool full_shadow_is_available =
- MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
-
-#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
- !ASAN_FIXED_MAPPING
- if (!full_shadow_is_available) {
- kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
- kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
- }
-#endif
-
- if (Verbosity()) PrintAddressSpaceLayout();
-
DisableCoreDumperIfNecessary();
- if (full_shadow_is_available) {
- // mmap the low shadow plus at least one page at the left.
- if (kLowShadowBeg)
- ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
- // mmap the high shadow.
- ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
- // protect the gap.
- ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
- CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
- } else if (kMidMemBeg &&
- MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
- MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
- CHECK(kLowShadowBeg != kLowShadowEnd);
- // mmap the low shadow plus at least one page at the left.
- ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
- // mmap the mid shadow.
- ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
- // mmap the high shadow.
- ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
- // protect the gaps.
- ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
- ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
- ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
- } else {
- Report("Shadow memory range interleaves with an existing memory mapping. "
- "ASan cannot proceed correctly. ABORTING.\n");
- Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
- shadow_start, kHighShadowEnd);
- DumpProcessMap();
- Die();
- }
+ InitializeShadowMemory();
AsanTSDInit(PlatformTSDDtor);
InstallDeadlySignalHandlers(AsanOnDeadlySignal);
@@ -574,20 +449,18 @@ static void AsanInitInternal() {
InitTlsSize();
// Create main thread.
- AsanThread *main_thread = AsanThread::Create(
- /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
- /* stack */ nullptr, /* detached */ true);
+ AsanThread *main_thread = CreateMainThread();
CHECK_EQ(0, main_thread->tid());
- SetCurrentThread(main_thread);
- main_thread->ThreadStart(internal_getpid(),
- /* signal_thread_is_registered */ nullptr);
force_interface_symbols(); // no-op.
SanitizerInitializeUnwinder();
if (CAN_SANITIZE_LEAKS) {
__lsan::InitCommonLsan();
if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) {
- Atexit(__lsan::DoLeakCheck);
+ if (flags()->halt_on_error)
+ Atexit(__lsan::DoLeakCheck);
+ else
+ Atexit(__lsan::DoRecoverableLeakCheckVoid);
}
}
@@ -607,6 +480,11 @@ static void AsanInitInternal() {
}
VReport(1, "AddressSanitizer Init done\n");
+
+ if (flags()->sleep_after_init) {
+ Report("Sleeping for %d second(s)\n", flags()->sleep_after_init);
+ SleepForSeconds(flags()->sleep_after_init);
+ }
}
// Initialize as requested from some part of ASan runtime library (interceptors,
@@ -646,6 +524,7 @@ void NOINLINE __asan_handle_no_return() {
top = curr_thread->stack_top();
bottom = ((uptr)&local_stack - PageSize) & ~(PageSize - 1);
} else {
+ CHECK(!SANITIZER_FUCHSIA);
// If we haven't seen this thread, try asking the OS for stack bounds.
uptr tls_addr, tls_size, stack_size;
GetThreadStackAndTls(/*main=*/false, &bottom, &stack_size, &tls_addr,
diff --git a/libsanitizer/asan/asan_scariness_score.h b/libsanitizer/asan/asan_scariness_score.h
index d72fce6..aa947ed 100644
--- a/libsanitizer/asan/asan_scariness_score.h
+++ b/libsanitizer/asan/asan_scariness_score.h
@@ -45,7 +45,7 @@ struct ScarinessScoreBase {
};
int GetScore() const { return score; }
const char *GetDescription() const { return descr; }
- void Print() {
+ void Print() const {
if (score && flags()->print_scariness)
Printf("SCARINESS: %d (%s)\n", score, descr);
}
diff --git a/libsanitizer/asan/asan_shadow_setup.cc b/libsanitizer/asan/asan_shadow_setup.cc
new file mode 100644
index 0000000..9629b36
--- /dev/null
+++ b/libsanitizer/asan/asan_shadow_setup.cc
@@ -0,0 +1,159 @@
+//===-- asan_shadow_setup.cc ----------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of AddressSanitizer, an address sanity checker.
+//
+// Set up the shadow memory.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+// asan_fuchsia.cc has its own InitializeShadowMemory implementation.
+#if !SANITIZER_FUCHSIA
+
+#include "asan_internal.h"
+#include "asan_mapping.h"
+
+namespace __asan {
+
+// ---------------------- mmap -------------------- {{{1
+// Reserve memory range [beg, end].
+// We need to use inclusive range because end+1 may not be representable.
+void ReserveShadowMemoryRange(uptr beg, uptr end, const char *name) {
+ CHECK_EQ((beg % GetMmapGranularity()), 0);
+ CHECK_EQ(((end + 1) % GetMmapGranularity()), 0);
+ uptr size = end - beg + 1;
+ DecreaseTotalMmap(size); // Don't count the shadow against mmap_limit_mb.
+ void *res = MmapFixedNoReserve(beg, size, name);
+ if (res != (void *)beg) {
+ Report(
+ "ReserveShadowMemoryRange failed while trying to map 0x%zx bytes. "
+ "Perhaps you're using ulimit -v\n",
+ size);
+ Abort();
+ }
+ if (common_flags()->no_huge_pages_for_shadow) NoHugePagesInRegion(beg, size);
+ if (common_flags()->use_madv_dontdump) DontDumpShadowMemory(beg, size);
+}
+
+static void ProtectGap(uptr addr, uptr size) {
+ if (!flags()->protect_shadow_gap) {
+ // The shadow gap is unprotected, so there is a chance that someone
+ // is actually using this memory. Which means it needs a shadow...
+ uptr GapShadowBeg = RoundDownTo(MEM_TO_SHADOW(addr), GetPageSizeCached());
+ uptr GapShadowEnd =
+ RoundUpTo(MEM_TO_SHADOW(addr + size), GetPageSizeCached()) - 1;
+ if (Verbosity())
+ Printf(
+ "protect_shadow_gap=0:"
+ " not protecting shadow gap, allocating gap's shadow\n"
+ "|| `[%p, %p]` || ShadowGap's shadow ||\n",
+ GapShadowBeg, GapShadowEnd);
+ ReserveShadowMemoryRange(GapShadowBeg, GapShadowEnd,
+ "unprotected gap shadow");
+ return;
+ }
+ void *res = MmapFixedNoAccess(addr, size, "shadow gap");
+ if (addr == (uptr)res) return;
+ // A few pages at the start of the address space can not be protected.
+ // But we really want to protect as much as possible, to prevent this memory
+ // being returned as a result of a non-FIXED mmap().
+ if (addr == kZeroBaseShadowStart) {
+ uptr step = GetMmapGranularity();
+ while (size > step && addr < kZeroBaseMaxShadowStart) {
+ addr += step;
+ size -= step;
+ void *res = MmapFixedNoAccess(addr, size, "shadow gap");
+ if (addr == (uptr)res) return;
+ }
+ }
+
+ Report(
+ "ERROR: Failed to protect the shadow gap. "
+ "ASan cannot proceed correctly. ABORTING.\n");
+ DumpProcessMap();
+ Die();
+}
+
+static void MaybeReportLinuxPIEBug() {
+#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__aarch64__))
+ Report("This might be related to ELF_ET_DYN_BASE change in Linux 4.12.\n");
+ Report(
+ "See https://github.com/google/sanitizers/issues/856 for possible "
+ "workarounds.\n");
+#endif
+}
+
+void InitializeShadowMemory() {
+ // Set the shadow memory address to uninitialized.
+ __asan_shadow_memory_dynamic_address = kDefaultShadowSentinel;
+
+ uptr shadow_start = kLowShadowBeg;
+ // Detect if a dynamic shadow address must used and find a available location
+ // when necessary. When dynamic address is used, the macro |kLowShadowBeg|
+ // expands to |__asan_shadow_memory_dynamic_address| which is
+ // |kDefaultShadowSentinel|.
+ if (shadow_start == kDefaultShadowSentinel) {
+ __asan_shadow_memory_dynamic_address = 0;
+ CHECK_EQ(0, kLowShadowBeg);
+ shadow_start = FindDynamicShadowStart();
+ }
+ // Update the shadow memory address (potentially) used by instrumentation.
+ __asan_shadow_memory_dynamic_address = shadow_start;
+
+ if (kLowShadowBeg) shadow_start -= GetMmapGranularity();
+ bool full_shadow_is_available =
+ MemoryRangeIsAvailable(shadow_start, kHighShadowEnd);
+
+#if SANITIZER_LINUX && defined(__x86_64__) && defined(_LP64) && \
+ !ASAN_FIXED_MAPPING
+ if (!full_shadow_is_available) {
+ kMidMemBeg = kLowMemEnd < 0x3000000000ULL ? 0x3000000000ULL : 0;
+ kMidMemEnd = kLowMemEnd < 0x3000000000ULL ? 0x4fffffffffULL : 0;
+ }
+#endif
+
+ if (Verbosity()) PrintAddressSpaceLayout();
+
+ if (full_shadow_is_available) {
+ // mmap the low shadow plus at least one page at the left.
+ if (kLowShadowBeg)
+ ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
+ // mmap the high shadow.
+ ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
+ // protect the gap.
+ ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+ CHECK_EQ(kShadowGapEnd, kHighShadowBeg - 1);
+ } else if (kMidMemBeg &&
+ MemoryRangeIsAvailable(shadow_start, kMidMemBeg - 1) &&
+ MemoryRangeIsAvailable(kMidMemEnd + 1, kHighShadowEnd)) {
+ CHECK(kLowShadowBeg != kLowShadowEnd);
+ // mmap the low shadow plus at least one page at the left.
+ ReserveShadowMemoryRange(shadow_start, kLowShadowEnd, "low shadow");
+ // mmap the mid shadow.
+ ReserveShadowMemoryRange(kMidShadowBeg, kMidShadowEnd, "mid shadow");
+ // mmap the high shadow.
+ ReserveShadowMemoryRange(kHighShadowBeg, kHighShadowEnd, "high shadow");
+ // protect the gaps.
+ ProtectGap(kShadowGapBeg, kShadowGapEnd - kShadowGapBeg + 1);
+ ProtectGap(kShadowGap2Beg, kShadowGap2End - kShadowGap2Beg + 1);
+ ProtectGap(kShadowGap3Beg, kShadowGap3End - kShadowGap3Beg + 1);
+ } else {
+ Report(
+ "Shadow memory range interleaves with an existing memory mapping. "
+ "ASan cannot proceed correctly. ABORTING.\n");
+ Report("ASan shadow was supposed to be located in the [%p-%p] range.\n",
+ shadow_start, kHighShadowEnd);
+ MaybeReportLinuxPIEBug();
+ DumpProcessMap();
+ Die();
+ }
+}
+
+} // namespace __asan
+
+#endif // !SANITIZER_FUCHSIA
diff --git a/libsanitizer/asan/asan_stack.h b/libsanitizer/asan/asan_stack.h
index 2b87381..aa8c4cd 100644
--- a/libsanitizer/asan/asan_stack.h
+++ b/libsanitizer/asan/asan_stack.h
@@ -39,10 +39,6 @@ void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
stack->size = 0;
if (LIKELY(asan_inited)) {
if ((t = GetCurrentThread()) && !t->isUnwinding()) {
- // On FreeBSD the slow unwinding that leverages _Unwind_Backtrace()
- // yields the call stack of the signal's handler and not of the code
- // that raised the signal (as it does on Linux).
- if (SANITIZER_FREEBSD && t->isInDeadlySignal()) fast = true;
uptr stack_top = t->stack_top();
uptr stack_bottom = t->stack_bottom();
ScopedUnwinding unwind_scope(t);
diff --git a/libsanitizer/asan/asan_suppressions.cc b/libsanitizer/asan/asan_suppressions.cc
index 1dc9d47..0040602 100644
--- a/libsanitizer/asan/asan_suppressions.cc
+++ b/libsanitizer/asan/asan_suppressions.cc
@@ -29,15 +29,9 @@ static const char *kSuppressionTypes[] = {
kInterceptorName, kInterceptorViaFunction, kInterceptorViaLibrary,
kODRViolation};
-extern "C" {
-#if SANITIZER_SUPPORTS_WEAK_HOOKS
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-const char *__asan_default_suppressions();
-#else
-// No week hooks, provide empty implementation.
-const char *__asan_default_suppressions() { return ""; }
-#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
-} // extern "C"
+SANITIZER_INTERFACE_WEAK_DEF(const char *, __asan_default_suppressions, void) {
+ return "";
+}
void InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
diff --git a/libsanitizer/asan/asan_thread.cc b/libsanitizer/asan/asan_thread.cc
index 818e126..d0fdf6e 100644
--- a/libsanitizer/asan/asan_thread.cc
+++ b/libsanitizer/asan/asan_thread.cc
@@ -25,11 +25,6 @@ namespace __asan {
// AsanThreadContext implementation.
-struct CreateThreadContextArgs {
- AsanThread *thread;
- StackTrace *stack;
-};
-
void AsanThreadContext::OnCreated(void *arg) {
CreateThreadContextArgs *args = static_cast<CreateThreadContextArgs*>(arg);
if (args->stack)
@@ -86,7 +81,7 @@ AsanThread *AsanThread::Create(thread_callback_t start_routine, void *arg,
AsanThread *thread = (AsanThread*)MmapOrDie(size, __func__);
thread->start_routine_ = start_routine;
thread->arg_ = arg;
- CreateThreadContextArgs args = { thread, stack };
+ AsanThreadContext::CreateThreadContextArgs args = {thread, stack};
asanThreadRegistry().CreateThread(*reinterpret_cast<uptr *>(thread), detached,
parent_tid, &args);
@@ -164,16 +159,19 @@ void AsanThread::FinishSwitchFiber(FakeStack *fake_stack_save,
}
inline AsanThread::StackBounds AsanThread::GetStackBounds() const {
- if (!atomic_load(&stack_switching_, memory_order_acquire))
- return StackBounds{stack_bottom_, stack_top_}; // NOLINT
+ if (!atomic_load(&stack_switching_, memory_order_acquire)) {
+ // Make sure the stack bounds are fully initialized.
+ if (stack_bottom_ >= stack_top_) return {0, 0};
+ return {stack_bottom_, stack_top_};
+ }
char local;
const uptr cur_stack = (uptr)&local;
// Note: need to check next stack first, because FinishSwitchFiber
// may be in process of overwriting stack_top_/bottom_. But in such case
// we are already on the next stack.
if (cur_stack >= next_stack_bottom_ && cur_stack < next_stack_top_)
- return StackBounds{next_stack_bottom_, next_stack_top_}; // NOLINT
- return StackBounds{stack_bottom_, stack_top_}; // NOLINT
+ return {next_stack_bottom_, next_stack_top_};
+ return {stack_bottom_, stack_top_};
}
uptr AsanThread::stack_top() {
@@ -218,12 +216,12 @@ FakeStack *AsanThread::AsyncSignalSafeLazyInitFakeStack() {
return nullptr;
}
-void AsanThread::Init() {
+void AsanThread::Init(const InitOptions *options) {
next_stack_top_ = next_stack_bottom_ = 0;
atomic_store(&stack_switching_, false, memory_order_release);
fake_stack_ = nullptr; // Will be initialized lazily if needed.
CHECK_EQ(this->stack_size(), 0U);
- SetThreadStackAndTls();
+ SetThreadStackAndTls(options);
CHECK_GT(this->stack_size(), 0U);
CHECK(AddrIsInMem(stack_bottom_));
CHECK(AddrIsInMem(stack_top_ - 1));
@@ -234,10 +232,15 @@ void AsanThread::Init() {
&local);
}
+// Fuchsia doesn't use ThreadStart.
+// asan_fuchsia.c defines CreateMainThread and SetThreadStackAndTls.
+#if !SANITIZER_FUCHSIA
+
thread_return_t AsanThread::ThreadStart(
- uptr os_id, atomic_uintptr_t *signal_thread_is_registered) {
+ tid_t os_id, atomic_uintptr_t *signal_thread_is_registered) {
Init();
- asanThreadRegistry().StartThread(tid(), os_id, nullptr);
+ asanThreadRegistry().StartThread(tid(), os_id, /*workerthread*/ false,
+ nullptr);
if (signal_thread_is_registered)
atomic_store(signal_thread_is_registered, 1, memory_order_release);
@@ -264,7 +267,21 @@ thread_return_t AsanThread::ThreadStart(
return res;
}
-void AsanThread::SetThreadStackAndTls() {
+AsanThread *CreateMainThread() {
+ AsanThread *main_thread = AsanThread::Create(
+ /* start_routine */ nullptr, /* arg */ nullptr, /* parent_tid */ 0,
+ /* stack */ nullptr, /* detached */ true);
+ SetCurrentThread(main_thread);
+ main_thread->ThreadStart(internal_getpid(),
+ /* signal_thread_is_registered */ nullptr);
+ return main_thread;
+}
+
+// This implementation doesn't use the argument, which is just passed down
+// from the caller of Init (which see, above). It's only there to support
+// OS-specific implementations that need more information passed through.
+void AsanThread::SetThreadStackAndTls(const InitOptions *options) {
+ DCHECK_EQ(options, nullptr);
uptr tls_size = 0;
uptr stack_size = 0;
GetThreadStackAndTls(tid() == 0, const_cast<uptr *>(&stack_bottom_),
@@ -277,6 +294,8 @@ void AsanThread::SetThreadStackAndTls() {
CHECK(AddrIsInStack((uptr)&local));
}
+#endif // !SANITIZER_FUCHSIA
+
void AsanThread::ClearShadowForThreadStackAndTLS() {
PoisonShadow(stack_bottom_, stack_top_ - stack_bottom_, 0);
if (tls_begin_ != tls_end_)
@@ -297,24 +316,27 @@ bool AsanThread::GetStackFrameAccessByAddr(uptr addr,
return true;
}
uptr aligned_addr = addr & ~(SANITIZER_WORDSIZE/8 - 1); // align addr.
+ uptr mem_ptr = RoundDownTo(aligned_addr, SHADOW_GRANULARITY);
u8 *shadow_ptr = (u8*)MemToShadow(aligned_addr);
u8 *shadow_bottom = (u8*)MemToShadow(bottom);
while (shadow_ptr >= shadow_bottom &&
*shadow_ptr != kAsanStackLeftRedzoneMagic) {
shadow_ptr--;
+ mem_ptr -= SHADOW_GRANULARITY;
}
while (shadow_ptr >= shadow_bottom &&
*shadow_ptr == kAsanStackLeftRedzoneMagic) {
shadow_ptr--;
+ mem_ptr -= SHADOW_GRANULARITY;
}
if (shadow_ptr < shadow_bottom) {
return false;
}
- uptr* ptr = (uptr*)SHADOW_TO_MEM((uptr)(shadow_ptr + 1));
+ uptr* ptr = (uptr*)(mem_ptr + SHADOW_GRANULARITY);
CHECK(ptr[0] == kCurrentStackFrameMagic);
access->offset = addr - (uptr)ptr;
access->frame_pc = ptr[2];
@@ -389,7 +411,7 @@ void EnsureMainThreadIDIsCorrect() {
context->os_id = GetTid();
}
-__asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
+__asan::AsanThread *GetAsanThreadByOsIDLocked(tid_t os_id) {
__asan::AsanThreadContext *context = static_cast<__asan::AsanThreadContext *>(
__asan::asanThreadRegistry().FindThreadContextByOsIDLocked(os_id));
if (!context) return nullptr;
@@ -399,7 +421,7 @@ __asan::AsanThread *GetAsanThreadByOsIDLocked(uptr os_id) {
// --- Implementation of LSan-specific functions --- {{{1
namespace __lsan {
-bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
uptr *cache_end, DTLS **dtls) {
__asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
@@ -415,7 +437,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
return true;
}
-void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
void *arg) {
__asan::AsanThread *t = __asan::GetAsanThreadByOsIDLocked(os_id);
if (t && t->has_fake_stack())
diff --git a/libsanitizer/asan/asan_thread.h b/libsanitizer/asan/asan_thread.h
index c51a58a..f7a91f3 100644
--- a/libsanitizer/asan/asan_thread.h
+++ b/libsanitizer/asan/asan_thread.h
@@ -47,6 +47,11 @@ class AsanThreadContext : public ThreadContextBase {
void OnCreated(void *arg) override;
void OnFinished() override;
+
+ struct CreateThreadContextArgs {
+ AsanThread *thread;
+ StackTrace *stack;
+ };
};
// AsanThreadContext objects are never freed, so we need many of them.
@@ -60,8 +65,10 @@ class AsanThread {
static void TSDDtor(void *tsd);
void Destroy();
- void Init(); // Should be called from the thread itself.
- thread_return_t ThreadStart(uptr os_id,
+ struct InitOptions;
+ void Init(const InitOptions *options = nullptr);
+
+ thread_return_t ThreadStart(tid_t os_id,
atomic_uintptr_t *signal_thread_is_registered);
uptr stack_top();
@@ -116,17 +123,15 @@ class AsanThread {
bool isUnwinding() const { return unwinding_; }
void setUnwinding(bool b) { unwinding_ = b; }
- // True if we are in a deadly signal handler.
- bool isInDeadlySignal() const { return in_deadly_signal_; }
- void setInDeadlySignal(bool b) { in_deadly_signal_ = b; }
-
AsanThreadLocalMallocStorage &malloc_storage() { return malloc_storage_; }
AsanStats &stats() { return stats_; }
private:
// NOTE: There is no AsanThread constructor. It is allocated
// via mmap() and *must* be valid in zero-initialized state.
- void SetThreadStackAndTls();
+
+ void SetThreadStackAndTls(const InitOptions *options);
+
void ClearShadowForThreadStackAndTLS();
FakeStack *AsyncSignalSafeLazyInitFakeStack();
@@ -156,7 +161,6 @@ class AsanThread {
AsanThreadLocalMallocStorage malloc_storage_;
AsanStats stats_;
bool unwinding_;
- bool in_deadly_signal_;
};
// ScopedUnwinding is a scope for stacktracing member of a context
@@ -171,20 +175,6 @@ class ScopedUnwinding {
AsanThread *thread;
};
-// ScopedDeadlySignal is a scope for handling deadly signals.
-class ScopedDeadlySignal {
- public:
- explicit ScopedDeadlySignal(AsanThread *t) : thread(t) {
- if (thread) thread->setInDeadlySignal(true);
- }
- ~ScopedDeadlySignal() {
- if (thread) thread->setInDeadlySignal(false);
- }
-
- private:
- AsanThread *thread;
-};
-
// Returns a single instance of registry.
ThreadRegistry &asanThreadRegistry();
diff --git a/libsanitizer/asan/asan_win.cc b/libsanitizer/asan/asan_win.cc
index efd82bf..02c7ed1 100644
--- a/libsanitizer/asan/asan_win.cc
+++ b/libsanitizer/asan/asan_win.cc
@@ -25,6 +25,8 @@
#include "asan_mapping.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_mutex.h"
+#include "sanitizer_common/sanitizer_win.h"
+#include "sanitizer_common/sanitizer_win_defs.h"
using namespace __asan; // NOLINT
@@ -40,35 +42,50 @@ uptr __asan_get_shadow_memory_dynamic_address() {
__asan_init();
return __asan_shadow_memory_dynamic_address;
}
-
-// -------------------- A workaround for the absence of weak symbols ----- {{{
-// We don't have a direct equivalent of weak symbols when using MSVC, but we can
-// use the /alternatename directive to tell the linker to default a specific
-// symbol to a specific value, which works nicely for allocator hooks and
-// __asan_default_options().
-void __sanitizer_default_malloc_hook(void *ptr, uptr size) { }
-void __sanitizer_default_free_hook(void *ptr) { }
-const char* __asan_default_default_options() { return ""; }
-const char* __asan_default_default_suppressions() { return ""; }
-void __asan_default_on_error() {}
-// 64-bit msvc will not prepend an underscore for symbols.
-#ifdef _WIN64
-#pragma comment(linker, "/alternatename:__sanitizer_malloc_hook=__sanitizer_default_malloc_hook") // NOLINT
-#pragma comment(linker, "/alternatename:__sanitizer_free_hook=__sanitizer_default_free_hook") // NOLINT
-#pragma comment(linker, "/alternatename:__asan_default_options=__asan_default_default_options") // NOLINT
-#pragma comment(linker, "/alternatename:__asan_default_suppressions=__asan_default_default_suppressions") // NOLINT
-#pragma comment(linker, "/alternatename:__asan_on_error=__asan_default_on_error") // NOLINT
-#else
-#pragma comment(linker, "/alternatename:___sanitizer_malloc_hook=___sanitizer_default_malloc_hook") // NOLINT
-#pragma comment(linker, "/alternatename:___sanitizer_free_hook=___sanitizer_default_free_hook") // NOLINT
-#pragma comment(linker, "/alternatename:___asan_default_options=___asan_default_default_options") // NOLINT
-#pragma comment(linker, "/alternatename:___asan_default_suppressions=___asan_default_default_suppressions") // NOLINT
-#pragma comment(linker, "/alternatename:___asan_on_error=___asan_default_on_error") // NOLINT
-#endif
-// }}}
} // extern "C"
// ---------------------- Windows-specific interceptors ---------------- {{{
+static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
+static LPTOP_LEVEL_EXCEPTION_FILTER user_seh_handler;
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+long __asan_unhandled_exception_filter(EXCEPTION_POINTERS *info) {
+ EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
+ CONTEXT *context = info->ContextRecord;
+
+ // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
+
+ SignalContext sig(exception_record, context);
+ ReportDeadlySignal(sig);
+ UNREACHABLE("returned from reporting deadly signal");
+}
+
+// Wrapper SEH Handler. If the exception should be handled by asan, we call
+// __asan_unhandled_exception_filter, otherwise, we execute the user provided
+// exception handler or the default.
+static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
+ DWORD exception_code = info->ExceptionRecord->ExceptionCode;
+ if (__sanitizer::IsHandledDeadlyException(exception_code))
+ return __asan_unhandled_exception_filter(info);
+ if (user_seh_handler)
+ return user_seh_handler(info);
+ // Bubble out to the default exception filter.
+ if (default_seh_handler)
+ return default_seh_handler(info);
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+INTERCEPTOR_WINAPI(LPTOP_LEVEL_EXCEPTION_FILTER, SetUnhandledExceptionFilter,
+ LPTOP_LEVEL_EXCEPTION_FILTER ExceptionFilter) {
+ CHECK(REAL(SetUnhandledExceptionFilter));
+ if (ExceptionFilter == &SEHHandler)
+ return REAL(SetUnhandledExceptionFilter)(ExceptionFilter);
+ // We record the user provided exception handler to be called for all the
+ // exceptions unhandled by asan.
+ Swap(ExceptionFilter, user_seh_handler);
+ return ExceptionFilter;
+}
+
INTERCEPTOR_WINAPI(void, RtlRaiseException, EXCEPTION_RECORD *ExceptionRecord) {
CHECK(REAL(RtlRaiseException));
// This is a noreturn function, unless it's one of the exceptions raised to
@@ -141,6 +158,7 @@ namespace __asan {
void InitializePlatformInterceptors() {
ASAN_INTERCEPT_FUNC(CreateThread);
+ ASAN_INTERCEPT_FUNC(SetUnhandledExceptionFilter);
#ifdef _WIN64
ASAN_INTERCEPT_FUNC(__C_specific_handler);
@@ -197,6 +215,18 @@ void *AsanDoesNotSupportStaticLinkage() {
return 0;
}
+uptr FindDynamicShadowStart() {
+ uptr granularity = GetMmapGranularity();
+ uptr alignment = 8 * granularity;
+ uptr left_padding = granularity;
+ uptr space_size = kHighShadowEnd + left_padding;
+ uptr shadow_start =
+ FindAvailableMemoryRange(space_size, alignment, granularity, nullptr);
+ CHECK_NE((uptr)0, shadow_start);
+ CHECK(IsAligned(shadow_start, alignment));
+ return shadow_start;
+}
+
void AsanCheckDynamicRTPrereqs() {}
void AsanCheckIncompatibleRT() {}
@@ -257,52 +287,8 @@ void InitializePlatformExceptionHandlers() {
#endif
}
-static LPTOP_LEVEL_EXCEPTION_FILTER default_seh_handler;
-
-// Check based on flags if we should report this exception.
-static bool ShouldReportDeadlyException(unsigned code) {
- switch (code) {
- case EXCEPTION_ACCESS_VIOLATION:
- case EXCEPTION_IN_PAGE_ERROR:
- return common_flags()->handle_segv;
- case EXCEPTION_BREAKPOINT:
- case EXCEPTION_ILLEGAL_INSTRUCTION: {
- return common_flags()->handle_sigill;
- }
- }
- return false;
-}
-
-// Return the textual name for this exception.
-const char *DescribeSignalOrException(int signo) {
- unsigned code = signo;
- // Get the string description of the exception if this is a known deadly
- // exception.
- switch (code) {
- case EXCEPTION_ACCESS_VIOLATION:
- return "access-violation";
- case EXCEPTION_IN_PAGE_ERROR:
- return "in-page-error";
- case EXCEPTION_BREAKPOINT:
- return "breakpoint";
- case EXCEPTION_ILLEGAL_INSTRUCTION:
- return "illegal-instruction";
- }
- return nullptr;
-}
-
-static long WINAPI SEHHandler(EXCEPTION_POINTERS *info) {
- EXCEPTION_RECORD *exception_record = info->ExceptionRecord;
- CONTEXT *context = info->ContextRecord;
-
- if (ShouldReportDeadlyException(exception_record->ExceptionCode)) {
- SignalContext sig = SignalContext::Create(exception_record, context);
- ReportDeadlySignal(exception_record->ExceptionCode, sig);
- }
-
- // FIXME: Handle EXCEPTION_STACK_OVERFLOW here.
-
- return default_seh_handler(info);
+bool IsSystemHeapAddress(uptr addr) {
+ return ::HeapValidate(GetProcessHeap(), 0, (void*)addr) != FALSE;
}
// We want to install our own exception handler (EH) to print helpful reports
@@ -341,10 +327,25 @@ int __asan_set_seh_filter() {
// immediately after the CRT runs. This way, our exception filter is called
// first and we can delegate to their filter if appropriate.
#pragma section(".CRT$XCAB", long, read) // NOLINT
-__declspec(allocate(".CRT$XCAB"))
- int (*__intercept_seh)() = __asan_set_seh_filter;
+__declspec(allocate(".CRT$XCAB")) int (*__intercept_seh)() =
+ __asan_set_seh_filter;
+
+// Piggyback on the TLS initialization callback directory to initialize asan as
+// early as possible. Initializers in .CRT$XL* are called directly by ntdll,
+// which run before the CRT. Users also add code to .CRT$XLC, so it's important
+// to run our initializers first.
+static void NTAPI asan_thread_init(void *module, DWORD reason, void *reserved) {
+ if (reason == DLL_PROCESS_ATTACH) __asan_init();
+}
+
+#pragma section(".CRT$XLAB", long, read) // NOLINT
+__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *,
+ unsigned long, void *) = asan_thread_init;
#endif
+
+WIN_FORCE_LINK(__asan_dso_reg_hook)
+
// }}}
} // namespace __asan
-#endif // _WIN32
+#endif // SANITIZER_WINDOWS
diff --git a/libsanitizer/asan/asan_win_dll_thunk.cc b/libsanitizer/asan/asan_win_dll_thunk.cc
index f7c9a37..31847efe 100644
--- a/libsanitizer/asan/asan_win_dll_thunk.cc
+++ b/libsanitizer/asan/asan_win_dll_thunk.cc
@@ -13,375 +13,41 @@
// See https://github.com/google/sanitizers/issues/209 for the details.
//===----------------------------------------------------------------------===//
-// Only compile this code when building asan_dll_thunk.lib
-// Using #ifdef rather than relying on Makefiles etc.
-// simplifies the build procedure.
-#ifdef ASAN_DLL_THUNK
+#ifdef SANITIZER_DLL_THUNK
#include "asan_init_version.h"
#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_win_defs.h"
+#include "sanitizer_common/sanitizer_win_dll_thunk.h"
#include "sanitizer_common/sanitizer_platform_interceptors.h"
-// ---------- Function interception helper functions and macros ----------- {{{1
-extern "C" {
-void *__stdcall GetModuleHandleA(const char *module_name);
-void *__stdcall GetProcAddress(void *module, const char *proc_name);
-void abort();
-}
-
-using namespace __sanitizer;
-
-static uptr getRealProcAddressOrDie(const char *name) {
- uptr ret =
- __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
- if (!ret)
- abort();
- return ret;
-}
-
-// We need to intercept some functions (e.g. ASan interface, memory allocator --
-// let's call them "hooks") exported by the DLL thunk and forward the hooks to
-// the runtime in the main module.
-// However, we don't want to keep two lists of these hooks.
-// To avoid that, the list of hooks should be defined using the
-// INTERCEPT_WHEN_POSSIBLE macro. Then, all these hooks can be intercepted
-// at once by calling INTERCEPT_HOOKS().
-
-// Use macro+template magic to automatically generate the list of hooks.
-// Each hook at line LINE defines a template class with a static
-// FunctionInterceptor<LINE>::Execute() method intercepting the hook.
-// The default implementation of FunctionInterceptor<LINE> is to call
-// the Execute() method corresponding to the previous line.
-template<int LINE>
-struct FunctionInterceptor {
- static void Execute() { FunctionInterceptor<LINE-1>::Execute(); }
-};
-
-// There shouldn't be any hooks with negative definition line number.
-template<>
-struct FunctionInterceptor<0> {
- static void Execute() {}
-};
-
-#define INTERCEPT_WHEN_POSSIBLE(main_function, dll_function) \
- template <> struct FunctionInterceptor<__LINE__> { \
- static void Execute() { \
- uptr wrapper = getRealProcAddressOrDie(main_function); \
- if (!__interception::OverrideFunction((uptr)dll_function, wrapper, 0)) \
- abort(); \
- FunctionInterceptor<__LINE__ - 1>::Execute(); \
- } \
- };
-
-// Special case of hooks -- ASan own interface functions. Those are only called
-// after __asan_init, thus an empty implementation is sufficient.
-#define INTERFACE_FUNCTION(name) \
- extern "C" __declspec(noinline) void name() { \
- volatile int prevent_icf = (__LINE__ << 8); (void)prevent_icf; \
- __debugbreak(); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name)
-
-// INTERCEPT_HOOKS must be used after the last INTERCEPT_WHEN_POSSIBLE.
-#define INTERCEPT_HOOKS FunctionInterceptor<__LINE__>::Execute
-
-// We can't define our own version of strlen etc. because that would lead to
-// link-time or even type mismatch errors. Instead, we can declare a function
-// just to be able to get its address. Me may miss the first few calls to the
-// functions since it can be called before __asan_init, but that would lead to
-// false negatives in the startup code before user's global initializers, which
-// isn't a big deal.
-#define INTERCEPT_LIBRARY_FUNCTION(name) \
- extern "C" void name(); \
- INTERCEPT_WHEN_POSSIBLE(WRAPPER_NAME(name), name)
-
-// Disable compiler warnings that show up if we declare our own version
-// of a compiler intrinsic (e.g. strlen).
-#pragma warning(disable: 4391)
-#pragma warning(disable: 4392)
-
-static void InterceptHooks();
-// }}}
-
-// ---------- Function wrapping helpers ----------------------------------- {{{1
-#define WRAP_V_V(name) \
- extern "C" void name() { \
- typedef void (*fntype)(); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_V_W(name) \
- extern "C" void name(void *arg) { \
- typedef void (*fntype)(void *arg); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_V_WW(name) \
- extern "C" void name(void *arg1, void *arg2) { \
- typedef void (*fntype)(void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg1, arg2); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_V_WWW(name) \
- extern "C" void name(void *arg1, void *arg2, void *arg3) { \
- typedef void *(*fntype)(void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- fn(arg1, arg2, arg3); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_W_V(name) \
- extern "C" void *name() { \
- typedef void *(*fntype)(); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_W_W(name) \
- extern "C" void *name(void *arg) { \
- typedef void *(*fntype)(void *arg); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_W_WW(name) \
- extern "C" void *name(void *arg1, void *arg2) { \
- typedef void *(*fntype)(void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_W_WWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
- typedef void *(*fntype)(void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_W_WWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
- typedef void *(*fntype)(void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_W_WWWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
- void *arg5) { \
- typedef void *(*fntype)(void *, void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4, arg5); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-
-#define WRAP_W_WWWWWW(name) \
- extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
- void *arg5, void *arg6) { \
- typedef void *(*fntype)(void *, void *, void *, void *, void *, void *); \
- static fntype fn = (fntype)getRealProcAddressOrDie(#name); \
- return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
- } \
- INTERCEPT_WHEN_POSSIBLE(#name, name);
-// }}}
-
-// ----------------- ASan own interface functions --------------------
-// Don't use the INTERFACE_FUNCTION machinery for this function as we actually
-// want to call it in the __asan_init interceptor.
-WRAP_W_V(__asan_should_detect_stack_use_after_return)
-WRAP_W_V(__asan_get_shadow_memory_dynamic_address)
-
-extern "C" {
- int __asan_option_detect_stack_use_after_return;
- uptr __asan_shadow_memory_dynamic_address;
-
- // Manually wrap __asan_init as we need to initialize
- // __asan_option_detect_stack_use_after_return afterwards.
- void __asan_init() {
- typedef void (*fntype)();
- static fntype fn = 0;
- // __asan_init is expected to be called by only one thread.
- if (fn) return;
-
- fn = (fntype)getRealProcAddressOrDie("__asan_init");
- fn();
- __asan_option_detect_stack_use_after_return =
- (__asan_should_detect_stack_use_after_return() != 0);
- __asan_shadow_memory_dynamic_address =
- (uptr)__asan_get_shadow_memory_dynamic_address();
- InterceptHooks();
- }
-}
-
-extern "C" void __asan_version_mismatch_check() {
- // Do nothing.
-}
-
-INTERFACE_FUNCTION(__asan_handle_no_return)
-
-INTERFACE_FUNCTION(__asan_report_store1)
-INTERFACE_FUNCTION(__asan_report_store2)
-INTERFACE_FUNCTION(__asan_report_store4)
-INTERFACE_FUNCTION(__asan_report_store8)
-INTERFACE_FUNCTION(__asan_report_store16)
-INTERFACE_FUNCTION(__asan_report_store_n)
-
-INTERFACE_FUNCTION(__asan_report_load1)
-INTERFACE_FUNCTION(__asan_report_load2)
-INTERFACE_FUNCTION(__asan_report_load4)
-INTERFACE_FUNCTION(__asan_report_load8)
-INTERFACE_FUNCTION(__asan_report_load16)
-INTERFACE_FUNCTION(__asan_report_load_n)
-
-INTERFACE_FUNCTION(__asan_store1)
-INTERFACE_FUNCTION(__asan_store2)
-INTERFACE_FUNCTION(__asan_store4)
-INTERFACE_FUNCTION(__asan_store8)
-INTERFACE_FUNCTION(__asan_store16)
-INTERFACE_FUNCTION(__asan_storeN)
-
-INTERFACE_FUNCTION(__asan_load1)
-INTERFACE_FUNCTION(__asan_load2)
-INTERFACE_FUNCTION(__asan_load4)
-INTERFACE_FUNCTION(__asan_load8)
-INTERFACE_FUNCTION(__asan_load16)
-INTERFACE_FUNCTION(__asan_loadN)
-
-INTERFACE_FUNCTION(__asan_memcpy);
-INTERFACE_FUNCTION(__asan_memset);
-INTERFACE_FUNCTION(__asan_memmove);
-
-INTERFACE_FUNCTION(__asan_set_shadow_00);
-INTERFACE_FUNCTION(__asan_set_shadow_f1);
-INTERFACE_FUNCTION(__asan_set_shadow_f2);
-INTERFACE_FUNCTION(__asan_set_shadow_f3);
-INTERFACE_FUNCTION(__asan_set_shadow_f5);
-INTERFACE_FUNCTION(__asan_set_shadow_f8);
-
-INTERFACE_FUNCTION(__asan_alloca_poison);
-INTERFACE_FUNCTION(__asan_allocas_unpoison);
-
-INTERFACE_FUNCTION(__asan_register_globals)
-INTERFACE_FUNCTION(__asan_unregister_globals)
-
-INTERFACE_FUNCTION(__asan_before_dynamic_init)
-INTERFACE_FUNCTION(__asan_after_dynamic_init)
-
-INTERFACE_FUNCTION(__asan_poison_stack_memory)
-INTERFACE_FUNCTION(__asan_unpoison_stack_memory)
+// ASan own interface functions.
+#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
+#include "asan_interface.inc"
-INTERFACE_FUNCTION(__asan_poison_memory_region)
-INTERFACE_FUNCTION(__asan_unpoison_memory_region)
+// Memory allocation functions.
+INTERCEPT_WRAP_V_W(free)
+INTERCEPT_WRAP_V_W(_free_base)
+INTERCEPT_WRAP_V_WW(_free_dbg)
-INTERFACE_FUNCTION(__asan_address_is_poisoned)
-INTERFACE_FUNCTION(__asan_region_is_poisoned)
+INTERCEPT_WRAP_W_W(malloc)
+INTERCEPT_WRAP_W_W(_malloc_base)
+INTERCEPT_WRAP_W_WWWW(_malloc_dbg)
-INTERFACE_FUNCTION(__asan_get_current_fake_stack)
-INTERFACE_FUNCTION(__asan_addr_is_in_fake_stack)
+INTERCEPT_WRAP_W_WW(calloc)
+INTERCEPT_WRAP_W_WW(_calloc_base)
+INTERCEPT_WRAP_W_WWWWW(_calloc_dbg)
+INTERCEPT_WRAP_W_WWW(_calloc_impl)
-INTERFACE_FUNCTION(__asan_stack_malloc_0)
-INTERFACE_FUNCTION(__asan_stack_malloc_1)
-INTERFACE_FUNCTION(__asan_stack_malloc_2)
-INTERFACE_FUNCTION(__asan_stack_malloc_3)
-INTERFACE_FUNCTION(__asan_stack_malloc_4)
-INTERFACE_FUNCTION(__asan_stack_malloc_5)
-INTERFACE_FUNCTION(__asan_stack_malloc_6)
-INTERFACE_FUNCTION(__asan_stack_malloc_7)
-INTERFACE_FUNCTION(__asan_stack_malloc_8)
-INTERFACE_FUNCTION(__asan_stack_malloc_9)
-INTERFACE_FUNCTION(__asan_stack_malloc_10)
+INTERCEPT_WRAP_W_WW(realloc)
+INTERCEPT_WRAP_W_WW(_realloc_base)
+INTERCEPT_WRAP_W_WWW(_realloc_dbg)
+INTERCEPT_WRAP_W_WWW(_recalloc)
+INTERCEPT_WRAP_W_WWW(_recalloc_base)
-INTERFACE_FUNCTION(__asan_stack_free_0)
-INTERFACE_FUNCTION(__asan_stack_free_1)
-INTERFACE_FUNCTION(__asan_stack_free_2)
-INTERFACE_FUNCTION(__asan_stack_free_4)
-INTERFACE_FUNCTION(__asan_stack_free_5)
-INTERFACE_FUNCTION(__asan_stack_free_6)
-INTERFACE_FUNCTION(__asan_stack_free_7)
-INTERFACE_FUNCTION(__asan_stack_free_8)
-INTERFACE_FUNCTION(__asan_stack_free_9)
-INTERFACE_FUNCTION(__asan_stack_free_10)
-
-// FIXME: we might want to have a sanitizer_win_dll_thunk?
-INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
-INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
-INTERFACE_FUNCTION(__sanitizer_cov)
-INTERFACE_FUNCTION(__sanitizer_cov_dump)
-INTERFACE_FUNCTION(__sanitizer_cov_indir_call16)
-INTERFACE_FUNCTION(__sanitizer_cov_init)
-INTERFACE_FUNCTION(__sanitizer_cov_module_init)
-INTERFACE_FUNCTION(__sanitizer_cov_trace_basic_block)
-INTERFACE_FUNCTION(__sanitizer_cov_trace_func_enter)
-INTERFACE_FUNCTION(__sanitizer_cov_with_check)
-INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
-INTERFACE_FUNCTION(__sanitizer_get_coverage_guards)
-INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
-INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
-INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
-INTERFACE_FUNCTION(__sanitizer_get_heap_size)
-INTERFACE_FUNCTION(__sanitizer_get_ownership)
-INTERFACE_FUNCTION(__sanitizer_get_total_unique_caller_callee_pairs)
-INTERFACE_FUNCTION(__sanitizer_get_total_unique_coverage)
-INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
-INTERFACE_FUNCTION(__sanitizer_maybe_open_cov_file)
-INTERFACE_FUNCTION(__sanitizer_print_stack_trace)
-INTERFACE_FUNCTION(__sanitizer_symbolize_pc)
-INTERFACE_FUNCTION(__sanitizer_symbolize_global)
-INTERFACE_FUNCTION(__sanitizer_ptr_cmp)
-INTERFACE_FUNCTION(__sanitizer_ptr_sub)
-INTERFACE_FUNCTION(__sanitizer_report_error_summary)
-INTERFACE_FUNCTION(__sanitizer_reset_coverage)
-INTERFACE_FUNCTION(__sanitizer_get_number_of_counters)
-INTERFACE_FUNCTION(__sanitizer_update_counter_bitset_and_clear_counters)
-INTERFACE_FUNCTION(__sanitizer_sandbox_on_notify)
-INTERFACE_FUNCTION(__sanitizer_set_death_callback)
-INTERFACE_FUNCTION(__sanitizer_set_report_path)
-INTERFACE_FUNCTION(__sanitizer_set_report_fd)
-INTERFACE_FUNCTION(__sanitizer_unaligned_load16)
-INTERFACE_FUNCTION(__sanitizer_unaligned_load32)
-INTERFACE_FUNCTION(__sanitizer_unaligned_load64)
-INTERFACE_FUNCTION(__sanitizer_unaligned_store16)
-INTERFACE_FUNCTION(__sanitizer_unaligned_store32)
-INTERFACE_FUNCTION(__sanitizer_unaligned_store64)
-INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
-INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks)
-INTERFACE_FUNCTION(__sanitizer_start_switch_fiber)
-INTERFACE_FUNCTION(__sanitizer_finish_switch_fiber)
-
-// TODO(timurrrr): Add more interface functions on the as-needed basis.
-
-// ----------------- Memory allocation functions ---------------------
-WRAP_V_W(free)
-WRAP_V_W(_free_base)
-WRAP_V_WW(_free_dbg)
-
-WRAP_W_W(malloc)
-WRAP_W_W(_malloc_base)
-WRAP_W_WWWW(_malloc_dbg)
-
-WRAP_W_WW(calloc)
-WRAP_W_WW(_calloc_base)
-WRAP_W_WWWWW(_calloc_dbg)
-WRAP_W_WWW(_calloc_impl)
-
-WRAP_W_WW(realloc)
-WRAP_W_WW(_realloc_base)
-WRAP_W_WWW(_realloc_dbg)
-WRAP_W_WWW(_recalloc)
-WRAP_W_WWW(_recalloc_base)
-
-WRAP_W_W(_msize)
-WRAP_W_W(_expand)
-WRAP_W_W(_expand_dbg)
+INTERCEPT_WRAP_W_W(_msize)
+INTERCEPT_WRAP_W_W(_expand)
+INTERCEPT_WRAP_W_W(_expand_dbg)
// TODO(timurrrr): Might want to add support for _aligned_* allocation
// functions to detect a bit more bugs. Those functions seem to wrap malloc().
@@ -390,20 +56,6 @@ WRAP_W_W(_expand_dbg)
INTERCEPT_LIBRARY_FUNCTION(atoi);
INTERCEPT_LIBRARY_FUNCTION(atol);
-
-#ifdef _WIN64
-INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler);
-#else
-INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
-
-// _except_handler4 checks -GS cookie which is different for each module, so we
-// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
-INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
- __asan_handle_no_return();
- return REAL(_except_handler4)(a, b, c, d);
-}
-#endif
-
INTERCEPT_LIBRARY_FUNCTION(frexp);
INTERCEPT_LIBRARY_FUNCTION(longjmp);
#if SANITIZER_INTERCEPT_MEMCHR
@@ -428,30 +80,71 @@ INTERCEPT_LIBRARY_FUNCTION(strpbrk);
INTERCEPT_LIBRARY_FUNCTION(strrchr);
INTERCEPT_LIBRARY_FUNCTION(strspn);
INTERCEPT_LIBRARY_FUNCTION(strstr);
+INTERCEPT_LIBRARY_FUNCTION(strtok);
INTERCEPT_LIBRARY_FUNCTION(strtol);
INTERCEPT_LIBRARY_FUNCTION(wcslen);
+INTERCEPT_LIBRARY_FUNCTION(wcsnlen);
+
+#ifdef _WIN64
+INTERCEPT_LIBRARY_FUNCTION(__C_specific_handler);
+#else
+INTERCEPT_LIBRARY_FUNCTION(_except_handler3);
+// _except_handler4 checks -GS cookie which is different for each module, so we
+// can't use INTERCEPT_LIBRARY_FUNCTION(_except_handler4).
+INTERCEPTOR(int, _except_handler4, void *a, void *b, void *c, void *d) {
+ __asan_handle_no_return();
+ return REAL(_except_handler4)(a, b, c, d);
+}
+#endif
+
+// Window specific functions not included in asan_interface.inc.
+INTERCEPT_WRAP_W_V(__asan_should_detect_stack_use_after_return)
+INTERCEPT_WRAP_W_V(__asan_get_shadow_memory_dynamic_address)
+INTERCEPT_WRAP_W_W(__asan_unhandled_exception_filter)
+
+using namespace __sanitizer;
+
+extern "C" {
+int __asan_option_detect_stack_use_after_return;
+uptr __asan_shadow_memory_dynamic_address;
+} // extern "C"
+
+static int asan_dll_thunk_init() {
+ typedef void (*fntype)();
+ static fntype fn = 0;
+ // asan_dll_thunk_init is expected to be called by only one thread.
+ if (fn) return 0;
+
+ // Ensure all interception was executed.
+ __dll_thunk_init();
+
+ fn = (fntype) dllThunkGetRealAddrOrDie("__asan_init");
+ fn();
+ __asan_option_detect_stack_use_after_return =
+ (__asan_should_detect_stack_use_after_return() != 0);
+ __asan_shadow_memory_dynamic_address =
+ (uptr)__asan_get_shadow_memory_dynamic_address();
-// Must be after all the interceptor declarations due to the way INTERCEPT_HOOKS
-// is defined.
-void InterceptHooks() {
- INTERCEPT_HOOKS();
#ifndef _WIN64
INTERCEPT_FUNCTION(_except_handler4);
#endif
+ // In DLLs, the callbacks are expected to return 0,
+ // otherwise CRT initialization fails.
+ return 0;
}
-// We want to call __asan_init before C/C++ initializers/constructors are
-// executed, otherwise functions like memset might be invoked.
-// For some strange reason, merely linking in asan_preinit.cc doesn't work
-// as the callback is never called... Is link.exe doing something too smart?
+#pragma section(".CRT$XIB", long, read) // NOLINT
+__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = asan_dll_thunk_init;
-// In DLLs, the callbacks are expected to return 0,
-// otherwise CRT initialization fails.
-static int call_asan_init() {
- __asan_init();
- return 0;
+static void WINAPI asan_thread_init(void *mod, unsigned long reason,
+ void *reserved) {
+ if (reason == /*DLL_PROCESS_ATTACH=*/1) asan_dll_thunk_init();
}
-#pragma section(".CRT$XIB", long, read) // NOLINT
-__declspec(allocate(".CRT$XIB")) int (*__asan_preinit)() = call_asan_init;
-#endif // ASAN_DLL_THUNK
+#pragma section(".CRT$XLAB", long, read) // NOLINT
+__declspec(allocate(".CRT$XLAB")) void (WINAPI *__asan_tls_init)(void *,
+ unsigned long, void *) = asan_thread_init;
+
+WIN_FORCE_LINK(__asan_dso_reg_hook)
+
+#endif // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc
index 8989159..d431b78 100644
--- a/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc
+++ b/libsanitizer/asan/asan_win_dynamic_runtime_thunk.cc
@@ -12,24 +12,31 @@
// using the default "import library" generated when linking the DLL RTL.
//
// This includes:
+// - creating weak aliases to default implementation imported from asan dll.
// - forwarding the detect_stack_use_after_return runtime option
// - working around deficiencies of the MD runtime
// - installing a custom SEH handler
//
//===----------------------------------------------------------------------===//
-// Only compile this code when building asan_dynamic_runtime_thunk.lib
-// Using #ifdef rather than relying on Makefiles etc.
-// simplifies the build procedure.
-#ifdef ASAN_DYNAMIC_RUNTIME_THUNK
+#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
+#define SANITIZER_IMPORT_INTERFACE 1
+#include "sanitizer_common/sanitizer_win_defs.h"
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
+// Define weak alias for all weak functions imported from asan dll.
+#define INTERFACE_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
+#include "asan_interface.inc"
+
// First, declare CRT sections we'll be using in this file
+#pragma section(".CRT$XIB", long, read) // NOLINT
#pragma section(".CRT$XID", long, read) // NOLINT
#pragma section(".CRT$XCAB", long, read) // NOLINT
#pragma section(".CRT$XTW", long, read) // NOLINT
#pragma section(".CRT$XTY", long, read) // NOLINT
+#pragma section(".CRT$XLAB", long, read) // NOLINT
////////////////////////////////////////////////////////////////////////////////
// Define a copy of __asan_option_detect_stack_use_after_return that should be
@@ -44,14 +51,33 @@
// after initialization anyways.
extern "C" {
__declspec(dllimport) int __asan_should_detect_stack_use_after_return();
-int __asan_option_detect_stack_use_after_return =
- __asan_should_detect_stack_use_after_return();
+int __asan_option_detect_stack_use_after_return;
__declspec(dllimport) void* __asan_get_shadow_memory_dynamic_address();
-void* __asan_shadow_memory_dynamic_address =
+void* __asan_shadow_memory_dynamic_address;
+}
+
+static int InitializeClonedVariables() {
+ __asan_option_detect_stack_use_after_return =
+ __asan_should_detect_stack_use_after_return();
+ __asan_shadow_memory_dynamic_address =
__asan_get_shadow_memory_dynamic_address();
+ return 0;
}
+static void NTAPI asan_thread_init(void *mod, unsigned long reason,
+ void *reserved) {
+ if (reason == DLL_PROCESS_ATTACH) InitializeClonedVariables();
+}
+
+// Our cloned variables must be initialized before C/C++ constructors. If TLS
+// is used, our .CRT$XLAB initializer will run first. If not, our .CRT$XIB
+// initializer is needed as a backup.
+__declspec(allocate(".CRT$XIB")) int (*__asan_initialize_cloned_variables)() =
+ InitializeClonedVariables;
+__declspec(allocate(".CRT$XLAB")) void (NTAPI *__asan_tls_init)(void *,
+ unsigned long, void *) = asan_thread_init;
+
////////////////////////////////////////////////////////////////////////////////
// For some reason, the MD CRT doesn't call the C/C++ terminators during on DLL
// unload or on exit. ASan relies on LLVM global_dtors to call
@@ -98,4 +124,6 @@ __declspec(allocate(".CRT$XCAB")) int (*__asan_seh_interceptor)() =
SetSEHFilter;
}
-#endif // ASAN_DYNAMIC_RUNTIME_THUNK
+WIN_FORCE_LINK(__asan_dso_reg_hook)
+
+#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
diff --git a/libsanitizer/asan/asan_win_weak_interception.cc b/libsanitizer/asan/asan_win_weak_interception.cc
new file mode 100644
index 0000000..74c1dcd
--- /dev/null
+++ b/libsanitizer/asan/asan_win_weak_interception.cc
@@ -0,0 +1,21 @@
+//===-- asan_win_weak_interception.cc -------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This module should be included in Address Sanitizer when it is implemented as
+// a shared library on Windows (dll), in order to delegate the calls of weak
+// functions to the implementation in the main executable when a strong
+// definition is provided.
+//===----------------------------------------------------------------------===//
+#ifdef SANITIZER_DYNAMIC
+#include "sanitizer_common/sanitizer_win_weak_interception.h"
+#include "asan_interface_internal.h"
+// Check if strong definitions for weak functions are present in the main
+// executable. If that is the case, override dll functions to point to strong
+// implementations.
+#define INTERFACE_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
+#include "asan_interface.inc"
+#endif // SANITIZER_DYNAMIC
diff --git a/libsanitizer/asan/libtool-version b/libsanitizer/asan/libtool-version
index 0f14ee3..e3138f3 100644
--- a/libsanitizer/asan/libtool-version
+++ b/libsanitizer/asan/libtool-version
@@ -3,4 +3,4 @@
# a separate file so that version updates don't involve re-running
# automake.
# CURRENT:REVISION:AGE
-4:0:0
+5:0:0
diff --git a/libsanitizer/builtins/assembly.h b/libsanitizer/builtins/assembly.h
index 5e36b5a..3f5e59b 100644
--- a/libsanitizer/builtins/assembly.h
+++ b/libsanitizer/builtins/assembly.h
@@ -44,7 +44,8 @@
#endif
#define CONST_SECTION .section .rodata
-#if defined(__GNU__) || defined(__ANDROID__) || defined(__FreeBSD__)
+#if defined(__GNU__) || defined(__FreeBSD__) || defined(__Fuchsia__) || \
+ defined(__linux__)
#define NO_EXEC_STACK_DIRECTIVE .section .note.GNU-stack,"",%progbits
#else
#define NO_EXEC_STACK_DIRECTIVE
@@ -67,10 +68,42 @@
#endif
#if defined(__arm__)
+
+/*
+ * Determine actual [ARM][THUMB[1][2]] ISA using compiler predefined macros:
+ * - for '-mthumb -march=armv6' compiler defines '__thumb__'
+ * - for '-mthumb -march=armv7' compiler defines '__thumb__' and '__thumb2__'
+ */
+#if defined(__thumb2__) || defined(__thumb__)
+#define DEFINE_CODE_STATE .thumb SEPARATOR
+#define DECLARE_FUNC_ENCODING .thumb_func SEPARATOR
+#if defined(__thumb2__)
+#define USE_THUMB_2
+#define IT(cond) it cond
+#define ITT(cond) itt cond
+#define ITE(cond) ite cond
+#else
+#define USE_THUMB_1
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif // defined(__thumb__2)
+#else // !defined(__thumb2__) && !defined(__thumb__)
+#define DEFINE_CODE_STATE .arm SEPARATOR
+#define DECLARE_FUNC_ENCODING
+#define IT(cond)
+#define ITT(cond)
+#define ITE(cond)
+#endif
+
+#if defined(USE_THUMB_1) && defined(USE_THUMB_2)
+#error "USE_THUMB_1 and USE_THUMB_2 can't be defined together."
+#endif
+
#if defined(__ARM_ARCH_4T__) || __ARM_ARCH >= 5
#define ARM_HAS_BX
#endif
-#if !defined(__ARM_FEATURE_CLZ) && \
+#if !defined(__ARM_FEATURE_CLZ) && !defined(USE_THUMB_1) && \
(__ARM_ARCH >= 6 || (__ARM_ARCH == 5 && !defined(__ARM_ARCH_5__)))
#define __ARM_FEATURE_CLZ
#endif
@@ -92,19 +125,14 @@
JMP(ip)
#endif
-#if __ARM_ARCH_ISA_THUMB == 2
-#define IT(cond) it cond
-#define ITT(cond) itt cond
-#else
-#define IT(cond)
-#define ITT(cond)
-#endif
-
-#if __ARM_ARCH_ISA_THUMB == 2
+#if defined(USE_THUMB_2)
#define WIDE(op) op.w
#else
#define WIDE(op) op
#endif
+#else // !defined(__arm)
+#define DECLARE_FUNC_ENCODING
+#define DEFINE_CODE_STATE
#endif
#define GLUE2(a, b) a##b
@@ -119,13 +147,16 @@
#endif
#define DEFINE_COMPILERRT_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
DECLARE_SYMBOL_VISIBILITY(name) \
+ DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_THUMB_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
@@ -134,16 +165,20 @@
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION(name) \
+ DEFINE_CODE_STATE \
FILE_LEVEL_DIRECTIVE SEPARATOR \
.globl SYMBOL_NAME(name) SEPARATOR \
SYMBOL_IS_FUNC(SYMBOL_NAME(name)) SEPARATOR \
HIDDEN(SYMBOL_NAME(name)) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
SYMBOL_NAME(name):
#define DEFINE_COMPILERRT_PRIVATE_FUNCTION_UNMANGLED(name) \
+ DEFINE_CODE_STATE \
.globl name SEPARATOR \
SYMBOL_IS_FUNC(name) SEPARATOR \
HIDDEN(name) SEPARATOR \
+ DECLARE_FUNC_ENCODING \
name:
#define DEFINE_COMPILERRT_FUNCTION_ALIAS(name, target) \
diff --git a/libsanitizer/configure.tgt b/libsanitizer/configure.tgt
index 82e8a55..573e3b4 100644
--- a/libsanitizer/configure.tgt
+++ b/libsanitizer/configure.tgt
@@ -27,6 +27,8 @@ case "${target}" in
TSAN_SUPPORTED=yes
LSAN_SUPPORTED=yes
TSAN_TARGET_DEPENDENT_OBJECTS=tsan_rtl_amd64.lo
+ fi
+ if echo "int x = __x86_64__;" | $CC -c -x c -o /dev/null - > /dev/null 2>&1; then
SANITIZER_COMMON_TARGET_DEPENDENT_OBJECTS=sanitizer_linux_x86_64.lo
fi
;;
diff --git a/libsanitizer/include/sanitizer/asan_interface.h b/libsanitizer/include/sanitizer/asan_interface.h
index 448a0bc..ad69ab4 100644
--- a/libsanitizer/include/sanitizer/asan_interface.h
+++ b/libsanitizer/include/sanitizer/asan_interface.h
@@ -142,6 +142,10 @@ extern "C" {
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
void **end);
+ // Performs cleanup before a [[noreturn]] function. Must be called
+ // before things like _exit and execl to avoid false positives on stack.
+ void __asan_handle_no_return(void);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/common_interface_defs.h b/libsanitizer/include/sanitizer/common_interface_defs.h
index fd38c55..a66c932b 100644
--- a/libsanitizer/include/sanitizer/common_interface_defs.h
+++ b/libsanitizer/include/sanitizer/common_interface_defs.h
@@ -156,8 +156,10 @@ extern "C" {
// Prints stack traces for all live heap allocations ordered by total
// allocation size until `top_percent` of total live heap is shown.
// `top_percent` should be between 1 and 100.
+ // At most `max_number_of_contexts` contexts (stack traces) is printed.
// Experimental feature currently available only with asan on Linux/x86_64.
- void __sanitizer_print_memory_profile(size_t top_percent);
+ void __sanitizer_print_memory_profile(size_t top_percent,
+ size_t max_number_of_contexts);
// Fiber annotation interface.
// Before switching to a different stack, one must call
@@ -180,6 +182,13 @@ extern "C" {
void __sanitizer_finish_switch_fiber(void *fake_stack_save,
const void **bottom_old,
size_t *size_old);
+
+ // Get full module name and calculate pc offset within it.
+ // Returns 1 if pc belongs to some module, 0 if module was not found.
+ int __sanitizer_get_module_and_offset_for_pc(void *pc, char *module_path,
+ size_t module_path_len,
+ void **pc_offset);
+
#ifdef __cplusplus
} // extern "C"
#endif
diff --git a/libsanitizer/include/sanitizer/coverage_interface.h b/libsanitizer/include/sanitizer/coverage_interface.h
index ffb956c..85447b6 100644
--- a/libsanitizer/include/sanitizer/coverage_interface.h
+++ b/libsanitizer/include/sanitizer/coverage_interface.h
@@ -17,45 +17,15 @@
extern "C" {
#endif
- // Initialize coverage.
- void __sanitizer_cov_init();
// Record and dump coverage info.
void __sanitizer_cov_dump();
- // Open <name>.sancov.packed in the coverage directory and return the file
- // descriptor. Returns -1 on failure, or if coverage dumping is disabled.
- // This is intended for use by sandboxing code.
- intptr_t __sanitizer_maybe_open_cov_file(const char *name);
- // Get the number of unique covered blocks (or edges).
- // This can be useful for coverage-directed in-process fuzzers.
- uintptr_t __sanitizer_get_total_unique_coverage();
- // Get the number of unique indirect caller-callee pairs.
- uintptr_t __sanitizer_get_total_unique_caller_callee_pairs();
- // Reset the basic-block (edge) coverage to the initial state.
- // Useful for in-process fuzzing to start collecting coverage from scratch.
- // Experimental, will likely not work for multi-threaded process.
- void __sanitizer_reset_coverage();
- // Set *data to the array of covered PCs and return the size of that array.
- // Some of the entries in *data will be zero.
- uintptr_t __sanitizer_get_coverage_guards(uintptr_t **data);
+ // Clear collected coverage info.
+ void __sanitizer_cov_reset();
- // The coverage instrumentation may optionally provide imprecise counters.
- // Rather than exposing the counter values to the user we instead map
- // the counters to a bitset.
- // Every counter is associated with 8 bits in the bitset.
- // We define 8 value ranges: 1, 2, 3, 4-7, 8-15, 16-31, 32-127, 128+
- // The i-th bit is set to 1 if the counter value is in the i-th range.
- // This counter-based coverage implementation is *not* thread-safe.
-
- // Returns the number of registered coverage counters.
- uintptr_t __sanitizer_get_number_of_counters();
- // Updates the counter 'bitset', clears the counters and returns the number of
- // new bits in 'bitset'.
- // If 'bitset' is nullptr, only clears the counters.
- // Otherwise 'bitset' should be at least
- // __sanitizer_get_number_of_counters bytes long and 8-aligned.
- uintptr_t
- __sanitizer_update_counter_bitset_and_clear_counters(uint8_t *bitset);
+ // Dump collected coverage info. Sorts pcs by module into individual .sancov
+ // files.
+ void __sanitizer_dump_coverage(const uintptr_t *pcs, uintptr_t len);
#ifdef __cplusplus
} // extern "C"
diff --git a/libsanitizer/include/sanitizer/lsan_interface.h b/libsanitizer/include/sanitizer/lsan_interface.h
index bdbe390..32051e6 100644
--- a/libsanitizer/include/sanitizer/lsan_interface.h
+++ b/libsanitizer/include/sanitizer/lsan_interface.h
@@ -62,8 +62,14 @@ extern "C" {
// for the program it is linked into (if the return value is non-zero). This
// function must be defined as returning a constant value; any behavior beyond
// that is unsupported.
+ // To avoid dead stripping, you may need to define this function with
+ // __attribute__((used))
int __lsan_is_turned_off();
+ // This function may be optionally provided by user and should return
+ // a string containing LSan runtime options. See lsan_flags.inc for details.
+ const char *__lsan_default_options();
+
// This function may be optionally provided by the user and should return
// a string containing LSan suppressions.
const char *__lsan_default_suppressions();
diff --git a/libsanitizer/include/sanitizer/tsan_interface.h b/libsanitizer/include/sanitizer/tsan_interface.h
new file mode 100644
index 0000000..9d91192
--- /dev/null
+++ b/libsanitizer/include/sanitizer/tsan_interface.h
@@ -0,0 +1,136 @@
+//===-- tsan_interface.h ----------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+// Public interface header for TSan.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_TSAN_INTERFACE_H
+#define SANITIZER_TSAN_INTERFACE_H
+
+#include <sanitizer/common_interface_defs.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// __tsan_release establishes a happens-before relation with a preceding
+// __tsan_acquire on the same address.
+void __tsan_acquire(void *addr);
+void __tsan_release(void *addr);
+
+// Annotations for custom mutexes.
+// The annotations allow to get better reports (with sets of locked mutexes),
+// detect more types of bugs (e.g. mutex misuses, races between lock/unlock and
+// destruction and potential deadlocks) and improve precision and performance
+// (by ignoring individual atomic operations in mutex code). However, the
+// downside is that annotated mutex code itself is not checked for correctness.
+
+// Mutex creation flags are passed to __tsan_mutex_create annotation.
+// If mutex has no constructor and __tsan_mutex_create is not called,
+// the flags may be passed to __tsan_mutex_pre_lock/__tsan_mutex_post_lock
+// annotations.
+
+// Mutex has static storage duration and no-op constructor and destructor.
+// This effectively makes tsan ignore destroy annotation.
+const unsigned __tsan_mutex_linker_init = 1 << 0;
+// Mutex is write reentrant.
+const unsigned __tsan_mutex_write_reentrant = 1 << 1;
+// Mutex is read reentrant.
+const unsigned __tsan_mutex_read_reentrant = 1 << 2;
+
+// Mutex operation flags:
+
+// Denotes read lock operation.
+const unsigned __tsan_mutex_read_lock = 1 << 3;
+// Denotes try lock operation.
+const unsigned __tsan_mutex_try_lock = 1 << 4;
+// Denotes that a try lock operation has failed to acquire the mutex.
+const unsigned __tsan_mutex_try_lock_failed = 1 << 5;
+// Denotes that the lock operation acquires multiple recursion levels.
+// Number of levels is passed in recursion parameter.
+// This is useful for annotation of e.g. Java builtin monitors,
+// for which wait operation releases all recursive acquisitions of the mutex.
+const unsigned __tsan_mutex_recursive_lock = 1 << 6;
+// Denotes that the unlock operation releases all recursion levels.
+// Number of released levels is returned and later must be passed to
+// the corresponding __tsan_mutex_post_lock annotation.
+const unsigned __tsan_mutex_recursive_unlock = 1 << 7;
+
+// Annotate creation of a mutex.
+// Supported flags: mutex creation flags.
+void __tsan_mutex_create(void *addr, unsigned flags);
+
+// Annotate destruction of a mutex.
+// Supported flags:
+// - __tsan_mutex_linker_init
+void __tsan_mutex_destroy(void *addr, unsigned flags);
+
+// Annotate start of lock operation.
+// Supported flags:
+// - __tsan_mutex_read_lock
+// - __tsan_mutex_try_lock
+// - all mutex creation flags
+void __tsan_mutex_pre_lock(void *addr, unsigned flags);
+
+// Annotate end of lock operation.
+// Supported flags:
+// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_lock)
+// - __tsan_mutex_try_lock (must match __tsan_mutex_pre_lock)
+// - __tsan_mutex_try_lock_failed
+// - __tsan_mutex_recursive_lock
+// - all mutex creation flags
+void __tsan_mutex_post_lock(void *addr, unsigned flags, int recursion);
+
+// Annotate start of unlock operation.
+// Supported flags:
+// - __tsan_mutex_read_lock
+// - __tsan_mutex_recursive_unlock
+int __tsan_mutex_pre_unlock(void *addr, unsigned flags);
+
+// Annotate end of unlock operation.
+// Supported flags:
+// - __tsan_mutex_read_lock (must match __tsan_mutex_pre_unlock)
+void __tsan_mutex_post_unlock(void *addr, unsigned flags);
+
+// Annotate start/end of notify/signal/broadcast operation.
+// Supported flags: none.
+void __tsan_mutex_pre_signal(void *addr, unsigned flags);
+void __tsan_mutex_post_signal(void *addr, unsigned flags);
+
+// Annotate start/end of a region of code where lock/unlock/signal operation
+// diverts to do something else unrelated to the mutex. This can be used to
+// annotate, for example, calls into cooperative scheduler or contention
+// profiling code.
+// These annotations must be called only from within
+// __tsan_mutex_pre/post_lock, __tsan_mutex_pre/post_unlock,
+// __tsan_mutex_pre/post_signal regions.
+// Supported flags: none.
+void __tsan_mutex_pre_divert(void *addr, unsigned flags);
+void __tsan_mutex_post_divert(void *addr, unsigned flags);
+
+// External race detection API.
+// Can be used by non-instrumented libraries to detect when their objects are
+// being used in an unsafe manner.
+// - __tsan_external_read/__tsan_external_write annotates the logical reads
+// and writes of the object at the specified address. 'caller_pc' should
+// be the PC of the library user, which the library can obtain with e.g.
+// `__builtin_return_address(0)`.
+// - __tsan_external_register_tag registers a 'tag' with the specified name,
+// which is later used in read/write annotations to denote the object type
+// - __tsan_external_assign_tag can optionally mark a heap object with a tag
+void *__tsan_external_register_tag(const char *object_type);
+void __tsan_external_register_header(void *tag, const char *header);
+void __tsan_external_assign_tag(void *addr, void *tag);
+void __tsan_external_read(void *addr, void *caller_pc, void *tag);
+void __tsan_external_write(void *addr, void *caller_pc, void *tag);
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+#endif // SANITIZER_TSAN_INTERFACE_H
diff --git a/libsanitizer/interception/interception.h b/libsanitizer/interception/interception.h
index 0db36dd..75631da 100644
--- a/libsanitizer/interception/interception.h
+++ b/libsanitizer/interception/interception.h
@@ -13,8 +13,8 @@
#ifndef INTERCEPTION_H
#define INTERCEPTION_H
-#if !defined(__linux__) && !defined(__FreeBSD__) && \
- !defined(__APPLE__) && !defined(_WIN32)
+#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__APPLE__) && \
+ !defined(__NetBSD__) && !defined(_WIN32) && !defined(__Fuchsia__)
# error "Interception doesn't work on this operating system."
#endif
@@ -127,7 +127,7 @@ const interpose_substitution substitution_##func_name[] \
extern "C" ret_type func(__VA_ARGS__);
# define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \
extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__);
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) || defined(__NetBSD__)
# define WRAP(x) __interceptor_ ## x
# define WRAPPER_NAME(x) "__interceptor_" #x
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
@@ -137,7 +137,7 @@ const interpose_substitution substitution_##func_name[] \
# define DECLARE_WRAPPER(ret_type, func, ...) \
extern "C" ret_type func(__VA_ARGS__) \
__attribute__((alias("__interceptor_" #func), visibility("default")));
-#else
+#elif !defined(__Fuchsia__)
# define WRAP(x) __interceptor_ ## x
# define WRAPPER_NAME(x) "__interceptor_" #x
# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
@@ -146,7 +146,15 @@ const interpose_substitution substitution_##func_name[] \
__attribute__((weak, alias("__interceptor_" #func), visibility("default")));
#endif
-#if !defined(__APPLE__)
+#if defined(__Fuchsia__)
+// There is no general interception at all on Fuchsia.
+// Sanitizer runtimes just define functions directly to preempt them,
+// and have bespoke ways to access the underlying libc functions.
+# include <zircon/sanitizer.h>
+# define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default")))
+# define REAL(x) __unsanitized_##x
+# define DECLARE_REAL(ret_type, func, ...)
+#elif !defined(__APPLE__)
# define PTR_TO_REAL(x) real_##x
# define REAL(x) __interception::PTR_TO_REAL(x)
# define FUNC_TYPE(x) x##_f
@@ -164,15 +172,19 @@ const interpose_substitution substitution_##func_name[] \
# define ASSIGN_REAL(x, y)
#endif // __APPLE__
+#if !defined(__Fuchsia__)
#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...) \
DECLARE_REAL(ret_type, func, __VA_ARGS__) \
extern "C" ret_type WRAP(func)(__VA_ARGS__);
+#else
+#define DECLARE_REAL_AND_INTERCEPTOR(ret_type, func, ...)
+#endif
// Generally, you don't need to use DEFINE_REAL by itself, as INTERCEPTOR
// macros does its job. In exceptional cases you may need to call REAL(foo)
// without defining INTERCEPTOR(..., foo, ...). For example, if you override
// foo with an interceptor for other function.
-#if !defined(__APPLE__)
+#if !defined(__APPLE__) && !defined(__Fuchsia__)
# define DEFINE_REAL(ret_type, func, ...) \
typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
namespace __interception { \
@@ -182,7 +194,18 @@ const interpose_substitution substitution_##func_name[] \
# define DEFINE_REAL(ret_type, func, ...)
#endif
-#if !defined(__APPLE__)
+#if defined(__Fuchsia__)
+
+// We need to define the __interceptor_func name just to get
+// sanitizer_common/scripts/gen_dynamic_list.py to export func.
+// But we don't need to export __interceptor_func to get that.
+#define INTERCEPTOR(ret_type, func, ...) \
+ extern "C"[[ gnu::alias(#func), gnu::visibility("hidden") ]] ret_type \
+ __interceptor_##func(__VA_ARGS__); \
+ extern "C" INTERCEPTOR_ATTRIBUTE ret_type func(__VA_ARGS__)
+
+#elif !defined(__APPLE__)
+
#define INTERCEPTOR(ret_type, func, ...) \
DEFINE_REAL(ret_type, func, __VA_ARGS__) \
DECLARE_WRAPPER(ret_type, func, __VA_ARGS__) \
@@ -239,7 +262,7 @@ typedef unsigned long uptr; // NOLINT
#define INCLUDED_FROM_INTERCEPTION_LIB
-#if defined(__linux__) || defined(__FreeBSD__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
# include "interception_linux.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func)
# define INTERCEPT_FUNCTION_VER(func, symver) \
@@ -249,7 +272,7 @@ typedef unsigned long uptr; // NOLINT
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_MAC(func)
# define INTERCEPT_FUNCTION_VER(func, symver) \
INTERCEPT_FUNCTION_VER_MAC(func, symver)
-#else // defined(_WIN32)
+#elif defined(_WIN32)
# include "interception_win.h"
# define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_WIN(func)
# define INTERCEPT_FUNCTION_VER(func, symver) \
diff --git a/libsanitizer/interception/interception_linux.cc b/libsanitizer/interception/interception_linux.cc
index 0a8305b..888b2ce 100644
--- a/libsanitizer/interception/interception_linux.cc
+++ b/libsanitizer/interception/interception_linux.cc
@@ -10,14 +10,22 @@
// Linux-specific interception methods.
//===----------------------------------------------------------------------===//
-#if defined(__linux__) || defined(__FreeBSD__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#include "interception.h"
#include <dlfcn.h> // for dlsym() and dlvsym()
+#ifdef __NetBSD__
+#include "sanitizer_common/sanitizer_libc.h"
+#endif
+
namespace __interception {
bool GetRealFunctionAddress(const char *func_name, uptr *func_addr,
uptr real, uptr wrapper) {
+#ifdef __NetBSD__
+ // XXX: Find a better way to handle renames
+ if (internal_strcmp(func_name, "sigaction") == 0) func_name = "__sigaction14";
+#endif
*func_addr = (uptr)dlsym(RTLD_NEXT, func_name);
return real == wrapper;
}
@@ -30,5 +38,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver) {
} // namespace __interception
-
-#endif // __linux__ || __FreeBSD__
+#endif // __linux__ || __FreeBSD__ || __NetBSD__
diff --git a/libsanitizer/interception/interception_linux.h b/libsanitizer/interception/interception_linux.h
index 61bf48a..f596518 100644
--- a/libsanitizer/interception/interception_linux.h
+++ b/libsanitizer/interception/interception_linux.h
@@ -10,7 +10,7 @@
// Linux-specific interception methods.
//===----------------------------------------------------------------------===//
-#if defined(__linux__) || defined(__FreeBSD__)
+#if defined(__linux__) || defined(__FreeBSD__) || defined(__NetBSD__)
#if !defined(INCLUDED_FROM_INTERCEPTION_LIB)
# error "interception_linux.h should be included from interception library only"
@@ -42,4 +42,4 @@ void *GetFuncAddrVer(const char *func_name, const char *ver);
#endif // !defined(__ANDROID__)
#endif // INTERCEPTION_LINUX_H
-#endif // __linux__ || __FreeBSD__
+#endif // __linux__ || __FreeBSD__ || __NetBSD__
diff --git a/libsanitizer/interception/interception_win.cc b/libsanitizer/interception/interception_win.cc
index fa81162..1957397 100644
--- a/libsanitizer/interception/interception_win.cc
+++ b/libsanitizer/interception/interception_win.cc
@@ -146,10 +146,16 @@ static void InterceptionFailed() {
}
static bool DistanceIsWithin2Gig(uptr from, uptr target) {
+#if SANITIZER_WINDOWS64
if (from < target)
return target - from <= (uptr)0x7FFFFFFFU;
else
return from - target <= (uptr)0x80000000U;
+#else
+ // In a 32-bit address space, the address calculation will wrap, so this check
+ // is unnecessary.
+ return true;
+#endif
}
static uptr GetMmapGranularity() {
@@ -215,9 +221,8 @@ static bool IsMemoryPadding(uptr address, uptr size) {
return true;
}
-static const u8 kHintNop10Bytes[] = {
- 0x66, 0x66, 0x0F, 0x1F, 0x84,
- 0x00, 0x00, 0x00, 0x00, 0x00
+static const u8 kHintNop9Bytes[] = {
+ 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00
};
template<class T>
@@ -232,8 +237,8 @@ static bool FunctionHasPrefix(uptr address, const T &pattern) {
static bool FunctionHasPadding(uptr address, uptr size) {
if (IsMemoryPadding(address - size, size))
return true;
- if (size <= sizeof(kHintNop10Bytes) &&
- FunctionHasPrefix(address, kHintNop10Bytes))
+ if (size <= sizeof(kHintNop9Bytes) &&
+ FunctionHasPrefix(address, kHintNop9Bytes))
return true;
return false;
}
@@ -469,7 +474,7 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
switch (*(u8*)address) {
case 0xA1: // A1 XX XX XX XX XX XX XX XX :
// movabs eax, dword ptr ds:[XXXXXXXX]
- return 8;
+ return 9;
}
switch (*(u16*)address) {
@@ -487,6 +492,11 @@ static size_t GetInstructionSize(uptr address, size_t* rel_offset = nullptr) {
case 0x5741: // push r15
case 0x9066: // Two-byte NOP
return 2;
+
+ case 0x058B: // 8B 05 XX XX XX XX : mov eax, dword ptr [XX XX XX XX]
+ if (rel_offset)
+ *rel_offset = 2;
+ return 6;
}
switch (0x00FFFFFF & *(u32*)address) {
@@ -870,6 +880,8 @@ uptr InternalGetProcAddress(void *module, const char *func_name) {
IMAGE_DATA_DIRECTORY *export_directory =
&headers->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];
+ if (export_directory->Size == 0)
+ return 0;
RVAPtr<IMAGE_EXPORT_DIRECTORY> exports(module,
export_directory->VirtualAddress);
RVAPtr<DWORD> functions(module, exports->AddressOfFunctions);
diff --git a/libsanitizer/libbacktrace/backtrace-rename.h b/libsanitizer/libbacktrace/backtrace-rename.h
index 159512f..2555fe5 100644
--- a/libsanitizer/libbacktrace/backtrace-rename.h
+++ b/libsanitizer/libbacktrace/backtrace-rename.h
@@ -11,6 +11,7 @@
#define backtrace_qsort __asan_backtrace_qsort
#define backtrace_release_view __asan_backtrace_release_view
#define backtrace_syminfo __asan_backtrace_syminfo
+#define backtrace_uncompress_zdebug __asan_backtrace_uncompress_zdebug
#define backtrace_vector_finish __asan_backtrace_vector_finish
#define backtrace_vector_grow __asan_backtrace_vector_grow
#define backtrace_vector_release __asan_backtrace_vector_release
diff --git a/libsanitizer/lsan/Makefile.am b/libsanitizer/lsan/Makefile.am
index 294342b..700d15f 100644
--- a/libsanitizer/lsan/Makefile.am
+++ b/libsanitizer/lsan/Makefile.am
@@ -12,18 +12,22 @@ ACLOCAL_AMFLAGS = -I m4
noinst_LTLIBRARIES = libsanitizer_lsan.la
if LSAN_SUPPORTED
toolexeclib_LTLIBRARIES = liblsan.la
+nodist_toolexeclib_HEADERS = liblsan_preinit.o
endif
sanitizer_lsan_files = \
lsan_common.cc \
- lsan_common_linux.cc
+ lsan_common_linux.cc \
+ lsan_common_mac.cc
lsan_files = \
$(sanitizer_lsan_files) \
lsan.cc \
+ lsan_linux.cc \
+ lsan_mac.cc \
+ lsan_malloc_mac.cc \
lsan_allocator.cc \
lsan_interceptors.cc \
- lsan_preinit.cc \
lsan_thread.cc
libsanitizer_lsan_la_SOURCES = $(sanitizer_lsan_files)
@@ -36,6 +40,9 @@ endif
liblsan_la_LIBADD += $(LIBSTDCXX_RAW_CXX_LDFLAGS)
liblsan_la_LDFLAGS = -version-info `grep -v '^\#' $(srcdir)/libtool-version` $(link_liblsan)
+liblsan_preinit.o: lsan_preinit.o
+ cp $< $@
+
# Work around what appears to be a GNU make bug handling MAKEFLAGS
# values defined in terms of make variables, as is the case for CC and
# friends when we are called from the top level Makefile.
diff --git a/libsanitizer/lsan/Makefile.in b/libsanitizer/lsan/Makefile.in
index d951741..8550250 100644
--- a/libsanitizer/lsan/Makefile.in
+++ b/libsanitizer/lsan/Makefile.in
@@ -15,6 +15,7 @@
@SET_MAKE@
+
VPATH = @srcdir@
am__make_dryrun = \
{ \
@@ -100,16 +101,18 @@ am__uninstall_files_from_dir = { \
|| { echo " ( cd '$$dir' && rm -f" $$files ")"; \
$(am__cd) "$$dir" && rm -f $$files; }; \
}
-am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
+am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
+ "$(DESTDIR)$(toolexeclibdir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES)
am__DEPENDENCIES_1 =
liblsan_la_DEPENDENCIES = \
$(top_builddir)/sanitizer_common/libsanitizer_common.la \
$(top_builddir)/interception/libinterception.la \
$(am__append_1) $(am__DEPENDENCIES_1)
-am__objects_1 = lsan_common.lo lsan_common_linux.lo
-am__objects_2 = $(am__objects_1) lsan.lo lsan_allocator.lo \
- lsan_interceptors.lo lsan_preinit.lo lsan_thread.lo
+am__objects_1 = lsan_common.lo lsan_common_linux.lo lsan_common_mac.lo
+am__objects_2 = $(am__objects_1) lsan.lo lsan_linux.lo lsan_mac.lo \
+ lsan_malloc_mac.lo lsan_allocator.lo lsan_interceptors.lo \
+ lsan_thread.lo
am_liblsan_la_OBJECTS = $(am__objects_2)
liblsan_la_OBJECTS = $(am_liblsan_la_OBJECTS)
liblsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -138,6 +141,7 @@ am__can_run_installinfo = \
n|no|NO) false;; \
*) (install-info --version) >/dev/null 2>&1;; \
esac
+HEADERS = $(nodist_toolexeclib_HEADERS)
ETAGS = etags
CTAGS = ctags
ACLOCAL = @ACLOCAL@
@@ -297,16 +301,20 @@ AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
ACLOCAL_AMFLAGS = -I m4
noinst_LTLIBRARIES = libsanitizer_lsan.la
@LSAN_SUPPORTED_TRUE@toolexeclib_LTLIBRARIES = liblsan.la
+@LSAN_SUPPORTED_TRUE@nodist_toolexeclib_HEADERS = liblsan_preinit.o
sanitizer_lsan_files = \
lsan_common.cc \
- lsan_common_linux.cc
+ lsan_common_linux.cc \
+ lsan_common_mac.cc
lsan_files = \
$(sanitizer_lsan_files) \
lsan.cc \
+ lsan_linux.cc \
+ lsan_mac.cc \
+ lsan_malloc_mac.cc \
lsan_allocator.cc \
lsan_interceptors.cc \
- lsan_preinit.cc \
lsan_thread.cc
libsanitizer_lsan_la_SOURCES = $(sanitizer_lsan_files)
@@ -446,8 +454,11 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common_linux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_common_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_interceptors.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_preinit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_linux.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_malloc_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lsan_thread.Plo@am__quote@
.cc.o:
@@ -476,6 +487,27 @@ mostlyclean-libtool:
clean-libtool:
-rm -rf .libs _libs
+install-nodist_toolexeclibHEADERS: $(nodist_toolexeclib_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(nodist_toolexeclib_HEADERS)'; test -n "$(toolexeclibdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(toolexeclibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(toolexeclibdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(toolexeclibdir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(toolexeclibdir)" || exit $$?; \
+ done
+
+uninstall-nodist_toolexeclibHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(nodist_toolexeclib_HEADERS)'; test -n "$(toolexeclibdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(toolexeclibdir)'; $(am__uninstall_files_from_dir)
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
@@ -530,9 +562,9 @@ distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
check-am: all-am
check: check-am
-all-am: Makefile $(LTLIBRARIES)
+all-am: Makefile $(LTLIBRARIES) $(HEADERS)
installdirs:
- for dir in "$(DESTDIR)$(toolexeclibdir)"; do \
+ for dir in "$(DESTDIR)$(toolexeclibdir)" "$(DESTDIR)$(toolexeclibdir)"; do \
test -z "$$dir" || $(MKDIR_P) "$$dir"; \
done
install: install-am
@@ -594,7 +626,8 @@ install-dvi: install-dvi-am
install-dvi-am:
-install-exec-am: install-toolexeclibLTLIBRARIES
+install-exec-am: install-nodist_toolexeclibHEADERS \
+ install-toolexeclibLTLIBRARIES
install-html: install-html-am
@@ -634,7 +667,8 @@ ps: ps-am
ps-am:
-uninstall-am: uninstall-toolexeclibLTLIBRARIES
+uninstall-am: uninstall-nodist_toolexeclibHEADERS \
+ uninstall-toolexeclibLTLIBRARIES
.MAKE: install-am install-strip
@@ -645,14 +679,19 @@ uninstall-am: uninstall-toolexeclibLTLIBRARIES
html html-am info info-am install install-am install-data \
install-data-am install-dvi install-dvi-am install-exec \
install-exec-am install-html install-html-am install-info \
- install-info-am install-man install-pdf install-pdf-am \
- install-ps install-ps-am install-strip \
- install-toolexeclibLTLIBRARIES installcheck installcheck-am \
- installdirs maintainer-clean maintainer-clean-generic \
- mostlyclean mostlyclean-compile mostlyclean-generic \
- mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
- uninstall-am uninstall-toolexeclibLTLIBRARIES
-
+ install-info-am install-man install-nodist_toolexeclibHEADERS \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip install-toolexeclibLTLIBRARIES installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags uninstall uninstall-am \
+ uninstall-nodist_toolexeclibHEADERS \
+ uninstall-toolexeclibLTLIBRARIES
+
+
+liblsan_preinit.o: lsan_preinit.o
+ cp $< $@
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
diff --git a/libsanitizer/lsan/lsan.cc b/libsanitizer/lsan/lsan.cc
index 2ded554..7540aeb 100644
--- a/libsanitizer/lsan/lsan.cc
+++ b/libsanitizer/lsan/lsan.cc
@@ -54,6 +54,9 @@ static void InitializeFlags() {
RegisterLsanFlags(&parser, f);
RegisterCommonFlags(&parser);
+ // Override from user-specified string.
+ const char *lsan_default_options = MaybeCallLsanDefaultOptions();
+ parser.ParseString(lsan_default_options);
parser.ParseString(GetEnv("LSAN_OPTIONS"));
SetVerbosity(common_flags()->verbosity);
@@ -63,6 +66,18 @@ static void InitializeFlags() {
if (common_flags()->help) parser.PrintFlagDescriptions();
}
+static void OnStackUnwind(const SignalContext &sig, const void *,
+ BufferedStackTrace *stack) {
+ GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp,
+ sig.context,
+ common_flags()->fast_unwind_on_fatal);
+}
+
+void LsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+ HandleDeadlySignal(siginfo, context, GetCurrentThread(), &OnStackUnwind,
+ nullptr);
+}
+
extern "C" void __lsan_init() {
CHECK(!lsan_init_is_running);
if (lsan_inited)
@@ -74,9 +89,11 @@ extern "C" void __lsan_init() {
InitializeFlags();
InitCommonLsan();
InitializeAllocator();
+ ReplaceSystemMalloc();
InitTlsSize();
InitializeInterceptors();
InitializeThreadRegistry();
+ InstallDeadlySignalHandlers(LsanOnDeadlySignal);
u32 tid = ThreadCreate(0, 0, true);
CHECK_EQ(tid, 0);
ThreadStart(tid, GetTid());
diff --git a/libsanitizer/lsan/lsan.h b/libsanitizer/lsan/lsan.h
index 6d2d427..42d4214 100644
--- a/libsanitizer/lsan/lsan.h
+++ b/libsanitizer/lsan/lsan.h
@@ -10,24 +10,15 @@
//
//===----------------------------------------------------------------------===//
+#include "lsan_thread.h"
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
-#define GET_STACK_TRACE(max_size, fast) \
- BufferedStackTrace stack; \
- { \
- uptr stack_top = 0, stack_bottom = 0; \
- ThreadContext *t; \
- if (fast && (t = CurrentThreadContext())) { \
- stack_top = t->stack_end(); \
- stack_bottom = t->stack_begin(); \
- } \
- if (!SANITIZER_MIPS || \
- IsValidFrame(GET_CURRENT_FRAME(), stack_top, stack_bottom)) { \
- stack.Unwind(max_size, StackTrace::GetCurrentPc(), GET_CURRENT_FRAME(), \
- /* context */ 0, stack_top, stack_bottom, fast); \
- } \
- }
+#define GET_STACK_TRACE(max_size, fast) \
+ __sanitizer::BufferedStackTrace stack; \
+ GetStackTraceWithPcBpAndContext(&stack, max_size, \
+ StackTrace::GetCurrentPc(), \
+ GET_CURRENT_FRAME(), nullptr, fast);
#define GET_STACK_TRACE_FATAL \
GET_STACK_TRACE(kStackTraceMax, common_flags()->fast_unwind_on_fatal)
@@ -36,13 +27,41 @@
GET_STACK_TRACE(__sanitizer::common_flags()->malloc_context_size, \
common_flags()->fast_unwind_on_malloc)
+#define GET_STACK_TRACE_THREAD GET_STACK_TRACE(kStackTraceMax, true)
+
namespace __lsan {
void InitializeInterceptors();
+void ReplaceSystemMalloc();
+
+#define ENSURE_LSAN_INITED do { \
+ CHECK(!lsan_init_is_running); \
+ if (!lsan_inited) \
+ __lsan_init(); \
+} while (0)
+
+// Get the stack trace with the given pc and bp.
+// The pc will be in the position 0 of the resulting stack trace.
+// The bp may refer to the current frame or to the caller's frame.
+ALWAYS_INLINE
+void GetStackTraceWithPcBpAndContext(__sanitizer::BufferedStackTrace *stack,
+ __sanitizer::uptr max_depth,
+ __sanitizer::uptr pc, __sanitizer::uptr bp,
+ void *context, bool fast) {
+ uptr stack_top = 0, stack_bottom = 0;
+ ThreadContext *t;
+ if (fast && (t = CurrentThreadContext())) {
+ stack_top = t->stack_end();
+ stack_bottom = t->stack_begin();
+ }
+ if (!SANITIZER_MIPS || IsValidFrame(bp, stack_top, stack_bottom)) {
+ stack->Unwind(max_depth, pc, bp, context, stack_top, stack_bottom, fast);
+ }
+}
} // namespace __lsan
extern bool lsan_inited;
extern bool lsan_init_is_running;
-extern "C" void __lsan_init();
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __lsan_init();
diff --git a/libsanitizer/lsan/lsan_allocator.cc b/libsanitizer/lsan/lsan_allocator.cc
index 0d2fcea..9e16680 100644
--- a/libsanitizer/lsan/lsan_allocator.cc
+++ b/libsanitizer/lsan/lsan_allocator.cc
@@ -13,7 +13,9 @@
#include "lsan_allocator.h"
#include "sanitizer_common/sanitizer_allocator.h"
+#include "sanitizer_common/sanitizer_allocator_checks.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
+#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
@@ -22,51 +24,27 @@
extern "C" void *memset(void *ptr, int value, uptr num);
namespace __lsan {
-
-struct ChunkMetadata {
- u8 allocated : 8; // Must be first.
- ChunkTag tag : 2;
- uptr requested_size : 54;
- u32 stack_trace_id;
-};
-
-#if defined(__mips64) || defined(__aarch64__)
+#if defined(__i386__) || defined(__arm__)
+static const uptr kMaxAllowedMallocSize = 1UL << 30;
+#elif defined(__mips64) || defined(__aarch64__)
static const uptr kMaxAllowedMallocSize = 4UL << 30;
-static const uptr kRegionSizeLog = 20;
-static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
-typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
-typedef CompactSizeClassMap SizeClassMap;
-typedef SizeClassAllocator32<0, SANITIZER_MMAP_RANGE_SIZE,
- sizeof(ChunkMetadata), SizeClassMap, kRegionSizeLog, ByteMap>
- PrimaryAllocator;
#else
static const uptr kMaxAllowedMallocSize = 8UL << 30;
-
-struct AP64 { // Allocator64 parameters. Deliberately using a short name.
- static const uptr kSpaceBeg = 0x600000000000ULL;
- static const uptr kSpaceSize = 0x40000000000ULL; // 4T.
- static const uptr kMetadataSize = sizeof(ChunkMetadata);
- typedef DefaultSizeClassMap SizeClassMap;
- typedef NoOpMapUnmapCallback MapUnmapCallback;
- static const uptr kFlags = 0;
-};
-
-typedef SizeClassAllocator64<AP64> PrimaryAllocator;
#endif
-typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
typedef LargeMmapAllocator<> SecondaryAllocator;
typedef CombinedAllocator<PrimaryAllocator, AllocatorCache,
SecondaryAllocator> Allocator;
static Allocator allocator;
-static THREADLOCAL AllocatorCache cache;
void InitializeAllocator() {
- allocator.InitLinkerInitialized(common_flags()->allocator_may_return_null);
+ SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
+ allocator.InitLinkerInitialized(
+ common_flags()->allocator_release_to_os_interval_ms);
}
void AllocatorThreadFinish() {
- allocator.SwallowCache(&cache);
+ allocator.SwallowCache(GetAllocatorCache());
}
static ChunkMetadata *Metadata(const void *p) {
@@ -96,9 +74,9 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
size = 1;
if (size > kMaxAllowedMallocSize) {
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", size);
- return nullptr;
+ return Allocator::FailureHandler::OnBadRequest();
}
- void *p = allocator.Allocate(&cache, size, alignment, false);
+ void *p = allocator.Allocate(GetAllocatorCache(), size, alignment);
// Do not rely on the allocator to clear the memory (it's slow).
if (cleared && allocator.FromPrimary(p))
memset(p, 0, size);
@@ -108,11 +86,18 @@ void *Allocate(const StackTrace &stack, uptr size, uptr alignment,
return p;
}
+static void *Calloc(uptr nmemb, uptr size, const StackTrace &stack) {
+ if (UNLIKELY(CheckForCallocOverflow(size, nmemb)))
+ return Allocator::FailureHandler::OnBadRequest();
+ size *= nmemb;
+ return Allocate(stack, size, 1, true);
+}
+
void Deallocate(void *p) {
if (&__sanitizer_free_hook) __sanitizer_free_hook(p);
RunFreeHooks(p);
RegisterDeallocation(p);
- allocator.Deallocate(&cache, p);
+ allocator.Deallocate(GetAllocatorCache(), p);
}
void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
@@ -120,17 +105,17 @@ void *Reallocate(const StackTrace &stack, void *p, uptr new_size,
RegisterDeallocation(p);
if (new_size > kMaxAllowedMallocSize) {
Report("WARNING: LeakSanitizer failed to allocate %zu bytes\n", new_size);
- allocator.Deallocate(&cache, p);
- return nullptr;
+ allocator.Deallocate(GetAllocatorCache(), p);
+ return Allocator::FailureHandler::OnBadRequest();
}
- p = allocator.Reallocate(&cache, p, new_size, alignment);
+ p = allocator.Reallocate(GetAllocatorCache(), p, new_size, alignment);
RegisterAllocation(stack, p, new_size);
return p;
}
void GetAllocatorCacheRange(uptr *begin, uptr *end) {
- *begin = (uptr)&cache;
- *end = *begin + sizeof(cache);
+ *begin = (uptr)GetAllocatorCache();
+ *end = *begin + sizeof(AllocatorCache);
}
uptr GetMallocUsableSize(const void *p) {
@@ -139,6 +124,39 @@ uptr GetMallocUsableSize(const void *p) {
return m->requested_size;
}
+void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack) {
+ if (UNLIKELY(!IsPowerOfTwo(alignment))) {
+ errno = errno_EINVAL;
+ return Allocator::FailureHandler::OnBadRequest();
+ }
+ return SetErrnoOnNull(Allocate(stack, size, alignment, kAlwaysClearMemory));
+}
+
+void *lsan_malloc(uptr size, const StackTrace &stack) {
+ return SetErrnoOnNull(Allocate(stack, size, 1, kAlwaysClearMemory));
+}
+
+void lsan_free(void *p) {
+ Deallocate(p);
+}
+
+void *lsan_realloc(void *p, uptr size, const StackTrace &stack) {
+ return SetErrnoOnNull(Reallocate(stack, p, size, 1));
+}
+
+void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack) {
+ return SetErrnoOnNull(Calloc(nmemb, size, stack));
+}
+
+void *lsan_valloc(uptr size, const StackTrace &stack) {
+ return SetErrnoOnNull(
+ Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory));
+}
+
+uptr lsan_mz_size(const void *p) {
+ return GetMallocUsableSize(p);
+}
+
///// Interface to the common LSan module. /////
void LockAllocator() {
@@ -254,4 +272,17 @@ SANITIZER_INTERFACE_ATTRIBUTE
uptr __sanitizer_get_allocated_size(const void *p) {
return GetMallocUsableSize(p);
}
+
+#if !SANITIZER_SUPPORTS_WEAK_HOOKS
+// Provide default (no-op) implementation of malloc hooks.
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_malloc_hook(void *ptr, uptr size) {
+ (void)ptr;
+ (void)size;
+}
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+void __sanitizer_free_hook(void *ptr) {
+ (void)ptr;
+}
+#endif
} // extern "C"
diff --git a/libsanitizer/lsan/lsan_allocator.h b/libsanitizer/lsan/lsan_allocator.h
index aae0d28..b0c0ec2 100644
--- a/libsanitizer/lsan/lsan_allocator.h
+++ b/libsanitizer/lsan/lsan_allocator.h
@@ -13,8 +13,10 @@
#ifndef LSAN_ALLOCATOR_H
#define LSAN_ALLOCATOR_H
+#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_common.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "lsan_common.h"
namespace __lsan {
@@ -32,6 +34,61 @@ void GetAllocatorCacheRange(uptr *begin, uptr *end);
void AllocatorThreadFinish();
void InitializeAllocator();
+const bool kAlwaysClearMemory = true;
+
+struct ChunkMetadata {
+ u8 allocated : 8; // Must be first.
+ ChunkTag tag : 2;
+#if SANITIZER_WORDSIZE == 64
+ uptr requested_size : 54;
+#else
+ uptr requested_size : 32;
+ uptr padding : 22;
+#endif
+ u32 stack_trace_id;
+};
+
+#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
+ defined(__arm__)
+static const uptr kRegionSizeLog = 20;
+static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
+typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
+
+struct AP32 {
+ static const uptr kSpaceBeg = 0;
+ static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
+ static const uptr kMetadataSize = sizeof(ChunkMetadata);
+ typedef __sanitizer::CompactSizeClassMap SizeClassMap;
+ static const uptr kRegionSizeLog = __lsan::kRegionSizeLog;
+ typedef __lsan::ByteMap ByteMap;
+ typedef NoOpMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+typedef SizeClassAllocator32<AP32> PrimaryAllocator;
+#elif defined(__x86_64__) || defined(__powerpc64__)
+struct AP64 { // Allocator64 parameters. Deliberately using a short name.
+ static const uptr kSpaceBeg = 0x600000000000ULL;
+ static const uptr kSpaceSize = 0x40000000000ULL; // 4T.
+ static const uptr kMetadataSize = sizeof(ChunkMetadata);
+ typedef DefaultSizeClassMap SizeClassMap;
+ typedef NoOpMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+
+typedef SizeClassAllocator64<AP64> PrimaryAllocator;
+#endif
+typedef SizeClassAllocatorLocalCache<PrimaryAllocator> AllocatorCache;
+
+AllocatorCache *GetAllocatorCache();
+
+void *lsan_memalign(uptr alignment, uptr size, const StackTrace &stack);
+void *lsan_malloc(uptr size, const StackTrace &stack);
+void lsan_free(void *p);
+void *lsan_realloc(void *p, uptr size, const StackTrace &stack);
+void *lsan_calloc(uptr nmemb, uptr size, const StackTrace &stack);
+void *lsan_valloc(uptr size, const StackTrace &stack);
+uptr lsan_mz_size(const void *p);
+
} // namespace __lsan
#endif // LSAN_ALLOCATOR_H
diff --git a/libsanitizer/lsan/lsan_common.cc b/libsanitizer/lsan/lsan_common.cc
index 41024e1..a3274d5 100644
--- a/libsanitizer/lsan/lsan_common.cc
+++ b/libsanitizer/lsan/lsan_common.cc
@@ -30,20 +30,15 @@ namespace __lsan {
// also to protect the global list of root regions.
BlockingMutex global_mutex(LINKER_INITIALIZED);
-__attribute__((tls_model("initial-exec")))
-THREADLOCAL int disable_counter;
-bool DisabledInThisThread() { return disable_counter > 0; }
-void DisableInThisThread() { disable_counter++; }
-void EnableInThisThread() {
- if (!disable_counter && common_flags()->detect_leaks) {
+Flags lsan_flags;
+
+void DisableCounterUnderflow() {
+ if (common_flags()->detect_leaks) {
Report("Unmatched call to __lsan_enable().\n");
Die();
}
- disable_counter--;
}
-Flags lsan_flags;
-
void Flags::SetDefaults() {
#define LSAN_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
#include "lsan_flags.inc"
@@ -71,6 +66,19 @@ ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
static SuppressionContext *suppression_ctx = nullptr;
static const char kSuppressionLeak[] = "leak";
static const char *kSuppressionTypes[] = { kSuppressionLeak };
+static const char kStdSuppressions[] =
+#if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
+ // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
+ // definition.
+ "leak:*pthread_exit*\n"
+#endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT
+#if SANITIZER_MAC
+ // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173
+ "leak:*_os_trace*\n"
+#endif
+ // TLS leak in some glibc versions, described in
+ // https://sourceware.org/bugzilla/show_bug.cgi?id=12650.
+ "leak:*tls_get_addr*\n";
void InitializeSuppressions() {
CHECK_EQ(nullptr, suppression_ctx);
@@ -79,6 +87,7 @@ void InitializeSuppressions() {
suppression_ctx->ParseFromFile(flags()->suppressions);
if (&__lsan_default_suppressions)
suppression_ctx->Parse(__lsan_default_suppressions());
+ suppression_ctx->Parse(kStdSuppressions);
}
static SuppressionContext *GetSuppressionContext() {
@@ -86,12 +95,9 @@ static SuppressionContext *GetSuppressionContext() {
return suppression_ctx;
}
-struct RootRegion {
- const void *begin;
- uptr size;
-};
+static InternalMmapVector<RootRegion> *root_regions;
-InternalMmapVector<RootRegion> *root_regions;
+InternalMmapVector<RootRegion> const *GetRootRegions() { return root_regions; }
void InitializeRootRegions() {
CHECK(!root_regions);
@@ -99,6 +105,10 @@ void InitializeRootRegions() {
root_regions = new(placeholder) InternalMmapVector<RootRegion>(1);
}
+const char *MaybeCallLsanDefaultOptions() {
+ return (&__lsan_default_options) ? __lsan_default_options() : "";
+}
+
void InitCommonLsan() {
InitializeRootRegions();
if (common_flags()->detect_leaks) {
@@ -114,7 +124,6 @@ class Decorator: public __sanitizer::SanitizerCommonDecorator {
Decorator() : SanitizerCommonDecorator() { }
const char *Error() { return Red(); }
const char *Leak() { return Blue(); }
- const char *End() { return Default(); }
};
static inline bool CanBeAHeapPointer(uptr p) {
@@ -178,6 +187,23 @@ void ScanRangeForPointers(uptr begin, uptr end,
}
}
+// Scans a global range for pointers
+void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier) {
+ uptr allocator_begin = 0, allocator_end = 0;
+ GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
+ if (begin <= allocator_begin && allocator_begin < end) {
+ CHECK_LE(allocator_begin, allocator_end);
+ CHECK_LE(allocator_end, end);
+ if (begin < allocator_begin)
+ ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
+ kReachable);
+ if (allocator_end < end)
+ ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL", kReachable);
+ } else {
+ ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable);
+ }
+}
+
void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
Frontier *frontier = reinterpret_cast<Frontier *>(arg);
ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable);
@@ -186,11 +212,11 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) {
// Scans thread data (stacks and TLS) for heap pointers.
static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
Frontier *frontier) {
- InternalScopedBuffer<uptr> registers(SuspendedThreadsList::RegisterCount());
+ InternalScopedBuffer<uptr> registers(suspended_threads.RegisterCount());
uptr registers_begin = reinterpret_cast<uptr>(registers.data());
uptr registers_end = registers_begin + registers.size();
- for (uptr i = 0; i < suspended_threads.thread_count(); i++) {
- uptr os_id = static_cast<uptr>(suspended_threads.GetThreadID(i));
+ for (uptr i = 0; i < suspended_threads.ThreadCount(); i++) {
+ tid_t os_id = static_cast<tid_t>(suspended_threads.GetThreadID(i));
LOG_THREADS("Processing thread %d.\n", os_id);
uptr stack_begin, stack_end, tls_begin, tls_end, cache_begin, cache_end;
DTLS *dtls;
@@ -204,11 +230,13 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
continue;
}
uptr sp;
- bool have_registers =
- (suspended_threads.GetRegistersAndSP(i, registers.data(), &sp) == 0);
- if (!have_registers) {
- Report("Unable to get registers from thread %d.\n");
- // If unable to get SP, consider the entire stack to be reachable.
+ PtraceRegistersStatus have_registers =
+ suspended_threads.GetRegistersAndSP(i, registers.data(), &sp);
+ if (have_registers != REGISTERS_AVAILABLE) {
+ Report("Unable to get registers from thread %d.\n", os_id);
+ // If unable to get SP, consider the entire stack to be reachable unless
+ // GetRegistersAndSP failed with ESRCH.
+ if (have_registers == REGISTERS_UNAVAILABLE_FATAL) continue;
sp = stack_begin;
}
@@ -242,21 +270,23 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
}
if (flags()->use_tls) {
- LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end);
- if (cache_begin == cache_end) {
- ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
- } else {
- // Because LSan should not be loaded with dlopen(), we can assume
- // that allocator cache will be part of static TLS image.
- CHECK_LE(tls_begin, cache_begin);
- CHECK_GE(tls_end, cache_end);
- if (tls_begin < cache_begin)
- ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
- kReachable);
- if (tls_end > cache_end)
- ScanRangeForPointers(cache_end, tls_end, frontier, "TLS", kReachable);
+ if (tls_begin) {
+ LOG_THREADS("TLS at %p-%p.\n", tls_begin, tls_end);
+ // If the tls and cache ranges don't overlap, scan full tls range,
+ // otherwise, only scan the non-overlapping portions
+ if (cache_begin == cache_end || tls_end < cache_begin ||
+ tls_begin > cache_end) {
+ ScanRangeForPointers(tls_begin, tls_end, frontier, "TLS", kReachable);
+ } else {
+ if (tls_begin < cache_begin)
+ ScanRangeForPointers(tls_begin, cache_begin, frontier, "TLS",
+ kReachable);
+ if (tls_end > cache_end)
+ ScanRangeForPointers(cache_end, tls_end, frontier, "TLS",
+ kReachable);
+ }
}
- if (dtls) {
+ if (dtls && !DTLSInDestruction(dtls)) {
for (uptr j = 0; j < dtls->dtv_size; ++j) {
uptr dtls_beg = dtls->dtv[j].beg;
uptr dtls_end = dtls_beg + dtls->dtv[j].size;
@@ -266,28 +296,36 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads,
kReachable);
}
}
+ } else {
+ // We are handling a thread with DTLS under destruction. Log about
+ // this and continue.
+ LOG_THREADS("Thread %d has DTLS under destruction.\n", os_id);
}
}
}
}
-static void ProcessRootRegion(Frontier *frontier, uptr root_begin,
- uptr root_end) {
- MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr begin, end, prot;
- while (proc_maps.Next(&begin, &end,
- /*offset*/ nullptr, /*filename*/ nullptr,
- /*filename_size*/ 0, &prot)) {
- uptr intersection_begin = Max(root_begin, begin);
- uptr intersection_end = Min(end, root_end);
- if (intersection_begin >= intersection_end) continue;
- bool is_readable = prot & MemoryMappingLayout::kProtectionRead;
- LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n",
- root_begin, root_end, begin, end,
- is_readable ? "readable" : "unreadable");
- if (is_readable)
- ScanRangeForPointers(intersection_begin, intersection_end, frontier,
- "ROOT", kReachable);
+void ScanRootRegion(Frontier *frontier, const RootRegion &root_region,
+ uptr region_begin, uptr region_end, bool is_readable) {
+ uptr intersection_begin = Max(root_region.begin, region_begin);
+ uptr intersection_end = Min(region_end, root_region.begin + root_region.size);
+ if (intersection_begin >= intersection_end) return;
+ LOG_POINTERS("Root region %p-%p intersects with mapped region %p-%p (%s)\n",
+ root_region.begin, root_region.begin + root_region.size,
+ region_begin, region_end,
+ is_readable ? "readable" : "unreadable");
+ if (is_readable)
+ ScanRangeForPointers(intersection_begin, intersection_end, frontier, "ROOT",
+ kReachable);
+}
+
+static void ProcessRootRegion(Frontier *frontier,
+ const RootRegion &root_region) {
+ MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
+ MemoryMappedSegment segment;
+ while (proc_maps.Next(&segment)) {
+ ScanRootRegion(frontier, root_region, segment.start, segment.end,
+ segment.IsReadable());
}
}
@@ -296,9 +334,7 @@ static void ProcessRootRegions(Frontier *frontier) {
if (!flags()->use_root_regions) return;
CHECK(root_regions);
for (uptr i = 0; i < root_regions->size(); i++) {
- RootRegion region = (*root_regions)[i];
- uptr begin_addr = reinterpret_cast<uptr>(region.begin);
- ProcessRootRegion(frontier, begin_addr, begin_addr + region.size);
+ ProcessRootRegion(frontier, (*root_regions)[i]);
}
}
@@ -336,6 +372,72 @@ static void CollectIgnoredCb(uptr chunk, void *arg) {
}
}
+static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
+ CHECK(stack_id);
+ StackTrace stack = map->Get(stack_id);
+ // The top frame is our malloc/calloc/etc. The next frame is the caller.
+ if (stack.size >= 2)
+ return stack.trace[1];
+ return 0;
+}
+
+struct InvalidPCParam {
+ Frontier *frontier;
+ StackDepotReverseMap *stack_depot_reverse_map;
+ bool skip_linker_allocations;
+};
+
+// ForEachChunk callback. If the caller pc is invalid or is within the linker,
+// mark as reachable. Called by ProcessPlatformSpecificAllocations.
+static void MarkInvalidPCCb(uptr chunk, void *arg) {
+ CHECK(arg);
+ InvalidPCParam *param = reinterpret_cast<InvalidPCParam *>(arg);
+ chunk = GetUserBegin(chunk);
+ LsanMetadata m(chunk);
+ if (m.allocated() && m.tag() != kReachable && m.tag() != kIgnored) {
+ u32 stack_id = m.stack_trace_id();
+ uptr caller_pc = 0;
+ if (stack_id > 0)
+ caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map);
+ // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark
+ // it as reachable, as we can't properly report its allocation stack anyway.
+ if (caller_pc == 0 || (param->skip_linker_allocations &&
+ GetLinker()->containsAddress(caller_pc))) {
+ m.set_tag(kReachable);
+ param->frontier->push_back(chunk);
+ }
+ }
+}
+
+// On Linux, handles dynamically allocated TLS blocks by treating all chunks
+// allocated from ld-linux.so as reachable.
+// Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
+// They are allocated with a __libc_memalign() call in allocate_and_init()
+// (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those
+// blocks, but we can make sure they come from our own allocator by intercepting
+// __libc_memalign(). On top of that, there is no easy way to reach them. Their
+// addresses are stored in a dynamically allocated array (the DTV) which is
+// referenced from the static TLS. Unfortunately, we can't just rely on the DTV
+// being reachable from the static TLS, and the dynamic TLS being reachable from
+// the DTV. This is because the initial DTV is allocated before our interception
+// mechanism kicks in, and thus we don't recognize it as allocated memory. We
+// can't special-case it either, since we don't know its size.
+// Our solution is to include in the root set all allocations made from
+// ld-linux.so (which is where allocate_and_init() is implemented). This is
+// guaranteed to include all dynamic TLS blocks (and possibly other allocations
+// which we don't care about).
+// On all other platforms, this simply checks to ensure that the caller pc is
+// valid before reporting chunks as leaked.
+void ProcessPC(Frontier *frontier) {
+ StackDepotReverseMap stack_depot_reverse_map;
+ InvalidPCParam arg;
+ arg.frontier = frontier;
+ arg.stack_depot_reverse_map = &stack_depot_reverse_map;
+ arg.skip_linker_allocations =
+ flags()->use_tls && flags()->use_ld_allocations && GetLinker() != nullptr;
+ ForEachChunk(MarkInvalidPCCb, &arg);
+}
+
// Sets the appropriate tag on each chunk.
static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
// Holds the flood fill frontier.
@@ -347,11 +449,13 @@ static void ClassifyAllChunks(SuspendedThreadsList const &suspended_threads) {
ProcessRootRegions(&frontier);
FloodFillTag(&frontier, kReachable);
+ CHECK_EQ(0, frontier.size());
+ ProcessPC(&frontier);
+
// The check here is relatively expensive, so we do this in a separate flood
// fill. That way we can skip the check for chunks that are reachable
// otherwise.
LOG_POINTERS("Processing platform-specific allocations.\n");
- CHECK_EQ(0, frontier.size());
ProcessPlatformSpecificAllocations(&frontier);
FloodFillTag(&frontier, kReachable);
@@ -461,7 +565,7 @@ static bool CheckForLeaks() {
"\n");
Printf("%s", d.Error());
Report("ERROR: LeakSanitizer: detected memory leaks\n");
- Printf("%s", d.End());
+ Printf("%s", d.Default());
param.leak_report.ReportTopLeaks(flags()->max_leaks);
}
if (common_flags()->print_suppressions)
@@ -473,18 +577,16 @@ static bool CheckForLeaks() {
return false;
}
+static bool has_reported_leaks = false;
+bool HasReportedLeaks() { return has_reported_leaks; }
+
void DoLeakCheck() {
BlockingMutexLock l(&global_mutex);
static bool already_done;
if (already_done) return;
already_done = true;
- bool have_leaks = CheckForLeaks();
- if (!have_leaks) {
- return;
- }
- if (common_flags()->exitcode) {
- Die();
- }
+ has_reported_leaks = CheckForLeaks();
+ if (has_reported_leaks) HandleLeaks();
}
static int DoRecoverableLeakCheck() {
@@ -493,6 +595,8 @@ static int DoRecoverableLeakCheck() {
return have_leaks ? 1 : 0;
}
+void DoRecoverableLeakCheckVoid() { DoRecoverableLeakCheck(); }
+
static Suppression *GetSuppressionForAddr(uptr addr) {
Suppression *s = nullptr;
@@ -597,7 +701,7 @@ void LeakReport::PrintReportForLeak(uptr index) {
Printf("%s leak of %zu byte(s) in %zu object(s) allocated from:\n",
leaks_[index].is_directly_leaked ? "Direct" : "Indirect",
leaks_[index].total_size, leaks_[index].hit_count);
- Printf("%s", d.End());
+ Printf("%s", d.Default());
PrintStackTraceById(leaks_[index].stack_trace_id);
@@ -655,6 +759,7 @@ uptr LeakReport::UnsuppressedLeakCount() {
namespace __lsan {
void InitCommonLsan() { }
void DoLeakCheck() { }
+void DoRecoverableLeakCheckVoid() { }
void DisableInThisThread() { }
void EnableInThisThread() { }
}
@@ -687,7 +792,7 @@ void __lsan_register_root_region(const void *begin, uptr size) {
#if CAN_SANITIZE_LEAKS
BlockingMutexLock l(&global_mutex);
CHECK(root_regions);
- RootRegion region = {begin, size};
+ RootRegion region = {reinterpret_cast<uptr>(begin), size};
root_regions->push_back(region);
VReport(1, "Registered root region at %p of size %llu\n", begin, size);
#endif // CAN_SANITIZE_LEAKS
@@ -701,7 +806,7 @@ void __lsan_unregister_root_region(const void *begin, uptr size) {
bool removed = false;
for (uptr i = 0; i < root_regions->size(); i++) {
RootRegion region = (*root_regions)[i];
- if (region.begin == begin && region.size == size) {
+ if (region.begin == reinterpret_cast<uptr>(begin) && region.size == size) {
removed = true;
uptr last_index = root_regions->size() - 1;
(*root_regions)[i] = (*root_regions)[last_index];
@@ -753,8 +858,18 @@ int __lsan_do_recoverable_leak_check() {
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char * __lsan_default_options() {
+ return "";
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
int __lsan_is_turned_off() {
return 0;
}
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__lsan_default_suppressions() {
+ return "";
+}
#endif
} // extern "C"
diff --git a/libsanitizer/lsan/lsan_common.h b/libsanitizer/lsan/lsan_common.h
index 1091b84..e99cd9e 100644
--- a/libsanitizer/lsan/lsan_common.h
+++ b/libsanitizer/lsan/lsan_common.h
@@ -20,8 +20,24 @@
#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "sanitizer_common/sanitizer_symbolizer.h"
-#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) \
- && (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__))
+// LeakSanitizer relies on some Glibc's internals (e.g. TLS machinery) thus
+// supported for Linux only. Also, LSan doesn't like 32 bit architectures
+// because of "small" (4 bytes) pointer size that leads to high false negative
+// ratio on large leaks. But we still want to have it for some 32 bit arches
+// (e.g. x86), see https://github.com/google/sanitizers/issues/403.
+// To enable LeakSanitizer on new architecture, one need to implement
+// internal_clone function as well as (probably) adjust TLS machinery for
+// new architecture inside sanitizer library.
+#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \
+ (SANITIZER_WORDSIZE == 64) && \
+ (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \
+ defined(__powerpc64__))
+#define CAN_SANITIZE_LEAKS 1
+#elif defined(__i386__) && \
+ (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC)
+#define CAN_SANITIZE_LEAKS 1
+#elif defined(__arm__) && \
+ SANITIZER_LINUX && !SANITIZER_ANDROID
#define CAN_SANITIZE_LEAKS 1
#else
#define CAN_SANITIZE_LEAKS 0
@@ -42,6 +58,8 @@ enum ChunkTag {
kIgnored = 3
};
+const u32 kInvalidTid = (u32) -1;
+
struct Flags {
#define LSAN_FLAG(Type, Name, DefaultValue, Description) Type Name;
#include "lsan_flags.inc"
@@ -99,12 +117,22 @@ typedef InternalMmapVector<uptr> Frontier;
void InitializePlatformSpecificModules();
void ProcessGlobalRegions(Frontier *frontier);
void ProcessPlatformSpecificAllocations(Frontier *frontier);
+
+struct RootRegion {
+ uptr begin;
+ uptr size;
+};
+
+InternalMmapVector<RootRegion> const *GetRootRegions();
+void ScanRootRegion(Frontier *frontier, RootRegion const &region,
+ uptr region_begin, uptr region_end, bool is_readable);
// Run stoptheworld while holding any platform-specific locks.
void DoStopTheWorld(StopTheWorldCallback callback, void* argument);
void ScanRangeForPointers(uptr begin, uptr end,
Frontier *frontier,
const char *region_type, ChunkTag tag);
+void ScanGlobalRange(uptr begin, uptr end, Frontier *frontier);
enum IgnoreObjectResult {
kIgnoreObjectSuccess,
@@ -113,8 +141,11 @@ enum IgnoreObjectResult {
};
// Functions called from the parent tool.
+const char *MaybeCallLsanDefaultOptions();
void InitCommonLsan();
void DoLeakCheck();
+void DoRecoverableLeakCheckVoid();
+void DisableCounterUnderflow();
bool DisabledInThisThread();
// Used to implement __lsan::ScopedDisabler.
@@ -127,13 +158,36 @@ struct ScopedInterceptorDisabler {
~ScopedInterceptorDisabler() { EnableInThisThread(); }
};
+// According to Itanium C++ ABI array cookie is a one word containing
+// size of allocated array.
+static inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size,
+ uptr addr) {
+ return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr &&
+ *reinterpret_cast<uptr *>(chunk_beg) == 0;
+}
+
+// According to ARM C++ ABI array cookie consists of two words:
+// struct array_cookie {
+// std::size_t element_size; // element_size != 0
+// std::size_t element_count;
+// };
+static inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size,
+ uptr addr) {
+ return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr &&
+ *reinterpret_cast<uptr *>(chunk_beg + sizeof(uptr)) == 0;
+}
+
// Special case for "new T[0]" where T is a type with DTOR.
-// new T[0] will allocate one word for the array size (0) and store a pointer
-// to the end of allocated chunk.
+// new T[0] will allocate a cookie (one or two words) for the array size (0)
+// and store a pointer to the end of allocated chunk. The actual cookie layout
+// varies between platforms according to their C++ ABI implementation.
inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
uptr addr) {
- return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr &&
- *reinterpret_cast<uptr *>(chunk_beg) == 0;
+#if defined(__arm__)
+ return IsARMABIArrayCookie(chunk_beg, chunk_size, addr);
+#else
+ return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr);
+#endif
}
// The following must be implemented in the parent tool.
@@ -149,10 +203,10 @@ bool WordIsPoisoned(uptr addr);
// Wrappers for ThreadRegistry access.
void LockThreadRegistry();
void UnlockThreadRegistry();
-bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
uptr *cache_end, DTLS **dtls);
-void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
void *arg);
// If called from the main thread, updates the main thread's TID in the thread
// registry. We need this to handle processes that fork() without a subsequent
@@ -168,6 +222,16 @@ uptr PointsIntoChunk(void *p);
uptr GetUserBegin(uptr chunk);
// Helper for __lsan_ignore_object().
IgnoreObjectResult IgnoreObjectLocked(const void *p);
+
+// Return the linker module, if valid for the platform.
+LoadedModule *GetLinker();
+
+// Return true if LSan has finished leak checking and reported leaks.
+bool HasReportedLeaks();
+
+// Run platform-specific leak handlers.
+void HandleLeaks();
+
// Wrapper for chunk metadata operations.
class LsanMetadata {
public:
@@ -186,6 +250,9 @@ class LsanMetadata {
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+const char *__lsan_default_options();
+
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
int __lsan_is_turned_off();
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
diff --git a/libsanitizer/lsan/lsan_common_linux.cc b/libsanitizer/lsan/lsan_common_linux.cc
index abbb61f..6777272 100644
--- a/libsanitizer/lsan/lsan_common_linux.cc
+++ b/libsanitizer/lsan/lsan_common_linux.cc
@@ -32,6 +32,17 @@ static bool IsLinker(const char* full_name) {
return LibraryNameIs(full_name, kLinkerName);
}
+__attribute__((tls_model("initial-exec")))
+THREADLOCAL int disable_counter;
+bool DisabledInThisThread() { return disable_counter > 0; }
+void DisableInThisThread() { disable_counter++; }
+void EnableInThisThread() {
+ if (disable_counter == 0) {
+ DisableCounterUnderflow();
+ }
+ disable_counter--;
+}
+
void InitializePlatformSpecificModules() {
ListOfModules modules;
modules.init();
@@ -49,8 +60,10 @@ void InitializePlatformSpecificModules() {
return;
}
}
- VReport(1, "LeakSanitizer: Dynamic linker not found. "
- "TLS will not be handled correctly.\n");
+ if (linker == nullptr) {
+ VReport(1, "LeakSanitizer: Dynamic linker not found. "
+ "TLS will not be handled correctly.\n");
+ }
}
static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
@@ -65,20 +78,7 @@ static int ProcessGlobalRegionsCallback(struct dl_phdr_info *info, size_t size,
continue;
uptr begin = info->dlpi_addr + phdr->p_vaddr;
uptr end = begin + phdr->p_memsz;
- uptr allocator_begin = 0, allocator_end = 0;
- GetAllocatorGlobalRange(&allocator_begin, &allocator_end);
- if (begin <= allocator_begin && allocator_begin < end) {
- CHECK_LE(allocator_begin, allocator_end);
- CHECK_LE(allocator_end, end);
- if (begin < allocator_begin)
- ScanRangeForPointers(begin, allocator_begin, frontier, "GLOBAL",
- kReachable);
- if (allocator_end < end)
- ScanRangeForPointers(allocator_end, end, frontier, "GLOBAL",
- kReachable);
- } else {
- ScanRangeForPointers(begin, end, frontier, "GLOBAL", kReachable);
- }
+ ScanGlobalRange(begin, end, frontier);
}
return 0;
}
@@ -89,76 +89,22 @@ void ProcessGlobalRegions(Frontier *frontier) {
dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier);
}
-static uptr GetCallerPC(u32 stack_id, StackDepotReverseMap *map) {
- CHECK(stack_id);
- StackTrace stack = map->Get(stack_id);
- // The top frame is our malloc/calloc/etc. The next frame is the caller.
- if (stack.size >= 2)
- return stack.trace[1];
- return 0;
-}
+LoadedModule *GetLinker() { return linker; }
-struct ProcessPlatformAllocParam {
- Frontier *frontier;
- StackDepotReverseMap *stack_depot_reverse_map;
- bool skip_linker_allocations;
-};
-
-// ForEachChunk callback. Identifies unreachable chunks which must be treated as
-// reachable. Marks them as reachable and adds them to the frontier.
-static void ProcessPlatformSpecificAllocationsCb(uptr chunk, void *arg) {
- CHECK(arg);
- ProcessPlatformAllocParam *param =
- reinterpret_cast<ProcessPlatformAllocParam *>(arg);
- chunk = GetUserBegin(chunk);
- LsanMetadata m(chunk);
- if (m.allocated() && m.tag() != kReachable && m.tag() != kIgnored) {
- u32 stack_id = m.stack_trace_id();
- uptr caller_pc = 0;
- if (stack_id > 0)
- caller_pc = GetCallerPC(stack_id, param->stack_depot_reverse_map);
- // If caller_pc is unknown, this chunk may be allocated in a coroutine. Mark
- // it as reachable, as we can't properly report its allocation stack anyway.
- if (caller_pc == 0 || (param->skip_linker_allocations &&
- linker->containsAddress(caller_pc))) {
- m.set_tag(kReachable);
- param->frontier->push_back(chunk);
- }
- }
-}
-
-// Handles dynamically allocated TLS blocks by treating all chunks allocated
-// from ld-linux.so as reachable.
-// Dynamic TLS blocks contain the TLS variables of dynamically loaded modules.
-// They are allocated with a __libc_memalign() call in allocate_and_init()
-// (elf/dl-tls.c). Glibc won't tell us the address ranges occupied by those
-// blocks, but we can make sure they come from our own allocator by intercepting
-// __libc_memalign(). On top of that, there is no easy way to reach them. Their
-// addresses are stored in a dynamically allocated array (the DTV) which is
-// referenced from the static TLS. Unfortunately, we can't just rely on the DTV
-// being reachable from the static TLS, and the dynamic TLS being reachable from
-// the DTV. This is because the initial DTV is allocated before our interception
-// mechanism kicks in, and thus we don't recognize it as allocated memory. We
-// can't special-case it either, since we don't know its size.
-// Our solution is to include in the root set all allocations made from
-// ld-linux.so (which is where allocate_and_init() is implemented). This is
-// guaranteed to include all dynamic TLS blocks (and possibly other allocations
-// which we don't care about).
-void ProcessPlatformSpecificAllocations(Frontier *frontier) {
- StackDepotReverseMap stack_depot_reverse_map;
- ProcessPlatformAllocParam arg;
- arg.frontier = frontier;
- arg.stack_depot_reverse_map = &stack_depot_reverse_map;
- arg.skip_linker_allocations =
- flags()->use_tls && flags()->use_ld_allocations && linker != nullptr;
- ForEachChunk(ProcessPlatformSpecificAllocationsCb, &arg);
-}
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {}
struct DoStopTheWorldParam {
StopTheWorldCallback callback;
void *argument;
};
+// While calling Die() here is undefined behavior and can potentially
+// cause race conditions, it isn't possible to intercept exit on linux,
+// so we have no choice but to call Die() from the atexit handler.
+void HandleLeaks() {
+ if (common_flags()->exitcode) Die();
+}
+
static int DoStopTheWorldCallback(struct dl_phdr_info *info, size_t size,
void *data) {
DoStopTheWorldParam *param = reinterpret_cast<DoStopTheWorldParam *>(data);
diff --git a/libsanitizer/lsan/lsan_common_mac.cc b/libsanitizer/lsan/lsan_common_mac.cc
new file mode 100644
index 0000000..e60b3d0
--- /dev/null
+++ b/libsanitizer/lsan/lsan_common_mac.cc
@@ -0,0 +1,197 @@
+//=-- lsan_common_mac.cc --------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer.
+// Implementation of common leak checking functionality. Darwin-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#include "lsan_common.h"
+
+#if CAN_SANITIZE_LEAKS && SANITIZER_MAC
+
+#include "sanitizer_common/sanitizer_allocator_internal.h"
+#include "lsan_allocator.h"
+
+#include <pthread.h>
+
+#include <mach/mach.h>
+
+namespace __lsan {
+
+typedef struct {
+ int disable_counter;
+ u32 current_thread_id;
+ AllocatorCache cache;
+} thread_local_data_t;
+
+static pthread_key_t key;
+static pthread_once_t key_once = PTHREAD_ONCE_INIT;
+
+// The main thread destructor requires the current thread id,
+// so we can't destroy it until it's been used and reset to invalid tid
+void restore_tid_data(void *ptr) {
+ thread_local_data_t *data = (thread_local_data_t *)ptr;
+ if (data->current_thread_id != kInvalidTid)
+ pthread_setspecific(key, data);
+}
+
+static void make_tls_key() {
+ CHECK_EQ(pthread_key_create(&key, restore_tid_data), 0);
+}
+
+static thread_local_data_t *get_tls_val(bool alloc) {
+ pthread_once(&key_once, make_tls_key);
+
+ thread_local_data_t *ptr = (thread_local_data_t *)pthread_getspecific(key);
+ if (ptr == NULL && alloc) {
+ ptr = (thread_local_data_t *)InternalAlloc(sizeof(*ptr));
+ ptr->disable_counter = 0;
+ ptr->current_thread_id = kInvalidTid;
+ ptr->cache = AllocatorCache();
+ pthread_setspecific(key, ptr);
+ }
+
+ return ptr;
+}
+
+bool DisabledInThisThread() {
+ thread_local_data_t *data = get_tls_val(false);
+ return data ? data->disable_counter > 0 : false;
+}
+
+void DisableInThisThread() { ++get_tls_val(true)->disable_counter; }
+
+void EnableInThisThread() {
+ int *disable_counter = &get_tls_val(true)->disable_counter;
+ if (*disable_counter == 0) {
+ DisableCounterUnderflow();
+ }
+ --*disable_counter;
+}
+
+u32 GetCurrentThread() {
+ thread_local_data_t *data = get_tls_val(false);
+ return data ? data->current_thread_id : kInvalidTid;
+}
+
+void SetCurrentThread(u32 tid) { get_tls_val(true)->current_thread_id = tid; }
+
+AllocatorCache *GetAllocatorCache() { return &get_tls_val(true)->cache; }
+
+LoadedModule *GetLinker() { return nullptr; }
+
+// Required on Linux for initialization of TLS behavior, but should not be
+// required on Darwin.
+void InitializePlatformSpecificModules() {}
+
+// Sections which can't contain contain global pointers. This list errs on the
+// side of caution to avoid false positives, at the expense of performance.
+//
+// Other potentially safe sections include:
+// __all_image_info, __crash_info, __const, __got, __interpose, __objc_msg_break
+//
+// Sections which definitely cannot be included here are:
+// __objc_data, __objc_const, __data, __bss, __common, __thread_data,
+// __thread_bss, __thread_vars, __objc_opt_rw, __objc_opt_ptrs
+static const char *kSkippedSecNames[] = {
+ "__cfstring", "__la_symbol_ptr", "__mod_init_func",
+ "__mod_term_func", "__nl_symbol_ptr", "__objc_classlist",
+ "__objc_classrefs", "__objc_imageinfo", "__objc_nlclslist",
+ "__objc_protolist", "__objc_selrefs", "__objc_superrefs"};
+
+// Scans global variables for heap pointers.
+void ProcessGlobalRegions(Frontier *frontier) {
+ for (auto name : kSkippedSecNames) CHECK(ARRAY_SIZE(name) < kMaxSegName);
+
+ MemoryMappingLayout memory_mapping(false);
+ InternalMmapVector<LoadedModule> modules(/*initial_capacity*/ 128);
+ memory_mapping.DumpListOfModules(&modules);
+ for (uptr i = 0; i < modules.size(); ++i) {
+ // Even when global scanning is disabled, we still need to scan
+ // system libraries for stashed pointers
+ if (!flags()->use_globals && modules[i].instrumented()) continue;
+
+ for (const __sanitizer::LoadedModule::AddressRange &range :
+ modules[i].ranges()) {
+ // Sections storing global variables are writable and non-executable
+ if (range.executable || !range.writable) continue;
+
+ for (auto name : kSkippedSecNames) {
+ if (!internal_strcmp(range.name, name)) continue;
+ }
+
+ ScanGlobalRange(range.beg, range.end, frontier);
+ }
+ }
+}
+
+void ProcessPlatformSpecificAllocations(Frontier *frontier) {
+ mach_port_name_t port;
+ if (task_for_pid(mach_task_self(), internal_getpid(), &port)
+ != KERN_SUCCESS) {
+ return;
+ }
+
+ unsigned depth = 1;
+ vm_size_t size = 0;
+ vm_address_t address = 0;
+ kern_return_t err = KERN_SUCCESS;
+ mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
+
+ InternalMmapVector<RootRegion> const *root_regions = GetRootRegions();
+
+ while (err == KERN_SUCCESS) {
+ struct vm_region_submap_info_64 info;
+ err = vm_region_recurse_64(port, &address, &size, &depth,
+ (vm_region_info_t)&info, &count);
+
+ uptr end_address = address + size;
+
+ // libxpc stashes some pointers in the Kernel Alloc Once page,
+ // make sure not to report those as leaks.
+ if (info.user_tag == VM_MEMORY_OS_ALLOC_ONCE) {
+ ScanRangeForPointers(address, end_address, frontier, "GLOBAL",
+ kReachable);
+
+ // Recursing over the full memory map is very slow, break out
+ // early if we don't need the full iteration.
+ if (!flags()->use_root_regions || !root_regions->size())
+ break;
+ }
+
+ // This additional root region scan is required on Darwin in order to
+ // detect root regions contained within mmap'd memory regions, because
+ // the Darwin implementation of sanitizer_procmaps traverses images
+ // as loaded by dyld, and not the complete set of all memory regions.
+ //
+ // TODO(fjricci) - remove this once sanitizer_procmaps_mac has the same
+ // behavior as sanitizer_procmaps_linux and traverses all memory regions
+ if (flags()->use_root_regions) {
+ for (uptr i = 0; i < root_regions->size(); i++) {
+ ScanRootRegion(frontier, (*root_regions)[i], address, end_address,
+ info.protection & kProtectionRead);
+ }
+ }
+
+ address = end_address;
+ }
+}
+
+// On darwin, we can intercept _exit gracefully, and return a failing exit code
+// if required at that point. Calling Die() here is undefined behavior and
+// causes rare race conditions.
+void HandleLeaks() {}
+
+void DoStopTheWorld(StopTheWorldCallback callback, void *argument) {
+ StopTheWorld(callback, argument);
+}
+
+} // namespace __lsan
+
+#endif // CAN_SANITIZE_LEAKS && SANITIZER_MAC
diff --git a/libsanitizer/lsan/lsan_interceptors.cc b/libsanitizer/lsan/lsan_interceptors.cc
index 160ed59..c9279aa 100644
--- a/libsanitizer/lsan/lsan_interceptors.cc
+++ b/libsanitizer/lsan/lsan_interceptors.cc
@@ -17,13 +17,18 @@
#include "sanitizer_common/sanitizer_flags.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_platform_interceptors.h"
+#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
+#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "lsan.h"
#include "lsan_allocator.h"
#include "lsan_common.h"
#include "lsan_thread.h"
+#include <stddef.h>
+
using namespace __lsan;
extern "C" {
@@ -34,29 +39,23 @@ int pthread_key_create(unsigned *key, void (*destructor)(void* v));
int pthread_setspecific(unsigned key, const void *v);
}
-#define ENSURE_LSAN_INITED do { \
- CHECK(!lsan_init_is_running); \
- if (!lsan_inited) \
- __lsan_init(); \
-} while (0)
-
///// Malloc/free interceptors. /////
-const bool kAlwaysClearMemory = true;
-
namespace std {
struct nothrow_t;
+ enum class align_val_t: size_t;
}
+#if !SANITIZER_MAC
INTERCEPTOR(void*, malloc, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
- return Allocate(stack, size, 1, kAlwaysClearMemory);
+ return lsan_malloc(size, stack);
}
INTERCEPTOR(void, free, void *p) {
ENSURE_LSAN_INITED;
- Deallocate(p);
+ lsan_free(p);
}
INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
@@ -71,60 +70,76 @@ INTERCEPTOR(void*, calloc, uptr nmemb, uptr size) {
CHECK(allocated < kCallocPoolSize);
return mem;
}
- if (CallocShouldReturnNullDueToOverflow(size, nmemb)) return nullptr;
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
- size *= nmemb;
- return Allocate(stack, size, 1, true);
+ return lsan_calloc(nmemb, size, stack);
}
INTERCEPTOR(void*, realloc, void *q, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
- return Reallocate(stack, q, size, 1);
+ return lsan_realloc(q, size, stack);
}
-INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
+INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
- return Allocate(stack, size, alignment, kAlwaysClearMemory);
+ *memptr = lsan_memalign(alignment, size, stack);
+ // FIXME: Return ENOMEM if user requested more than max alloc size.
+ return 0;
}
-INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
+INTERCEPTOR(void*, valloc, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
- return Allocate(stack, size, alignment, kAlwaysClearMemory);
+ return lsan_valloc(size, stack);
}
+#endif
-INTERCEPTOR(int, posix_memalign, void **memptr, uptr alignment, uptr size) {
+#if SANITIZER_INTERCEPT_MEMALIGN
+INTERCEPTOR(void*, memalign, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
- *memptr = Allocate(stack, size, alignment, kAlwaysClearMemory);
- // FIXME: Return ENOMEM if user requested more than max alloc size.
- return 0;
+ return lsan_memalign(alignment, size, stack);
}
+#define LSAN_MAYBE_INTERCEPT_MEMALIGN INTERCEPT_FUNCTION(memalign)
INTERCEPTOR(void *, __libc_memalign, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
- void *res = Allocate(stack, size, alignment, kAlwaysClearMemory);
+ void *res = lsan_memalign(alignment, size, stack);
DTLS_on_libc_memalign(res, size);
return res;
}
+#define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN INTERCEPT_FUNCTION(__libc_memalign)
+#else
+#define LSAN_MAYBE_INTERCEPT_MEMALIGN
+#define LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN
+#endif // SANITIZER_INTERCEPT_MEMALIGN
-INTERCEPTOR(void*, valloc, uptr size) {
+#if SANITIZER_INTERCEPT_ALIGNED_ALLOC
+INTERCEPTOR(void*, aligned_alloc, uptr alignment, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
- if (size == 0)
- size = GetPageSizeCached();
- return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
+ return lsan_memalign(alignment, size, stack);
}
+#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC INTERCEPT_FUNCTION(aligned_alloc)
+#else
+#define LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC
+#endif
+#if SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE
INTERCEPTOR(uptr, malloc_usable_size, void *ptr) {
ENSURE_LSAN_INITED;
return GetMallocUsableSize(ptr);
}
+#define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE \
+ INTERCEPT_FUNCTION(malloc_usable_size)
+#else
+#define LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE
+#endif
+#if SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
struct fake_mallinfo {
int x[10];
};
@@ -134,11 +149,18 @@ INTERCEPTOR(struct fake_mallinfo, mallinfo, void) {
internal_memset(&res, 0, sizeof(res));
return res;
}
+#define LSAN_MAYBE_INTERCEPT_MALLINFO INTERCEPT_FUNCTION(mallinfo)
INTERCEPTOR(int, mallopt, int cmd, int value) {
return -1;
}
+#define LSAN_MAYBE_INTERCEPT_MALLOPT INTERCEPT_FUNCTION(mallopt)
+#else
+#define LSAN_MAYBE_INTERCEPT_MALLINFO
+#define LSAN_MAYBE_INTERCEPT_MALLOPT
+#endif // SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO
+#if SANITIZER_INTERCEPT_PVALLOC
INTERCEPTOR(void*, pvalloc, uptr size) {
ENSURE_LSAN_INITED;
GET_STACK_TRACE_MALLOC;
@@ -150,26 +172,81 @@ INTERCEPTOR(void*, pvalloc, uptr size) {
}
return Allocate(stack, size, GetPageSizeCached(), kAlwaysClearMemory);
}
+#define LSAN_MAYBE_INTERCEPT_PVALLOC INTERCEPT_FUNCTION(pvalloc)
+#else
+#define LSAN_MAYBE_INTERCEPT_PVALLOC
+#endif // SANITIZER_INTERCEPT_PVALLOC
+#if SANITIZER_INTERCEPT_CFREE
INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
+#define LSAN_MAYBE_INTERCEPT_CFREE INTERCEPT_FUNCTION(cfree)
+#else
+#define LSAN_MAYBE_INTERCEPT_CFREE
+#endif // SANITIZER_INTERCEPT_CFREE
+
+#if SANITIZER_INTERCEPT_MCHECK_MPROBE
+INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {
+ return 0;
+}
+
+INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {
+ return 0;
+}
-#define OPERATOR_NEW_BODY \
- ENSURE_LSAN_INITED; \
- GET_STACK_TRACE_MALLOC; \
- return Allocate(stack, size, 1, kAlwaysClearMemory);
+INTERCEPTOR(int, mprobe, void *ptr) {
+ return 0;
+}
+#endif // SANITIZER_INTERCEPT_MCHECK_MPROBE
+
+
+// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
+#define OPERATOR_NEW_BODY(nothrow) \
+ ENSURE_LSAN_INITED; \
+ GET_STACK_TRACE_MALLOC; \
+ void *res = lsan_malloc(size, stack); \
+ if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM(); \
+ return res;
+#define OPERATOR_NEW_BODY_ALIGN(nothrow) \
+ ENSURE_LSAN_INITED; \
+ GET_STACK_TRACE_MALLOC; \
+ void *res = lsan_memalign((uptr)align, size, stack); \
+ if (!nothrow && UNLIKELY(!res)) DieOnFailure::OnOOM(); \
+ return res;
+
+#define OPERATOR_DELETE_BODY \
+ ENSURE_LSAN_INITED; \
+ lsan_free(ptr);
+
+// On OS X it's not enough to just provide our own 'operator new' and
+// 'operator delete' implementations, because they're going to be in the runtime
+// dylib, and the main executable will depend on both the runtime dylib and
+// libstdc++, each of has its implementation of new and delete.
+// To make sure that C++ allocation/deallocation operators are overridden on
+// OS X we need to intercept them using their mangled names.
+#if !SANITIZER_MAC
INTERCEPTOR_ATTRIBUTE
-void *operator new(uptr size) { OPERATOR_NEW_BODY; }
+void *operator new(size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
INTERCEPTOR_ATTRIBUTE
-void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
+void *operator new[](size_t size) { OPERATOR_NEW_BODY(false /*nothrow*/); }
INTERCEPTOR_ATTRIBUTE
-void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
+void *operator new(size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(true /*nothrow*/); }
INTERCEPTOR_ATTRIBUTE
-void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
-
-#define OPERATOR_DELETE_BODY \
- ENSURE_LSAN_INITED; \
- Deallocate(ptr);
+void *operator new[](size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(true /*nothrow*/); }
+INTERCEPTOR_ATTRIBUTE
+void *operator new(size_t size, std::align_val_t align)
+{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](size_t size, std::align_val_t align)
+{ OPERATOR_NEW_BODY_ALIGN(false /*nothrow*/); }
+INTERCEPTOR_ATTRIBUTE
+void *operator new(size_t size, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
+INTERCEPTOR_ATTRIBUTE
+void *operator new[](size_t size, std::align_val_t align, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY_ALIGN(true /*nothrow*/); }
INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
@@ -178,9 +255,55 @@ void operator delete[](void *ptr) NOEXCEPT { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
void operator delete(void *ptr, std::nothrow_t const&) { OPERATOR_DELETE_BODY; }
INTERCEPTOR_ATTRIBUTE
-void operator delete[](void *ptr, std::nothrow_t const &) {
- OPERATOR_DELETE_BODY;
-}
+void operator delete[](void *ptr, std::nothrow_t const &)
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, size_t size) NOEXCEPT
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, size_t size) NOEXCEPT
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, std::align_val_t) NOEXCEPT
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, std::align_val_t) NOEXCEPT
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, std::align_val_t, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, std::align_val_t, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete(void *ptr, size_t size, std::align_val_t) NOEXCEPT
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR_ATTRIBUTE
+void operator delete[](void *ptr, size_t size, std::align_val_t) NOEXCEPT
+{ OPERATOR_DELETE_BODY; }
+
+#else // SANITIZER_MAC
+
+INTERCEPTOR(void *, _Znwm, size_t size)
+{ OPERATOR_NEW_BODY(false /*nothrow*/); }
+INTERCEPTOR(void *, _Znam, size_t size)
+{ OPERATOR_NEW_BODY(false /*nothrow*/); }
+INTERCEPTOR(void *, _ZnwmRKSt9nothrow_t, size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(true /*nothrow*/); }
+INTERCEPTOR(void *, _ZnamRKSt9nothrow_t, size_t size, std::nothrow_t const&)
+{ OPERATOR_NEW_BODY(true /*nothrow*/); }
+
+INTERCEPTOR(void, _ZdlPv, void *ptr)
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR(void, _ZdaPv, void *ptr)
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR(void, _ZdlPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY; }
+INTERCEPTOR(void, _ZdaPvRKSt9nothrow_t, void *ptr, std::nothrow_t const&)
+{ OPERATOR_DELETE_BODY; }
+
+#endif // !SANITIZER_MAC
+
///// Thread initialization and finalization. /////
@@ -250,7 +373,8 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr,
res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p);
}
if (res == 0) {
- int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, detached);
+ int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th,
+ IsStateDetached(detached));
CHECK_NE(tid, 0);
atomic_store(&p.tid, tid, memory_order_release);
while (atomic_load(&p.tid, memory_order_acquire) != 0)
@@ -270,24 +394,36 @@ INTERCEPTOR(int, pthread_join, void *th, void **ret) {
return res;
}
+INTERCEPTOR(void, _exit, int status) {
+ if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode;
+ REAL(_exit)(status);
+}
+
+#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
+#include "sanitizer_common/sanitizer_signal_interceptors.inc"
+
namespace __lsan {
void InitializeInterceptors() {
+ InitializeSignalInterceptors();
+
INTERCEPT_FUNCTION(malloc);
INTERCEPT_FUNCTION(free);
- INTERCEPT_FUNCTION(cfree);
+ LSAN_MAYBE_INTERCEPT_CFREE;
INTERCEPT_FUNCTION(calloc);
INTERCEPT_FUNCTION(realloc);
- INTERCEPT_FUNCTION(memalign);
+ LSAN_MAYBE_INTERCEPT_MEMALIGN;
+ LSAN_MAYBE_INTERCEPT___LIBC_MEMALIGN;
+ LSAN_MAYBE_INTERCEPT_ALIGNED_ALLOC;
INTERCEPT_FUNCTION(posix_memalign);
- INTERCEPT_FUNCTION(__libc_memalign);
INTERCEPT_FUNCTION(valloc);
- INTERCEPT_FUNCTION(pvalloc);
- INTERCEPT_FUNCTION(malloc_usable_size);
- INTERCEPT_FUNCTION(mallinfo);
- INTERCEPT_FUNCTION(mallopt);
+ LSAN_MAYBE_INTERCEPT_PVALLOC;
+ LSAN_MAYBE_INTERCEPT_MALLOC_USABLE_SIZE;
+ LSAN_MAYBE_INTERCEPT_MALLINFO;
+ LSAN_MAYBE_INTERCEPT_MALLOPT;
INTERCEPT_FUNCTION(pthread_create);
INTERCEPT_FUNCTION(pthread_join);
+ INTERCEPT_FUNCTION(_exit);
if (pthread_key_create(&g_thread_finalize_key, &thread_finalize)) {
Report("LeakSanitizer: failed to create thread key.\n");
diff --git a/libsanitizer/lsan/lsan_linux.cc b/libsanitizer/lsan/lsan_linux.cc
new file mode 100644
index 0000000..aa6445a
--- /dev/null
+++ b/libsanitizer/lsan/lsan_linux.cc
@@ -0,0 +1,31 @@
+//=-- lsan_linux.cc -------------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer. Linux-specific code.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+
+#if SANITIZER_LINUX
+
+#include "lsan_allocator.h"
+
+namespace __lsan {
+
+static THREADLOCAL u32 current_thread_tid = kInvalidTid;
+u32 GetCurrentThread() { return current_thread_tid; }
+void SetCurrentThread(u32 tid) { current_thread_tid = tid; }
+
+static THREADLOCAL AllocatorCache allocator_cache;
+AllocatorCache *GetAllocatorCache() { return &allocator_cache; }
+
+void ReplaceSystemMalloc() {}
+
+} // namespace __lsan
+
+#endif // SANITIZER_LINUX
diff --git a/libsanitizer/lsan/lsan_mac.cc b/libsanitizer/lsan/lsan_mac.cc
new file mode 100644
index 0000000..ca38c1c
--- /dev/null
+++ b/libsanitizer/lsan/lsan_mac.cc
@@ -0,0 +1,190 @@
+//===-- lsan_mac.cc -------------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer, a memory leak checker.
+//
+// Mac-specific details.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "interception/interception.h"
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_thread.h"
+
+#include <pthread.h>
+
+namespace __lsan {
+// Support for the following functions from libdispatch on Mac OS:
+// dispatch_async_f()
+// dispatch_async()
+// dispatch_sync_f()
+// dispatch_sync()
+// dispatch_after_f()
+// dispatch_after()
+// dispatch_group_async_f()
+// dispatch_group_async()
+// TODO(glider): libdispatch API contains other functions that we don't support
+// yet.
+//
+// dispatch_sync() and dispatch_sync_f() are synchronous, although chances are
+// they can cause jobs to run on a thread different from the current one.
+// TODO(glider): if so, we need a test for this (otherwise we should remove
+// them).
+//
+// The following functions use dispatch_barrier_async_f() (which isn't a library
+// function but is exported) and are thus supported:
+// dispatch_source_set_cancel_handler_f()
+// dispatch_source_set_cancel_handler()
+// dispatch_source_set_event_handler_f()
+// dispatch_source_set_event_handler()
+//
+// The reference manual for Grand Central Dispatch is available at
+// http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html
+// The implementation details are at
+// http://libdispatch.macosforge.org/trac/browser/trunk/src/queue.c
+
+typedef void *dispatch_group_t;
+typedef void *dispatch_queue_t;
+typedef void *dispatch_source_t;
+typedef u64 dispatch_time_t;
+typedef void (*dispatch_function_t)(void *block);
+typedef void *(*worker_t)(void *block);
+
+// A wrapper for the ObjC blocks used to support libdispatch.
+typedef struct {
+ void *block;
+ dispatch_function_t func;
+ u32 parent_tid;
+} lsan_block_context_t;
+
+ALWAYS_INLINE
+void lsan_register_worker_thread(int parent_tid) {
+ if (GetCurrentThread() == kInvalidTid) {
+ u32 tid = ThreadCreate(parent_tid, 0, true);
+ ThreadStart(tid, GetTid());
+ SetCurrentThread(tid);
+ }
+}
+
+// For use by only those functions that allocated the context via
+// alloc_lsan_context().
+extern "C" void lsan_dispatch_call_block_and_release(void *block) {
+ lsan_block_context_t *context = (lsan_block_context_t *)block;
+ VReport(2,
+ "lsan_dispatch_call_block_and_release(): "
+ "context: %p, pthread_self: %p\n",
+ block, pthread_self());
+ lsan_register_worker_thread(context->parent_tid);
+ // Call the original dispatcher for the block.
+ context->func(context->block);
+ lsan_free(context);
+}
+
+} // namespace __lsan
+
+using namespace __lsan; // NOLINT
+
+// Wrap |ctxt| and |func| into an lsan_block_context_t.
+// The caller retains control of the allocated context.
+extern "C" lsan_block_context_t *alloc_lsan_context(void *ctxt,
+ dispatch_function_t func) {
+ GET_STACK_TRACE_THREAD;
+ lsan_block_context_t *lsan_ctxt =
+ (lsan_block_context_t *)lsan_malloc(sizeof(lsan_block_context_t), stack);
+ lsan_ctxt->block = ctxt;
+ lsan_ctxt->func = func;
+ lsan_ctxt->parent_tid = GetCurrentThread();
+ return lsan_ctxt;
+}
+
+// Define interceptor for dispatch_*_f function with the three most common
+// parameters: dispatch_queue_t, context, dispatch_function_t.
+#define INTERCEPT_DISPATCH_X_F_3(dispatch_x_f) \
+ INTERCEPTOR(void, dispatch_x_f, dispatch_queue_t dq, void *ctxt, \
+ dispatch_function_t func) { \
+ lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func); \
+ return REAL(dispatch_x_f)(dq, (void *)lsan_ctxt, \
+ lsan_dispatch_call_block_and_release); \
+ }
+
+INTERCEPT_DISPATCH_X_F_3(dispatch_async_f)
+INTERCEPT_DISPATCH_X_F_3(dispatch_sync_f)
+INTERCEPT_DISPATCH_X_F_3(dispatch_barrier_async_f)
+
+INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when, dispatch_queue_t dq,
+ void *ctxt, dispatch_function_t func) {
+ lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func);
+ return REAL(dispatch_after_f)(when, dq, (void *)lsan_ctxt,
+ lsan_dispatch_call_block_and_release);
+}
+
+INTERCEPTOR(void, dispatch_group_async_f, dispatch_group_t group,
+ dispatch_queue_t dq, void *ctxt, dispatch_function_t func) {
+ lsan_block_context_t *lsan_ctxt = alloc_lsan_context(ctxt, func);
+ REAL(dispatch_group_async_f)
+ (group, dq, (void *)lsan_ctxt, lsan_dispatch_call_block_and_release);
+}
+
+#if !defined(MISSING_BLOCKS_SUPPORT)
+extern "C" {
+void dispatch_async(dispatch_queue_t dq, void (^work)(void));
+void dispatch_group_async(dispatch_group_t dg, dispatch_queue_t dq,
+ void (^work)(void));
+void dispatch_after(dispatch_time_t when, dispatch_queue_t queue,
+ void (^work)(void));
+void dispatch_source_set_cancel_handler(dispatch_source_t ds,
+ void (^work)(void));
+void dispatch_source_set_event_handler(dispatch_source_t ds,
+ void (^work)(void));
+}
+
+#define GET_LSAN_BLOCK(work) \
+ void (^lsan_block)(void); \
+ int parent_tid = GetCurrentThread(); \
+ lsan_block = ^(void) { \
+ lsan_register_worker_thread(parent_tid); \
+ work(); \
+ }
+
+INTERCEPTOR(void, dispatch_async, dispatch_queue_t dq, void (^work)(void)) {
+ GET_LSAN_BLOCK(work);
+ REAL(dispatch_async)(dq, lsan_block);
+}
+
+INTERCEPTOR(void, dispatch_group_async, dispatch_group_t dg,
+ dispatch_queue_t dq, void (^work)(void)) {
+ GET_LSAN_BLOCK(work);
+ REAL(dispatch_group_async)(dg, dq, lsan_block);
+}
+
+INTERCEPTOR(void, dispatch_after, dispatch_time_t when, dispatch_queue_t queue,
+ void (^work)(void)) {
+ GET_LSAN_BLOCK(work);
+ REAL(dispatch_after)(when, queue, lsan_block);
+}
+
+INTERCEPTOR(void, dispatch_source_set_cancel_handler, dispatch_source_t ds,
+ void (^work)(void)) {
+ if (!work) {
+ REAL(dispatch_source_set_cancel_handler)(ds, work);
+ return;
+ }
+ GET_LSAN_BLOCK(work);
+ REAL(dispatch_source_set_cancel_handler)(ds, lsan_block);
+}
+
+INTERCEPTOR(void, dispatch_source_set_event_handler, dispatch_source_t ds,
+ void (^work)(void)) {
+ GET_LSAN_BLOCK(work);
+ REAL(dispatch_source_set_event_handler)(ds, lsan_block);
+}
+#endif
+
+#endif // SANITIZER_MAC
diff --git a/libsanitizer/lsan/lsan_malloc_mac.cc b/libsanitizer/lsan/lsan_malloc_mac.cc
new file mode 100644
index 0000000..2d810af
--- /dev/null
+++ b/libsanitizer/lsan/lsan_malloc_mac.cc
@@ -0,0 +1,53 @@
+//===-- lsan_malloc_mac.cc ------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of LeakSanitizer (LSan), a memory leak detector.
+//
+// Mac-specific malloc interception.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_MAC
+
+#include "lsan.h"
+#include "lsan_allocator.h"
+#include "lsan_thread.h"
+
+using namespace __lsan;
+#define COMMON_MALLOC_ZONE_NAME "lsan"
+#define COMMON_MALLOC_ENTER() ENSURE_LSAN_INITED
+#define COMMON_MALLOC_SANITIZER_INITIALIZED lsan_inited
+#define COMMON_MALLOC_FORCE_LOCK()
+#define COMMON_MALLOC_FORCE_UNLOCK()
+#define COMMON_MALLOC_MEMALIGN(alignment, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = lsan_memalign(alignment, size, stack)
+#define COMMON_MALLOC_MALLOC(size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = lsan_malloc(size, stack)
+#define COMMON_MALLOC_REALLOC(ptr, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = lsan_realloc(ptr, size, stack)
+#define COMMON_MALLOC_CALLOC(count, size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = lsan_calloc(count, size, stack)
+#define COMMON_MALLOC_VALLOC(size) \
+ GET_STACK_TRACE_MALLOC; \
+ void *p = lsan_valloc(size, stack)
+#define COMMON_MALLOC_FREE(ptr) \
+ lsan_free(ptr)
+#define COMMON_MALLOC_SIZE(ptr) \
+ uptr size = lsan_mz_size(ptr)
+#define COMMON_MALLOC_FILL_STATS(zone, stats)
+#define COMMON_MALLOC_REPORT_UNKNOWN_REALLOC(ptr, zone_ptr, zone_name) \
+ (void)zone_name; \
+ Report("mz_realloc(%p) -- attempting to realloc unallocated memory.\n", ptr);
+#define COMMON_MALLOC_NAMESPACE __lsan
+
+#include "sanitizer_common/sanitizer_malloc_mac.inc"
+
+#endif // SANITIZER_MAC
diff --git a/libsanitizer/lsan/lsan_thread.cc b/libsanitizer/lsan/lsan_thread.cc
index af5ad47..e03e876 100644
--- a/libsanitizer/lsan/lsan_thread.cc
+++ b/libsanitizer/lsan/lsan_thread.cc
@@ -17,13 +17,11 @@
#include "sanitizer_common/sanitizer_thread_registry.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "lsan_allocator.h"
+#include "lsan_common.h"
namespace __lsan {
-const u32 kInvalidTid = (u32) -1;
-
static ThreadRegistry *thread_registry;
-static THREADLOCAL u32 current_thread_tid = kInvalidTid;
static ThreadContextBase *CreateThreadContext(u32 tid) {
void *mem = MmapOrDie(sizeof(ThreadContext), "ThreadContext");
@@ -39,14 +37,6 @@ void InitializeThreadRegistry() {
ThreadRegistry(CreateThreadContext, kMaxThreads, kThreadQuarantineSize);
}
-u32 GetCurrentThread() {
- return current_thread_tid;
-}
-
-void SetCurrentThread(u32 tid) {
- current_thread_tid = tid;
-}
-
ThreadContext::ThreadContext(int tid)
: ThreadContextBase(tid),
stack_begin_(0),
@@ -85,7 +75,7 @@ u32 ThreadCreate(u32 parent_tid, uptr user_id, bool detached) {
/* arg */ nullptr);
}
-void ThreadStart(u32 tid, uptr os_id) {
+void ThreadStart(u32 tid, tid_t os_id, bool workerthread) {
OnStartedArgs args;
uptr stack_size = 0;
uptr tls_size = 0;
@@ -95,11 +85,12 @@ void ThreadStart(u32 tid, uptr os_id) {
args.tls_end = args.tls_begin + tls_size;
GetAllocatorCacheRange(&args.cache_begin, &args.cache_end);
args.dtls = DTLS_Get();
- thread_registry->StartThread(tid, os_id, &args);
+ thread_registry->StartThread(tid, os_id, workerthread, &args);
}
void ThreadFinish() {
thread_registry->FinishThread(GetCurrentThread());
+ SetCurrentThread(kInvalidTid);
}
ThreadContext *CurrentThreadContext() {
@@ -134,7 +125,7 @@ void EnsureMainThreadIDIsCorrect() {
///// Interface to the common LSan module. /////
-bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
+bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end,
uptr *tls_begin, uptr *tls_end, uptr *cache_begin,
uptr *cache_end, DTLS **dtls) {
ThreadContext *context = static_cast<ThreadContext *>(
@@ -150,7 +141,7 @@ bool GetThreadRangesLocked(uptr os_id, uptr *stack_begin, uptr *stack_end,
return true;
}
-void ForEachExtraStackRange(uptr os_id, RangeIteratorCallback callback,
+void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback,
void *arg) {
}
diff --git a/libsanitizer/lsan/lsan_thread.h b/libsanitizer/lsan/lsan_thread.h
index dafd8af..8675834 100644
--- a/libsanitizer/lsan/lsan_thread.h
+++ b/libsanitizer/lsan/lsan_thread.h
@@ -43,7 +43,7 @@ class ThreadContext : public ThreadContextBase {
void InitializeThreadRegistry();
-void ThreadStart(u32 tid, uptr os_id);
+void ThreadStart(u32 tid, tid_t os_id, bool workerthread = false);
void ThreadFinish();
u32 ThreadCreate(u32 tid, uptr uid, bool detached);
void ThreadJoin(u32 tid);
diff --git a/libsanitizer/sanitizer_common/Makefile.am b/libsanitizer/sanitizer_common/Makefile.am
index 92c8419..adaab4c 100644
--- a/libsanitizer/sanitizer_common/Makefile.am
+++ b/libsanitizer/sanitizer_common/Makefile.am
@@ -19,13 +19,16 @@ ACLOCAL_AMFLAGS = -I m4
noinst_LTLIBRARIES = libsanitizer_common.la
sanitizer_common_files = \
+ sancov_flags.cc \
sanitizer_allocator.cc \
+ sanitizer_allocator_checks.cc \
sanitizer_common.cc \
sanitizer_common_libcdep.cc \
- sanitizer_coverage_libcdep.cc \
- sanitizer_coverage_mapping_libcdep.cc \
+ sanitizer_coverage_libcdep_new.cc \
sanitizer_deadlock_detector1.cc \
sanitizer_deadlock_detector2.cc \
+ sanitizer_errno.cc \
+ sanitizer_file.cc \
sanitizer_flags.cc \
sanitizer_flag_parser.cc \
sanitizer_libc.cc \
@@ -34,6 +37,7 @@ sanitizer_common_files = \
sanitizer_linux_libcdep.cc \
sanitizer_linux_s390.cc \
sanitizer_mac.cc \
+ sanitizer_mac_libcdep.cc \
sanitizer_persistent_allocator.cc \
sanitizer_platform_limits_linux.cc \
sanitizer_platform_limits_posix.cc \
@@ -50,6 +54,7 @@ sanitizer_common_files = \
sanitizer_symbolizer_mac.cc \
sanitizer_stacktrace_printer.cc \
sanitizer_stoptheworld_linux_libcdep.cc \
+ sanitizer_stoptheworld_mac.cc \
sanitizer_suppressions.cc \
sanitizer_symbolizer.cc \
sanitizer_symbolizer_libbacktrace.cc \
diff --git a/libsanitizer/sanitizer_common/Makefile.in b/libsanitizer/sanitizer_common/Makefile.in
index c375f63..b2acc5c 100644
--- a/libsanitizer/sanitizer_common/Makefile.in
+++ b/libsanitizer/sanitizer_common/Makefile.in
@@ -80,15 +80,16 @@ CONFIG_CLEAN_FILES =
CONFIG_CLEAN_VPATH_FILES =
LTLIBRARIES = $(noinst_LTLIBRARIES)
am__DEPENDENCIES_1 =
-am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
- sanitizer_common_libcdep.lo sanitizer_coverage_libcdep.lo \
- sanitizer_coverage_mapping_libcdep.lo \
+am__objects_1 = sancov_flags.lo sanitizer_allocator.lo \
+ sanitizer_allocator_checks.lo sanitizer_common.lo \
+ sanitizer_common_libcdep.lo sanitizer_coverage_libcdep_new.lo \
sanitizer_deadlock_detector1.lo \
- sanitizer_deadlock_detector2.lo sanitizer_flags.lo \
- sanitizer_flag_parser.lo sanitizer_libc.lo \
- sanitizer_libignore.lo sanitizer_linux.lo \
+ sanitizer_deadlock_detector2.lo sanitizer_errno.lo \
+ sanitizer_file.lo sanitizer_flags.lo sanitizer_flag_parser.lo \
+ sanitizer_libc.lo sanitizer_libignore.lo sanitizer_linux.lo \
sanitizer_linux_libcdep.lo sanitizer_linux_s390.lo \
- sanitizer_mac.lo sanitizer_persistent_allocator.lo \
+ sanitizer_mac.lo sanitizer_mac_libcdep.lo \
+ sanitizer_persistent_allocator.lo \
sanitizer_platform_limits_linux.lo \
sanitizer_platform_limits_posix.lo sanitizer_posix.lo \
sanitizer_posix_libcdep.lo sanitizer_printf.lo \
@@ -98,8 +99,8 @@ am__objects_1 = sanitizer_allocator.lo sanitizer_common.lo \
sanitizer_stacktrace_libcdep.lo sanitizer_symbolizer_mac.lo \
sanitizer_stacktrace_printer.lo \
sanitizer_stoptheworld_linux_libcdep.lo \
- sanitizer_suppressions.lo sanitizer_symbolizer.lo \
- sanitizer_symbolizer_libbacktrace.lo \
+ sanitizer_stoptheworld_mac.lo sanitizer_suppressions.lo \
+ sanitizer_symbolizer.lo sanitizer_symbolizer_libbacktrace.lo \
sanitizer_symbolizer_libcdep.lo \
sanitizer_symbolizer_posix_libcdep.lo \
sanitizer_symbolizer_win.lo sanitizer_termination.lo \
@@ -300,13 +301,16 @@ AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic \
ACLOCAL_AMFLAGS = -I m4
noinst_LTLIBRARIES = libsanitizer_common.la
sanitizer_common_files = \
+ sancov_flags.cc \
sanitizer_allocator.cc \
+ sanitizer_allocator_checks.cc \
sanitizer_common.cc \
sanitizer_common_libcdep.cc \
- sanitizer_coverage_libcdep.cc \
- sanitizer_coverage_mapping_libcdep.cc \
+ sanitizer_coverage_libcdep_new.cc \
sanitizer_deadlock_detector1.cc \
sanitizer_deadlock_detector2.cc \
+ sanitizer_errno.cc \
+ sanitizer_file.cc \
sanitizer_flags.cc \
sanitizer_flag_parser.cc \
sanitizer_libc.cc \
@@ -315,6 +319,7 @@ sanitizer_common_files = \
sanitizer_linux_libcdep.cc \
sanitizer_linux_s390.cc \
sanitizer_mac.cc \
+ sanitizer_mac_libcdep.cc \
sanitizer_persistent_allocator.cc \
sanitizer_platform_limits_linux.cc \
sanitizer_platform_limits_posix.cc \
@@ -331,6 +336,7 @@ sanitizer_common_files = \
sanitizer_symbolizer_mac.cc \
sanitizer_stacktrace_printer.cc \
sanitizer_stoptheworld_linux_libcdep.cc \
+ sanitizer_stoptheworld_mac.cc \
sanitizer_suppressions.cc \
sanitizer_symbolizer.cc \
sanitizer_symbolizer_libbacktrace.cc \
@@ -439,13 +445,16 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sancov_flags.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_allocator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_allocator_checks.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_common_libcdep.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage_libcdep.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage_mapping_libcdep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_coverage_libcdep_new.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_deadlock_detector1.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_deadlock_detector2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_errno.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_file.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flag_parser.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_flags.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_libc.Plo@am__quote@
@@ -456,6 +465,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_s390.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_linux_x86_64.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_mac_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_persistent_allocator.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_linux.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_platform_limits_posix.Plo@am__quote@
@@ -471,6 +481,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace_libcdep.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stacktrace_printer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stoptheworld_linux_libcdep.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_stoptheworld_mac.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_suppressions.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sanitizer_symbolizer_libbacktrace.Plo@am__quote@
diff --git a/libsanitizer/sanitizer_common/sancov_flags.cc b/libsanitizer/sanitizer_common/sancov_flags.cc
new file mode 100644
index 0000000..e600cda
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sancov_flags.cc
@@ -0,0 +1,57 @@
+//===-- sancov_flags.cc -----------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer Coverage runtime flags.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sancov_flags.h"
+#include "sanitizer_flag_parser.h"
+#include "sanitizer_platform.h"
+
+SANITIZER_INTERFACE_WEAK_DEF(const char*, __sancov_default_options, void) {
+ return "";
+}
+
+using namespace __sanitizer;
+
+namespace __sancov {
+
+SancovFlags sancov_flags_dont_use_directly; // use via flags();
+
+void SancovFlags::SetDefaults() {
+#define SANCOV_FLAG(Type, Name, DefaultValue, Description) Name = DefaultValue;
+#include "sancov_flags.inc"
+#undef SANCOV_FLAG
+}
+
+static void RegisterSancovFlags(FlagParser *parser, SancovFlags *f) {
+#define SANCOV_FLAG(Type, Name, DefaultValue, Description) \
+ RegisterFlag(parser, #Name, Description, &f->Name);
+#include "sancov_flags.inc"
+#undef SANCOV_FLAG
+}
+
+static const char *MaybeCallSancovDefaultOptions() {
+ return (&__sancov_default_options) ? __sancov_default_options() : "";
+}
+
+void InitializeSancovFlags() {
+ SancovFlags *f = sancov_flags();
+ f->SetDefaults();
+
+ FlagParser parser;
+ RegisterSancovFlags(&parser, f);
+
+ parser.ParseString(MaybeCallSancovDefaultOptions());
+ parser.ParseString(GetEnv("SANCOV_OPTIONS"));
+
+ ReportUnrecognizedFlags();
+ if (f->help) parser.PrintFlagDescriptions();
+}
+
+} // namespace __sancov
diff --git a/libsanitizer/sanitizer_common/sancov_flags.h b/libsanitizer/sanitizer_common/sancov_flags.h
new file mode 100644
index 0000000..f7e0186
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sancov_flags.h
@@ -0,0 +1,38 @@
+//===-- sancov_flags.h ------------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer Coverage runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANCOV_FLAGS_H
+#define SANCOV_FLAGS_H
+
+#include "sanitizer_flag_parser.h"
+#include "sanitizer_internal_defs.h"
+
+namespace __sancov {
+
+struct SancovFlags {
+#define SANCOV_FLAG(Type, Name, DefaultValue, Description) Type Name;
+#include "sancov_flags.inc"
+#undef SANCOV_FLAG
+
+ void SetDefaults();
+};
+
+extern SancovFlags sancov_flags_dont_use_directly;
+
+inline SancovFlags* sancov_flags() { return &sancov_flags_dont_use_directly; }
+
+void InitializeSancovFlags();
+
+} // namespace __sancov
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE const char*
+__sancov_default_options();
+
+#endif
diff --git a/libsanitizer/sanitizer_common/sancov_flags.inc b/libsanitizer/sanitizer_common/sancov_flags.inc
new file mode 100644
index 0000000..a6107cc
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sancov_flags.inc
@@ -0,0 +1,19 @@
+//===-- sancov_flags.inc ----------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Sanitizer Coverage runtime flags.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANCOV_FLAG
+#error "Defnine SANCOV_FLAG prior to including this file!"
+#endif
+
+SANCOV_FLAG(bool, symbolize, true,
+ "If set, converage information will be symbolized by sancov tool "
+ "after dumping.")
+
+SANCOV_FLAG(bool, help, false, "Print flags help.")
diff --git a/libsanitizer/sanitizer_common/sanitizer_addrhashmap.h b/libsanitizer/sanitizer_common/sanitizer_addrhashmap.h
index 3bc40ef..a67ec84 100644
--- a/libsanitizer/sanitizer_common/sanitizer_addrhashmap.h
+++ b/libsanitizer/sanitizer_common/sanitizer_addrhashmap.h
@@ -71,6 +71,8 @@ class AddrHashMap {
~Handle();
T *operator->();
+ T &operator*();
+ const T &operator*() const;
bool created() const;
bool exists() const;
@@ -134,6 +136,16 @@ T *AddrHashMap<T, kSize>::Handle::operator->() {
return &cell_->val;
}
+template <typename T, uptr kSize>
+const T &AddrHashMap<T, kSize>::Handle::operator*() const {
+ return cell_->val;
+}
+
+template <typename T, uptr kSize>
+T &AddrHashMap<T, kSize>::Handle::operator*() {
+ return cell_->val;
+}
+
template<typename T, uptr kSize>
bool AddrHashMap<T, kSize>::Handle::created() const {
return created_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.cc b/libsanitizer/sanitizer_common/sanitizer_allocator.cc
index 2755853..895efcf 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.cc
@@ -12,6 +12,7 @@
#include "sanitizer_allocator.h"
+#include "sanitizer_allocator_checks.h"
#include "sanitizer_allocator_internal.h"
#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
@@ -92,7 +93,7 @@ InternalAllocator *internal_allocator() {
SpinMutexLock l(&internal_alloc_init_mu);
if (atomic_load(&internal_allocator_initialized, memory_order_relaxed) ==
0) {
- internal_allocator_instance->Init(/* may_return_null*/ false);
+ internal_allocator_instance->Init(kReleaseToOSIntervalNever);
atomic_store(&internal_allocator_initialized, 1, memory_order_release);
}
}
@@ -105,9 +106,9 @@ static void *RawInternalAlloc(uptr size, InternalAllocatorCache *cache,
if (cache == 0) {
SpinMutexLock l(&internal_allocator_cache_mu);
return internal_allocator()->Allocate(&internal_allocator_cache, size,
- alignment, false);
+ alignment);
}
- return internal_allocator()->Allocate(cache, size, alignment, false);
+ return internal_allocator()->Allocate(cache, size, alignment);
}
static void *RawInternalRealloc(void *ptr, uptr size,
@@ -158,8 +159,8 @@ void *InternalRealloc(void *addr, uptr size, InternalAllocatorCache *cache) {
}
void *InternalCalloc(uptr count, uptr size, InternalAllocatorCache *cache) {
- if (CallocShouldReturnNullDueToOverflow(count, size))
- return internal_allocator()->ReturnNullOrDieOnBadRequest();
+ if (UNLIKELY(CheckForCallocOverflow(count, size)))
+ return InternalAllocator::FailureHandler::OnBadRequest();
void *p = InternalAlloc(count * size, cache);
if (p) internal_memset(p, 0, count * size);
return p;
@@ -200,18 +201,15 @@ void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback) {
low_level_alloc_callback = callback;
}
-bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n) {
- if (!size) return false;
- uptr max = (uptr)-1L;
- return (max / size) < n;
-}
-
-static atomic_uint8_t reporting_out_of_memory = {0};
+static atomic_uint8_t allocator_out_of_memory = {0};
+static atomic_uint8_t allocator_may_return_null = {0};
-bool IsReportingOOM() { return atomic_load_relaxed(&reporting_out_of_memory); }
+bool IsAllocatorOutOfMemory() {
+ return atomic_load_relaxed(&allocator_out_of_memory);
+}
-void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory) {
- if (out_of_memory) atomic_store_relaxed(&reporting_out_of_memory, 1);
+// Prints error message and kills the program.
+void NORETURN ReportAllocatorCannotReturnNull() {
Report("%s's allocator is terminating the process instead of returning 0\n",
SanitizerToolName);
Report("If you don't like this behavior set allocator_may_return_null=1\n");
@@ -219,4 +217,35 @@ void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory) {
Die();
}
+bool AllocatorMayReturnNull() {
+ return atomic_load(&allocator_may_return_null, memory_order_relaxed);
+}
+
+void SetAllocatorMayReturnNull(bool may_return_null) {
+ atomic_store(&allocator_may_return_null, may_return_null,
+ memory_order_relaxed);
+}
+
+void *ReturnNullOrDieOnFailure::OnBadRequest() {
+ if (AllocatorMayReturnNull())
+ return nullptr;
+ ReportAllocatorCannotReturnNull();
+}
+
+void *ReturnNullOrDieOnFailure::OnOOM() {
+ atomic_store_relaxed(&allocator_out_of_memory, 1);
+ if (AllocatorMayReturnNull())
+ return nullptr;
+ ReportAllocatorCannotReturnNull();
+}
+
+void NORETURN *DieOnFailure::OnBadRequest() {
+ ReportAllocatorCannotReturnNull();
+}
+
+void NORETURN *DieOnFailure::OnOOM() {
+ atomic_store_relaxed(&allocator_out_of_memory, 1);
+ ReportAllocatorCannotReturnNull();
+}
+
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator.h b/libsanitizer/sanitizer_common/sanitizer_allocator.h
index ba50acd..523578a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator.h
@@ -22,12 +22,28 @@
namespace __sanitizer {
-// Returns true if ReportAllocatorCannotReturnNull(true) was called.
-// Can be use to avoid memory hungry operations.
-bool IsReportingOOM();
+// Since flags are immutable and allocator behavior can be changed at runtime
+// (unit tests or ASan on Android are some examples), allocator_may_return_null
+// flag value is cached here and can be altered later.
+bool AllocatorMayReturnNull();
+void SetAllocatorMayReturnNull(bool may_return_null);
-// Prints error message and kills the program.
-void NORETURN ReportAllocatorCannotReturnNull(bool out_of_memory);
+// Allocator failure handling policies:
+// Implements AllocatorMayReturnNull policy, returns null when the flag is set,
+// dies otherwise.
+struct ReturnNullOrDieOnFailure {
+ static void *OnBadRequest();
+ static void *OnOOM();
+};
+// Always dies on the failure.
+struct DieOnFailure {
+ static void NORETURN *OnBadRequest();
+ static void NORETURN *OnOOM();
+};
+
+// Returns true if allocator detected OOM condition. Can be used to avoid memory
+// hungry operations. Set when AllocatorReturnNullOrDieOnOOM() is called.
+bool IsAllocatorOutOfMemory();
// Allocators call these callbacks on mmap/munmap.
struct NoOpMapUnmapCallback {
@@ -38,9 +54,6 @@ struct NoOpMapUnmapCallback {
// Callback type for iterating over chunks.
typedef void (*ForEachChunkCallback)(uptr chunk, void *arg);
-// Returns true if calloc(size, n) should return 0 due to overflow in size*n.
-bool CallocShouldReturnNullDueToOverflow(uptr size, uptr n);
-
#include "sanitizer_allocator_size_class_map.h"
#include "sanitizer_allocator_stats.h"
#include "sanitizer_allocator_primary64.h"
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_checks.cc b/libsanitizer/sanitizer_common/sanitizer_allocator_checks.cc
new file mode 100644
index 0000000..3e6eb61
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_checks.cc
@@ -0,0 +1,21 @@
+//===-- sanitizer_allocator_checks.cc ---------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory
+// allocators.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_errno.h"
+
+namespace __sanitizer {
+
+void SetErrnoToENOMEM() {
+ errno = errno_ENOMEM;
+}
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h b/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h
new file mode 100644
index 0000000..9788132
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_checks.h
@@ -0,0 +1,73 @@
+//===-- sanitizer_allocator_checks.h ----------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Various checks shared between ThreadSanitizer, MemorySanitizer, etc. memory
+// allocators.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ALLOCATOR_CHECKS_H
+#define SANITIZER_ALLOCATOR_CHECKS_H
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_common.h"
+#include "sanitizer_platform.h"
+
+namespace __sanitizer {
+
+// The following is defined in a separate compilation unit to avoid pulling in
+// sanitizer_errno.h in this header, which leads to conflicts when other system
+// headers include errno.h. This is usually the result of an unlikely event,
+// and as such we do not care as much about having it inlined.
+void SetErrnoToENOMEM();
+
+// A common errno setting logic shared by almost all sanitizer allocator APIs.
+INLINE void *SetErrnoOnNull(void *ptr) {
+ if (UNLIKELY(!ptr))
+ SetErrnoToENOMEM();
+ return ptr;
+}
+
+// In case of the check failure, the caller of the following Check... functions
+// should "return POLICY::OnBadRequest();" where POLICY is the current allocator
+// failure handling policy.
+
+// Checks aligned_alloc() parameters, verifies that the alignment is a power of
+// two and that the size is a multiple of alignment for POSIX implementation,
+// and a bit relaxed requirement for non-POSIX ones, that the size is a multiple
+// of alignment.
+INLINE bool CheckAlignedAllocAlignmentAndSize(uptr alignment, uptr size) {
+#if SANITIZER_POSIX
+ return IsPowerOfTwo(alignment) && (size & (alignment - 1)) == 0;
+#else
+ return size % alignment == 0;
+#endif
+}
+
+// Checks posix_memalign() parameters, verifies that alignment is a power of two
+// and a multiple of sizeof(void *).
+INLINE bool CheckPosixMemalignAlignment(uptr alignment) {
+ return IsPowerOfTwo(alignment) && (alignment % sizeof(void *)) == 0; // NOLINT
+}
+
+// Returns true if calloc(size, n) call overflows on size*n calculation.
+INLINE bool CheckForCallocOverflow(uptr size, uptr n) {
+ if (!size)
+ return false;
+ uptr max = (uptr)-1L;
+ return (max / size) < n;
+}
+
+// Returns true if the size passed to pvalloc overflows when rounded to the next
+// multiple of page_size.
+INLINE bool CheckForPvallocOverflow(uptr size, uptr page_size) {
+ return RoundUpTo(size, page_size) < size;
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ALLOCATOR_CHECKS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
index 4dc9ca7..99e411f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_combined.h
@@ -22,72 +22,57 @@ template <class PrimaryAllocator, class AllocatorCache,
class SecondaryAllocator> // NOLINT
class CombinedAllocator {
public:
- void InitCommon(bool may_return_null) {
- primary_.Init();
- atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
- }
+ typedef typename SecondaryAllocator::FailureHandler FailureHandler;
- void InitLinkerInitialized(bool may_return_null) {
- secondary_.InitLinkerInitialized(may_return_null);
+ void InitLinkerInitialized(s32 release_to_os_interval_ms) {
+ primary_.Init(release_to_os_interval_ms);
+ secondary_.InitLinkerInitialized();
stats_.InitLinkerInitialized();
- InitCommon(may_return_null);
}
- void Init(bool may_return_null) {
- secondary_.Init(may_return_null);
+ void Init(s32 release_to_os_interval_ms) {
+ primary_.Init(release_to_os_interval_ms);
+ secondary_.Init();
stats_.Init();
- InitCommon(may_return_null);
}
- void *Allocate(AllocatorCache *cache, uptr size, uptr alignment,
- bool cleared = false, bool check_rss_limit = false) {
+ void *Allocate(AllocatorCache *cache, uptr size, uptr alignment) {
// Returning 0 on malloc(0) may break a lot of code.
if (size == 0)
size = 1;
- if (size + alignment < size) return ReturnNullOrDieOnBadRequest();
- if (check_rss_limit && RssLimitIsExceeded()) return ReturnNullOrDieOnOOM();
+ if (size + alignment < size)
+ return FailureHandler::OnBadRequest();
+ uptr original_size = size;
+ // If alignment requirements are to be fulfilled by the frontend allocator
+ // rather than by the primary or secondary, passing an alignment lower than
+ // or equal to 8 will prevent any further rounding up, as well as the later
+ // alignment check.
if (alignment > 8)
size = RoundUpTo(size, alignment);
+ // The primary allocator should return a 2^x aligned allocation when
+ // requested 2^x bytes, hence using the rounded up 'size' when being
+ // serviced by the primary (this is no longer true when the primary is
+ // using a non-fixed base address). The secondary takes care of the
+ // alignment without such requirement, and allocating 'size' would use
+ // extraneous memory, so we employ 'original_size'.
void *res;
- bool from_primary = primary_.CanAllocate(size, alignment);
- if (from_primary)
+ if (primary_.CanAllocate(size, alignment))
res = cache->Allocate(&primary_, primary_.ClassID(size));
else
- res = secondary_.Allocate(&stats_, size, alignment);
+ res = secondary_.Allocate(&stats_, original_size, alignment);
+ if (!res)
+ return FailureHandler::OnOOM();
if (alignment > 8)
CHECK_EQ(reinterpret_cast<uptr>(res) & (alignment - 1), 0);
- if (cleared && res && from_primary)
- internal_bzero_aligned16(res, RoundUpTo(size, 16));
return res;
}
- bool MayReturnNull() const {
- return atomic_load(&may_return_null_, memory_order_acquire);
- }
-
- void *ReturnNullOrDieOnBadRequest() {
- if (MayReturnNull())
- return nullptr;
- ReportAllocatorCannotReturnNull(false);
- }
-
- void *ReturnNullOrDieOnOOM() {
- if (MayReturnNull()) return nullptr;
- ReportAllocatorCannotReturnNull(true);
+ s32 ReleaseToOSIntervalMs() const {
+ return primary_.ReleaseToOSIntervalMs();
}
- void SetMayReturnNull(bool may_return_null) {
- secondary_.SetMayReturnNull(may_return_null);
- atomic_store(&may_return_null_, may_return_null, memory_order_release);
- }
-
- bool RssLimitIsExceeded() {
- return atomic_load(&rss_limit_is_exceeded_, memory_order_acquire);
- }
-
- void SetRssLimitIsExceeded(bool rss_limit_is_exceeded) {
- atomic_store(&rss_limit_is_exceeded_, rss_limit_is_exceeded,
- memory_order_release);
+ void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) {
+ primary_.SetReleaseToOSIntervalMs(release_to_os_interval_ms);
}
void Deallocate(AllocatorCache *cache, void *p) {
@@ -191,8 +176,6 @@ class CombinedAllocator {
primary_.ForceUnlock();
}
- void ReleaseToOS() { primary_.ReleaseToOS(); }
-
// Iterate over all existing chunks.
// The allocator must be locked when calling this function.
void ForEachChunk(ForEachChunkCallback callback, void *arg) {
@@ -204,6 +187,4 @@ class CombinedAllocator {
PrimaryAllocator primary_;
SecondaryAllocator secondary_;
AllocatorGlobalStats stats_;
- atomic_uint8_t may_return_null_;
- atomic_uint8_t rss_limit_is_exceeded_;
};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
index 166f8c2..fa74f8c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_interface.h
@@ -32,13 +32,12 @@ SANITIZER_INTERFACE_ATTRIBUTE int __sanitizer_install_malloc_and_free_hooks(
void (*free_hook)(const void *));
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ void __sanitizer_malloc_hook(void *ptr, uptr size);
+ void __sanitizer_malloc_hook(void *ptr, uptr size);
SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- /* OPTIONAL */ void __sanitizer_free_hook(void *ptr);
+ void __sanitizer_free_hook(void *ptr);
-
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
- void __sanitizer_print_memory_profile(int top_percent);
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void
+__sanitizer_print_memory_profile(uptr top_percent, uptr max_number_of_contexts);
} // extern "C"
#endif // SANITIZER_ALLOCATOR_INTERFACE_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
index 6a8da8f..f1aed0f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_internal.h
@@ -21,27 +21,32 @@ namespace __sanitizer {
// purposes.
typedef CompactSizeClassMap InternalSizeClassMap;
-static const uptr kInternalAllocatorSpace = 0;
-static const u64 kInternalAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kInternalAllocatorRegionSizeLog = 20;
-#if SANITIZER_WORDSIZE == 32
static const uptr kInternalAllocatorNumRegions =
- kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
+ SANITIZER_MMAP_RANGE_SIZE >> kInternalAllocatorRegionSizeLog;
+#if SANITIZER_WORDSIZE == 32
typedef FlatByteMap<kInternalAllocatorNumRegions> ByteMap;
#else
-static const uptr kInternalAllocatorNumRegions =
- kInternalAllocatorSize >> kInternalAllocatorRegionSizeLog;
typedef TwoLevelByteMap<(kInternalAllocatorNumRegions >> 12), 1 << 12> ByteMap;
#endif
-typedef SizeClassAllocator32<
- kInternalAllocatorSpace, kInternalAllocatorSize, 0, InternalSizeClassMap,
- kInternalAllocatorRegionSizeLog, ByteMap> PrimaryInternalAllocator;
+struct AP32 {
+ static const uptr kSpaceBeg = 0;
+ static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
+ static const uptr kMetadataSize = 0;
+ typedef InternalSizeClassMap SizeClassMap;
+ static const uptr kRegionSizeLog = kInternalAllocatorRegionSizeLog;
+ typedef __sanitizer::ByteMap ByteMap;
+ typedef NoOpMapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+typedef SizeClassAllocator32<AP32> PrimaryInternalAllocator;
typedef SizeClassAllocatorLocalCache<PrimaryInternalAllocator>
InternalAllocatorCache;
typedef CombinedAllocator<PrimaryInternalAllocator, InternalAllocatorCache,
- LargeMmapAllocator<> > InternalAllocator;
+ LargeMmapAllocator<NoOpMapUnmapCallback, DieOnFailure>
+ > InternalAllocator;
void *InternalAlloc(uptr size, InternalAllocatorCache *cache = nullptr,
uptr alignment = 0);
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h b/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h
index 40ef078..99013e3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_local_cache.h
@@ -24,9 +24,6 @@ struct SizeClassAllocatorLocalCache
template <class SizeClassAllocator>
struct SizeClassAllocator64LocalCache {
typedef SizeClassAllocator Allocator;
- static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
- typedef typename Allocator::SizeClassMapT SizeClassMap;
- typedef typename Allocator::CompactPtrT CompactPtrT;
void Init(AllocatorGlobalStats *s) {
stats_.Init();
@@ -43,10 +40,12 @@ struct SizeClassAllocator64LocalCache {
void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
CHECK_NE(class_id, 0UL);
CHECK_LT(class_id, kNumClasses);
- stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id));
PerClass *c = &per_class_[class_id];
- if (UNLIKELY(c->count == 0))
- Refill(c, allocator, class_id);
+ if (UNLIKELY(c->count == 0)) {
+ if (UNLIKELY(!Refill(c, allocator, class_id)))
+ return nullptr;
+ }
+ stats_.Add(AllocatorStatAllocated, c->class_size);
CHECK_GT(c->count, 0);
CompactPtrT chunk = c->chunks[--c->count];
void *res = reinterpret_cast<void *>(allocator->CompactPtrToPointer(
@@ -60,8 +59,8 @@ struct SizeClassAllocator64LocalCache {
// If the first allocator call on a new thread is a deallocation, then
// max_count will be zero, leading to check failure.
InitCache();
- stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id));
PerClass *c = &per_class_[class_id];
+ stats_.Sub(AllocatorStatAllocated, c->class_size);
CHECK_NE(c->max_count, 0UL);
if (UNLIKELY(c->count == c->max_count))
Drain(c, allocator, class_id, c->max_count / 2);
@@ -72,38 +71,46 @@ struct SizeClassAllocator64LocalCache {
}
void Drain(SizeClassAllocator *allocator) {
- for (uptr class_id = 0; class_id < kNumClasses; class_id++) {
- PerClass *c = &per_class_[class_id];
+ for (uptr i = 0; i < kNumClasses; i++) {
+ PerClass *c = &per_class_[i];
while (c->count > 0)
- Drain(c, allocator, class_id, c->count);
+ Drain(c, allocator, i, c->count);
}
}
- // private:
+ private:
+ typedef typename Allocator::SizeClassMapT SizeClassMap;
+ static const uptr kNumClasses = SizeClassMap::kNumClasses;
+ typedef typename Allocator::CompactPtrT CompactPtrT;
+
struct PerClass {
u32 count;
u32 max_count;
+ uptr class_size;
CompactPtrT chunks[2 * SizeClassMap::kMaxNumCachedHint];
};
PerClass per_class_[kNumClasses];
AllocatorStats stats_;
void InitCache() {
- if (per_class_[1].max_count)
+ if (LIKELY(per_class_[1].max_count))
return;
for (uptr i = 0; i < kNumClasses; i++) {
PerClass *c = &per_class_[i];
c->max_count = 2 * SizeClassMap::MaxCachedHint(i);
+ c->class_size = Allocator::ClassIdToSize(i);
}
}
- NOINLINE void Refill(PerClass *c, SizeClassAllocator *allocator,
+ NOINLINE bool Refill(PerClass *c, SizeClassAllocator *allocator,
uptr class_id) {
InitCache();
- uptr num_requested_chunks = SizeClassMap::MaxCachedHint(class_id);
- allocator->GetFromAllocator(&stats_, class_id, c->chunks,
- num_requested_chunks);
+ uptr num_requested_chunks = c->max_count / 2;
+ if (UNLIKELY(!allocator->GetFromAllocator(&stats_, class_id, c->chunks,
+ num_requested_chunks)))
+ return false;
c->count = num_requested_chunks;
+ return true;
}
NOINLINE void Drain(PerClass *c, SizeClassAllocator *allocator, uptr class_id,
@@ -122,7 +129,6 @@ template <class SizeClassAllocator>
struct SizeClassAllocator32LocalCache {
typedef SizeClassAllocator Allocator;
typedef typename Allocator::TransferBatch TransferBatch;
- static const uptr kNumClasses = SizeClassAllocator::kNumClasses;
void Init(AllocatorGlobalStats *s) {
stats_.Init();
@@ -130,6 +136,21 @@ struct SizeClassAllocator32LocalCache {
s->Register(&stats_);
}
+ // Returns a TransferBatch suitable for class_id.
+ TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator,
+ TransferBatch *b) {
+ if (uptr batch_class_id = per_class_[class_id].batch_class_id)
+ return (TransferBatch*)Allocate(allocator, batch_class_id);
+ return b;
+ }
+
+ // Destroys TransferBatch b.
+ void DestroyBatch(uptr class_id, SizeClassAllocator *allocator,
+ TransferBatch *b) {
+ if (uptr batch_class_id = per_class_[class_id].batch_class_id)
+ Deallocate(allocator, batch_class_id, b);
+ }
+
void Destroy(SizeClassAllocator *allocator, AllocatorGlobalStats *s) {
Drain(allocator);
if (s)
@@ -139,10 +160,12 @@ struct SizeClassAllocator32LocalCache {
void *Allocate(SizeClassAllocator *allocator, uptr class_id) {
CHECK_NE(class_id, 0UL);
CHECK_LT(class_id, kNumClasses);
- stats_.Add(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id));
PerClass *c = &per_class_[class_id];
- if (UNLIKELY(c->count == 0))
- Refill(allocator, class_id);
+ if (UNLIKELY(c->count == 0)) {
+ if (UNLIKELY(!Refill(allocator, class_id)))
+ return nullptr;
+ }
+ stats_.Add(AllocatorStatAllocated, c->class_size);
void *res = c->batch[--c->count];
PREFETCH(c->batch[c->count - 1]);
return res;
@@ -154,8 +177,8 @@ struct SizeClassAllocator32LocalCache {
// If the first allocator call on a new thread is a deallocation, then
// max_count will be zero, leading to check failure.
InitCache();
- stats_.Sub(AllocatorStatAllocated, Allocator::ClassIdToSize(class_id));
PerClass *c = &per_class_[class_id];
+ stats_.Sub(AllocatorStatAllocated, c->class_size);
CHECK_NE(c->max_count, 0UL);
if (UNLIKELY(c->count == c->max_count))
Drain(allocator, class_id);
@@ -163,72 +186,68 @@ struct SizeClassAllocator32LocalCache {
}
void Drain(SizeClassAllocator *allocator) {
- for (uptr class_id = 0; class_id < kNumClasses; class_id++) {
- PerClass *c = &per_class_[class_id];
+ for (uptr i = 0; i < kNumClasses; i++) {
+ PerClass *c = &per_class_[i];
while (c->count > 0)
- Drain(allocator, class_id);
+ Drain(allocator, i);
}
}
- // private:
- typedef typename SizeClassAllocator::SizeClassMapT SizeClassMap;
+ private:
+ typedef typename Allocator::SizeClassMapT SizeClassMap;
+ static const uptr kBatchClassID = SizeClassMap::kBatchClassID;
+ static const uptr kNumClasses = SizeClassMap::kNumClasses;
+ // If kUseSeparateSizeClassForBatch is true, all TransferBatch objects are
+ // allocated from kBatchClassID size class (except for those that are needed
+ // for kBatchClassID itself). The goal is to have TransferBatches in a totally
+ // different region of RAM to improve security.
+ static const bool kUseSeparateSizeClassForBatch =
+ Allocator::kUseSeparateSizeClassForBatch;
+
struct PerClass {
uptr count;
uptr max_count;
+ uptr class_size;
+ uptr batch_class_id;
void *batch[2 * TransferBatch::kMaxNumCached];
};
PerClass per_class_[kNumClasses];
AllocatorStats stats_;
void InitCache() {
- if (per_class_[1].max_count)
+ if (LIKELY(per_class_[1].max_count))
return;
+ const uptr batch_class_id = SizeClassMap::ClassID(sizeof(TransferBatch));
for (uptr i = 0; i < kNumClasses; i++) {
PerClass *c = &per_class_[i];
- c->max_count = 2 * TransferBatch::MaxCached(i);
+ uptr max_cached = TransferBatch::MaxCached(i);
+ c->max_count = 2 * max_cached;
+ c->class_size = Allocator::ClassIdToSize(i);
+ // Precompute the class id to use to store batches for the current class
+ // id. 0 means the class size is large enough to store a batch within one
+ // of the chunks. If using a separate size class, it will always be
+ // kBatchClassID, except for kBatchClassID itself.
+ if (kUseSeparateSizeClassForBatch) {
+ c->batch_class_id = (i == kBatchClassID) ? 0 : kBatchClassID;
+ } else {
+ c->batch_class_id = (c->class_size <
+ TransferBatch::AllocationSizeRequiredForNElements(max_cached)) ?
+ batch_class_id : 0;
+ }
}
}
- // TransferBatch class is declared in SizeClassAllocator.
- // We transfer chunks between central and thread-local free lists in batches.
- // For small size classes we allocate batches separately.
- // For large size classes we may use one of the chunks to store the batch.
- // sizeof(TransferBatch) must be a power of 2 for more efficient allocation.
- static uptr SizeClassForTransferBatch(uptr class_id) {
- if (Allocator::ClassIdToSize(class_id) <
- TransferBatch::AllocationSizeRequiredForNElements(
- TransferBatch::MaxCached(class_id)))
- return SizeClassMap::ClassID(sizeof(TransferBatch));
- return 0;
- }
-
- // Returns a TransferBatch suitable for class_id.
- // For small size classes allocates the batch from the allocator.
- // For large size classes simply returns b.
- TransferBatch *CreateBatch(uptr class_id, SizeClassAllocator *allocator,
- TransferBatch *b) {
- if (uptr batch_class_id = SizeClassForTransferBatch(class_id))
- return (TransferBatch*)Allocate(allocator, batch_class_id);
- return b;
- }
-
- // Destroys TransferBatch b.
- // For small size classes deallocates b to the allocator.
- // Does notthing for large size classes.
- void DestroyBatch(uptr class_id, SizeClassAllocator *allocator,
- TransferBatch *b) {
- if (uptr batch_class_id = SizeClassForTransferBatch(class_id))
- Deallocate(allocator, batch_class_id, b);
- }
-
- NOINLINE void Refill(SizeClassAllocator *allocator, uptr class_id) {
+ NOINLINE bool Refill(SizeClassAllocator *allocator, uptr class_id) {
InitCache();
PerClass *c = &per_class_[class_id];
TransferBatch *b = allocator->AllocateBatch(&stats_, this, class_id);
+ if (UNLIKELY(!b))
+ return false;
CHECK_GT(b->Count(), 0);
b->CopyToArray(c->batch);
c->count = b->Count();
DestroyBatch(class_id, allocator, b);
+ return true;
}
NOINLINE void Drain(SizeClassAllocator *allocator, uptr class_id) {
@@ -238,6 +257,10 @@ struct SizeClassAllocator32LocalCache {
uptr first_idx_to_drain = c->count - cnt;
TransferBatch *b = CreateBatch(
class_id, allocator, (TransferBatch *)c->batch[first_idx_to_drain]);
+ // Failure to allocate a batch while releasing memory is non recoverable.
+ // TODO(alekseys): Figure out how to do it without allocating a new batch.
+ if (UNLIKELY(!b))
+ DieOnFailure::OnOOM();
b->SetFromArray(allocator->GetRegionBeginBySizeClass(class_id),
&c->batch[first_idx_to_drain], cnt);
c->count -= cnt;
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
index 989b87a..90a57db 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary32.h
@@ -22,7 +22,8 @@ template<class SizeClassAllocator> struct SizeClassAllocator32LocalCache;
// be returned by MmapOrDie().
//
// Region:
-// a result of a single call to MmapAlignedOrDie(kRegionSize, kRegionSize).
+// a result of a single call to MmapAlignedOrDieOnFatalError(kRegionSize,
+// kRegionSize).
// Since the regions are aligned by kRegionSize, there are exactly
// kNumPossibleRegions possible regions in the address space and so we keep
// a ByteMap possible_regions to store the size classes of each Region.
@@ -34,13 +35,30 @@ template<class SizeClassAllocator> struct SizeClassAllocator32LocalCache;
//
// In order to avoid false sharing the objects of this class should be
// chache-line aligned.
-template <const uptr kSpaceBeg, const u64 kSpaceSize,
- const uptr kMetadataSize, class SizeClassMap,
- const uptr kRegionSizeLog,
- class ByteMap,
- class MapUnmapCallback = NoOpMapUnmapCallback>
+
+struct SizeClassAllocator32FlagMasks { // Bit masks.
+ enum {
+ kRandomShuffleChunks = 1,
+ kUseSeparateSizeClassForBatch = 2,
+ };
+};
+
+template <class Params>
class SizeClassAllocator32 {
public:
+ static const uptr kSpaceBeg = Params::kSpaceBeg;
+ static const u64 kSpaceSize = Params::kSpaceSize;
+ static const uptr kMetadataSize = Params::kMetadataSize;
+ typedef typename Params::SizeClassMap SizeClassMap;
+ static const uptr kRegionSizeLog = Params::kRegionSizeLog;
+ typedef typename Params::ByteMap ByteMap;
+ typedef typename Params::MapUnmapCallback MapUnmapCallback;
+
+ static const bool kRandomShuffleChunks = Params::kFlags &
+ SizeClassAllocator32FlagMasks::kRandomShuffleChunks;
+ static const bool kUseSeparateSizeClassForBatch = Params::kFlags &
+ SizeClassAllocator32FlagMasks::kUseSeparateSizeClassForBatch;
+
struct TransferBatch {
static const uptr kMaxNumCached = SizeClassMap::kMaxNumCachedHint - 2;
void SetFromArray(uptr region_beg_unused, void *batch[], uptr count) {
@@ -77,24 +95,30 @@ class SizeClassAllocator32 {
static const uptr kBatchSize = sizeof(TransferBatch);
COMPILER_CHECK((kBatchSize & (kBatchSize - 1)) == 0);
- COMPILER_CHECK(sizeof(TransferBatch) ==
- SizeClassMap::kMaxNumCachedHint * sizeof(uptr));
+ COMPILER_CHECK(kBatchSize == SizeClassMap::kMaxNumCachedHint * sizeof(uptr));
static uptr ClassIdToSize(uptr class_id) {
- return SizeClassMap::Size(class_id);
+ return (class_id == SizeClassMap::kBatchClassID) ?
+ kBatchSize : SizeClassMap::Size(class_id);
}
- typedef SizeClassAllocator32<kSpaceBeg, kSpaceSize, kMetadataSize,
- SizeClassMap, kRegionSizeLog, ByteMap, MapUnmapCallback> ThisT;
+ typedef SizeClassAllocator32<Params> ThisT;
typedef SizeClassAllocator32LocalCache<ThisT> AllocatorCache;
- void Init() {
+ void Init(s32 release_to_os_interval_ms) {
possible_regions.TestOnlyInit();
internal_memset(size_class_info_array, 0, sizeof(size_class_info_array));
}
+ s32 ReleaseToOSIntervalMs() const {
+ return kReleaseToOSIntervalNever;
+ }
+
+ void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) {
+ // This is empty here. Currently only implemented in 64-bit allocator.
+ }
+
void *MapWithCallback(uptr size) {
- size = RoundUpTo(size, GetPageSizeCached());
void *res = MmapOrDie(size, "SizeClassAllocator32");
MapUnmapCallback().OnMap((uptr)res, size);
return res;
@@ -126,8 +150,9 @@ class SizeClassAllocator32 {
CHECK_LT(class_id, kNumClasses);
SizeClassInfo *sci = GetSizeClassInfo(class_id);
SpinMutexLock l(&sci->mutex);
- if (sci->free_list.empty())
- PopulateFreeList(stat, c, sci, class_id);
+ if (sci->free_list.empty() &&
+ UNLIKELY(!PopulateFreeList(stat, c, sci, class_id)))
+ return nullptr;
CHECK(!sci->free_list.empty());
TransferBatch *b = sci->free_list.front();
sci->free_list.pop_front();
@@ -137,9 +162,9 @@ class SizeClassAllocator32 {
NOINLINE void DeallocateBatch(AllocatorStats *stat, uptr class_id,
TransferBatch *b) {
CHECK_LT(class_id, kNumClasses);
+ CHECK_GT(b->Count(), 0);
SizeClassInfo *sci = GetSizeClassInfo(class_id);
SpinMutexLock l(&sci->mutex);
- CHECK_GT(b->Count(), 0);
sci->free_list.push_front(b);
}
@@ -227,10 +252,6 @@ class SizeClassAllocator32 {
return 0;
}
- // This is empty here. Currently only implemented in 64-bit allocator.
- void ReleaseToOS() { }
-
-
typedef SizeClassMap SizeClassMapT;
static const uptr kNumClasses = SizeClassMap::kNumClasses;
@@ -258,11 +279,13 @@ class SizeClassAllocator32 {
uptr AllocateRegion(AllocatorStats *stat, uptr class_id) {
CHECK_LT(class_id, kNumClasses);
- uptr res = reinterpret_cast<uptr>(MmapAlignedOrDie(kRegionSize, kRegionSize,
- "SizeClassAllocator32"));
+ uptr res = reinterpret_cast<uptr>(MmapAlignedOrDieOnFatalError(
+ kRegionSize, kRegionSize, "SizeClassAllocator32"));
+ if (UNLIKELY(!res))
+ return 0;
MapUnmapCallback().OnMap(res, kRegionSize);
stat->Add(AllocatorStatMapped, kRegionSize);
- CHECK_EQ(0U, (res & (kRegionSize - 1)));
+ CHECK(IsAligned(res, kRegionSize));
possible_regions.set(ComputeRegionId(res), static_cast<u8>(class_id));
return res;
}
@@ -272,21 +295,25 @@ class SizeClassAllocator32 {
return &size_class_info_array[class_id];
}
- void PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
+ bool PopulateFreeList(AllocatorStats *stat, AllocatorCache *c,
SizeClassInfo *sci, uptr class_id) {
uptr size = ClassIdToSize(class_id);
uptr reg = AllocateRegion(stat, class_id);
+ if (UNLIKELY(!reg))
+ return false;
uptr n_chunks = kRegionSize / (size + kMetadataSize);
uptr max_count = TransferBatch::MaxCached(class_id);
+ CHECK_GT(max_count, 0);
TransferBatch *b = nullptr;
for (uptr i = reg; i < reg + n_chunks * size; i += size) {
if (!b) {
b = c->CreateBatch(class_id, this, (TransferBatch*)i);
+ if (UNLIKELY(!b))
+ return false;
b->Clear();
}
b->Add((void*)i);
if (b->Count() == max_count) {
- CHECK_GT(b->Count(), 0);
sci->free_list.push_back(b);
b = nullptr;
}
@@ -295,6 +322,7 @@ class SizeClassAllocator32 {
CHECK_GT(b->Count(), 0);
sci->free_list.push_back(b);
}
+ return true;
}
ByteMap possible_regions;
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
index 620639a..4ae59c8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_primary64.h
@@ -60,14 +60,14 @@ class SizeClassAllocator64 {
// as a 4-byte integer (offset from the region start shifted right by 4).
typedef u32 CompactPtrT;
static const uptr kCompactPtrScale = 4;
- CompactPtrT PointerToCompactPtr(uptr base, uptr ptr) {
+ CompactPtrT PointerToCompactPtr(uptr base, uptr ptr) const {
return static_cast<CompactPtrT>((ptr - base) >> kCompactPtrScale);
}
- uptr CompactPtrToPointer(uptr base, CompactPtrT ptr32) {
+ uptr CompactPtrToPointer(uptr base, CompactPtrT ptr32) const {
return base + (static_cast<uptr>(ptr32) << kCompactPtrScale);
}
- void Init() {
+ void Init(s32 release_to_os_interval_ms) {
uptr TotalSpaceSize = kSpaceSize + AdditionalSize();
if (kUsingConstantSpaceBeg) {
CHECK_EQ(kSpaceBeg, reinterpret_cast<uptr>(
@@ -77,17 +77,17 @@ class SizeClassAllocator64 {
reinterpret_cast<uptr>(MmapNoAccess(TotalSpaceSize));
CHECK_NE(NonConstSpaceBeg, ~(uptr)0);
}
- MapWithCallback(SpaceEnd(), AdditionalSize());
+ SetReleaseToOSIntervalMs(release_to_os_interval_ms);
+ MapWithCallbackOrDie(SpaceEnd(), AdditionalSize());
}
- void MapWithCallback(uptr beg, uptr size) {
- CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
- MapUnmapCallback().OnMap(beg, size);
+ s32 ReleaseToOSIntervalMs() const {
+ return atomic_load(&release_to_os_interval_ms_, memory_order_relaxed);
}
- void UnmapWithCallback(uptr beg, uptr size) {
- MapUnmapCallback().OnUnmap(beg, size);
- UnmapOrDie(reinterpret_cast<void *>(beg), size);
+ void SetReleaseToOSIntervalMs(s32 release_to_os_interval_ms) {
+ atomic_store(&release_to_os_interval_ms_, release_to_os_interval_ms,
+ memory_order_relaxed);
}
static bool CanAllocate(uptr size, uptr alignment) {
@@ -104,14 +104,20 @@ class SizeClassAllocator64 {
BlockingMutexLock l(&region->mutex);
uptr old_num_chunks = region->num_freed_chunks;
uptr new_num_freed_chunks = old_num_chunks + n_chunks;
- EnsureFreeArraySpace(region, region_beg, new_num_freed_chunks);
+ // Failure to allocate free array space while releasing memory is non
+ // recoverable.
+ if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg,
+ new_num_freed_chunks)))
+ DieOnFailure::OnOOM();
for (uptr i = 0; i < n_chunks; i++)
free_array[old_num_chunks + i] = chunks[i];
region->num_freed_chunks = new_num_freed_chunks;
- region->n_freed += n_chunks;
+ region->stats.n_freed += n_chunks;
+
+ MaybeReleaseToOS(class_id);
}
- NOINLINE void GetFromAllocator(AllocatorStats *stat, uptr class_id,
+ NOINLINE bool GetFromAllocator(AllocatorStats *stat, uptr class_id,
CompactPtrT *chunks, uptr n_chunks) {
RegionInfo *region = GetRegionInfo(class_id);
uptr region_beg = GetRegionBeginBySizeClass(class_id);
@@ -119,18 +125,19 @@ class SizeClassAllocator64 {
BlockingMutexLock l(&region->mutex);
if (UNLIKELY(region->num_freed_chunks < n_chunks)) {
- PopulateFreeArray(stat, class_id, region,
- n_chunks - region->num_freed_chunks);
+ if (UNLIKELY(!PopulateFreeArray(stat, class_id, region,
+ n_chunks - region->num_freed_chunks)))
+ return false;
CHECK_GE(region->num_freed_chunks, n_chunks);
}
region->num_freed_chunks -= n_chunks;
uptr base_idx = region->num_freed_chunks;
for (uptr i = 0; i < n_chunks; i++)
chunks[i] = free_array[base_idx + i];
- region->n_allocated += n_chunks;
+ region->stats.n_allocated += n_chunks;
+ return true;
}
-
bool PointerIsMine(const void *p) {
uptr P = reinterpret_cast<uptr>(p);
if (kUsingConstantSpaceBeg && (kSpaceBeg % kSpaceSize) == 0)
@@ -146,7 +153,7 @@ class SizeClassAllocator64 {
space_beg;
}
- uptr GetRegionBeginBySizeClass(uptr class_id) {
+ uptr GetRegionBeginBySizeClass(uptr class_id) const {
return SpaceBeg() + kRegionSize * class_id;
}
@@ -197,7 +204,7 @@ class SizeClassAllocator64 {
// Test-only.
void TestOnlyUnmap() {
- UnmapWithCallback(SpaceBeg(), kSpaceSize + AdditionalSize());
+ UnmapWithCallbackOrDie(SpaceBeg(), kSpaceSize + AdditionalSize());
}
static void FillMemoryProfile(uptr start, uptr rss, bool file, uptr *stats,
@@ -210,16 +217,18 @@ class SizeClassAllocator64 {
void PrintStats(uptr class_id, uptr rss) {
RegionInfo *region = GetRegionInfo(class_id);
if (region->mapped_user == 0) return;
- uptr in_use = region->n_allocated - region->n_freed;
+ uptr in_use = region->stats.n_allocated - region->stats.n_freed;
uptr avail_chunks = region->allocated_user / ClassIdToSize(class_id);
Printf(
- " %02zd (%zd): mapped: %zdK allocs: %zd frees: %zd inuse: %zd "
- "num_freed_chunks %zd"
- " avail: %zd rss: %zdK releases: %zd\n",
- class_id, ClassIdToSize(class_id), region->mapped_user >> 10,
- region->n_allocated, region->n_freed, in_use,
- region->num_freed_chunks, avail_chunks, rss >> 10,
- region->rtoi.num_releases);
+ "%s %02zd (%6zd): mapped: %6zdK allocs: %7zd frees: %7zd inuse: %6zd "
+ "num_freed_chunks %7zd avail: %6zd rss: %6zdK releases: %6zd "
+ "last released: %6zdK region: 0x%zx\n",
+ region->exhausted ? "F" : " ", class_id, ClassIdToSize(class_id),
+ region->mapped_user >> 10, region->stats.n_allocated,
+ region->stats.n_freed, in_use, region->num_freed_chunks, avail_chunks,
+ rss >> 10, region->rtoi.num_releases,
+ region->rtoi.last_released_bytes >> 10,
+ SpaceBeg() + kRegionSize * class_id);
}
void PrintStats() {
@@ -229,8 +238,8 @@ class SizeClassAllocator64 {
for (uptr class_id = 1; class_id < kNumClasses; class_id++) {
RegionInfo *region = GetRegionInfo(class_id);
total_mapped += region->mapped_user;
- n_allocated += region->n_allocated;
- n_freed += region->n_freed;
+ n_allocated += region->stats.n_allocated;
+ n_freed += region->stats.n_freed;
}
Printf("Stats: SizeClassAllocator64: %zdM mapped in %zd allocations; "
"remains %zd\n",
@@ -282,16 +291,244 @@ class SizeClassAllocator64 {
GetPageSizeCached());
}
- void ReleaseToOS() {
- for (uptr class_id = 1; class_id < kNumClasses; class_id++)
- ReleaseToOS(class_id);
- }
-
typedef SizeClassMap SizeClassMapT;
static const uptr kNumClasses = SizeClassMap::kNumClasses;
static const uptr kNumClassesRounded = SizeClassMap::kNumClassesRounded;
+ // A packed array of counters. Each counter occupies 2^n bits, enough to store
+ // counter's max_value. Ctor will try to allocate the required buffer via
+ // mapper->MapPackedCounterArrayBuffer and the caller is expected to check
+ // whether the initialization was successful by checking IsAllocated() result.
+ // For the performance sake, none of the accessors check the validity of the
+ // arguments, it is assumed that index is always in [0, n) range and the value
+ // is not incremented past max_value.
+ template<class MemoryMapperT>
+ class PackedCounterArray {
+ public:
+ PackedCounterArray(u64 num_counters, u64 max_value, MemoryMapperT *mapper)
+ : n(num_counters), memory_mapper(mapper) {
+ CHECK_GT(num_counters, 0);
+ CHECK_GT(max_value, 0);
+ constexpr u64 kMaxCounterBits = sizeof(*buffer) * 8ULL;
+ // Rounding counter storage size up to the power of two allows for using
+ // bit shifts calculating particular counter's index and offset.
+ uptr counter_size_bits =
+ RoundUpToPowerOfTwo(MostSignificantSetBitIndex(max_value) + 1);
+ CHECK_LE(counter_size_bits, kMaxCounterBits);
+ counter_size_bits_log = Log2(counter_size_bits);
+ counter_mask = ~0ULL >> (kMaxCounterBits - counter_size_bits);
+
+ uptr packing_ratio = kMaxCounterBits >> counter_size_bits_log;
+ CHECK_GT(packing_ratio, 0);
+ packing_ratio_log = Log2(packing_ratio);
+ bit_offset_mask = packing_ratio - 1;
+
+ buffer_size =
+ (RoundUpTo(n, 1ULL << packing_ratio_log) >> packing_ratio_log) *
+ sizeof(*buffer);
+ buffer = reinterpret_cast<u64*>(
+ memory_mapper->MapPackedCounterArrayBuffer(buffer_size));
+ }
+ ~PackedCounterArray() {
+ if (buffer) {
+ memory_mapper->UnmapPackedCounterArrayBuffer(
+ reinterpret_cast<uptr>(buffer), buffer_size);
+ }
+ }
+
+ bool IsAllocated() const {
+ return !!buffer;
+ }
+
+ u64 GetCount() const {
+ return n;
+ }
+
+ uptr Get(uptr i) const {
+ DCHECK_LT(i, n);
+ uptr index = i >> packing_ratio_log;
+ uptr bit_offset = (i & bit_offset_mask) << counter_size_bits_log;
+ return (buffer[index] >> bit_offset) & counter_mask;
+ }
+
+ void Inc(uptr i) const {
+ DCHECK_LT(Get(i), counter_mask);
+ uptr index = i >> packing_ratio_log;
+ uptr bit_offset = (i & bit_offset_mask) << counter_size_bits_log;
+ buffer[index] += 1ULL << bit_offset;
+ }
+
+ void IncRange(uptr from, uptr to) const {
+ DCHECK_LE(from, to);
+ for (uptr i = from; i <= to; i++)
+ Inc(i);
+ }
+
+ private:
+ const u64 n;
+ u64 counter_size_bits_log;
+ u64 counter_mask;
+ u64 packing_ratio_log;
+ u64 bit_offset_mask;
+
+ MemoryMapperT* const memory_mapper;
+ u64 buffer_size;
+ u64* buffer;
+ };
+
+ template<class MemoryMapperT>
+ class FreePagesRangeTracker {
+ public:
+ explicit FreePagesRangeTracker(MemoryMapperT* mapper)
+ : memory_mapper(mapper),
+ page_size_scaled_log(Log2(GetPageSizeCached() >> kCompactPtrScale)),
+ in_the_range(false), current_page(0), current_range_start_page(0) {}
+
+ void NextPage(bool freed) {
+ if (freed) {
+ if (!in_the_range) {
+ current_range_start_page = current_page;
+ in_the_range = true;
+ }
+ } else {
+ CloseOpenedRange();
+ }
+ current_page++;
+ }
+
+ void Done() {
+ CloseOpenedRange();
+ }
+
+ private:
+ void CloseOpenedRange() {
+ if (in_the_range) {
+ memory_mapper->ReleasePageRangeToOS(
+ current_range_start_page << page_size_scaled_log,
+ current_page << page_size_scaled_log);
+ in_the_range = false;
+ }
+ }
+
+ MemoryMapperT* const memory_mapper;
+ const uptr page_size_scaled_log;
+ bool in_the_range;
+ uptr current_page;
+ uptr current_range_start_page;
+ };
+
+ // Iterates over the free_array to identify memory pages containing freed
+ // chunks only and returns these pages back to OS.
+ // allocated_pages_count is the total number of pages allocated for the
+ // current bucket.
+ template<class MemoryMapperT>
+ static void ReleaseFreeMemoryToOS(CompactPtrT *free_array,
+ uptr free_array_count, uptr chunk_size,
+ uptr allocated_pages_count,
+ MemoryMapperT *memory_mapper) {
+ const uptr page_size = GetPageSizeCached();
+
+ // Figure out the number of chunks per page and whether we can take a fast
+ // path (the number of chunks per page is the same for all pages).
+ uptr full_pages_chunk_count_max;
+ bool same_chunk_count_per_page;
+ if (chunk_size <= page_size && page_size % chunk_size == 0) {
+ // Same number of chunks per page, no cross overs.
+ full_pages_chunk_count_max = page_size / chunk_size;
+ same_chunk_count_per_page = true;
+ } else if (chunk_size <= page_size && page_size % chunk_size != 0 &&
+ chunk_size % (page_size % chunk_size) == 0) {
+ // Some chunks are crossing page boundaries, which means that the page
+ // contains one or two partial chunks, but all pages contain the same
+ // number of chunks.
+ full_pages_chunk_count_max = page_size / chunk_size + 1;
+ same_chunk_count_per_page = true;
+ } else if (chunk_size <= page_size) {
+ // Some chunks are crossing page boundaries, which means that the page
+ // contains one or two partial chunks.
+ full_pages_chunk_count_max = page_size / chunk_size + 2;
+ same_chunk_count_per_page = false;
+ } else if (chunk_size > page_size && chunk_size % page_size == 0) {
+ // One chunk covers multiple pages, no cross overs.
+ full_pages_chunk_count_max = 1;
+ same_chunk_count_per_page = true;
+ } else if (chunk_size > page_size) {
+ // One chunk covers multiple pages, Some chunks are crossing page
+ // boundaries. Some pages contain one chunk, some contain two.
+ full_pages_chunk_count_max = 2;
+ same_chunk_count_per_page = false;
+ } else {
+ UNREACHABLE("All chunk_size/page_size ratios must be handled.");
+ }
+
+ PackedCounterArray<MemoryMapperT> counters(allocated_pages_count,
+ full_pages_chunk_count_max,
+ memory_mapper);
+ if (!counters.IsAllocated())
+ return;
+
+ const uptr chunk_size_scaled = chunk_size >> kCompactPtrScale;
+ const uptr page_size_scaled = page_size >> kCompactPtrScale;
+ const uptr page_size_scaled_log = Log2(page_size_scaled);
+
+ // Iterate over free chunks and count how many free chunks affect each
+ // allocated page.
+ if (chunk_size <= page_size && page_size % chunk_size == 0) {
+ // Each chunk affects one page only.
+ for (uptr i = 0; i < free_array_count; i++)
+ counters.Inc(free_array[i] >> page_size_scaled_log);
+ } else {
+ // In all other cases chunks might affect more than one page.
+ for (uptr i = 0; i < free_array_count; i++) {
+ counters.IncRange(
+ free_array[i] >> page_size_scaled_log,
+ (free_array[i] + chunk_size_scaled - 1) >> page_size_scaled_log);
+ }
+ }
+
+ // Iterate over pages detecting ranges of pages with chunk counters equal
+ // to the expected number of chunks for the particular page.
+ FreePagesRangeTracker<MemoryMapperT> range_tracker(memory_mapper);
+ if (same_chunk_count_per_page) {
+ // Fast path, every page has the same number of chunks affecting it.
+ for (uptr i = 0; i < counters.GetCount(); i++)
+ range_tracker.NextPage(counters.Get(i) == full_pages_chunk_count_max);
+ } else {
+ // Show path, go through the pages keeping count how many chunks affect
+ // each page.
+ const uptr pn =
+ chunk_size < page_size ? page_size_scaled / chunk_size_scaled : 1;
+ const uptr pnc = pn * chunk_size_scaled;
+ // The idea is to increment the current page pointer by the first chunk
+ // size, middle portion size (the portion of the page covered by chunks
+ // except the first and the last one) and then the last chunk size, adding
+ // up the number of chunks on the current page and checking on every step
+ // whether the page boundary was crossed.
+ uptr prev_page_boundary = 0;
+ uptr current_boundary = 0;
+ for (uptr i = 0; i < counters.GetCount(); i++) {
+ uptr page_boundary = prev_page_boundary + page_size_scaled;
+ uptr chunks_per_page = pn;
+ if (current_boundary < page_boundary) {
+ if (current_boundary > prev_page_boundary)
+ chunks_per_page++;
+ current_boundary += pnc;
+ if (current_boundary < page_boundary) {
+ chunks_per_page++;
+ current_boundary += chunk_size_scaled;
+ }
+ }
+ prev_page_boundary = page_boundary;
+
+ range_tracker.NextPage(counters.Get(i) == chunks_per_page);
+ }
+ }
+ range_tracker.Done();
+ }
+
private:
+ friend class MemoryMapper;
+
static const uptr kRegionSize = kSpaceSize / kNumClassesRounded;
// FreeArray is the array of free-d chunks (stored as 4-byte offsets).
// In the worst case it may reguire kRegionSize/SizeClassMap::kMinSize
@@ -315,12 +552,19 @@ class SizeClassAllocator64 {
static const uptr kMetaMapSize = 1 << 16;
// Call mmap for free array memory with at least this size.
static const uptr kFreeArrayMapSize = 1 << 16;
- // Granularity of ReleaseToOs (aka madvise).
- static const uptr kReleaseToOsGranularity = 1 << 12;
+
+ atomic_sint32_t release_to_os_interval_ms_;
+
+ struct Stats {
+ uptr n_allocated;
+ uptr n_freed;
+ };
struct ReleaseToOsInfo {
uptr n_freed_at_last_release;
uptr num_releases;
+ u64 last_release_at_ns;
+ u64 last_released_bytes;
};
struct RegionInfo {
@@ -331,8 +575,9 @@ class SizeClassAllocator64 {
uptr allocated_meta; // Bytes allocated for metadata.
uptr mapped_user; // Bytes mapped for user memory.
uptr mapped_meta; // Bytes mapped for metadata.
- u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks.
- uptr n_allocated, n_freed; // Just stats.
+ u32 rand_state; // Seed for random shuffle, used if kRandomShuffleChunks.
+ bool exhausted; // Whether region is out of space for new chunks.
+ Stats stats;
ReleaseToOsInfo rtoi;
};
COMPILER_CHECK(sizeof(RegionInfo) >= kCacheLineSize);
@@ -349,18 +594,18 @@ class SizeClassAllocator64 {
Swap(a[i], a[RandN(rand_state, i + 1)]);
}
- RegionInfo *GetRegionInfo(uptr class_id) {
+ RegionInfo *GetRegionInfo(uptr class_id) const {
CHECK_LT(class_id, kNumClasses);
RegionInfo *regions =
reinterpret_cast<RegionInfo *>(SpaceBeg() + kSpaceSize);
return &regions[class_id];
}
- uptr GetMetadataEnd(uptr region_beg) {
+ uptr GetMetadataEnd(uptr region_beg) const {
return region_beg + kRegionSize - kFreeArraySize;
}
- uptr GetChunkIdx(uptr chunk, uptr size) {
+ uptr GetChunkIdx(uptr chunk, uptr size) const {
if (!kUsingConstantSpaceBeg)
chunk -= SpaceBeg();
@@ -372,132 +617,205 @@ class SizeClassAllocator64 {
return (u32)offset / (u32)size;
}
- CompactPtrT *GetFreeArray(uptr region_beg) {
- return reinterpret_cast<CompactPtrT *>(region_beg + kRegionSize -
- kFreeArraySize);
+ CompactPtrT *GetFreeArray(uptr region_beg) const {
+ return reinterpret_cast<CompactPtrT *>(GetMetadataEnd(region_beg));
}
- void EnsureFreeArraySpace(RegionInfo *region, uptr region_beg,
+ bool MapWithCallback(uptr beg, uptr size) {
+ uptr mapped = reinterpret_cast<uptr>(MmapFixedOrDieOnFatalError(beg, size));
+ if (UNLIKELY(!mapped))
+ return false;
+ CHECK_EQ(beg, mapped);
+ MapUnmapCallback().OnMap(beg, size);
+ return true;
+ }
+
+ void MapWithCallbackOrDie(uptr beg, uptr size) {
+ CHECK_EQ(beg, reinterpret_cast<uptr>(MmapFixedOrDie(beg, size)));
+ MapUnmapCallback().OnMap(beg, size);
+ }
+
+ void UnmapWithCallbackOrDie(uptr beg, uptr size) {
+ MapUnmapCallback().OnUnmap(beg, size);
+ UnmapOrDie(reinterpret_cast<void *>(beg), size);
+ }
+
+ bool EnsureFreeArraySpace(RegionInfo *region, uptr region_beg,
uptr num_freed_chunks) {
uptr needed_space = num_freed_chunks * sizeof(CompactPtrT);
if (region->mapped_free_array < needed_space) {
- CHECK_LE(needed_space, kFreeArraySize);
uptr new_mapped_free_array = RoundUpTo(needed_space, kFreeArrayMapSize);
+ CHECK_LE(new_mapped_free_array, kFreeArraySize);
uptr current_map_end = reinterpret_cast<uptr>(GetFreeArray(region_beg)) +
region->mapped_free_array;
uptr new_map_size = new_mapped_free_array - region->mapped_free_array;
- MapWithCallback(current_map_end, new_map_size);
+ if (UNLIKELY(!MapWithCallback(current_map_end, new_map_size)))
+ return false;
region->mapped_free_array = new_mapped_free_array;
}
+ return true;
}
-
- NOINLINE void PopulateFreeArray(AllocatorStats *stat, uptr class_id,
+ NOINLINE bool PopulateFreeArray(AllocatorStats *stat, uptr class_id,
RegionInfo *region, uptr requested_count) {
// region->mutex is held.
- uptr size = ClassIdToSize(class_id);
- uptr beg_idx = region->allocated_user;
- uptr end_idx = beg_idx + requested_count * size;
- uptr region_beg = GetRegionBeginBySizeClass(class_id);
- if (end_idx > region->mapped_user) {
+ const uptr size = ClassIdToSize(class_id);
+ const uptr new_space_beg = region->allocated_user;
+ const uptr new_space_end = new_space_beg + requested_count * size;
+ const uptr region_beg = GetRegionBeginBySizeClass(class_id);
+
+ // Map more space for chunks, if necessary.
+ if (new_space_end > region->mapped_user) {
if (!kUsingConstantSpaceBeg && region->mapped_user == 0)
region->rand_state = static_cast<u32>(region_beg >> 12); // From ASLR.
// Do the mmap for the user memory.
uptr map_size = kUserMapSize;
- while (end_idx > region->mapped_user + map_size)
+ while (new_space_end > region->mapped_user + map_size)
map_size += kUserMapSize;
- CHECK_GE(region->mapped_user + map_size, end_idx);
- MapWithCallback(region_beg + region->mapped_user, map_size);
+ CHECK_GE(region->mapped_user + map_size, new_space_end);
+ if (UNLIKELY(!MapWithCallback(region_beg + region->mapped_user,
+ map_size)))
+ return false;
stat->Add(AllocatorStatMapped, map_size);
region->mapped_user += map_size;
}
- CompactPtrT *free_array = GetFreeArray(region_beg);
- uptr total_count = (region->mapped_user - beg_idx) / size;
- uptr num_freed_chunks = region->num_freed_chunks;
- EnsureFreeArraySpace(region, region_beg, num_freed_chunks + total_count);
- for (uptr i = 0; i < total_count; i++) {
- uptr chunk = beg_idx + i * size;
- free_array[num_freed_chunks + total_count - 1 - i] =
- PointerToCompactPtr(0, chunk);
+ const uptr new_chunks_count = (region->mapped_user - new_space_beg) / size;
+
+ // Calculate the required space for metadata.
+ const uptr requested_allocated_meta =
+ region->allocated_meta + new_chunks_count * kMetadataSize;
+ uptr requested_mapped_meta = region->mapped_meta;
+ while (requested_allocated_meta > requested_mapped_meta)
+ requested_mapped_meta += kMetaMapSize;
+ // Check whether this size class is exhausted.
+ if (region->mapped_user + requested_mapped_meta >
+ kRegionSize - kFreeArraySize) {
+ if (!region->exhausted) {
+ region->exhausted = true;
+ Printf("%s: Out of memory. ", SanitizerToolName);
+ Printf("The process has exhausted %zuMB for size class %zu.\n",
+ kRegionSize >> 20, size);
+ }
+ return false;
+ }
+ // Map more space for metadata, if necessary.
+ if (requested_mapped_meta > region->mapped_meta) {
+ if (UNLIKELY(!MapWithCallback(
+ GetMetadataEnd(region_beg) - requested_mapped_meta,
+ requested_mapped_meta - region->mapped_meta)))
+ return false;
+ region->mapped_meta = requested_mapped_meta;
}
+
+ // If necessary, allocate more space for the free array and populate it with
+ // newly allocated chunks.
+ const uptr total_freed_chunks = region->num_freed_chunks + new_chunks_count;
+ if (UNLIKELY(!EnsureFreeArraySpace(region, region_beg, total_freed_chunks)))
+ return false;
+ CompactPtrT *free_array = GetFreeArray(region_beg);
+ for (uptr i = 0, chunk = new_space_beg; i < new_chunks_count;
+ i++, chunk += size)
+ free_array[total_freed_chunks - 1 - i] = PointerToCompactPtr(0, chunk);
if (kRandomShuffleChunks)
- RandomShuffle(&free_array[num_freed_chunks], total_count,
+ RandomShuffle(&free_array[region->num_freed_chunks], new_chunks_count,
&region->rand_state);
- region->num_freed_chunks += total_count;
- region->allocated_user += total_count * size;
- CHECK_LE(region->allocated_user, region->mapped_user);
- region->allocated_meta += total_count * kMetadataSize;
- if (region->allocated_meta > region->mapped_meta) {
- uptr map_size = kMetaMapSize;
- while (region->allocated_meta > region->mapped_meta + map_size)
- map_size += kMetaMapSize;
- // Do the mmap for the metadata.
- CHECK_GE(region->mapped_meta + map_size, region->allocated_meta);
- MapWithCallback(GetMetadataEnd(region_beg) -
- region->mapped_meta - map_size, map_size);
- region->mapped_meta += map_size;
- }
+ // All necessary memory is mapped and now it is safe to advance all
+ // 'allocated_*' counters.
+ region->num_freed_chunks += new_chunks_count;
+ region->allocated_user += new_chunks_count * size;
+ CHECK_LE(region->allocated_user, region->mapped_user);
+ region->allocated_meta = requested_allocated_meta;
CHECK_LE(region->allocated_meta, region->mapped_meta);
- if (region->mapped_user + region->mapped_meta >
- kRegionSize - kFreeArraySize) {
- Printf("%s: Out of memory. Dying. ", SanitizerToolName);
- Printf("The process has exhausted %zuMB for size class %zu.\n",
- kRegionSize / 1024 / 1024, size);
- Die();
- }
- }
+ region->exhausted = false;
+
+ // TODO(alekseyshl): Consider bumping last_release_at_ns here to prevent
+ // MaybeReleaseToOS from releasing just allocated pages or protect these
+ // not yet used chunks some other way.
- bool MaybeReleaseChunkRange(uptr region_beg, uptr chunk_size,
- CompactPtrT first, CompactPtrT last) {
- uptr beg_ptr = CompactPtrToPointer(region_beg, first);
- uptr end_ptr = CompactPtrToPointer(region_beg, last) + chunk_size;
- CHECK_GE(end_ptr - beg_ptr, kReleaseToOsGranularity);
- beg_ptr = RoundUpTo(beg_ptr, kReleaseToOsGranularity);
- end_ptr = RoundDownTo(end_ptr, kReleaseToOsGranularity);
- if (end_ptr == beg_ptr) return false;
- ReleaseMemoryToOS(beg_ptr, end_ptr - beg_ptr);
return true;
}
- // Releases some RAM back to OS.
- // Algorithm:
- // * Lock the region.
- // * Sort the chunks.
- // * Find ranges fully covered by free-d chunks
- // * Release them to OS with madvise.
- //
- // TODO(kcc): make sure we don't do it too frequently.
- void ReleaseToOS(uptr class_id) {
+ class MemoryMapper {
+ public:
+ MemoryMapper(const ThisT& base_allocator, uptr class_id)
+ : allocator(base_allocator),
+ region_base(base_allocator.GetRegionBeginBySizeClass(class_id)),
+ released_ranges_count(0),
+ released_bytes(0) {
+ }
+
+ uptr GetReleasedRangesCount() const {
+ return released_ranges_count;
+ }
+
+ uptr GetReleasedBytes() const {
+ return released_bytes;
+ }
+
+ uptr MapPackedCounterArrayBuffer(uptr buffer_size) {
+ // TODO(alekseyshl): The idea to explore is to check if we have enough
+ // space between num_freed_chunks*sizeof(CompactPtrT) and
+ // mapped_free_array to fit buffer_size bytes and use that space instead
+ // of mapping a temporary one.
+ return reinterpret_cast<uptr>(
+ MmapOrDieOnFatalError(buffer_size, "ReleaseToOSPageCounters"));
+ }
+
+ void UnmapPackedCounterArrayBuffer(uptr buffer, uptr buffer_size) {
+ UnmapOrDie(reinterpret_cast<void *>(buffer), buffer_size);
+ }
+
+ // Releases [from, to) range of pages back to OS.
+ void ReleasePageRangeToOS(CompactPtrT from, CompactPtrT to) {
+ const uptr from_page = allocator.CompactPtrToPointer(region_base, from);
+ const uptr to_page = allocator.CompactPtrToPointer(region_base, to);
+ ReleaseMemoryPagesToOS(from_page, to_page);
+ released_ranges_count++;
+ released_bytes += to_page - from_page;
+ }
+
+ private:
+ const ThisT& allocator;
+ const uptr region_base;
+ uptr released_ranges_count;
+ uptr released_bytes;
+ };
+
+ // Attempts to release RAM occupied by freed chunks back to OS. The region is
+ // expected to be locked.
+ void MaybeReleaseToOS(uptr class_id) {
RegionInfo *region = GetRegionInfo(class_id);
- uptr region_beg = GetRegionBeginBySizeClass(class_id);
- CompactPtrT *free_array = GetFreeArray(region_beg);
- uptr chunk_size = ClassIdToSize(class_id);
- uptr scaled_chunk_size = chunk_size >> kCompactPtrScale;
- const uptr kScaledGranularity = kReleaseToOsGranularity >> kCompactPtrScale;
- BlockingMutexLock l(&region->mutex);
+ const uptr chunk_size = ClassIdToSize(class_id);
+ const uptr page_size = GetPageSizeCached();
+
uptr n = region->num_freed_chunks;
- if (n * chunk_size < kReleaseToOsGranularity)
- return; // No chance to release anything.
- if ((region->rtoi.n_freed_at_last_release - region->n_freed) * chunk_size <
- kReleaseToOsGranularity)
+ if (n * chunk_size < page_size)
+ return; // No chance to release anything.
+ if ((region->stats.n_freed -
+ region->rtoi.n_freed_at_last_release) * chunk_size < page_size) {
return; // Nothing new to release.
- SortArray(free_array, n);
- uptr beg = free_array[0];
- uptr prev = free_array[0];
- for (uptr i = 1; i < n; i++) {
- uptr chunk = free_array[i];
- CHECK_GT(chunk, prev);
- if (chunk - prev != scaled_chunk_size) {
- CHECK_GT(chunk - prev, scaled_chunk_size);
- if (prev + scaled_chunk_size - beg >= kScaledGranularity) {
- MaybeReleaseChunkRange(region_beg, chunk_size, beg, prev);
- region->rtoi.n_freed_at_last_release = region->n_freed;
- region->rtoi.num_releases++;
- }
- beg = chunk;
- }
- prev = chunk;
}
+
+ s32 interval_ms = ReleaseToOSIntervalMs();
+ if (interval_ms < 0)
+ return;
+
+ if (region->rtoi.last_release_at_ns + interval_ms * 1000000ULL > NanoTime())
+ return; // Memory was returned recently.
+
+ MemoryMapper memory_mapper(*this, class_id);
+
+ ReleaseFreeMemoryToOS<MemoryMapper>(
+ GetFreeArray(GetRegionBeginBySizeClass(class_id)), n, chunk_size,
+ RoundUpTo(region->allocated_user, page_size) / page_size,
+ &memory_mapper);
+
+ if (memory_mapper.GetReleasedRangesCount() > 0) {
+ region->rtoi.n_freed_at_last_release = region->stats.n_freed;
+ region->rtoi.num_releases += memory_mapper.GetReleasedRangesCount();
+ region->rtoi.last_released_bytes = memory_mapper.GetReleasedBytes();
+ }
+ region->rtoi.last_release_at_ns = NanoTime();
}
};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h
index 91c2ecc..9a9b83a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_secondary.h
@@ -15,17 +15,19 @@
// This class can (de)allocate only large chunks of memory using mmap/unmap.
// The main purpose of this allocator is to cover large and rare allocation
// sizes not covered by more efficient allocators (e.g. SizeClassAllocator64).
-template <class MapUnmapCallback = NoOpMapUnmapCallback>
+template <class MapUnmapCallback = NoOpMapUnmapCallback,
+ class FailureHandlerT = ReturnNullOrDieOnFailure>
class LargeMmapAllocator {
public:
- void InitLinkerInitialized(bool may_return_null) {
+ typedef FailureHandlerT FailureHandler;
+
+ void InitLinkerInitialized() {
page_size_ = GetPageSizeCached();
- atomic_store(&may_return_null_, may_return_null, memory_order_relaxed);
}
- void Init(bool may_return_null) {
+ void Init() {
internal_memset(this, 0, sizeof(*this));
- InitLinkerInitialized(may_return_null);
+ InitLinkerInitialized();
}
void *Allocate(AllocatorStats *stat, uptr size, uptr alignment) {
@@ -34,9 +36,12 @@ class LargeMmapAllocator {
if (alignment > page_size_)
map_size += alignment;
// Overflow.
- if (map_size < size) return ReturnNullOrDieOnBadRequest();
+ if (map_size < size)
+ return FailureHandler::OnBadRequest();
uptr map_beg = reinterpret_cast<uptr>(
- MmapOrDie(map_size, "LargeMmapAllocator"));
+ MmapOrDieOnFatalError(map_size, "LargeMmapAllocator"));
+ if (!map_beg)
+ return FailureHandler::OnOOM();
CHECK(IsAligned(map_beg, page_size_));
MapUnmapCallback().OnMap(map_beg, map_size);
uptr map_end = map_beg + map_size;
@@ -70,24 +75,6 @@ class LargeMmapAllocator {
return reinterpret_cast<void*>(res);
}
- bool MayReturnNull() const {
- return atomic_load(&may_return_null_, memory_order_acquire);
- }
-
- void *ReturnNullOrDieOnBadRequest() {
- if (MayReturnNull()) return nullptr;
- ReportAllocatorCannotReturnNull(false);
- }
-
- void *ReturnNullOrDieOnOOM() {
- if (MayReturnNull()) return nullptr;
- ReportAllocatorCannotReturnNull(true);
- }
-
- void SetMayReturnNull(bool may_return_null) {
- atomic_store(&may_return_null_, may_return_null, memory_order_release);
- }
-
void Deallocate(AllocatorStats *stat, void *p) {
Header *h = GetHeader(p);
{
@@ -159,6 +146,14 @@ class LargeMmapAllocator {
return GetUser(h);
}
+ void EnsureSortedChunks() {
+ if (chunks_sorted_) return;
+ SortArray(reinterpret_cast<uptr*>(chunks_), n_chunks_);
+ for (uptr i = 0; i < n_chunks_; i++)
+ chunks_[i]->chunk_idx = i;
+ chunks_sorted_ = true;
+ }
+
// This function does the same as GetBlockBegin, but is much faster.
// Must be called with the allocator locked.
void *GetBlockBeginFastLocked(void *ptr) {
@@ -166,16 +161,10 @@ class LargeMmapAllocator {
uptr p = reinterpret_cast<uptr>(ptr);
uptr n = n_chunks_;
if (!n) return nullptr;
- if (!chunks_sorted_) {
- // Do one-time sort. chunks_sorted_ is reset in Allocate/Deallocate.
- SortArray(reinterpret_cast<uptr*>(chunks_), n);
- for (uptr i = 0; i < n; i++)
- chunks_[i]->chunk_idx = i;
- chunks_sorted_ = true;
- min_mmap_ = reinterpret_cast<uptr>(chunks_[0]);
- max_mmap_ = reinterpret_cast<uptr>(chunks_[n - 1]) +
- chunks_[n - 1]->map_size;
- }
+ EnsureSortedChunks();
+ auto min_mmap_ = reinterpret_cast<uptr>(chunks_[0]);
+ auto max_mmap_ =
+ reinterpret_cast<uptr>(chunks_[n - 1]) + chunks_[n - 1]->map_size;
if (p < min_mmap_ || p >= max_mmap_)
return nullptr;
uptr beg = 0, end = n - 1;
@@ -228,8 +217,14 @@ class LargeMmapAllocator {
// Iterate over all existing chunks.
// The allocator must be locked when calling this function.
void ForEachChunk(ForEachChunkCallback callback, void *arg) {
- for (uptr i = 0; i < n_chunks_; i++)
+ EnsureSortedChunks(); // Avoid doing the sort while iterating.
+ for (uptr i = 0; i < n_chunks_; i++) {
+ auto t = chunks_[i];
callback(reinterpret_cast<uptr>(GetUser(chunks_[i])), arg);
+ // Consistency check: verify that the array did not change.
+ CHECK_EQ(chunks_[i], t);
+ CHECK_EQ(chunks_[i]->chunk_idx, i);
+ }
}
private:
@@ -261,11 +256,9 @@ class LargeMmapAllocator {
uptr page_size_;
Header *chunks_[kMaxNumChunks];
uptr n_chunks_;
- uptr min_mmap_, max_mmap_;
bool chunks_sorted_;
struct Stats {
uptr n_allocs, n_frees, currently_allocated, max_allocated, by_size_log[64];
} stats;
- atomic_uint8_t may_return_null_;
SpinMutex mutex_;
};
diff --git a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
index 4cda021..19af551 100644
--- a/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
+++ b/libsanitizer/sanitizer_common/sanitizer_allocator_size_class_map.h
@@ -132,8 +132,9 @@ class SizeClassMap {
static const uptr kMaxSize = 1UL << kMaxSizeLog;
static const uptr kNumClasses =
- kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1;
+ kMidClass + ((kMaxSizeLog - kMidSizeLog) << S) + 1 + 1;
static const uptr kLargestClassID = kNumClasses - 2;
+ static const uptr kBatchClassID = kNumClasses - 1;
COMPILER_CHECK(kNumClasses >= 16 && kNumClasses <= 256);
static const uptr kNumClassesRounded =
kNumClasses <= 32 ? 32 :
@@ -141,6 +142,11 @@ class SizeClassMap {
kNumClasses <= 128 ? 128 : 256;
static uptr Size(uptr class_id) {
+ // Estimate the result for kBatchClassID because this class does not know
+ // the exact size of TransferBatch. It's OK since we are using the actual
+ // sizeof(TransferBatch) where it matters.
+ if (UNLIKELY(class_id == kBatchClassID))
+ return kMaxNumCachedHint * sizeof(uptr);
if (class_id <= kMidClass)
return kMinSize * class_id;
class_id -= kMidClass;
@@ -149,9 +155,10 @@ class SizeClassMap {
}
static uptr ClassID(uptr size) {
+ if (UNLIKELY(size > kMaxSize))
+ return 0;
if (size <= kMidSize)
return (size + kMinSize - 1) >> kMinSizeLog;
- if (size > kMaxSize) return 0;
uptr l = MostSignificantSetBitIndex(size);
uptr hbits = (size >> (l - S)) & M;
uptr lbits = size & ((1 << (l - S)) - 1);
@@ -160,7 +167,13 @@ class SizeClassMap {
}
static uptr MaxCachedHint(uptr class_id) {
- if (class_id == 0) return 0;
+ // Estimate the result for kBatchClassID because this class does not know
+ // the exact size of TransferBatch. We need to cache fewer batches than user
+ // chunks, so this number can be small.
+ if (UNLIKELY(class_id == kBatchClassID))
+ return 16;
+ if (UNLIKELY(class_id == 0))
+ return 0;
uptr n = (1UL << kMaxBytesCachedLog) / Size(class_id);
return Max<uptr>(1, Min(kMaxNumCachedHint, n));
}
@@ -176,6 +189,8 @@ class SizeClassMap {
uptr p = prev_s ? (d * 100 / prev_s) : 0;
uptr l = s ? MostSignificantSetBitIndex(s) : 0;
uptr cached = MaxCachedHint(i) * s;
+ if (i == kBatchClassID)
+ d = p = l = 0;
Printf("c%02zd => s: %zd diff: +%zd %02zd%% l %zd "
"cached: %zd %zd; id %zd\n",
i, Size(i), d, p, l, MaxCachedHint(i), cached, ClassID(s));
@@ -190,12 +205,13 @@ class SizeClassMap {
// Printf("Validate: c%zd\n", c);
uptr s = Size(c);
CHECK_NE(s, 0U);
+ if (c == kBatchClassID)
+ continue;
CHECK_EQ(ClassID(s), c);
- if (c != kNumClasses - 1)
+ if (c < kLargestClassID)
CHECK_EQ(ClassID(s + 1), c + 1);
CHECK_EQ(ClassID(s - 1), c);
- if (c)
- CHECK_GT(Size(c), Size(c-1));
+ CHECK_GT(Size(c), Size(c - 1));
}
CHECK_EQ(ClassID(kMaxSize + 1), 0);
@@ -205,7 +221,7 @@ class SizeClassMap {
CHECK_LT(c, kNumClasses);
CHECK_GE(Size(c), s);
if (c > 0)
- CHECK_LT(Size(c-1), s);
+ CHECK_LT(Size(c - 1), s);
}
}
};
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic.h b/libsanitizer/sanitizer_common/sanitizer_atomic.h
index 4973b7d..82de0c6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_atomic.h
+++ b/libsanitizer/sanitizer_common/sanitizer_atomic.h
@@ -35,6 +35,11 @@ struct atomic_uint16_t {
volatile Type val_dont_use;
};
+struct atomic_sint32_t {
+ typedef s32 Type;
+ volatile Type val_dont_use;
+};
+
struct atomic_uint32_t {
typedef u32 Type;
volatile Type val_dont_use;
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
index c600999..dcdcd0e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
+++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang.h
@@ -69,16 +69,25 @@ INLINE typename T::Type atomic_exchange(volatile T *a,
return v;
}
-template<typename T>
-INLINE bool atomic_compare_exchange_strong(volatile T *a,
- typename T::Type *cmp,
+template <typename T>
+INLINE bool atomic_compare_exchange_strong(volatile T *a, typename T::Type *cmp,
typename T::Type xchg,
memory_order mo) {
typedef typename T::Type Type;
Type cmpv = *cmp;
- Type prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
- if (prev == cmpv)
- return true;
+ Type prev;
+#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
+ if (sizeof(*a) == 8) {
+ Type volatile *val_ptr = const_cast<Type volatile *>(&a->val_dont_use);
+ prev = __mips_sync_val_compare_and_swap<u64>(
+ reinterpret_cast<u64 volatile *>(val_ptr), (u64)cmpv, (u64)xchg);
+ } else {
+ prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
+ }
+#else
+ prev = __sync_val_compare_and_swap(&a->val_dont_use, cmpv, xchg);
+#endif
+ if (prev == cmpv) return true;
*cmp = prev;
return false;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h
index c66c099..a0605bb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h
+++ b/libsanitizer/sanitizer_common/sanitizer_atomic_clang_other.h
@@ -15,6 +15,56 @@
namespace __sanitizer {
+// MIPS32 does not support atomic > 4 bytes. To address this lack of
+// functionality, the sanitizer library provides helper methods which use an
+// internal spin lock mechanism to emulate atomic oprations when the size is
+// 8 bytes.
+#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
+static void __spin_lock(volatile int *lock) {
+ while (__sync_lock_test_and_set(lock, 1))
+ while (*lock) {
+ }
+}
+
+static void __spin_unlock(volatile int *lock) { __sync_lock_release(lock); }
+
+
+// Make sure the lock is on its own cache line to prevent false sharing.
+// Put it inside a struct that is aligned and padded to the typical MIPS
+// cacheline which is 32 bytes.
+static struct {
+ int lock;
+ char pad[32 - sizeof(int)];
+} __attribute__((aligned(32))) lock = {0};
+
+template <class T>
+T __mips_sync_fetch_and_add(volatile T *ptr, T val) {
+ T ret;
+
+ __spin_lock(&lock.lock);
+
+ ret = *ptr;
+ *ptr = ret + val;
+
+ __spin_unlock(&lock.lock);
+
+ return ret;
+}
+
+template <class T>
+T __mips_sync_val_compare_and_swap(volatile T *ptr, T oldval, T newval) {
+ T ret;
+ __spin_lock(&lock.lock);
+
+ ret = *ptr;
+ if (ret == oldval) *ptr = newval;
+
+ __spin_unlock(&lock.lock);
+
+ return ret;
+}
+#endif
+
INLINE void proc_yield(int cnt) {
__asm__ __volatile__("" ::: "memory");
}
@@ -51,8 +101,15 @@ INLINE typename T::Type atomic_load(
// 64-bit load on 32-bit platform.
// Gross, but simple and reliable.
// Assume that it is not in read-only memory.
+#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
+ typename T::Type volatile *val_ptr =
+ const_cast<typename T::Type volatile *>(&a->val_dont_use);
+ v = __mips_sync_fetch_and_add<u64>(
+ reinterpret_cast<u64 volatile *>(val_ptr), 0);
+#else
v = __sync_fetch_and_add(
const_cast<typename T::Type volatile *>(&a->val_dont_use), 0);
+#endif
}
return v;
}
@@ -82,7 +139,14 @@ INLINE void atomic_store(volatile T *a, typename T::Type v, memory_order mo) {
typename T::Type cmp = a->val_dont_use;
typename T::Type cur;
for (;;) {
+#if defined(_MIPS_SIM) && _MIPS_SIM == _ABIO32
+ typename T::Type volatile *val_ptr =
+ const_cast<typename T::Type volatile *>(&a->val_dont_use);
+ cur = __mips_sync_val_compare_and_swap<u64>(
+ reinterpret_cast<u64 volatile *>(val_ptr), (u64)cmp, (u64)v);
+#else
cur = __sync_val_compare_and_swap(&a->val_dont_use, cmp, v);
+#endif
if (cmp == v)
break;
cmp = cur;
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.cc b/libsanitizer/sanitizer_common/sanitizer_common.cc
index b445f61..8d7e9fa 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_common.cc
@@ -25,72 +25,6 @@ const char *SanitizerToolName = "SanitizerTool";
atomic_uint32_t current_verbosity;
uptr PageSizeCached;
-StaticSpinMutex report_file_mu;
-ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
-
-void RawWrite(const char *buffer) {
- report_file.Write(buffer, internal_strlen(buffer));
-}
-
-void ReportFile::ReopenIfNecessary() {
- mu->CheckLocked();
- if (fd == kStdoutFd || fd == kStderrFd) return;
-
- uptr pid = internal_getpid();
- // If in tracer, use the parent's file.
- if (pid == stoptheworld_tracer_pid)
- pid = stoptheworld_tracer_ppid;
- if (fd != kInvalidFd) {
- // If the report file is already opened by the current process,
- // do nothing. Otherwise the report file was opened by the parent
- // process, close it now.
- if (fd_pid == pid)
- return;
- else
- CloseFile(fd);
- }
-
- const char *exe_name = GetProcessName();
- if (common_flags()->log_exe_name && exe_name) {
- internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
- exe_name, pid);
- } else {
- internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
- }
- fd = OpenFile(full_path, WrOnly);
- if (fd == kInvalidFd) {
- const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
- WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
- WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
- Die();
- }
- fd_pid = pid;
-}
-
-void ReportFile::SetReportPath(const char *path) {
- if (!path)
- return;
- uptr len = internal_strlen(path);
- if (len > sizeof(path_prefix) - 100) {
- Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
- path[0], path[1], path[2], path[3],
- path[4], path[5], path[6], path[7]);
- Die();
- }
-
- SpinMutexLock l(mu);
- if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
- CloseFile(fd);
- fd = kInvalidFd;
- if (internal_strcmp(path, "stdout") == 0) {
- fd = kStdoutFd;
- } else if (internal_strcmp(path, "stderr") == 0) {
- fd = kStderrFd;
- } else {
- internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
- }
-}
-
// PID of the tracer task in StopTheWorld. It shares the address space with the
// main process, but has a different PID and thus requires special handling.
uptr stoptheworld_tracer_pid = 0;
@@ -98,6 +32,8 @@ uptr stoptheworld_tracer_pid = 0;
// writing to the same log file.
uptr stoptheworld_tracer_ppid = 0;
+StaticSpinMutex CommonSanitizerReportMutex;
+
void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
const char *mmap_type, error_t err,
bool raw_report) {
@@ -118,42 +54,6 @@ void NORETURN ReportMmapFailureAndDie(uptr size, const char *mem_type,
UNREACHABLE("unable to mmap");
}
-bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
- uptr *read_len, uptr max_len, error_t *errno_p) {
- uptr PageSize = GetPageSizeCached();
- uptr kMinFileLen = PageSize;
- *buff = nullptr;
- *buff_size = 0;
- *read_len = 0;
- // The files we usually open are not seekable, so try different buffer sizes.
- for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
- fd_t fd = OpenFile(file_name, RdOnly, errno_p);
- if (fd == kInvalidFd) return false;
- UnmapOrDie(*buff, *buff_size);
- *buff = (char*)MmapOrDie(size, __func__);
- *buff_size = size;
- *read_len = 0;
- // Read up to one page at a time.
- bool reached_eof = false;
- while (*read_len + PageSize <= size) {
- uptr just_read;
- if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) {
- UnmapOrDie(*buff, *buff_size);
- return false;
- }
- if (just_read == 0) {
- reached_eof = true;
- break;
- }
- *read_len += just_read;
- }
- CloseFile(fd);
- if (reached_eof) // We've read the whole file.
- break;
- }
- return true;
-}
-
typedef bool UptrComparisonFunction(const uptr &a, const uptr &b);
typedef bool U32ComparisonFunction(const u32 &a, const u32 &b);
@@ -197,23 +97,24 @@ const char *StripModuleName(const char *module) {
return module;
}
-void ReportErrorSummary(const char *error_message) {
+void ReportErrorSummary(const char *error_message, const char *alt_tool_name) {
if (!common_flags()->print_summary)
return;
InternalScopedString buff(kMaxSummaryLength);
- buff.append("SUMMARY: %s: %s", SanitizerToolName, error_message);
+ buff.append("SUMMARY: %s: %s",
+ alt_tool_name ? alt_tool_name : SanitizerToolName, error_message);
__sanitizer_report_error_summary(buff.data());
}
#if !SANITIZER_GO
-void ReportErrorSummary(const char *error_type, const AddressInfo &info) {
- if (!common_flags()->print_summary)
- return;
+void ReportErrorSummary(const char *error_type, const AddressInfo &info,
+ const char *alt_tool_name) {
+ if (!common_flags()->print_summary) return;
InternalScopedString buff(kMaxSummaryLength);
buff.append("%s ", error_type);
RenderFrame(&buff, "%L %F", 0, info, common_flags()->symbolize_vs_style,
common_flags()->strip_path_prefix);
- ReportErrorSummary(buff.data());
+ ReportErrorSummary(buff.data(), alt_tool_name);
}
#endif
@@ -257,9 +158,23 @@ void LoadedModule::set(const char *module_name, uptr base_address) {
base_address_ = base_address;
}
+void LoadedModule::set(const char *module_name, uptr base_address,
+ ModuleArch arch, u8 uuid[kModuleUUIDSize],
+ bool instrumented) {
+ set(module_name, base_address);
+ arch_ = arch;
+ internal_memcpy(uuid_, uuid, sizeof(uuid_));
+ instrumented_ = instrumented;
+}
+
void LoadedModule::clear() {
InternalFree(full_name_);
+ base_address_ = 0;
+ max_executable_address_ = 0;
full_name_ = nullptr;
+ arch_ = kModuleArchUnknown;
+ internal_memset(uuid_, 0, kModuleUUIDSize);
+ instrumented_ = false;
while (!ranges_.empty()) {
AddressRange *r = ranges_.front();
ranges_.pop_front();
@@ -267,10 +182,14 @@ void LoadedModule::clear() {
}
}
-void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable) {
+void LoadedModule::addAddressRange(uptr beg, uptr end, bool executable,
+ bool writable, const char *name) {
void *mem = InternalAlloc(sizeof(AddressRange));
- AddressRange *r = new(mem) AddressRange(beg, end, executable);
+ AddressRange *r =
+ new(mem) AddressRange(beg, end, executable, writable, name);
ranges_.push_back(r);
+ if (executable && end > max_executable_address_)
+ max_executable_address_ = end;
}
bool LoadedModule::containsAddress(uptr address) const {
@@ -339,36 +258,6 @@ bool TemplateMatch(const char *templ, const char *str) {
return true;
}
-static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
-
-char *FindPathToBinary(const char *name) {
- if (FileExists(name)) {
- return internal_strdup(name);
- }
-
- const char *path = GetEnv("PATH");
- if (!path)
- return nullptr;
- uptr name_len = internal_strlen(name);
- InternalScopedBuffer<char> buffer(kMaxPathLength);
- const char *beg = path;
- while (true) {
- const char *end = internal_strchrnul(beg, kPathSeparator);
- uptr prefix_len = end - beg;
- if (prefix_len + name_len + 2 <= kMaxPathLength) {
- internal_memcpy(buffer.data(), beg, prefix_len);
- buffer[prefix_len] = '/';
- internal_memcpy(&buffer[prefix_len + 1], name, name_len);
- buffer[prefix_len + 1 + name_len] = '\0';
- if (FileExists(buffer.data()))
- return internal_strdup(buffer.data());
- }
- if (*end == '\0') break;
- beg = end + 1;
- }
- return nullptr;
-}
-
static char binary_name_cache_str[kMaxPathLength];
static char process_name_cache_str[kMaxPathLength];
@@ -462,16 +351,8 @@ static int InstallMallocFreeHooks(void (*malloc_hook)(const void *, uptr),
using namespace __sanitizer; // NOLINT
extern "C" {
-void __sanitizer_set_report_path(const char *path) {
- report_file.SetReportPath(path);
-}
-
-void __sanitizer_set_report_fd(void *fd) {
- report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
- report_file.fd_pid = internal_getpid();
-}
-
-void __sanitizer_report_error_summary(const char *error_summary) {
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_report_error_summary,
+ const char *error_summary) {
Printf("%s\n", error_summary);
}
@@ -486,11 +367,4 @@ int __sanitizer_install_malloc_and_free_hooks(void (*malloc_hook)(const void *,
void (*free_hook)(const void *)) {
return InstallMallocFreeHooks(malloc_hook, free_hook);
}
-
-#if !SANITIZER_GO && !SANITIZER_SUPPORTS_WEAK_HOOKS
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_print_memory_profile(int top_percent) {
- (void)top_percent;
-}
-#endif
} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_common.h b/libsanitizer/sanitizer_common/sanitizer_common.h
index 3e079ab..dd207d7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common.h
+++ b/libsanitizer/sanitizer_common/sanitizer_common.h
@@ -27,8 +27,11 @@ extern "C" void _ReadWriteBarrier();
#endif
namespace __sanitizer {
-struct StackTrace;
+
struct AddressInfo;
+struct BufferedStackTrace;
+struct SignalContext;
+struct StackTrace;
// Constants.
const uptr kWordSize = SANITIZER_WORDSIZE / 8;
@@ -70,7 +73,7 @@ INLINE uptr GetPageSizeCached() {
uptr GetMmapGranularity();
uptr GetMaxVirtualAddress();
// Threads
-uptr GetTid();
+tid_t GetTid();
uptr GetThreadSelf();
void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
uptr *stack_bottom);
@@ -83,25 +86,36 @@ INLINE void *MmapOrDieQuietly(uptr size, const char *mem_type) {
return MmapOrDie(size, mem_type, /*raw_report*/ true);
}
void UnmapOrDie(void *addr, uptr size);
+// Behaves just like MmapOrDie, but tolerates out of memory condition, in that
+// case returns nullptr.
+void *MmapOrDieOnFatalError(uptr size, const char *mem_type);
void *MmapFixedNoReserve(uptr fixed_addr, uptr size,
const char *name = nullptr);
void *MmapNoReserveOrDie(uptr size, const char *mem_type);
void *MmapFixedOrDie(uptr fixed_addr, uptr size);
+// Behaves just like MmapFixedOrDie, but tolerates out of memory condition, in
+// that case returns nullptr.
+void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size);
void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name = nullptr);
void *MmapNoAccess(uptr size);
// Map aligned chunk of address space; size and alignment are powers of two.
-void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type);
+// Dies on all but out of memory errors, in the latter case returns nullptr.
+void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
+ const char *mem_type);
// Disallow access to a memory range. Use MmapFixedNoAccess to allocate an
// unaccessible memory.
bool MprotectNoAccess(uptr addr, uptr size);
bool MprotectReadOnly(uptr addr, uptr size);
// Find an available address space.
-uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding);
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
+ uptr *largest_gap_found);
// Used to check if we can map shadow memory to a fixed location.
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end);
-void ReleaseMemoryToOS(uptr addr, uptr size);
+// Releases memory pages entirely within the [beg, end] address range. Noop if
+// the provided range does not contain at least one entire page.
+void ReleaseMemoryPagesToOS(uptr beg, uptr end);
void IncreaseTotalMmap(uptr size);
void DecreaseTotalMmap(uptr size);
uptr GetRSS();
@@ -112,6 +126,14 @@ void CheckVMASize();
void RunMallocHooks(const void *ptr, uptr size);
void RunFreeHooks(const void *ptr);
+typedef void (*fill_profile_f)(uptr start, uptr rss, bool file,
+ /*out*/uptr *stats, uptr stats_size);
+
+// Parse the contents of /proc/self/smaps and generate a memory profile.
+// |cb| is a tool-specific callback that fills the |stats| array containing
+// |stats_size| elements.
+void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size);
+
// InternalScopedBuffer can be used instead of large stack arrays to
// keep frame size low.
// FIXME: use InternalAlloc instead of MmapOrDie once
@@ -172,6 +194,7 @@ typedef void (*LowLevelAllocateCallback)(uptr ptr, uptr size);
void SetLowLevelAllocateCallback(LowLevelAllocateCallback callback);
// IO
+void CatastrophicErrorWrite(const char *buffer, uptr length);
void RawWrite(const char *buffer);
bool ColorizeReports();
void RemoveANSIEscapeSequencesFromString(char *buffer);
@@ -188,66 +211,21 @@ void SetPrintfAndReportCallback(void (*callback)(const char *));
} while (0)
// Can be used to prevent mixing error reports from different sanitizers.
+// FIXME: Replace with ScopedErrorReportLock and hide.
extern StaticSpinMutex CommonSanitizerReportMutex;
-struct ReportFile {
- void Write(const char *buffer, uptr length);
- bool SupportsColors();
- void SetReportPath(const char *path);
-
- // Don't use fields directly. They are only declared public to allow
- // aggregate initialization.
-
- // Protects fields below.
- StaticSpinMutex *mu;
- // Opened file descriptor. Defaults to stderr. It may be equal to
- // kInvalidFd, in which case new file will be opened when necessary.
- fd_t fd;
- // Path prefix of report file, set via __sanitizer_set_report_path.
- char path_prefix[kMaxPathLength];
- // Full path to report, obtained as <path_prefix>.PID
- char full_path[kMaxPathLength];
- // PID of the process that opened fd. If a fork() occurs,
- // the PID of child will be different from fd_pid.
- uptr fd_pid;
+// Lock sanitizer error reporting and protects against nested errors.
+class ScopedErrorReportLock {
+ public:
+ ScopedErrorReportLock();
+ ~ScopedErrorReportLock();
- private:
- void ReopenIfNecessary();
+ static void CheckLocked();
};
-extern ReportFile report_file;
extern uptr stoptheworld_tracer_pid;
extern uptr stoptheworld_tracer_ppid;
-enum FileAccessMode {
- RdOnly,
- WrOnly,
- RdWr
-};
-
-// Returns kInvalidFd on error.
-fd_t OpenFile(const char *filename, FileAccessMode mode,
- error_t *errno_p = nullptr);
-void CloseFile(fd_t);
-
-// Return true on success, false on error.
-bool ReadFromFile(fd_t fd, void *buff, uptr buff_size,
- uptr *bytes_read = nullptr, error_t *error_p = nullptr);
-bool WriteToFile(fd_t fd, const void *buff, uptr buff_size,
- uptr *bytes_written = nullptr, error_t *error_p = nullptr);
-
-bool RenameFile(const char *oldpath, const char *newpath,
- error_t *error_p = nullptr);
-
-// Scoped file handle closer.
-struct FileCloser {
- explicit FileCloser(fd_t fd) : fd(fd) {}
- ~FileCloser() { CloseFile(fd); }
- fd_t fd;
-};
-
-bool SupportsColoredOutput(fd_t fd);
-
// Opens the file 'file_name" and reads up to 'max_len' bytes.
// The resulting buffer is mmaped and stored in '*buff'.
// The size of the mmaped region is stored in '*buff_size'.
@@ -256,11 +234,6 @@ bool SupportsColoredOutput(fd_t fd);
bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
uptr *read_len, uptr max_len = 1 << 26,
error_t *errno_p = nullptr);
-// Maps given file to virtual memory, and returns pointer to it
-// (or NULL if mapping fails). Stores the size of mmaped region
-// in '*buff_size'.
-void *MapFileToMemory(const char *file_name, uptr *buff_size);
-void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset);
bool IsAccessibleMemoryRange(uptr beg, uptr size);
@@ -279,27 +252,9 @@ void UpdateProcessName();
void CacheBinaryName();
void DisableCoreDumperIfNecessary();
void DumpProcessMap();
-bool FileExists(const char *filename);
+void PrintModuleMap();
const char *GetEnv(const char *name);
bool SetEnv(const char *name, const char *value);
-const char *GetPwd();
-char *FindPathToBinary(const char *name);
-bool IsPathSeparator(const char c);
-bool IsAbsolutePath(const char *path);
-// Starts a subprocess and returs its pid.
-// If *_fd parameters are not kInvalidFd their corresponding input/output
-// streams will be redirect to the file. The files will always be closed
-// in parent process even in case of an error.
-// The child process will close all fds after STDERR_FILENO
-// before passing control to a program.
-pid_t StartSubprocess(const char *filename, const char *const argv[],
- fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd,
- fd_t stderr_fd = kInvalidFd);
-// Checks if specified process is still running
-bool IsProcessRunning(pid_t pid);
-// Waits for the process to finish and returns its exit code.
-// Returns -1 in case of an error.
-int WaitForProcess(pid_t pid);
u32 GetUid();
void ReExec();
@@ -312,15 +267,9 @@ bool AddressSpaceIsUnlimited();
void SetAddressSpaceUnlimited();
void AdjustStackSize(void *attr);
void PrepareForSandboxing(__sanitizer_sandbox_arguments *args);
-void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args);
void SetSandboxingCallback(void (*f)());
-void CoverageUpdateMapping();
-void CovBeforeFork();
-void CovAfterFork(int child_pid);
-
void InitializeCoverage(bool enabled, const char *coverage_dir);
-void ReInitializeCoverage(bool enabled, const char *coverage_dir);
void InitTlsSize();
uptr GetTlsSize();
@@ -373,16 +322,28 @@ void SetCheckFailedCallback(CheckFailedCallbackType callback);
// The callback should be registered once at the tool init time.
void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded));
-// Callback to be called when we want to try releasing unused allocator memory
-// back to the OS.
-typedef void (*AllocatorReleaseToOSCallback)();
-// The callback should be registered once at the tool init time.
-void SetAllocatorReleaseToOSCallback(AllocatorReleaseToOSCallback Callback);
-
// Functions related to signal handling.
typedef void (*SignalHandlerType)(int, void *, void *);
-bool IsHandledDeadlySignal(int signum);
+HandleSignalMode GetHandleSignalMode(int signum);
void InstallDeadlySignalHandlers(SignalHandlerType handler);
+
+// Signal reporting.
+// Each sanitizer uses slightly different implementation of stack unwinding.
+typedef void (*UnwindSignalStackCallbackType)(const SignalContext &sig,
+ const void *callback_context,
+ BufferedStackTrace *stack);
+// Print deadly signal report and die.
+void HandleDeadlySignal(void *siginfo, void *context, u32 tid,
+ UnwindSignalStackCallbackType unwind,
+ const void *unwind_context);
+
+// Part of HandleDeadlySignal, exposed for asan.
+void StartReportDeadlySignal();
+// Part of HandleDeadlySignal, exposed for asan.
+void ReportDeadlySignal(const SignalContext &sig, u32 tid,
+ UnwindSignalStackCallbackType unwind,
+ const void *unwind_context);
+
// Alternative signal stack (POSIX-only).
void SetAlternateSignalStack();
void UnsetAlternateSignalStack();
@@ -392,12 +353,16 @@ const int kMaxSummaryLength = 1024;
// Construct a one-line string:
// SUMMARY: SanitizerToolName: error_message
// and pass it to __sanitizer_report_error_summary.
-void ReportErrorSummary(const char *error_message);
+// If alt_tool_name is provided, it's used in place of SanitizerToolName.
+void ReportErrorSummary(const char *error_message,
+ const char *alt_tool_name = nullptr);
// Same as above, but construct error_message as:
// error_type file:line[:column][ function]
-void ReportErrorSummary(const char *error_type, const AddressInfo &info);
+void ReportErrorSummary(const char *error_type, const AddressInfo &info,
+ const char *alt_tool_name = nullptr);
// Same as above, but obtains AddressInfo by symbolizing top stack trace frame.
-void ReportErrorSummary(const char *error_type, const StackTrace *trace);
+void ReportErrorSummary(const char *error_type, const StackTrace *trace,
+ const char *alt_tool_name = nullptr);
// Math
#if SANITIZER_WINDOWS && !defined(__clang__) && !defined(__GNUC__)
@@ -549,6 +514,13 @@ class InternalMmapVectorNoCtor {
uptr capacity() const {
return capacity_;
}
+ void resize(uptr new_size) {
+ Resize(new_size);
+ if (new_size > size_) {
+ internal_memset(&data_[size_], 0, sizeof(T) * (new_size - size_));
+ }
+ size_ = new_size;
+ }
void clear() { size_ = 0; }
bool empty() const { return size() == 0; }
@@ -633,43 +605,108 @@ void InternalSort(Container *v, uptr size, Compare comp) {
}
}
-template<class Container, class Value, class Compare>
-uptr InternalBinarySearch(const Container &v, uptr first, uptr last,
- const Value &val, Compare comp) {
- uptr not_found = last + 1;
- while (last >= first) {
+// Works like std::lower_bound: finds the first element that is not less
+// than the val.
+template <class Container, class Value, class Compare>
+uptr InternalLowerBound(const Container &v, uptr first, uptr last,
+ const Value &val, Compare comp) {
+ while (last > first) {
uptr mid = (first + last) / 2;
if (comp(v[mid], val))
first = mid + 1;
- else if (comp(val, v[mid]))
- last = mid - 1;
else
- return mid;
+ last = mid;
+ }
+ return first;
+}
+
+enum ModuleArch {
+ kModuleArchUnknown,
+ kModuleArchI386,
+ kModuleArchX86_64,
+ kModuleArchX86_64H,
+ kModuleArchARMV6,
+ kModuleArchARMV7,
+ kModuleArchARMV7S,
+ kModuleArchARMV7K,
+ kModuleArchARM64
+};
+
+// When adding a new architecture, don't forget to also update
+// script/asan_symbolize.py and sanitizer_symbolizer_libcdep.cc.
+inline const char *ModuleArchToString(ModuleArch arch) {
+ switch (arch) {
+ case kModuleArchUnknown:
+ return "";
+ case kModuleArchI386:
+ return "i386";
+ case kModuleArchX86_64:
+ return "x86_64";
+ case kModuleArchX86_64H:
+ return "x86_64h";
+ case kModuleArchARMV6:
+ return "armv6";
+ case kModuleArchARMV7:
+ return "armv7";
+ case kModuleArchARMV7S:
+ return "armv7s";
+ case kModuleArchARMV7K:
+ return "armv7k";
+ case kModuleArchARM64:
+ return "arm64";
}
- return not_found;
+ CHECK(0 && "Invalid module arch");
+ return "";
}
+const uptr kModuleUUIDSize = 16;
+const uptr kMaxSegName = 16;
+
// Represents a binary loaded into virtual memory (e.g. this can be an
// executable or a shared object).
class LoadedModule {
public:
- LoadedModule() : full_name_(nullptr), base_address_(0) { ranges_.clear(); }
+ LoadedModule()
+ : full_name_(nullptr),
+ base_address_(0),
+ max_executable_address_(0),
+ arch_(kModuleArchUnknown),
+ instrumented_(false) {
+ internal_memset(uuid_, 0, kModuleUUIDSize);
+ ranges_.clear();
+ }
void set(const char *module_name, uptr base_address);
+ void set(const char *module_name, uptr base_address, ModuleArch arch,
+ u8 uuid[kModuleUUIDSize], bool instrumented);
void clear();
- void addAddressRange(uptr beg, uptr end, bool executable);
+ void addAddressRange(uptr beg, uptr end, bool executable, bool writable,
+ const char *name = nullptr);
bool containsAddress(uptr address) const;
const char *full_name() const { return full_name_; }
uptr base_address() const { return base_address_; }
+ uptr max_executable_address() const { return max_executable_address_; }
+ ModuleArch arch() const { return arch_; }
+ const u8 *uuid() const { return uuid_; }
+ bool instrumented() const { return instrumented_; }
struct AddressRange {
AddressRange *next;
uptr beg;
uptr end;
bool executable;
-
- AddressRange(uptr beg, uptr end, bool executable)
- : next(nullptr), beg(beg), end(end), executable(executable) {}
+ bool writable;
+ char name[kMaxSegName];
+
+ AddressRange(uptr beg, uptr end, bool executable, bool writable,
+ const char *name)
+ : next(nullptr),
+ beg(beg),
+ end(end),
+ executable(executable),
+ writable(writable) {
+ internal_strncpy(this->name, (name ? name : ""), ARRAY_SIZE(this->name));
+ }
};
const IntrusiveList<AddressRange> &ranges() const { return ranges_; }
@@ -677,6 +714,10 @@ class LoadedModule {
private:
char *full_name_; // Owned.
uptr base_address_;
+ uptr max_executable_address_;
+ ModuleArch arch_;
+ u8 uuid_[kModuleUUIDSize];
+ bool instrumented_;
IntrusiveList<AddressRange> ranges_;
};
@@ -684,9 +725,10 @@ class LoadedModule {
// filling this information.
class ListOfModules {
public:
- ListOfModules() : modules_(kInitialCapacity) {}
+ ListOfModules() : initialized(false) {}
~ListOfModules() { clear(); }
void init();
+ void fallbackInit(); // Uses fallback init if available, otherwise clears
const LoadedModule *begin() const { return modules_.begin(); }
LoadedModule *begin() { return modules_.begin(); }
const LoadedModule *end() const { return modules_.end(); }
@@ -702,10 +744,15 @@ class ListOfModules {
for (auto &module : modules_) module.clear();
modules_.clear();
}
+ void clearOrInit() {
+ initialized ? clear() : modules_.Initialize(kInitialCapacity);
+ initialized = true;
+ }
- InternalMmapVector<LoadedModule> modules_;
+ InternalMmapVectorNoCtor<LoadedModule> modules_;
// We rarely have more than 16K loaded modules.
static const uptr kInitialCapacity = 1 << 14;
+ bool initialized;
};
// Callback type for iterating over a set of memory ranges.
@@ -737,8 +784,11 @@ INLINE void LogMessageOnPrintf(const char *str) {}
#if SANITIZER_LINUX
// Initialize Android logging. Any writes before this are silently lost.
void AndroidLogInit();
+void SetAbortMessage(const char *);
#else
INLINE void AndroidLogInit() {}
+// FIXME: MacOS implementation could use CRSetCrashLogMessage.
+INLINE void SetAbortMessage(const char *) {}
#endif
#if SANITIZER_ANDROID
@@ -778,33 +828,49 @@ static inline void SanitizerBreakOptimization(void *arg) {
}
struct SignalContext {
+ void *siginfo;
void *context;
uptr addr;
uptr pc;
uptr sp;
uptr bp;
bool is_memory_access;
-
enum WriteFlag { UNKNOWN, READ, WRITE } write_flag;
- SignalContext(void *context, uptr addr, uptr pc, uptr sp, uptr bp,
- bool is_memory_access, WriteFlag write_flag)
- : context(context),
- addr(addr),
- pc(pc),
- sp(sp),
- bp(bp),
- is_memory_access(is_memory_access),
- write_flag(write_flag) {}
+ // VS2013 doesn't implement unrestricted unions, so we need a trivial default
+ // constructor
+ SignalContext() = default;
// Creates signal context in a platform-specific manner.
- static SignalContext Create(void *siginfo, void *context);
+ // SignalContext is going to keep pointers to siginfo and context without
+ // owning them.
+ SignalContext(void *siginfo, void *context)
+ : siginfo(siginfo),
+ context(context),
+ addr(GetAddress()),
+ is_memory_access(IsMemoryAccess()),
+ write_flag(GetWriteFlag()) {
+ InitPcSpBp();
+ }
- // Returns true if the "context" indicates a memory write.
- static WriteFlag GetWriteFlag(void *context);
-};
+ static void DumpAllRegisters(void *context);
+
+ // Type of signal e.g. SIGSEGV or EXCEPTION_ACCESS_VIOLATION.
+ int GetType() const;
+
+ // String description of the signal.
+ const char *Describe() const;
+
+ // Returns true if signal is stack overflow.
+ bool IsStackOverflow() const;
-void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp);
+ private:
+ // Platform specific initialization.
+ void InitPcSpBp();
+ uptr GetAddress() const;
+ WriteFlag GetWriteFlag() const;
+ bool IsMemoryAccess() const;
+};
void MaybeReexec();
@@ -840,6 +906,16 @@ struct StackDepotStats {
uptr allocated;
};
+// The default value for allocator_release_to_os_interval_ms common flag to
+// indicate that sanitizer allocator should not attempt to release memory to OS.
+const s32 kReleaseToOSIntervalNever = -1;
+
+void CheckNoDeepBind(const char *filename, int flag);
+
+// Returns the requested amount of random data (up to 256 bytes) that can then
+// be used to seed a PRNG. Defaults to blocking like the underlying syscall.
+bool GetRandom(void *buffer, uptr length, bool blocking = true);
+
} // namespace __sanitizer
inline void *operator new(__sanitizer::operator_new_size_type size,
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
index 19501402..3f32b2f 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors.inc
@@ -22,32 +22,34 @@
// COMMON_INTERCEPTOR_SET_THREAD_NAME
// COMMON_INTERCEPTOR_ON_DLOPEN
// COMMON_INTERCEPTOR_ON_EXIT
-// COMMON_INTERCEPTOR_MUTEX_LOCK
+// COMMON_INTERCEPTOR_MUTEX_PRE_LOCK
+// COMMON_INTERCEPTOR_MUTEX_POST_LOCK
// COMMON_INTERCEPTOR_MUTEX_UNLOCK
// COMMON_INTERCEPTOR_MUTEX_REPAIR
// COMMON_INTERCEPTOR_SET_PTHREAD_NAME
// COMMON_INTERCEPTOR_HANDLE_RECVMSG
// COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED
+// COMMON_INTERCEPTOR_MEMSET_IMPL
+// COMMON_INTERCEPTOR_MEMMOVE_IMPL
+// COMMON_INTERCEPTOR_MEMCPY_IMPL
+// COMMON_INTERCEPTOR_COPY_STRING
+// COMMON_INTERCEPTOR_STRNDUP_IMPL
//===----------------------------------------------------------------------===//
#include "interception/interception.h"
#include "sanitizer_addrhashmap.h"
+#include "sanitizer_errno.h"
#include "sanitizer_placement_new.h"
#include "sanitizer_platform_interceptors.h"
+#include "sanitizer_symbolizer.h"
#include "sanitizer_tls_get_addr.h"
#include <stdarg.h>
#if SANITIZER_INTERCEPTOR_HOOKS
-#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) \
- do { \
- if (f) \
- f(__VA_ARGS__); \
- } while (false);
-#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
- extern "C" { \
- SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE void f(__VA_ARGS__); \
- } // extern "C"
+#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...) f(__VA_ARGS__);
+#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...) \
+ SANITIZER_INTERFACE_WEAK_DEF(void, f, __VA_ARGS__) {}
#else
#define DECLARE_WEAK_INTERCEPTOR_HOOK(f, ...)
#define CALL_WEAK_INTERCEPTOR_HOOK(f, ...)
@@ -65,6 +67,19 @@
#define iconv __bsd_iconv
#endif
+// Platform-specific options.
+#if SANITIZER_MAC
+namespace __sanitizer {
+bool PlatformHasDifferentMemcpyAndMemmove();
+}
+#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE \
+ (__sanitizer::PlatformHasDifferentMemcpyAndMemmove())
+#elif SANITIZER_WINDOWS64
+#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE false
+#else
+#define PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE true
+#endif // SANITIZER_MAC
+
#ifndef COMMON_INTERCEPTOR_INITIALIZE_RANGE
#define COMMON_INTERCEPTOR_INITIALIZE_RANGE(p, size) {}
#endif
@@ -77,8 +92,12 @@
#define COMMON_INTERCEPTOR_FD_ACCESS(ctx, fd) {}
#endif
-#ifndef COMMON_INTERCEPTOR_MUTEX_LOCK
-#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) {}
+#ifndef COMMON_INTERCEPTOR_MUTEX_PRE_LOCK
+#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MUTEX_POST_LOCK
+#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) {}
#endif
#ifndef COMMON_INTERCEPTOR_MUTEX_UNLOCK
@@ -122,15 +141,13 @@
#define COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED (0)
#endif
-#define COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n) \
- COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \
- common_flags()->strict_string_checks ? (len) + 1 : (n) )
-
#define COMMON_INTERCEPTOR_READ_STRING(ctx, s, n) \
- COMMON_INTERCEPTOR_READ_STRING_OF_LEN((ctx), (s), REAL(strlen)(s), (n))
+ COMMON_INTERCEPTOR_READ_RANGE((ctx), (s), \
+ common_flags()->strict_string_checks ? (REAL(strlen)(s)) + 1 : (n) )
#ifndef COMMON_INTERCEPTOR_ON_DLOPEN
-#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) {}
+#define COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag) \
+ CheckNoDeepBind(filename, flag);
#endif
#ifndef COMMON_INTERCEPTOR_GET_TLS_RANGE
@@ -161,6 +178,65 @@
COMMON_INTERCEPT_FUNCTION(fn)
#endif
+#ifndef COMMON_INTERCEPTOR_MEMSET_IMPL
+#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \
+ { \
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \
+ return internal_memset(dst, v, size); \
+ COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size); \
+ if (common_flags()->intercept_intrin) \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
+ return REAL(memset)(dst, v, size); \
+ }
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MEMMOVE_IMPL
+#define COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size) \
+ { \
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) \
+ return internal_memmove(dst, src, size); \
+ COMMON_INTERCEPTOR_ENTER(ctx, memmove, dst, src, size); \
+ if (common_flags()->intercept_intrin) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size); \
+ } \
+ return REAL(memmove)(dst, src, size); \
+ }
+#endif
+
+#ifndef COMMON_INTERCEPTOR_MEMCPY_IMPL
+#define COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size) \
+ { \
+ if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) { \
+ return internal_memmove(dst, src, size); \
+ } \
+ COMMON_INTERCEPTOR_ENTER(ctx, memcpy, dst, src, size); \
+ if (common_flags()->intercept_intrin) { \
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size); \
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size); \
+ } \
+ return REAL(memcpy)(dst, src, size); \
+ }
+#endif
+
+#ifndef COMMON_INTERCEPTOR_COPY_STRING
+#define COMMON_INTERCEPTOR_COPY_STRING(ctx, to, from, size) {}
+#endif
+
+#ifndef COMMON_INTERCEPTOR_STRNDUP_IMPL
+#define COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size) \
+ COMMON_INTERCEPTOR_ENTER(ctx, strndup, s, size); \
+ uptr copy_length = internal_strnlen(s, size); \
+ char *new_mem = (char *)WRAP(malloc)(copy_length + 1); \
+ if (common_flags()->intercept_strndup) { \
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s, Min(size, copy_length + 1)); \
+ } \
+ COMMON_INTERCEPTOR_COPY_STRING(ctx, new_mem, s, copy_length); \
+ internal_memcpy(new_mem, s, copy_length); \
+ new_mem[copy_length] = '\0'; \
+ return new_mem;
+#endif
+
struct FileMetadata {
// For open_memstream().
char **addr;
@@ -181,7 +257,7 @@ typedef AddrHashMap<CommonInterceptorMetadata, 31051> MetadataHashMap;
static MetadataHashMap *interceptor_metadata_map;
-#if SI_NOT_WINDOWS
+#if SI_POSIX
UNUSED static void SetInterceptorMetadata(__sanitizer_FILE *addr,
const FileMetadata &file) {
MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr);
@@ -208,7 +284,7 @@ UNUSED static void DeleteInterceptorMetadata(void *addr) {
MetadataHashMap::Handle h(interceptor_metadata_map, (uptr)addr, true);
CHECK(h.exists());
}
-#endif // SI_NOT_WINDOWS
+#endif // SI_POSIX
#if SANITIZER_INTERCEPT_STRLEN
INTERCEPTOR(SIZE_T, strlen, const char *s) {
@@ -244,11 +320,31 @@ INTERCEPTOR(SIZE_T, strnlen, const char *s, SIZE_T maxlen) {
#define INIT_STRNLEN
#endif
+#if SANITIZER_INTERCEPT_STRNDUP
+INTERCEPTOR(char*, strndup, const char *s, uptr size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size);
+}
+#define INIT_STRNDUP COMMON_INTERCEPT_FUNCTION(strndup)
+#else
+#define INIT_STRNDUP
+#endif // SANITIZER_INTERCEPT_STRNDUP
+
+#if SANITIZER_INTERCEPT___STRNDUP
+INTERCEPTOR(char*, __strndup, const char *s, uptr size) {
+ void *ctx;
+ COMMON_INTERCEPTOR_STRNDUP_IMPL(ctx, s, size);
+}
+#define INIT___STRNDUP COMMON_INTERCEPT_FUNCTION(__strndup)
+#else
+#define INIT___STRNDUP
+#endif // SANITIZER_INTERCEPT___STRNDUP
+
#if SANITIZER_INTERCEPT_TEXTDOMAIN
INTERCEPTOR(char*, textdomain, const char *domainname) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, textdomain, domainname);
- COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0);
+ if (domainname) COMMON_INTERCEPTOR_READ_STRING(ctx, domainname, 0);
char *domain = REAL(textdomain)(domainname);
if (domain) {
COMMON_INTERCEPTOR_INITIALIZE_RANGE(domain, REAL(strlen)(domain) + 1);
@@ -302,8 +398,14 @@ INTERCEPTOR(int, strncmp, const char *s1, const char *s2, uptr size) {
c2 = (unsigned char)s2[i];
if (c1 != c2 || c1 == '\0') break;
}
- COMMON_INTERCEPTOR_READ_STRING(ctx, s1, Min(i + 1, size));
- COMMON_INTERCEPTOR_READ_STRING(ctx, s2, Min(i + 1, size));
+ uptr i1 = i;
+ uptr i2 = i;
+ if (common_flags()->strict_string_checks) {
+ for (; i1 < size && s1[i1]; i1++) {}
+ for (; i2 < size && s2[i2]; i2++) {}
+ }
+ COMMON_INTERCEPTOR_READ_RANGE((ctx), (s1), Min(i1 + 1, size));
+ COMMON_INTERCEPTOR_READ_RANGE((ctx), (s2), Min(i2 + 1, size));
int result = CharCmpX(c1, c2);
CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncmp, GET_CALLER_PC(), s1,
s2, size, result);
@@ -346,24 +448,30 @@ INTERCEPTOR(int, strcasecmp, const char *s1, const char *s2) {
}
DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, uptr called_pc,
- const char *s1, const char *s2, uptr n,
+ const char *s1, const char *s2, uptr size,
int result)
-INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T n) {
+INTERCEPTOR(int, strncasecmp, const char *s1, const char *s2, SIZE_T size) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, n);
+ COMMON_INTERCEPTOR_ENTER(ctx, strncasecmp, s1, s2, size);
unsigned char c1 = 0, c2 = 0;
uptr i;
- for (i = 0; i < n; i++) {
+ for (i = 0; i < size; i++) {
c1 = (unsigned char)s1[i];
c2 = (unsigned char)s2[i];
if (CharCaseCmp(c1, c2) != 0 || c1 == '\0') break;
}
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s1, Min(i + 1, n));
- COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, Min(i + 1, n));
+ uptr i1 = i;
+ uptr i2 = i;
+ if (common_flags()->strict_string_checks) {
+ for (; i1 < size && s1[i1]; i1++) {}
+ for (; i2 < size && s2[i2]; i2++) {}
+ }
+ COMMON_INTERCEPTOR_READ_RANGE((ctx), (s1), Min(i1 + 1, size));
+ COMMON_INTERCEPTOR_READ_RANGE((ctx), (s2), Min(i2 + 1, size));
int result = CharCaseCmp(c1, c2);
CALL_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_strncasecmp, GET_CALLER_PC(),
- s1, s2, n, result);
+ s1, s2, size, result);
return result;
}
@@ -379,8 +487,7 @@ static inline void StrstrCheck(void *ctx, char *r, const char *s1,
const char *s2) {
uptr len1 = REAL(strlen)(s1);
uptr len2 = REAL(strlen)(s2);
- COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s1, len1,
- r ? r - s1 + len2 : len1 + 1);
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s1, r ? r - s1 + len2 : len1 + 1);
COMMON_INTERCEPTOR_READ_RANGE(ctx, s2, len2 + 1);
}
#endif
@@ -429,6 +536,52 @@ INTERCEPTOR(char*, strcasestr, const char *s1, const char *s2) {
#define INIT_STRCASESTR
#endif
+#if SANITIZER_INTERCEPT_STRTOK
+
+INTERCEPTOR(char*, strtok, char *str, const char *delimiters) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strtok, str, delimiters);
+ if (!common_flags()->intercept_strtok) {
+ return REAL(strtok)(str, delimiters);
+ }
+ if (common_flags()->strict_string_checks) {
+ // If strict_string_checks is enabled, we check the whole first argument
+ // string on the first call (strtok saves this string in a static buffer
+ // for subsequent calls). We do not need to check strtok's result.
+ // As the delimiters can change, we check them every call.
+ if (str != nullptr) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1);
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters,
+ REAL(strlen)(delimiters) + 1);
+ return REAL(strtok)(str, delimiters);
+ } else {
+ // However, when strict_string_checks is disabled we cannot check the
+ // whole string on the first call. Instead, we check the result string
+ // which is guaranteed to be a NULL-terminated substring of the first
+ // argument. We also conservatively check one character of str and the
+ // delimiters.
+ if (str != nullptr) {
+ COMMON_INTERCEPTOR_READ_STRING(ctx, str, 1);
+ }
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, delimiters, 1);
+ char *result = REAL(strtok)(str, delimiters);
+ if (result != nullptr) {
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, result, REAL(strlen)(result) + 1);
+ } else if (str != nullptr) {
+ // No delimiter were found, it's safe to assume that the entire str was
+ // scanned.
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, str, REAL(strlen)(str) + 1);
+ }
+ return result;
+ }
+}
+
+#define INIT_STRTOK COMMON_INTERCEPT_FUNCTION(strtok)
+#else
+#define INIT_STRTOK
+#endif
+
#if SANITIZER_INTERCEPT_MEMMEM
DECLARE_WEAK_INTERCEPTOR_HOOK(__sanitizer_weak_hook_memmem, uptr called_pc,
const void *s1, SIZE_T len1, const void *s2,
@@ -460,10 +613,11 @@ INTERCEPTOR(char*, strchr, const char *s, int c) {
return internal_strchr(s, c);
COMMON_INTERCEPTOR_ENTER(ctx, strchr, s, c);
char *result = REAL(strchr)(s, c);
- uptr len = internal_strlen(s);
- uptr n = result ? result - s + 1 : len + 1;
- if (common_flags()->intercept_strchr)
- COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, n);
+ if (common_flags()->intercept_strchr) {
+ // Keep strlen as macro argument, as macro may ignore it.
+ COMMON_INTERCEPTOR_READ_STRING(ctx, s,
+ (result ? result - s : REAL(strlen)(s)) + 1);
+ }
return result;
}
#define INIT_STRCHR COMMON_INTERCEPT_FUNCTION(strchr)
@@ -492,9 +646,8 @@ INTERCEPTOR(char*, strrchr, const char *s, int c) {
if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
return internal_strrchr(s, c);
COMMON_INTERCEPTOR_ENTER(ctx, strrchr, s, c);
- uptr len = internal_strlen(s);
if (common_flags()->intercept_strchr)
- COMMON_INTERCEPTOR_READ_STRING_OF_LEN(ctx, s, len, len + 1);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, REAL(strlen)(s) + 1);
return REAL(strrchr)(s, c);
}
#define INIT_STRRCHR COMMON_INTERCEPT_FUNCTION(strrchr)
@@ -551,14 +704,9 @@ INTERCEPTOR(char *, strpbrk, const char *s1, const char *s2) {
#endif
#if SANITIZER_INTERCEPT_MEMSET
-INTERCEPTOR(void*, memset, void *dst, int v, uptr size) {
- if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
- return internal_memset(dst, v, size);
+INTERCEPTOR(void *, memset, void *dst, int v, uptr size) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size);
- if (common_flags()->intercept_intrin)
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);
- return REAL(memset)(dst, v, size);
+ COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size);
}
#define INIT_MEMSET COMMON_INTERCEPT_FUNCTION(memset)
@@ -567,16 +715,9 @@ INTERCEPTOR(void*, memset, void *dst, int v, uptr size) {
#endif
#if SANITIZER_INTERCEPT_MEMMOVE
-INTERCEPTOR(void*, memmove, void *dst, const void *src, uptr size) {
- if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)
- return internal_memmove(dst, src, size);
+INTERCEPTOR(void *, memmove, void *dst, const void *src, uptr size) {
void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, memmove, dst, src, size);
- if (common_flags()->intercept_intrin) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size);
- }
- return REAL(memmove)(dst, src, size);
+ COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size);
}
#define INIT_MEMMOVE COMMON_INTERCEPT_FUNCTION(memmove)
@@ -585,25 +726,30 @@ INTERCEPTOR(void*, memmove, void *dst, const void *src, uptr size) {
#endif
#if SANITIZER_INTERCEPT_MEMCPY
-INTERCEPTOR(void*, memcpy, void *dst, const void *src, uptr size) {
- if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED) {
- // On OS X, calling internal_memcpy here will cause memory corruptions,
- // because memcpy and memmove are actually aliases of the same
- // implementation. We need to use internal_memmove here.
- return internal_memmove(dst, src, size);
- }
- void *ctx;
- COMMON_INTERCEPTOR_ENTER(ctx, memcpy, dst, src, size);
- if (common_flags()->intercept_intrin) {
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);
- COMMON_INTERCEPTOR_READ_RANGE(ctx, src, size);
- }
+INTERCEPTOR(void *, memcpy, void *dst, const void *src, uptr size) {
+ // On OS X, calling internal_memcpy here will cause memory corruptions,
+ // because memcpy and memmove are actually aliases of the same
+ // implementation. We need to use internal_memmove here.
// N.B.: If we switch this to internal_ we'll have to use internal_memmove
// due to memcpy being an alias of memmove on OS X.
- return REAL(memcpy)(dst, src, size);
+ void *ctx;
+ if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) {
+ COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, dst, src, size);
+ } else {
+ COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, dst, src, size);
+ }
}
-#define INIT_MEMCPY COMMON_INTERCEPT_FUNCTION(memcpy)
+#define INIT_MEMCPY \
+ do { \
+ if (PLATFORM_HAS_DIFFERENT_MEMCPY_AND_MEMMOVE) { \
+ COMMON_INTERCEPT_FUNCTION(memcpy); \
+ } else { \
+ ASSIGN_REAL(memcpy, memmove); \
+ } \
+ CHECK(REAL(memcpy)); \
+ } while (false)
+
#else
#define INIT_MEMCPY
#endif
@@ -739,7 +885,7 @@ INTERCEPTOR(long double, frexpl, long double x, int *exp) {
#define INIT_FREXPF_FREXPL
#endif // SANITIZER_INTERCEPT_FREXPF_FREXPL
-#if SI_NOT_WINDOWS
+#if SI_POSIX
static void write_iovec(void *ctx, struct __sanitizer_iovec *iovec,
SIZE_T iovlen, SIZE_T maxlen) {
for (SIZE_T i = 0; i < iovlen && maxlen; ++i) {
@@ -778,6 +924,23 @@ INTERCEPTOR(SSIZE_T, read, int fd, void *ptr, SIZE_T count) {
#define INIT_READ
#endif
+#if SANITIZER_INTERCEPT_FREAD
+INTERCEPTOR(SIZE_T, fread, void *ptr, SIZE_T size, SIZE_T nmemb, void *file) {
+ // libc file streams can call user-supplied functions, see fopencookie.
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fread, ptr, size, nmemb, file);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ SIZE_T res = REAL(fread)(ptr, size, nmemb, file);
+ if (res > 0) COMMON_INTERCEPTOR_WRITE_RANGE(ctx, ptr, res * size);
+ return res;
+}
+#define INIT_FREAD COMMON_INTERCEPT_FUNCTION(fread)
+#else
+#define INIT_FREAD
+#endif
+
#if SANITIZER_INTERCEPT_PREAD
INTERCEPTOR(SSIZE_T, pread, int fd, void *ptr, SIZE_T count, OFF_T offset) {
void *ctx;
@@ -878,6 +1041,20 @@ INTERCEPTOR(SSIZE_T, write, int fd, void *ptr, SIZE_T count) {
#define INIT_WRITE
#endif
+#if SANITIZER_INTERCEPT_FWRITE
+INTERCEPTOR(SIZE_T, fwrite, const void *p, uptr size, uptr nmemb, void *file) {
+ // libc file streams can call user-supplied functions, see fopencookie.
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, fwrite, p, size, nmemb, file);
+ SIZE_T res = REAL(fwrite)(p, size, nmemb, file);
+ if (res > 0) COMMON_INTERCEPTOR_READ_RANGE(ctx, p, res * size);
+ return res;
+}
+#define INIT_FWRITE COMMON_INTERCEPT_FUNCTION(fwrite)
+#else
+#define INIT_FWRITE
+#endif
+
#if SANITIZER_INTERCEPT_PWRITE
INTERCEPTOR(SSIZE_T, pwrite, int fd, void *ptr, SIZE_T count, OFF_T offset) {
void *ctx;
@@ -1225,12 +1402,12 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_sscanf, __isoc99_vsscanf, str, format)
#if SANITIZER_INTERCEPT_SCANF
#define INIT_SCANF \
- COMMON_INTERCEPT_FUNCTION(scanf); \
- COMMON_INTERCEPT_FUNCTION(sscanf); \
- COMMON_INTERCEPT_FUNCTION(fscanf); \
- COMMON_INTERCEPT_FUNCTION(vscanf); \
- COMMON_INTERCEPT_FUNCTION(vsscanf); \
- COMMON_INTERCEPT_FUNCTION(vfscanf);
+ COMMON_INTERCEPT_FUNCTION_LDBL(scanf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(sscanf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(fscanf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(vscanf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(vsscanf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(vfscanf);
#else
#define INIT_SCANF
#endif
@@ -1403,16 +1580,16 @@ FORMAT_INTERCEPTOR_IMPL(__isoc99_snprintf, __isoc99_vsnprintf, str, size,
#if SANITIZER_INTERCEPT_PRINTF
#define INIT_PRINTF \
- COMMON_INTERCEPT_FUNCTION(printf); \
- COMMON_INTERCEPT_FUNCTION(sprintf); \
- COMMON_INTERCEPT_FUNCTION(snprintf); \
- COMMON_INTERCEPT_FUNCTION(asprintf); \
- COMMON_INTERCEPT_FUNCTION(fprintf); \
- COMMON_INTERCEPT_FUNCTION(vprintf); \
- COMMON_INTERCEPT_FUNCTION(vsprintf); \
- COMMON_INTERCEPT_FUNCTION(vsnprintf); \
- COMMON_INTERCEPT_FUNCTION(vasprintf); \
- COMMON_INTERCEPT_FUNCTION(vfprintf);
+ COMMON_INTERCEPT_FUNCTION_LDBL(printf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(sprintf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(snprintf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(asprintf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(fprintf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(vprintf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(vsprintf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(vsnprintf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(vasprintf); \
+ COMMON_INTERCEPT_FUNCTION_LDBL(vfprintf);
#else
#define INIT_PRINTF
#endif
@@ -3187,6 +3364,30 @@ INTERCEPTOR(char *, strerror, int errnum) {
#endif
#if SANITIZER_INTERCEPT_STRERROR_R
+// There are 2 versions of strerror_r:
+// * POSIX version returns 0 on success, negative error code on failure,
+// writes message to buf.
+// * GNU version returns message pointer, which points to either buf or some
+// static storage.
+#if ((_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE) || \
+ SANITIZER_MAC || SANITIZER_ANDROID
+// POSIX version. Spec is not clear on whether buf is NULL-terminated.
+// At least on OSX, buf contents are valid even when the call fails.
+INTERCEPTOR(int, strerror_r, int errnum, char *buf, SIZE_T buflen) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
+ // FIXME: under ASan the call below may write to freed memory and corrupt
+ // its metadata. See
+ // https://github.com/google/sanitizers/issues/321.
+ int res = REAL(strerror_r)(errnum, buf, buflen);
+
+ SIZE_T sz = internal_strnlen(buf, buflen);
+ if (sz < buflen) ++sz;
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
+ return res;
+}
+#else
+// GNU version.
INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, strerror_r, errnum, buf, buflen);
@@ -3194,24 +3395,14 @@ INTERCEPTOR(char *, strerror_r, int errnum, char *buf, SIZE_T buflen) {
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
char *res = REAL(strerror_r)(errnum, buf, buflen);
- // There are 2 versions of strerror_r:
- // * POSIX version returns 0 on success, negative error code on failure,
- // writes message to buf.
- // * GNU version returns message pointer, which points to either buf or some
- // static storage.
- SIZE_T posix_res = (SIZE_T)res;
- if (posix_res < 1024 || posix_res > (SIZE_T) - 1024) {
- // POSIX version. Spec is not clear on whether buf is NULL-terminated.
- // At least on OSX, buf contents are valid even when the call fails.
- SIZE_T sz = internal_strnlen(buf, buflen);
- if (sz < buflen) ++sz;
- COMMON_INTERCEPTOR_WRITE_RANGE(ctx, buf, sz);
- } else {
- // GNU version.
+ if (res == buf)
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, res, REAL(strlen)(res) + 1);
- }
+ else
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, REAL(strlen)(res) + 1);
return res;
}
+#endif //(_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && !_GNU_SOURCE ||
+ //SANITIZER_MAC
#define INIT_STRERROR_R COMMON_INTERCEPT_FUNCTION(strerror_r);
#else
#define INIT_STRERROR_R
@@ -3397,7 +3588,7 @@ INTERCEPTOR(int, ppoll, __sanitizer_pollfd *fds, __sanitizer_nfds_t nfds,
if (fds && nfds) read_pollfd(ctx, fds, nfds);
if (timeout_ts)
COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout_ts, struct_timespec_sz);
- // FIXME: read sigmask when all of sigemptyset, etc are intercepted.
+ if (sigmask) COMMON_INTERCEPTOR_READ_RANGE(ctx, sigmask, sizeof(*sigmask));
int res =
COMMON_INTERCEPTOR_BLOCK_REAL(ppoll)(fds, nfds, timeout_ts, sigmask);
if (fds && nfds) write_pollfd(ctx, fds, nfds);
@@ -3438,7 +3629,7 @@ INTERCEPTOR(int, wordexp, char *s, __sanitizer_wordexp_t *p, int flags) {
INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, sigwait, set, sig);
- // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
@@ -3455,7 +3646,7 @@ INTERCEPTOR(int, sigwait, __sanitizer_sigset_t *set, int *sig) {
INTERCEPTOR(int, sigwaitinfo, __sanitizer_sigset_t *set, void *info) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, sigwaitinfo, set, info);
- // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
@@ -3474,7 +3665,7 @@ INTERCEPTOR(int, sigtimedwait, __sanitizer_sigset_t *set, void *info,
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, sigtimedwait, set, info, timeout);
if (timeout) COMMON_INTERCEPTOR_READ_RANGE(ctx, timeout, struct_timespec_sz);
- // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
@@ -3537,7 +3728,7 @@ INTERCEPTOR(int, sigprocmask, int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, sigprocmask, how, set, oldset);
- // FIXME: read sigset_t when all of sigemptyset, etc are intercepted
+ if (set) COMMON_INTERCEPTOR_READ_RANGE(ctx, set, sizeof(*set));
// FIXME: under ASan the call below may write to freed memory and corrupt
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
@@ -3606,11 +3797,12 @@ INTERCEPTOR(void, _exit, int status) {
INTERCEPTOR(int, pthread_mutex_lock, void *m) {
void *ctx;
COMMON_INTERCEPTOR_ENTER(ctx, pthread_mutex_lock, m);
+ COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m);
int res = REAL(pthread_mutex_lock)(m);
if (res == errno_EOWNERDEAD)
COMMON_INTERCEPTOR_MUTEX_REPAIR(ctx, m);
if (res == 0 || res == errno_EOWNERDEAD)
- COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m);
+ COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m);
if (res == errno_EINVAL)
COMMON_INTERCEPTOR_MUTEX_INVALID(ctx, m);
return res;
@@ -4484,7 +4676,7 @@ INTERCEPTOR(SIZE_T, iconv, void *cd, char **inbuf, SIZE_T *inbytesleft,
// its metadata. See
// https://github.com/google/sanitizers/issues/321.
SIZE_T res = REAL(iconv)(cd, inbuf, inbytesleft, outbuf, outbytesleft);
- if (res != (SIZE_T) - 1 && outbuf && *outbuf > outbuf_orig) {
+ if (outbuf && *outbuf > outbuf_orig) {
SIZE_T sz = (char *)*outbuf - (char *)outbuf_orig;
COMMON_INTERCEPTOR_WRITE_RANGE(ctx, outbuf_orig, sz);
}
@@ -4839,47 +5031,67 @@ INTERCEPTOR(int, capset, void *hdrp, const void *datap) {
#endif
#if SANITIZER_INTERCEPT_AEABI_MEM
-DECLARE_REAL_AND_INTERCEPTOR(void *, memmove, void *, const void *, uptr)
-DECLARE_REAL_AND_INTERCEPTOR(void *, memcpy, void *, const void *, uptr)
-DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr)
-
INTERCEPTOR(void *, __aeabi_memmove, void *to, const void *from, uptr size) {
- return WRAP(memmove)(to, from, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size);
}
+
INTERCEPTOR(void *, __aeabi_memmove4, void *to, const void *from, uptr size) {
- return WRAP(memmove)(to, from, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size);
}
+
INTERCEPTOR(void *, __aeabi_memmove8, void *to, const void *from, uptr size) {
- return WRAP(memmove)(to, from, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMMOVE_IMPL(ctx, to, from, size);
}
+
INTERCEPTOR(void *, __aeabi_memcpy, void *to, const void *from, uptr size) {
- return WRAP(memcpy)(to, from, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size);
}
+
INTERCEPTOR(void *, __aeabi_memcpy4, void *to, const void *from, uptr size) {
- return WRAP(memcpy)(to, from, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size);
}
+
INTERCEPTOR(void *, __aeabi_memcpy8, void *to, const void *from, uptr size) {
- return WRAP(memcpy)(to, from, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMCPY_IMPL(ctx, to, from, size);
}
+
// Note the argument order.
INTERCEPTOR(void *, __aeabi_memset, void *block, uptr size, int c) {
- return WRAP(memset)(block, c, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size);
}
+
INTERCEPTOR(void *, __aeabi_memset4, void *block, uptr size, int c) {
- return WRAP(memset)(block, c, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size);
}
+
INTERCEPTOR(void *, __aeabi_memset8, void *block, uptr size, int c) {
- return WRAP(memset)(block, c, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, c, size);
}
+
INTERCEPTOR(void *, __aeabi_memclr, void *block, uptr size) {
- return WRAP(memset)(block, 0, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
}
+
INTERCEPTOR(void *, __aeabi_memclr4, void *block, uptr size) {
- return WRAP(memset)(block, 0, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
}
+
INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) {
- return WRAP(memset)(block, 0, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
}
+
#define INIT_AEABI_MEM \
COMMON_INTERCEPT_FUNCTION(__aeabi_memmove); \
COMMON_INTERCEPT_FUNCTION(__aeabi_memmove4); \
@@ -4898,11 +5110,11 @@ INTERCEPTOR(void *, __aeabi_memclr8, void *block, uptr size) {
#endif // SANITIZER_INTERCEPT_AEABI_MEM
#if SANITIZER_INTERCEPT___BZERO
-DECLARE_REAL_AND_INTERCEPTOR(void *, memset, void *, int, uptr);
-
INTERCEPTOR(void *, __bzero, void *block, uptr size) {
- return WRAP(memset)(block, 0, size);
+ void *ctx;
+ COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, block, 0, size);
}
+
#define INIT___BZERO COMMON_INTERCEPT_FUNCTION(__bzero);
#else
#define INIT___BZERO
@@ -5362,6 +5574,7 @@ INTERCEPTOR(void*, dlopen, const char *filename, int flag) {
if (filename) COMMON_INTERCEPTOR_READ_STRING(ctx, filename, 0);
COMMON_INTERCEPTOR_ON_DLOPEN(filename, flag);
void *res = REAL(dlopen)(filename, flag);
+ Symbolizer::GetOrInit()->InvalidateModuleList();
COMMON_INTERCEPTOR_LIBRARY_LOADED(filename, res);
return res;
}
@@ -5370,6 +5583,7 @@ INTERCEPTOR(int, dlclose, void *handle) {
void *ctx;
COMMON_INTERCEPTOR_ENTER_NOIGNORE(ctx, dlclose, handle);
int res = REAL(dlclose)(handle);
+ Symbolizer::GetOrInit()->InvalidateModuleList();
COMMON_INTERCEPTOR_LIBRARY_UNLOADED();
return res;
}
@@ -5892,6 +6106,152 @@ INTERCEPTOR(int, __lxstat64, int version, const char *path, void *buf) {
// FIXME: add other *stat interceptor
+#if SANITIZER_INTERCEPT_UTMP
+INTERCEPTOR(void *, getutent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getutent, dummy);
+ void *res = REAL(getutent)(dummy);
+ if (res)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz);
+ return res;
+}
+INTERCEPTOR(void *, getutid, void *ut) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getutid, ut);
+ void *res = REAL(getutid)(ut);
+ if (res)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz);
+ return res;
+}
+INTERCEPTOR(void *, getutline, void *ut) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getutline, ut);
+ void *res = REAL(getutline)(ut);
+ if (res)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmp_sz);
+ return res;
+}
+#define INIT_UTMP \
+ COMMON_INTERCEPT_FUNCTION(getutent); \
+ COMMON_INTERCEPT_FUNCTION(getutid); \
+ COMMON_INTERCEPT_FUNCTION(getutline);
+#else
+#define INIT_UTMP
+#endif
+
+#if SANITIZER_INTERCEPT_UTMPX
+INTERCEPTOR(void *, getutxent, int dummy) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getutxent, dummy);
+ void *res = REAL(getutxent)(dummy);
+ if (res)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz);
+ return res;
+}
+INTERCEPTOR(void *, getutxid, void *ut) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getutxid, ut);
+ void *res = REAL(getutxid)(ut);
+ if (res)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz);
+ return res;
+}
+INTERCEPTOR(void *, getutxline, void *ut) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getutxline, ut);
+ void *res = REAL(getutxline)(ut);
+ if (res)
+ COMMON_INTERCEPTOR_INITIALIZE_RANGE(res, __sanitizer::struct_utmpx_sz);
+ return res;
+}
+#define INIT_UTMPX \
+ COMMON_INTERCEPT_FUNCTION(getutxent); \
+ COMMON_INTERCEPT_FUNCTION(getutxid); \
+ COMMON_INTERCEPT_FUNCTION(getutxline);
+#else
+#define INIT_UTMPX
+#endif
+
+#if SANITIZER_INTERCEPT_GETLOADAVG
+INTERCEPTOR(int, getloadavg, double *loadavg, int nelem) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, getloadavg, loadavg, nelem);
+ int res = REAL(getloadavg)(loadavg, nelem);
+ if (res > 0)
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, loadavg, res * sizeof(*loadavg));
+ return res;
+}
+#define INIT_GETLOADAVG \
+ COMMON_INTERCEPT_FUNCTION(getloadavg);
+#else
+#define INIT_GETLOADAVG
+#endif
+
+#if SANITIZER_INTERCEPT_MCHECK_MPROBE
+INTERCEPTOR(int, mcheck, void (*abortfunc)(int mstatus)) {
+ return 0;
+}
+
+INTERCEPTOR(int, mcheck_pedantic, void (*abortfunc)(int mstatus)) {
+ return 0;
+}
+
+INTERCEPTOR(int, mprobe, void *ptr) {
+ return 0;
+}
+#endif
+
+INTERCEPTOR(SIZE_T, wcslen, const wchar_t *s) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcslen, s);
+ SIZE_T res = REAL(wcslen)(s);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * (res + 1));
+ return res;
+}
+
+INTERCEPTOR(SIZE_T, wcsnlen, const wchar_t *s, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsnlen, s, n);
+ SIZE_T res = REAL(wcsnlen)(s, n);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, s, sizeof(wchar_t) * Min(res + 1, n));
+ return res;
+}
+#define INIT_WCSLEN \
+ COMMON_INTERCEPT_FUNCTION(wcslen); \
+ COMMON_INTERCEPT_FUNCTION(wcsnlen);
+
+#if SANITIZER_INTERCEPT_WCSCAT
+INTERCEPTOR(wchar_t *, wcscat, wchar_t *dst, const wchar_t *src) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcscat, dst, src);
+ SIZE_T src_size = REAL(wcslen)(src);
+ SIZE_T dst_size = REAL(wcslen)(dst);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src, (src_size + 1) * sizeof(wchar_t));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size,
+ (src_size + 1) * sizeof(wchar_t));
+ return REAL(wcscat)(dst, src); // NOLINT
+}
+
+INTERCEPTOR(wchar_t *, wcsncat, wchar_t *dst, const wchar_t *src, SIZE_T n) {
+ void *ctx;
+ COMMON_INTERCEPTOR_ENTER(ctx, wcsncat, dst, src, n);
+ SIZE_T src_size = REAL(wcsnlen)(src, n);
+ SIZE_T dst_size = REAL(wcslen)(dst);
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, src,
+ Min(src_size + 1, n) * sizeof(wchar_t));
+ COMMON_INTERCEPTOR_READ_RANGE(ctx, dst, (dst_size + 1) * sizeof(wchar_t));
+ COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst + dst_size,
+ (src_size + 1) * sizeof(wchar_t));
+ return REAL(wcsncat)(dst, src, n); // NOLINT
+}
+#define INIT_WCSCAT \
+ COMMON_INTERCEPT_FUNCTION(wcscat); \
+ COMMON_INTERCEPT_FUNCTION(wcsncat);
+#else
+#define INIT_WCSCAT
+#endif
+
static void InitializeCommonInterceptors() {
static u64 metadata_mem[sizeof(MetadataHashMap) / sizeof(u64) + 1];
interceptor_metadata_map = new((void *)&metadata_mem) MetadataHashMap();
@@ -5899,6 +6259,8 @@ static void InitializeCommonInterceptors() {
INIT_TEXTDOMAIN;
INIT_STRLEN;
INIT_STRNLEN;
+ INIT_STRNDUP;
+ INIT___STRNDUP;
INIT_STRCMP;
INIT_STRNCMP;
INIT_STRCASECMP;
@@ -5909,6 +6271,7 @@ static void InitializeCommonInterceptors() {
INIT_STRCHRNUL;
INIT_STRRCHR;
INIT_STRSPN;
+ INIT_STRTOK;
INIT_STRPBRK;
INIT_MEMSET;
INIT_MEMMOVE;
@@ -5918,12 +6281,14 @@ static void InitializeCommonInterceptors() {
INIT_MEMRCHR;
INIT_MEMMEM;
INIT_READ;
+ INIT_FREAD;
INIT_PREAD;
INIT_PREAD64;
INIT_READV;
INIT_PREADV;
INIT_PREADV64;
INIT_WRITE;
+ INIT_FWRITE;
INIT_PWRITE;
INIT_PWRITE64;
INIT_WRITEV;
@@ -6088,4 +6453,9 @@ static void InitializeCommonInterceptors() {
INIT___LXSTAT;
INIT___LXSTAT64;
// FIXME: add other *stat interceptors.
+ INIT_UTMP;
+ INIT_UTMPX;
+ INIT_GETLOADAVG;
+ INIT_WCSLEN;
+ INIT_WCSCAT;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc
index 9133be7..30927d2 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interceptors_format.inc
@@ -323,8 +323,8 @@ static void scanf_common(void *ctx, int n_inputs, bool allowGnuMalloc,
continue;
int size = scanf_get_value_size(&dir);
if (size == FSS_INVALID) {
- Report("WARNING: unexpected format specifier in scanf interceptor: "
- "%.*s\n", dir.end - dir.begin, dir.begin);
+ Report("%s: WARNING: unexpected format specifier in scanf interceptor: ",
+ SanitizerToolName, "%.*s\n", dir.end - dir.begin, dir.begin);
break;
}
void *argp = va_arg(aq, void *);
@@ -433,10 +433,6 @@ static const char *printf_parse_next(const char *p, PrintfDirective *dir) {
}
static int printf_get_value_size(PrintfDirective *dir) {
- if (dir->convSpecifier == 'm') {
- return sizeof(char *);
- }
-
if (char_is_one_of(dir->convSpecifier, "cCsS")) {
unsigned charSize =
format_get_char_size(dir->convSpecifier, dir->lengthModifier);
@@ -517,10 +513,17 @@ static void printf_common(void *ctx, const char *format, va_list aq) {
// Dynamic precision
SKIP_SCALAR_ARG(&aq, 'd', sizeof(int));
}
+ // %m does not require an argument: strlen(errno).
+ if (dir.convSpecifier == 'm')
+ continue;
int size = printf_get_value_size(&dir);
if (size == FSS_INVALID) {
- Report("WARNING: unexpected format specifier in printf "
- "interceptor: %.*s\n", dir.end - dir.begin, dir.begin);
+ static int ReportedOnce;
+ if (!ReportedOnce++)
+ Report(
+ "%s: WARNING: unexpected format specifier in printf "
+ "interceptor: %.*s (reported once per process)\n",
+ SanitizerToolName, dir.end - dir.begin, dir.begin);
break;
}
if (dir.convSpecifier == 'n') {
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
new file mode 100644
index 0000000..bd296f6
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interface.inc
@@ -0,0 +1,37 @@
+//===-- sanitizer_common_interface.inc ------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Sanitizer Common interface list.
+//===----------------------------------------------------------------------===//
+INTERFACE_FUNCTION(__sanitizer_annotate_contiguous_container)
+INTERFACE_FUNCTION(__sanitizer_contiguous_container_find_bad_address)
+INTERFACE_FUNCTION(__sanitizer_set_death_callback)
+INTERFACE_FUNCTION(__sanitizer_set_report_path)
+INTERFACE_FUNCTION(__sanitizer_set_report_fd)
+INTERFACE_FUNCTION(__sanitizer_verify_contiguous_container)
+INTERFACE_WEAK_FUNCTION(__sanitizer_report_error_summary)
+INTERFACE_WEAK_FUNCTION(__sanitizer_sandbox_on_notify)
+// Sanitizer weak hooks
+INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_memcmp)
+INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strcmp)
+INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strncmp)
+INTERFACE_WEAK_FUNCTION(__sanitizer_weak_hook_strstr)
+// Stacktrace interface.
+INTERFACE_FUNCTION(__sanitizer_get_module_and_offset_for_pc)
+INTERFACE_FUNCTION(__sanitizer_symbolize_global)
+INTERFACE_FUNCTION(__sanitizer_symbolize_pc)
+// Allocator interface.
+INTERFACE_FUNCTION(__sanitizer_get_allocated_size)
+INTERFACE_FUNCTION(__sanitizer_get_current_allocated_bytes)
+INTERFACE_FUNCTION(__sanitizer_get_estimated_allocated_size)
+INTERFACE_FUNCTION(__sanitizer_get_free_bytes)
+INTERFACE_FUNCTION(__sanitizer_get_heap_size)
+INTERFACE_FUNCTION(__sanitizer_get_ownership)
+INTERFACE_FUNCTION(__sanitizer_get_unmapped_bytes)
+INTERFACE_FUNCTION(__sanitizer_install_malloc_and_free_hooks)
+INTERFACE_FUNCTION(__sanitizer_print_memory_profile)
+INTERFACE_WEAK_FUNCTION(__sanitizer_free_hook)
+INTERFACE_WEAK_FUNCTION(__sanitizer_malloc_hook)
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_interface_posix.inc b/libsanitizer/sanitizer_common/sanitizer_common_interface_posix.inc
new file mode 100644
index 0000000..d3b72a8
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_common_interface_posix.inc
@@ -0,0 +1,12 @@
+//===-- sanitizer_common_interface_posix.inc ------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Sanitizer Common interface list only available for Posix systems.
+//===----------------------------------------------------------------------===//
+INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_code)
+INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_data)
+INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_demangle)
+INTERFACE_WEAK_FUNCTION(__sanitizer_symbolize_flush)
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc
index 8c9fa98..a3f3531 100644
--- a/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_common_libcdep.cc
@@ -12,7 +12,10 @@
#include "sanitizer_common.h"
#include "sanitizer_allocator_interface.h"
+#include "sanitizer_file.h"
#include "sanitizer_flags.h"
+#include "sanitizer_procmaps.h"
+#include "sanitizer_report_decorator.h"
#include "sanitizer_stackdepot.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
@@ -23,12 +26,25 @@
namespace __sanitizer {
+#if !SANITIZER_FUCHSIA
+
bool ReportFile::SupportsColors() {
SpinMutexLock l(mu);
ReopenIfNecessary();
return SupportsColoredOutput(fd);
}
+static INLINE bool ReportSupportsColors() {
+ return report_file.SupportsColors();
+}
+
+#else // SANITIZER_FUCHSIA
+
+// Fuchsia's logs always go through post-processing that handles colorization.
+static INLINE bool ReportSupportsColors() { return true; }
+
+#endif // !SANITIZER_FUCHSIA
+
bool ColorizeReports() {
// FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
// printing on Windows.
@@ -37,7 +53,7 @@ bool ColorizeReports() {
const char *flag = common_flags()->color;
return internal_strcmp(flag, "always") == 0 ||
- (internal_strcmp(flag, "auto") == 0 && report_file.SupportsColors());
+ (internal_strcmp(flag, "auto") == 0 && ReportSupportsColors());
}
static void (*sandboxing_callback)();
@@ -45,7 +61,8 @@ void SetSandboxingCallback(void (*f)()) {
sandboxing_callback = f;
}
-void ReportErrorSummary(const char *error_type, const StackTrace *stack) {
+void ReportErrorSummary(const char *error_type, const StackTrace *stack,
+ const char *alt_tool_name) {
#if !SANITIZER_GO
if (!common_flags()->print_summary)
return;
@@ -57,7 +74,7 @@ void ReportErrorSummary(const char *error_type, const StackTrace *stack) {
// Maybe sometimes we need to choose another frame (e.g. skip memcpy/etc).
uptr pc = StackTrace::GetPreviousInstructionPc(stack->trace[0]);
SymbolizedStack *frame = Symbolizer::GetOrInit()->SymbolizePC(pc);
- ReportErrorSummary(error_type, frame->info);
+ ReportErrorSummary(error_type, frame->info, alt_tool_name);
frame->ClearAll();
#endif
}
@@ -68,18 +85,11 @@ void SetSoftRssLimitExceededCallback(void (*Callback)(bool exceeded)) {
SoftRssLimitExceededCallback = Callback;
}
-static AllocatorReleaseToOSCallback ReleseCallback;
-void SetAllocatorReleaseToOSCallback(AllocatorReleaseToOSCallback Callback) {
- CHECK_EQ(ReleseCallback, nullptr);
- ReleseCallback = Callback;
-}
-
#if SANITIZER_LINUX && !SANITIZER_GO
void BackgroundThread(void *arg) {
uptr hard_rss_limit_mb = common_flags()->hard_rss_limit_mb;
uptr soft_rss_limit_mb = common_flags()->soft_rss_limit_mb;
bool heap_profile = common_flags()->heap_profile;
- bool allocator_release_to_os = common_flags()->allocator_release_to_os;
uptr prev_reported_rss = 0;
uptr prev_reported_stack_depot_size = 0;
bool reached_soft_rss_limit = false;
@@ -125,17 +135,137 @@ void BackgroundThread(void *arg) {
SoftRssLimitExceededCallback(false);
}
}
- if (allocator_release_to_os && ReleseCallback) ReleseCallback();
if (heap_profile &&
current_rss_mb > rss_during_last_reported_profile * 1.1) {
Printf("\n\nHEAP PROFILE at RSS %zdMb\n", current_rss_mb);
- __sanitizer_print_memory_profile(90);
+ __sanitizer_print_memory_profile(90, 20);
rss_during_last_reported_profile = current_rss_mb;
}
}
}
#endif
+#if !SANITIZER_FUCHSIA && !SANITIZER_GO
+void StartReportDeadlySignal() {
+ // Write the first message using fd=2, just in case.
+ // It may actually fail to write in case stderr is closed.
+ CatastrophicErrorWrite(SanitizerToolName, internal_strlen(SanitizerToolName));
+ static const char kDeadlySignal[] = ":DEADLYSIGNAL\n";
+ CatastrophicErrorWrite(kDeadlySignal, sizeof(kDeadlySignal) - 1);
+}
+
+static void MaybeReportNonExecRegion(uptr pc) {
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
+ MemoryMappingLayout proc_maps(/*cache_enabled*/ true);
+ MemoryMappedSegment segment;
+ while (proc_maps.Next(&segment)) {
+ if (pc >= segment.start && pc < segment.end && !segment.IsExecutable())
+ Report("Hint: PC is at a non-executable region. Maybe a wild jump?\n");
+ }
+#endif
+}
+
+static void PrintMemoryByte(InternalScopedString *str, const char *before,
+ u8 byte) {
+ SanitizerCommonDecorator d;
+ str->append("%s%s%x%x%s ", before, d.MemoryByte(), byte >> 4, byte & 15,
+ d.Default());
+}
+
+static void MaybeDumpInstructionBytes(uptr pc) {
+ if (!common_flags()->dump_instruction_bytes || (pc < GetPageSizeCached()))
+ return;
+ InternalScopedString str(1024);
+ str.append("First 16 instruction bytes at pc: ");
+ if (IsAccessibleMemoryRange(pc, 16)) {
+ for (int i = 0; i < 16; ++i) {
+ PrintMemoryByte(&str, "", ((u8 *)pc)[i]);
+ }
+ str.append("\n");
+ } else {
+ str.append("unaccessible\n");
+ }
+ Report("%s", str.data());
+}
+
+static void MaybeDumpRegisters(void *context) {
+ if (!common_flags()->dump_registers) return;
+ SignalContext::DumpAllRegisters(context);
+}
+
+static void ReportStackOverflowImpl(const SignalContext &sig, u32 tid,
+ UnwindSignalStackCallbackType unwind,
+ const void *unwind_context) {
+ SanitizerCommonDecorator d;
+ Printf("%s", d.Warning());
+ static const char kDescription[] = "stack-overflow";
+ Report("ERROR: %s: %s on address %p (pc %p bp %p sp %p T%d)\n",
+ SanitizerToolName, kDescription, (void *)sig.addr, (void *)sig.pc,
+ (void *)sig.bp, (void *)sig.sp, tid);
+ Printf("%s", d.Default());
+ InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
+ BufferedStackTrace *stack = stack_buffer.data();
+ stack->Reset();
+ unwind(sig, unwind_context, stack);
+ stack->Print();
+ ReportErrorSummary(kDescription, stack);
+}
+
+static void ReportDeadlySignalImpl(const SignalContext &sig, u32 tid,
+ UnwindSignalStackCallbackType unwind,
+ const void *unwind_context) {
+ SanitizerCommonDecorator d;
+ Printf("%s", d.Warning());
+ const char *description = sig.Describe();
+ Report("ERROR: %s: %s on unknown address %p (pc %p bp %p sp %p T%d)\n",
+ SanitizerToolName, description, (void *)sig.addr, (void *)sig.pc,
+ (void *)sig.bp, (void *)sig.sp, tid);
+ Printf("%s", d.Default());
+ if (sig.pc < GetPageSizeCached())
+ Report("Hint: pc points to the zero page.\n");
+ if (sig.is_memory_access) {
+ const char *access_type =
+ sig.write_flag == SignalContext::WRITE
+ ? "WRITE"
+ : (sig.write_flag == SignalContext::READ ? "READ" : "UNKNOWN");
+ Report("The signal is caused by a %s memory access.\n", access_type);
+ if (sig.addr < GetPageSizeCached())
+ Report("Hint: address points to the zero page.\n");
+ }
+ MaybeReportNonExecRegion(sig.pc);
+ InternalScopedBuffer<BufferedStackTrace> stack_buffer(1);
+ BufferedStackTrace *stack = stack_buffer.data();
+ stack->Reset();
+ unwind(sig, unwind_context, stack);
+ stack->Print();
+ MaybeDumpInstructionBytes(sig.pc);
+ MaybeDumpRegisters(sig.context);
+ Printf("%s can not provide additional info.\n", SanitizerToolName);
+ ReportErrorSummary(description, stack);
+}
+
+void ReportDeadlySignal(const SignalContext &sig, u32 tid,
+ UnwindSignalStackCallbackType unwind,
+ const void *unwind_context) {
+ if (sig.IsStackOverflow())
+ ReportStackOverflowImpl(sig, tid, unwind, unwind_context);
+ else
+ ReportDeadlySignalImpl(sig, tid, unwind, unwind_context);
+}
+
+void HandleDeadlySignal(void *siginfo, void *context, u32 tid,
+ UnwindSignalStackCallbackType unwind,
+ const void *unwind_context) {
+ StartReportDeadlySignal();
+ ScopedErrorReportLock rl;
+ SignalContext sig(siginfo, context);
+ ReportDeadlySignal(sig, tid, unwind, unwind_context);
+ Report("ABORTING\n");
+ Die();
+}
+
+#endif // !SANITIZER_FUCHSIA && !SANITIZER_GO
+
void WriteToSyslog(const char *msg) {
InternalScopedString msg_copy(kErrorMessageBufferSize);
msg_copy.append("%s", msg);
@@ -160,17 +290,56 @@ void MaybeStartBackgroudThread() {
// Start the background thread if one of the rss limits is given.
if (!common_flags()->hard_rss_limit_mb &&
!common_flags()->soft_rss_limit_mb &&
- !common_flags()->allocator_release_to_os &&
!common_flags()->heap_profile) return;
if (!&real_pthread_create) return; // Can't spawn the thread anyway.
internal_start_thread(BackgroundThread, nullptr);
#endif
}
+static atomic_uintptr_t reporting_thread = {0};
+
+ScopedErrorReportLock::ScopedErrorReportLock() {
+ uptr current = GetThreadSelf();
+ for (;;) {
+ uptr expected = 0;
+ if (atomic_compare_exchange_strong(&reporting_thread, &expected, current,
+ memory_order_relaxed)) {
+ // We've claimed reporting_thread so proceed.
+ CommonSanitizerReportMutex.Lock();
+ return;
+ }
+
+ if (expected == current) {
+ // This is either asynch signal or nested error during error reporting.
+ // Fail simple to avoid deadlocks in Report().
+
+ // Can't use Report() here because of potential deadlocks in nested
+ // signal handlers.
+ CatastrophicErrorWrite(SanitizerToolName,
+ internal_strlen(SanitizerToolName));
+ static const char msg[] = ": nested bug in the same thread, aborting.\n";
+ CatastrophicErrorWrite(msg, sizeof(msg) - 1);
+
+ internal__exit(common_flags()->exitcode);
+ }
+
+ internal_sched_yield();
+ }
+}
+
+ScopedErrorReportLock::~ScopedErrorReportLock() {
+ CommonSanitizerReportMutex.Unlock();
+ atomic_store_relaxed(&reporting_thread, 0);
+}
+
+void ScopedErrorReportLock::CheckLocked() {
+ CommonSanitizerReportMutex.CheckLocked();
+}
+
} // namespace __sanitizer
-void NOINLINE
-__sanitizer_sandbox_on_notify(__sanitizer_sandbox_arguments *args) {
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_sandbox_on_notify,
+ __sanitizer_sandbox_arguments *args) {
__sanitizer::PrepareForSandboxing(args);
if (__sanitizer::sandboxing_callback)
__sanitizer::sandboxing_callback();
diff --git a/libsanitizer/sanitizer_common/sanitizer_common_nolibc.cc b/libsanitizer/sanitizer_common/sanitizer_common_nolibc.cc
new file mode 100644
index 0000000..7397a01
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_common_nolibc.cc
@@ -0,0 +1,34 @@
+//===-- sanitizer_common_nolibc.cc ----------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains stubs for libc function to facilitate optional use of
+// libc in no-libcdep sources.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+
+namespace __sanitizer {
+
+// The Windows implementations of these functions use the win32 API directly,
+// bypassing libc.
+#if !SANITIZER_WINDOWS
+#if SANITIZER_LINUX
+bool ShouldLogAfterPrintf() { return false; }
+void LogMessageOnPrintf(const char *str) {}
+#endif
+void WriteToSyslog(const char *buffer) {}
+void Abort() { internal__exit(1); }
+void SleepForSeconds(int seconds) { internal_sleep(seconds); }
+#endif // !SANITIZER_WINDOWS
+
+#if !SANITIZER_WINDOWS && !SANITIZER_MAC
+void ListOfModules::init() {}
+#endif
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cc
new file mode 100644
index 0000000..7f29451
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_fuchsia.cc
@@ -0,0 +1,238 @@
+//===-- sanitizer_coverage_fuchsia.cc ------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Sanitizer Coverage Controller for Trace PC Guard, Fuchsia-specific version.
+//
+// This Fuchsia-specific implementation uses the same basic scheme and the
+// same simple '.sancov' file format as the generic implementation. The
+// difference is that we just produce a single blob of output for the whole
+// program, not a separate one per DSO. We do not sort the PC table and do
+// not prune the zeros, so the resulting file is always as large as it
+// would be to report 100% coverage. Implicit tracing information about
+// the address ranges of DSOs allows offline tools to split the one big
+// blob into separate files that the 'sancov' tool can understand.
+//
+// Unlike the traditional implementation that uses an atexit hook to write
+// out data files at the end, the results on Fuchsia do not go into a file
+// per se. The 'coverage_dir' option is ignored. Instead, they are stored
+// directly into a shared memory object (a Zircon VMO). At exit, that VMO
+// is handed over to a system service that's responsible for getting the
+// data out to somewhere that it can be fed into the sancov tool (where and
+// how is not our problem).
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FUCHSIA
+#include "sanitizer_atomic.h"
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+
+#include <zircon/process.h>
+#include <zircon/sanitizer.h>
+#include <zircon/syscalls.h>
+
+using namespace __sanitizer; // NOLINT
+
+namespace __sancov {
+namespace {
+
+// TODO(mcgrathr): Move the constant into a header shared with other impls.
+constexpr u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL;
+static_assert(SANITIZER_WORDSIZE == 64, "Fuchsia is always LP64");
+
+constexpr const char kSancovSinkName[] = "sancov";
+
+// Collects trace-pc guard coverage.
+// This class relies on zero-initialization.
+class TracePcGuardController {
+ public:
+ // For each PC location being tracked, there is a u32 reserved in global
+ // data called the "guard". At startup, we assign each guard slot a
+ // unique index into the big results array. Later during runtime, the
+ // first call to TracePcGuard (below) will store the corresponding PC at
+ // that index in the array. (Each later call with the same guard slot is
+ // presumed to be from the same PC.) Then it clears the guard slot back
+ // to zero, which tells the compiler not to bother calling in again. At
+ // the end of the run, we have a big array where each element is either
+ // zero or is a tracked PC location that was hit in the trace.
+
+ // This is called from global constructors. Each translation unit has a
+ // contiguous array of guard slots, and a constructor that calls here
+ // with the bounds of its array. Those constructors are allowed to call
+ // here more than once for the same array. Usually all of these
+ // constructors run in the initial thread, but it's possible that a
+ // dlopen call on a secondary thread will run constructors that get here.
+ void InitTracePcGuard(u32 *start, u32 *end) {
+ if (end > start && *start == 0 && common_flags()->coverage) {
+ // Complete the setup before filling in any guards with indices.
+ // This avoids the possibility of code called from Setup reentering
+ // TracePcGuard.
+ u32 idx = Setup(end - start);
+ for (u32 *p = start; p < end; ++p) {
+ *p = idx++;
+ }
+ }
+ }
+
+ void TracePcGuard(u32 *guard, uptr pc) {
+ atomic_uint32_t *guard_ptr = reinterpret_cast<atomic_uint32_t *>(guard);
+ u32 idx = atomic_exchange(guard_ptr, 0, memory_order_relaxed);
+ if (idx > 0) array_[idx] = pc;
+ }
+
+ void Dump() {
+ BlockingMutexLock locked(&setup_lock_);
+ if (array_) {
+ CHECK_NE(vmo_, ZX_HANDLE_INVALID);
+
+ // Publish the VMO to the system, where it can be collected and
+ // analyzed after this process exits. This always consumes the VMO
+ // handle. Any failure is just logged and not indicated to us.
+ __sanitizer_publish_data(kSancovSinkName, vmo_);
+ vmo_ = ZX_HANDLE_INVALID;
+
+ // This will route to __sanitizer_log_write, which will ensure that
+ // information about shared libraries is written out. This message
+ // uses the `dumpfile` symbolizer markup element to highlight the
+ // dump. See the explanation for this in:
+ // https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md
+ Printf("SanitizerCoverage: {{{dumpfile:%s:%s}}} with up to %u PCs\n",
+ kSancovSinkName, vmo_name_, next_index_ - 1);
+ }
+ }
+
+ private:
+ // We map in the largest possible view into the VMO: one word
+ // for every possible 32-bit index value. This avoids the need
+ // to change the mapping when increasing the size of the VMO.
+ // We can always spare the 32G of address space.
+ static constexpr size_t MappingSize = sizeof(uptr) << 32;
+
+ BlockingMutex setup_lock_;
+ uptr *array_;
+ u32 next_index_;
+ zx_handle_t vmo_;
+ char vmo_name_[ZX_MAX_NAME_LEN];
+
+ size_t DataSize() const { return next_index_ * sizeof(uintptr_t); }
+
+ u32 Setup(u32 num_guards) {
+ BlockingMutexLock locked(&setup_lock_);
+ DCHECK(common_flags()->coverage);
+
+ if (next_index_ == 0) {
+ CHECK_EQ(vmo_, ZX_HANDLE_INVALID);
+ CHECK_EQ(array_, nullptr);
+
+ // The first sample goes at [1] to reserve [0] for the magic number.
+ next_index_ = 1 + num_guards;
+
+ zx_status_t status = _zx_vmo_create(DataSize(), 0, &vmo_);
+ CHECK_EQ(status, ZX_OK);
+
+ // Give the VMO a name including our process KOID so it's easy to spot.
+ internal_snprintf(vmo_name_, sizeof(vmo_name_), "%s.%zu", kSancovSinkName,
+ internal_getpid());
+ _zx_object_set_property(vmo_, ZX_PROP_NAME, vmo_name_,
+ internal_strlen(vmo_name_));
+
+ // Map the largest possible view we might need into the VMO. Later
+ // we might need to increase the VMO's size before we can use larger
+ // indices, but we'll never move the mapping address so we don't have
+ // any multi-thread synchronization issues with that.
+ uintptr_t mapping;
+ status =
+ _zx_vmar_map(_zx_vmar_root_self(), 0, vmo_, 0, MappingSize,
+ ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &mapping);
+ CHECK_EQ(status, ZX_OK);
+
+ // Hereafter other threads are free to start storing into
+ // elements [1, next_index_) of the big array.
+ array_ = reinterpret_cast<uptr *>(mapping);
+
+ // Store the magic number.
+ // Hereafter, the VMO serves as the contents of the '.sancov' file.
+ array_[0] = Magic64;
+
+ return 1;
+ } else {
+ // The VMO is already mapped in, but it's not big enough to use the
+ // new indices. So increase the size to cover the new maximum index.
+
+ CHECK_NE(vmo_, ZX_HANDLE_INVALID);
+ CHECK_NE(array_, nullptr);
+
+ uint32_t first_index = next_index_;
+ next_index_ += num_guards;
+
+ zx_status_t status = _zx_vmo_set_size(vmo_, DataSize());
+ CHECK_EQ(status, ZX_OK);
+
+ return first_index;
+ }
+ }
+};
+
+static TracePcGuardController pc_guard_controller;
+
+} // namespace
+} // namespace __sancov
+
+namespace __sanitizer {
+void InitializeCoverage(bool enabled, const char *dir) {
+ CHECK_EQ(enabled, common_flags()->coverage);
+ CHECK_EQ(dir, common_flags()->coverage_dir);
+
+ static bool coverage_enabled = false;
+ if (!coverage_enabled) {
+ coverage_enabled = enabled;
+ Atexit(__sanitizer_cov_dump);
+ AddDieCallback(__sanitizer_cov_dump);
+ }
+}
+} // namespace __sanitizer
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT
+ const uptr *pcs, uptr len) {
+ UNIMPLEMENTED();
+}
+
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32 *guard) {
+ if (!*guard) return;
+ __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1);
+}
+
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init,
+ u32 *start, u32 *end) {
+ if (start == end || *start) return;
+ __sancov::pc_guard_controller.InitTracePcGuard(start, end);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() {
+ __sancov::pc_guard_controller.Dump();
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() {
+ __sanitizer_dump_trace_pc_guard_coverage();
+}
+// Default empty implementations (weak). Users should redefine them.
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
+} // extern "C"
+
+#endif // !SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
new file mode 100644
index 0000000..fb78cc0
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_interface.inc
@@ -0,0 +1,31 @@
+//===-- sanitizer_coverage_interface.inc ----------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Sanitizer Coverage interface list.
+//===----------------------------------------------------------------------===//
+INTERFACE_FUNCTION(__sanitizer_cov_dump)
+INTERFACE_FUNCTION(__sanitizer_cov_reset)
+INTERFACE_FUNCTION(__sanitizer_dump_coverage)
+INTERFACE_FUNCTION(__sanitizer_dump_trace_pc_guard_coverage)
+INTERFACE_WEAK_FUNCTION(__sancov_default_options)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp1)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp2)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp4)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp8)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp1)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp2)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp4)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp8)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div4)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div8)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_gep)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_guard_init)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_pc_indir)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_switch)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_8bit_counters_init)
+INTERFACE_WEAK_FUNCTION(__sanitizer_cov_pcs_init)
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc
deleted file mode 100644
index dd8620b..0000000
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep.cc
+++ /dev/null
@@ -1,1043 +0,0 @@
-//===-- sanitizer_coverage.cc ---------------------------------------------===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Sanitizer Coverage.
-// This file implements run-time support for a poor man's coverage tool.
-//
-// Compiler instrumentation:
-// For every interesting basic block the compiler injects the following code:
-// if (Guard < 0) {
-// __sanitizer_cov(&Guard);
-// }
-// At the module start up time __sanitizer_cov_module_init sets the guards
-// to consecutive negative numbers (-1, -2, -3, ...).
-// It's fine to call __sanitizer_cov more than once for a given block.
-//
-// Run-time:
-// - __sanitizer_cov(): record that we've executed the PC (GET_CALLER_PC).
-// and atomically set Guard to -Guard.
-// - __sanitizer_cov_dump: dump the coverage data to disk.
-// For every module of the current process that has coverage data
-// this will create a file module_name.PID.sancov.
-//
-// The file format is simple: the first 8 bytes is the magic,
-// one of 0xC0BFFFFFFFFFFF64 and 0xC0BFFFFFFFFFFF32. The last byte of the
-// magic defines the size of the following offsets.
-// The rest of the data is the offsets in the module.
-//
-// Eventually, this coverage implementation should be obsoleted by a more
-// powerful general purpose Clang/LLVM coverage instrumentation.
-// Consider this implementation as prototype.
-//
-// FIXME: support (or at least test with) dlclose.
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_common.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_mutex.h"
-#include "sanitizer_procmaps.h"
-#include "sanitizer_stacktrace.h"
-#include "sanitizer_symbolizer.h"
-#include "sanitizer_flags.h"
-
-using namespace __sanitizer;
-
-static const u64 kMagic64 = 0xC0BFFFFFFFFFFF64ULL;
-static const u64 kMagic32 = 0xC0BFFFFFFFFFFF32ULL;
-static const uptr kNumWordsForMagic = SANITIZER_WORDSIZE == 64 ? 1 : 2;
-static const u64 kMagic = SANITIZER_WORDSIZE == 64 ? kMagic64 : kMagic32;
-
-static atomic_uint32_t dump_once_guard; // Ensure that CovDump runs only once.
-
-static atomic_uintptr_t coverage_counter;
-static atomic_uintptr_t caller_callee_counter;
-
-static void ResetGlobalCounters() {
- return atomic_store(&coverage_counter, 0, memory_order_relaxed);
- return atomic_store(&caller_callee_counter, 0, memory_order_relaxed);
-}
-
-// pc_array is the array containing the covered PCs.
-// To make the pc_array thread- and async-signal-safe it has to be large enough.
-// 128M counters "ought to be enough for anybody" (4M on 32-bit).
-
-// With coverage_direct=1 in ASAN_OPTIONS, pc_array memory is mapped to a file.
-// In this mode, __sanitizer_cov_dump does nothing, and CovUpdateMapping()
-// dump current memory layout to another file.
-
-static bool cov_sandboxed = false;
-static fd_t cov_fd = kInvalidFd;
-static unsigned int cov_max_block_size = 0;
-static bool coverage_enabled = false;
-static const char *coverage_dir;
-
-namespace __sanitizer {
-
-class CoverageData {
- public:
- void Init();
- void Enable();
- void Disable();
- void ReInit();
- void BeforeFork();
- void AfterFork(int child_pid);
- void Extend(uptr npcs);
- void Add(uptr pc, u32 *guard);
- void IndirCall(uptr caller, uptr callee, uptr callee_cache[],
- uptr cache_size);
- void DumpCallerCalleePairs();
- void DumpTrace();
- void DumpAsBitSet();
- void DumpCounters();
- void DumpOffsets();
- void DumpAll();
-
- ALWAYS_INLINE
- void TraceBasicBlock(u32 *id);
-
- void InitializeGuardArray(s32 *guards);
- void InitializeGuards(s32 *guards, uptr n, const char *module_name,
- uptr caller_pc);
- void InitializeCounters(u8 *counters, uptr n);
- void ReinitializeGuards();
- uptr GetNumberOf8bitCounters();
- uptr Update8bitCounterBitsetAndClearCounters(u8 *bitset);
-
- uptr *data();
- uptr size() const;
-
- private:
- struct NamedPcRange {
- const char *copied_module_name;
- uptr beg, end; // elements [beg,end) in pc_array.
- };
-
- void DirectOpen();
- void UpdateModuleNameVec(uptr caller_pc, uptr range_beg, uptr range_end);
- void GetRangeOffsets(const NamedPcRange& r, Symbolizer* s,
- InternalMmapVector<uptr>* offsets) const;
-
- // Maximal size pc array may ever grow.
- // We MmapNoReserve this space to ensure that the array is contiguous.
- static const uptr kPcArrayMaxSize =
- FIRST_32_SECOND_64(1 << (SANITIZER_ANDROID ? 24 : 26), 1 << 27);
- // The amount file mapping for the pc array is grown by.
- static const uptr kPcArrayMmapSize = 64 * 1024;
-
- // pc_array is allocated with MmapNoReserveOrDie and so it uses only as
- // much RAM as it really needs.
- uptr *pc_array;
- // Index of the first available pc_array slot.
- atomic_uintptr_t pc_array_index;
- // Array size.
- atomic_uintptr_t pc_array_size;
- // Current file mapped size of the pc array.
- uptr pc_array_mapped_size;
- // Descriptor of the file mapped pc array.
- fd_t pc_fd;
-
- // Vector of coverage guard arrays, protected by mu.
- InternalMmapVectorNoCtor<s32*> guard_array_vec;
-
- // Vector of module and compilation unit pc ranges.
- InternalMmapVectorNoCtor<NamedPcRange> comp_unit_name_vec;
- InternalMmapVectorNoCtor<NamedPcRange> module_name_vec;
-
- struct CounterAndSize {
- u8 *counters;
- uptr n;
- };
-
- InternalMmapVectorNoCtor<CounterAndSize> counters_vec;
- uptr num_8bit_counters;
-
- // Caller-Callee (cc) array, size and current index.
- static const uptr kCcArrayMaxSize = FIRST_32_SECOND_64(1 << 18, 1 << 24);
- uptr **cc_array;
- atomic_uintptr_t cc_array_index;
- atomic_uintptr_t cc_array_size;
-
- // Tracing event array, size and current pointer.
- // We record all events (basic block entries) in a global buffer of u32
- // values. Each such value is the index in pc_array.
- // So far the tracing is highly experimental:
- // - not thread-safe;
- // - does not support long traces;
- // - not tuned for performance.
- static const uptr kTrEventArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 30);
- u32 *tr_event_array;
- uptr tr_event_array_size;
- u32 *tr_event_pointer;
- static const uptr kTrPcArrayMaxSize = FIRST_32_SECOND_64(1 << 22, 1 << 27);
-
- StaticSpinMutex mu;
-};
-
-static CoverageData coverage_data;
-
-void CovUpdateMapping(const char *path, uptr caller_pc = 0);
-
-void CoverageData::DirectOpen() {
- InternalScopedString path(kMaxPathLength);
- internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.raw",
- coverage_dir, internal_getpid());
- pc_fd = OpenFile(path.data(), RdWr);
- if (pc_fd == kInvalidFd) {
- Report("Coverage: failed to open %s for reading/writing\n", path.data());
- Die();
- }
-
- pc_array_mapped_size = 0;
- CovUpdateMapping(coverage_dir);
-}
-
-void CoverageData::Init() {
- pc_fd = kInvalidFd;
-}
-
-void CoverageData::Enable() {
- if (pc_array)
- return;
- pc_array = reinterpret_cast<uptr *>(
- MmapNoReserveOrDie(sizeof(uptr) * kPcArrayMaxSize, "CovInit"));
- atomic_store(&pc_array_index, 0, memory_order_relaxed);
- if (common_flags()->coverage_direct) {
- atomic_store(&pc_array_size, 0, memory_order_relaxed);
- } else {
- atomic_store(&pc_array_size, kPcArrayMaxSize, memory_order_relaxed);
- }
-
- cc_array = reinterpret_cast<uptr **>(MmapNoReserveOrDie(
- sizeof(uptr *) * kCcArrayMaxSize, "CovInit::cc_array"));
- atomic_store(&cc_array_size, kCcArrayMaxSize, memory_order_relaxed);
- atomic_store(&cc_array_index, 0, memory_order_relaxed);
-
- // Allocate tr_event_array with a guard page at the end.
- tr_event_array = reinterpret_cast<u32 *>(MmapNoReserveOrDie(
- sizeof(tr_event_array[0]) * kTrEventArrayMaxSize + GetMmapGranularity(),
- "CovInit::tr_event_array"));
- MprotectNoAccess(
- reinterpret_cast<uptr>(&tr_event_array[kTrEventArrayMaxSize]),
- GetMmapGranularity());
- tr_event_array_size = kTrEventArrayMaxSize;
- tr_event_pointer = tr_event_array;
-
- num_8bit_counters = 0;
-}
-
-void CoverageData::InitializeGuardArray(s32 *guards) {
- Enable(); // Make sure coverage is enabled at this point.
- s32 n = guards[0];
- for (s32 j = 1; j <= n; j++) {
- uptr idx = atomic_load_relaxed(&pc_array_index);
- atomic_store_relaxed(&pc_array_index, idx + 1);
- guards[j] = -static_cast<s32>(idx + 1);
- }
-}
-
-void CoverageData::Disable() {
- if (pc_array) {
- UnmapOrDie(pc_array, sizeof(uptr) * kPcArrayMaxSize);
- pc_array = nullptr;
- }
- if (cc_array) {
- UnmapOrDie(cc_array, sizeof(uptr *) * kCcArrayMaxSize);
- cc_array = nullptr;
- }
- if (tr_event_array) {
- UnmapOrDie(tr_event_array,
- sizeof(tr_event_array[0]) * kTrEventArrayMaxSize +
- GetMmapGranularity());
- tr_event_array = nullptr;
- tr_event_pointer = nullptr;
- }
- if (pc_fd != kInvalidFd) {
- CloseFile(pc_fd);
- pc_fd = kInvalidFd;
- }
-}
-
-void CoverageData::ReinitializeGuards() {
- // Assuming single thread.
- atomic_store(&pc_array_index, 0, memory_order_relaxed);
- for (uptr i = 0; i < guard_array_vec.size(); i++)
- InitializeGuardArray(guard_array_vec[i]);
-}
-
-void CoverageData::ReInit() {
- Disable();
- if (coverage_enabled) {
- if (common_flags()->coverage_direct) {
- // In memory-mapped mode we must extend the new file to the known array
- // size.
- uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
- uptr npcs = size / sizeof(uptr);
- Enable();
- if (size) Extend(npcs);
- if (coverage_enabled) CovUpdateMapping(coverage_dir);
- } else {
- Enable();
- }
- }
- // Re-initialize the guards.
- // We are single-threaded now, no need to grab any lock.
- CHECK_EQ(atomic_load(&pc_array_index, memory_order_relaxed), 0);
- ReinitializeGuards();
-}
-
-void CoverageData::BeforeFork() {
- mu.Lock();
-}
-
-void CoverageData::AfterFork(int child_pid) {
- // We are single-threaded so it's OK to release the lock early.
- mu.Unlock();
- if (child_pid == 0) ReInit();
-}
-
-// Extend coverage PC array to fit additional npcs elements.
-void CoverageData::Extend(uptr npcs) {
- if (!common_flags()->coverage_direct) return;
- SpinMutexLock l(&mu);
-
- uptr size = atomic_load(&pc_array_size, memory_order_relaxed);
- size += npcs * sizeof(uptr);
-
- if (coverage_enabled && size > pc_array_mapped_size) {
- if (pc_fd == kInvalidFd) DirectOpen();
- CHECK_NE(pc_fd, kInvalidFd);
-
- uptr new_mapped_size = pc_array_mapped_size;
- while (size > new_mapped_size) new_mapped_size += kPcArrayMmapSize;
- CHECK_LE(new_mapped_size, sizeof(uptr) * kPcArrayMaxSize);
-
- // Extend the file and map the new space at the end of pc_array.
- uptr res = internal_ftruncate(pc_fd, new_mapped_size);
- int err;
- if (internal_iserror(res, &err)) {
- Printf("failed to extend raw coverage file: %d\n", err);
- Die();
- }
-
- uptr next_map_base = ((uptr)pc_array) + pc_array_mapped_size;
- void *p = MapWritableFileToMemory((void *)next_map_base,
- new_mapped_size - pc_array_mapped_size,
- pc_fd, pc_array_mapped_size);
- CHECK_EQ((uptr)p, next_map_base);
- pc_array_mapped_size = new_mapped_size;
- }
-
- atomic_store(&pc_array_size, size, memory_order_release);
-}
-
-void CoverageData::InitializeCounters(u8 *counters, uptr n) {
- if (!counters) return;
- CHECK_EQ(reinterpret_cast<uptr>(counters) % 16, 0);
- n = RoundUpTo(n, 16); // The compiler must ensure that counters is 16-aligned.
- SpinMutexLock l(&mu);
- counters_vec.push_back({counters, n});
- num_8bit_counters += n;
-}
-
-void CoverageData::UpdateModuleNameVec(uptr caller_pc, uptr range_beg,
- uptr range_end) {
- auto sym = Symbolizer::GetOrInit();
- if (!sym)
- return;
- const char *module_name = sym->GetModuleNameForPc(caller_pc);
- if (!module_name) return;
- if (module_name_vec.empty() ||
- module_name_vec.back().copied_module_name != module_name)
- module_name_vec.push_back({module_name, range_beg, range_end});
- else
- module_name_vec.back().end = range_end;
-}
-
-void CoverageData::InitializeGuards(s32 *guards, uptr n,
- const char *comp_unit_name,
- uptr caller_pc) {
- // The array 'guards' has n+1 elements, we use the element zero
- // to store 'n'.
- CHECK_LT(n, 1 << 30);
- guards[0] = static_cast<s32>(n);
- InitializeGuardArray(guards);
- SpinMutexLock l(&mu);
- uptr range_end = atomic_load(&pc_array_index, memory_order_relaxed);
- uptr range_beg = range_end - n;
- comp_unit_name_vec.push_back({comp_unit_name, range_beg, range_end});
- guard_array_vec.push_back(guards);
- UpdateModuleNameVec(caller_pc, range_beg, range_end);
-}
-
-static const uptr kBundleCounterBits = 16;
-
-// When coverage_order_pcs==true and SANITIZER_WORDSIZE==64
-// we insert the global counter into the first 16 bits of the PC.
-uptr BundlePcAndCounter(uptr pc, uptr counter) {
- if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
- return pc;
- static const uptr kMaxCounter = (1 << kBundleCounterBits) - 1;
- if (counter > kMaxCounter)
- counter = kMaxCounter;
- CHECK_EQ(0, pc >> (SANITIZER_WORDSIZE - kBundleCounterBits));
- return pc | (counter << (SANITIZER_WORDSIZE - kBundleCounterBits));
-}
-
-uptr UnbundlePc(uptr bundle) {
- if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
- return bundle;
- return (bundle << kBundleCounterBits) >> kBundleCounterBits;
-}
-
-uptr UnbundleCounter(uptr bundle) {
- if (SANITIZER_WORDSIZE != 64 || !common_flags()->coverage_order_pcs)
- return 0;
- return bundle >> (SANITIZER_WORDSIZE - kBundleCounterBits);
-}
-
-// If guard is negative, atomically set it to -guard and store the PC in
-// pc_array.
-void CoverageData::Add(uptr pc, u32 *guard) {
- atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard);
- s32 guard_value = atomic_load(atomic_guard, memory_order_relaxed);
- if (guard_value >= 0) return;
-
- atomic_store(atomic_guard, -guard_value, memory_order_relaxed);
- if (!pc_array) return;
-
- uptr idx = -guard_value - 1;
- if (idx >= atomic_load(&pc_array_index, memory_order_acquire))
- return; // May happen after fork when pc_array_index becomes 0.
- CHECK_LT(idx * sizeof(uptr),
- atomic_load(&pc_array_size, memory_order_acquire));
- uptr counter = atomic_fetch_add(&coverage_counter, 1, memory_order_relaxed);
- pc_array[idx] = BundlePcAndCounter(pc, counter);
-}
-
-// Registers a pair caller=>callee.
-// When a given caller is seen for the first time, the callee_cache is added
-// to the global array cc_array, callee_cache[0] is set to caller and
-// callee_cache[1] is set to cache_size.
-// Then we are trying to add callee to callee_cache [2,cache_size) if it is
-// not there yet.
-// If the cache is full we drop the callee (may want to fix this later).
-void CoverageData::IndirCall(uptr caller, uptr callee, uptr callee_cache[],
- uptr cache_size) {
- if (!cc_array) return;
- atomic_uintptr_t *atomic_callee_cache =
- reinterpret_cast<atomic_uintptr_t *>(callee_cache);
- uptr zero = 0;
- if (atomic_compare_exchange_strong(&atomic_callee_cache[0], &zero, caller,
- memory_order_seq_cst)) {
- uptr idx = atomic_fetch_add(&cc_array_index, 1, memory_order_relaxed);
- CHECK_LT(idx * sizeof(uptr),
- atomic_load(&cc_array_size, memory_order_acquire));
- callee_cache[1] = cache_size;
- cc_array[idx] = callee_cache;
- }
- CHECK_EQ(atomic_load(&atomic_callee_cache[0], memory_order_relaxed), caller);
- for (uptr i = 2; i < cache_size; i++) {
- uptr was = 0;
- if (atomic_compare_exchange_strong(&atomic_callee_cache[i], &was, callee,
- memory_order_seq_cst)) {
- atomic_fetch_add(&caller_callee_counter, 1, memory_order_relaxed);
- return;
- }
- if (was == callee) // Already have this callee.
- return;
- }
-}
-
-uptr CoverageData::GetNumberOf8bitCounters() {
- return num_8bit_counters;
-}
-
-// Map every 8bit counter to a 8-bit bitset and clear the counter.
-uptr CoverageData::Update8bitCounterBitsetAndClearCounters(u8 *bitset) {
- uptr num_new_bits = 0;
- uptr cur = 0;
- // For better speed we map 8 counters to 8 bytes of bitset at once.
- static const uptr kBatchSize = 8;
- CHECK_EQ(reinterpret_cast<uptr>(bitset) % kBatchSize, 0);
- for (uptr i = 0, len = counters_vec.size(); i < len; i++) {
- u8 *c = counters_vec[i].counters;
- uptr n = counters_vec[i].n;
- CHECK_EQ(n % 16, 0);
- CHECK_EQ(cur % kBatchSize, 0);
- CHECK_EQ(reinterpret_cast<uptr>(c) % kBatchSize, 0);
- if (!bitset) {
- internal_bzero_aligned16(c, n);
- cur += n;
- continue;
- }
- for (uptr j = 0; j < n; j += kBatchSize, cur += kBatchSize) {
- CHECK_LT(cur, num_8bit_counters);
- u64 *pc64 = reinterpret_cast<u64*>(c + j);
- u64 *pb64 = reinterpret_cast<u64*>(bitset + cur);
- u64 c64 = *pc64;
- u64 old_bits_64 = *pb64;
- u64 new_bits_64 = old_bits_64;
- if (c64) {
- *pc64 = 0;
- for (uptr k = 0; k < kBatchSize; k++) {
- u64 x = (c64 >> (8 * k)) & 0xff;
- if (x) {
- u64 bit = 0;
- /**/ if (x >= 128) bit = 128;
- else if (x >= 32) bit = 64;
- else if (x >= 16) bit = 32;
- else if (x >= 8) bit = 16;
- else if (x >= 4) bit = 8;
- else if (x >= 3) bit = 4;
- else if (x >= 2) bit = 2;
- else if (x >= 1) bit = 1;
- u64 mask = bit << (8 * k);
- if (!(new_bits_64 & mask)) {
- num_new_bits++;
- new_bits_64 |= mask;
- }
- }
- }
- *pb64 = new_bits_64;
- }
- }
- }
- CHECK_EQ(cur, num_8bit_counters);
- return num_new_bits;
-}
-
-uptr *CoverageData::data() {
- return pc_array;
-}
-
-uptr CoverageData::size() const {
- return atomic_load(&pc_array_index, memory_order_relaxed);
-}
-
-// Block layout for packed file format: header, followed by module name (no
-// trailing zero), followed by data blob.
-struct CovHeader {
- int pid;
- unsigned int module_name_length;
- unsigned int data_length;
-};
-
-static void CovWritePacked(int pid, const char *module, const void *blob,
- unsigned int blob_size) {
- if (cov_fd == kInvalidFd) return;
- unsigned module_name_length = internal_strlen(module);
- CovHeader header = {pid, module_name_length, blob_size};
-
- if (cov_max_block_size == 0) {
- // Writing to a file. Just go ahead.
- WriteToFile(cov_fd, &header, sizeof(header));
- WriteToFile(cov_fd, module, module_name_length);
- WriteToFile(cov_fd, blob, blob_size);
- } else {
- // Writing to a socket. We want to split the data into appropriately sized
- // blocks.
- InternalScopedBuffer<char> block(cov_max_block_size);
- CHECK_EQ((uptr)block.data(), (uptr)(CovHeader *)block.data());
- uptr header_size_with_module = sizeof(header) + module_name_length;
- CHECK_LT(header_size_with_module, cov_max_block_size);
- unsigned int max_payload_size =
- cov_max_block_size - header_size_with_module;
- char *block_pos = block.data();
- internal_memcpy(block_pos, &header, sizeof(header));
- block_pos += sizeof(header);
- internal_memcpy(block_pos, module, module_name_length);
- block_pos += module_name_length;
- char *block_data_begin = block_pos;
- const char *blob_pos = (const char *)blob;
- while (blob_size > 0) {
- unsigned int payload_size = Min(blob_size, max_payload_size);
- blob_size -= payload_size;
- internal_memcpy(block_data_begin, blob_pos, payload_size);
- blob_pos += payload_size;
- ((CovHeader *)block.data())->data_length = payload_size;
- WriteToFile(cov_fd, block.data(), header_size_with_module + payload_size);
- }
- }
-}
-
-// If packed = false: <name>.<pid>.<sancov> (name = module name).
-// If packed = true and name == 0: <pid>.<sancov>.<packed>.
-// If packed = true and name != 0: <name>.<sancov>.<packed> (name is
-// user-supplied).
-static fd_t CovOpenFile(InternalScopedString *path, bool packed,
- const char *name, const char *extension = "sancov") {
- path->clear();
- if (!packed) {
- CHECK(name);
- path->append("%s/%s.%zd.%s", coverage_dir, name, internal_getpid(),
- extension);
- } else {
- if (!name)
- path->append("%s/%zd.%s.packed", coverage_dir, internal_getpid(),
- extension);
- else
- path->append("%s/%s.%s.packed", coverage_dir, name, extension);
- }
- error_t err;
- fd_t fd = OpenFile(path->data(), WrOnly, &err);
- if (fd == kInvalidFd)
- Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n",
- path->data(), err);
- return fd;
-}
-
-// Dump trace PCs and trace events into two separate files.
-void CoverageData::DumpTrace() {
- uptr max_idx = tr_event_pointer - tr_event_array;
- if (!max_idx) return;
- auto sym = Symbolizer::GetOrInit();
- if (!sym)
- return;
- InternalScopedString out(32 << 20);
- for (uptr i = 0, n = size(); i < n; i++) {
- const char *module_name = "<unknown>";
- uptr module_address = 0;
- sym->GetModuleNameAndOffsetForPC(UnbundlePc(pc_array[i]), &module_name,
- &module_address);
- out.append("%s 0x%zx\n", module_name, module_address);
- }
- InternalScopedString path(kMaxPathLength);
- fd_t fd = CovOpenFile(&path, false, "trace-points");
- if (fd == kInvalidFd) return;
- WriteToFile(fd, out.data(), out.length());
- CloseFile(fd);
-
- fd = CovOpenFile(&path, false, "trace-compunits");
- if (fd == kInvalidFd) return;
- out.clear();
- for (uptr i = 0; i < comp_unit_name_vec.size(); i++)
- out.append("%s\n", comp_unit_name_vec[i].copied_module_name);
- WriteToFile(fd, out.data(), out.length());
- CloseFile(fd);
-
- fd = CovOpenFile(&path, false, "trace-events");
- if (fd == kInvalidFd) return;
- uptr bytes_to_write = max_idx * sizeof(tr_event_array[0]);
- u8 *event_bytes = reinterpret_cast<u8*>(tr_event_array);
- // The trace file could be huge, and may not be written with a single syscall.
- while (bytes_to_write) {
- uptr actually_written;
- if (WriteToFile(fd, event_bytes, bytes_to_write, &actually_written) &&
- actually_written <= bytes_to_write) {
- bytes_to_write -= actually_written;
- event_bytes += actually_written;
- } else {
- break;
- }
- }
- CloseFile(fd);
- VReport(1, " CovDump: Trace: %zd PCs written\n", size());
- VReport(1, " CovDump: Trace: %zd Events written\n", max_idx);
-}
-
-// This function dumps the caller=>callee pairs into a file as a sequence of
-// lines like "module_name offset".
-void CoverageData::DumpCallerCalleePairs() {
- uptr max_idx = atomic_load(&cc_array_index, memory_order_relaxed);
- if (!max_idx) return;
- auto sym = Symbolizer::GetOrInit();
- if (!sym)
- return;
- InternalScopedString out(32 << 20);
- uptr total = 0;
- for (uptr i = 0; i < max_idx; i++) {
- uptr *cc_cache = cc_array[i];
- CHECK(cc_cache);
- uptr caller = cc_cache[0];
- uptr n_callees = cc_cache[1];
- const char *caller_module_name = "<unknown>";
- uptr caller_module_address = 0;
- sym->GetModuleNameAndOffsetForPC(caller, &caller_module_name,
- &caller_module_address);
- for (uptr j = 2; j < n_callees; j++) {
- uptr callee = cc_cache[j];
- if (!callee) break;
- total++;
- const char *callee_module_name = "<unknown>";
- uptr callee_module_address = 0;
- sym->GetModuleNameAndOffsetForPC(callee, &callee_module_name,
- &callee_module_address);
- out.append("%s 0x%zx\n%s 0x%zx\n", caller_module_name,
- caller_module_address, callee_module_name,
- callee_module_address);
- }
- }
- InternalScopedString path(kMaxPathLength);
- fd_t fd = CovOpenFile(&path, false, "caller-callee");
- if (fd == kInvalidFd) return;
- WriteToFile(fd, out.data(), out.length());
- CloseFile(fd);
- VReport(1, " CovDump: %zd caller-callee pairs written\n", total);
-}
-
-// Record the current PC into the event buffer.
-// Every event is a u32 value (index in tr_pc_array_index) so we compute
-// it once and then cache in the provided 'cache' storage.
-//
-// This function will eventually be inlined by the compiler.
-void CoverageData::TraceBasicBlock(u32 *id) {
- // Will trap here if
- // 1. coverage is not enabled at run-time.
- // 2. The array tr_event_array is full.
- *tr_event_pointer = *id - 1;
- tr_event_pointer++;
-}
-
-void CoverageData::DumpCounters() {
- if (!common_flags()->coverage_counters) return;
- uptr n = coverage_data.GetNumberOf8bitCounters();
- if (!n) return;
- InternalScopedBuffer<u8> bitset(n);
- coverage_data.Update8bitCounterBitsetAndClearCounters(bitset.data());
- InternalScopedString path(kMaxPathLength);
-
- for (uptr m = 0; m < module_name_vec.size(); m++) {
- auto r = module_name_vec[m];
- CHECK(r.copied_module_name);
- CHECK_LE(r.beg, r.end);
- CHECK_LE(r.end, size());
- const char *base_name = StripModuleName(r.copied_module_name);
- fd_t fd =
- CovOpenFile(&path, /* packed */ false, base_name, "counters-sancov");
- if (fd == kInvalidFd) return;
- WriteToFile(fd, bitset.data() + r.beg, r.end - r.beg);
- CloseFile(fd);
- VReport(1, " CovDump: %zd counters written for '%s'\n", r.end - r.beg,
- base_name);
- }
-}
-
-void CoverageData::DumpAsBitSet() {
- if (!common_flags()->coverage_bitset) return;
- if (!size()) return;
- InternalScopedBuffer<char> out(size());
- InternalScopedString path(kMaxPathLength);
- for (uptr m = 0; m < module_name_vec.size(); m++) {
- uptr n_set_bits = 0;
- auto r = module_name_vec[m];
- CHECK(r.copied_module_name);
- CHECK_LE(r.beg, r.end);
- CHECK_LE(r.end, size());
- for (uptr i = r.beg; i < r.end; i++) {
- uptr pc = UnbundlePc(pc_array[i]);
- out[i] = pc ? '1' : '0';
- if (pc)
- n_set_bits++;
- }
- const char *base_name = StripModuleName(r.copied_module_name);
- fd_t fd = CovOpenFile(&path, /* packed */false, base_name, "bitset-sancov");
- if (fd == kInvalidFd) return;
- WriteToFile(fd, out.data() + r.beg, r.end - r.beg);
- CloseFile(fd);
- VReport(1,
- " CovDump: bitset of %zd bits written for '%s', %zd bits are set\n",
- r.end - r.beg, base_name, n_set_bits);
- }
-}
-
-
-void CoverageData::GetRangeOffsets(const NamedPcRange& r, Symbolizer* sym,
- InternalMmapVector<uptr>* offsets) const {
- offsets->clear();
- for (uptr i = 0; i < kNumWordsForMagic; i++)
- offsets->push_back(0);
- CHECK(r.copied_module_name);
- CHECK_LE(r.beg, r.end);
- CHECK_LE(r.end, size());
- for (uptr i = r.beg; i < r.end; i++) {
- uptr pc = UnbundlePc(pc_array[i]);
- uptr counter = UnbundleCounter(pc_array[i]);
- if (!pc) continue; // Not visited.
- uptr offset = 0;
- sym->GetModuleNameAndOffsetForPC(pc, nullptr, &offset);
- offsets->push_back(BundlePcAndCounter(offset, counter));
- }
-
- CHECK_GE(offsets->size(), kNumWordsForMagic);
- SortArray(offsets->data(), offsets->size());
- for (uptr i = 0; i < offsets->size(); i++)
- (*offsets)[i] = UnbundlePc((*offsets)[i]);
-}
-
-static void GenerateHtmlReport(const InternalMmapVector<char *> &cov_files) {
- if (!common_flags()->html_cov_report) {
- return;
- }
- char *sancov_path = FindPathToBinary(common_flags()->sancov_path);
- if (sancov_path == nullptr) {
- return;
- }
-
- InternalMmapVector<char *> sancov_argv(cov_files.size() * 2 + 3);
- sancov_argv.push_back(sancov_path);
- sancov_argv.push_back(internal_strdup("-html-report"));
- auto argv_deleter = at_scope_exit([&] {
- for (uptr i = 0; i < sancov_argv.size(); ++i) {
- InternalFree(sancov_argv[i]);
- }
- });
-
- for (const auto &cov_file : cov_files) {
- sancov_argv.push_back(internal_strdup(cov_file));
- }
-
- {
- ListOfModules modules;
- modules.init();
- for (const LoadedModule &module : modules) {
- sancov_argv.push_back(internal_strdup(module.full_name()));
- }
- }
-
- InternalScopedString report_path(kMaxPathLength);
- fd_t report_fd =
- CovOpenFile(&report_path, false /* packed */, GetProcessName(), "html");
- int pid = StartSubprocess(sancov_argv[0], sancov_argv.data(),
- kInvalidFd /* stdin */, report_fd /* std_out */);
- if (pid > 0) {
- int result = WaitForProcess(pid);
- if (result == 0)
- Printf("coverage report generated to %s\n", report_path.data());
- }
-}
-
-void CoverageData::DumpOffsets() {
- auto sym = Symbolizer::GetOrInit();
- if (!common_flags()->coverage_pcs) return;
- CHECK_NE(sym, nullptr);
- InternalMmapVector<uptr> offsets(0);
- InternalScopedString path(kMaxPathLength);
-
- InternalMmapVector<char *> cov_files(module_name_vec.size());
- auto cov_files_deleter = at_scope_exit([&] {
- for (uptr i = 0; i < cov_files.size(); ++i) {
- InternalFree(cov_files[i]);
- }
- });
-
- for (uptr m = 0; m < module_name_vec.size(); m++) {
- auto r = module_name_vec[m];
- GetRangeOffsets(r, sym, &offsets);
-
- uptr num_offsets = offsets.size() - kNumWordsForMagic;
- u64 *magic_p = reinterpret_cast<u64*>(offsets.data());
- CHECK_EQ(*magic_p, 0ULL);
- // FIXME: we may want to write 32-bit offsets even in 64-mode
- // if all the offsets are small enough.
- *magic_p = kMagic;
-
- const char *module_name = StripModuleName(r.copied_module_name);
- if (cov_sandboxed) {
- if (cov_fd != kInvalidFd) {
- CovWritePacked(internal_getpid(), module_name, offsets.data(),
- offsets.size() * sizeof(offsets[0]));
- VReport(1, " CovDump: %zd PCs written to packed file\n", num_offsets);
- }
- } else {
- // One file per module per process.
- fd_t fd = CovOpenFile(&path, false /* packed */, module_name);
- if (fd == kInvalidFd) continue;
- WriteToFile(fd, offsets.data(), offsets.size() * sizeof(offsets[0]));
- CloseFile(fd);
- cov_files.push_back(internal_strdup(path.data()));
- VReport(1, " CovDump: %s: %zd PCs written\n", path.data(), num_offsets);
- }
- }
- if (cov_fd != kInvalidFd)
- CloseFile(cov_fd);
-
- GenerateHtmlReport(cov_files);
-}
-
-void CoverageData::DumpAll() {
- if (!coverage_enabled || common_flags()->coverage_direct) return;
- if (atomic_fetch_add(&dump_once_guard, 1, memory_order_relaxed))
- return;
- DumpAsBitSet();
- DumpCounters();
- DumpTrace();
- DumpOffsets();
- DumpCallerCalleePairs();
-}
-
-void CovPrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
- if (!args) return;
- if (!coverage_enabled) return;
- cov_sandboxed = args->coverage_sandboxed;
- if (!cov_sandboxed) return;
- cov_max_block_size = args->coverage_max_block_size;
- if (args->coverage_fd >= 0) {
- cov_fd = (fd_t)args->coverage_fd;
- } else {
- InternalScopedString path(kMaxPathLength);
- // Pre-open the file now. The sandbox won't allow us to do it later.
- cov_fd = CovOpenFile(&path, true /* packed */, nullptr);
- }
-}
-
-fd_t MaybeOpenCovFile(const char *name) {
- CHECK(name);
- if (!coverage_enabled) return kInvalidFd;
- InternalScopedString path(kMaxPathLength);
- return CovOpenFile(&path, true /* packed */, name);
-}
-
-void CovBeforeFork() {
- coverage_data.BeforeFork();
-}
-
-void CovAfterFork(int child_pid) {
- coverage_data.AfterFork(child_pid);
-}
-
-static void MaybeDumpCoverage() {
- if (common_flags()->coverage)
- __sanitizer_cov_dump();
-}
-
-void InitializeCoverage(bool enabled, const char *dir) {
- if (coverage_enabled)
- return; // May happen if two sanitizer enable coverage in the same process.
- coverage_enabled = enabled;
- coverage_dir = dir;
- coverage_data.Init();
- if (enabled) coverage_data.Enable();
- if (!common_flags()->coverage_direct) Atexit(__sanitizer_cov_dump);
- AddDieCallback(MaybeDumpCoverage);
-}
-
-void ReInitializeCoverage(bool enabled, const char *dir) {
- coverage_enabled = enabled;
- coverage_dir = dir;
- coverage_data.ReInit();
-}
-
-void CoverageUpdateMapping() {
- if (coverage_enabled)
- CovUpdateMapping(coverage_dir);
-}
-
-} // namespace __sanitizer
-
-extern "C" {
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(u32 *guard) {
- coverage_data.Add(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
- guard);
-}
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_with_check(u32 *guard) {
- atomic_uint32_t *atomic_guard = reinterpret_cast<atomic_uint32_t*>(guard);
- if (static_cast<s32>(
- __sanitizer::atomic_load(atomic_guard, memory_order_relaxed)) < 0)
- __sanitizer_cov(guard);
-}
-SANITIZER_INTERFACE_ATTRIBUTE void
-__sanitizer_cov_indir_call16(uptr callee, uptr callee_cache16[]) {
- coverage_data.IndirCall(StackTrace::GetPreviousInstructionPc(GET_CALLER_PC()),
- callee, callee_cache16, 16);
-}
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init() {
- coverage_enabled = true;
- coverage_dir = common_flags()->coverage_dir;
- coverage_data.Init();
-}
-SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() {
- coverage_data.DumpAll();
-}
-SANITIZER_INTERFACE_ATTRIBUTE void
-__sanitizer_cov_module_init(s32 *guards, uptr npcs, u8 *counters,
- const char *comp_unit_name) {
- coverage_data.InitializeGuards(guards, npcs, comp_unit_name, GET_CALLER_PC());
- coverage_data.InitializeCounters(counters, npcs);
- if (!common_flags()->coverage_direct) return;
- if (SANITIZER_ANDROID && coverage_enabled) {
- // dlopen/dlclose interceptors do not work on Android, so we rely on
- // Extend() calls to update .sancov.map.
- CovUpdateMapping(coverage_dir, GET_CALLER_PC());
- }
- coverage_data.Extend(npcs);
-}
-SANITIZER_INTERFACE_ATTRIBUTE
-sptr __sanitizer_maybe_open_cov_file(const char *name) {
- return (sptr)MaybeOpenCovFile(name);
-}
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __sanitizer_get_total_unique_coverage() {
- return atomic_load(&coverage_counter, memory_order_relaxed);
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __sanitizer_get_total_unique_caller_callee_pairs() {
- return atomic_load(&caller_callee_counter, memory_order_relaxed);
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_cov_trace_func_enter(u32 *id) {
- __sanitizer_cov_with_check(id);
- coverage_data.TraceBasicBlock(id);
-}
-SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_cov_trace_basic_block(u32 *id) {
- __sanitizer_cov_with_check(id);
- coverage_data.TraceBasicBlock(id);
-}
-SANITIZER_INTERFACE_ATTRIBUTE
-void __sanitizer_reset_coverage() {
- ResetGlobalCounters();
- coverage_data.ReinitializeGuards();
- internal_bzero_aligned16(
- coverage_data.data(),
- RoundUpTo(coverage_data.size() * sizeof(coverage_data.data()[0]), 16));
-}
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __sanitizer_get_coverage_guards(uptr **data) {
- *data = coverage_data.data();
- return coverage_data.size();
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __sanitizer_get_number_of_counters() {
- return coverage_data.GetNumberOf8bitCounters();
-}
-
-SANITIZER_INTERFACE_ATTRIBUTE
-uptr __sanitizer_update_counter_bitset_and_clear_counters(u8 *bitset) {
- return coverage_data.Update8bitCounterBitsetAndClearCounters(bitset);
-}
-// Default empty implementations (weak). Users should redefine them.
-#if !SANITIZER_WINDOWS // weak does not work on Windows.
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_cmp() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_cmp1() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_cmp2() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_cmp4() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_cmp8() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_switch() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_div4() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_div8() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_gep() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_pc_guard() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_pc_indir() {}
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void __sanitizer_cov_trace_pc_guard_init() {}
-#endif // !SANITIZER_WINDOWS
-} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cc
new file mode 100644
index 0000000..25a5001
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_libcdep_new.cc
@@ -0,0 +1,218 @@
+//===-- sanitizer_coverage_libcdep_new.cc ---------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Sanitizer Coverage Controller for Trace PC Guard.
+
+#include "sanitizer_platform.h"
+
+#if !SANITIZER_FUCHSIA
+#include "sancov_flags.h"
+#include "sanitizer_allocator_internal.h"
+#include "sanitizer_atomic.h"
+#include "sanitizer_common.h"
+#include "sanitizer_file.h"
+#include "sanitizer_symbolizer.h"
+
+using namespace __sanitizer;
+
+using AddressRange = LoadedModule::AddressRange;
+
+namespace __sancov {
+namespace {
+
+static const u64 Magic64 = 0xC0BFFFFFFFFFFF64ULL;
+static const u64 Magic32 = 0xC0BFFFFFFFFFFF32ULL;
+static const u64 Magic = SANITIZER_WORDSIZE == 64 ? Magic64 : Magic32;
+
+static fd_t OpenFile(const char* path) {
+ error_t err;
+ fd_t fd = OpenFile(path, WrOnly, &err);
+ if (fd == kInvalidFd)
+ Report("SanitizerCoverage: failed to open %s for writing (reason: %d)\n",
+ path, err);
+ return fd;
+}
+
+static void GetCoverageFilename(char* path, const char* name,
+ const char* extension) {
+ CHECK(name);
+ internal_snprintf(path, kMaxPathLength, "%s/%s.%zd.%s",
+ common_flags()->coverage_dir, name, internal_getpid(),
+ extension);
+}
+
+static void WriteModuleCoverage(char* file_path, const char* module_name,
+ const uptr* pcs, uptr len) {
+ GetCoverageFilename(file_path, StripModuleName(module_name), "sancov");
+ fd_t fd = OpenFile(file_path);
+ WriteToFile(fd, &Magic, sizeof(Magic));
+ WriteToFile(fd, pcs, len * sizeof(*pcs));
+ CloseFile(fd);
+ Printf("SanitizerCoverage: %s: %zd PCs written\n", file_path, len);
+}
+
+static void SanitizerDumpCoverage(const uptr* unsorted_pcs, uptr len) {
+ if (!len) return;
+
+ char* file_path = static_cast<char*>(InternalAlloc(kMaxPathLength));
+ char* module_name = static_cast<char*>(InternalAlloc(kMaxPathLength));
+ uptr* pcs = static_cast<uptr*>(InternalAlloc(len * sizeof(uptr)));
+
+ internal_memcpy(pcs, unsorted_pcs, len * sizeof(uptr));
+ SortArray(pcs, len);
+
+ bool module_found = false;
+ uptr last_base = 0;
+ uptr module_start_idx = 0;
+
+ for (uptr i = 0; i < len; ++i) {
+ const uptr pc = pcs[i];
+ if (!pc) continue;
+
+ if (!__sanitizer_get_module_and_offset_for_pc(pc, nullptr, 0, &pcs[i])) {
+ Printf("ERROR: unknown pc 0x%x (may happen if dlclose is used)\n", pc);
+ continue;
+ }
+ uptr module_base = pc - pcs[i];
+
+ if (module_base != last_base || !module_found) {
+ if (module_found) {
+ WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx],
+ i - module_start_idx);
+ }
+
+ last_base = module_base;
+ module_start_idx = i;
+ module_found = true;
+ __sanitizer_get_module_and_offset_for_pc(pc, module_name, kMaxPathLength,
+ &pcs[i]);
+ }
+ }
+
+ if (module_found) {
+ WriteModuleCoverage(file_path, module_name, &pcs[module_start_idx],
+ len - module_start_idx);
+ }
+
+ InternalFree(file_path);
+ InternalFree(module_name);
+ InternalFree(pcs);
+}
+
+// Collects trace-pc guard coverage.
+// This class relies on zero-initialization.
+class TracePcGuardController {
+ public:
+ void Initialize() {
+ CHECK(!initialized);
+
+ initialized = true;
+ InitializeSancovFlags();
+
+ pc_vector.Initialize(0);
+ }
+
+ void InitTracePcGuard(u32* start, u32* end) {
+ if (!initialized) Initialize();
+ CHECK(!*start);
+ CHECK_NE(start, end);
+
+ u32 i = pc_vector.size();
+ for (u32* p = start; p < end; p++) *p = ++i;
+ pc_vector.resize(i);
+ }
+
+ void TracePcGuard(u32* guard, uptr pc) {
+ u32 idx = *guard;
+ if (!idx) return;
+ // we start indices from 1.
+ atomic_uintptr_t* pc_ptr =
+ reinterpret_cast<atomic_uintptr_t*>(&pc_vector[idx - 1]);
+ if (atomic_load(pc_ptr, memory_order_relaxed) == 0)
+ atomic_store(pc_ptr, pc, memory_order_relaxed);
+ }
+
+ void Reset() {
+ internal_memset(&pc_vector[0], 0, sizeof(pc_vector[0]) * pc_vector.size());
+ }
+
+ void Dump() {
+ if (!initialized || !common_flags()->coverage) return;
+ __sanitizer_dump_coverage(pc_vector.data(), pc_vector.size());
+ }
+
+ private:
+ bool initialized;
+ InternalMmapVectorNoCtor<uptr> pc_vector;
+};
+
+static TracePcGuardController pc_guard_controller;
+
+} // namespace
+} // namespace __sancov
+
+namespace __sanitizer {
+void InitializeCoverage(bool enabled, const char *dir) {
+ static bool coverage_enabled = false;
+ if (coverage_enabled)
+ return; // May happen if two sanitizer enable coverage in the same process.
+ coverage_enabled = enabled;
+ Atexit(__sanitizer_cov_dump);
+ AddDieCallback(__sanitizer_cov_dump);
+}
+} // namespace __sanitizer
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage( // NOLINT
+ const uptr* pcs, uptr len) {
+ return __sancov::SanitizerDumpCoverage(pcs, len);
+}
+
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard, u32* guard) {
+ if (!*guard) return;
+ __sancov::pc_guard_controller.TracePcGuard(guard, GET_CALLER_PC() - 1);
+}
+
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_guard_init,
+ u32* start, u32* end) {
+ if (start == end || *start) return;
+ __sancov::pc_guard_controller.InitTracePcGuard(start, end);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage() {
+ __sancov::pc_guard_controller.Dump();
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump() {
+ __sanitizer_dump_trace_pc_guard_coverage();
+}
+SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_reset() {
+ __sancov::pc_guard_controller.Reset();
+}
+// Default empty implementations (weak). Users should redefine them.
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp1, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_gep, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_pc_indir, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_8bit_counters_init, void) {}
+SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_pcs_init, void) {}
+} // extern "C"
+// Weak definition for code instrumented with -fsanitize-coverage=stack-depth
+// and later linked with code containing a strong definition.
+// E.g., -fsanitize=fuzzer-no-link
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE uptr __sancov_lowest_stack;
+
+#endif // !SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
deleted file mode 100644
index b2e724a..0000000
--- a/libsanitizer/sanitizer_common/sanitizer_coverage_mapping_libcdep.cc
+++ /dev/null
@@ -1,120 +0,0 @@
-//===-- sanitizer_coverage_mapping.cc -------------------------------------===//
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Mmap-based implementation of sanitizer coverage.
-//
-// This is part of the implementation of code coverage that does not require
-// __sanitizer_cov_dump() call. Data is stored in 2 files per process.
-//
-// $pid.sancov.map describes process memory layout in the following text-based
-// format:
-// <pointer size in bits> // 1 line, 32 or 64
-// <mapping start> <mapping end> <base address> <dso name> // repeated
-// ...
-// Mapping lines are NOT sorted. This file is updated every time memory layout
-// is changed (i.e. in dlopen() and dlclose() interceptors).
-//
-// $pid.sancov.raw is a binary dump of PC values, sizeof(uptr) each. Again, not
-// sorted. This file is extended by 64Kb at a time and mapped into memory. It
-// contains one or more 0 words at the end, up to the next 64Kb aligned offset.
-//
-// To convert these 2 files to the usual .sancov format, run sancov.py rawunpack
-// $pid.sancov.raw.
-//
-//===----------------------------------------------------------------------===//
-
-#include "sanitizer_allocator_internal.h"
-#include "sanitizer_libc.h"
-#include "sanitizer_procmaps.h"
-
-namespace __sanitizer {
-
-static const uptr kMaxTextSize = 64 * 1024;
-
-struct CachedMapping {
- public:
- bool NeedsUpdate(uptr pc) {
- int new_pid = internal_getpid();
- if (last_pid == new_pid && pc && pc >= last_range_start &&
- pc < last_range_end)
- return false;
- last_pid = new_pid;
- return true;
- }
-
- void SetModuleRange(uptr start, uptr end) {
- last_range_start = start;
- last_range_end = end;
- }
-
- private:
- uptr last_range_start, last_range_end;
- int last_pid;
-};
-
-static CachedMapping cached_mapping;
-static StaticSpinMutex mapping_mu;
-
-void CovUpdateMapping(const char *coverage_dir, uptr caller_pc) {
- if (!common_flags()->coverage_direct) return;
-
- SpinMutexLock l(&mapping_mu);
-
- if (!cached_mapping.NeedsUpdate(caller_pc))
- return;
-
- InternalScopedString text(kMaxTextSize);
-
- {
- text.append("%d\n", sizeof(uptr) * 8);
- ListOfModules modules;
- modules.init();
- for (const LoadedModule &module : modules) {
- const char *module_name = StripModuleName(module.full_name());
- uptr base = module.base_address();
- for (const auto &range : module.ranges()) {
- if (range.executable) {
- uptr start = range.beg;
- uptr end = range.end;
- text.append("%zx %zx %zx %s\n", start, end, base, module_name);
- if (caller_pc && caller_pc >= start && caller_pc < end)
- cached_mapping.SetModuleRange(start, end);
- }
- }
- }
- }
-
- error_t err;
- InternalScopedString tmp_path(64 + internal_strlen(coverage_dir));
- uptr res = internal_snprintf((char *)tmp_path.data(), tmp_path.size(),
- "%s/%zd.sancov.map.tmp", coverage_dir,
- internal_getpid());
- CHECK_LE(res, tmp_path.size());
- fd_t map_fd = OpenFile(tmp_path.data(), WrOnly, &err);
- if (map_fd == kInvalidFd) {
- Report("Coverage: failed to open %s for writing: %d\n", tmp_path.data(),
- err);
- Die();
- }
-
- if (!WriteToFile(map_fd, text.data(), text.length(), nullptr, &err)) {
- Printf("sancov.map write failed: %d\n", err);
- Die();
- }
- CloseFile(map_fd);
-
- InternalScopedString path(64 + internal_strlen(coverage_dir));
- res = internal_snprintf((char *)path.data(), path.size(), "%s/%zd.sancov.map",
- coverage_dir, internal_getpid());
- CHECK_LE(res, path.size());
- if (!RenameFile(tmp_path.data(), path.data(), &err)) {
- Printf("sancov.map rename failed: %d\n", err);
- Die();
- }
-}
-
-} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cc
new file mode 100644
index 0000000..5aea120
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_win_dll_thunk.cc
@@ -0,0 +1,19 @@
+//===-- sanitizer_coverage_win_dll_thunk.cc -------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a family of thunks that should be statically linked into
+// the DLLs that have instrumentation in order to delegate the calls to the
+// shared runtime that lives in the main binary.
+// See https://github.com/google/sanitizers/issues/209 for the details.
+//===----------------------------------------------------------------------===//
+#ifdef SANITIZER_DLL_THUNK
+#include "sanitizer_win_dll_thunk.h"
+// Sanitizer Coverage interface functions.
+#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
+#include "sanitizer_coverage_interface.inc"
+#endif // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cc
new file mode 100644
index 0000000..939f395
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_win_dynamic_runtime_thunk.cc
@@ -0,0 +1,19 @@
+//===-- sanitizer_coverage_win_dynamic_runtime_thunk.cc -------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines things that need to be present in the application modules
+// to interact with Sanitizer Coverage, when it is included in a dll.
+//
+//===----------------------------------------------------------------------===//
+#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
+#define SANITIZER_IMPORT_INTERFACE 1
+#include "sanitizer_win_defs.h"
+// Define weak alias for all weak functions imported from sanitizer coverage.
+#define INTERFACE_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
+#include "sanitizer_coverage_interface.inc"
+#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_win_sections.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_win_sections.cc
new file mode 100644
index 0000000..485dd45
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_win_sections.cc
@@ -0,0 +1,20 @@
+//===-- sanitizer_coverage_win_sections.cc --------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines delimiters for Sanitizer Coverage's section.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+#include <stdint.h>
+#pragma section(".SCOV$A", read, write) // NOLINT
+#pragma section(".SCOV$Z", read, write) // NOLINT
+extern "C" {
+__declspec(allocate(".SCOV$A")) uint32_t __start___sancov_guards = 0;
+__declspec(allocate(".SCOV$Z")) uint32_t __stop___sancov_guards = 0;
+}
+#endif // SANITIZER_WINDOWS
diff --git a/libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cc b/libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cc
new file mode 100644
index 0000000..64718df
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_coverage_win_weak_interception.cc
@@ -0,0 +1,22 @@
+//===-- sanitizer_coverage_win_weak_interception.cc -----------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This module should be included in Sanitizer Coverage when it implemented as a
+// shared library on Windows (dll), in order to delegate the calls of weak
+// functions to the implementation in the main executable when a strong
+// definition is provided.
+//===----------------------------------------------------------------------===//
+#ifdef SANITIZER_DYNAMIC
+#include "sanitizer_win_weak_interception.h"
+#include "sanitizer_interface_internal.h"
+#include "sancov_flags.h"
+// Check if strong definitions for weak functions are present in the main
+// executable. If that is the case, override dll functions to point to strong
+// implementations.
+#define INTERFACE_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
+#include "sanitizer_coverage_interface.inc"
+#endif // SANITIZER_DYNAMIC
diff --git a/libsanitizer/sanitizer_common/sanitizer_dbghelp.h b/libsanitizer/sanitizer_common/sanitizer_dbghelp.h
new file mode 100644
index 0000000..bad17a9
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_dbghelp.h
@@ -0,0 +1,40 @@
+//===-- sanitizer_dbghelp.h ------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Wrappers for lazy loaded dbghelp.dll. Provides function pointers and a
+// callback to initialize them.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_SYMBOLIZER_WIN_H
+#define SANITIZER_SYMBOLIZER_WIN_H
+
+#if !SANITIZER_WINDOWS
+#error "sanitizer_dbghelp.h is a Windows-only header"
+#endif
+
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <dbghelp.h>
+
+namespace __sanitizer {
+
+extern decltype(::StackWalk64) *StackWalk64;
+extern decltype(::SymCleanup) *SymCleanup;
+extern decltype(::SymFromAddr) *SymFromAddr;
+extern decltype(::SymFunctionTableAccess64) *SymFunctionTableAccess64;
+extern decltype(::SymGetLineFromAddr64) *SymGetLineFromAddr64;
+extern decltype(::SymGetModuleBase64) *SymGetModuleBase64;
+extern decltype(::SymGetSearchPathW) *SymGetSearchPathW;
+extern decltype(::SymInitialize) *SymInitialize;
+extern decltype(::SymSetOptions) *SymSetOptions;
+extern decltype(::SymSetSearchPathW) *SymSetSearchPathW;
+extern decltype(::UnDecorateSymbolName) *UnDecorateSymbolName;
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_SYMBOLIZER_WIN_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_errno.cc b/libsanitizer/sanitizer_common/sanitizer_errno.cc
new file mode 100644
index 0000000..b65f0e7
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_errno.cc
@@ -0,0 +1,33 @@
+//===-- sanitizer_errno.cc --------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers run-time libraries.
+//
+// Defines errno to avoid including errno.h and its dependencies into other
+// files (e.g. interceptors are not supposed to include any system headers).
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_errno_codes.h"
+#include "sanitizer_internal_defs.h"
+
+#include <errno.h>
+
+namespace __sanitizer {
+
+COMPILER_CHECK(errno_ENOMEM == ENOMEM);
+COMPILER_CHECK(errno_EBUSY == EBUSY);
+COMPILER_CHECK(errno_EINVAL == EINVAL);
+
+// EOWNERDEAD is not present in some older platforms.
+#if defined(EOWNERDEAD)
+extern const int errno_EOWNERDEAD = EOWNERDEAD;
+#else
+extern const int errno_EOWNERDEAD = -1;
+#endif
+
+} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_errno.h b/libsanitizer/sanitizer_common/sanitizer_errno.h
new file mode 100644
index 0000000..e9fc00f
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_errno.h
@@ -0,0 +1,35 @@
+//===-- sanitizer_errno.h ---------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers run-time libraries.
+//
+// Defines errno to avoid including errno.h and its dependencies into sensitive
+// files (e.g. interceptors are not supposed to include any system headers).
+// It's ok to use errno.h directly when your file already depend on other system
+// includes though.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ERRNO_H
+#define SANITIZER_ERRNO_H
+
+#include "sanitizer_errno_codes.h"
+#include "sanitizer_platform.h"
+
+#if SANITIZER_FREEBSD || SANITIZER_MAC
+# define __errno_location __error
+#elif SANITIZER_ANDROID || SANITIZER_NETBSD
+# define __errno_location __errno
+#elif SANITIZER_WINDOWS
+# define __errno_location _errno
+#endif
+
+extern "C" int *__errno_location();
+
+#define errno (*__errno_location())
+
+#endif // SANITIZER_ERRNO_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_errno_codes.h b/libsanitizer/sanitizer_common/sanitizer_errno_codes.h
new file mode 100644
index 0000000..709f43b
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_errno_codes.h
@@ -0,0 +1,32 @@
+//===-- sanitizer_errno_codes.h ---------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between sanitizers run-time libraries.
+//
+// Defines errno codes to avoid including errno.h and its dependencies into
+// sensitive files (e.g. interceptors are not supposed to include any system
+// headers).
+// It's ok to use errno.h directly when your file already depend on other system
+// includes though.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_ERRNO_CODES_H
+#define SANITIZER_ERRNO_CODES_H
+
+namespace __sanitizer {
+
+#define errno_ENOMEM 12
+#define errno_EBUSY 16
+#define errno_EINVAL 22
+
+// Those might not present or their value differ on different platforms.
+extern const int errno_EOWNERDEAD;
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_ERRNO_CODES_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_file.cc b/libsanitizer/sanitizer_common/sanitizer_file.cc
new file mode 100644
index 0000000..8740dbb
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_file.cc
@@ -0,0 +1,175 @@
+//===-- sanitizer_file.cc ------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and ThreadSanitizer
+// run-time libraries. It defines filesystem-related interfaces. This
+// is separate from sanitizer_common.cc so that it's simpler to disable
+// all the filesystem support code for a port that doesn't use it.
+//
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if !SANITIZER_FUCHSIA
+
+#include "sanitizer_common.h"
+#include "sanitizer_file.h"
+
+namespace __sanitizer {
+
+void CatastrophicErrorWrite(const char *buffer, uptr length) {
+ WriteToFile(kStderrFd, buffer, length);
+}
+
+StaticSpinMutex report_file_mu;
+ReportFile report_file = {&report_file_mu, kStderrFd, "", "", 0};
+
+void RawWrite(const char *buffer) {
+ report_file.Write(buffer, internal_strlen(buffer));
+}
+
+void ReportFile::ReopenIfNecessary() {
+ mu->CheckLocked();
+ if (fd == kStdoutFd || fd == kStderrFd) return;
+
+ uptr pid = internal_getpid();
+ // If in tracer, use the parent's file.
+ if (pid == stoptheworld_tracer_pid)
+ pid = stoptheworld_tracer_ppid;
+ if (fd != kInvalidFd) {
+ // If the report file is already opened by the current process,
+ // do nothing. Otherwise the report file was opened by the parent
+ // process, close it now.
+ if (fd_pid == pid)
+ return;
+ else
+ CloseFile(fd);
+ }
+
+ const char *exe_name = GetProcessName();
+ if (common_flags()->log_exe_name && exe_name) {
+ internal_snprintf(full_path, kMaxPathLength, "%s.%s.%zu", path_prefix,
+ exe_name, pid);
+ } else {
+ internal_snprintf(full_path, kMaxPathLength, "%s.%zu", path_prefix, pid);
+ }
+ fd = OpenFile(full_path, WrOnly);
+ if (fd == kInvalidFd) {
+ const char *ErrorMsgPrefix = "ERROR: Can't open file: ";
+ WriteToFile(kStderrFd, ErrorMsgPrefix, internal_strlen(ErrorMsgPrefix));
+ WriteToFile(kStderrFd, full_path, internal_strlen(full_path));
+ Die();
+ }
+ fd_pid = pid;
+}
+
+void ReportFile::SetReportPath(const char *path) {
+ if (!path)
+ return;
+ uptr len = internal_strlen(path);
+ if (len > sizeof(path_prefix) - 100) {
+ Report("ERROR: Path is too long: %c%c%c%c%c%c%c%c...\n",
+ path[0], path[1], path[2], path[3],
+ path[4], path[5], path[6], path[7]);
+ Die();
+ }
+
+ SpinMutexLock l(mu);
+ if (fd != kStdoutFd && fd != kStderrFd && fd != kInvalidFd)
+ CloseFile(fd);
+ fd = kInvalidFd;
+ if (internal_strcmp(path, "stdout") == 0) {
+ fd = kStdoutFd;
+ } else if (internal_strcmp(path, "stderr") == 0) {
+ fd = kStderrFd;
+ } else {
+ internal_snprintf(path_prefix, kMaxPathLength, "%s", path);
+ }
+}
+
+bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
+ uptr *read_len, uptr max_len, error_t *errno_p) {
+ uptr PageSize = GetPageSizeCached();
+ uptr kMinFileLen = PageSize;
+ *buff = nullptr;
+ *buff_size = 0;
+ *read_len = 0;
+ // The files we usually open are not seekable, so try different buffer sizes.
+ for (uptr size = kMinFileLen; size <= max_len; size *= 2) {
+ fd_t fd = OpenFile(file_name, RdOnly, errno_p);
+ if (fd == kInvalidFd) return false;
+ UnmapOrDie(*buff, *buff_size);
+ *buff = (char*)MmapOrDie(size, __func__);
+ *buff_size = size;
+ *read_len = 0;
+ // Read up to one page at a time.
+ bool reached_eof = false;
+ while (*read_len + PageSize <= size) {
+ uptr just_read;
+ if (!ReadFromFile(fd, *buff + *read_len, PageSize, &just_read, errno_p)) {
+ UnmapOrDie(*buff, *buff_size);
+ return false;
+ }
+ if (just_read == 0) {
+ reached_eof = true;
+ break;
+ }
+ *read_len += just_read;
+ }
+ CloseFile(fd);
+ if (reached_eof) // We've read the whole file.
+ break;
+ }
+ return true;
+}
+
+static const char kPathSeparator = SANITIZER_WINDOWS ? ';' : ':';
+
+char *FindPathToBinary(const char *name) {
+ if (FileExists(name)) {
+ return internal_strdup(name);
+ }
+
+ const char *path = GetEnv("PATH");
+ if (!path)
+ return nullptr;
+ uptr name_len = internal_strlen(name);
+ InternalScopedBuffer<char> buffer(kMaxPathLength);
+ const char *beg = path;
+ while (true) {
+ const char *end = internal_strchrnul(beg, kPathSeparator);
+ uptr prefix_len = end - beg;
+ if (prefix_len + name_len + 2 <= kMaxPathLength) {
+ internal_memcpy(buffer.data(), beg, prefix_len);
+ buffer[prefix_len] = '/';
+ internal_memcpy(&buffer[prefix_len + 1], name, name_len);
+ buffer[prefix_len + 1 + name_len] = '\0';
+ if (FileExists(buffer.data()))
+ return internal_strdup(buffer.data());
+ }
+ if (*end == '\0') break;
+ beg = end + 1;
+ }
+ return nullptr;
+}
+
+} // namespace __sanitizer
+
+using namespace __sanitizer; // NOLINT
+
+extern "C" {
+void __sanitizer_set_report_path(const char *path) {
+ report_file.SetReportPath(path);
+}
+
+void __sanitizer_set_report_fd(void *fd) {
+ report_file.fd = (fd_t)reinterpret_cast<uptr>(fd);
+ report_file.fd_pid = internal_getpid();
+}
+} // extern "C"
+
+#endif // !SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_file.h b/libsanitizer/sanitizer_common/sanitizer_file.h
new file mode 100644
index 0000000..3f9e8ab
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_file.h
@@ -0,0 +1,108 @@
+//===-- sanitizer_file.h ---------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is shared between run-time libraries of sanitizers.
+// It declares filesystem-related interfaces. This is separate from
+// sanitizer_common.h so that it's simpler to disable all the filesystem
+// support code for a port that doesn't use it.
+//
+//===---------------------------------------------------------------------===//
+#ifndef SANITIZER_FILE_H
+#define SANITIZER_FILE_H
+
+#include "sanitizer_interface_internal.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
+
+namespace __sanitizer {
+
+struct ReportFile {
+ void Write(const char *buffer, uptr length);
+ bool SupportsColors();
+ void SetReportPath(const char *path);
+
+ // Don't use fields directly. They are only declared public to allow
+ // aggregate initialization.
+
+ // Protects fields below.
+ StaticSpinMutex *mu;
+ // Opened file descriptor. Defaults to stderr. It may be equal to
+ // kInvalidFd, in which case new file will be opened when necessary.
+ fd_t fd;
+ // Path prefix of report file, set via __sanitizer_set_report_path.
+ char path_prefix[kMaxPathLength];
+ // Full path to report, obtained as <path_prefix>.PID
+ char full_path[kMaxPathLength];
+ // PID of the process that opened fd. If a fork() occurs,
+ // the PID of child will be different from fd_pid.
+ uptr fd_pid;
+
+ private:
+ void ReopenIfNecessary();
+};
+extern ReportFile report_file;
+
+enum FileAccessMode {
+ RdOnly,
+ WrOnly,
+ RdWr
+};
+
+// Returns kInvalidFd on error.
+fd_t OpenFile(const char *filename, FileAccessMode mode,
+ error_t *errno_p = nullptr);
+void CloseFile(fd_t);
+
+// Return true on success, false on error.
+bool ReadFromFile(fd_t fd, void *buff, uptr buff_size,
+ uptr *bytes_read = nullptr, error_t *error_p = nullptr);
+bool WriteToFile(fd_t fd, const void *buff, uptr buff_size,
+ uptr *bytes_written = nullptr, error_t *error_p = nullptr);
+
+bool RenameFile(const char *oldpath, const char *newpath,
+ error_t *error_p = nullptr);
+
+// Scoped file handle closer.
+struct FileCloser {
+ explicit FileCloser(fd_t fd) : fd(fd) {}
+ ~FileCloser() { CloseFile(fd); }
+ fd_t fd;
+};
+
+bool SupportsColoredOutput(fd_t fd);
+
+// OS
+const char *GetPwd();
+bool FileExists(const char *filename);
+char *FindPathToBinary(const char *name);
+bool IsPathSeparator(const char c);
+bool IsAbsolutePath(const char *path);
+// Starts a subprocess and returs its pid.
+// If *_fd parameters are not kInvalidFd their corresponding input/output
+// streams will be redirect to the file. The files will always be closed
+// in parent process even in case of an error.
+// The child process will close all fds after STDERR_FILENO
+// before passing control to a program.
+pid_t StartSubprocess(const char *filename, const char *const argv[],
+ fd_t stdin_fd = kInvalidFd, fd_t stdout_fd = kInvalidFd,
+ fd_t stderr_fd = kInvalidFd);
+// Checks if specified process is still running
+bool IsProcessRunning(pid_t pid);
+// Waits for the process to finish and returns its exit code.
+// Returns -1 in case of an error.
+int WaitForProcess(pid_t pid);
+
+// Maps given file to virtual memory, and returns pointer to it
+// (or NULL if mapping fails). Stores the size of mmaped region
+// in '*buff_size'.
+void *MapFileToMemory(const char *file_name, uptr *buff_size);
+void *MapWritableFileToMemory(void *addr, uptr size, fd_t fd, OFF_T offset);
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FILE_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
index 7827d73..13677c0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
+++ b/libsanitizer/sanitizer_common/sanitizer_flag_parser.h
@@ -32,27 +32,48 @@ class FlagHandler : public FlagHandlerBase {
bool Parse(const char *value) final;
};
-template <>
-inline bool FlagHandler<bool>::Parse(const char *value) {
+inline bool ParseBool(const char *value, bool *b) {
if (internal_strcmp(value, "0") == 0 ||
internal_strcmp(value, "no") == 0 ||
internal_strcmp(value, "false") == 0) {
- *t_ = false;
+ *b = false;
return true;
}
if (internal_strcmp(value, "1") == 0 ||
internal_strcmp(value, "yes") == 0 ||
internal_strcmp(value, "true") == 0) {
- *t_ = true;
+ *b = true;
return true;
}
+ return false;
+}
+
+template <>
+inline bool FlagHandler<bool>::Parse(const char *value) {
+ if (ParseBool(value, t_)) return true;
Printf("ERROR: Invalid value for bool option: '%s'\n", value);
return false;
}
template <>
+inline bool FlagHandler<HandleSignalMode>::Parse(const char *value) {
+ bool b;
+ if (ParseBool(value, &b)) {
+ *t_ = b ? kHandleSignalYes : kHandleSignalNo;
+ return true;
+ }
+ if (internal_strcmp(value, "2") == 0 ||
+ internal_strcmp(value, "exclusive") == 0) {
+ *t_ = kHandleSignalExclusive;
+ return true;
+ }
+ Printf("ERROR: Invalid value for signal handler option: '%s'\n", value);
+ return false;
+}
+
+template <>
inline bool FlagHandler<const char *>::Parse(const char *value) {
- *t_ = internal_strdup(value);
+ *t_ = value;
return true;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.h b/libsanitizer/sanitizer_common/sanitizer_flags.h
index ff64af1..2e3739e 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.h
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.h
@@ -16,6 +16,12 @@
namespace __sanitizer {
+enum HandleSignalMode {
+ kHandleSignalNo,
+ kHandleSignalYes,
+ kHandleSignalExclusive,
+};
+
struct CommonFlags {
#define COMMON_FLAG(Type, Name, DefaultValue, Description) Type Name;
#include "sanitizer_flags.inc"
diff --git a/libsanitizer/sanitizer_common/sanitizer_flags.inc b/libsanitizer/sanitizer_common/sanitizer_flags.inc
index ccc0e41..9e9b8a7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_flags.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_flags.inc
@@ -60,7 +60,7 @@ COMMON_FLAG(
COMMON_FLAG(
int, verbosity, 0,
"Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).")
-COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.")
+COMMON_FLAG(bool, detect_leaks, !SANITIZER_MAC, "Enable memory leak detection.")
COMMON_FLAG(
bool, leak_check_at_exit, true,
"Invoke leak checking in an atexit handler. Has no effect if "
@@ -72,18 +72,28 @@ COMMON_FLAG(bool, allocator_may_return_null, false,
COMMON_FLAG(bool, print_summary, true,
"If false, disable printing error summaries in addition to error "
"reports.")
+COMMON_FLAG(int, print_module_map, 0,
+ "OS X only (0 - don't print, 1 - print only once before process "
+ "exits, 2 - print after each report).")
COMMON_FLAG(bool, check_printf, true, "Check printf arguments.")
-COMMON_FLAG(bool, handle_segv, true,
- "If set, registers the tool's custom SIGSEGV/SIGBUS handler.")
-COMMON_FLAG(bool, handle_abort, false,
- "If set, registers the tool's custom SIGABRT handler.")
-COMMON_FLAG(bool, handle_sigill, false,
- "If set, registers the tool's custom SIGILL handler.")
-COMMON_FLAG(bool, handle_sigfpe, true,
- "If set, registers the tool's custom SIGFPE handler.")
-COMMON_FLAG(bool, allow_user_segv_handler, false,
- "If set, allows user to register a SEGV handler even if the tool "
- "registers one.")
+#define COMMON_FLAG_HANDLE_SIGNAL_HELP(signal) \
+ "Controls custom tool's " #signal " handler (0 - do not registers the " \
+ "handler, 1 - register the handler and allow user to set own, " \
+ "2 - registers the handler and block user from changing it). "
+COMMON_FLAG(HandleSignalMode, handle_segv, kHandleSignalYes,
+ COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGSEGV))
+COMMON_FLAG(HandleSignalMode, handle_sigbus, kHandleSignalYes,
+ COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGBUS))
+COMMON_FLAG(HandleSignalMode, handle_abort, kHandleSignalNo,
+ COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGABRT))
+COMMON_FLAG(HandleSignalMode, handle_sigill, kHandleSignalNo,
+ COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGILL))
+COMMON_FLAG(HandleSignalMode, handle_sigfpe, kHandleSignalYes,
+ COMMON_FLAG_HANDLE_SIGNAL_HELP(SIGFPE))
+#undef COMMON_FLAG_HANDLE_SIGNAL_HELP
+COMMON_FLAG(bool, allow_user_segv_handler, true,
+ "Deprecated. True has no effect, use handle_sigbus=1. If false, "
+ "handle_*=1 will be upgraded to handle_*=2.")
COMMON_FLAG(bool, use_sigaltstack, true,
"If set, uses alternate stack for signal handling.")
COMMON_FLAG(bool, detect_deadlocks, false,
@@ -117,9 +127,11 @@ COMMON_FLAG(uptr, soft_rss_limit_mb, 0,
" This limit does not affect memory allocations other than"
" malloc/new.")
COMMON_FLAG(bool, heap_profile, false, "Experimental heap profiler, asan-only")
-COMMON_FLAG(bool, allocator_release_to_os, false,
- "Experimental. If true, try to periodically release unused"
- " memory to the OS.\n")
+COMMON_FLAG(s32, allocator_release_to_os_interval_ms, kReleaseToOSIntervalNever,
+ "Experimental. Only affects a 64-bit allocator. If set, tries to "
+ "release unused memory to the OS, but not more often than this "
+ "interval (in milliseconds). Negative values mean do not attempt "
+ "to release memory to the OS.\n")
COMMON_FLAG(bool, can_use_proc_maps_statm, true,
"If false, do not attempt to read /proc/maps/statm."
" Mostly useful for testing sanitizers.")
@@ -127,22 +139,6 @@ COMMON_FLAG(
bool, coverage, false,
"If set, coverage information will be dumped at program shutdown (if the "
"coverage instrumentation was enabled at compile time).")
-COMMON_FLAG(bool, coverage_pcs, true,
- "If set (and if 'coverage' is set too), the coverage information "
- "will be dumped as a set of PC offsets for every module.")
-COMMON_FLAG(bool, coverage_order_pcs, false,
- "If true, the PCs will be dumped in the order they've"
- " appeared during the execution.")
-COMMON_FLAG(bool, coverage_bitset, false,
- "If set (and if 'coverage' is set too), the coverage information "
- "will also be dumped as a bitset to a separate file.")
-COMMON_FLAG(bool, coverage_counters, false,
- "If set (and if 'coverage' is set too), the bitmap that corresponds"
- " to coverage counters will be dumped.")
-COMMON_FLAG(bool, coverage_direct, SANITIZER_ANDROID,
- "If set, coverage information will be dumped directly to a memory "
- "mapped file. This way data is not lost even if the process is "
- "suddenly killed.")
COMMON_FLAG(const char *, coverage_dir, ".",
"Target directory for coverage dumps. Defaults to the current "
"directory.")
@@ -183,12 +179,18 @@ COMMON_FLAG(bool, intercept_strstr, true,
COMMON_FLAG(bool, intercept_strspn, true,
"If set, uses custom wrappers for strspn and strcspn function "
"to find more errors.")
+COMMON_FLAG(bool, intercept_strtok, true,
+ "If set, uses a custom wrapper for the strtok function "
+ "to find more errors.")
COMMON_FLAG(bool, intercept_strpbrk, true,
"If set, uses custom wrappers for strpbrk function "
"to find more errors.")
COMMON_FLAG(bool, intercept_strlen, true,
"If set, uses custom wrappers for strlen and strnlen functions "
"to find more errors.")
+COMMON_FLAG(bool, intercept_strndup, true,
+ "If set, uses custom wrappers for strndup functions "
+ "to find more errors.")
COMMON_FLAG(bool, intercept_strchr, true,
"If set, uses custom wrappers for strchr, strchrnul, and strrchr "
"functions to find more errors.")
@@ -225,3 +227,8 @@ COMMON_FLAG(bool, print_cmdline, false, "Print command line on crash "
"(asan only).")
COMMON_FLAG(bool, html_cov_report, false, "Generate html coverage report.")
COMMON_FLAG(const char *, sancov_path, "sancov", "Sancov tool location.")
+COMMON_FLAG(bool, dump_instruction_bytes, false,
+ "If true, dump 16 bytes starting at the instruction that caused SEGV")
+COMMON_FLAG(bool, dump_registers, true,
+ "If true, dump values of CPU registers when SEGV happens. Only "
+ "available on OS X for now.")
diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.cc b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cc
new file mode 100644
index 0000000..da7018c
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.cc
@@ -0,0 +1,517 @@
+//===-- sanitizer_fuchsia.cc ---------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// This file is shared between AddressSanitizer and other sanitizer
+// run-time libraries and implements Fuchsia-specific functions from
+// sanitizer_common.h.
+//===---------------------------------------------------------------------===//
+
+#include "sanitizer_fuchsia.h"
+#if SANITIZER_FUCHSIA
+
+#include "sanitizer_common.h"
+#include "sanitizer_libc.h"
+#include "sanitizer_mutex.h"
+#include "sanitizer_stacktrace.h"
+
+#include <limits.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <unwind.h>
+#include <zircon/errors.h>
+#include <zircon/process.h>
+#include <zircon/syscalls.h>
+
+namespace __sanitizer {
+
+void NORETURN internal__exit(int exitcode) { _zx_process_exit(exitcode); }
+
+uptr internal_sched_yield() {
+ zx_status_t status = _zx_nanosleep(0);
+ CHECK_EQ(status, ZX_OK);
+ return 0; // Why doesn't this return void?
+}
+
+static void internal_nanosleep(zx_time_t ns) {
+ zx_status_t status = _zx_nanosleep(_zx_deadline_after(ns));
+ CHECK_EQ(status, ZX_OK);
+}
+
+unsigned int internal_sleep(unsigned int seconds) {
+ internal_nanosleep(ZX_SEC(seconds));
+ return 0;
+}
+
+u64 NanoTime() { return _zx_time_get(ZX_CLOCK_UTC); }
+
+uptr internal_getpid() {
+ zx_info_handle_basic_t info;
+ zx_status_t status =
+ _zx_object_get_info(_zx_process_self(), ZX_INFO_HANDLE_BASIC, &info,
+ sizeof(info), NULL, NULL);
+ CHECK_EQ(status, ZX_OK);
+ uptr pid = static_cast<uptr>(info.koid);
+ CHECK_EQ(pid, info.koid);
+ return pid;
+}
+
+uptr GetThreadSelf() { return reinterpret_cast<uptr>(thrd_current()); }
+
+uptr GetTid() { return GetThreadSelf(); }
+
+void Abort() { abort(); }
+
+int Atexit(void (*function)(void)) { return atexit(function); }
+
+void SleepForSeconds(int seconds) { internal_sleep(seconds); }
+
+void SleepForMillis(int millis) { internal_nanosleep(ZX_MSEC(millis)); }
+
+void GetThreadStackTopAndBottom(bool, uptr *stack_top, uptr *stack_bottom) {
+ pthread_attr_t attr;
+ CHECK_EQ(pthread_getattr_np(pthread_self(), &attr), 0);
+ void *base;
+ size_t size;
+ CHECK_EQ(pthread_attr_getstack(&attr, &base, &size), 0);
+ CHECK_EQ(pthread_attr_destroy(&attr), 0);
+
+ *stack_bottom = reinterpret_cast<uptr>(base);
+ *stack_top = *stack_bottom + size;
+}
+
+void MaybeReexec() {}
+void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {}
+void DisableCoreDumperIfNecessary() {}
+void InstallDeadlySignalHandlers(SignalHandlerType handler) {}
+void StartReportDeadlySignal() {}
+void ReportDeadlySignal(const SignalContext &sig, u32 tid,
+ UnwindSignalStackCallbackType unwind,
+ const void *unwind_context) {}
+void SetAlternateSignalStack() {}
+void UnsetAlternateSignalStack() {}
+void InitTlsSize() {}
+
+void PrintModuleMap() {}
+
+bool SignalContext::IsStackOverflow() const { return false; }
+void SignalContext::DumpAllRegisters(void *context) { UNIMPLEMENTED(); }
+const char *SignalContext::Describe() const { UNIMPLEMENTED(); }
+
+struct UnwindTraceArg {
+ BufferedStackTrace *stack;
+ u32 max_depth;
+};
+
+_Unwind_Reason_Code Unwind_Trace(struct _Unwind_Context *ctx, void *param) {
+ UnwindTraceArg *arg = static_cast<UnwindTraceArg *>(param);
+ CHECK_LT(arg->stack->size, arg->max_depth);
+ uptr pc = _Unwind_GetIP(ctx);
+ if (pc < PAGE_SIZE) return _URC_NORMAL_STOP;
+ arg->stack->trace_buffer[arg->stack->size++] = pc;
+ return (arg->stack->size == arg->max_depth ? _URC_NORMAL_STOP
+ : _URC_NO_REASON);
+}
+
+void BufferedStackTrace::SlowUnwindStack(uptr pc, u32 max_depth) {
+ CHECK_GE(max_depth, 2);
+ size = 0;
+ UnwindTraceArg arg = {this, Min(max_depth + 1, kStackTraceMax)};
+ _Unwind_Backtrace(Unwind_Trace, &arg);
+ CHECK_GT(size, 0);
+ // We need to pop a few frames so that pc is on top.
+ uptr to_pop = LocatePcInTrace(pc);
+ // trace_buffer[0] belongs to the current function so we always pop it,
+ // unless there is only 1 frame in the stack trace (1 frame is always better
+ // than 0!).
+ PopStackFrames(Min(to_pop, static_cast<uptr>(1)));
+ trace_buffer[0] = pc;
+}
+
+void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
+ u32 max_depth) {
+ CHECK_NE(context, nullptr);
+ UNREACHABLE("signal context doesn't exist");
+}
+
+enum MutexState : int { MtxUnlocked = 0, MtxLocked = 1, MtxSleeping = 2 };
+
+BlockingMutex::BlockingMutex() {
+ // NOTE! It's important that this use internal_memset, because plain
+ // memset might be intercepted (e.g., actually be __asan_memset).
+ // Defining this so the compiler initializes each field, e.g.:
+ // BlockingMutex::BlockingMutex() : BlockingMutex(LINKER_INITIALIZED) {}
+ // might result in the compiler generating a call to memset, which would
+ // have the same problem.
+ internal_memset(this, 0, sizeof(*this));
+}
+
+void BlockingMutex::Lock() {
+ CHECK_EQ(owner_, 0);
+ atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
+ if (atomic_exchange(m, MtxLocked, memory_order_acquire) == MtxUnlocked)
+ return;
+ while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
+ zx_status_t status = _zx_futex_wait(reinterpret_cast<zx_futex_t *>(m),
+ MtxSleeping, ZX_TIME_INFINITE);
+ if (status != ZX_ERR_BAD_STATE) // Normal race.
+ CHECK_EQ(status, ZX_OK);
+ }
+}
+
+void BlockingMutex::Unlock() {
+ atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
+ u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
+ CHECK_NE(v, MtxUnlocked);
+ if (v == MtxSleeping) {
+ zx_status_t status = _zx_futex_wake(reinterpret_cast<zx_futex_t *>(m), 1);
+ CHECK_EQ(status, ZX_OK);
+ }
+}
+
+void BlockingMutex::CheckLocked() {
+ atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
+ CHECK_NE(MtxUnlocked, atomic_load(m, memory_order_relaxed));
+}
+
+uptr GetPageSize() { return PAGE_SIZE; }
+
+uptr GetMmapGranularity() { return PAGE_SIZE; }
+
+sanitizer_shadow_bounds_t ShadowBounds;
+
+uptr GetMaxVirtualAddress() {
+ ShadowBounds = __sanitizer_shadow_bounds();
+ return ShadowBounds.memory_limit - 1;
+}
+
+static void *DoAnonymousMmapOrDie(uptr size, const char *mem_type,
+ bool raw_report, bool die_for_nomem) {
+ size = RoundUpTo(size, PAGE_SIZE);
+
+ zx_handle_t vmo;
+ zx_status_t status = _zx_vmo_create(size, 0, &vmo);
+ if (status != ZX_OK) {
+ if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
+ ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status,
+ raw_report);
+ return nullptr;
+ }
+ _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
+ internal_strlen(mem_type));
+
+ // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
+ uintptr_t addr;
+ status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, size,
+ ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &addr);
+ _zx_handle_close(vmo);
+
+ if (status != ZX_OK) {
+ if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
+ ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status,
+ raw_report);
+ return nullptr;
+ }
+
+ IncreaseTotalMmap(size);
+
+ return reinterpret_cast<void *>(addr);
+}
+
+void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
+ return DoAnonymousMmapOrDie(size, mem_type, raw_report, true);
+}
+
+void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
+ return MmapOrDie(size, mem_type);
+}
+
+void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
+ return DoAnonymousMmapOrDie(size, mem_type, false, false);
+}
+
+// MmapNoAccess and MmapFixedOrDie are used only by sanitizer_allocator.
+// Instead of doing exactly what they say, we make MmapNoAccess actually
+// just allocate a VMAR to reserve the address space. Then MmapFixedOrDie
+// uses that VMAR instead of the root.
+
+zx_handle_t allocator_vmar = ZX_HANDLE_INVALID;
+uintptr_t allocator_vmar_base;
+size_t allocator_vmar_size;
+
+void *MmapNoAccess(uptr size) {
+ size = RoundUpTo(size, PAGE_SIZE);
+ CHECK_EQ(allocator_vmar, ZX_HANDLE_INVALID);
+ uintptr_t base;
+ zx_status_t status =
+ _zx_vmar_allocate(_zx_vmar_root_self(), 0, size,
+ ZX_VM_FLAG_CAN_MAP_READ | ZX_VM_FLAG_CAN_MAP_WRITE |
+ ZX_VM_FLAG_CAN_MAP_SPECIFIC,
+ &allocator_vmar, &base);
+ if (status != ZX_OK)
+ ReportMmapFailureAndDie(size, "sanitizer allocator address space",
+ "zx_vmar_allocate", status);
+
+ allocator_vmar_base = base;
+ allocator_vmar_size = size;
+ return reinterpret_cast<void *>(base);
+}
+
+constexpr const char kAllocatorVmoName[] = "sanitizer_allocator";
+
+static void *DoMmapFixedOrDie(uptr fixed_addr, uptr size, bool die_for_nomem) {
+ size = RoundUpTo(size, PAGE_SIZE);
+
+ zx_handle_t vmo;
+ zx_status_t status = _zx_vmo_create(size, 0, &vmo);
+ if (status != ZX_OK) {
+ if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
+ ReportMmapFailureAndDie(size, kAllocatorVmoName, "zx_vmo_create", status);
+ return nullptr;
+ }
+ _zx_object_set_property(vmo, ZX_PROP_NAME, kAllocatorVmoName,
+ sizeof(kAllocatorVmoName) - 1);
+
+ DCHECK_GE(fixed_addr, allocator_vmar_base);
+ uintptr_t offset = fixed_addr - allocator_vmar_base;
+ DCHECK_LE(size, allocator_vmar_size);
+ DCHECK_GE(allocator_vmar_size - offset, size);
+
+ uintptr_t addr;
+ status = _zx_vmar_map(
+ allocator_vmar, offset, vmo, 0, size,
+ ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE | ZX_VM_FLAG_SPECIFIC,
+ &addr);
+ _zx_handle_close(vmo);
+ if (status != ZX_OK) {
+ if (status != ZX_ERR_NO_MEMORY || die_for_nomem)
+ ReportMmapFailureAndDie(size, kAllocatorVmoName, "zx_vmar_map", status);
+ return nullptr;
+ }
+
+ IncreaseTotalMmap(size);
+
+ return reinterpret_cast<void *>(addr);
+}
+
+void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
+ return DoMmapFixedOrDie(fixed_addr, size, true);
+}
+
+void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) {
+ return DoMmapFixedOrDie(fixed_addr, size, false);
+}
+
+// This should never be called.
+void *MmapFixedNoAccess(uptr fixed_addr, uptr size, const char *name) {
+ UNIMPLEMENTED();
+}
+
+void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
+ const char *mem_type) {
+ CHECK_GE(size, PAGE_SIZE);
+ CHECK(IsPowerOfTwo(size));
+ CHECK(IsPowerOfTwo(alignment));
+
+ zx_handle_t vmo;
+ zx_status_t status = _zx_vmo_create(size, 0, &vmo);
+ if (status != ZX_OK) {
+ if (status != ZX_ERR_NO_MEMORY)
+ ReportMmapFailureAndDie(size, mem_type, "zx_vmo_create", status, false);
+ return nullptr;
+ }
+ _zx_object_set_property(vmo, ZX_PROP_NAME, mem_type,
+ internal_strlen(mem_type));
+
+ // TODO(mcgrathr): Maybe allocate a VMAR for all sanitizer heap and use that?
+
+ // Map a larger size to get a chunk of address space big enough that
+ // it surely contains an aligned region of the requested size. Then
+ // overwrite the aligned middle portion with a mapping from the
+ // beginning of the VMO, and unmap the excess before and after.
+ size_t map_size = size + alignment;
+ uintptr_t addr;
+ status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, map_size,
+ ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE, &addr);
+ if (status == ZX_OK) {
+ uintptr_t map_addr = addr;
+ uintptr_t map_end = map_addr + map_size;
+ addr = RoundUpTo(map_addr, alignment);
+ uintptr_t end = addr + size;
+ if (addr != map_addr) {
+ zx_info_vmar_t info;
+ status = _zx_object_get_info(_zx_vmar_root_self(), ZX_INFO_VMAR, &info,
+ sizeof(info), NULL, NULL);
+ if (status == ZX_OK) {
+ uintptr_t new_addr;
+ status =
+ _zx_vmar_map(_zx_vmar_root_self(), addr - info.base, vmo, 0, size,
+ ZX_VM_FLAG_PERM_READ | ZX_VM_FLAG_PERM_WRITE |
+ ZX_VM_FLAG_SPECIFIC_OVERWRITE,
+ &new_addr);
+ if (status == ZX_OK) CHECK_EQ(new_addr, addr);
+ }
+ }
+ if (status == ZX_OK && addr != map_addr)
+ status = _zx_vmar_unmap(_zx_vmar_root_self(), map_addr, addr - map_addr);
+ if (status == ZX_OK && end != map_end)
+ status = _zx_vmar_unmap(_zx_vmar_root_self(), end, map_end - end);
+ }
+ _zx_handle_close(vmo);
+
+ if (status != ZX_OK) {
+ if (status != ZX_ERR_NO_MEMORY)
+ ReportMmapFailureAndDie(size, mem_type, "zx_vmar_map", status, false);
+ return nullptr;
+ }
+
+ IncreaseTotalMmap(size);
+
+ return reinterpret_cast<void *>(addr);
+}
+
+void UnmapOrDie(void *addr, uptr size) {
+ if (!addr || !size) return;
+ size = RoundUpTo(size, PAGE_SIZE);
+
+ zx_status_t status = _zx_vmar_unmap(_zx_vmar_root_self(),
+ reinterpret_cast<uintptr_t>(addr), size);
+ if (status != ZX_OK) {
+ Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
+ SanitizerToolName, size, size, addr);
+ CHECK("unable to unmap" && 0);
+ }
+
+ DecreaseTotalMmap(size);
+}
+
+// This is used on the shadow mapping, which cannot be changed.
+// Zircon doesn't have anything like MADV_DONTNEED.
+void ReleaseMemoryPagesToOS(uptr beg, uptr end) {}
+
+void DumpProcessMap() {
+ UNIMPLEMENTED(); // TODO(mcgrathr): write it
+}
+
+bool IsAccessibleMemoryRange(uptr beg, uptr size) {
+ // TODO(mcgrathr): Figure out a better way.
+ zx_handle_t vmo;
+ zx_status_t status = _zx_vmo_create(size, 0, &vmo);
+ if (status == ZX_OK) {
+ while (size > 0) {
+ size_t wrote;
+ status = _zx_vmo_write(vmo, reinterpret_cast<const void *>(beg), 0, size,
+ &wrote);
+ if (status != ZX_OK) break;
+ CHECK_GT(wrote, 0);
+ CHECK_LE(wrote, size);
+ beg += wrote;
+ size -= wrote;
+ }
+ _zx_handle_close(vmo);
+ }
+ return status == ZX_OK;
+}
+
+// FIXME implement on this platform.
+void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {}
+
+bool ReadFileToBuffer(const char *file_name, char **buff, uptr *buff_size,
+ uptr *read_len, uptr max_len, error_t *errno_p) {
+ zx_handle_t vmo;
+ zx_status_t status = __sanitizer_get_configuration(file_name, &vmo);
+ if (status == ZX_OK) {
+ uint64_t vmo_size;
+ status = _zx_vmo_get_size(vmo, &vmo_size);
+ if (status == ZX_OK) {
+ if (vmo_size < max_len) max_len = vmo_size;
+ size_t map_size = RoundUpTo(max_len, PAGE_SIZE);
+ uintptr_t addr;
+ status = _zx_vmar_map(_zx_vmar_root_self(), 0, vmo, 0, map_size,
+ ZX_VM_FLAG_PERM_READ, &addr);
+ if (status == ZX_OK) {
+ *buff = reinterpret_cast<char *>(addr);
+ *buff_size = map_size;
+ *read_len = max_len;
+ }
+ }
+ _zx_handle_close(vmo);
+ }
+ if (status != ZX_OK && errno_p) *errno_p = status;
+ return status == ZX_OK;
+}
+
+void RawWrite(const char *buffer) {
+ __sanitizer_log_write(buffer, internal_strlen(buffer));
+}
+
+void CatastrophicErrorWrite(const char *buffer, uptr length) {
+ __sanitizer_log_write(buffer, length);
+}
+
+char **StoredArgv;
+char **StoredEnviron;
+
+char **GetArgv() { return StoredArgv; }
+
+const char *GetEnv(const char *name) {
+ if (StoredEnviron) {
+ uptr NameLen = internal_strlen(name);
+ for (char **Env = StoredEnviron; *Env != 0; Env++) {
+ if (internal_strncmp(*Env, name, NameLen) == 0 && (*Env)[NameLen] == '=')
+ return (*Env) + NameLen + 1;
+ }
+ }
+ return nullptr;
+}
+
+uptr ReadBinaryName(/*out*/ char *buf, uptr buf_len) {
+ const char *argv0 = StoredArgv[0];
+ if (!argv0) argv0 = "<UNKNOWN>";
+ internal_strncpy(buf, argv0, buf_len);
+ return internal_strlen(buf);
+}
+
+uptr ReadLongProcessName(/*out*/ char *buf, uptr buf_len) {
+ return ReadBinaryName(buf, buf_len);
+}
+
+uptr MainThreadStackBase, MainThreadStackSize;
+
+bool GetRandom(void *buffer, uptr length, bool blocking) {
+ CHECK_LE(length, ZX_CPRNG_DRAW_MAX_LEN);
+ size_t size;
+ CHECK_EQ(_zx_cprng_draw(buffer, length, &size), ZX_OK);
+ CHECK_EQ(size, length);
+ return true;
+}
+
+} // namespace __sanitizer
+
+using namespace __sanitizer; // NOLINT
+
+extern "C" {
+void __sanitizer_startup_hook(int argc, char **argv, char **envp,
+ void *stack_base, size_t stack_size) {
+ __sanitizer::StoredArgv = argv;
+ __sanitizer::StoredEnviron = envp;
+ __sanitizer::MainThreadStackBase = reinterpret_cast<uintptr_t>(stack_base);
+ __sanitizer::MainThreadStackSize = stack_size;
+}
+
+void __sanitizer_set_report_path(const char *path) {
+ // Handle the initialization code in each sanitizer, but no other calls.
+ // This setting is never consulted on Fuchsia.
+ DCHECK_EQ(path, common_flags()->log_path);
+}
+
+void __sanitizer_set_report_fd(void *fd) {
+ UNREACHABLE("not available on Fuchsia");
+}
+} // extern "C"
+
+#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_fuchsia.h b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
new file mode 100644
index 0000000..59b679d
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_fuchsia.h
@@ -0,0 +1,29 @@
+//===-- sanitizer_fuchsia.h ------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===---------------------------------------------------------------------===//
+//
+// Fuchsia-specific sanitizer support.
+//
+//===---------------------------------------------------------------------===//
+#ifndef SANITIZER_FUCHSIA_H
+#define SANITIZER_FUCHSIA_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FUCHSIA
+
+#include "sanitizer_common.h"
+
+#include <zircon/sanitizer.h>
+
+namespace __sanitizer {
+
+extern uptr MainThreadStackBase, MainThreadStackSize;
+extern sanitizer_shadow_bounds_t ShadowBounds;
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FUCHSIA
+#endif // SANITIZER_FUCHSIA_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
index 34e80c3..08c110c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_interface_internal.h
@@ -45,7 +45,10 @@ extern "C" {
void __sanitizer_report_error_summary(const char *error_summary);
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_dump();
- SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov_init();
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_coverage(
+ const __sanitizer::uptr *pcs, const __sanitizer::uptr len);
+ SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_dump_trace_pc_guard_coverage();
+
SANITIZER_INTERFACE_ATTRIBUTE void __sanitizer_cov(__sanitizer::u32 *guard);
SANITIZER_INTERFACE_ATTRIBUTE
void __sanitizer_annotate_contiguous_container(const void *beg,
@@ -58,6 +61,49 @@ extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
const void *__sanitizer_contiguous_container_find_bad_address(
const void *beg, const void *mid, const void *end);
- } // extern "C"
+
+ SANITIZER_INTERFACE_ATTRIBUTE
+ int __sanitizer_get_module_and_offset_for_pc(
+ __sanitizer::uptr pc, char *module_path,
+ __sanitizer::uptr module_path_len, __sanitizer::uptr *pc_offset);
+
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_cmp();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_cmp1();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_cmp2();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_cmp4();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_cmp8();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_const_cmp1();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_const_cmp2();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_const_cmp4();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_const_cmp8();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_switch();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_div4();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_div8();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_gep();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_pc_indir();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_pc_guard(__sanitizer::u32*);
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_trace_pc_guard_init(__sanitizer::u32*,
+ __sanitizer::u32*);
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_8bit_counters_init();
+ SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
+ void __sanitizer_cov_pcs_init();
+} // extern "C"
#endif // SANITIZER_INTERFACE_INTERNAL_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
index 676ade1..ef405de 100644
--- a/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
+++ b/libsanitizer/sanitizer_common/sanitizer_internal_defs.h
@@ -19,8 +19,11 @@
// Only use SANITIZER_*ATTRIBUTE* before the function return type!
#if SANITIZER_WINDOWS
+#if SANITIZER_IMPORT_INTERFACE
+# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllimport)
+#else
# define SANITIZER_INTERFACE_ATTRIBUTE __declspec(dllexport)
-// FIXME find out what we need on Windows, if anything.
+#endif
# define SANITIZER_WEAK_ATTRIBUTE
#elif SANITIZER_GO
# define SANITIZER_INTERFACE_ATTRIBUTE
@@ -30,11 +33,56 @@
# define SANITIZER_WEAK_ATTRIBUTE __attribute__((weak))
#endif
-#if (SANITIZER_LINUX || SANITIZER_WINDOWS) && !SANITIZER_GO
+// TLS is handled differently on different platforms
+#if SANITIZER_LINUX
+# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE \
+ __attribute__((tls_model("initial-exec"))) thread_local
+#else
+# define SANITIZER_TLS_INITIAL_EXEC_ATTRIBUTE
+#endif
+
+//--------------------------- WEAK FUNCTIONS ---------------------------------//
+// When working with weak functions, to simplify the code and make it more
+// portable, when possible define a default implementation using this macro:
+//
+// SANITIZER_INTERFACE_WEAK_DEF(<return_type>, <name>, <parameter list>)
+//
+// For example:
+// SANITIZER_INTERFACE_WEAK_DEF(bool, compare, int a, int b) { return a > b; }
+//
+#if SANITIZER_WINDOWS
+#include "sanitizer_win_defs.h"
+# define SANITIZER_INTERFACE_WEAK_DEF(ReturnType, Name, ...) \
+ WIN_WEAK_EXPORT_DEF(ReturnType, Name, __VA_ARGS__)
+#else
+# define SANITIZER_INTERFACE_WEAK_DEF(ReturnType, Name, ...) \
+ extern "C" SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE \
+ ReturnType Name(__VA_ARGS__)
+#endif
+
+// SANITIZER_SUPPORTS_WEAK_HOOKS means that we support real weak functions that
+// will evaluate to a null pointer when not defined.
+#ifndef SANITIZER_SUPPORTS_WEAK_HOOKS
+#if (SANITIZER_LINUX || SANITIZER_MAC) && !SANITIZER_GO
# define SANITIZER_SUPPORTS_WEAK_HOOKS 1
#else
# define SANITIZER_SUPPORTS_WEAK_HOOKS 0
#endif
+#endif // SANITIZER_SUPPORTS_WEAK_HOOKS
+// For some weak hooks that will be called very often and we want to avoid the
+// overhead of executing the default implementation when it is not necessary,
+// we can use the flag SANITIZER_SUPPORTS_WEAK_HOOKS to only define the default
+// implementation for platforms that doesn't support weak symbols. For example:
+//
+// #if !SANITIZER_SUPPORT_WEAK_HOOKS
+// SANITIZER_INTERFACE_WEAK_DEF(bool, compare_hook, int a, int b) {
+// return a > b;
+// }
+// #endif
+//
+// And then use it as: if (compare_hook) compare_hook(a, b);
+//----------------------------------------------------------------------------//
+
// We can use .preinit_array section on Linux to call sanitizer initialization
// functions very early in the process startup (unless PIC macro is defined).
@@ -89,12 +137,8 @@ typedef int error_t;
#endif
typedef int pid_t;
-// WARNING: OFF_T may be different from OS type off_t, depending on the value of
-// _FILE_OFFSET_BITS. This definition of OFF_T matches the ABI of system calls
-// like pread and mmap, as opposed to pread64 and mmap64.
-// FreeBSD, Mac and Linux/x86-64 are special.
-#if SANITIZER_FREEBSD || SANITIZER_MAC || \
- (SANITIZER_LINUX && defined(__x86_64__))
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC || \
+ (SANITIZER_LINUX && defined(__x86_64__))
typedef u64 OFF_T;
#else
typedef uptr OFF_T;
@@ -112,6 +156,12 @@ typedef u32 operator_new_size_type;
# endif
#endif
+#if SANITIZER_MAC
+// On Darwin, thread IDs are 64-bit even on 32-bit systems.
+typedef u64 tid_t;
+#else
+typedef uptr tid_t;
+#endif
// ----------- ATTENTION -------------
// This header should NOT include any other headers to avoid portability issues.
@@ -211,8 +261,8 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
#define CHECK_IMPL(c1, op, c2) \
do { \
- __sanitizer::u64 v1 = (u64)(c1); \
- __sanitizer::u64 v2 = (u64)(c2); \
+ __sanitizer::u64 v1 = (__sanitizer::u64)(c1); \
+ __sanitizer::u64 v2 = (__sanitizer::u64)(c2); \
if (UNLIKELY(!(v1 op v2))) \
__sanitizer::CheckFailed(__FILE__, __LINE__, \
"(" #c1 ") " #op " (" #c2 ")", v1, v2); \
@@ -287,13 +337,13 @@ void NORETURN CheckFailed(const char *file, int line, const char *cond,
enum LinkerInitialized { LINKER_INITIALIZED = 0 };
#if !defined(_MSC_VER) || defined(__clang__)
-# if SANITIZER_S390_31
-# define GET_CALLER_PC() \
- (uptr)__builtin_extract_return_addr(__builtin_return_address(0))
-# else
-# define GET_CALLER_PC() (uptr)__builtin_return_address(0)
-# endif
-# define GET_CURRENT_FRAME() (uptr)__builtin_frame_address(0)
+#if SANITIZER_S390_31
+#define GET_CALLER_PC() \
+ (__sanitizer::uptr) __builtin_extract_return_addr(__builtin_return_address(0))
+#else
+#define GET_CALLER_PC() (__sanitizer::uptr) __builtin_return_address(0)
+#endif
+#define GET_CURRENT_FRAME() (__sanitizer::uptr) __builtin_frame_address(0)
inline void Trap() {
__builtin_trap();
}
@@ -302,9 +352,10 @@ extern "C" void* _ReturnAddress(void);
extern "C" void* _AddressOfReturnAddress(void);
# pragma intrinsic(_ReturnAddress)
# pragma intrinsic(_AddressOfReturnAddress)
-# define GET_CALLER_PC() (uptr)_ReturnAddress()
+#define GET_CALLER_PC() (__sanitizer::uptr) _ReturnAddress()
// CaptureStackBackTrace doesn't need to know BP on Windows.
-# define GET_CURRENT_FRAME() (((uptr)_AddressOfReturnAddress()) + sizeof(uptr))
+#define GET_CURRENT_FRAME() \
+ (((__sanitizer::uptr)_AddressOfReturnAddress()) + sizeof(__sanitizer::uptr))
extern "C" void __ud2(void);
# pragma intrinsic(__ud2)
@@ -322,11 +373,11 @@ inline void Trap() {
}
// Forces the compiler to generate a frame pointer in the function.
-#define ENABLE_FRAME_POINTER \
- do { \
- volatile uptr enable_fp; \
- enable_fp = GET_CURRENT_FRAME(); \
- (void)enable_fp; \
+#define ENABLE_FRAME_POINTER \
+ do { \
+ volatile __sanitizer::uptr enable_fp; \
+ enable_fp = GET_CURRENT_FRAME(); \
+ (void)enable_fp; \
} while (0)
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.cc b/libsanitizer/sanitizer_common/sanitizer_libignore.cc
index 4b8cbed..e20c755 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libignore.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_libignore.cc
@@ -7,7 +7,7 @@
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD
#include "sanitizer_libignore.h"
#include "sanitizer_flags.h"
@@ -48,23 +48,23 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
}
// Scan suppressions list and find newly loaded and unloaded libraries.
- MemoryMappingLayout proc_maps(/*cache_enabled*/false);
- InternalScopedString module(kMaxPathLength);
+ ListOfModules modules;
+ modules.init();
for (uptr i = 0; i < count_; i++) {
Lib *lib = &libs_[i];
bool loaded = false;
- proc_maps.Reset();
- uptr b, e, off, prot;
- while (proc_maps.Next(&b, &e, &off, module.data(), module.size(), &prot)) {
- if ((prot & MemoryMappingLayout::kProtectionExecute) == 0)
- continue;
- if (TemplateMatch(lib->templ, module.data()) ||
- (lib->real_name &&
- internal_strcmp(lib->real_name, module.data()) == 0)) {
+ for (const auto &mod : modules) {
+ for (const auto &range : mod.ranges()) {
+ if (!range.executable)
+ continue;
+ if (!TemplateMatch(lib->templ, mod.full_name()) &&
+ !(lib->real_name &&
+ internal_strcmp(lib->real_name, mod.full_name()) == 0))
+ continue;
if (loaded) {
Report("%s: called_from_lib suppression '%s' is matched against"
" 2 libraries: '%s' and '%s'\n",
- SanitizerToolName, lib->templ, lib->name, module.data());
+ SanitizerToolName, lib->templ, lib->name, mod.full_name());
Die();
}
loaded = true;
@@ -73,13 +73,16 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
VReport(1,
"Matched called_from_lib suppression '%s' against library"
" '%s'\n",
- lib->templ, module.data());
+ lib->templ, mod.full_name());
lib->loaded = true;
- lib->name = internal_strdup(module.data());
- const uptr idx = atomic_load(&loaded_count_, memory_order_relaxed);
- code_ranges_[idx].begin = b;
- code_ranges_[idx].end = e;
- atomic_store(&loaded_count_, idx + 1, memory_order_release);
+ lib->name = internal_strdup(mod.full_name());
+ const uptr idx =
+ atomic_load(&ignored_ranges_count_, memory_order_relaxed);
+ CHECK_LT(idx, kMaxLibs);
+ ignored_code_ranges_[idx].begin = range.beg;
+ ignored_code_ranges_[idx].end = range.end;
+ atomic_store(&ignored_ranges_count_, idx + 1, memory_order_release);
+ break;
}
}
if (lib->loaded && !loaded) {
@@ -89,6 +92,29 @@ void LibIgnore::OnLibraryLoaded(const char *name) {
Die();
}
}
+
+ // Track instrumented ranges.
+ if (track_instrumented_libs_) {
+ for (const auto &mod : modules) {
+ if (!mod.instrumented())
+ continue;
+ for (const auto &range : mod.ranges()) {
+ if (!range.executable)
+ continue;
+ if (IsPcInstrumented(range.beg) && IsPcInstrumented(range.end - 1))
+ continue;
+ VReport(1, "Adding instrumented range %p-%p from library '%s'\n",
+ range.beg, range.end, mod.full_name());
+ const uptr idx =
+ atomic_load(&instrumented_ranges_count_, memory_order_relaxed);
+ CHECK_LT(idx, kMaxLibs);
+ instrumented_code_ranges_[idx].begin = range.beg;
+ instrumented_code_ranges_[idx].end = range.end;
+ atomic_store(&instrumented_ranges_count_, idx + 1,
+ memory_order_release);
+ }
+ }
+ }
}
void LibIgnore::OnLibraryUnloaded() {
@@ -97,4 +123,5 @@ void LibIgnore::OnLibraryUnloaded() {
} // namespace __sanitizer
-#endif // #if SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC ||
+ // SANITIZER_NETBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_libignore.h b/libsanitizer/sanitizer_common/sanitizer_libignore.h
index 84419d1..e7627ee 100644
--- a/libsanitizer/sanitizer_common/sanitizer_libignore.h
+++ b/libsanitizer/sanitizer_common/sanitizer_libignore.h
@@ -28,6 +28,9 @@ class LibIgnore {
// Must be called during initialization.
void AddIgnoredLibrary(const char *name_templ);
+ void IgnoreNoninstrumentedModules(bool enable) {
+ track_instrumented_libs_ = enable;
+ }
// Must be called after a new dynamic library is loaded.
void OnLibraryLoaded(const char *name);
@@ -35,8 +38,14 @@ class LibIgnore {
// Must be called after a dynamic library is unloaded.
void OnLibraryUnloaded();
- // Checks whether the provided PC belongs to one of the ignored libraries.
- bool IsIgnored(uptr pc) const;
+ // Checks whether the provided PC belongs to one of the ignored libraries or
+ // the PC should be ignored because it belongs to an non-instrumented module
+ // (when ignore_noninstrumented_modules=1). Also returns true via
+ // "pc_in_ignored_lib" if the PC is in an ignored library, false otherwise.
+ bool IsIgnored(uptr pc, bool *pc_in_ignored_lib) const;
+
+ // Checks whether the provided PC belongs to an instrumented module.
+ bool IsPcInstrumented(uptr pc) const;
private:
struct Lib {
@@ -51,26 +60,48 @@ class LibIgnore {
uptr end;
};
+ inline bool IsInRange(uptr pc, const LibCodeRange &range) const {
+ return (pc >= range.begin && pc < range.end);
+ }
+
static const uptr kMaxLibs = 128;
// Hot part:
- atomic_uintptr_t loaded_count_;
- LibCodeRange code_ranges_[kMaxLibs];
+ atomic_uintptr_t ignored_ranges_count_;
+ LibCodeRange ignored_code_ranges_[kMaxLibs];
+
+ atomic_uintptr_t instrumented_ranges_count_;
+ LibCodeRange instrumented_code_ranges_[kMaxLibs];
// Cold part:
BlockingMutex mutex_;
uptr count_;
Lib libs_[kMaxLibs];
+ bool track_instrumented_libs_;
// Disallow copying of LibIgnore objects.
LibIgnore(const LibIgnore&); // not implemented
void operator = (const LibIgnore&); // not implemented
};
-inline bool LibIgnore::IsIgnored(uptr pc) const {
- const uptr n = atomic_load(&loaded_count_, memory_order_acquire);
+inline bool LibIgnore::IsIgnored(uptr pc, bool *pc_in_ignored_lib) const {
+ const uptr n = atomic_load(&ignored_ranges_count_, memory_order_acquire);
+ for (uptr i = 0; i < n; i++) {
+ if (IsInRange(pc, ignored_code_ranges_[i])) {
+ *pc_in_ignored_lib = true;
+ return true;
+ }
+ }
+ *pc_in_ignored_lib = false;
+ if (track_instrumented_libs_ && !IsPcInstrumented(pc))
+ return true;
+ return false;
+}
+
+inline bool LibIgnore::IsPcInstrumented(uptr pc) const {
+ const uptr n = atomic_load(&instrumented_ranges_count_, memory_order_acquire);
for (uptr i = 0; i < n; i++) {
- if (pc >= code_ranges_[i].begin && pc < code_ranges_[i].end)
+ if (IsInRange(pc, instrumented_code_ranges_[i]))
return true;
}
return false;
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.cc b/libsanitizer/sanitizer_common/sanitizer_linux.cc
index 5b6f186..2826cc8 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.cc
@@ -12,7 +12,7 @@
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
@@ -25,10 +25,14 @@
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
-#if !SANITIZER_FREEBSD
+#if SANITIZER_LINUX
#include <asm/param.h>
#endif
+#if SANITIZER_NETBSD
+#include <lwp.h>
+#endif
+
// For mips64, syscall(__NR_stat) fills the buffer in the 'struct kernel_stat'
// format. Struct kernel_stat is defined as 'struct stat' in asm/stat.h. To
// access stat from asm/stat.h, without conflicting with definition in
@@ -57,11 +61,17 @@
#include <ucontext.h>
#include <unistd.h>
+#if SANITIZER_LINUX
+#include <sys/utsname.h>
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
+#include <sys/personality.h>
+#endif
+
#if SANITIZER_FREEBSD
#include <sys/exec.h>
#include <sys/sysctl.h>
-#include <vm/vm_param.h>
-#include <vm/pmap.h>
#include <machine/atomic.h>
extern "C" {
// <sys/umtx.h> must be included after <errno.h> and <sys/types.h> on
@@ -71,10 +81,30 @@ extern "C" {
extern char **environ; // provided by crt1
#endif // SANITIZER_FREEBSD
+#if SANITIZER_NETBSD
+#include <limits.h> // For NAME_MAX
+#include <sys/sysctl.h>
+extern char **environ; // provided by crt1
+#endif // SANITIZER_NETBSD
+
#if !SANITIZER_ANDROID
#include <sys/signal.h>
#endif
+#ifndef __GLIBC_PREREQ
+#define __GLIBC_PREREQ(x, y) 0
+#endif
+
+#if SANITIZER_LINUX && __GLIBC_PREREQ(2, 16)
+# define SANITIZER_USE_GETAUXVAL 1
+#else
+# define SANITIZER_USE_GETAUXVAL 0
+#endif
+
+#if SANITIZER_USE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
+
#if SANITIZER_LINUX
// <linux/time.h>
struct kernel_timeval {
@@ -103,6 +133,15 @@ extern void internal_sigreturn();
}
#endif
+#if SANITIZER_LINUX && defined(__NR_getrandom)
+# if !defined(GRND_NONBLOCK)
+# define GRND_NONBLOCK 1
+# endif
+# define SANITIZER_USE_GETRANDOM 1
+#else
+# define SANITIZER_USE_GETRANDOM 0
+#endif // SANITIZER_LINUX && defined(__NR_getrandom)
+
namespace __sanitizer {
#if SANITIZER_LINUX && defined(__x86_64__)
@@ -117,7 +156,10 @@ namespace __sanitizer {
#if !SANITIZER_S390
uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd,
OFF_T offset) {
-#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+#if SANITIZER_NETBSD
+ return internal_syscall_ptr(SYSCALL(mmap), addr, length, prot, flags, fd,
+ (long)0, offset);
+#elif SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
return internal_syscall(SYSCALL(mmap), (uptr)addr, length, prot, flags, fd,
offset);
#else
@@ -160,26 +202,38 @@ uptr internal_open(const char *filename, int flags, u32 mode) {
uptr internal_read(fd_t fd, void *buf, uptr count) {
sptr res;
+#if SANITIZER_NETBSD
+ HANDLE_EINTR(res, internal_syscall_ptr(SYSCALL(read), fd, buf, count));
+#else
HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf,
count));
+#endif
return res;
}
uptr internal_write(fd_t fd, const void *buf, uptr count) {
sptr res;
+#if SANITIZER_NETBSD
+ HANDLE_EINTR(res, internal_syscall_ptr(SYSCALL(write), fd, buf, count));
+#else
HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf,
count));
+#endif
return res;
}
uptr internal_ftruncate(fd_t fd, uptr size) {
sptr res;
+#if SANITIZER_NETBSD
+ HANDLE_EINTR(res, internal_syscall(SYSCALL(ftruncate), fd, 0, (s64)size));
+#else
HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd,
(OFF_T)size));
+#endif
return res;
}
-#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && !SANITIZER_FREEBSD
+#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX
static void stat64_to_stat(struct stat64 *in, struct stat *out) {
internal_memset(out, 0, sizeof(*out));
out->st_dev = in->st_dev;
@@ -195,11 +249,25 @@ static void stat64_to_stat(struct stat64 *in, struct stat *out) {
out->st_atime = in->st_atime;
out->st_mtime = in->st_mtime;
out->st_ctime = in->st_ctime;
- out->st_ino = in->st_ino;
}
#endif
#if defined(__mips64)
+// Undefine compatibility macros from <sys/stat.h>
+// so that they would not clash with the kernel_stat
+// st_[a|m|c]time fields
+#undef st_atime
+#undef st_mtime
+#undef st_ctime
+#if defined(SANITIZER_ANDROID)
+// Bionic sys/stat.h defines additional macros
+// for compatibility with the old NDKs and
+// they clash with the kernel_stat structure
+// st_[a|m|c]time_nsec fields.
+#undef st_atime_nsec
+#undef st_mtime_nsec
+#undef st_ctime_nsec
+#endif
static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
internal_memset(out, 0, sizeof(*out));
out->st_dev = in->st_dev;
@@ -212,16 +280,30 @@ static void kernel_stat_to_stat(struct kernel_stat *in, struct stat *out) {
out->st_size = in->st_size;
out->st_blksize = in->st_blksize;
out->st_blocks = in->st_blocks;
- out->st_atime = in->st_atime_nsec;
- out->st_mtime = in->st_mtime_nsec;
- out->st_ctime = in->st_ctime_nsec;
- out->st_ino = in->st_ino;
+#if defined(__USE_MISC) || \
+ defined(__USE_XOPEN2K8) || \
+ defined(SANITIZER_ANDROID)
+ out->st_atim.tv_sec = in->st_atime;
+ out->st_atim.tv_nsec = in->st_atime_nsec;
+ out->st_mtim.tv_sec = in->st_mtime;
+ out->st_mtim.tv_nsec = in->st_mtime_nsec;
+ out->st_ctim.tv_sec = in->st_ctime;
+ out->st_ctim.tv_nsec = in->st_ctime_nsec;
+#else
+ out->st_atime = in->st_atime;
+ out->st_atimensec = in->st_atime_nsec;
+ out->st_mtime = in->st_mtime;
+ out->st_mtimensec = in->st_mtime_nsec;
+ out->st_ctime = in->st_ctime;
+ out->st_atimensec = in->st_ctime_nsec;
+#endif
}
#endif
uptr internal_stat(const char *path, void *buf) {
-#if SANITIZER_FREEBSD
- return internal_syscall(SYSCALL(stat), path, buf);
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
+ return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path,
+ (uptr)buf, 0);
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
(uptr)buf, 0);
@@ -244,8 +326,11 @@ uptr internal_stat(const char *path, void *buf) {
}
uptr internal_lstat(const char *path, void *buf) {
-#if SANITIZER_FREEBSD
+#if SANITIZER_NETBSD
return internal_syscall(SYSCALL(lstat), path, buf);
+#elif SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(fstatat), AT_FDCWD, (uptr)path,
+ (uptr)buf, AT_SYMLINK_NOFOLLOW);
#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(newfstatat), AT_FDCWD, (uptr)path,
(uptr)buf, AT_SYMLINK_NOFOLLOW);
@@ -268,7 +353,7 @@ uptr internal_lstat(const char *path, void *buf) {
}
uptr internal_fstat(fd_t fd, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS
+#if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS || SANITIZER_NETBSD
# if SANITIZER_MIPS64
// For mips64, fstat syscall fills buffer in the format of kernel_stat
struct kernel_stat kbuf;
@@ -302,7 +387,9 @@ uptr internal_dup2(int oldfd, int newfd) {
}
uptr internal_readlink(const char *path, char *buf, uptr bufsize) {
-#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+#if SANITIZER_NETBSD
+ return internal_syscall_ptr(SYSCALL(readlink), path, buf, bufsize);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(readlinkat), AT_FDCWD,
(uptr)path, (uptr)buf, bufsize);
#else
@@ -332,7 +419,7 @@ uptr internal_sched_yield() {
}
void internal__exit(int exitcode) {
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
internal_syscall(SYSCALL(exit), exitcode);
#else
internal_syscall(SYSCALL(exit_group), exitcode);
@@ -368,22 +455,28 @@ bool FileExists(const char *filename) {
return S_ISREG(st.st_mode);
}
-uptr GetTid() {
+tid_t GetTid() {
#if SANITIZER_FREEBSD
return (uptr)pthread_self();
+#elif SANITIZER_NETBSD
+ return _lwp_self();
#else
return internal_syscall(SYSCALL(gettid));
#endif
}
u64 NanoTime() {
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
timeval tv;
#else
kernel_timeval tv;
#endif
internal_memset(&tv, 0, sizeof(tv));
+#if SANITIZER_NETBSD
+ internal_syscall_ptr(SYSCALL(gettimeofday), &tv, NULL);
+#else
internal_syscall(SYSCALL(gettimeofday), (uptr)&tv, 0);
+#endif
return (u64)tv.tv_sec * 1000*1000*1000 + tv.tv_usec * 1000;
}
@@ -391,7 +484,7 @@ u64 NanoTime() {
// 'environ' array (on FreeBSD) and does not use libc. This function should be
// called first inside __asan_init.
const char *GetEnv(const char *name) {
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
if (::environ != 0) {
uptr NameLen = internal_strlen(name);
for (char **Env = ::environ; *Env != 0; Env++) {
@@ -525,6 +618,8 @@ void BlockingMutex::Lock() {
while (atomic_exchange(m, MtxSleeping, memory_order_acquire) != MtxUnlocked) {
#if SANITIZER_FREEBSD
_umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0);
+#elif SANITIZER_NETBSD
+ sched_yield(); /* No userspace futex-like synchromization */
#else
internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT, MtxSleeping, 0, 0, 0);
#endif
@@ -533,11 +628,13 @@ void BlockingMutex::Lock() {
void BlockingMutex::Unlock() {
atomic_uint32_t *m = reinterpret_cast<atomic_uint32_t *>(&opaque_storage_);
- u32 v = atomic_exchange(m, MtxUnlocked, memory_order_relaxed);
+ u32 v = atomic_exchange(m, MtxUnlocked, memory_order_release);
CHECK_NE(v, MtxUnlocked);
if (v == MtxSleeping) {
#if SANITIZER_FREEBSD
_umtx_op(m, UMTX_OP_WAKE, 1, 0, 0);
+#elif SANITIZER_NETBSD
+ /* No userspace futex-like synchromization */
#else
internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE, 1, 0, 0, 0);
#endif
@@ -553,6 +650,17 @@ void BlockingMutex::CheckLocked() {
// The actual size of this structure is specified by d_reclen.
// Note that getdents64 uses a different structure format. We only provide the
// 32-bit syscall here.
+#if SANITIZER_NETBSD
+// struct dirent is different for Linux and us. At this moment, we use only
+// d_fileno (Linux call this d_ino), d_reclen, and d_name.
+struct linux_dirent {
+ u64 d_ino; // d_fileno
+ u16 d_reclen;
+ u16 d_namlen; // not used
+ u8 d_type; // not used
+ char d_name[NAME_MAX + 1];
+};
+#else
struct linux_dirent {
#if SANITIZER_X32 || defined(__aarch64__)
u64 d_ino;
@@ -567,16 +675,34 @@ struct linux_dirent {
#endif
char d_name[256];
};
+#endif
// Syscall wrappers.
uptr internal_ptrace(int request, int pid, void *addr, void *data) {
+#if SANITIZER_NETBSD
+ // XXX We need additional work for ptrace:
+ // - for request, we use PT_FOO whereas Linux uses PTRACE_FOO
+ // - data is int for us, but void * for Linux
+ // - Linux sometimes uses data in the case where we use addr instead
+ // At this moment, this function is used only within
+ // "#if SANITIZER_LINUX && defined(__x86_64__)" block in
+ // sanitizer_stoptheworld_linux_libcdep.cc.
+ return internal_syscall_ptr(SYSCALL(ptrace), request, pid, (uptr)addr,
+ (uptr)data);
+#else
return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr,
(uptr)data);
+#endif
}
uptr internal_waitpid(int pid, int *status, int options) {
+#if SANITIZER_NETBSD
+ return internal_syscall(SYSCALL(wait4), pid, status, options,
+ NULL /* rusage */);
+#else
return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options,
0 /* rusage */);
+#endif
}
uptr internal_getpid() {
@@ -588,7 +714,11 @@ uptr internal_getppid() {
}
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
-#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
+#if SANITIZER_NETBSD
+ return internal_syscall(SYSCALL(getdents), fd, dirp, (uptr)count);
+#elif SANITIZER_FREEBSD
+ return internal_syscall(SYSCALL(getdirentries), fd, (uptr)dirp, count, NULL);
+#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS
return internal_syscall(SYSCALL(getdents64), fd, (uptr)dirp, count);
#else
return internal_syscall(SYSCALL(getdents), fd, (uptr)dirp, count);
@@ -596,7 +726,11 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) {
}
uptr internal_lseek(fd_t fd, OFF_T offset, int whence) {
+#if SANITIZER_NETBSD
+ return internal_syscall64(SYSCALL(lseek), fd, 0, offset, whence);
+#else
return internal_syscall(SYSCALL(lseek), fd, offset, whence);
+#endif
}
#if SANITIZER_LINUX
@@ -687,7 +821,7 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact) {
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset) {
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
return internal_syscall(SYSCALL(sigprocmask), how, set, oldset);
#else
__sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set;
@@ -796,20 +930,94 @@ bool ThreadLister::GetDirectoryEntries() {
return true;
}
+#if SANITIZER_WORDSIZE == 32
+// Take care of unusable kernel area in top gigabyte.
+static uptr GetKernelAreaSize() {
+#if SANITIZER_LINUX && !SANITIZER_X32
+ const uptr gbyte = 1UL << 30;
+
+ // Firstly check if there are writable segments
+ // mapped to top gigabyte (e.g. stack).
+ MemoryMappingLayout proc_maps(/*cache_enabled*/true);
+ MemoryMappedSegment segment;
+ while (proc_maps.Next(&segment)) {
+ if ((segment.end >= 3 * gbyte) && segment.IsWritable()) return 0;
+ }
+
+#if !SANITIZER_ANDROID
+ // Even if nothing is mapped, top Gb may still be accessible
+ // if we are running on 64-bit kernel.
+ // Uname may report misleading results if personality type
+ // is modified (e.g. under schroot) so check this as well.
+ struct utsname uname_info;
+ int pers = personality(0xffffffffUL);
+ if (!(pers & PER_MASK)
+ && uname(&uname_info) == 0
+ && internal_strstr(uname_info.machine, "64"))
+ return 0;
+#endif // SANITIZER_ANDROID
+
+ // Top gigabyte is reserved for kernel.
+ return gbyte;
+#else
+ return 0;
+#endif // SANITIZER_LINUX && !SANITIZER_X32
+}
+#endif // SANITIZER_WORDSIZE == 32
+
+uptr GetMaxVirtualAddress() {
+#if SANITIZER_NETBSD && defined(__x86_64__)
+ return 0x7f7ffffff000ULL; // (0x00007f8000000000 - PAGE_SIZE)
+#elif SANITIZER_WORDSIZE == 64
+# if defined(__powerpc64__) || defined(__aarch64__)
+ // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
+ // We somehow need to figure out which one we are using now and choose
+ // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
+ // Note that with 'ulimit -s unlimited' the stack is moved away from the top
+ // of the address space, so simply checking the stack address is not enough.
+ // This should (does) work for both PowerPC64 Endian modes.
+ // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
+ return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
+# elif defined(__mips64)
+ return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
+# elif defined(__s390x__)
+ return (1ULL << 53) - 1; // 0x001fffffffffffffUL;
+# else
+ return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
+# endif
+#else // SANITIZER_WORDSIZE == 32
+# if defined(__s390__)
+ return (1ULL << 31) - 1; // 0x7fffffff;
+# else
+ uptr res = (1ULL << 32) - 1; // 0xffffffff;
+ if (!common_flags()->full_address_space)
+ res -= GetKernelAreaSize();
+ CHECK_LT(reinterpret_cast<uptr>(&res), res);
+ return res;
+# endif
+#endif // SANITIZER_WORDSIZE
+}
+
uptr GetPageSize() {
// Android post-M sysconf(_SC_PAGESIZE) crashes if called from .preinit_array.
#if SANITIZER_ANDROID
return 4096;
#elif SANITIZER_LINUX && (defined(__x86_64__) || defined(__i386__))
return EXEC_PAGESIZE;
+#elif SANITIZER_USE_GETAUXVAL
+ return getauxval(AT_PAGESZ);
#else
return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy.
#endif
}
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
#if SANITIZER_FREEBSD
- const int Mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+ const int Mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
+#else
+ const int Mib[4] = {CTL_KERN, KERN_PROC_ARGS, -1, KERN_PROC_PATHNAME};
+#endif
const char *default_module_name = "kern.proc.pathname";
size_t Size = buf_len;
bool IsErr = (sysctl(Mib, ARRAY_SIZE(Mib), buf, &Size, NULL, 0) != 0);
@@ -1094,36 +1302,50 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
long long res;
-/* Stack frame offsets. */
-#if _CALL_ELF != 2
-#define FRAME_MIN_SIZE 112
-#define FRAME_TOC_SAVE 40
+// Stack frame structure.
+#if SANITIZER_PPC64V1
+// Back chain == 0 (SP + 112)
+// Frame (112 bytes):
+// Parameter save area (SP + 48), 8 doublewords
+// TOC save area (SP + 40)
+// Link editor doubleword (SP + 32)
+// Compiler doubleword (SP + 24)
+// LR save area (SP + 16)
+// CR save area (SP + 8)
+// Back chain (SP + 0)
+# define FRAME_SIZE 112
+# define FRAME_TOC_SAVE_OFFSET 40
+#elif SANITIZER_PPC64V2
+// Back chain == 0 (SP + 32)
+// Frame (32 bytes):
+// TOC save area (SP + 24)
+// LR save area (SP + 16)
+// CR save area (SP + 8)
+// Back chain (SP + 0)
+# define FRAME_SIZE 32
+# define FRAME_TOC_SAVE_OFFSET 24
#else
-#define FRAME_MIN_SIZE 32
-#define FRAME_TOC_SAVE 24
+# error "Unsupported PPC64 ABI"
#endif
if (!fn || !child_stack)
return -EINVAL;
CHECK_EQ(0, (uptr)child_stack % 16);
- child_stack = (char *)child_stack - 2 * sizeof(unsigned long long);
- ((unsigned long long *)child_stack)[0] = (uptr)fn;
- ((unsigned long long *)child_stack)[1] = (uptr)arg;
register int (*__fn)(void *) __asm__("r3") = fn;
register void *__cstack __asm__("r4") = child_stack;
register int __flags __asm__("r5") = flags;
- register void * __arg __asm__("r6") = arg;
- register int * __ptidptr __asm__("r7") = parent_tidptr;
- register void * __newtls __asm__("r8") = newtls;
- register int * __ctidptr __asm__("r9") = child_tidptr;
+ register void *__arg __asm__("r6") = arg;
+ register int *__ptidptr __asm__("r7") = parent_tidptr;
+ register void *__newtls __asm__("r8") = newtls;
+ register int *__ctidptr __asm__("r9") = child_tidptr;
__asm__ __volatile__(
- /* fn, arg, child_stack are saved acrVoss the syscall */
+ /* fn and arg are saved across the syscall */
"mr 28, %5\n\t"
- "mr 29, %6\n\t"
"mr 27, %8\n\t"
/* syscall
+ r0 == __NR_clone
r3 == flags
r4 == child_stack
r5 == parent_tidptr
@@ -1141,15 +1363,21 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
"crandc cr1*4+eq, cr1*4+eq, cr0*4+so\n\t"
"bne- cr1, 1f\n\t"
+ /* Set up stack frame */
+ "li 29, 0\n\t"
+ "stdu 29, -8(1)\n\t"
+ "stdu 1, -%12(1)\n\t"
/* Do the function call */
"std 2, %13(1)\n\t"
-#if _CALL_ELF != 2
+#if SANITIZER_PPC64V1
"ld 0, 0(28)\n\t"
"ld 2, 8(28)\n\t"
"mtctr 0\n\t"
-#else
+#elif SANITIZER_PPC64V2
"mr 12, 28\n\t"
"mtctr 12\n\t"
+#else
+# error "Unsupported PPC64 ABI"
#endif
"mr 3, 27\n\t"
"bctrl\n\t"
@@ -1163,13 +1391,151 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
"1:\n\t"
"mr %0, 3\n\t"
: "=r" (res)
- : "0" (-1), "i" (EINVAL),
- "i" (__NR_clone), "i" (__NR_exit),
- "r" (__fn), "r" (__cstack), "r" (__flags),
- "r" (__arg), "r" (__ptidptr), "r" (__newtls),
- "r" (__ctidptr), "i" (FRAME_MIN_SIZE), "i" (FRAME_TOC_SAVE)
- : "cr0", "cr1", "memory", "ctr",
- "r0", "r29", "r27", "r28");
+ : "0" (-1),
+ "i" (EINVAL),
+ "i" (__NR_clone),
+ "i" (__NR_exit),
+ "r" (__fn),
+ "r" (__cstack),
+ "r" (__flags),
+ "r" (__arg),
+ "r" (__ptidptr),
+ "r" (__newtls),
+ "r" (__ctidptr),
+ "i" (FRAME_SIZE),
+ "i" (FRAME_TOC_SAVE_OFFSET)
+ : "cr0", "cr1", "memory", "ctr", "r0", "r27", "r28", "r29");
+ return res;
+}
+#elif defined(__i386__) && SANITIZER_LINUX
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ int res;
+ if (!fn || !child_stack)
+ return -EINVAL;
+ CHECK_EQ(0, (uptr)child_stack % 16);
+ child_stack = (char *)child_stack - 7 * sizeof(unsigned int);
+ ((unsigned int *)child_stack)[0] = (uptr)flags;
+ ((unsigned int *)child_stack)[1] = (uptr)0;
+ ((unsigned int *)child_stack)[2] = (uptr)fn;
+ ((unsigned int *)child_stack)[3] = (uptr)arg;
+ __asm__ __volatile__(
+ /* %eax = syscall(%eax = SYSCALL(clone),
+ * %ebx = flags,
+ * %ecx = child_stack,
+ * %edx = parent_tidptr,
+ * %esi = new_tls,
+ * %edi = child_tidptr)
+ */
+
+ /* Obtain flags */
+ "movl (%%ecx), %%ebx\n"
+ /* Do the system call */
+ "pushl %%ebx\n"
+ "pushl %%esi\n"
+ "pushl %%edi\n"
+ /* Remember the flag value. */
+ "movl %%ebx, (%%ecx)\n"
+ "int $0x80\n"
+ "popl %%edi\n"
+ "popl %%esi\n"
+ "popl %%ebx\n"
+
+ /* if (%eax != 0)
+ * return;
+ */
+
+ "test %%eax,%%eax\n"
+ "jnz 1f\n"
+
+ /* terminate the stack frame */
+ "xorl %%ebp,%%ebp\n"
+ /* Call FN. */
+ "call *%%ebx\n"
+#ifdef PIC
+ "call here\n"
+ "here:\n"
+ "popl %%ebx\n"
+ "addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n"
+#endif
+ /* Call exit */
+ "movl %%eax, %%ebx\n"
+ "movl %2, %%eax\n"
+ "int $0x80\n"
+ "1:\n"
+ : "=a" (res)
+ : "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
+ "c"(child_stack),
+ "d"(parent_tidptr),
+ "S"(newtls),
+ "D"(child_tidptr)
+ : "memory");
+ return res;
+}
+#elif defined(__arm__) && SANITIZER_LINUX
+uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
+ int *parent_tidptr, void *newtls, int *child_tidptr) {
+ unsigned int res;
+ if (!fn || !child_stack)
+ return -EINVAL;
+ child_stack = (char *)child_stack - 2 * sizeof(unsigned int);
+ ((unsigned int *)child_stack)[0] = (uptr)fn;
+ ((unsigned int *)child_stack)[1] = (uptr)arg;
+ register int r0 __asm__("r0") = flags;
+ register void *r1 __asm__("r1") = child_stack;
+ register int *r2 __asm__("r2") = parent_tidptr;
+ register void *r3 __asm__("r3") = newtls;
+ register int *r4 __asm__("r4") = child_tidptr;
+ register int r7 __asm__("r7") = __NR_clone;
+
+#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__)
+# define ARCH_HAS_BX
+#endif
+#if __ARM_ARCH > 4
+# define ARCH_HAS_BLX
+#endif
+
+#ifdef ARCH_HAS_BX
+# ifdef ARCH_HAS_BLX
+# define BLX(R) "blx " #R "\n"
+# else
+# define BLX(R) "mov lr, pc; bx " #R "\n"
+# endif
+#else
+# define BLX(R) "mov lr, pc; mov pc," #R "\n"
+#endif
+
+ __asm__ __volatile__(
+ /* %r0 = syscall(%r7 = SYSCALL(clone),
+ * %r0 = flags,
+ * %r1 = child_stack,
+ * %r2 = parent_tidptr,
+ * %r3 = new_tls,
+ * %r4 = child_tidptr)
+ */
+
+ /* Do the system call */
+ "swi 0x0\n"
+
+ /* if (%r0 != 0)
+ * return %r0;
+ */
+ "cmp r0, #0\n"
+ "bne 1f\n"
+
+ /* In the child, now. Call "fn(arg)". */
+ "ldr r0, [sp, #4]\n"
+ "ldr ip, [sp], #8\n"
+ BLX(ip)
+ /* Call _exit(%r0). */
+ "mov r7, %7\n"
+ "swi 0x0\n"
+ "1:\n"
+ "mov %0, r0\n"
+ : "=r"(res)
+ : "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7),
+ "i"(__NR_exit)
+ : "memory");
return res;
}
#endif // defined(__x86_64__) && SANITIZER_LINUX
@@ -1217,14 +1583,27 @@ AndroidApiLevel AndroidGetApiLevel() {
#endif
-bool IsHandledDeadlySignal(int signum) {
- if (common_flags()->handle_abort && signum == SIGABRT)
- return true;
- if (common_flags()->handle_sigill && signum == SIGILL)
- return true;
- if (common_flags()->handle_sigfpe && signum == SIGFPE)
- return true;
- return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
+static HandleSignalMode GetHandleSignalModeImpl(int signum) {
+ switch (signum) {
+ case SIGABRT:
+ return common_flags()->handle_abort;
+ case SIGILL:
+ return common_flags()->handle_sigill;
+ case SIGFPE:
+ return common_flags()->handle_sigfpe;
+ case SIGSEGV:
+ return common_flags()->handle_segv;
+ case SIGBUS:
+ return common_flags()->handle_sigbus;
+ }
+ return kHandleSignalNo;
+}
+
+HandleSignalMode GetHandleSignalMode(int signum) {
+ HandleSignalMode result = GetHandleSignalModeImpl(signum);
+ if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler)
+ return kHandleSignalExclusive;
+ return result;
}
#if !SANITIZER_GO
@@ -1276,12 +1655,14 @@ static bool Aarch64GetESR(ucontext_t *ucontext, u64 *esr) {
}
#endif
-SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) {
+SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
ucontext_t *ucontext = (ucontext_t *)context;
#if defined(__x86_64__) || defined(__i386__)
static const uptr PF_WRITE = 1U << 1;
#if SANITIZER_FREEBSD
uptr err = ucontext->uc_mcontext.mc_err;
+#elif SANITIZER_NETBSD
+ uptr err = ucontext->uc_mcontext.__gregs[_REG_ERR];
#else
uptr err = ucontext->uc_mcontext.gregs[REG_ERR];
#endif
@@ -1301,7 +1682,11 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) {
#endif
}
-void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
+void SignalContext::DumpAllRegisters(void *context) {
+ // FIXME: Implement this.
+}
+
+static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#if defined(__arm__)
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.arm_pc;
@@ -1324,6 +1709,11 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*pc = ucontext->uc_mcontext.mc_rip;
*bp = ucontext->uc_mcontext.mc_rbp;
*sp = ucontext->uc_mcontext.mc_rsp;
+#elif SANITIZER_NETBSD
+ ucontext_t *ucontext = (ucontext_t *)context;
+ *pc = ucontext->uc_mcontext.__gregs[_REG_RIP];
+ *bp = ucontext->uc_mcontext.__gregs[_REG_RBP];
+ *sp = ucontext->uc_mcontext.__gregs[_REG_RSP];
# else
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_RIP];
@@ -1336,6 +1726,11 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
*pc = ucontext->uc_mcontext.mc_eip;
*bp = ucontext->uc_mcontext.mc_ebp;
*sp = ucontext->uc_mcontext.mc_esp;
+#elif SANITIZER_NETBSD
+ ucontext_t *ucontext = (ucontext_t *)context;
+ *pc = ucontext->uc_mcontext.__gregs[_REG_EIP];
+ *bp = ucontext->uc_mcontext.__gregs[_REG_EBP];
+ *sp = ucontext->uc_mcontext.__gregs[_REG_ESP];
# else
ucontext_t *ucontext = (ucontext_t*)context;
*pc = ucontext->uc_mcontext.gregs[REG_EIP];
@@ -1382,15 +1777,63 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
#endif
}
+void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }
+
void MaybeReexec() {
// No need to re-exec on Linux.
}
-uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) {
+void PrintModuleMap() { }
+
+void CheckNoDeepBind(const char *filename, int flag) {
+#ifdef RTLD_DEEPBIND
+ if (flag & RTLD_DEEPBIND) {
+ Report(
+ "You are trying to dlopen a %s shared library with RTLD_DEEPBIND flag"
+ " which is incompatibe with sanitizer runtime "
+ "(see https://github.com/google/sanitizers/issues/611 for details"
+ "). If you want to run %s library under sanitizers please remove "
+ "RTLD_DEEPBIND from dlopen flags.\n",
+ filename, filename);
+ Die();
+ }
+#endif
+}
+
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
+ uptr *largest_gap_found) {
UNREACHABLE("FindAvailableMemoryRange is not available");
return 0;
}
+bool GetRandom(void *buffer, uptr length, bool blocking) {
+ if (!buffer || !length || length > 256)
+ return false;
+#if SANITIZER_USE_GETRANDOM
+ static atomic_uint8_t skip_getrandom_syscall;
+ if (!atomic_load_relaxed(&skip_getrandom_syscall)) {
+ // Up to 256 bytes, getrandom will not be interrupted.
+ uptr res = internal_syscall(SYSCALL(getrandom), buffer, length,
+ blocking ? 0 : GRND_NONBLOCK);
+ int rverrno = 0;
+ if (internal_iserror(res, &rverrno) && rverrno == ENOSYS)
+ atomic_store_relaxed(&skip_getrandom_syscall, 1);
+ else if (res == length)
+ return true;
+ }
+#endif // SANITIZER_USE_GETRANDOM
+ // Up to 256 bytes, a read off /dev/urandom will not be interrupted.
+ // blocking is moot here, O_NONBLOCK has no effect when opening /dev/urandom.
+ uptr fd = internal_open("/dev/urandom", O_RDONLY);
+ if (internal_iserror(fd))
+ return false;
+ uptr res = internal_read(fd, buffer, length);
+ if (internal_iserror(res))
+ return false;
+ internal_close(fd);
+ return true;
+}
+
} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux.h b/libsanitizer/sanitizer_common/sanitizer_linux.h
index a42df57..910703d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux.h
+++ b/libsanitizer/sanitizer_common/sanitizer_linux.h
@@ -12,11 +12,12 @@
#define SANITIZER_LINUX_H
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
-#include "sanitizer_posix.h"
+#include "sanitizer_platform_limits_netbsd.h"
#include "sanitizer_platform_limits_posix.h"
+#include "sanitizer_posix.h"
struct link_map; // Opaque type returned by dlopen().
@@ -25,6 +26,19 @@ namespace __sanitizer {
// the one in <dirent.h>, which is used by readdir().
struct linux_dirent;
+struct ProcSelfMapsBuff {
+ char *data;
+ uptr mmaped_size;
+ uptr len;
+};
+
+struct MemoryMappingLayoutData {
+ ProcSelfMapsBuff proc_self_maps;
+ const char *current;
+};
+
+void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
+
// Syscall wrappers.
uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count);
uptr internal_sigaltstack(const void* ss, void* oss);
@@ -44,7 +58,8 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact);
#endif
void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \
- || defined(__powerpc64__) || defined(__s390__)
+ || defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \
+ || defined(__arm__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
@@ -83,7 +98,47 @@ bool LibraryNameIs(const char *full_name, const char *base_name);
// Call cb for each region mapped by map.
void ForEachMappedRegion(link_map *map, void (*cb)(const void *, uptr));
+
+#if SANITIZER_ANDROID
+
+#if defined(__aarch64__)
+# define __get_tls() \
+ ({ void** __v; __asm__("mrs %0, tpidr_el0" : "=r"(__v)); __v; })
+#elif defined(__arm__)
+# define __get_tls() \
+ ({ void** __v; __asm__("mrc p15, 0, %0, c13, c0, 3" : "=r"(__v)); __v; })
+#elif defined(__mips__)
+// On mips32r1, this goes via a kernel illegal instruction trap that's
+// optimized for v1.
+# define __get_tls() \
+ ({ register void** __v asm("v1"); \
+ __asm__(".set push\n" \
+ ".set mips32r2\n" \
+ "rdhwr %0,$29\n" \
+ ".set pop\n" : "=r"(__v)); \
+ __v; })
+#elif defined(__i386__)
+# define __get_tls() \
+ ({ void** __v; __asm__("movl %%gs:0, %0" : "=r"(__v)); __v; })
+#elif defined(__x86_64__)
+# define __get_tls() \
+ ({ void** __v; __asm__("mov %%fs:0, %0" : "=r"(__v)); __v; })
+#else
+#error "Unsupported architecture."
+#endif
+
+// The Android Bionic team has allocated a TLS slot for TSan starting with N,
+// given that Android currently doesn't support ELF TLS. It is used to store
+// Sanitizers thread specific data.
+static const int TLS_SLOT_TSAN = 8;
+
+ALWAYS_INLINE uptr *get_android_tls_ptr() {
+ return reinterpret_cast<uptr *>(&__get_tls()[TLS_SLOT_TSAN]);
+}
+
+#endif // SANITIZER_ANDROID
+
} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#endif // SANITIZER_LINUX_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
index 63e7066..b279cf3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_libcdep.cc
@@ -12,11 +12,12 @@
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#include "sanitizer_allocator_internal.h"
#include "sanitizer_atomic.h"
#include "sanitizer_common.h"
+#include "sanitizer_file.h"
#include "sanitizer_flags.h"
#include "sanitizer_freebsd.h"
#include "sanitizer_linux.h"
@@ -24,10 +25,7 @@
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
-#if SANITIZER_ANDROID || SANITIZER_FREEBSD
#include <dlfcn.h> // for dlsym()
-#endif
-
#include <link.h>
#include <pthread.h>
#include <signal.h>
@@ -82,28 +80,25 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
// Find the mapping that contains a stack variable.
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr start, end, offset;
+ MemoryMappedSegment segment;
uptr prev_end = 0;
- while (proc_maps.Next(&start, &end, &offset, nullptr, 0,
- /* protection */nullptr)) {
- if ((uptr)&rl < end)
- break;
- prev_end = end;
+ while (proc_maps.Next(&segment)) {
+ if ((uptr)&rl < segment.end) break;
+ prev_end = segment.end;
}
- CHECK((uptr)&rl >= start && (uptr)&rl < end);
+ CHECK((uptr)&rl >= segment.start && (uptr)&rl < segment.end);
// Get stacksize from rlimit, but clip it so that it does not overlap
// with other mappings.
uptr stacksize = rl.rlim_cur;
- if (stacksize > end - prev_end)
- stacksize = end - prev_end;
+ if (stacksize > segment.end - prev_end) stacksize = segment.end - prev_end;
// When running with unlimited stack size, we still want to set some limit.
// The unlimited stack size is caused by 'ulimit -s unlimited'.
// Also, for some reason, GNU make spawns subprocesses with unlimited stack.
if (stacksize > kMaxThreadStackSize)
stacksize = kMaxThreadStackSize;
- *stack_top = end;
- *stack_bottom = end - stacksize;
+ *stack_top = segment.end;
+ *stack_bottom = segment.end - stacksize;
return;
}
pthread_attr_t attr;
@@ -114,7 +109,6 @@ void GetThreadStackTopAndBottom(bool at_initialization, uptr *stack_top,
my_pthread_attr_getstack(&attr, &stackaddr, &stacksize);
pthread_attr_destroy(&attr);
- CHECK_LE(stacksize, kMaxThreadStackSize); // Sanity check.
*stack_top = (uptr)stackaddr + stacksize;
*stack_bottom = (uptr)stackaddr;
}
@@ -153,7 +147,8 @@ bool SanitizerGetThreadName(char *name, int max_len) {
#endif
}
-#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
+#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO && \
+ !SANITIZER_NETBSD
static uptr g_tls_size;
#ifdef __i386__
@@ -181,11 +176,12 @@ void InitTlsSize() {
}
#else
void InitTlsSize() { }
-#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO
+#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO &&
+ // !SANITIZER_NETBSD
#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \
- || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__)) \
- && SANITIZER_LINUX && !SANITIZER_ANDROID
+ || defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) \
+ || defined(__arm__)) && SANITIZER_LINUX && !SANITIZER_ANDROID
// sizeof(struct pthread) from glibc.
static atomic_uintptr_t kThreadDescriptorSize;
@@ -193,14 +189,14 @@ uptr ThreadDescriptorSize() {
uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed);
if (val)
return val;
-#if defined(__x86_64__) || defined(__i386__)
+#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
#ifdef _CS_GNU_LIBC_VERSION
char buf[64];
uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) {
char *end;
int minor = internal_simple_strtoll(buf + 8, &end, 10);
- if (end != buf + 8 && (*end == '\0' || *end == '.')) {
+ if (end != buf + 8 && (*end == '\0' || *end == '.' || *end == '-')) {
int patch = 0;
if (*end == '.')
// strtoll will return 0 if no valid conversion could be performed
@@ -209,6 +205,9 @@ uptr ThreadDescriptorSize() {
/* sizeof(struct pthread) values from various glibc versions. */
if (SANITIZER_X32)
val = 1728; // Assume only one particular version for x32.
+ // For ARM sizeof(struct pthread) changed in Glibc 2.23.
+ else if (SANITIZER_ARM)
+ val = minor <= 22 ? 1120 : 1216;
else if (minor <= 3)
val = FIRST_32_SECOND_64(1104, 1696);
else if (minor == 4)
@@ -271,9 +270,7 @@ static uptr TlsPreTcbSize() {
# endif
const uptr kTlsAlign = 16;
const uptr kTlsPreTcbSize =
- (ThreadDescriptorSize() + kTcbHead + kTlsAlign - 1) & ~(kTlsAlign - 1);
- InitTlsSize();
- g_tls_size = (g_tls_size + kTlsPreTcbSize + kTlsAlign -1) & ~(kTlsAlign - 1);
+ RoundUpTo(ThreadDescriptorSize() + kTcbHead, kTlsAlign);
return kTlsPreTcbSize;
}
#endif
@@ -296,7 +293,7 @@ uptr ThreadSelf() {
rdhwr %0,$29;\
.set pop" : "=r" (thread_pointer));
descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
-# elif defined(__aarch64__)
+# elif defined(__aarch64__) || defined(__arm__)
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
ThreadDescriptorSize();
# elif defined(__s390__)
@@ -335,7 +332,9 @@ static void **ThreadSelfSegbase() {
uptr ThreadSelf() {
return (uptr)ThreadSelfSegbase()[2];
}
-#endif // SANITIZER_FREEBSD
+#elif SANITIZER_NETBSD
+uptr ThreadSelf() { return (uptr)pthread_self(); }
+#endif // SANITIZER_NETBSD
#if !SANITIZER_GO
static void GetTls(uptr *addr, uptr *size) {
@@ -345,7 +344,8 @@ static void GetTls(uptr *addr, uptr *size) {
*size = GetTlsSize();
*addr -= *size;
*addr += ThreadDescriptorSize();
-# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__)
+# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \
+ || defined(__arm__)
*addr = ThreadSelf();
*size = GetTlsSize();
# else
@@ -365,7 +365,7 @@ static void GetTls(uptr *addr, uptr *size) {
*addr = (uptr) dtv[2];
*size = (*addr == 0) ? 0 : ((uptr) segbase[0] - (uptr) dtv[2]);
}
-#elif SANITIZER_ANDROID
+#elif SANITIZER_ANDROID || SANITIZER_NETBSD
*addr = 0;
*size = 0;
#else
@@ -376,10 +376,12 @@ static void GetTls(uptr *addr, uptr *size) {
#if !SANITIZER_GO
uptr GetTlsSize() {
-#if SANITIZER_FREEBSD || SANITIZER_ANDROID
+#if SANITIZER_FREEBSD || SANITIZER_ANDROID || SANITIZER_NETBSD
uptr addr, size;
GetTls(&addr, &size);
return size;
+#elif defined(__mips__) || defined(__powerpc64__)
+ return RoundUpTo(g_tls_size + TlsPreTcbSize(), 16);
#else
return g_tls_size;
#endif
@@ -420,7 +422,7 @@ typedef ElfW(Phdr) Elf_Phdr;
# endif
struct DlIteratePhdrData {
- InternalMmapVector<LoadedModule> *modules;
+ InternalMmapVectorNoCtor<LoadedModule> *modules;
bool first;
};
@@ -444,7 +446,9 @@ static int dl_iterate_phdr_cb(dl_phdr_info *info, size_t size, void *arg) {
uptr cur_beg = info->dlpi_addr + phdr->p_vaddr;
uptr cur_end = cur_beg + phdr->p_memsz;
bool executable = phdr->p_flags & PF_X;
- cur_module.addAddressRange(cur_beg, cur_end, executable);
+ bool writable = phdr->p_flags & PF_W;
+ cur_module.addAddressRange(cur_beg, cur_end, executable,
+ writable);
}
}
data->modules->push_back(cur_module);
@@ -456,21 +460,41 @@ extern "C" __attribute__((weak)) int dl_iterate_phdr(
int (*)(struct dl_phdr_info *, size_t, void *), void *);
#endif
-void ListOfModules::init() {
- clear();
+static bool requiresProcmaps() {
#if SANITIZER_ANDROID && __ANDROID_API__ <= 22
- u32 api_level = AndroidGetApiLevel();
// Fall back to /proc/maps if dl_iterate_phdr is unavailable or broken.
// The runtime check allows the same library to work with
// both K and L (and future) Android releases.
- if (api_level <= ANDROID_LOLLIPOP_MR1) { // L or earlier
- MemoryMappingLayout memory_mapping(false);
- memory_mapping.DumpListOfModules(&modules_);
- return;
- }
+ return AndroidGetApiLevel() <= ANDROID_LOLLIPOP_MR1;
+#else
+ return false;
#endif
- DlIteratePhdrData data = {&modules_, true};
- dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+}
+
+static void procmapsInit(InternalMmapVectorNoCtor<LoadedModule> *modules) {
+ MemoryMappingLayout memory_mapping(/*cache_enabled*/true);
+ memory_mapping.DumpListOfModules(modules);
+}
+
+void ListOfModules::init() {
+ clearOrInit();
+ if (requiresProcmaps()) {
+ procmapsInit(&modules_);
+ } else {
+ DlIteratePhdrData data = {&modules_, true};
+ dl_iterate_phdr(dl_iterate_phdr_cb, &data);
+ }
+}
+
+// When a custom loader is used, dl_iterate_phdr may not contain the full
+// list of modules. Allow callers to fall back to using procmaps.
+void ListOfModules::fallbackInit() {
+ if (!requiresProcmaps()) {
+ clearOrInit();
+ procmapsInit(&modules_);
+ } else {
+ clear();
+ }
}
// getrusage does not give us the current RSS, only the max RSS.
@@ -547,6 +571,15 @@ void LogMessageOnPrintf(const char *str) {
WriteToSyslog(str);
}
+#if SANITIZER_ANDROID
+extern "C" __attribute__((weak)) void android_set_abort_message(const char *);
+void SetAbortMessage(const char *str) {
+ if (&android_set_abort_message) android_set_abort_message(str);
+}
+#else
+void SetAbortMessage(const char *str) {}
+#endif
+
#endif // SANITIZER_LINUX
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cc b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cc
index 3faaa1c..b836447 100644
--- a/libsanitizer/sanitizer_common/sanitizer_linux_s390.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_linux_s390.cc
@@ -176,6 +176,13 @@ static bool FixedCVE_2016_2143() {
// 4.4.6+ is OK.
if (minor == 4 && patch >= 6)
return true;
+ if (minor == 4 && patch == 0 && ptr[0] == '-' &&
+ internal_strstr(buf.version, "Ubuntu")) {
+ // Check Ubuntu 16.04
+ int r1 = internal_simple_strtoll(ptr+1, &ptr, 10);
+ if (r1 >= 13) // 4.4.0-13 or later
+ return true;
+ }
// Otherwise, OK if 4.5+.
return minor >= 5;
} else {
diff --git a/libsanitizer/sanitizer_common/sanitizer_list.h b/libsanitizer/sanitizer_common/sanitizer_list.h
index 190c7e67..d7e8b50 100644
--- a/libsanitizer/sanitizer_common/sanitizer_list.h
+++ b/libsanitizer/sanitizer_common/sanitizer_list.h
@@ -68,6 +68,17 @@ struct IntrusiveList {
size_--;
}
+ void extract(Item *prev, Item *x) {
+ CHECK(!empty());
+ CHECK_NE(prev, nullptr);
+ CHECK_NE(x, nullptr);
+ CHECK_EQ(prev->next, x);
+ prev->next = x->next;
+ if (last_ == x)
+ last_ = prev;
+ size_--;
+ }
+
Item *front() { return first_; }
const Item *front() const { return first_; }
Item *back() { return last_; }
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.cc b/libsanitizer/sanitizer_common/sanitizer_mac.cc
index 2a05102..8c78494 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.cc
@@ -21,6 +21,7 @@
#include <stdio.h>
#include "sanitizer_common.h"
+#include "sanitizer_file.h"
#include "sanitizer_flags.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_libc.h"
@@ -100,12 +101,12 @@ extern "C" int __munmap(void *, size_t) SANITIZER_WEAK_ATTRIBUTE;
uptr internal_mmap(void *addr, size_t length, int prot, int flags,
int fd, u64 offset) {
if (fd == -1) fd = VM_MAKE_TAG(VM_MEMORY_ANALYSIS_TOOL);
- if (__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset);
+ if (&__mmap) return (uptr)__mmap(addr, length, prot, flags, fd, offset);
return (uptr)mmap(addr, length, prot, flags, fd, offset);
}
uptr internal_munmap(void *addr, uptr length) {
- if (__munmap) return __munmap(addr, length);
+ if (&__munmap) return __munmap(addr, length);
return munmap(addr, length);
}
@@ -189,14 +190,15 @@ void internal_sigfillset(__sanitizer_sigset_t *set) { sigfillset(set); }
uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set,
__sanitizer_sigset_t *oldset) {
- return sigprocmask(how, set, oldset);
+ // Don't use sigprocmask here, because it affects all threads.
+ return pthread_sigmask(how, set, oldset);
}
// Doesn't call pthread_atfork() handlers (but not available on 10.6).
extern "C" pid_t __fork(void) SANITIZER_WEAK_ATTRIBUTE;
int internal_fork() {
- if (__fork)
+ if (&__fork)
return __fork();
return fork();
}
@@ -250,9 +252,8 @@ bool FileExists(const char *filename) {
return S_ISREG(st.st_mode);
}
-uptr GetTid() {
- // FIXME: This can potentially get truncated on 32-bit, where uptr is 4 bytes.
- uint64_t tid;
+tid_t GetTid() {
+ tid_t tid;
pthread_threadid_np(nullptr, &tid);
return tid;
}
@@ -346,20 +347,16 @@ BlockingMutex::BlockingMutex() {
void BlockingMutex::Lock() {
CHECK(sizeof(OSSpinLock) <= sizeof(opaque_storage_));
CHECK_EQ(OS_SPINLOCK_INIT, 0);
- CHECK_NE(owner_, (uptr)pthread_self());
+ CHECK_EQ(owner_, 0);
OSSpinLockLock((OSSpinLock*)&opaque_storage_);
- CHECK(!owner_);
- owner_ = (uptr)pthread_self();
}
void BlockingMutex::Unlock() {
- CHECK(owner_ == (uptr)pthread_self());
- owner_ = 0;
OSSpinLockUnlock((OSSpinLock*)&opaque_storage_);
}
void BlockingMutex::CheckLocked() {
- CHECK_EQ((uptr)pthread_self(), owner_);
+ CHECK_NE(*(OSSpinLock*)&opaque_storage_, 0);
}
u64 NanoTime() {
@@ -373,6 +370,27 @@ uptr GetTlsSize() {
void InitTlsSize() {
}
+uptr TlsBaseAddr() {
+ uptr segbase = 0;
+#if defined(__x86_64__)
+ asm("movq %%gs:0,%0" : "=r"(segbase));
+#elif defined(__i386__)
+ asm("movl %%gs:0,%0" : "=r"(segbase));
+#endif
+ return segbase;
+}
+
+// The size of the tls on darwin does not appear to be well documented,
+// however the vm memory map suggests that it is 1024 uptrs in size,
+// with a size of 0x2000 bytes on x86_64 and 0x1000 bytes on i386.
+uptr TlsSize() {
+#if defined(__x86_64__) || defined(__i386__)
+ return 1024 * sizeof(uptr);
+#else
+ return 0;
+#endif
+}
+
void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
uptr *tls_addr, uptr *tls_size) {
#if !SANITIZER_GO
@@ -380,8 +398,8 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
GetThreadStackTopAndBottom(main, &stack_top, &stack_bottom);
*stk_addr = stack_bottom;
*stk_size = stack_top - stack_bottom;
- *tls_addr = 0;
- *tls_size = 0;
+ *tls_addr = TlsBaseAddr();
+ *tls_size = TlsSize();
#else
*stk_addr = 0;
*stk_size = 0;
@@ -391,18 +409,37 @@ void GetThreadStackAndTls(bool main, uptr *stk_addr, uptr *stk_size,
}
void ListOfModules::init() {
- clear();
+ clearOrInit();
MemoryMappingLayout memory_mapping(false);
memory_mapping.DumpListOfModules(&modules_);
}
-bool IsHandledDeadlySignal(int signum) {
+void ListOfModules::fallbackInit() { clear(); }
+
+static HandleSignalMode GetHandleSignalModeImpl(int signum) {
+ switch (signum) {
+ case SIGABRT:
+ return common_flags()->handle_abort;
+ case SIGILL:
+ return common_flags()->handle_sigill;
+ case SIGFPE:
+ return common_flags()->handle_sigfpe;
+ case SIGSEGV:
+ return common_flags()->handle_segv;
+ case SIGBUS:
+ return common_flags()->handle_sigbus;
+ }
+ return kHandleSignalNo;
+}
+
+HandleSignalMode GetHandleSignalMode(int signum) {
+ // Handling fatal signals on watchOS and tvOS devices is disallowed.
if ((SANITIZER_WATCHOS || SANITIZER_TVOS) && !(SANITIZER_IOSSIM))
- // Handling fatal signals on watchOS and tvOS devices is disallowed.
- return false;
- if (common_flags()->handle_abort && signum == SIGABRT)
- return true;
- return (signum == SIGSEGV || signum == SIGBUS) && common_flags()->handle_segv;
+ return kHandleSignalNo;
+ HandleSignalMode result = GetHandleSignalModeImpl(signum);
+ if (result == kHandleSignalYes && !common_flags()->allow_user_segv_handler)
+ return kHandleSignalExclusive;
+ return result;
}
MacosVersion cached_macos_version = MACOS_VERSION_UNINITIALIZED;
@@ -448,6 +485,15 @@ MacosVersion GetMacosVersion() {
return result;
}
+bool PlatformHasDifferentMemcpyAndMemmove() {
+ // On OS X 10.7 memcpy() and memmove() are both resolved
+ // into memmove$VARIANT$sse42.
+ // See also https://github.com/google/sanitizers/issues/34.
+ // TODO(glider): need to check dynamically that memcpy() and memmove() are
+ // actually the same function.
+ return GetMacosVersion() == MACOS_VERSION_SNOW_LEOPARD;
+}
+
uptr GetRSS() {
struct task_basic_info info;
unsigned count = TASK_BASIC_INFO_COUNT;
@@ -528,7 +574,7 @@ void LogFullErrorReport(const char *buffer) {
#endif
}
-SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) {
+SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
#if defined(__x86_64__) || defined(__i386__)
ucontext_t *ucontext = static_cast<ucontext_t*>(context);
return ucontext->uc_mcontext->__es.__err & 2 /*T_PF_WRITE*/ ? WRITE : READ;
@@ -537,7 +583,7 @@ SignalContext::WriteFlag SignalContext::GetWriteFlag(void *context) {
#endif
}
-void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
+static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
ucontext_t *ucontext = (ucontext_t*)context;
# if defined(__aarch64__)
*pc = ucontext->uc_mcontext->__ss.__pc;
@@ -564,6 +610,8 @@ void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) {
# endif
}
+void SignalContext::InitPcSpBp() { GetPcSpBp(context, &pc, &sp, &bp); }
+
#if !SANITIZER_GO
static const char kDyldInsertLibraries[] = "DYLD_INSERT_LIBRARIES";
LowLevelAllocator allocator_for_env;
@@ -755,9 +803,69 @@ char **GetArgv() {
return *_NSGetArgv();
}
+#if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM
+// The task_vm_info struct is normally provided by the macOS SDK, but we need
+// fields only available in 10.12+. Declare the struct manually to be able to
+// build against older SDKs.
+struct __sanitizer_task_vm_info {
+ mach_vm_size_t virtual_size;
+ integer_t region_count;
+ integer_t page_size;
+ mach_vm_size_t resident_size;
+ mach_vm_size_t resident_size_peak;
+ mach_vm_size_t device;
+ mach_vm_size_t device_peak;
+ mach_vm_size_t internal;
+ mach_vm_size_t internal_peak;
+ mach_vm_size_t external;
+ mach_vm_size_t external_peak;
+ mach_vm_size_t reusable;
+ mach_vm_size_t reusable_peak;
+ mach_vm_size_t purgeable_volatile_pmap;
+ mach_vm_size_t purgeable_volatile_resident;
+ mach_vm_size_t purgeable_volatile_virtual;
+ mach_vm_size_t compressed;
+ mach_vm_size_t compressed_peak;
+ mach_vm_size_t compressed_lifetime;
+ mach_vm_size_t phys_footprint;
+ mach_vm_address_t min_address;
+ mach_vm_address_t max_address;
+};
+#define __SANITIZER_TASK_VM_INFO_COUNT ((mach_msg_type_number_t) \
+ (sizeof(__sanitizer_task_vm_info) / sizeof(natural_t)))
+
+uptr GetTaskInfoMaxAddress() {
+ __sanitizer_task_vm_info vm_info = {};
+ mach_msg_type_number_t count = __SANITIZER_TASK_VM_INFO_COUNT;
+ int err = task_info(mach_task_self(), TASK_VM_INFO, (int *)&vm_info, &count);
+ if (err == 0) {
+ return vm_info.max_address - 1;
+ } else {
+ // xnu cannot provide vm address limit
+ return 0x200000000 - 1;
+ }
+}
+#endif
+
+uptr GetMaxVirtualAddress() {
+#if SANITIZER_WORDSIZE == 64
+# if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM
+ // Get the maximum VM address
+ static uptr max_vm = GetTaskInfoMaxAddress();
+ CHECK(max_vm);
+ return max_vm;
+# else
+ return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
+# endif
+#else // SANITIZER_WORDSIZE == 32
+ return (1ULL << 32) - 1; // 0xffffffff;
+#endif // SANITIZER_WORDSIZE
+}
+
uptr FindAvailableMemoryRange(uptr shadow_size,
uptr alignment,
- uptr left_padding) {
+ uptr left_padding,
+ uptr *largest_gap_found) {
typedef vm_region_submap_short_info_data_64_t RegionInfo;
enum { kRegionInfoSize = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64 };
// Start searching for available memory region past PAGEZERO, which is
@@ -768,6 +876,7 @@ uptr FindAvailableMemoryRange(uptr shadow_size,
mach_vm_address_t address = start_address;
mach_vm_address_t free_begin = start_address;
kern_return_t kr = KERN_SUCCESS;
+ if (largest_gap_found) *largest_gap_found = 0;
while (kr == KERN_SUCCESS) {
mach_vm_size_t vmsize = 0;
natural_t depth = 0;
@@ -777,10 +886,15 @@ uptr FindAvailableMemoryRange(uptr shadow_size,
(vm_region_info_t)&vminfo, &count);
if (free_begin != address) {
// We found a free region [free_begin..address-1].
- uptr shadow_address = RoundUpTo((uptr)free_begin + left_padding,
- alignment);
- if (shadow_address + shadow_size < (uptr)address) {
- return shadow_address;
+ uptr gap_start = RoundUpTo((uptr)free_begin + left_padding, alignment);
+ uptr gap_end = RoundDownTo((uptr)address, alignment);
+ uptr gap_size = gap_end > gap_start ? gap_end - gap_start : 0;
+ if (shadow_size < gap_size) {
+ return gap_start;
+ }
+
+ if (largest_gap_found && *largest_gap_found < gap_size) {
+ *largest_gap_found = gap_size;
}
}
// Move to the next region.
@@ -795,6 +909,95 @@ uptr FindAvailableMemoryRange(uptr shadow_size,
// FIXME implement on this platform.
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { }
+void SignalContext::DumpAllRegisters(void *context) {
+ Report("Register values:\n");
+
+ ucontext_t *ucontext = (ucontext_t*)context;
+# define DUMPREG64(r) \
+ Printf("%s = 0x%016llx ", #r, ucontext->uc_mcontext->__ss.__ ## r);
+# define DUMPREG32(r) \
+ Printf("%s = 0x%08x ", #r, ucontext->uc_mcontext->__ss.__ ## r);
+# define DUMPREG_(r) Printf(" "); DUMPREG(r);
+# define DUMPREG__(r) Printf(" "); DUMPREG(r);
+# define DUMPREG___(r) Printf(" "); DUMPREG(r);
+
+# if defined(__x86_64__)
+# define DUMPREG(r) DUMPREG64(r)
+ DUMPREG(rax); DUMPREG(rbx); DUMPREG(rcx); DUMPREG(rdx); Printf("\n");
+ DUMPREG(rdi); DUMPREG(rsi); DUMPREG(rbp); DUMPREG(rsp); Printf("\n");
+ DUMPREG_(r8); DUMPREG_(r9); DUMPREG(r10); DUMPREG(r11); Printf("\n");
+ DUMPREG(r12); DUMPREG(r13); DUMPREG(r14); DUMPREG(r15); Printf("\n");
+# elif defined(__i386__)
+# define DUMPREG(r) DUMPREG32(r)
+ DUMPREG(eax); DUMPREG(ebx); DUMPREG(ecx); DUMPREG(edx); Printf("\n");
+ DUMPREG(edi); DUMPREG(esi); DUMPREG(ebp); DUMPREG(esp); Printf("\n");
+# elif defined(__aarch64__)
+# define DUMPREG(r) DUMPREG64(r)
+ DUMPREG_(x[0]); DUMPREG_(x[1]); DUMPREG_(x[2]); DUMPREG_(x[3]); Printf("\n");
+ DUMPREG_(x[4]); DUMPREG_(x[5]); DUMPREG_(x[6]); DUMPREG_(x[7]); Printf("\n");
+ DUMPREG_(x[8]); DUMPREG_(x[9]); DUMPREG(x[10]); DUMPREG(x[11]); Printf("\n");
+ DUMPREG(x[12]); DUMPREG(x[13]); DUMPREG(x[14]); DUMPREG(x[15]); Printf("\n");
+ DUMPREG(x[16]); DUMPREG(x[17]); DUMPREG(x[18]); DUMPREG(x[19]); Printf("\n");
+ DUMPREG(x[20]); DUMPREG(x[21]); DUMPREG(x[22]); DUMPREG(x[23]); Printf("\n");
+ DUMPREG(x[24]); DUMPREG(x[25]); DUMPREG(x[26]); DUMPREG(x[27]); Printf("\n");
+ DUMPREG(x[28]); DUMPREG___(fp); DUMPREG___(lr); DUMPREG___(sp); Printf("\n");
+# elif defined(__arm__)
+# define DUMPREG(r) DUMPREG32(r)
+ DUMPREG_(r[0]); DUMPREG_(r[1]); DUMPREG_(r[2]); DUMPREG_(r[3]); Printf("\n");
+ DUMPREG_(r[4]); DUMPREG_(r[5]); DUMPREG_(r[6]); DUMPREG_(r[7]); Printf("\n");
+ DUMPREG_(r[8]); DUMPREG_(r[9]); DUMPREG(r[10]); DUMPREG(r[11]); Printf("\n");
+ DUMPREG(r[12]); DUMPREG___(sp); DUMPREG___(lr); DUMPREG___(pc); Printf("\n");
+# else
+# error "Unknown architecture"
+# endif
+
+# undef DUMPREG64
+# undef DUMPREG32
+# undef DUMPREG_
+# undef DUMPREG__
+# undef DUMPREG___
+# undef DUMPREG
+}
+
+static inline bool CompareBaseAddress(const LoadedModule &a,
+ const LoadedModule &b) {
+ return a.base_address() < b.base_address();
+}
+
+void FormatUUID(char *out, uptr size, const u8 *uuid) {
+ internal_snprintf(out, size,
+ "<%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-"
+ "%02X%02X%02X%02X%02X%02X>",
+ uuid[0], uuid[1], uuid[2], uuid[3], uuid[4], uuid[5],
+ uuid[6], uuid[7], uuid[8], uuid[9], uuid[10], uuid[11],
+ uuid[12], uuid[13], uuid[14], uuid[15]);
+}
+
+void PrintModuleMap() {
+ Printf("Process module map:\n");
+ MemoryMappingLayout memory_mapping(false);
+ InternalMmapVector<LoadedModule> modules(/*initial_capacity*/ 128);
+ memory_mapping.DumpListOfModules(&modules);
+ InternalSort(&modules, modules.size(), CompareBaseAddress);
+ for (uptr i = 0; i < modules.size(); ++i) {
+ char uuid_str[128];
+ FormatUUID(uuid_str, sizeof(uuid_str), modules[i].uuid());
+ Printf("0x%zx-0x%zx %s (%s) %s\n", modules[i].base_address(),
+ modules[i].max_executable_address(), modules[i].full_name(),
+ ModuleArchToString(modules[i].arch()), uuid_str);
+ }
+ Printf("End of module map.\n");
+}
+
+void CheckNoDeepBind(const char *filename, int flag) {
+ // Do nothing.
+}
+
+// FIXME: implement on this platform.
+bool GetRandom(void *buffer, uptr length, bool blocking) {
+ UNIMPLEMENTED();
+}
+
} // namespace __sanitizer
#endif // SANITIZER_MAC
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac.h b/libsanitizer/sanitizer_common/sanitizer_mac.h
index 4bea069..4881b62 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mac.h
+++ b/libsanitizer/sanitizer_common/sanitizer_mac.h
@@ -18,6 +18,17 @@
namespace __sanitizer {
+struct MemoryMappingLayoutData {
+ int current_image;
+ u32 current_magic;
+ u32 current_filetype;
+ ModuleArch current_arch;
+ u8 current_uuid[kModuleUUIDSize];
+ int current_load_cmd_count;
+ char *current_load_cmd_addr;
+ bool current_instrumented;
+};
+
enum MacosVersion {
MACOS_VERSION_UNINITIALIZED = 0,
MACOS_VERSION_UNKNOWN,
@@ -34,6 +45,8 @@ MacosVersion GetMacosVersion();
char **GetEnviron();
+void RestrictMemoryToMaxAddress(uptr max_address);
+
} // namespace __sanitizer
extern "C" {
diff --git a/libsanitizer/sanitizer_common/sanitizer_mac_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_mac_libcdep.cc
new file mode 100644
index 0000000..b376a07
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_mac_libcdep.cc
@@ -0,0 +1,28 @@
+//===-- sanitizer_mac_libcdep.cc ------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries and
+// implements OSX-specific functions.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_MAC
+#include "sanitizer_mac.h"
+
+#include <sys/mman.h>
+
+namespace __sanitizer {
+
+void RestrictMemoryToMaxAddress(uptr max_address) {
+ uptr size_to_mmap = GetMaxVirtualAddress() + 1 - max_address;
+ void *res = MmapFixedNoAccess(max_address, size_to_mmap, "high gap");
+ CHECK(res != MAP_FAILED);
+}
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_MAC
diff --git a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
index 93fb19e..2ca4e06 100644
--- a/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_malloc_mac.inc
@@ -44,9 +44,48 @@ INTERCEPTOR(malloc_zone_t *, malloc_create_zone,
// This matches the behavior of malloc_create_zone() on OSX 10.7 and higher.
mprotect(new_zone, allocated_size, PROT_READ);
}
+ // We're explicitly *NOT* registering the zone.
return new_zone;
}
+INTERCEPTOR(void, malloc_destroy_zone, malloc_zone_t *zone) {
+ COMMON_MALLOC_ENTER();
+ // We don't need to do anything here. We're not registering new zones, so we
+ // don't to unregister. Just un-mprotect and free() the zone.
+ if (GetMacosVersion() >= MACOS_VERSION_LION) {
+ uptr page_size = GetPageSizeCached();
+ uptr allocated_size = RoundUpTo(sizeof(sanitizer_zone), page_size);
+ mprotect(zone, allocated_size, PROT_READ | PROT_WRITE);
+ }
+ if (zone->zone_name) {
+ COMMON_MALLOC_FREE((void *)zone->zone_name);
+ }
+ COMMON_MALLOC_FREE(zone);
+}
+
+extern unsigned malloc_num_zones;
+extern malloc_zone_t **malloc_zones;
+
+// We need to make sure that sanitizer_zone is registered as malloc_zones[0]. If
+// libmalloc tries to set up a different zone as malloc_zones[0], it will call
+// mprotect(malloc_zones, ..., PROT_READ). This interceptor will catch that and
+// make sure we are still the first (default) zone.
+INTERCEPTOR(int, mprotect, void *addr, size_t len, int prot) {
+ if (addr == malloc_zones && prot == PROT_READ) {
+ if (malloc_num_zones > 1 && malloc_zones[0] != &sanitizer_zone) {
+ for (unsigned i = 1; i < malloc_num_zones; i++) {
+ if (malloc_zones[i] == &sanitizer_zone) {
+ // Swap malloc_zones[0] and malloc_zones[i].
+ malloc_zones[i] = malloc_zones[0];
+ malloc_zones[0] = &sanitizer_zone;
+ break;
+ }
+ }
+ }
+ }
+ return REAL(mprotect)(addr, len, prot);
+}
+
INTERCEPTOR(malloc_zone_t *, malloc_default_zone, void) {
COMMON_MALLOC_ENTER();
return &sanitizer_zone;
diff --git a/libsanitizer/sanitizer_common/sanitizer_mutex.h b/libsanitizer/sanitizer_common/sanitizer_mutex.h
index 75f495a..1ec409d 100644
--- a/libsanitizer/sanitizer_common/sanitizer_mutex.h
+++ b/libsanitizer/sanitizer_common/sanitizer_mutex.h
@@ -81,6 +81,14 @@ class BlockingMutex {
BlockingMutex();
void Lock();
void Unlock();
+
+ // This function does not guarantee an explicit check that the calling thread
+ // is the thread which owns the mutex. This behavior, while more strictly
+ // correct, causes problems in cases like StopTheWorld, where a parent thread
+ // owns the mutex but a child checks that it is locked. Rather than
+ // maintaining complex state to work around those situations, the check only
+ // checks that the mutex is owned, and assumes callers to be generally
+ // well-behaved.
void CheckLocked();
private:
uptr opaque_storage_[10];
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform.h b/libsanitizer/sanitizer_common/sanitizer_platform.h
index 428709d..1eb4d0c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform.h
@@ -11,8 +11,8 @@
#ifndef SANITIZER_PLATFORM_H
#define SANITIZER_PLATFORM_H
-#if !defined(__linux__) && !defined(__FreeBSD__) && \
- !defined(__APPLE__) && !defined(_WIN32)
+#if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \
+ !defined(__APPLE__) && !defined(_WIN32) && !defined(__Fuchsia__)
# error "This operating system is not supported"
#endif
@@ -28,6 +28,12 @@
# define SANITIZER_FREEBSD 0
#endif
+#if defined(__NetBSD__)
+# define SANITIZER_NETBSD 1
+#else
+# define SANITIZER_NETBSD 0
+#endif
+
#if defined(__APPLE__)
# define SANITIZER_MAC 1
# include <TargetConditionals.h>
@@ -77,7 +83,14 @@
# define SANITIZER_ANDROID 0
#endif
-#define SANITIZER_POSIX (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC)
+#if defined(__Fuchsia__)
+# define SANITIZER_FUCHSIA 1
+#else
+# define SANITIZER_FUCHSIA 0
+#endif
+
+#define SANITIZER_POSIX \
+ (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_NETBSD)
#if __LP64__ || defined(_WIN64)
# define SANITIZER_WORDSIZE 64
@@ -160,13 +173,19 @@
# define SANITIZER_PPC64V2 0
#endif
+#if defined(__arm__)
+# define SANITIZER_ARM 1
+#else
+# define SANITIZER_ARM 0
+#endif
+
// By default we allow to use SizeClassAllocator64 on 64-bit platform.
// But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64
// does not work well and we need to fallback to SizeClassAllocator32.
// For such platforms build this code with -DSANITIZER_CAN_USE_ALLOCATOR64=0 or
// change the definition of SANITIZER_CAN_USE_ALLOCATOR64 here.
#ifndef SANITIZER_CAN_USE_ALLOCATOR64
-# if SANITIZER_ANDROID && defined(__aarch64__)
+# if (SANITIZER_ANDROID && defined(__aarch64__)) || SANITIZER_FUCHSIA
# define SANITIZER_CAN_USE_ALLOCATOR64 1
# elif defined(__mips64) || defined(__aarch64__)
# define SANITIZER_CAN_USE_ALLOCATOR64 0
@@ -251,4 +270,15 @@
# define SANITIZER_GO 0
#endif
+// On PowerPC and ARM Thumb, calling pthread_exit() causes LSan to detect leaks.
+// pthread_exit() performs unwinding that leads to dlopen'ing libgcc_s.so.
+// dlopen mallocs "libgcc_s.so" string which confuses LSan, it fails to realize
+// that this allocation happens in dynamic linker and should be ignored.
+#if SANITIZER_PPC || defined(__thumb__)
+# define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 1
+#else
+# define SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT 0
+#endif
+
+
#endif // SANITIZER_PLATFORM_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
index 6b2ba31..b9eb09a 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_interceptors.h
@@ -14,11 +14,25 @@
#include "sanitizer_internal_defs.h"
+#if SANITIZER_POSIX
+# define SI_POSIX 1
+#else
+# define SI_POSIX 0
+#endif
+
#if !SANITIZER_WINDOWS
-# define SI_NOT_WINDOWS 1
-# include "sanitizer_platform_limits_posix.h"
+# define SI_WINDOWS 0
#else
-# define SI_NOT_WINDOWS 0
+# define SI_WINDOWS 1
+#endif
+
+#if (SI_POSIX != 0) == (SI_WINDOWS != 0) && !SANITIZER_FUCHSIA
+# error "Windows is not POSIX!"
+#endif
+
+#if SI_POSIX
+# include "sanitizer_platform_limits_netbsd.h"
+# include "sanitizer_platform_limits_posix.h"
#endif
#if SANITIZER_LINUX && !SANITIZER_ANDROID
@@ -39,6 +53,12 @@
# define SI_FREEBSD 0
#endif
+#if SANITIZER_NETBSD
+# define SI_NETBSD 1
+#else
+# define SI_NETBSD 0
+#endif
+
#if SANITIZER_LINUX
# define SI_LINUX 1
#else
@@ -59,28 +79,43 @@
# define SI_IOS 0
#endif
-#if !SANITIZER_WINDOWS && !SANITIZER_MAC
-# define SI_UNIX_NOT_MAC 1
+#if SANITIZER_FUCHSIA
+# define SI_NOT_FUCHSIA 0
+#else
+# define SI_NOT_FUCHSIA 1
+#endif
+
+#if SANITIZER_POSIX && !SANITIZER_MAC
+# define SI_POSIX_NOT_MAC 1
#else
-# define SI_UNIX_NOT_MAC 0
+# define SI_POSIX_NOT_MAC 0
+#endif
+
+#if SANITIZER_LINUX && !SANITIZER_FREEBSD
+# define SI_LINUX_NOT_FREEBSD 1
+# else
+# define SI_LINUX_NOT_FREEBSD 0
#endif
-#define SANITIZER_INTERCEPT_STRLEN 1
-#define SANITIZER_INTERCEPT_STRNLEN SI_NOT_MAC
-#define SANITIZER_INTERCEPT_STRCMP 1
-#define SANITIZER_INTERCEPT_STRSTR 1
-#define SANITIZER_INTERCEPT_STRCASESTR SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_STRCHR 1
-#define SANITIZER_INTERCEPT_STRCHRNUL SI_UNIX_NOT_MAC
-#define SANITIZER_INTERCEPT_STRRCHR 1
-#define SANITIZER_INTERCEPT_STRSPN 1
-#define SANITIZER_INTERCEPT_STRPBRK 1
+#define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA)
+#define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_STRSTR SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_STRCASESTR SI_POSIX
+#define SANITIZER_INTERCEPT_STRTOK SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_STRCHR SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_STRCHRNUL SI_POSIX_NOT_MAC
+#define SANITIZER_INTERCEPT_STRRCHR SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_STRSPN SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_STRPBRK SI_NOT_FUCHSIA
#define SANITIZER_INTERCEPT_TEXTDOMAIN SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_STRCASECMP SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRCASECMP SI_POSIX
#define SANITIZER_INTERCEPT_MEMSET 1
#define SANITIZER_INTERCEPT_MEMMOVE 1
#define SANITIZER_INTERCEPT_MEMCPY 1
-#define SANITIZER_INTERCEPT_MEMCMP 1
+#define SANITIZER_INTERCEPT_MEMCMP SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_STRNDUP SI_POSIX
+#define SANITIZER_INTERCEPT___STRNDUP SI_LINUX_NOT_FREEBSD
#if defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \
__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ < 1070
# define SI_MAC_DEPLOYMENT_BELOW_10_7 1
@@ -89,78 +124,83 @@
#endif
// memmem on Darwin doesn't exist on 10.6
// FIXME: enable memmem on Windows.
-#define SANITIZER_INTERCEPT_MEMMEM \
- SI_NOT_WINDOWS && !SI_MAC_DEPLOYMENT_BELOW_10_7
-#define SANITIZER_INTERCEPT_MEMCHR 1
-#define SANITIZER_INTERCEPT_MEMRCHR SI_FREEBSD || SI_LINUX
+#define SANITIZER_INTERCEPT_MEMMEM (SI_POSIX && !SI_MAC_DEPLOYMENT_BELOW_10_7)
+#define SANITIZER_INTERCEPT_MEMCHR SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_MEMRCHR (SI_FREEBSD || SI_LINUX || SI_NETBSD)
-#define SANITIZER_INTERCEPT_READ SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_PREAD SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_WRITE SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_PWRITE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_READ SI_POSIX
+#define SANITIZER_INTERCEPT_PREAD SI_POSIX
+#define SANITIZER_INTERCEPT_WRITE SI_POSIX
+#define SANITIZER_INTERCEPT_PWRITE SI_POSIX
+
+#define SANITIZER_INTERCEPT_FREAD SI_POSIX
+#define SANITIZER_INTERCEPT_FWRITE SI_POSIX
#define SANITIZER_INTERCEPT_PREAD64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PWRITE64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_READV SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_WRITEV SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_READV SI_POSIX
+#define SANITIZER_INTERCEPT_WRITEV SI_POSIX
-#define SANITIZER_INTERCEPT_PREADV SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_PREADV \
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_PWRITEV SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PREADV64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PWRITEV64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PRCTL SI_LINUX
-#define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_STRPTIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_LOCALTIME_AND_FRIENDS SI_POSIX
+#define SANITIZER_INTERCEPT_STRPTIME SI_POSIX
-#define SANITIZER_INTERCEPT_SCANF SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SCANF SI_POSIX
#define SANITIZER_INTERCEPT_ISOC99_SCANF SI_LINUX_NOT_ANDROID
#ifndef SANITIZER_INTERCEPT_PRINTF
-# define SANITIZER_INTERCEPT_PRINTF SI_NOT_WINDOWS
-# define SANITIZER_INTERCEPT_PRINTF_L SI_FREEBSD
+# define SANITIZER_INTERCEPT_PRINTF SI_POSIX
+# define SANITIZER_INTERCEPT_PRINTF_L (SI_FREEBSD || SI_NETBSD)
# define SANITIZER_INTERCEPT_ISOC99_PRINTF SI_LINUX_NOT_ANDROID
#endif
-#define SANITIZER_INTERCEPT_FREXP 1
-#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FREXP SI_NOT_FUCHSIA
+#define SANITIZER_INTERCEPT_FREXPF_FREXPL SI_POSIX
-#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETPWNAM_AND_FRIENDS SI_POSIX
#define SANITIZER_INTERCEPT_GETPWNAM_R_AND_FRIENDS \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_GETPWENT \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_FGETPWENT SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_GETPWENT_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_SETPWENT SI_MAC || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_CLOCK_GETTIME SI_FREEBSD || SI_LINUX
-#define SANITIZER_INTERCEPT_GETITIMER SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_TIME SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETPWENT_R \
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_SETPWENT (SI_MAC || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_CLOCK_GETTIME (SI_FREEBSD || SI_NETBSD || SI_LINUX)
+#define SANITIZER_INTERCEPT_GETITIMER SI_POSIX
+#define SANITIZER_INTERCEPT_TIME SI_POSIX
#define SANITIZER_INTERCEPT_GLOB SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_WAIT SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_INET SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_GETADDRINFO SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_GETNAMEINFO SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_GETSOCKNAME SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R SI_FREEBSD || SI_LINUX
-#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_GETHOSTENT_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_GETSOCKOPT SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_ACCEPT SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_WAIT SI_POSIX
+#define SANITIZER_INTERCEPT_INET SI_POSIX
+#define SANITIZER_INTERCEPT_PTHREAD_GETSCHEDPARAM SI_POSIX
+#define SANITIZER_INTERCEPT_GETADDRINFO SI_POSIX
+#define SANITIZER_INTERCEPT_GETNAMEINFO SI_POSIX
+#define SANITIZER_INTERCEPT_GETSOCKNAME SI_POSIX
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME SI_POSIX
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME_R (SI_FREEBSD || SI_LINUX)
+#define SANITIZER_INTERCEPT_GETHOSTBYNAME2_R \
+ (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_GETHOSTBYADDR_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_GETHOSTENT_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_GETSOCKOPT SI_POSIX
+#define SANITIZER_INTERCEPT_ACCEPT SI_POSIX
#define SANITIZER_INTERCEPT_ACCEPT4 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_MODF SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_RECVMSG SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_SENDMSG SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_GETPEERNAME SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_IOCTL SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_INET_ATON SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MODF SI_POSIX
+#define SANITIZER_INTERCEPT_RECVMSG SI_POSIX
+#define SANITIZER_INTERCEPT_SENDMSG SI_POSIX
+#define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX
+#define SANITIZER_INTERCEPT_IOCTL SI_POSIX
+#define SANITIZER_INTERCEPT_INET_ATON SI_POSIX
#define SANITIZER_INTERCEPT_SYSINFO SI_LINUX
-#define SANITIZER_INTERCEPT_READDIR SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_READDIR SI_POSIX
#define SANITIZER_INTERCEPT_READDIR64 SI_LINUX_NOT_ANDROID
#if SI_LINUX_NOT_ANDROID && \
(defined(__i386) || defined(__x86_64) || defined(__mips64) || \
@@ -170,109 +210,116 @@
#else
#define SANITIZER_INTERCEPT_PTRACE 0
#endif
-#define SANITIZER_INTERCEPT_SETLOCALE SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_GETCWD SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_SETLOCALE SI_POSIX
+#define SANITIZER_INTERCEPT_GETCWD SI_POSIX
#define SANITIZER_INTERCEPT_GET_CURRENT_DIR_NAME SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_STRTOIMAX SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_MBSTOWCS SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_MBSNRTOWCS SI_MAC || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_WCSTOMBS SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRTOIMAX SI_POSIX
+#define SANITIZER_INTERCEPT_MBSTOWCS SI_POSIX
+#define SANITIZER_INTERCEPT_MBSNRTOWCS (SI_MAC || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_WCSTOMBS SI_POSIX
#define SANITIZER_INTERCEPT_WCSNRTOMBS \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_WCRTOMB \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_TCGETATTR SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_REALPATH SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_REALPATH SI_POSIX
#define SANITIZER_INTERCEPT_CANONICALIZE_FILE_NAME SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_CONFSTR \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_STRERROR SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_STRERROR_R SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STRERROR SI_POSIX
+#define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX
#define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SCANDIR \
- SI_FREEBSD || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_SCANDIR64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_GETGROUPS SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_POLL SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_GETGROUPS SI_POSIX
+#define SANITIZER_INTERCEPT_POLL SI_POSIX
#define SANITIZER_INTERCEPT_PPOLL SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_WORDEXP \
- SI_FREEBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_SIGWAIT SI_NOT_WINDOWS
+ (SI_FREEBSD || SI_NETBSD || (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_SIGWAIT SI_POSIX
#define SANITIZER_INTERCEPT_SIGWAITINFO SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SIGTIMEDWAIT SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_SIGSETOPS \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_SIGPENDING SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_SIGPROCMASK SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_BACKTRACE SI_FREEBSD || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_SIGPENDING SI_POSIX
+#define SANITIZER_INTERCEPT_SIGPROCMASK SI_POSIX
+#define SANITIZER_INTERCEPT_BACKTRACE \
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_GETMNTENT SI_LINUX
#define SANITIZER_INTERCEPT_GETMNTENT_R SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_STATFS SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_STATFS \
+ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_STATFS64 \
- (SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_STATVFS SI_FREEBSD || SI_LINUX_NOT_ANDROID
+ ((SI_MAC && !SI_IOS) || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_STATVFS \
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_STATVFS64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_INITGROUPS SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_INITGROUPS SI_POSIX
+#define SANITIZER_INTERCEPT_ETHER_NTOA_ATON SI_POSIX
#define SANITIZER_INTERCEPT_ETHER_HOST \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_ETHER_R SI_FREEBSD || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_SHMCTL \
- ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && SANITIZER_WORDSIZE == 64)
+ (SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_ETHER_R (SI_FREEBSD || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_SHMCTL \
+ (SI_NETBSD || ((SI_FREEBSD || SI_LINUX_NOT_ANDROID) && \
+ SANITIZER_WORDSIZE == 64)) // NOLINT
#define SANITIZER_INTERCEPT_RANDOM_R SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GET SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETINHERITSCHED \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_PTHREAD_ATTR_GETAFFINITY_NP SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPSHARED SI_POSIX
+#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETTYPE SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPROTOCOL \
- SI_MAC || SI_LINUX_NOT_ANDROID
+ (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETPRIOCEILING \
- SI_MAC || SI_LINUX_NOT_ANDROID
+ (SI_MAC || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_MUTEXATTR_GETROBUST_NP SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETPSHARED SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_RWLOCKATTR_GETKIND_NP SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETPSHARED SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_CONDATTR_GETCLOCK SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_PTHREAD_BARRIERATTR_GETPSHARED SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_TMPNAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_TMPNAM SI_POSIX
#define SANITIZER_INTERCEPT_TMPNAM_R SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_TTYNAME_R SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_TEMPNAM SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_TTYNAME_R SI_POSIX
+#define SANITIZER_INTERCEPT_TEMPNAM SI_POSIX
#define SANITIZER_INTERCEPT_SINCOS SI_LINUX
-#define SANITIZER_INTERCEPT_REMQUO SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_LGAMMA SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_LGAMMA_R SI_FREEBSD || SI_LINUX
+#define SANITIZER_INTERCEPT_REMQUO SI_POSIX
+#define SANITIZER_INTERCEPT_LGAMMA SI_POSIX
+#define SANITIZER_INTERCEPT_LGAMMA_R (SI_FREEBSD || SI_LINUX)
#define SANITIZER_INTERCEPT_LGAMMAL_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_DRAND48_R SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT_RAND_R \
- SI_FREEBSD || SI_MAC || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_ICONV SI_FREEBSD || SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_TIMES SI_NOT_WINDOWS
+ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_ICONV \
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
+#define SANITIZER_INTERCEPT_TIMES SI_POSIX
// FIXME: getline seems to be available on OSX 10.7
-#define SANITIZER_INTERCEPT_GETLINE SI_FREEBSD || SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_GETLINE \
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
-#define SANITIZER_INTERCEPT__EXIT SI_LINUX || SI_FREEBSD || SI_MAC
+#define SANITIZER_INTERCEPT__EXIT \
+ (SI_LINUX || SI_FREEBSD || SI_NETBSD || SI_MAC)
-#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_PHTREAD_MUTEX SI_POSIX
#define SANITIZER_INTERCEPT_PTHREAD_SETNAME_NP \
- SI_FREEBSD || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_TLS_GET_ADDR \
- SI_FREEBSD || SI_LINUX_NOT_ANDROID
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID)
#define SANITIZER_INTERCEPT_LISTXATTR SI_LINUX
#define SANITIZER_INTERCEPT_GETXATTR SI_LINUX
#define SANITIZER_INTERCEPT_GETRESID SI_LINUX
#define SANITIZER_INTERCEPT_GETIFADDRS \
- SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC)
#define SANITIZER_INTERCEPT_IF_INDEXTONAME \
- SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC)
#define SANITIZER_INTERCEPT_CAPGET SI_LINUX_NOT_ANDROID
#if SI_LINUX && defined(__arm__)
#define SANITIZER_INTERCEPT_AEABI_MEM 1
@@ -280,42 +327,67 @@
#define SANITIZER_INTERCEPT_AEABI_MEM 0
#endif
#define SANITIZER_INTERCEPT___BZERO SI_MAC
-#define SANITIZER_INTERCEPT_FTIME !SI_FREEBSD && SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FTIME (!SI_FREEBSD && !SI_NETBSD && SI_POSIX)
#define SANITIZER_INTERCEPT_XDR SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_TSEARCH SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_TSEARCH \
+ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD)
#define SANITIZER_INTERCEPT_LIBIO_INTERNALS SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_FOPEN SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FOPEN SI_POSIX
#define SANITIZER_INTERCEPT_FOPEN64 SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_OPEN_MEMSTREAM (SI_LINUX_NOT_ANDROID || SI_NETBSD)
#define SANITIZER_INTERCEPT_OBSTACK SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_FFLUSH SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_FCLOSE SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_FFLUSH SI_POSIX
+#define SANITIZER_INTERCEPT_FCLOSE SI_POSIX
#ifndef SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
#define SANITIZER_INTERCEPT_DLOPEN_DLCLOSE \
- SI_FREEBSD || SI_LINUX_NOT_ANDROID || SI_MAC
+ (SI_FREEBSD || SI_NETBSD || SI_LINUX_NOT_ANDROID || SI_MAC)
#endif
-#define SANITIZER_INTERCEPT_GETPASS SI_LINUX_NOT_ANDROID || SI_MAC
+#define SANITIZER_INTERCEPT_GETPASS \
+ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_NETBSD)
#define SANITIZER_INTERCEPT_TIMERFD SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_MLOCKX SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_MLOCKX SI_POSIX
#define SANITIZER_INTERCEPT_FOPENCOOKIE SI_LINUX_NOT_ANDROID
-#define SANITIZER_INTERCEPT_SEM SI_LINUX || SI_FREEBSD
-#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_MINCORE SI_LINUX
+#define SANITIZER_INTERCEPT_SEM (SI_LINUX || SI_FREEBSD || SI_NETBSD)
+#define SANITIZER_INTERCEPT_PTHREAD_SETCANCEL SI_POSIX
+#define SANITIZER_INTERCEPT_MINCORE (SI_LINUX || SI_NETBSD)
#define SANITIZER_INTERCEPT_PROCESS_VM_READV SI_LINUX
-#define SANITIZER_INTERCEPT_CTERMID SI_LINUX || SI_MAC || SI_FREEBSD
-#define SANITIZER_INTERCEPT_CTERMID_R SI_MAC || SI_FREEBSD
+#define SANITIZER_INTERCEPT_CTERMID \
+ (SI_LINUX || SI_MAC || SI_FREEBSD || SI_NETBSD)
+#define SANITIZER_INTERCEPT_CTERMID_R (SI_MAC || SI_FREEBSD)
-#define SANITIZER_INTERCEPTOR_HOOKS SI_LINUX
-#define SANITIZER_INTERCEPT_RECV_RECVFROM SI_NOT_WINDOWS
-#define SANITIZER_INTERCEPT_SEND_SENDTO SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPTOR_HOOKS (SI_LINUX || SI_MAC || SI_WINDOWS)
+#define SANITIZER_INTERCEPT_RECV_RECVFROM SI_POSIX
+#define SANITIZER_INTERCEPT_SEND_SENDTO SI_POSIX
#define SANITIZER_INTERCEPT_EVENTFD_READ_WRITE SI_LINUX
-#define SANITIZER_INTERCEPT_STAT (SI_FREEBSD || SI_MAC || SI_ANDROID)
-#define SANITIZER_INTERCEPT___XSTAT !SANITIZER_INTERCEPT_STAT && SI_NOT_WINDOWS
+#define SANITIZER_INTERCEPT_STAT \
+ (SI_FREEBSD || SI_MAC || SI_ANDROID || SI_NETBSD)
+#define SANITIZER_INTERCEPT___XSTAT (!SANITIZER_INTERCEPT_STAT && SI_POSIX)
#define SANITIZER_INTERCEPT___XSTAT64 SI_LINUX_NOT_ANDROID
#define SANITIZER_INTERCEPT___LXSTAT SANITIZER_INTERCEPT___XSTAT
#define SANITIZER_INTERCEPT___LXSTAT64 SI_LINUX_NOT_ANDROID
+
+#define SANITIZER_INTERCEPT_UTMP (SI_POSIX && !SI_MAC && !SI_FREEBSD)
+#define SANITIZER_INTERCEPT_UTMPX (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD)
+
+#define SANITIZER_INTERCEPT_GETLOADAVG \
+ (SI_LINUX_NOT_ANDROID || SI_MAC || SI_FREEBSD || SI_NETBSD)
+
+#define SANITIZER_INTERCEPT_MALLOPT_AND_MALLINFO \
+ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA)
+#define SANITIZER_INTERCEPT_MEMALIGN (!SI_FREEBSD && !SI_MAC && !SI_NETBSD)
+#define SANITIZER_INTERCEPT_PVALLOC \
+ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA)
+#define SANITIZER_INTERCEPT_CFREE \
+ (!SI_FREEBSD && !SI_MAC && !SI_NETBSD && SI_NOT_FUCHSIA)
+#define SANITIZER_INTERCEPT_ALIGNED_ALLOC (!SI_MAC)
+#define SANITIZER_INTERCEPT_MALLOC_USABLE_SIZE (!SI_MAC)
+#define SANITIZER_INTERCEPT_MCHECK_MPROBE SI_LINUX_NOT_ANDROID
+#define SANITIZER_INTERCEPT_WCSCAT SI_POSIX
+#define SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION (!SI_WINDOWS && SI_NOT_FUCHSIA)
+#define SANITIZER_INTERCEPT_BSD_SIGNAL SI_ANDROID
+
#endif // #ifndef SANITIZER_PLATFORM_INTERCEPTORS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cc
new file mode 100644
index 0000000..3c18ca6
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.cc
@@ -0,0 +1,357 @@
+//===-- sanitizer_platform_limits_netbsd.cc -------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer common code.
+//
+// Sizes and layouts of platform-specific NetBSD data structures.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_NETBSD
+#include <arpa/inet.h>
+#include <dirent.h>
+#include <glob.h>
+#include <grp.h>
+#include <ifaddrs.h>
+#include <limits.h>
+#include <link_elf.h>
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/ppp_defs.h>
+#include <net/route.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <netinet/ip_mroute.h>
+#include <poll.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <stddef.h>
+#include <sys/filio.h>
+#include <sys/ipc.h>
+#include <sys/mman.h>
+#include <sys/mount.h>
+#include <sys/mqueue.h>
+#include <sys/msg.h>
+#include <sys/mtio.h>
+#include <sys/ptrace.h>
+#include <sys/resource.h>
+#include <sys/shm.h>
+#include <sys/signal.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+#include <sys/soundcard.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/time.h>
+#include <sys/timeb.h>
+#include <sys/times.h>
+#include <sys/timespec.h>
+#include <sys/timex.h>
+#include <sys/types.h>
+#include <sys/ucontext.h>
+#include <sys/utsname.h>
+#include <term.h>
+#include <termios.h>
+#include <time.h>
+#include <utime.h>
+#include <utmp.h>
+#include <utmpx.h>
+#include <wchar.h>
+#include <wordexp.h>
+
+// Include these after system headers to avoid name clashes and ambiguities.
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_netbsd.h"
+
+namespace __sanitizer {
+unsigned struct_utsname_sz = sizeof(struct utsname);
+unsigned struct_stat_sz = sizeof(struct stat);
+unsigned struct_rusage_sz = sizeof(struct rusage);
+unsigned struct_tm_sz = sizeof(struct tm);
+unsigned struct_passwd_sz = sizeof(struct passwd);
+unsigned struct_group_sz = sizeof(struct group);
+unsigned siginfo_t_sz = sizeof(siginfo_t);
+unsigned struct_sigaction_sz = sizeof(struct sigaction);
+unsigned struct_itimerval_sz = sizeof(struct itimerval);
+unsigned pthread_t_sz = sizeof(pthread_t);
+unsigned pthread_cond_t_sz = sizeof(pthread_cond_t);
+unsigned pid_t_sz = sizeof(pid_t);
+unsigned timeval_sz = sizeof(timeval);
+unsigned uid_t_sz = sizeof(uid_t);
+unsigned gid_t_sz = sizeof(gid_t);
+unsigned mbstate_t_sz = sizeof(mbstate_t);
+unsigned sigset_t_sz = sizeof(sigset_t);
+unsigned struct_timezone_sz = sizeof(struct timezone);
+unsigned struct_tms_sz = sizeof(struct tms);
+unsigned struct_sigevent_sz = sizeof(struct sigevent);
+unsigned struct_sched_param_sz = sizeof(struct sched_param);
+unsigned struct_sockaddr_sz = sizeof(struct sockaddr);
+unsigned ucontext_t_sz = sizeof(ucontext_t);
+unsigned struct_rlimit_sz = sizeof(struct rlimit);
+unsigned struct_timespec_sz = sizeof(struct timespec);
+unsigned struct_utimbuf_sz = sizeof(struct utimbuf);
+unsigned struct_itimerspec_sz = sizeof(struct itimerspec);
+unsigned struct_timex_sz = sizeof(struct timex);
+unsigned struct_msqid_ds_sz = sizeof(struct msqid_ds);
+unsigned struct_mq_attr_sz = sizeof(struct mq_attr);
+unsigned struct_statvfs_sz = sizeof(struct statvfs);
+
+uptr sig_ign = (uptr)SIG_IGN;
+uptr sig_dfl = (uptr)SIG_DFL;
+uptr sa_siginfo = (uptr)SA_SIGINFO;
+
+int shmctl_ipc_stat = (int)IPC_STAT;
+
+unsigned struct_utmp_sz = sizeof(struct utmp);
+unsigned struct_utmpx_sz = sizeof(struct utmpx);
+
+int map_fixed = MAP_FIXED;
+
+int af_inet = (int)AF_INET;
+int af_inet6 = (int)AF_INET6;
+
+uptr __sanitizer_in_addr_sz(int af) {
+ if (af == AF_INET)
+ return sizeof(struct in_addr);
+ else if (af == AF_INET6)
+ return sizeof(struct in6_addr);
+ else
+ return 0;
+}
+
+int glob_nomatch = GLOB_NOMATCH;
+int glob_altdirfunc = GLOB_ALTDIRFUNC;
+
+unsigned path_max = PATH_MAX;
+
+// ioctl arguments
+unsigned struct_ifreq_sz = sizeof(struct ifreq);
+unsigned struct_termios_sz = sizeof(struct termios);
+unsigned struct_winsize_sz = sizeof(struct winsize);
+unsigned struct_mtget_sz = sizeof(struct mtget);
+unsigned struct_mtop_sz = sizeof(struct mtop);
+unsigned struct_audio_buf_info_sz = sizeof(struct audio_buf_info);
+unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats);
+unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req);
+unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req);
+
+const unsigned IOCTL_NOT_PRESENT = 0;
+
+unsigned IOCTL_FIOASYNC = FIOASYNC;
+unsigned IOCTL_FIOCLEX = FIOCLEX;
+unsigned IOCTL_FIOGETOWN = FIOGETOWN;
+unsigned IOCTL_FIONBIO = FIONBIO;
+unsigned IOCTL_FIONCLEX = FIONCLEX;
+unsigned IOCTL_FIOSETOWN = FIOSETOWN;
+unsigned IOCTL_SIOCADDMULTI = SIOCADDMULTI;
+unsigned IOCTL_SIOCATMARK = SIOCATMARK;
+unsigned IOCTL_SIOCDELMULTI = SIOCDELMULTI;
+unsigned IOCTL_SIOCGIFADDR = SIOCGIFADDR;
+unsigned IOCTL_SIOCGIFBRDADDR = SIOCGIFBRDADDR;
+unsigned IOCTL_SIOCGIFCONF = SIOCGIFCONF;
+unsigned IOCTL_SIOCGIFDSTADDR = SIOCGIFDSTADDR;
+unsigned IOCTL_SIOCGIFFLAGS = SIOCGIFFLAGS;
+unsigned IOCTL_SIOCGIFMETRIC = SIOCGIFMETRIC;
+unsigned IOCTL_SIOCGIFMTU = SIOCGIFMTU;
+unsigned IOCTL_SIOCGIFNETMASK = SIOCGIFNETMASK;
+unsigned IOCTL_SIOCGPGRP = SIOCGPGRP;
+unsigned IOCTL_SIOCSIFADDR = SIOCSIFADDR;
+unsigned IOCTL_SIOCSIFBRDADDR = SIOCSIFBRDADDR;
+unsigned IOCTL_SIOCSIFDSTADDR = SIOCSIFDSTADDR;
+unsigned IOCTL_SIOCSIFFLAGS = SIOCSIFFLAGS;
+unsigned IOCTL_SIOCSIFMETRIC = SIOCSIFMETRIC;
+unsigned IOCTL_SIOCSIFMTU = SIOCSIFMTU;
+unsigned IOCTL_SIOCSIFNETMASK = SIOCSIFNETMASK;
+unsigned IOCTL_SIOCSPGRP = SIOCSPGRP;
+unsigned IOCTL_TIOCCONS = TIOCCONS;
+unsigned IOCTL_TIOCEXCL = TIOCEXCL;
+unsigned IOCTL_TIOCGETD = TIOCGETD;
+unsigned IOCTL_TIOCGPGRP = TIOCGPGRP;
+unsigned IOCTL_TIOCGWINSZ = TIOCGWINSZ;
+unsigned IOCTL_TIOCMBIC = TIOCMBIC;
+unsigned IOCTL_TIOCMBIS = TIOCMBIS;
+unsigned IOCTL_TIOCMGET = TIOCMGET;
+unsigned IOCTL_TIOCMSET = TIOCMSET;
+unsigned IOCTL_TIOCNOTTY = TIOCNOTTY;
+unsigned IOCTL_TIOCNXCL = TIOCNXCL;
+unsigned IOCTL_TIOCOUTQ = TIOCOUTQ;
+unsigned IOCTL_TIOCPKT = TIOCPKT;
+unsigned IOCTL_TIOCSCTTY = TIOCSCTTY;
+unsigned IOCTL_TIOCSETD = TIOCSETD;
+unsigned IOCTL_TIOCSPGRP = TIOCSPGRP;
+unsigned IOCTL_TIOCSTI = TIOCSTI;
+unsigned IOCTL_TIOCSWINSZ = TIOCSWINSZ;
+unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT;
+unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT;
+
+const int si_SEGV_MAPERR = SEGV_MAPERR;
+const int si_SEGV_ACCERR = SEGV_ACCERR;
+} // namespace __sanitizer
+
+using namespace __sanitizer;
+
+COMPILER_CHECK(sizeof(__sanitizer_pthread_attr_t) >= sizeof(pthread_attr_t));
+
+COMPILER_CHECK(sizeof(socklen_t) == sizeof(unsigned));
+CHECK_TYPE_SIZE(pthread_key_t);
+
+// There are more undocumented fields in dl_phdr_info that we are not interested
+// in.
+COMPILER_CHECK(sizeof(__sanitizer_dl_phdr_info) <= sizeof(dl_phdr_info));
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_addr);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_name);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phdr);
+CHECK_SIZE_AND_OFFSET(dl_phdr_info, dlpi_phnum);
+
+CHECK_TYPE_SIZE(glob_t);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathc);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_pathv);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_offs);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_flags);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_closedir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_readdir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_opendir);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_lstat);
+CHECK_SIZE_AND_OFFSET(glob_t, gl_stat);
+
+CHECK_TYPE_SIZE(addrinfo);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_flags);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_family);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_socktype);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_protocol);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addrlen);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_canonname);
+CHECK_SIZE_AND_OFFSET(addrinfo, ai_addr);
+
+CHECK_TYPE_SIZE(hostent);
+CHECK_SIZE_AND_OFFSET(hostent, h_name);
+CHECK_SIZE_AND_OFFSET(hostent, h_aliases);
+CHECK_SIZE_AND_OFFSET(hostent, h_addrtype);
+CHECK_SIZE_AND_OFFSET(hostent, h_length);
+CHECK_SIZE_AND_OFFSET(hostent, h_addr_list);
+
+CHECK_TYPE_SIZE(iovec);
+CHECK_SIZE_AND_OFFSET(iovec, iov_base);
+CHECK_SIZE_AND_OFFSET(iovec, iov_len);
+
+CHECK_TYPE_SIZE(msghdr);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_name);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_namelen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iov);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_iovlen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_control);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_controllen);
+CHECK_SIZE_AND_OFFSET(msghdr, msg_flags);
+
+CHECK_TYPE_SIZE(cmsghdr);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_len);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_level);
+CHECK_SIZE_AND_OFFSET(cmsghdr, cmsg_type);
+
+COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent));
+CHECK_SIZE_AND_OFFSET(dirent, d_fileno);
+CHECK_SIZE_AND_OFFSET(dirent, d_reclen);
+
+CHECK_TYPE_SIZE(ifconf);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_len);
+CHECK_SIZE_AND_OFFSET(ifconf, ifc_ifcu);
+
+CHECK_TYPE_SIZE(pollfd);
+CHECK_SIZE_AND_OFFSET(pollfd, fd);
+CHECK_SIZE_AND_OFFSET(pollfd, events);
+CHECK_SIZE_AND_OFFSET(pollfd, revents);
+
+CHECK_TYPE_SIZE(nfds_t);
+
+CHECK_TYPE_SIZE(sigset_t);
+
+COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction));
+// Can't write checks for sa_handler and sa_sigaction due to them being
+// preprocessor macros.
+CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_mask);
+
+CHECK_TYPE_SIZE(wordexp_t);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordc);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_wordv);
+CHECK_SIZE_AND_OFFSET(wordexp_t, we_offs);
+
+CHECK_TYPE_SIZE(tm);
+CHECK_SIZE_AND_OFFSET(tm, tm_sec);
+CHECK_SIZE_AND_OFFSET(tm, tm_min);
+CHECK_SIZE_AND_OFFSET(tm, tm_hour);
+CHECK_SIZE_AND_OFFSET(tm, tm_mday);
+CHECK_SIZE_AND_OFFSET(tm, tm_mon);
+CHECK_SIZE_AND_OFFSET(tm, tm_year);
+CHECK_SIZE_AND_OFFSET(tm, tm_wday);
+CHECK_SIZE_AND_OFFSET(tm, tm_yday);
+CHECK_SIZE_AND_OFFSET(tm, tm_isdst);
+CHECK_SIZE_AND_OFFSET(tm, tm_gmtoff);
+CHECK_SIZE_AND_OFFSET(tm, tm_zone);
+
+CHECK_TYPE_SIZE(ether_addr);
+
+CHECK_TYPE_SIZE(ipc_perm);
+CHECK_SIZE_AND_OFFSET(ipc_perm, _key);
+CHECK_SIZE_AND_OFFSET(ipc_perm, _seq);
+CHECK_SIZE_AND_OFFSET(ipc_perm, uid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, gid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, cuid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, cgid);
+CHECK_SIZE_AND_OFFSET(ipc_perm, mode);
+
+CHECK_TYPE_SIZE(shmid_ds);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_perm);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_segsz);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_atime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_dtime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_ctime);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_cpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_lpid);
+CHECK_SIZE_AND_OFFSET(shmid_ds, shm_nattch);
+
+CHECK_TYPE_SIZE(clock_t);
+
+CHECK_TYPE_SIZE(ifaddrs);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_addr);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_netmask);
+// Compare against the union, because we can't reach into the union in a
+// compliant way.
+#ifdef ifa_dstaddr
+#undef ifa_dstaddr
+#endif
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_dstaddr);
+CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data);
+
+CHECK_TYPE_SIZE(timeb);
+CHECK_SIZE_AND_OFFSET(timeb, time);
+CHECK_SIZE_AND_OFFSET(timeb, millitm);
+CHECK_SIZE_AND_OFFSET(timeb, timezone);
+CHECK_SIZE_AND_OFFSET(timeb, dstflag);
+
+CHECK_TYPE_SIZE(passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_name);
+CHECK_SIZE_AND_OFFSET(passwd, pw_passwd);
+CHECK_SIZE_AND_OFFSET(passwd, pw_uid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_gid);
+CHECK_SIZE_AND_OFFSET(passwd, pw_dir);
+CHECK_SIZE_AND_OFFSET(passwd, pw_shell);
+
+CHECK_SIZE_AND_OFFSET(passwd, pw_gecos);
+
+CHECK_TYPE_SIZE(group);
+CHECK_SIZE_AND_OFFSET(group, gr_name);
+CHECK_SIZE_AND_OFFSET(group, gr_passwd);
+CHECK_SIZE_AND_OFFSET(group, gr_gid);
+CHECK_SIZE_AND_OFFSET(group, gr_mem);
+
+#endif // SANITIZER_NETBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
new file mode 100644
index 0000000..e7034ed
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_netbsd.h
@@ -0,0 +1,566 @@
+//===-- sanitizer_platform_limits_netbsd.h --------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of Sanitizer common code.
+//
+// Sizes and layouts of platform-specific NetBSD data structures.
+//===----------------------------------------------------------------------===//
+
+#ifndef SANITIZER_PLATFORM_LIMITS_NETBSD_H
+#define SANITIZER_PLATFORM_LIMITS_NETBSD_H
+
+#if SANITIZER_NETBSD
+
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform.h"
+
+#define _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, shift) \
+ ((link_map *)((handle) == nullptr ? nullptr : ((char *)(handle) + (shift))))
+
+#if defined(__x86_64__)
+#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
+ _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 608)
+#elif defined(__i386__)
+#define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
+ _GET_LINK_MAP_BY_DLOPEN_HANDLE(handle, 324)
+#endif
+
+namespace __sanitizer {
+extern unsigned struct_utsname_sz;
+extern unsigned struct_stat_sz;
+extern unsigned struct_rusage_sz;
+extern unsigned siginfo_t_sz;
+extern unsigned struct_itimerval_sz;
+extern unsigned pthread_t_sz;
+extern unsigned pthread_cond_t_sz;
+extern unsigned pid_t_sz;
+extern unsigned timeval_sz;
+extern unsigned uid_t_sz;
+extern unsigned gid_t_sz;
+extern unsigned mbstate_t_sz;
+extern unsigned struct_timezone_sz;
+extern unsigned struct_tms_sz;
+extern unsigned struct_itimerspec_sz;
+extern unsigned struct_sigevent_sz;
+extern unsigned struct_sched_param_sz;
+extern unsigned struct_statfs_sz;
+extern unsigned struct_sockaddr_sz;
+extern unsigned ucontext_t_sz;
+
+extern unsigned struct_rlimit_sz;
+extern unsigned struct_utimbuf_sz;
+extern unsigned struct_timespec_sz;
+
+struct __sanitizer_iocb {
+ u64 aio_offset;
+ uptr aio_buf;
+ long aio_nbytes;
+ u32 aio_fildes;
+ u32 aio_lio_opcode;
+ long aio_reqprio;
+#if SANITIZER_WORDSIZE == 64
+ u8 aio_sigevent[32];
+#else
+ u8 aio_sigevent[20];
+#endif
+ u32 _state;
+ u32 _errno;
+ long _retval;
+};
+
+struct __sanitizer___sysctl_args {
+ int *name;
+ int nlen;
+ void *oldval;
+ uptr *oldlenp;
+ void *newval;
+ uptr newlen;
+};
+
+struct __sanitizer_sem_t {
+ uptr data[5];
+};
+
+struct __sanitizer_ipc_perm {
+ u32 uid;
+ u32 gid;
+ u32 cuid;
+ u32 cgid;
+ u32 mode;
+ unsigned short _seq;
+ long _key;
+};
+
+struct __sanitizer_shmid_ds {
+ __sanitizer_ipc_perm shm_perm;
+ unsigned long shm_segsz;
+ u32 shm_lpid;
+ u32 shm_cpid;
+ unsigned int shm_nattch;
+ u64 shm_atime;
+ u64 shm_dtime;
+ u64 shm_ctime;
+ void *_shm_internal;
+};
+
+extern unsigned struct_msqid_ds_sz;
+extern unsigned struct_mq_attr_sz;
+extern unsigned struct_timex_sz;
+extern unsigned struct_statvfs_sz;
+
+struct __sanitizer_iovec {
+ void *iov_base;
+ uptr iov_len;
+};
+
+struct __sanitizer_ifaddrs {
+ struct __sanitizer_ifaddrs *ifa_next;
+ char *ifa_name;
+ unsigned int ifa_flags;
+ void *ifa_addr; // (struct sockaddr *)
+ void *ifa_netmask; // (struct sockaddr *)
+ void *ifa_dstaddr; // (struct sockaddr *)
+ void *ifa_data;
+ unsigned int ifa_addrflags;
+};
+
+typedef unsigned __sanitizer_pthread_key_t;
+
+typedef long long __sanitizer_time_t;
+
+struct __sanitizer_passwd {
+ char *pw_name;
+ char *pw_passwd;
+ int pw_uid;
+ int pw_gid;
+ __sanitizer_time_t pw_change;
+ char *pw_class;
+ char *pw_gecos;
+ char *pw_dir;
+ char *pw_shell;
+ __sanitizer_time_t pw_expire;
+};
+
+struct __sanitizer_group {
+ char *gr_name;
+ char *gr_passwd;
+ int gr_gid;
+ char **gr_mem;
+};
+
+struct __sanitizer_timeb {
+ __sanitizer_time_t time;
+ unsigned short millitm;
+ short timezone;
+ short dstflag;
+};
+
+struct __sanitizer_ether_addr {
+ u8 octet[6];
+};
+
+struct __sanitizer_tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+ int tm_wday;
+ int tm_yday;
+ int tm_isdst;
+ long int tm_gmtoff;
+ const char *tm_zone;
+};
+
+struct __sanitizer_msghdr {
+ void *msg_name;
+ unsigned msg_namelen;
+ struct __sanitizer_iovec *msg_iov;
+ unsigned msg_iovlen;
+ void *msg_control;
+ unsigned msg_controllen;
+ int msg_flags;
+};
+struct __sanitizer_cmsghdr {
+ unsigned cmsg_len;
+ int cmsg_level;
+ int cmsg_type;
+};
+
+struct __sanitizer_dirent {
+ u64 d_fileno;
+ u16 d_reclen;
+ // more fields that we don't care about
+};
+
+typedef int __sanitizer_clock_t;
+typedef int __sanitizer_clockid_t;
+
+typedef u32 __sanitizer___kernel_uid_t;
+typedef u32 __sanitizer___kernel_gid_t;
+typedef u64 __sanitizer___kernel_off_t;
+typedef struct {
+ u32 fds_bits[8];
+} __sanitizer___kernel_fd_set;
+
+typedef struct {
+ unsigned int pta_magic;
+ int pta_flags;
+ void *pta_private;
+} __sanitizer_pthread_attr_t;
+
+struct __sanitizer_sigset_t {
+ // uint32_t * 4
+ unsigned int __bits[4];
+};
+
+struct __sanitizer_sigaction {
+ union {
+ void (*handler)(int sig);
+ void (*sigaction)(int sig, void *siginfo, void *uctx);
+ };
+ __sanitizer_sigset_t sa_mask;
+ int sa_flags;
+};
+
+typedef __sanitizer_sigset_t __sanitizer_kernel_sigset_t;
+
+struct __sanitizer_kernel_sigaction_t {
+ union {
+ void (*handler)(int signo);
+ void (*sigaction)(int signo, void *info, void *ctx);
+ };
+ unsigned long sa_flags;
+ void (*sa_restorer)(void);
+ __sanitizer_kernel_sigset_t sa_mask;
+};
+
+extern uptr sig_ign;
+extern uptr sig_dfl;
+extern uptr sa_siginfo;
+
+extern int af_inet;
+extern int af_inet6;
+uptr __sanitizer_in_addr_sz(int af);
+
+struct __sanitizer_dl_phdr_info {
+ uptr dlpi_addr;
+ const char *dlpi_name;
+ const void *dlpi_phdr;
+ short dlpi_phnum;
+};
+
+extern unsigned struct_ElfW_Phdr_sz;
+
+struct __sanitizer_addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ unsigned ai_addrlen;
+ char *ai_canonname;
+ void *ai_addr;
+ struct __sanitizer_addrinfo *ai_next;
+};
+
+struct __sanitizer_hostent {
+ char *h_name;
+ char **h_aliases;
+ int h_addrtype;
+ int h_length;
+ char **h_addr_list;
+};
+
+struct __sanitizer_pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+typedef unsigned __sanitizer_nfds_t;
+
+struct __sanitizer_glob_t {
+ uptr gl_pathc;
+ uptr gl_matchc;
+ uptr gl_offs;
+ int gl_flags;
+ char **gl_pathv;
+ int (*gl_errfunc)(const char *, int);
+ void (*gl_closedir)(void *dirp);
+ struct dirent *(*gl_readdir)(void *dirp);
+ void *(*gl_opendir)(const char *);
+ int (*gl_lstat)(const char *, void * /* struct stat* */);
+ int (*gl_stat)(const char *, void * /* struct stat* */);
+};
+
+extern int glob_nomatch;
+extern int glob_altdirfunc;
+
+extern unsigned path_max;
+
+struct __sanitizer_wordexp_t {
+ uptr we_wordc;
+ char **we_wordv;
+ uptr we_offs;
+ char *we_strings;
+ uptr we_nbytes;
+};
+
+typedef void __sanitizer_FILE;
+#define SANITIZER_HAS_STRUCT_FILE 0
+
+extern int shmctl_ipc_stat;
+
+// This simplifies generic code
+#define struct_shminfo_sz -1
+#define struct_shm_info_sz -1
+#define shmctl_shm_stat -1
+#define shmctl_ipc_info -1
+#define shmctl_shm_info -1
+
+extern unsigned struct_utmp_sz;
+extern unsigned struct_utmpx_sz;
+
+extern int map_fixed;
+
+// ioctl arguments
+struct __sanitizer_ifconf {
+ int ifc_len;
+ union {
+ void *ifcu_req;
+ } ifc_ifcu;
+};
+
+#define IOC_NRBITS 8
+#define IOC_TYPEBITS 8
+#define IOC_SIZEBITS 14
+#define IOC_DIRBITS 2
+#define IOC_NONE 0U
+#define IOC_WRITE 1U
+#define IOC_READ 2U
+#define IOC_NRMASK ((1 << IOC_NRBITS) - 1)
+#define IOC_TYPEMASK ((1 << IOC_TYPEBITS) - 1)
+#define IOC_SIZEMASK ((1 << IOC_SIZEBITS) - 1)
+#undef IOC_DIRMASK
+#define IOC_DIRMASK ((1 << IOC_DIRBITS) - 1)
+#define IOC_NRSHIFT 0
+#define IOC_TYPESHIFT (IOC_NRSHIFT + IOC_NRBITS)
+#define IOC_SIZESHIFT (IOC_TYPESHIFT + IOC_TYPEBITS)
+#define IOC_DIRSHIFT (IOC_SIZESHIFT + IOC_SIZEBITS)
+#define EVIOC_EV_MAX 0x1f
+#define EVIOC_ABS_MAX 0x3f
+
+#define IOC_DIR(nr) (((nr) >> IOC_DIRSHIFT) & IOC_DIRMASK)
+#define IOC_TYPE(nr) (((nr) >> IOC_TYPESHIFT) & IOC_TYPEMASK)
+#define IOC_NR(nr) (((nr) >> IOC_NRSHIFT) & IOC_NRMASK)
+#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK)
+
+extern unsigned struct_ifreq_sz;
+extern unsigned struct_termios_sz;
+extern unsigned struct_winsize_sz;
+
+extern unsigned struct_arpreq_sz;
+
+extern unsigned struct_mtget_sz;
+extern unsigned struct_mtop_sz;
+extern unsigned struct_rtentry_sz;
+extern unsigned struct_sbi_instrument_sz;
+extern unsigned struct_seq_event_rec_sz;
+extern unsigned struct_synth_info_sz;
+extern unsigned struct_vt_mode_sz;
+extern unsigned struct_audio_buf_info_sz;
+extern unsigned struct_ppp_stats_sz;
+extern unsigned struct_sioc_sg_req_sz;
+extern unsigned struct_sioc_vif_req_sz;
+
+// ioctl request identifiers
+
+// A special value to mark ioctls that are not present on the target platform,
+// when it can not be determined without including any system headers.
+extern const unsigned IOCTL_NOT_PRESENT;
+
+extern unsigned IOCTL_FIOASYNC;
+extern unsigned IOCTL_FIOCLEX;
+extern unsigned IOCTL_FIOGETOWN;
+extern unsigned IOCTL_FIONBIO;
+extern unsigned IOCTL_FIONCLEX;
+extern unsigned IOCTL_FIOSETOWN;
+extern unsigned IOCTL_SIOCADDMULTI;
+extern unsigned IOCTL_SIOCATMARK;
+extern unsigned IOCTL_SIOCDELMULTI;
+extern unsigned IOCTL_SIOCGIFADDR;
+extern unsigned IOCTL_SIOCGIFBRDADDR;
+extern unsigned IOCTL_SIOCGIFCONF;
+extern unsigned IOCTL_SIOCGIFDSTADDR;
+extern unsigned IOCTL_SIOCGIFFLAGS;
+extern unsigned IOCTL_SIOCGIFMETRIC;
+extern unsigned IOCTL_SIOCGIFMTU;
+extern unsigned IOCTL_SIOCGIFNETMASK;
+extern unsigned IOCTL_SIOCGPGRP;
+extern unsigned IOCTL_SIOCSIFADDR;
+extern unsigned IOCTL_SIOCSIFBRDADDR;
+extern unsigned IOCTL_SIOCSIFDSTADDR;
+extern unsigned IOCTL_SIOCSIFFLAGS;
+extern unsigned IOCTL_SIOCSIFMETRIC;
+extern unsigned IOCTL_SIOCSIFMTU;
+extern unsigned IOCTL_SIOCSIFNETMASK;
+extern unsigned IOCTL_SIOCSPGRP;
+extern unsigned IOCTL_TIOCCONS;
+extern unsigned IOCTL_TIOCEXCL;
+extern unsigned IOCTL_TIOCGETD;
+extern unsigned IOCTL_TIOCGPGRP;
+extern unsigned IOCTL_TIOCGWINSZ;
+extern unsigned IOCTL_TIOCMBIC;
+extern unsigned IOCTL_TIOCMBIS;
+extern unsigned IOCTL_TIOCMGET;
+extern unsigned IOCTL_TIOCMSET;
+extern unsigned IOCTL_TIOCNOTTY;
+extern unsigned IOCTL_TIOCNXCL;
+extern unsigned IOCTL_TIOCOUTQ;
+extern unsigned IOCTL_TIOCPKT;
+extern unsigned IOCTL_TIOCSCTTY;
+extern unsigned IOCTL_TIOCSETD;
+extern unsigned IOCTL_TIOCSPGRP;
+extern unsigned IOCTL_TIOCSTI;
+extern unsigned IOCTL_TIOCSWINSZ;
+extern unsigned IOCTL_SIOCGETSGCNT;
+extern unsigned IOCTL_SIOCGETVIFCNT;
+extern unsigned IOCTL_MTIOCGET;
+extern unsigned IOCTL_MTIOCTOP;
+extern unsigned IOCTL_SIOCADDRT;
+extern unsigned IOCTL_SIOCDELRT;
+extern unsigned IOCTL_SNDCTL_DSP_GETBLKSIZE;
+extern unsigned IOCTL_SNDCTL_DSP_GETFMTS;
+extern unsigned IOCTL_SNDCTL_DSP_NONBLOCK;
+extern unsigned IOCTL_SNDCTL_DSP_POST;
+extern unsigned IOCTL_SNDCTL_DSP_RESET;
+extern unsigned IOCTL_SNDCTL_DSP_SETFMT;
+extern unsigned IOCTL_SNDCTL_DSP_SETFRAGMENT;
+extern unsigned IOCTL_SNDCTL_DSP_SPEED;
+extern unsigned IOCTL_SNDCTL_DSP_STEREO;
+extern unsigned IOCTL_SNDCTL_DSP_SUBDIVIDE;
+extern unsigned IOCTL_SNDCTL_DSP_SYNC;
+extern unsigned IOCTL_SNDCTL_FM_4OP_ENABLE;
+extern unsigned IOCTL_SNDCTL_FM_LOAD_INSTR;
+extern unsigned IOCTL_SNDCTL_MIDI_INFO;
+extern unsigned IOCTL_SNDCTL_MIDI_PRETIME;
+extern unsigned IOCTL_SNDCTL_SEQ_CTRLRATE;
+extern unsigned IOCTL_SNDCTL_SEQ_GETINCOUNT;
+extern unsigned IOCTL_SNDCTL_SEQ_GETOUTCOUNT;
+extern unsigned IOCTL_SNDCTL_SEQ_NRMIDIS;
+extern unsigned IOCTL_SNDCTL_SEQ_NRSYNTHS;
+extern unsigned IOCTL_SNDCTL_SEQ_OUTOFBAND;
+extern unsigned IOCTL_SNDCTL_SEQ_PANIC;
+extern unsigned IOCTL_SNDCTL_SEQ_PERCMODE;
+extern unsigned IOCTL_SNDCTL_SEQ_RESET;
+extern unsigned IOCTL_SNDCTL_SEQ_RESETSAMPLES;
+extern unsigned IOCTL_SNDCTL_SEQ_SYNC;
+extern unsigned IOCTL_SNDCTL_SEQ_TESTMIDI;
+extern unsigned IOCTL_SNDCTL_SEQ_THRESHOLD;
+extern unsigned IOCTL_SNDCTL_SYNTH_INFO;
+extern unsigned IOCTL_SNDCTL_SYNTH_MEMAVL;
+extern unsigned IOCTL_SNDCTL_TMR_CONTINUE;
+extern unsigned IOCTL_SNDCTL_TMR_METRONOME;
+extern unsigned IOCTL_SNDCTL_TMR_SELECT;
+extern unsigned IOCTL_SNDCTL_TMR_SOURCE;
+extern unsigned IOCTL_SNDCTL_TMR_START;
+extern unsigned IOCTL_SNDCTL_TMR_STOP;
+extern unsigned IOCTL_SNDCTL_TMR_TEMPO;
+extern unsigned IOCTL_SNDCTL_TMR_TIMEBASE;
+extern unsigned IOCTL_SOUND_MIXER_READ_ALTPCM;
+extern unsigned IOCTL_SOUND_MIXER_READ_BASS;
+extern unsigned IOCTL_SOUND_MIXER_READ_CAPS;
+extern unsigned IOCTL_SOUND_MIXER_READ_CD;
+extern unsigned IOCTL_SOUND_MIXER_READ_DEVMASK;
+extern unsigned IOCTL_SOUND_MIXER_READ_ENHANCE;
+extern unsigned IOCTL_SOUND_MIXER_READ_IGAIN;
+extern unsigned IOCTL_SOUND_MIXER_READ_IMIX;
+extern unsigned IOCTL_SOUND_MIXER_READ_LINE1;
+extern unsigned IOCTL_SOUND_MIXER_READ_LINE2;
+extern unsigned IOCTL_SOUND_MIXER_READ_LINE3;
+extern unsigned IOCTL_SOUND_MIXER_READ_LINE;
+extern unsigned IOCTL_SOUND_MIXER_READ_LOUD;
+extern unsigned IOCTL_SOUND_MIXER_READ_MIC;
+extern unsigned IOCTL_SOUND_MIXER_READ_MUTE;
+extern unsigned IOCTL_SOUND_MIXER_READ_OGAIN;
+extern unsigned IOCTL_SOUND_MIXER_READ_PCM;
+extern unsigned IOCTL_SOUND_MIXER_READ_RECLEV;
+extern unsigned IOCTL_SOUND_MIXER_READ_RECMASK;
+extern unsigned IOCTL_SOUND_MIXER_READ_RECSRC;
+extern unsigned IOCTL_SOUND_MIXER_READ_SPEAKER;
+extern unsigned IOCTL_SOUND_MIXER_READ_STEREODEVS;
+extern unsigned IOCTL_SOUND_MIXER_READ_SYNTH;
+extern unsigned IOCTL_SOUND_MIXER_READ_TREBLE;
+extern unsigned IOCTL_SOUND_MIXER_READ_VOLUME;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_ALTPCM;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_BASS;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_CD;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_ENHANCE;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_IGAIN;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_IMIX;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE1;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE2;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE3;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_LINE;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_LOUD;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_MIC;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_MUTE;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_OGAIN;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_PCM;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_RECLEV;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_RECSRC;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_SPEAKER;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_SYNTH;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_TREBLE;
+extern unsigned IOCTL_SOUND_MIXER_WRITE_VOLUME;
+extern unsigned IOCTL_SOUND_PCM_READ_BITS;
+extern unsigned IOCTL_SOUND_PCM_READ_CHANNELS;
+extern unsigned IOCTL_SOUND_PCM_READ_FILTER;
+extern unsigned IOCTL_SOUND_PCM_READ_RATE;
+extern unsigned IOCTL_SOUND_PCM_WRITE_CHANNELS;
+extern unsigned IOCTL_SOUND_PCM_WRITE_FILTER;
+extern unsigned IOCTL_VT_ACTIVATE;
+extern unsigned IOCTL_VT_GETMODE;
+extern unsigned IOCTL_VT_OPENQRY;
+extern unsigned IOCTL_VT_RELDISP;
+extern unsigned IOCTL_VT_SETMODE;
+extern unsigned IOCTL_VT_WAITACTIVE;
+extern unsigned IOCTL_KDDISABIO;
+extern unsigned IOCTL_KDENABIO;
+extern unsigned IOCTL_KDGETLED;
+extern unsigned IOCTL_KDGKBMODE;
+extern unsigned IOCTL_KDGKBTYPE;
+extern unsigned IOCTL_KDMKTONE;
+extern unsigned IOCTL_KDSETLED;
+extern unsigned IOCTL_KDSETMODE;
+extern unsigned IOCTL_KDSKBMODE;
+
+extern const int si_SEGV_MAPERR;
+extern const int si_SEGV_ACCERR;
+} // namespace __sanitizer
+
+#define CHECK_TYPE_SIZE(TYPE) \
+ COMPILER_CHECK(sizeof(__sanitizer_##TYPE) == sizeof(TYPE))
+
+#define CHECK_SIZE_AND_OFFSET(CLASS, MEMBER) \
+ COMPILER_CHECK(sizeof(((__sanitizer_##CLASS *)NULL)->MEMBER) == \
+ sizeof(((CLASS *)NULL)->MEMBER)); \
+ COMPILER_CHECK(offsetof(__sanitizer_##CLASS, MEMBER) == \
+ offsetof(CLASS, MEMBER))
+
+// For sigaction, which is a function and struct at the same time,
+// and thus requires explicit "struct" in sizeof() expression.
+#define CHECK_STRUCT_SIZE_AND_OFFSET(CLASS, MEMBER) \
+ COMPILER_CHECK(sizeof(((struct __sanitizer_##CLASS *)NULL)->MEMBER) == \
+ sizeof(((struct CLASS *)NULL)->MEMBER)); \
+ COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \
+ offsetof(struct CLASS, MEMBER))
+
+#endif // SANITIZER_NETBSD
+
+#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
index 31a5e69..858bb21 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.cc
@@ -23,7 +23,6 @@
#endif
#include <arpa/inet.h>
#include <dirent.h>
-#include <errno.h>
#include <grp.h>
#include <limits.h>
#include <net/if.h>
@@ -44,6 +43,9 @@
#include <termios.h>
#include <time.h>
#include <wchar.h>
+#if !SANITIZER_MAC && !SANITIZER_FREEBSD
+#include <utmp.h>
+#endif
#if !SANITIZER_IOS
#include <net/route.h>
@@ -52,6 +54,7 @@
#if !SANITIZER_ANDROID
#include <sys/mount.h>
#include <sys/timeb.h>
+#include <utmpx.h>
#endif
#if SANITIZER_LINUX
@@ -277,6 +280,13 @@ namespace __sanitizer {
int shmctl_shm_stat = (int)SHM_STAT;
#endif
+#if !SANITIZER_MAC && !SANITIZER_FREEBSD
+ unsigned struct_utmp_sz = sizeof(struct utmp);
+#endif
+#if !SANITIZER_ANDROID
+ unsigned struct_utmpx_sz = sizeof(struct utmpx);
+#endif
+
int map_fixed = MAP_FIXED;
int af_inet = (int)AF_INET;
@@ -918,14 +928,6 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr);
unsigned IOCTL_SNDCTL_DSP_GETOSPACE = SNDCTL_DSP_GETOSPACE;
#endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID
- const int errno_EINVAL = EINVAL;
-// EOWNERDEAD is not present in some older platforms.
-#if defined(EOWNERDEAD)
- const int errno_EOWNERDEAD = EOWNERDEAD;
-#else
- const int errno_EOWNERDEAD = -1;
-#endif
-
const int si_SEGV_MAPERR = SEGV_MAPERR;
const int si_SEGV_ACCERR = SEGV_ACCERR;
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
index c139322..4d11d07 100644
--- a/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_platform_limits_posix.h
@@ -13,6 +13,8 @@
#ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H
#define SANITIZER_PLATFORM_LIMITS_POSIX_H
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC
+
#include "sanitizer_internal_defs.h"
#include "sanitizer_platform.h"
@@ -21,6 +23,9 @@
// incorporates the map structure.
# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) \
((link_map*)((handle) == nullptr ? nullptr : ((char*)(handle) + 544)))
+// Get sys/_types.h, because that tells us whether 64-bit inodes are
+// used in struct dirent below.
+#include <sys/_types.h>
#else
# define GET_LINK_MAP_BY_DLOPEN_HANDLE(handle) ((link_map*)(handle))
#endif // !SANITIZER_FREEBSD
@@ -81,7 +86,7 @@ namespace __sanitizer {
#elif defined(__mips__)
const unsigned struct_kernel_stat_sz =
SANITIZER_ANDROID ? FIRST_32_SECOND_64(104, 128) :
- FIRST_32_SECOND_64(144, 216);
+ FIRST_32_SECOND_64(160, 216);
const unsigned struct_kernel_stat64_sz = 104;
#elif defined(__s390__) && !defined(__s390x__)
const unsigned struct_kernel_stat_sz = 64;
@@ -204,24 +209,24 @@ namespace __sanitizer {
unsigned __seq;
u64 __unused1;
u64 __unused2;
-#elif defined(__mips__) || defined(__aarch64__) || defined(__s390x__)
- unsigned int mode;
- unsigned short __seq;
- unsigned short __pad1;
- unsigned long __unused1;
- unsigned long __unused2;
#elif defined(__sparc__)
-# if defined(__arch64__)
+#if defined(__arch64__)
unsigned mode;
unsigned short __pad1;
-# else
+#else
unsigned short __pad1;
unsigned short mode;
unsigned short __pad2;
-# endif
+#endif
unsigned short __seq;
unsigned long long __unused1;
unsigned long long __unused2;
+#elif defined(__mips__) || defined(__aarch64__) || defined(__s390x__)
+ unsigned int mode;
+ unsigned short __seq;
+ unsigned short __pad1;
+ unsigned long __unused1;
+ unsigned long __unused2;
#else
unsigned short mode;
unsigned short __pad1;
@@ -240,17 +245,17 @@ namespace __sanitizer {
struct __sanitizer_shmid_ds {
__sanitizer_ipc_perm shm_perm;
#if defined(__sparc__)
- # if !defined(__arch64__)
+ #if !defined(__arch64__)
u32 __pad1;
- # endif
+ #endif
long shm_atime;
- # if !defined(__arch64__)
+ #if !defined(__arch64__)
u32 __pad2;
- # endif
+ #endif
long shm_dtime;
- # if !defined(__arch64__)
+ #if !defined(__arch64__)
u32 __pad3;
- # endif
+ #endif
long shm_ctime;
uptr shm_segsz;
int shm_cpid;
@@ -483,7 +488,12 @@ namespace __sanitizer {
};
#elif SANITIZER_FREEBSD
struct __sanitizer_dirent {
+#if defined(__INO64)
+ unsigned long long d_fileno;
+ unsigned long long d_off;
+#else
unsigned int d_fileno;
+#endif
unsigned short d_reclen;
// more fields that we don't care about
};
@@ -863,6 +873,13 @@ namespace __sanitizer {
extern int shmctl_shm_stat;
#endif
+#if !SANITIZER_MAC && !SANITIZER_FREEBSD
+ extern unsigned struct_utmp_sz;
+#endif
+#if !SANITIZER_ANDROID
+ extern unsigned struct_utmpx_sz;
+#endif
+
extern int map_fixed;
// ioctl arguments
@@ -908,7 +925,8 @@ struct __sanitizer_cookie_io_functions_t {
#define IOC_NRBITS 8
#define IOC_TYPEBITS 8
-#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) || defined(__sparc__)
+#if defined(__powerpc__) || defined(__powerpc64__) || defined(__mips__) || \
+ defined(__sparc__)
#define IOC_SIZEBITS 13
#define IOC_DIRBITS 3
#define IOC_NONE 1U
@@ -943,9 +961,8 @@ struct __sanitizer_cookie_io_functions_t {
// In sparc the 14 bits SIZE field overlaps with the
// least significant bit of DIR, so either IOC_READ or
// IOC_WRITE shall be 1 in order to get a non-zero SIZE.
-# define IOC_SIZE(nr) \
- ((((((nr) >> 29) & 0x7) & (4U|2U)) == 0)? \
- 0 : (((nr) >> 16) & 0x3fff))
+#define IOC_SIZE(nr) \
+ ((((((nr) >> 29) & 0x7) & (4U | 2U)) == 0) ? 0 : (((nr) >> 16) & 0x3fff))
#else
#define IOC_SIZE(nr) (((nr) >> IOC_SIZESHIFT) & IOC_SIZEMASK)
#endif
@@ -1447,9 +1464,6 @@ struct __sanitizer_cookie_io_functions_t {
extern unsigned IOCTL_PIO_SCRNMAP;
#endif
- extern const int errno_EINVAL;
- extern const int errno_EOWNERDEAD;
-
extern const int si_SEGV_MAPERR;
extern const int si_SEGV_ACCERR;
} // namespace __sanitizer
@@ -1471,4 +1485,6 @@ struct __sanitizer_cookie_io_functions_t {
COMPILER_CHECK(offsetof(struct __sanitizer_##CLASS, MEMBER) == \
offsetof(struct CLASS, MEMBER))
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC
+
#endif
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.cc b/libsanitizer/sanitizer_common/sanitizer_posix.cc
index d10213d..8f59deb 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.cc
@@ -15,23 +15,17 @@
#if SANITIZER_POSIX
#include "sanitizer_common.h"
+#include "sanitizer_file.h"
#include "sanitizer_libc.h"
#include "sanitizer_posix.h"
#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
+#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/mman.h>
-#if SANITIZER_LINUX
-#include <sys/utsname.h>
-#endif
-
-#if SANITIZER_LINUX && !SANITIZER_ANDROID
-#include <sys/personality.h>
-#endif
-
#if SANITIZER_FREEBSD
// The MAP_NORESERVE define has been removed in FreeBSD 11.x, and even before
// that, it was never implemented. So just define it to zero.
@@ -46,87 +40,13 @@ uptr GetMmapGranularity() {
return GetPageSize();
}
-#if SANITIZER_WORDSIZE == 32
-// Take care of unusable kernel area in top gigabyte.
-static uptr GetKernelAreaSize() {
-#if SANITIZER_LINUX && !SANITIZER_X32
- const uptr gbyte = 1UL << 30;
-
- // Firstly check if there are writable segments
- // mapped to top gigabyte (e.g. stack).
- MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr end, prot;
- while (proc_maps.Next(/*start*/nullptr, &end,
- /*offset*/nullptr, /*filename*/nullptr,
- /*filename_size*/0, &prot)) {
- if ((end >= 3 * gbyte)
- && (prot & MemoryMappingLayout::kProtectionWrite) != 0)
- return 0;
- }
-
-#if !SANITIZER_ANDROID
- // Even if nothing is mapped, top Gb may still be accessible
- // if we are running on 64-bit kernel.
- // Uname may report misleading results if personality type
- // is modified (e.g. under schroot) so check this as well.
- struct utsname uname_info;
- int pers = personality(0xffffffffUL);
- if (!(pers & PER_MASK)
- && uname(&uname_info) == 0
- && internal_strstr(uname_info.machine, "64"))
- return 0;
-#endif // SANITIZER_ANDROID
-
- // Top gigabyte is reserved for kernel.
- return gbyte;
-#else
- return 0;
-#endif // SANITIZER_LINUX && !SANITIZER_X32
-}
-#endif // SANITIZER_WORDSIZE == 32
-
-uptr GetMaxVirtualAddress() {
-#if SANITIZER_WORDSIZE == 64
-# if defined(__aarch64__) && SANITIZER_IOS && !SANITIZER_IOSSIM
- // Ideally, we would derive the upper bound from MACH_VM_MAX_ADDRESS. The
- // upper bound can change depending on the device.
- return 0x200000000 - 1;
-# elif defined(__powerpc64__) || defined(__aarch64__)
- // On PowerPC64 we have two different address space layouts: 44- and 46-bit.
- // We somehow need to figure out which one we are using now and choose
- // one of 0x00000fffffffffffUL and 0x00003fffffffffffUL.
- // Note that with 'ulimit -s unlimited' the stack is moved away from the top
- // of the address space, so simply checking the stack address is not enough.
- // This should (does) work for both PowerPC64 Endian modes.
- // Similarly, aarch64 has multiple address space layouts: 39, 42 and 47-bit.
- return (1ULL << (MostSignificantSetBitIndex(GET_CURRENT_FRAME()) + 1)) - 1;
-# elif defined(__mips64)
- return (1ULL << 40) - 1; // 0x000000ffffffffffUL;
-# elif defined(__s390x__)
- return (1ULL << 53) - 1; // 0x001fffffffffffffUL;
-# else
- return (1ULL << 47) - 1; // 0x00007fffffffffffUL;
-# endif
-#else // SANITIZER_WORDSIZE == 32
-# if defined(__s390__)
- return (1ULL << 31) - 1; // 0x7fffffff;
-# else
- uptr res = (1ULL << 32) - 1; // 0xffffffff;
- if (!common_flags()->full_address_space)
- res -= GetKernelAreaSize();
- CHECK_LT(reinterpret_cast<uptr>(&res), res);
- return res;
-# endif
-#endif // SANITIZER_WORDSIZE
-}
-
void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
size = RoundUpTo(size, GetPageSizeCached());
uptr res = internal_mmap(nullptr, size,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON, -1, 0);
int reserrno;
- if (internal_iserror(res, &reserrno))
+ if (UNLIKELY(internal_iserror(res, &reserrno)))
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno, raw_report);
IncreaseTotalMmap(size);
return (void *)res;
@@ -135,7 +55,7 @@ void *MmapOrDie(uptr size, const char *mem_type, bool raw_report) {
void UnmapOrDie(void *addr, uptr size) {
if (!addr || !size) return;
uptr res = internal_munmap(addr, size);
- if (internal_iserror(res)) {
+ if (UNLIKELY(internal_iserror(res))) {
Report("ERROR: %s failed to deallocate 0x%zx (%zd) bytes at address %p\n",
SanitizerToolName, size, size, addr);
CHECK("unable to unmap" && 0);
@@ -143,21 +63,39 @@ void UnmapOrDie(void *addr, uptr size) {
DecreaseTotalMmap(size);
}
+void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
+ size = RoundUpTo(size, GetPageSizeCached());
+ uptr res = internal_mmap(nullptr, size,
+ PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANON, -1, 0);
+ int reserrno;
+ if (UNLIKELY(internal_iserror(res, &reserrno))) {
+ if (reserrno == ENOMEM)
+ return nullptr;
+ ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
+ }
+ IncreaseTotalMmap(size);
+ return (void *)res;
+}
+
// We want to map a chunk of address space aligned to 'alignment'.
-// We do it by maping a bit more and then unmaping redundant pieces.
+// We do it by mapping a bit more and then unmapping redundant pieces.
// We probably can do it with fewer syscalls in some OS-dependent way.
-void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
+void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
+ const char *mem_type) {
CHECK(IsPowerOfTwo(size));
CHECK(IsPowerOfTwo(alignment));
uptr map_size = size + alignment;
- uptr map_res = (uptr)MmapOrDie(map_size, mem_type);
+ uptr map_res = (uptr)MmapOrDieOnFatalError(map_size, mem_type);
+ if (UNLIKELY(!map_res))
+ return nullptr;
uptr map_end = map_res + map_size;
uptr res = map_res;
- if (res & (alignment - 1)) // Not aligned.
- res = (map_res + alignment) & ~(alignment - 1);
- uptr end = res + size;
- if (res != map_res)
+ if (!IsAligned(res, alignment)) {
+ res = (map_res + alignment - 1) & ~(alignment - 1);
UnmapOrDie((void*)map_res, res - map_res);
+ }
+ uptr end = res + size;
if (end != map_end)
UnmapOrDie((void*)end, map_end - end);
return (void*)res;
@@ -171,13 +109,13 @@ void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
MAP_PRIVATE | MAP_ANON | MAP_NORESERVE,
-1, 0);
int reserrno;
- if (internal_iserror(p, &reserrno))
+ if (UNLIKELY(internal_iserror(p, &reserrno)))
ReportMmapFailureAndDie(size, mem_type, "allocate noreserve", reserrno);
IncreaseTotalMmap(size);
return (void *)p;
}
-void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
+void *MmapFixedImpl(uptr fixed_addr, uptr size, bool tolerate_enomem) {
uptr PageSize = GetPageSizeCached();
uptr p = internal_mmap((void*)(fixed_addr & ~(PageSize - 1)),
RoundUpTo(size, PageSize),
@@ -185,8 +123,10 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
MAP_PRIVATE | MAP_ANON | MAP_FIXED,
-1, 0);
int reserrno;
- if (internal_iserror(p, &reserrno)) {
- char mem_type[30];
+ if (UNLIKELY(internal_iserror(p, &reserrno))) {
+ if (tolerate_enomem && reserrno == ENOMEM)
+ return nullptr;
+ char mem_type[40];
internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
fixed_addr);
ReportMmapFailureAndDie(size, mem_type, "allocate", reserrno);
@@ -195,6 +135,14 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
return (void *)p;
}
+void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
+ return MmapFixedImpl(fixed_addr, size, false /*tolerate_enomem*/);
+}
+
+void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) {
+ return MmapFixedImpl(fixed_addr, size, true /*tolerate_enomem*/);
+}
+
bool MprotectNoAccess(uptr addr, uptr size) {
return 0 == internal_mprotect((void*)addr, size, PROT_NONE);
}
@@ -282,13 +230,12 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1,
// memory).
bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr start, end;
- while (proc_maps.Next(&start, &end,
- /*offset*/nullptr, /*filename*/nullptr,
- /*filename_size*/0, /*protection*/nullptr)) {
- if (start == end) continue; // Empty range.
- CHECK_NE(0, end);
- if (!IntervalsAreSeparate(start, end - 1, range_start, range_end))
+ MemoryMappedSegment segment;
+ while (proc_maps.Next(&segment)) {
+ if (segment.start == segment.end) continue; // Empty range.
+ CHECK_NE(0, segment.end);
+ if (!IntervalsAreSeparate(segment.start, segment.end - 1, range_start,
+ range_end))
return false;
}
return true;
@@ -296,13 +243,13 @@ bool MemoryRangeIsAvailable(uptr range_start, uptr range_end) {
void DumpProcessMap() {
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr start, end;
const sptr kBufSize = 4095;
char *filename = (char*)MmapOrDie(kBufSize, __func__);
+ MemoryMappedSegment segment(filename, kBufSize);
Report("Process memory map follows:\n");
- while (proc_maps.Next(&start, &end, /* file_offset */nullptr,
- filename, kBufSize, /* protection */nullptr)) {
- Printf("\t%p-%p\t%s\n", (void*)start, (void*)end, filename);
+ while (proc_maps.Next(&segment)) {
+ Printf("\t%p-%p\t%s\n", (void *)segment.start, (void *)segment.end,
+ segment.filename);
}
Report("End of process memory map.\n");
UnmapOrDie(filename, kBufSize);
@@ -332,28 +279,48 @@ void ReportFile::Write(const char *buffer, uptr length) {
}
bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) {
- uptr s, e, off, prot;
- InternalScopedString buff(kMaxPathLength);
MemoryMappingLayout proc_maps(/*cache_enabled*/false);
- while (proc_maps.Next(&s, &e, &off, buff.data(), buff.size(), &prot)) {
- if ((prot & MemoryMappingLayout::kProtectionExecute) != 0
- && internal_strcmp(module, buff.data()) == 0) {
- *start = s;
- *end = e;
+ InternalScopedString buff(kMaxPathLength);
+ MemoryMappedSegment segment(buff.data(), kMaxPathLength);
+ while (proc_maps.Next(&segment)) {
+ if (segment.IsExecutable() &&
+ internal_strcmp(module, segment.filename) == 0) {
+ *start = segment.start;
+ *end = segment.end;
return true;
}
}
return false;
}
-SignalContext SignalContext::Create(void *siginfo, void *context) {
- auto si = (siginfo_t *)siginfo;
- uptr addr = (uptr)si->si_addr;
- uptr pc, sp, bp;
- GetPcSpBp(context, &pc, &sp, &bp);
- WriteFlag write_flag = GetWriteFlag(context);
- bool is_memory_access = si->si_signo == SIGSEGV;
- return SignalContext(context, addr, pc, sp, bp, is_memory_access, write_flag);
+uptr SignalContext::GetAddress() const {
+ auto si = static_cast<const siginfo_t *>(siginfo);
+ return (uptr)si->si_addr;
+}
+
+bool SignalContext::IsMemoryAccess() const {
+ auto si = static_cast<const siginfo_t *>(siginfo);
+ return si->si_signo == SIGSEGV;
+}
+
+int SignalContext::GetType() const {
+ return static_cast<const siginfo_t *>(siginfo)->si_signo;
+}
+
+const char *SignalContext::Describe() const {
+ switch (GetType()) {
+ case SIGFPE:
+ return "FPE";
+ case SIGILL:
+ return "ILL";
+ case SIGABRT:
+ return "ABRT";
+ case SIGSEGV:
+ return "SEGV";
+ case SIGBUS:
+ return "BUS";
+ }
+ return "UNKNOWN SIGNAL";
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix.h b/libsanitizer/sanitizer_common/sanitizer_posix.h
index 68b34ba..9626654 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix.h
+++ b/libsanitizer/sanitizer_common/sanitizer_posix.h
@@ -14,6 +14,7 @@
// ----------- ATTENTION -------------
// This header should NOT include any other headers from sanitizer runtime.
#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_limits_netbsd.h"
#include "sanitizer_platform_limits_posix.h"
#if !SANITIZER_POSIX
@@ -85,6 +86,9 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum);
uptr internal_execve(const char *filename, char *const argv[],
char *const envp[]);
+
+bool IsStateDetached(int state);
+
} // namespace __sanitizer
#endif // SANITIZER_POSIX_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
index 335aad1..1a37118 100644
--- a/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_posix_libcdep.cc
@@ -16,6 +16,7 @@
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
+#include "sanitizer_platform_limits_netbsd.h"
#include "sanitizer_platform_limits_posix.h"
#include "sanitizer_posix.h"
#include "sanitizer_procmaps.h"
@@ -54,8 +55,12 @@ uptr GetThreadSelf() {
return (uptr)pthread_self();
}
-void ReleaseMemoryToOS(uptr addr, uptr size) {
- madvise((void*)addr, size, MADV_DONTNEED);
+void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
+ uptr page_size = GetPageSizeCached();
+ uptr beg_aligned = RoundUpTo(beg, page_size);
+ uptr end_aligned = RoundDownTo(end, page_size);
+ if (beg_aligned < end_aligned)
+ madvise((void*)beg_aligned, end_aligned - beg_aligned, MADV_DONTNEED);
}
void NoHugePagesInRegion(uptr addr, uptr size) {
@@ -128,7 +133,8 @@ void SleepForMillis(int millis) {
void Abort() {
#if !SANITIZER_GO
// If we are handling SIGABRT, unhandle it first.
- if (IsHandledDeadlySignal(SIGABRT)) {
+ // TODO(vitalybuka): Check if handler belongs to sanitizer.
+ if (GetHandleSignalMode(SIGABRT) != kHandleSignalNo) {
struct sigaction sigact;
internal_memset(&sigact, 0, sizeof(sigact));
sigact.sa_sigaction = (sa_sigaction_t)SIG_DFL;
@@ -182,8 +188,8 @@ void UnsetAlternateSignalStack() {
static void MaybeInstallSigaction(int signum,
SignalHandlerType handler) {
- if (!IsHandledDeadlySignal(signum))
- return;
+ if (GetHandleSignalMode(signum) == kHandleSignalNo) return;
+
struct sigaction sigact;
internal_memset(&sigact, 0, sizeof(sigact));
sigact.sa_sigaction = (sa_sigaction_t)handler;
@@ -206,6 +212,53 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
MaybeInstallSigaction(SIGFPE, handler);
MaybeInstallSigaction(SIGILL, handler);
}
+
+bool SignalContext::IsStackOverflow() const {
+ // Access at a reasonable offset above SP, or slightly below it (to account
+ // for x86_64 or PowerPC redzone, ARM push of multiple registers, etc) is
+ // probably a stack overflow.
+#ifdef __s390__
+ // On s390, the fault address in siginfo points to start of the page, not
+ // to the precise word that was accessed. Mask off the low bits of sp to
+ // take it into account.
+ bool IsStackAccess = addr >= (sp & ~0xFFF) && addr < sp + 0xFFFF;
+#else
+ bool IsStackAccess = addr + 512 > sp && addr < sp + 0xFFFF;
+#endif
+
+#if __powerpc__
+ // Large stack frames can be allocated with e.g.
+ // lis r0,-10000
+ // stdux r1,r1,r0 # store sp to [sp-10000] and update sp by -10000
+ // If the store faults then sp will not have been updated, so test above
+ // will not work, because the fault address will be more than just "slightly"
+ // below sp.
+ if (!IsStackAccess && IsAccessibleMemoryRange(pc, 4)) {
+ u32 inst = *(unsigned *)pc;
+ u32 ra = (inst >> 16) & 0x1F;
+ u32 opcd = inst >> 26;
+ u32 xo = (inst >> 1) & 0x3FF;
+ // Check for store-with-update to sp. The instructions we accept are:
+ // stbu rs,d(ra) stbux rs,ra,rb
+ // sthu rs,d(ra) sthux rs,ra,rb
+ // stwu rs,d(ra) stwux rs,ra,rb
+ // stdu rs,ds(ra) stdux rs,ra,rb
+ // where ra is r1 (the stack pointer).
+ if (ra == 1 &&
+ (opcd == 39 || opcd == 45 || opcd == 37 || opcd == 62 ||
+ (opcd == 31 && (xo == 247 || xo == 439 || xo == 183 || xo == 181))))
+ IsStackAccess = true;
+ }
+#endif // __powerpc__
+
+ // We also check si_code to filter out SEGV caused by something else other
+ // then hitting the guard page or unmapped memory, like, for example,
+ // unaligned memory access.
+ auto si = static_cast<const siginfo_t *>(siginfo);
+ return IsStackAccess &&
+ (si->si_code == si_SEGV_MAPERR || si->si_code == si_SEGV_ACCERR);
+}
+
#endif // SANITIZER_GO
bool IsAccessibleMemoryRange(uptr beg, uptr size) {
@@ -239,7 +292,6 @@ void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
// Same for /proc/self/exe in the symbolizer.
#if !SANITIZER_GO
Symbolizer::GetOrInit()->PrepareForSandboxing();
- CovPrepareForSandboxing(args);
#endif
}
@@ -412,6 +464,10 @@ int WaitForProcess(pid_t pid) {
return process_status;
}
+bool IsStateDetached(int state) {
+ return state == PTHREAD_CREATE_DETACHED;
+}
+
} // namespace __sanitizer
#endif // SANITIZER_POSIX
diff --git a/libsanitizer/sanitizer_common/sanitizer_printf.cc b/libsanitizer/sanitizer_common/sanitizer_printf.cc
index c11113d..1456c76 100644
--- a/libsanitizer/sanitizer_common/sanitizer_printf.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_printf.cc
@@ -26,8 +26,6 @@
namespace __sanitizer {
-StaticSpinMutex CommonSanitizerReportMutex;
-
static int AppendChar(char **buff, const char *buff_end, char c) {
if (*buff < buff_end) {
**buff = c;
@@ -41,7 +39,7 @@ static int AppendChar(char **buff, const char *buff_end, char c) {
// on the value of |pad_with_zero|.
static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
u8 base, u8 minimal_num_length, bool pad_with_zero,
- bool negative) {
+ bool negative, bool uppercase) {
uptr const kMaxLen = 30;
RAW_CHECK(base == 10 || base == 16);
RAW_CHECK(base == 10 || !negative);
@@ -74,23 +72,25 @@ static int AppendNumber(char **buff, const char *buff_end, u64 absolute_value,
if (negative && !pad_with_zero) result += AppendChar(buff, buff_end, '-');
for (; pos >= 0; pos--) {
char digit = static_cast<char>(num_buffer[pos]);
- result += AppendChar(buff, buff_end, (digit < 10) ? '0' + digit
- : 'a' + digit - 10);
+ digit = (digit < 10) ? '0' + digit : (uppercase ? 'A' : 'a') + digit - 10;
+ result += AppendChar(buff, buff_end, digit);
}
return result;
}
static int AppendUnsigned(char **buff, const char *buff_end, u64 num, u8 base,
- u8 minimal_num_length, bool pad_with_zero) {
+ u8 minimal_num_length, bool pad_with_zero,
+ bool uppercase) {
return AppendNumber(buff, buff_end, num, base, minimal_num_length,
- pad_with_zero, false /* negative */);
+ pad_with_zero, false /* negative */, uppercase);
}
static int AppendSignedDecimal(char **buff, const char *buff_end, s64 num,
u8 minimal_num_length, bool pad_with_zero) {
bool negative = (num < 0);
return AppendNumber(buff, buff_end, (u64)(negative ? -num : num), 10,
- minimal_num_length, pad_with_zero, negative);
+ minimal_num_length, pad_with_zero, negative,
+ false /* uppercase */);
}
static int AppendString(char **buff, const char *buff_end, int precision,
@@ -110,14 +110,16 @@ static int AppendPointer(char **buff, const char *buff_end, u64 ptr_value) {
int result = 0;
result += AppendString(buff, buff_end, -1, "0x");
result += AppendUnsigned(buff, buff_end, ptr_value, 16,
- SANITIZER_POINTER_FORMAT_LENGTH, true);
+ SANITIZER_POINTER_FORMAT_LENGTH,
+ true /* pad_with_zero */, false /* uppercase */);
return result;
}
int VSNPrintf(char *buff, int buff_length,
const char *format, va_list args) {
static const char *kPrintfFormatsHelp =
- "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x}; %p; %(\\.\\*)?s; %c\n";
+ "Supported Printf formats: %([0-9]*)?(z|ll)?{d,u,x,X}; %p; %(\\.\\*)?s; "
+ "%c\n";
RAW_CHECK(format);
RAW_CHECK(buff_length > 0);
const char *buff_end = &buff[buff_length - 1];
@@ -162,12 +164,14 @@ int VSNPrintf(char *buff, int buff_length,
break;
}
case 'u':
- case 'x': {
+ case 'x':
+ case 'X': {
uval = have_ll ? va_arg(args, u64)
: have_z ? va_arg(args, uptr)
: va_arg(args, unsigned);
- result += AppendUnsigned(&buff, buff_end, uval,
- (*cur == 'u') ? 10 : 16, width, pad_with_zero);
+ bool uppercase = (*cur == 'X');
+ result += AppendUnsigned(&buff, buff_end, uval, (*cur == 'u') ? 10 : 16,
+ width, pad_with_zero, uppercase);
break;
}
case 'p': {
@@ -206,15 +210,11 @@ void SetPrintfAndReportCallback(void (*callback)(const char *)) {
}
// Can be overriden in frontend.
-#if SANITIZER_SUPPORTS_WEAK_HOOKS
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-void OnPrint(const char *str) {
- (void)str;
-}
-#elif SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS)
-void OnPrint(const char *str);
+#if SANITIZER_GO && defined(TSAN_EXTERNAL_HOOKS)
+// Implementation must be defined in frontend.
+extern "C" void OnPrint(const char *str);
#else
-void OnPrint(const char *str) {
+SANITIZER_INTERFACE_WEAK_DEF(void, OnPrint, const char *str) {
(void)str;
}
#endif
@@ -225,19 +225,16 @@ static void CallPrintfAndReportCallback(const char *str) {
PrintfAndReportCallback(str);
}
-static void SharedPrintfCode(bool append_pid, const char *format,
- va_list args) {
+static void NOINLINE SharedPrintfCodeNoBuffer(bool append_pid,
+ char *local_buffer,
+ int buffer_size,
+ const char *format,
+ va_list args) {
va_list args2;
va_copy(args2, args);
const int kLen = 16 * 1024;
- // |local_buffer| is small enough not to overflow the stack and/or violate
- // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other
- // hand, the bigger the buffer is, the more the chance the error report will
- // fit into it.
- char local_buffer[400];
int needed_length;
char *buffer = local_buffer;
- int buffer_size = ARRAY_SIZE(local_buffer);
// First try to print a message using a local buffer, and then fall back to
// mmaped buffer.
for (int use_mmap = 0; use_mmap < 2; use_mmap++) {
@@ -255,7 +252,9 @@ static void SharedPrintfCode(bool append_pid, const char *format,
RAW_CHECK_MSG(needed_length < kLen, \
"Buffer in Report is too short!\n"); \
}
- if (append_pid) {
+ // Fuchsia's logging infrastructure always keeps track of the logging
+ // process, thread, and timestamp, so never prepend such information.
+ if (!SANITIZER_FUCHSIA && append_pid) {
int pid = internal_getpid();
const char *exe_name = GetProcessName();
if (common_flags()->log_exe_name && exe_name) {
@@ -263,9 +262,8 @@ static void SharedPrintfCode(bool append_pid, const char *format,
"==%s", exe_name);
CHECK_NEEDED_LENGTH
}
- needed_length += internal_snprintf(buffer + needed_length,
- buffer_size - needed_length,
- "==%d==", pid);
+ needed_length += internal_snprintf(
+ buffer + needed_length, buffer_size - needed_length, "==%d==", pid);
CHECK_NEEDED_LENGTH
}
needed_length += VSNPrintf(buffer + needed_length,
@@ -288,6 +286,17 @@ static void SharedPrintfCode(bool append_pid, const char *format,
va_end(args2);
}
+static void NOINLINE SharedPrintfCode(bool append_pid, const char *format,
+ va_list args) {
+ // |local_buffer| is small enough not to overflow the stack and/or violate
+ // the stack limit enforced by TSan (-Wframe-larger-than=512). On the other
+ // hand, the bigger the buffer is, the more the chance the error report will
+ // fit into it.
+ char local_buffer[400];
+ SharedPrintfCodeNoBuffer(append_pid, local_buffer, ARRAY_SIZE(local_buffer),
+ format, args);
+}
+
FORMAT(1, 2)
void Printf(const char *format, ...) {
va_list args;
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps.h b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
index 0183a09..040f694 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps.h
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps.h
@@ -12,29 +12,61 @@
#ifndef SANITIZER_PROCMAPS_H
#define SANITIZER_PROCMAPS_H
+#include "sanitizer_platform.h"
+
+#if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC
+
#include "sanitizer_common.h"
#include "sanitizer_internal_defs.h"
+#include "sanitizer_linux.h"
+#include "sanitizer_mac.h"
#include "sanitizer_mutex.h"
namespace __sanitizer {
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
-struct ProcSelfMapsBuff {
- char *data;
- uptr mmaped_size;
- uptr len;
-};
-// Reads process memory map in an OS-specific way.
-void ReadProcMaps(ProcSelfMapsBuff *proc_maps);
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+// Memory protection masks.
+static const uptr kProtectionRead = 1;
+static const uptr kProtectionWrite = 2;
+static const uptr kProtectionExecute = 4;
+static const uptr kProtectionShared = 8;
+
+struct MemoryMappedSegmentData;
+
+class MemoryMappedSegment {
+ public:
+ MemoryMappedSegment(char *buff = nullptr, uptr size = 0)
+ : filename(buff), filename_size(size), data_(nullptr) {}
+ ~MemoryMappedSegment() {}
+
+ bool IsReadable() const { return protection & kProtectionRead; }
+ bool IsWritable() const { return protection & kProtectionWrite; }
+ bool IsExecutable() const { return protection & kProtectionExecute; }
+ bool IsShared() const { return protection & kProtectionShared; }
+
+ void AddAddressRanges(LoadedModule *module);
+
+ uptr start;
+ uptr end;
+ uptr offset;
+ char *filename; // owned by caller
+ uptr filename_size;
+ uptr protection;
+ ModuleArch arch;
+ u8 uuid[kModuleUUIDSize];
+
+ private:
+ friend class MemoryMappingLayout;
+
+ // This field is assigned and owned by MemoryMappingLayout if needed
+ MemoryMappedSegmentData *data_;
+};
class MemoryMappingLayout {
public:
explicit MemoryMappingLayout(bool cache_enabled);
~MemoryMappingLayout();
- bool Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size, uptr *protection);
+ bool Next(MemoryMappedSegment *segment);
void Reset();
// In some cases, e.g. when running under a sandbox on Linux, ASan is unable
// to obtain the memory mappings. It should fall back to pre-cached data
@@ -42,47 +74,14 @@ class MemoryMappingLayout {
static void CacheMemoryMappings();
// Adds all mapped objects into a vector.
- void DumpListOfModules(InternalMmapVector<LoadedModule> *modules);
-
- // Memory protection masks.
- static const uptr kProtectionRead = 1;
- static const uptr kProtectionWrite = 2;
- static const uptr kProtectionExecute = 4;
- static const uptr kProtectionShared = 8;
+ void DumpListOfModules(InternalMmapVectorNoCtor<LoadedModule> *modules);
private:
void LoadFromCache();
- // FIXME: Hide implementation details for different platforms in
- // platform-specific files.
-# if SANITIZER_FREEBSD || SANITIZER_LINUX
- ProcSelfMapsBuff proc_self_maps_;
- const char *current_;
-
- // Static mappings cache.
- static ProcSelfMapsBuff cached_proc_self_maps_;
- static StaticSpinMutex cache_lock_; // protects cached_proc_self_maps_.
-# elif SANITIZER_MAC
- template<u32 kLCSegment, typename SegmentCommand>
- bool NextSegmentLoad(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection);
- int current_image_;
- u32 current_magic_;
- u32 current_filetype_;
- int current_load_cmd_count_;
- char *current_load_cmd_addr_;
-# endif
+ MemoryMappingLayoutData data_;
};
-typedef void (*fill_profile_f)(uptr start, uptr rss, bool file,
- /*out*/uptr *stats, uptr stats_size);
-
-// Parse the contents of /proc/self/smaps and generate a memory profile.
-// |cb| is a tool-specific callback that fills the |stats| array containing
-// |stats_size| elements.
-void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size);
-
// Returns code range for the specified module.
bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end);
@@ -93,4 +92,6 @@ uptr ParseHex(const char **p);
} // namespace __sanitizer
+#endif // SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD ||
+ // SANITIZER_MAC
#endif // SANITIZER_PROCMAPS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc
index c725c2e..36b97b1 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_common.cc
@@ -10,7 +10,7 @@
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#include "sanitizer_common.h"
#include "sanitizer_placement_new.h"
@@ -18,9 +18,8 @@
namespace __sanitizer {
-// Linker initialized.
-ProcSelfMapsBuff MemoryMappingLayout::cached_proc_self_maps_;
-StaticSpinMutex MemoryMappingLayout::cache_lock_; // Linker initialized.
+static ProcSelfMapsBuff cached_proc_self_maps;
+static StaticSpinMutex cache_lock;
static int TranslateDigit(char c) {
if (c >= '0' && c <= '9')
@@ -62,15 +61,21 @@ uptr ParseHex(const char **p) {
return ParseNumber(p, 16);
}
+void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
+ // data_ should be unused on this platform
+ CHECK(!data_);
+ module->addAddressRange(start, end, IsExecutable(), IsWritable());
+}
+
MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
- ReadProcMaps(&proc_self_maps_);
+ ReadProcMaps(&data_.proc_self_maps);
if (cache_enabled) {
- if (proc_self_maps_.mmaped_size == 0) {
+ if (data_.proc_self_maps.mmaped_size == 0) {
LoadFromCache();
- CHECK_GT(proc_self_maps_.len, 0);
+ CHECK_GT(data_.proc_self_maps.len, 0);
}
} else {
- CHECK_GT(proc_self_maps_.mmaped_size, 0);
+ CHECK_GT(data_.proc_self_maps.mmaped_size, 0);
}
Reset();
// FIXME: in the future we may want to cache the mappings on demand only.
@@ -81,24 +86,22 @@ MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
MemoryMappingLayout::~MemoryMappingLayout() {
// Only unmap the buffer if it is different from the cached one. Otherwise
// it will be unmapped when the cache is refreshed.
- if (proc_self_maps_.data != cached_proc_self_maps_.data) {
- UnmapOrDie(proc_self_maps_.data, proc_self_maps_.mmaped_size);
+ if (data_.proc_self_maps.data != cached_proc_self_maps.data) {
+ UnmapOrDie(data_.proc_self_maps.data, data_.proc_self_maps.mmaped_size);
}
}
-void MemoryMappingLayout::Reset() {
- current_ = proc_self_maps_.data;
-}
+void MemoryMappingLayout::Reset() { data_.current = data_.proc_self_maps.data; }
// static
void MemoryMappingLayout::CacheMemoryMappings() {
- SpinMutexLock l(&cache_lock_);
+ SpinMutexLock l(&cache_lock);
// Don't invalidate the cache if the mappings are unavailable.
ProcSelfMapsBuff old_proc_self_maps;
- old_proc_self_maps = cached_proc_self_maps_;
- ReadProcMaps(&cached_proc_self_maps_);
- if (cached_proc_self_maps_.mmaped_size == 0) {
- cached_proc_self_maps_ = old_proc_self_maps;
+ old_proc_self_maps = cached_proc_self_maps;
+ ReadProcMaps(&cached_proc_self_maps);
+ if (cached_proc_self_maps.mmaped_size == 0) {
+ cached_proc_self_maps = old_proc_self_maps;
} else {
if (old_proc_self_maps.mmaped_size) {
UnmapOrDie(old_proc_self_maps.data,
@@ -108,21 +111,19 @@ void MemoryMappingLayout::CacheMemoryMappings() {
}
void MemoryMappingLayout::LoadFromCache() {
- SpinMutexLock l(&cache_lock_);
- if (cached_proc_self_maps_.data) {
- proc_self_maps_ = cached_proc_self_maps_;
+ SpinMutexLock l(&cache_lock);
+ if (cached_proc_self_maps.data) {
+ data_.proc_self_maps = cached_proc_self_maps;
}
}
void MemoryMappingLayout::DumpListOfModules(
- InternalMmapVector<LoadedModule> *modules) {
+ InternalMmapVectorNoCtor<LoadedModule> *modules) {
Reset();
- uptr cur_beg, cur_end, cur_offset, prot;
InternalScopedString module_name(kMaxPathLength);
- for (uptr i = 0; Next(&cur_beg, &cur_end, &cur_offset, module_name.data(),
- module_name.size(), &prot);
- i++) {
- const char *cur_name = module_name.data();
+ MemoryMappedSegment segment(module_name.data(), module_name.size());
+ for (uptr i = 0; Next(&segment); i++) {
+ const char *cur_name = segment.filename;
if (cur_name[0] == '\0')
continue;
// Don't subtract 'cur_beg' from the first entry:
@@ -136,10 +137,10 @@ void MemoryMappingLayout::DumpListOfModules(
// mapped high at address space (in particular, higher than
// shadow memory of the tool), so the module can't be the
// first entry.
- uptr base_address = (i ? cur_beg : 0) - cur_offset;
+ uptr base_address = (i ? segment.start : 0) - segment.offset;
LoadedModule cur_module;
cur_module.set(cur_name, base_address);
- cur_module.addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+ segment.AddAddressRanges(&cur_module);
modules->push_back(cur_module);
}
}
@@ -170,4 +171,4 @@ void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) {
} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_freebsd.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_freebsd.cc
index fbc5520..ba5d144 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_freebsd.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_freebsd.cc
@@ -5,18 +5,22 @@
//
//===----------------------------------------------------------------------===//
//
-// Information about the process mappings (FreeBSD-specific parts).
+// Information about the process mappings (FreeBSD and NetBSD-specific parts).
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
#include "sanitizer_common.h"
+#if SANITIZER_FREEBSD
#include "sanitizer_freebsd.h"
+#endif
#include "sanitizer_procmaps.h"
#include <unistd.h>
#include <sys/sysctl.h>
+#if SANITIZER_FREEBSD
#include <sys/user.h>
+#endif
// Fix 'kinfo_vmentry' definition on FreeBSD prior v9.2 in 32-bit mode.
#if SANITIZER_FREEBSD && (SANITIZER_WORDSIZE == 32)
@@ -29,16 +33,30 @@
namespace __sanitizer {
void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
- const int Mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid() };
+ const int Mib[] = {
+#if SANITIZER_FREEBSD
+ CTL_KERN,
+ KERN_PROC,
+ KERN_PROC_VMMAP,
+ getpid()
+#else
+ CTL_VM,
+ VM_PROC,
+ VM_PROC_MAP,
+ getpid(),
+ sizeof(struct kinfo_vmentry)
+#endif
+ };
+
size_t Size = 0;
- int Err = sysctl(Mib, 4, NULL, &Size, NULL, 0);
+ int Err = sysctl(Mib, ARRAY_SIZE(Mib), NULL, &Size, NULL, 0);
CHECK_EQ(Err, 0);
CHECK_GT(Size, 0);
size_t MmapedSize = Size * 4 / 3;
void *VmMap = MmapOrDie(MmapedSize, "ReadProcMaps()");
Size = MmapedSize;
- Err = sysctl(Mib, 4, VmMap, &Size, NULL, 0);
+ Err = sysctl(Mib, ARRAY_SIZE(Mib), VmMap, &Size, NULL, 0);
CHECK_EQ(Err, 0);
proc_maps->data = (char*)VmMap;
@@ -46,41 +64,38 @@ void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
proc_maps->len = Size;
}
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection) {
- char *last = proc_self_maps_.data + proc_self_maps_.len;
- if (current_ >= last) return false;
- uptr dummy;
- if (!start) start = &dummy;
- if (!end) end = &dummy;
- if (!offset) offset = &dummy;
- if (!protection) protection = &dummy;
- struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry*)current_;
-
- *start = (uptr)VmEntry->kve_start;
- *end = (uptr)VmEntry->kve_end;
- *offset = (uptr)VmEntry->kve_offset;
-
- *protection = 0;
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
+ char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
+ if (data_.current >= last) return false;
+ struct kinfo_vmentry *VmEntry = (struct kinfo_vmentry *)data_.current;
+
+ segment->start = (uptr)VmEntry->kve_start;
+ segment->end = (uptr)VmEntry->kve_end;
+ segment->offset = (uptr)VmEntry->kve_offset;
+
+ segment->protection = 0;
if ((VmEntry->kve_protection & KVME_PROT_READ) != 0)
- *protection |= kProtectionRead;
+ segment->protection |= kProtectionRead;
if ((VmEntry->kve_protection & KVME_PROT_WRITE) != 0)
- *protection |= kProtectionWrite;
+ segment->protection |= kProtectionWrite;
if ((VmEntry->kve_protection & KVME_PROT_EXEC) != 0)
- *protection |= kProtectionExecute;
+ segment->protection |= kProtectionExecute;
- if (filename != NULL && filename_size > 0) {
- internal_snprintf(filename,
- Min(filename_size, (uptr)PATH_MAX),
- "%s", VmEntry->kve_path);
+ if (segment->filename != NULL && segment->filename_size > 0) {
+ internal_snprintf(segment->filename,
+ Min(segment->filename_size, (uptr)PATH_MAX), "%s",
+ VmEntry->kve_path);
}
- current_ += VmEntry->kve_structsize;
+#if SANITIZER_FREEBSD
+ data_.current += VmEntry->kve_structsize;
+#else
+ data_.current += sizeof(*VmEntry);
+#endif
return true;
}
} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD
+#endif // SANITIZER_FREEBSD || SANITIZER_NETBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc
index 10918e5..b97d5f6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_linux.cc
@@ -16,70 +16,57 @@
namespace __sanitizer {
void ReadProcMaps(ProcSelfMapsBuff *proc_maps) {
- CHECK(ReadFileToBuffer("/proc/self/maps", &proc_maps->data,
- &proc_maps->mmaped_size, &proc_maps->len));
+ ReadFileToBuffer("/proc/self/maps", &proc_maps->data, &proc_maps->mmaped_size,
+ &proc_maps->len);
}
static bool IsOneOf(char c, char c1, char c2) {
return c == c1 || c == c2;
}
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection) {
- char *last = proc_self_maps_.data + proc_self_maps_.len;
- if (current_ >= last) return false;
- uptr dummy;
- if (!start) start = &dummy;
- if (!end) end = &dummy;
- if (!offset) offset = &dummy;
- if (!protection) protection = &dummy;
- char *next_line = (char*)internal_memchr(current_, '\n', last - current_);
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
+ char *last = data_.proc_self_maps.data + data_.proc_self_maps.len;
+ if (data_.current >= last) return false;
+ char *next_line =
+ (char *)internal_memchr(data_.current, '\n', last - data_.current);
if (next_line == 0)
next_line = last;
// Example: 08048000-08056000 r-xp 00000000 03:0c 64593 /foo/bar
- *start = ParseHex(&current_);
- CHECK_EQ(*current_++, '-');
- *end = ParseHex(&current_);
- CHECK_EQ(*current_++, ' ');
- CHECK(IsOneOf(*current_, '-', 'r'));
- *protection = 0;
- if (*current_++ == 'r')
- *protection |= kProtectionRead;
- CHECK(IsOneOf(*current_, '-', 'w'));
- if (*current_++ == 'w')
- *protection |= kProtectionWrite;
- CHECK(IsOneOf(*current_, '-', 'x'));
- if (*current_++ == 'x')
- *protection |= kProtectionExecute;
- CHECK(IsOneOf(*current_, 's', 'p'));
- if (*current_++ == 's')
- *protection |= kProtectionShared;
- CHECK_EQ(*current_++, ' ');
- *offset = ParseHex(&current_);
- CHECK_EQ(*current_++, ' ');
- ParseHex(&current_);
- CHECK_EQ(*current_++, ':');
- ParseHex(&current_);
- CHECK_EQ(*current_++, ' ');
- while (IsDecimal(*current_))
- current_++;
+ segment->start = ParseHex(&data_.current);
+ CHECK_EQ(*data_.current++, '-');
+ segment->end = ParseHex(&data_.current);
+ CHECK_EQ(*data_.current++, ' ');
+ CHECK(IsOneOf(*data_.current, '-', 'r'));
+ segment->protection = 0;
+ if (*data_.current++ == 'r') segment->protection |= kProtectionRead;
+ CHECK(IsOneOf(*data_.current, '-', 'w'));
+ if (*data_.current++ == 'w') segment->protection |= kProtectionWrite;
+ CHECK(IsOneOf(*data_.current, '-', 'x'));
+ if (*data_.current++ == 'x') segment->protection |= kProtectionExecute;
+ CHECK(IsOneOf(*data_.current, 's', 'p'));
+ if (*data_.current++ == 's') segment->protection |= kProtectionShared;
+ CHECK_EQ(*data_.current++, ' ');
+ segment->offset = ParseHex(&data_.current);
+ CHECK_EQ(*data_.current++, ' ');
+ ParseHex(&data_.current);
+ CHECK_EQ(*data_.current++, ':');
+ ParseHex(&data_.current);
+ CHECK_EQ(*data_.current++, ' ');
+ while (IsDecimal(*data_.current)) data_.current++;
// Qemu may lack the trailing space.
// https://github.com/google/sanitizers/issues/160
- // CHECK_EQ(*current_++, ' ');
+ // CHECK_EQ(*data_.current++, ' ');
// Skip spaces.
- while (current_ < next_line && *current_ == ' ')
- current_++;
+ while (data_.current < next_line && *data_.current == ' ') data_.current++;
// Fill in the filename.
- uptr i = 0;
- while (current_ < next_line) {
- if (filename && i < filename_size - 1)
- filename[i++] = *current_;
- current_++;
+ if (segment->filename) {
+ uptr len =
+ Min((uptr)(next_line - data_.current), segment->filename_size - 1);
+ internal_strncpy(segment->filename, data_.current, len);
+ segment->filename[len] = 0;
}
- if (filename && i < filename_size)
- filename[i] = 0;
- current_ = next_line + 1;
+
+ data_.current = next_line + 1;
return true;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc
index 81829a7..34f0c20 100644
--- a/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_procmaps_mac.cc
@@ -16,9 +16,69 @@
#include <mach-o/dyld.h>
#include <mach-o/loader.h>
+#include <mach/mach.h>
+
+// These are not available in older macOS SDKs.
+#ifndef CPU_SUBTYPE_X86_64_H
+#define CPU_SUBTYPE_X86_64_H ((cpu_subtype_t)8) /* Haswell */
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7S
+#define CPU_SUBTYPE_ARM_V7S ((cpu_subtype_t)11) /* Swift */
+#endif
+#ifndef CPU_SUBTYPE_ARM_V7K
+#define CPU_SUBTYPE_ARM_V7K ((cpu_subtype_t)12)
+#endif
+#ifndef CPU_TYPE_ARM64
+#define CPU_TYPE_ARM64 (CPU_TYPE_ARM | CPU_ARCH_ABI64)
+#endif
namespace __sanitizer {
+// Contains information used to iterate through sections.
+struct MemoryMappedSegmentData {
+ char name[kMaxSegName];
+ uptr nsects;
+ char *current_load_cmd_addr;
+ u32 lc_type;
+ uptr base_virt_addr;
+ uptr addr_mask;
+};
+
+template <typename Section>
+static void NextSectionLoad(LoadedModule *module, MemoryMappedSegmentData *data,
+ bool isWritable) {
+ const Section *sc = (const Section *)data->current_load_cmd_addr;
+ data->current_load_cmd_addr += sizeof(Section);
+
+ uptr sec_start = (sc->addr & data->addr_mask) + data->base_virt_addr;
+ uptr sec_end = sec_start + sc->size;
+ module->addAddressRange(sec_start, sec_end, /*executable=*/false, isWritable,
+ sc->sectname);
+}
+
+void MemoryMappedSegment::AddAddressRanges(LoadedModule *module) {
+ // Don't iterate over sections when the caller hasn't set up the
+ // data pointer, when there are no sections, or when the segment
+ // is executable. Avoid iterating over executable sections because
+ // it will confuse libignore, and because the extra granularity
+ // of information is not needed by any sanitizers.
+ if (!data_ || !data_->nsects || IsExecutable()) {
+ module->addAddressRange(start, end, IsExecutable(), IsWritable(),
+ data_ ? data_->name : nullptr);
+ return;
+ }
+
+ do {
+ if (data_->lc_type == LC_SEGMENT) {
+ NextSectionLoad<struct section>(module, data_, IsWritable());
+#ifdef MH_MAGIC_64
+ } else if (data_->lc_type == LC_SEGMENT_64) {
+ NextSectionLoad<struct section_64>(module, data_, IsWritable());
+#endif
+ }
+ } while (--data_->nsects);
+}
+
MemoryMappingLayout::MemoryMappingLayout(bool cache_enabled) {
Reset();
}
@@ -46,13 +106,22 @@ void MemoryMappingLayout::Reset() {
// _dyld_image_count is thread-unsafe. We need to register callbacks for
// adding and removing images which will invalidate the MemoryMappingLayout
// state.
- current_image_ = _dyld_image_count();
- current_load_cmd_count_ = -1;
- current_load_cmd_addr_ = 0;
- current_magic_ = 0;
- current_filetype_ = 0;
+ data_.current_image = _dyld_image_count();
+ data_.current_load_cmd_count = -1;
+ data_.current_load_cmd_addr = 0;
+ data_.current_magic = 0;
+ data_.current_filetype = 0;
+ data_.current_arch = kModuleArchUnknown;
+ internal_memset(data_.current_uuid, 0, kModuleUUIDSize);
}
+// The dyld load address should be unchanged throughout process execution,
+// and it is expensive to compute once many libraries have been loaded,
+// so cache it here and do not reset.
+static mach_header *dyld_hdr = 0;
+static const char kDyldPath[] = "/usr/lib/dyld";
+static const int kDyldImageIdx = -1;
+
// static
void MemoryMappingLayout::CacheMemoryMappings() {
// No-op on Mac for now.
@@ -62,6 +131,48 @@ void MemoryMappingLayout::LoadFromCache() {
// No-op on Mac for now.
}
+// _dyld_get_image_header() and related APIs don't report dyld itself.
+// We work around this by manually recursing through the memory map
+// until we hit a Mach header matching dyld instead. These recurse
+// calls are expensive, but the first memory map generation occurs
+// early in the process, when dyld is one of the only images loaded,
+// so it will be hit after only a few iterations.
+static mach_header *get_dyld_image_header() {
+ mach_port_name_t port;
+ if (task_for_pid(mach_task_self(), internal_getpid(), &port) !=
+ KERN_SUCCESS) {
+ return nullptr;
+ }
+
+ unsigned depth = 1;
+ vm_size_t size = 0;
+ vm_address_t address = 0;
+ kern_return_t err = KERN_SUCCESS;
+ mach_msg_type_number_t count = VM_REGION_SUBMAP_INFO_COUNT_64;
+
+ while (true) {
+ struct vm_region_submap_info_64 info;
+ err = vm_region_recurse_64(port, &address, &size, &depth,
+ (vm_region_info_t)&info, &count);
+ if (err != KERN_SUCCESS) return nullptr;
+
+ if (size >= sizeof(mach_header) && info.protection & kProtectionRead) {
+ mach_header *hdr = (mach_header *)address;
+ if ((hdr->magic == MH_MAGIC || hdr->magic == MH_MAGIC_64) &&
+ hdr->filetype == MH_DYLINKER) {
+ return hdr;
+ }
+ }
+ address += size;
+ }
+}
+
+const mach_header *get_dyld_hdr() {
+ if (!dyld_hdr) dyld_hdr = get_dyld_image_header();
+
+ return dyld_hdr;
+}
+
// Next and NextSegmentLoad were inspired by base/sysinfo.cc in
// Google Perftools, https://github.com/gperftools/gperftools.
@@ -69,79 +180,165 @@ void MemoryMappingLayout::LoadFromCache() {
// and returns the start and end addresses and file offset of the corresponding
// segment.
// Note that the segment addresses are not necessarily sorted.
-template<u32 kLCSegment, typename SegmentCommand>
-bool MemoryMappingLayout::NextSegmentLoad(
- uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size, uptr *protection) {
- const char* lc = current_load_cmd_addr_;
- current_load_cmd_addr_ += ((const load_command *)lc)->cmdsize;
+template <u32 kLCSegment, typename SegmentCommand>
+static bool NextSegmentLoad(MemoryMappedSegment *segment,
+MemoryMappedSegmentData *seg_data, MemoryMappingLayoutData &layout_data) {
+ const char *lc = layout_data.current_load_cmd_addr;
+ layout_data.current_load_cmd_addr += ((const load_command *)lc)->cmdsize;
if (((const load_command *)lc)->cmd == kLCSegment) {
- const sptr dlloff = _dyld_get_image_vmaddr_slide(current_image_);
const SegmentCommand* sc = (const SegmentCommand *)lc;
- if (start) *start = sc->vmaddr + dlloff;
- if (protection) {
- // Return the initial protection.
- *protection = sc->initprot;
+ uptr base_virt_addr, addr_mask;
+ if (layout_data.current_image == kDyldImageIdx) {
+ base_virt_addr = (uptr)get_dyld_hdr();
+ // vmaddr is masked with 0xfffff because on macOS versions < 10.12,
+ // it contains an absolute address rather than an offset for dyld.
+ // To make matters even more complicated, this absolute address
+ // isn't actually the absolute segment address, but the offset portion
+ // of the address is accurate when combined with the dyld base address,
+ // and the mask will give just this offset.
+ addr_mask = 0xfffff;
+ } else {
+ base_virt_addr =
+ (uptr)_dyld_get_image_vmaddr_slide(layout_data.current_image);
+ addr_mask = ~0;
}
- if (end) *end = sc->vmaddr + sc->vmsize + dlloff;
- if (offset) {
- if (current_filetype_ == /*MH_EXECUTE*/ 0x2) {
- *offset = sc->vmaddr;
- } else {
- *offset = sc->fileoff;
- }
+
+ segment->start = (sc->vmaddr & addr_mask) + base_virt_addr;
+ segment->end = segment->start + sc->vmsize;
+ // Most callers don't need section information, so only fill this struct
+ // when required.
+ if (seg_data) {
+ seg_data->nsects = sc->nsects;
+ seg_data->current_load_cmd_addr =
+ (char *)lc + sizeof(SegmentCommand);
+ seg_data->lc_type = kLCSegment;
+ seg_data->base_virt_addr = base_virt_addr;
+ seg_data->addr_mask = addr_mask;
+ internal_strncpy(seg_data->name, sc->segname,
+ ARRAY_SIZE(seg_data->name));
}
- if (filename) {
- internal_strncpy(filename, _dyld_get_image_name(current_image_),
- filename_size);
+
+ // Return the initial protection.
+ segment->protection = sc->initprot;
+ segment->offset = (layout_data.current_filetype ==
+ /*MH_EXECUTE*/ 0x2)
+ ? sc->vmaddr
+ : sc->fileoff;
+ if (segment->filename) {
+ const char *src = (layout_data.current_image == kDyldImageIdx)
+ ? kDyldPath
+ : _dyld_get_image_name(layout_data.current_image);
+ internal_strncpy(segment->filename, src, segment->filename_size);
}
+ segment->arch = layout_data.current_arch;
+ internal_memcpy(segment->uuid, layout_data.current_uuid, kModuleUUIDSize);
return true;
}
return false;
}
-bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
- char filename[], uptr filename_size,
- uptr *protection) {
- for (; current_image_ >= 0; current_image_--) {
- const mach_header* hdr = _dyld_get_image_header(current_image_);
+ModuleArch ModuleArchFromCpuType(cpu_type_t cputype, cpu_subtype_t cpusubtype) {
+ cpusubtype = cpusubtype & ~CPU_SUBTYPE_MASK;
+ switch (cputype) {
+ case CPU_TYPE_I386:
+ return kModuleArchI386;
+ case CPU_TYPE_X86_64:
+ if (cpusubtype == CPU_SUBTYPE_X86_64_ALL) return kModuleArchX86_64;
+ if (cpusubtype == CPU_SUBTYPE_X86_64_H) return kModuleArchX86_64H;
+ CHECK(0 && "Invalid subtype of x86_64");
+ return kModuleArchUnknown;
+ case CPU_TYPE_ARM:
+ if (cpusubtype == CPU_SUBTYPE_ARM_V6) return kModuleArchARMV6;
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7) return kModuleArchARMV7;
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7S) return kModuleArchARMV7S;
+ if (cpusubtype == CPU_SUBTYPE_ARM_V7K) return kModuleArchARMV7K;
+ CHECK(0 && "Invalid subtype of ARM");
+ return kModuleArchUnknown;
+ case CPU_TYPE_ARM64:
+ return kModuleArchARM64;
+ default:
+ CHECK(0 && "Invalid CPU type");
+ return kModuleArchUnknown;
+ }
+}
+
+static const load_command *NextCommand(const load_command *lc) {
+ return (const load_command *)((char *)lc + lc->cmdsize);
+}
+
+static void FindUUID(const load_command *first_lc, u8 *uuid_output) {
+ for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) {
+ if (lc->cmd != LC_UUID) continue;
+
+ const uuid_command *uuid_lc = (const uuid_command *)lc;
+ const uint8_t *uuid = &uuid_lc->uuid[0];
+ internal_memcpy(uuid_output, uuid, kModuleUUIDSize);
+ return;
+ }
+}
+
+static bool IsModuleInstrumented(const load_command *first_lc) {
+ for (const load_command *lc = first_lc; lc->cmd != 0; lc = NextCommand(lc)) {
+ if (lc->cmd != LC_LOAD_DYLIB) continue;
+
+ const dylib_command *dylib_lc = (const dylib_command *)lc;
+ uint32_t dylib_name_offset = dylib_lc->dylib.name.offset;
+ const char *dylib_name = ((const char *)dylib_lc) + dylib_name_offset;
+ dylib_name = StripModuleName(dylib_name);
+ if (dylib_name != 0 && (internal_strstr(dylib_name, "libclang_rt."))) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool MemoryMappingLayout::Next(MemoryMappedSegment *segment) {
+ for (; data_.current_image >= kDyldImageIdx; data_.current_image--) {
+ const mach_header *hdr = (data_.current_image == kDyldImageIdx)
+ ? get_dyld_hdr()
+ : _dyld_get_image_header(data_.current_image);
if (!hdr) continue;
- if (current_load_cmd_count_ < 0) {
+ if (data_.current_load_cmd_count < 0) {
// Set up for this image;
- current_load_cmd_count_ = hdr->ncmds;
- current_magic_ = hdr->magic;
- current_filetype_ = hdr->filetype;
- switch (current_magic_) {
+ data_.current_load_cmd_count = hdr->ncmds;
+ data_.current_magic = hdr->magic;
+ data_.current_filetype = hdr->filetype;
+ data_.current_arch = ModuleArchFromCpuType(hdr->cputype, hdr->cpusubtype);
+ switch (data_.current_magic) {
#ifdef MH_MAGIC_64
case MH_MAGIC_64: {
- current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header_64);
+ data_.current_load_cmd_addr = (char *)hdr + sizeof(mach_header_64);
break;
}
#endif
case MH_MAGIC: {
- current_load_cmd_addr_ = (char*)hdr + sizeof(mach_header);
+ data_.current_load_cmd_addr = (char *)hdr + sizeof(mach_header);
break;
}
default: {
continue;
}
}
+ FindUUID((const load_command *)data_.current_load_cmd_addr,
+ data_.current_uuid);
+ data_.current_instrumented = IsModuleInstrumented(
+ (const load_command *)data_.current_load_cmd_addr);
}
- for (; current_load_cmd_count_ >= 0; current_load_cmd_count_--) {
- switch (current_magic_) {
- // current_magic_ may be only one of MH_MAGIC, MH_MAGIC_64.
+ for (; data_.current_load_cmd_count >= 0; data_.current_load_cmd_count--) {
+ switch (data_.current_magic) {
+ // data_.current_magic may be only one of MH_MAGIC, MH_MAGIC_64.
#ifdef MH_MAGIC_64
case MH_MAGIC_64: {
if (NextSegmentLoad<LC_SEGMENT_64, struct segment_command_64>(
- start, end, offset, filename, filename_size, protection))
+ segment, segment->data_, data_))
return true;
break;
}
#endif
case MH_MAGIC: {
if (NextSegmentLoad<LC_SEGMENT, struct segment_command>(
- start, end, offset, filename, filename_size, protection))
+ segment, segment->data_, data_))
return true;
break;
}
@@ -154,26 +351,25 @@ bool MemoryMappingLayout::Next(uptr *start, uptr *end, uptr *offset,
}
void MemoryMappingLayout::DumpListOfModules(
- InternalMmapVector<LoadedModule> *modules) {
+ InternalMmapVectorNoCtor<LoadedModule> *modules) {
Reset();
- uptr cur_beg, cur_end, prot;
InternalScopedString module_name(kMaxPathLength);
- for (uptr i = 0; Next(&cur_beg, &cur_end, 0, module_name.data(),
- module_name.size(), &prot);
- i++) {
- const char *cur_name = module_name.data();
- if (cur_name[0] == '\0')
- continue;
+ MemoryMappedSegment segment(module_name.data(), kMaxPathLength);
+ MemoryMappedSegmentData data;
+ segment.data_ = &data;
+ while (Next(&segment)) {
+ if (segment.filename[0] == '\0') continue;
LoadedModule *cur_module = nullptr;
if (!modules->empty() &&
- 0 == internal_strcmp(cur_name, modules->back().full_name())) {
+ 0 == internal_strcmp(segment.filename, modules->back().full_name())) {
cur_module = &modules->back();
} else {
modules->push_back(LoadedModule());
cur_module = &modules->back();
- cur_module->set(cur_name, cur_beg);
+ cur_module->set(segment.filename, segment.start, segment.arch,
+ segment.uuid, data_.current_instrumented);
}
- cur_module->addAddressRange(cur_beg, cur_end, prot & kProtectionExecute);
+ segment.AddAddressRanges(cur_module);
}
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_quarantine.h b/libsanitizer/sanitizer_common/sanitizer_quarantine.h
index 9e9268f..a90c8e3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_quarantine.h
+++ b/libsanitizer/sanitizer_common/sanitizer_quarantine.h
@@ -29,6 +29,40 @@ struct QuarantineBatch {
uptr size;
uptr count;
void *batch[kSize];
+
+ void init(void *ptr, uptr size) {
+ count = 1;
+ batch[0] = ptr;
+ this->size = size + sizeof(QuarantineBatch); // Account for the batch size.
+ }
+
+ // The total size of quarantined nodes recorded in this batch.
+ uptr quarantined_size() const {
+ return size - sizeof(QuarantineBatch);
+ }
+
+ void push_back(void *ptr, uptr size) {
+ CHECK_LT(count, kSize);
+ batch[count++] = ptr;
+ this->size += size;
+ }
+
+ bool can_merge(const QuarantineBatch* const from) const {
+ return count + from->count <= kSize;
+ }
+
+ void merge(QuarantineBatch* const from) {
+ CHECK_LE(count + from->count, kSize);
+ CHECK_GE(size, sizeof(QuarantineBatch));
+
+ for (uptr i = 0; i < from->count; ++i)
+ batch[count + i] = from->batch[i];
+ count += from->count;
+ size += from->quarantined_size();
+
+ from->count = 0;
+ from->size = sizeof(QuarantineBatch);
+ }
};
COMPILER_CHECK(sizeof(QuarantineBatch) <= (1 << 13)); // 8Kb.
@@ -47,17 +81,31 @@ class Quarantine {
}
void Init(uptr size, uptr cache_size) {
- atomic_store(&max_size_, size, memory_order_release);
+ // Thread local quarantine size can be zero only when global quarantine size
+ // is zero (it allows us to perform just one atomic read per Put() call).
+ CHECK((size == 0 && cache_size == 0) || cache_size != 0);
+
+ atomic_store(&max_size_, size, memory_order_relaxed);
atomic_store(&min_size_, size / 10 * 9,
- memory_order_release); // 90% of max size.
- max_cache_size_ = cache_size;
+ memory_order_relaxed); // 90% of max size.
+ atomic_store(&max_cache_size_, cache_size, memory_order_relaxed);
}
- uptr GetSize() const { return atomic_load(&max_size_, memory_order_acquire); }
+ uptr GetSize() const { return atomic_load(&max_size_, memory_order_relaxed); }
+ uptr GetCacheSize() const {
+ return atomic_load(&max_cache_size_, memory_order_relaxed);
+ }
void Put(Cache *c, Callback cb, Node *ptr, uptr size) {
- c->Enqueue(cb, ptr, size);
- if (c->Size() > max_cache_size_)
+ uptr cache_size = GetCacheSize();
+ if (cache_size) {
+ c->Enqueue(cb, ptr, size);
+ } else {
+ // GetCacheSize() == 0 only when GetSize() == 0 (see Init).
+ cb.Recycle(ptr);
+ }
+ // Check cache size anyway to accommodate for runtime cache_size change.
+ if (c->Size() > cache_size)
Drain(c, cb);
}
@@ -70,12 +118,19 @@ class Quarantine {
Recycle(cb);
}
+ void PrintStats() const {
+ // It assumes that the world is stopped, just as the allocator's PrintStats.
+ Printf("Quarantine limits: global: %zdMb; thread local: %zdKb\n",
+ GetSize() >> 20, GetCacheSize() >> 10);
+ cache_.PrintStats();
+ }
+
private:
// Read-only data.
char pad0_[kCacheLineSize];
atomic_uintptr_t max_size_;
atomic_uintptr_t min_size_;
- uptr max_cache_size_;
+ atomic_uintptr_t max_cache_size_;
char pad1_[kCacheLineSize];
SpinMutex cache_mutex_;
SpinMutex recycle_mutex_;
@@ -84,12 +139,30 @@ class Quarantine {
void NOINLINE Recycle(Callback cb) {
Cache tmp;
- uptr min_size = atomic_load(&min_size_, memory_order_acquire);
+ uptr min_size = atomic_load(&min_size_, memory_order_relaxed);
{
SpinMutexLock l(&cache_mutex_);
+ // Go over the batches and merge partially filled ones to
+ // save some memory, otherwise batches themselves (since the memory used
+ // by them is counted against quarantine limit) can overcome the actual
+ // user's quarantined chunks, which diminishes the purpose of the
+ // quarantine.
+ uptr cache_size = cache_.Size();
+ uptr overhead_size = cache_.OverheadSize();
+ CHECK_GE(cache_size, overhead_size);
+ // Do the merge only when overhead exceeds this predefined limit (might
+ // require some tuning). It saves us merge attempt when the batch list
+ // quarantine is unlikely to contain batches suitable for merge.
+ const uptr kOverheadThresholdPercents = 100;
+ if (cache_size > overhead_size &&
+ overhead_size * (100 + kOverheadThresholdPercents) >
+ cache_size * kOverheadThresholdPercents) {
+ cache_.MergeBatches(&tmp);
+ }
+ // Extract enough chunks from the quarantine to get below the max
+ // quarantine size and leave some leeway for the newly quarantined chunks.
while (cache_.Size() > min_size) {
- QuarantineBatch *b = cache_.DequeueBatch();
- tmp.EnqueueBatch(b);
+ tmp.EnqueueBatch(cache_.DequeueBatch());
}
}
recycle_mutex_.Unlock();
@@ -124,26 +197,33 @@ class QuarantineCache {
list_.clear();
}
+ // Total memory used, including internal accounting.
uptr Size() const {
return atomic_load(&size_, memory_order_relaxed);
}
+ // Memory used for internal accounting.
+ uptr OverheadSize() const {
+ return list_.size() * sizeof(QuarantineBatch);
+ }
+
void Enqueue(Callback cb, void *ptr, uptr size) {
if (list_.empty() || list_.back()->count == QuarantineBatch::kSize) {
- AllocBatch(cb);
- size += sizeof(QuarantineBatch); // Count the batch in Quarantine size.
+ QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b));
+ CHECK(b);
+ b->init(ptr, size);
+ EnqueueBatch(b);
+ } else {
+ list_.back()->push_back(ptr, size);
+ SizeAdd(size);
}
- QuarantineBatch *b = list_.back();
- CHECK(b);
- b->batch[b->count++] = ptr;
- b->size += size;
- SizeAdd(size);
}
- void Transfer(QuarantineCache *c) {
- list_.append_back(&c->list_);
- SizeAdd(c->Size());
- atomic_store(&c->size_, 0, memory_order_relaxed);
+ void Transfer(QuarantineCache *from_cache) {
+ list_.append_back(&from_cache->list_);
+ SizeAdd(from_cache->Size());
+
+ atomic_store(&from_cache->size_, 0, memory_order_relaxed);
}
void EnqueueBatch(QuarantineBatch *b) {
@@ -160,8 +240,57 @@ class QuarantineCache {
return b;
}
+ void MergeBatches(QuarantineCache *to_deallocate) {
+ uptr extracted_size = 0;
+ QuarantineBatch *current = list_.front();
+ while (current && current->next) {
+ if (current->can_merge(current->next)) {
+ QuarantineBatch *extracted = current->next;
+ // Move all the chunks into the current batch.
+ current->merge(extracted);
+ CHECK_EQ(extracted->count, 0);
+ CHECK_EQ(extracted->size, sizeof(QuarantineBatch));
+ // Remove the next batch from the list and account for its size.
+ list_.extract(current, extracted);
+ extracted_size += extracted->size;
+ // Add it to deallocation list.
+ to_deallocate->EnqueueBatch(extracted);
+ } else {
+ current = current->next;
+ }
+ }
+ SizeSub(extracted_size);
+ }
+
+ void PrintStats() const {
+ uptr batch_count = 0;
+ uptr total_overhead_bytes = 0;
+ uptr total_bytes = 0;
+ uptr total_quarantine_chunks = 0;
+ for (List::ConstIterator it = list_.begin(); it != list_.end(); ++it) {
+ batch_count++;
+ total_bytes += (*it).size;
+ total_overhead_bytes += (*it).size - (*it).quarantined_size();
+ total_quarantine_chunks += (*it).count;
+ }
+ uptr quarantine_chunks_capacity = batch_count * QuarantineBatch::kSize;
+ int chunks_usage_percent = quarantine_chunks_capacity == 0 ?
+ 0 : total_quarantine_chunks * 100 / quarantine_chunks_capacity;
+ uptr total_quarantined_bytes = total_bytes - total_overhead_bytes;
+ int memory_overhead_percent = total_quarantined_bytes == 0 ?
+ 0 : total_overhead_bytes * 100 / total_quarantined_bytes;
+ Printf("Global quarantine stats: batches: %zd; bytes: %zd (user: %zd); "
+ "chunks: %zd (capacity: %zd); %d%% chunks used; %d%% memory overhead"
+ "\n",
+ batch_count, total_bytes, total_quarantined_bytes,
+ total_quarantine_chunks, quarantine_chunks_capacity,
+ chunks_usage_percent, memory_overhead_percent);
+ }
+
private:
- IntrusiveList<QuarantineBatch> list_;
+ typedef IntrusiveList<QuarantineBatch> List;
+
+ List list_;
atomic_uintptr_t size_;
void SizeAdd(uptr add) {
@@ -170,16 +299,8 @@ class QuarantineCache {
void SizeSub(uptr sub) {
atomic_store(&size_, Size() - sub, memory_order_relaxed);
}
-
- NOINLINE QuarantineBatch* AllocBatch(Callback cb) {
- QuarantineBatch *b = (QuarantineBatch *)cb.Allocate(sizeof(*b));
- CHECK(b);
- b->count = 0;
- b->size = 0;
- list_.push_back(b);
- return b;
- }
};
+
} // namespace __sanitizer
#endif // SANITIZER_QUARANTINE_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_report_decorator.h b/libsanitizer/sanitizer_common/sanitizer_report_decorator.h
index e9be29f..c0edfcf 100644
--- a/libsanitizer/sanitizer_common/sanitizer_report_decorator.h
+++ b/libsanitizer/sanitizer_common/sanitizer_report_decorator.h
@@ -25,8 +25,9 @@ class SanitizerCommonDecorator {
SanitizerCommonDecorator() : ansi_(ColorizeReports()) {}
const char *Bold() const { return ansi_ ? "\033[1m" : ""; }
const char *Default() const { return ansi_ ? "\033[1m\033[0m" : ""; }
- const char *Warning() { return Red(); }
- const char *EndWarning() { return Default(); }
+ const char *Warning() const { return Red(); }
+ const char *MemoryByte() { return Magenta(); }
+
protected:
const char *Black() const { return ansi_ ? "\033[1m\033[30m" : ""; }
const char *Red() const { return ansi_ ? "\033[1m\033[31m" : ""; }
diff --git a/libsanitizer/sanitizer_common/sanitizer_signal_interceptors.inc b/libsanitizer/sanitizer_common/sanitizer_signal_interceptors.inc
new file mode 100644
index 0000000..b278f82
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_signal_interceptors.inc
@@ -0,0 +1,65 @@
+//===-- sanitizer_signal_interceptors.inc -----------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Signal interceptors for sanitizers.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "sanitizer_common.h"
+#include "sanitizer_internal_defs.h"
+#include "sanitizer_platform_interceptors.h"
+
+using namespace __sanitizer;
+
+#if SANITIZER_INTERCEPT_BSD_SIGNAL
+INTERCEPTOR(void *, bsd_signal, int signum, void *handler) {
+ if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0;
+ return REAL(bsd_signal)(signum, handler);
+}
+#define INIT_BSD_SIGNAL COMMON_INTERCEPT_FUNCTION(bsd_signal)
+#else // SANITIZER_INTERCEPT_BSD_SIGNAL
+#define INIT_BSD_SIGNAL
+#endif // SANITIZER_INTERCEPT_BSD_SIGNAL
+
+#if SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION
+INTERCEPTOR(void *, signal, int signum, void *handler) {
+ if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return nullptr;
+ return REAL(signal)(signum, handler);
+}
+#define INIT_SIGNAL COMMON_INTERCEPT_FUNCTION(signal)
+
+INTERCEPTOR(int, sigaction, int signum, const struct sigaction *act,
+ struct sigaction *oldact) {
+ if (GetHandleSignalMode(signum) == kHandleSignalExclusive) return 0;
+ return REAL(sigaction)(signum, act, oldact);
+}
+#define INIT_SIGACTION COMMON_INTERCEPT_FUNCTION(sigaction)
+
+namespace __sanitizer {
+int real_sigaction(int signum, const void *act, void *oldact) {
+ return REAL(sigaction)(signum, (const struct sigaction *)act,
+ (struct sigaction *)oldact);
+}
+} // namespace __sanitizer
+#else // SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION
+#define INIT_SIGNAL
+#define INIT_SIGACTION
+// We need to have defined REAL(sigaction) on other systems.
+DEFINE_REAL(int, sigaction, int signum, const struct sigaction *act,
+ struct sigaction *oldact)
+#endif // SANITIZER_INTERCEPT_SIGNAL_AND_SIGACTION
+
+static void InitializeSignalInterceptors() {
+ static bool was_called_once;
+ CHECK(!was_called_once);
+ was_called_once = true;
+
+ INIT_BSD_SIGNAL;
+ INIT_SIGNAL;
+ INIT_SIGACTION;
+}
diff --git a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc
index 3c5313c..816a35c 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stackdepot.cc
@@ -151,9 +151,9 @@ StackTrace StackDepotReverseMap::Get(u32 id) {
if (!map_.size())
return StackTrace();
IdDescPair pair = {id, nullptr};
- uptr idx = InternalBinarySearch(map_, 0, map_.size(), pair,
- IdDescPair::IdComparator);
- if (idx > map_.size())
+ uptr idx =
+ InternalLowerBound(map_, 0, map_.size(), pair, IdDescPair::IdComparator);
+ if (idx > map_.size() || map_[idx].id != id)
return StackTrace();
return map_[idx].desc->load();
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
index cbb3af2..83309d6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.cc
@@ -104,10 +104,6 @@ void BufferedStackTrace::FastUnwindStack(uptr pc, uptr bp, uptr stack_top,
}
}
-static bool MatchPc(uptr cur_pc, uptr trace_pc, uptr threshold) {
- return cur_pc - trace_pc <= threshold || trace_pc - cur_pc <= threshold;
-}
-
void BufferedStackTrace::PopStackFrames(uptr count) {
CHECK_LT(count, size);
size -= count;
@@ -116,15 +112,14 @@ void BufferedStackTrace::PopStackFrames(uptr count) {
}
}
+static uptr Distance(uptr a, uptr b) { return a < b ? b - a : a - b; }
+
uptr BufferedStackTrace::LocatePcInTrace(uptr pc) {
- // Use threshold to find PC in stack trace, as PC we want to unwind from may
- // slightly differ from return address in the actual unwinded stack trace.
- const int kPcThreshold = 350;
- for (uptr i = 0; i < size; ++i) {
- if (MatchPc(pc, trace[i], kPcThreshold))
- return i;
+ uptr best = 0;
+ for (uptr i = 1; i < size; ++i) {
+ if (Distance(trace[i], pc) < Distance(trace[best], pc)) best = i;
}
- return 0;
+ return best;
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
index c59dbd5..31e99f6 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace.h
@@ -95,6 +95,11 @@ struct BufferedStackTrace : public StackTrace {
void Unwind(u32 max_depth, uptr pc, uptr bp, void *context, uptr stack_top,
uptr stack_bottom, bool request_fast_unwind);
+ void Reset() {
+ *static_cast<StackTrace *>(this) = StackTrace(trace_buffer, 0);
+ top_frame_bp = 0;
+ }
+
private:
void FastUnwindStack(uptr pc, uptr bp, uptr stack_top, uptr stack_bottom,
u32 max_depth);
@@ -104,8 +109,8 @@ struct BufferedStackTrace : public StackTrace {
void PopStackFrames(uptr count);
uptr LocatePcInTrace(uptr pc);
- BufferedStackTrace(const BufferedStackTrace &);
- void operator=(const BufferedStackTrace &);
+ BufferedStackTrace(const BufferedStackTrace &) = delete;
+ void operator=(const BufferedStackTrace &) = delete;
};
// Check if given pointer points into allocated stack area.
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
index ac3ee3a..f4c0f31 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_libcdep.cc
@@ -41,7 +41,8 @@ void StackTrace::Print() const {
if (dedup_frames-- > 0) {
if (dedup_token.length())
dedup_token.append("--");
- dedup_token.append(cur->info.function);
+ if (cur->info.function != nullptr)
+ dedup_token.append(cur->info.function);
}
}
frames->ClearAll();
@@ -80,6 +81,21 @@ void BufferedStackTrace::Unwind(u32 max_depth, uptr pc, uptr bp, void *context,
}
}
+static int GetModuleAndOffsetForPc(uptr pc, char *module_name,
+ uptr module_name_len, uptr *pc_offset) {
+ const char *found_module_name = nullptr;
+ bool ok = Symbolizer::GetOrInit()->GetModuleNameAndOffsetForPC(
+ pc, &found_module_name, pc_offset);
+
+ if (!ok) return false;
+
+ if (module_name && module_name_len) {
+ internal_strncpy(module_name, found_module_name, module_name_len);
+ module_name[module_name_len - 1] = '\x00';
+ }
+ return true;
+}
+
} // namespace __sanitizer
using namespace __sanitizer;
@@ -115,4 +131,11 @@ void __sanitizer_symbolize_global(uptr data_addr, const char *fmt,
internal_strncpy(out_buf, data_desc.data(), out_buf_size);
out_buf[out_buf_size - 1] = 0;
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __sanitizer_get_module_and_offset_for_pc( // NOLINT
+ uptr pc, char *module_name, uptr module_name_len, uptr *pc_offset) {
+ return __sanitizer::GetModuleAndOffsetForPc(pc, module_name, module_name_len,
+ pc_offset);
+}
} // extern "C"
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc
index de78c7a..3c5bed3 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.cc
@@ -10,9 +10,14 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_stacktrace_printer.h"
+#include "sanitizer_file.h"
+#include "sanitizer_fuchsia.h"
namespace __sanitizer {
+// sanitizer_symbolizer_fuchsia.cc implements these differently for Fuchsia.
+#if !SANITIZER_FUCHSIA
+
static const char *StripFunctionName(const char *function, const char *prefix) {
if (!function) return nullptr;
if (!prefix) return function;
@@ -91,7 +96,7 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
vs_style, strip_path_prefix);
} else if (info.module) {
RenderModuleLocation(buffer, info.module, info.module_offset,
- strip_path_prefix);
+ info.module_arch, strip_path_prefix);
} else {
buffer->append("(<unknown module>)");
}
@@ -101,8 +106,9 @@ void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
if (info.address & kExternalPCBit)
{} // There PCs are not meaningful.
else if (info.module)
- buffer->append("(%s+%p)", StripModuleName(info.module),
- (void *)info.module_offset);
+ // Always strip the module name for %M.
+ RenderModuleLocation(buffer, StripModuleName(info.module),
+ info.module_offset, info.module_arch, "");
else
buffer->append("(%p)", (void *)info.address);
break;
@@ -143,6 +149,8 @@ void RenderData(InternalScopedString *buffer, const char *format,
}
}
+#endif // !SANITIZER_FUCHSIA
+
void RenderSourceLocation(InternalScopedString *buffer, const char *file,
int line, int column, bool vs_style,
const char *strip_path_prefix) {
@@ -163,9 +171,13 @@ void RenderSourceLocation(InternalScopedString *buffer, const char *file,
}
void RenderModuleLocation(InternalScopedString *buffer, const char *module,
- uptr offset, const char *strip_path_prefix) {
- buffer->append("(%s+0x%zx)", StripPathPrefix(module, strip_path_prefix),
- offset);
+ uptr offset, ModuleArch arch,
+ const char *strip_path_prefix) {
+ buffer->append("(%s", StripPathPrefix(module, strip_path_prefix));
+ if (arch != kModuleArchUnknown) {
+ buffer->append(":%s", ModuleArchToString(arch));
+ }
+ buffer->append("+0x%zx)", offset);
}
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
index 6726f14..cf3cd42 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stacktrace_printer.h
@@ -55,7 +55,8 @@ void RenderSourceLocation(InternalScopedString *buffer, const char *file,
const char *strip_path_prefix);
void RenderModuleLocation(InternalScopedString *buffer, const char *module,
- uptr offset, const char *strip_path_prefix);
+ uptr offset, ModuleArch arch,
+ const char *strip_path_prefix);
// Same as RenderFrame, but for data section (global variables).
// Accepts %s, %l from above.
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h b/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h
index c324526..8c3d2c0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld.h
@@ -16,36 +16,32 @@
#include "sanitizer_common.h"
namespace __sanitizer {
-typedef int SuspendedThreadID;
+
+enum PtraceRegistersStatus {
+ REGISTERS_UNAVAILABLE_FATAL = -1,
+ REGISTERS_UNAVAILABLE = 0,
+ REGISTERS_AVAILABLE = 1
+};
// Holds the list of suspended threads and provides an interface to dump their
// register contexts.
class SuspendedThreadsList {
public:
- SuspendedThreadsList()
- : thread_ids_(1024) {}
- SuspendedThreadID GetThreadID(uptr index) const {
- CHECK_LT(index, thread_ids_.size());
- return thread_ids_[index];
+ SuspendedThreadsList() = default;
+
+ // Can't declare pure virtual functions in sanitizer runtimes:
+ // __cxa_pure_virtual might be unavailable. Use UNIMPLEMENTED() instead.
+ virtual PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
+ uptr *sp) const {
+ UNIMPLEMENTED();
}
- int GetRegistersAndSP(uptr index, uptr *buffer, uptr *sp) const;
+
// The buffer in GetRegistersAndSP should be at least this big.
- static uptr RegisterCount();
- uptr thread_count() const { return thread_ids_.size(); }
- bool Contains(SuspendedThreadID thread_id) const {
- for (uptr i = 0; i < thread_ids_.size(); i++) {
- if (thread_ids_[i] == thread_id)
- return true;
- }
- return false;
- }
- void Append(SuspendedThreadID thread_id) {
- thread_ids_.push_back(thread_id);
- }
+ virtual uptr RegisterCount() const { UNIMPLEMENTED(); }
+ virtual uptr ThreadCount() const { UNIMPLEMENTED(); }
+ virtual tid_t GetThreadID(uptr index) const { UNIMPLEMENTED(); }
private:
- InternalMmapVector<SuspendedThreadID> thread_ids_;
-
// Prohibit copy and assign.
SuspendedThreadsList(const SuspendedThreadsList&);
void operator=(const SuspendedThreadsList&);
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
index 234e8c6..d746fa5 100644
--- a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cc
@@ -14,7 +14,8 @@
#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \
defined(__aarch64__) || defined(__powerpc64__) || \
- defined(__s390__))
+ defined(__s390__) || defined(__i386__) || \
+ defined(__arm__))
#include "sanitizer_stoptheworld.h"
@@ -29,17 +30,13 @@
#include <sys/types.h> // for pid_t
#include <sys/uio.h> // for iovec
#include <elf.h> // for NT_PRSTATUS
-#if SANITIZER_ANDROID && defined(__arm__)
-# include <linux/user.h> // for pt_regs
-#else
-# ifdef __aarch64__
+#if defined(__aarch64__) && !SANITIZER_ANDROID
// GLIBC 2.20+ sys/user does not include asm/ptrace.h
-# include <asm/ptrace.h>
-# endif
-# include <sys/user.h> // for user_regs_struct
-# if SANITIZER_ANDROID && SANITIZER_MIPS
-# include <asm/reg.h> // for mips SP register in sys/user.h
-# endif
+# include <asm/ptrace.h>
+#endif
+#include <sys/user.h> // for user_regs_struct
+#if SANITIZER_ANDROID && SANITIZER_MIPS
+# include <asm/reg.h> // for mips SP register in sys/user.h
#endif
#include <sys/wait.h> // for signal-related stuff
@@ -79,7 +76,22 @@
namespace __sanitizer {
-COMPILER_CHECK(sizeof(SuspendedThreadID) == sizeof(pid_t));
+class SuspendedThreadsListLinux : public SuspendedThreadsList {
+ public:
+ SuspendedThreadsListLinux() : thread_ids_(1024) {}
+
+ tid_t GetThreadID(uptr index) const;
+ uptr ThreadCount() const;
+ bool ContainsTid(tid_t thread_id) const;
+ void Append(tid_t tid);
+
+ PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
+ uptr *sp) const;
+ uptr RegisterCount() const;
+
+ private:
+ InternalMmapVector<tid_t> thread_ids_;
+};
// Structure for passing arguments into the tracer thread.
struct TracerThreadArgument {
@@ -104,31 +116,31 @@ class ThreadSuspender {
bool SuspendAllThreads();
void ResumeAllThreads();
void KillAllThreads();
- SuspendedThreadsList &suspended_threads_list() {
+ SuspendedThreadsListLinux &suspended_threads_list() {
return suspended_threads_list_;
}
TracerThreadArgument *arg;
private:
- SuspendedThreadsList suspended_threads_list_;
+ SuspendedThreadsListLinux suspended_threads_list_;
pid_t pid_;
- bool SuspendThread(SuspendedThreadID thread_id);
+ bool SuspendThread(tid_t thread_id);
};
-bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) {
+bool ThreadSuspender::SuspendThread(tid_t tid) {
// Are we already attached to this thread?
// Currently this check takes linear time, however the number of threads is
// usually small.
- if (suspended_threads_list_.Contains(tid))
- return false;
+ if (suspended_threads_list_.ContainsTid(tid)) return false;
int pterrno;
if (internal_iserror(internal_ptrace(PTRACE_ATTACH, tid, nullptr, nullptr),
&pterrno)) {
// Either the thread is dead, or something prevented us from attaching.
// Log this event and move on.
- VReport(1, "Could not attach to thread %d (errno %d).\n", tid, pterrno);
+ VReport(1, "Could not attach to thread %zu (errno %d).\n", (uptr)tid,
+ pterrno);
return false;
} else {
- VReport(2, "Attached to thread %d.\n", tid);
+ VReport(2, "Attached to thread %zu.\n", (uptr)tid);
// The thread is not guaranteed to stop before ptrace returns, so we must
// wait on it. Note: if the thread receives a signal concurrently,
// we can get notification about the signal before notification about stop.
@@ -146,8 +158,8 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) {
if (internal_iserror(waitpid_status, &wperrno)) {
// Got a ECHILD error. I don't think this situation is possible, but it
// doesn't hurt to report it.
- VReport(1, "Waiting on thread %d failed, detaching (errno %d).\n",
- tid, wperrno);
+ VReport(1, "Waiting on thread %zu failed, detaching (errno %d).\n",
+ (uptr)tid, wperrno);
internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr);
return false;
}
@@ -164,7 +176,7 @@ bool ThreadSuspender::SuspendThread(SuspendedThreadID tid) {
}
void ThreadSuspender::ResumeAllThreads() {
- for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++) {
+ for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++) {
pid_t tid = suspended_threads_list_.GetThreadID(i);
int pterrno;
if (!internal_iserror(internal_ptrace(PTRACE_DETACH, tid, nullptr, nullptr),
@@ -180,7 +192,7 @@ void ThreadSuspender::ResumeAllThreads() {
}
void ThreadSuspender::KillAllThreads() {
- for (uptr i = 0; i < suspended_threads_list_.thread_count(); i++)
+ for (uptr i = 0; i < suspended_threads_list_.ThreadCount(); i++)
internal_ptrace(PTRACE_KILL, suspended_threads_list_.GetThreadID(i),
nullptr, nullptr);
}
@@ -232,7 +244,7 @@ static void TracerThreadDieCallback() {
// Signal handler to wake up suspended threads when the tracer thread dies.
static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) {
- SignalContext ctx = SignalContext::Create(siginfo, uctx);
+ SignalContext ctx(siginfo, uctx);
Printf("Tracer caught signal %d: addr=0x%zx pc=0x%zx sp=0x%zx\n", signum,
ctx.addr, ctx.pc, ctx.sp);
ThreadSuspender *inst = thread_suspender_instance;
@@ -249,7 +261,7 @@ static void TracerThreadSignalHandler(int signum, void *siginfo, void *uctx) {
}
// Size of alternative stack for signal handlers in the tracer thread.
-static const int kHandlerStackSize = 4096;
+static const int kHandlerStackSize = 8192;
// This function will be run as a cloned task.
static int TracerThread(void* argument) {
@@ -491,9 +503,28 @@ typedef _user_regs_struct regs_struct;
#error "Unsupported architecture"
#endif // SANITIZER_ANDROID && defined(__arm__)
-int SuspendedThreadsList::GetRegistersAndSP(uptr index,
- uptr *buffer,
- uptr *sp) const {
+tid_t SuspendedThreadsListLinux::GetThreadID(uptr index) const {
+ CHECK_LT(index, thread_ids_.size());
+ return thread_ids_[index];
+}
+
+uptr SuspendedThreadsListLinux::ThreadCount() const {
+ return thread_ids_.size();
+}
+
+bool SuspendedThreadsListLinux::ContainsTid(tid_t thread_id) const {
+ for (uptr i = 0; i < thread_ids_.size(); i++) {
+ if (thread_ids_[i] == thread_id) return true;
+ }
+ return false;
+}
+
+void SuspendedThreadsListLinux::Append(tid_t tid) {
+ thread_ids_.push_back(tid);
+}
+
+PtraceRegistersStatus SuspendedThreadsListLinux::GetRegistersAndSP(
+ uptr index, uptr *buffer, uptr *sp) const {
pid_t tid = GetThreadID(index);
regs_struct regs;
int pterrno;
@@ -511,19 +542,23 @@ int SuspendedThreadsList::GetRegistersAndSP(uptr index,
if (isErr) {
VReport(1, "Could not get registers from thread %d (errno %d).\n", tid,
pterrno);
- return -1;
+ // ESRCH means that the given thread is not suspended or already dead.
+ // Therefore it's unsafe to inspect its data (e.g. walk through stack) and
+ // we should notify caller about this.
+ return pterrno == ESRCH ? REGISTERS_UNAVAILABLE_FATAL
+ : REGISTERS_UNAVAILABLE;
}
*sp = regs.REG_SP;
internal_memcpy(buffer, &regs, sizeof(regs));
- return 0;
+ return REGISTERS_AVAILABLE;
}
-uptr SuspendedThreadsList::RegisterCount() {
+uptr SuspendedThreadsListLinux::RegisterCount() const {
return sizeof(regs_struct) / sizeof(uptr);
}
} // namespace __sanitizer
#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
// || defined(__aarch64__) || defined(__powerpc64__)
- // || defined(__s390__)
+ // || defined(__s390__) || defined(__i386__) || defined(__arm__)
diff --git a/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cc b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cc
new file mode 100644
index 0000000..6282694
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_stoptheworld_mac.cc
@@ -0,0 +1,176 @@
+//===-- sanitizer_stoptheworld_mac.cc -------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// See sanitizer_stoptheworld.h for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+
+#if SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__) || \
+ defined(__i386))
+
+#include <mach/mach.h>
+#include <mach/thread_info.h>
+#include <pthread.h>
+
+#include "sanitizer_stoptheworld.h"
+
+namespace __sanitizer {
+typedef struct {
+ tid_t tid;
+ thread_t thread;
+} SuspendedThreadInfo;
+
+class SuspendedThreadsListMac : public SuspendedThreadsList {
+ public:
+ SuspendedThreadsListMac() : threads_(1024) {}
+
+ tid_t GetThreadID(uptr index) const;
+ thread_t GetThread(uptr index) const;
+ uptr ThreadCount() const;
+ bool ContainsThread(thread_t thread) const;
+ void Append(thread_t thread);
+
+ PtraceRegistersStatus GetRegistersAndSP(uptr index, uptr *buffer,
+ uptr *sp) const;
+ uptr RegisterCount() const;
+
+ private:
+ InternalMmapVector<SuspendedThreadInfo> threads_;
+};
+
+struct RunThreadArgs {
+ StopTheWorldCallback callback;
+ void *argument;
+};
+
+void RunThread(void *arg) {
+ struct RunThreadArgs *run_args = (struct RunThreadArgs *)arg;
+ SuspendedThreadsListMac suspended_threads_list;
+
+ thread_array_t threads;
+ mach_msg_type_number_t num_threads;
+ kern_return_t err = task_threads(mach_task_self(), &threads, &num_threads);
+ if (err != KERN_SUCCESS) {
+ VReport(1, "Failed to get threads for task (errno %d).\n", err);
+ return;
+ }
+
+ thread_t thread_self = mach_thread_self();
+ for (unsigned int i = 0; i < num_threads; ++i) {
+ if (threads[i] == thread_self) continue;
+
+ thread_suspend(threads[i]);
+ suspended_threads_list.Append(threads[i]);
+ }
+
+ run_args->callback(suspended_threads_list, run_args->argument);
+
+ uptr num_suspended = suspended_threads_list.ThreadCount();
+ for (unsigned int i = 0; i < num_suspended; ++i) {
+ thread_resume(suspended_threads_list.GetThread(i));
+ }
+}
+
+void StopTheWorld(StopTheWorldCallback callback, void *argument) {
+ struct RunThreadArgs arg = {callback, argument};
+ pthread_t run_thread = (pthread_t)internal_start_thread(RunThread, &arg);
+ internal_join_thread(run_thread);
+}
+
+#if defined(__x86_64__)
+typedef x86_thread_state64_t regs_struct;
+
+#define SP_REG __rsp
+
+#elif defined(__aarch64__)
+typedef arm_thread_state64_t regs_struct;
+
+# if __DARWIN_UNIX03
+# define SP_REG __sp
+# else
+# define SP_REG sp
+# endif
+
+#elif defined(__i386)
+typedef x86_thread_state32_t regs_struct;
+
+#define SP_REG __esp
+
+#else
+#error "Unsupported architecture"
+#endif
+
+tid_t SuspendedThreadsListMac::GetThreadID(uptr index) const {
+ CHECK_LT(index, threads_.size());
+ return threads_[index].tid;
+}
+
+thread_t SuspendedThreadsListMac::GetThread(uptr index) const {
+ CHECK_LT(index, threads_.size());
+ return threads_[index].thread;
+}
+
+uptr SuspendedThreadsListMac::ThreadCount() const {
+ return threads_.size();
+}
+
+bool SuspendedThreadsListMac::ContainsThread(thread_t thread) const {
+ for (uptr i = 0; i < threads_.size(); i++) {
+ if (threads_[i].thread == thread) return true;
+ }
+ return false;
+}
+
+void SuspendedThreadsListMac::Append(thread_t thread) {
+ thread_identifier_info_data_t info;
+ mach_msg_type_number_t info_count = THREAD_IDENTIFIER_INFO_COUNT;
+ kern_return_t err = thread_info(thread, THREAD_IDENTIFIER_INFO,
+ (thread_info_t)&info, &info_count);
+ if (err != KERN_SUCCESS) {
+ VReport(1, "Error - unable to get thread ident for a thread\n");
+ return;
+ }
+ threads_.push_back({info.thread_id, thread});
+}
+
+PtraceRegistersStatus SuspendedThreadsListMac::GetRegistersAndSP(
+ uptr index, uptr *buffer, uptr *sp) const {
+ thread_t thread = GetThread(index);
+ regs_struct regs;
+ int err;
+ mach_msg_type_number_t reg_count = MACHINE_THREAD_STATE_COUNT;
+ err = thread_get_state(thread, MACHINE_THREAD_STATE, (thread_state_t)&regs,
+ &reg_count);
+ if (err != KERN_SUCCESS) {
+ VReport(1, "Error - unable to get registers for a thread\n");
+ // KERN_INVALID_ARGUMENT indicates that either the flavor is invalid,
+ // or the thread does not exist. The other possible error case,
+ // MIG_ARRAY_TOO_LARGE, means that the state is too large, but it's
+ // still safe to proceed.
+ return err == KERN_INVALID_ARGUMENT ? REGISTERS_UNAVAILABLE_FATAL
+ : REGISTERS_UNAVAILABLE;
+ }
+
+ internal_memcpy(buffer, &regs, sizeof(regs));
+ *sp = regs.SP_REG;
+
+ // On x86_64 and aarch64, we must account for the stack redzone, which is 128
+ // bytes.
+ if (SANITIZER_WORDSIZE == 64) *sp -= 128;
+
+ return REGISTERS_AVAILABLE;
+}
+
+uptr SuspendedThreadsListMac::RegisterCount() const {
+ return MACHINE_THREAD_STATE_COUNT;
+}
+} // namespace __sanitizer
+
+#endif // SANITIZER_MAC && (defined(__x86_64__) || defined(__aarch64__)) ||
+ // defined(__i386))
diff --git a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
index bfdff59..4095a09 100644
--- a/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_suppressions.cc
@@ -14,6 +14,7 @@
#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
#include "sanitizer_flags.h"
+#include "sanitizer_file.h"
#include "sanitizer_libc.h"
#include "sanitizer_placement_new.h"
@@ -48,6 +49,7 @@ void SuppressionContext::ParseFromFile(const char *filename) {
if (filename[0] == '\0')
return;
+#if !SANITIZER_FUCHSIA
// If we cannot find the file, check if its location is relative to
// the location of the executable.
InternalScopedString new_file_path(kMaxPathLength);
@@ -56,6 +58,7 @@ void SuppressionContext::ParseFromFile(const char *filename) {
new_file_path.size())) {
filename = new_file_path.data();
}
+#endif // !SANITIZER_FUCHSIA
// Read the file.
VPrintf(1, "%s: reading suppressions file at %s\n",
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
index 3557415..9d3e011 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.cc
@@ -31,9 +31,11 @@ void AddressInfo::Clear() {
function_offset = kUnknown;
}
-void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset) {
+void AddressInfo::FillModuleInfo(const char *mod_name, uptr mod_offset,
+ ModuleArch mod_arch) {
module = internal_strdup(mod_name);
module_offset = mod_offset;
+ module_arch = mod_arch;
}
SymbolizedStack::SymbolizedStack() : next(nullptr), info() {}
@@ -67,6 +69,10 @@ Symbolizer *Symbolizer::symbolizer_;
StaticSpinMutex Symbolizer::init_mu_;
LowLevelAllocator Symbolizer::symbolizer_allocator_;
+void Symbolizer::InvalidateModuleList() {
+ modules_fresh_ = false;
+}
+
void Symbolizer::AddHooks(Symbolizer::StartSymbolizationHook start_hook,
Symbolizer::EndSymbolizationHook end_hook) {
CHECK(start_hook_ == 0 && end_hook_ == 0);
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
index 2b90b42..5e2c843 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer.h
@@ -29,6 +29,7 @@ struct AddressInfo {
char *module;
uptr module_offset;
+ ModuleArch module_arch;
static const uptr kUnknown = ~(uptr)0;
char *function;
@@ -41,7 +42,7 @@ struct AddressInfo {
AddressInfo();
// Deletes all strings and resets all fields.
void Clear();
- void FillModuleInfo(const char *mod_name, uptr mod_offset);
+ void FillModuleInfo(const char *mod_name, uptr mod_offset, ModuleArch arch);
};
// Linked list of symbolized frames (each frame is described by AddressInfo).
@@ -63,6 +64,8 @@ struct DataInfo {
// (de)allocated using sanitizer internal allocator.
char *module;
uptr module_offset;
+ ModuleArch module_arch;
+
char *file;
uptr line;
char *name;
@@ -114,8 +117,11 @@ class Symbolizer final {
void AddHooks(StartSymbolizationHook start_hook,
EndSymbolizationHook end_hook);
+ void RefreshModules();
const LoadedModule *FindModuleForAddress(uptr address);
+ void InvalidateModuleList();
+
private:
// GetModuleNameAndOffsetForPC has to return a string to the caller.
// Since the corresponding module might get unloaded later, we should create
@@ -141,8 +147,10 @@ class Symbolizer final {
static Symbolizer *PlatformInit();
bool FindModuleNameAndOffsetForAddress(uptr address, const char **module_name,
- uptr *module_offset);
+ uptr *module_offset,
+ ModuleArch *module_arch);
ListOfModules modules_;
+ ListOfModules fallback_modules_;
// If stale, need to reload the modules before looking up addresses.
bool modules_fresh_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_fuchsia.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_fuchsia.cc
new file mode 100644
index 0000000..0426320
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_fuchsia.cc
@@ -0,0 +1,105 @@
+//===-- sanitizer_symbolizer_fuchsia.cc -----------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is shared between various sanitizers' runtime libraries.
+//
+// Implementation of Fuchsia-specific symbolizer.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_platform.h"
+#if SANITIZER_FUCHSIA
+
+#include "sanitizer_fuchsia.h"
+#include "sanitizer_symbolizer.h"
+
+namespace __sanitizer {
+
+// For Fuchsia we don't do any actual symbolization per se.
+// Instead, we emit text containing raw addresses and raw linkage
+// symbol names, embedded in Fuchsia's symbolization markup format.
+// Fuchsia's logging infrastructure emits enough information about
+// process memory layout that a post-processing filter can do the
+// symbolization and pretty-print the markup. See the spec at:
+// https://fuchsia.googlesource.com/zircon/+/master/docs/symbolizer_markup.md
+
+// This is used by UBSan for type names, and by ASan for global variable names.
+constexpr const char *kFormatDemangle = "{{{symbol:%s}}}";
+constexpr uptr kFormatDemangleMax = 1024; // Arbitrary.
+
+// Function name or equivalent from PC location.
+constexpr const char *kFormatFunction = "{{{pc:%p}}}";
+constexpr uptr kFormatFunctionMax = 64; // More than big enough for 64-bit hex.
+
+// Global variable name or equivalent from data memory address.
+constexpr const char *kFormatData = "{{{data:%p}}}";
+
+// One frame in a backtrace (printed on a line by itself).
+constexpr const char *kFormatFrame = "{{{bt:%u:%p}}}";
+
+// This is used by UBSan for type names, and by ASan for global variable names.
+// It's expected to return a static buffer that will be reused on each call.
+const char *Symbolizer::Demangle(const char *name) {
+ static char buffer[kFormatDemangleMax];
+ internal_snprintf(buffer, sizeof(buffer), kFormatDemangle, name);
+ return buffer;
+}
+
+// This is used mostly for suppression matching. Making it work
+// would enable "interceptor_via_lib" suppressions. It's also used
+// once in UBSan to say "in module ..." in a message that also
+// includes an address in the module, so post-processing can already
+// pretty-print that so as to indicate the module.
+bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
+ uptr *module_address) {
+ return false;
+}
+
+// This is used in some places for suppression checking, which we
+// don't really support for Fuchsia. It's also used in UBSan to
+// identify a PC location to a function name, so we always fill in
+// the function member with a string containing markup around the PC
+// value.
+// TODO(mcgrathr): Under SANITIZER_GO, it's currently used by TSan
+// to render stack frames, but that should be changed to use
+// RenderStackFrame.
+SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
+ SymbolizedStack *s = SymbolizedStack::New(addr);
+ char buffer[kFormatFunctionMax];
+ internal_snprintf(buffer, sizeof(buffer), kFormatFunction, addr);
+ s->info.function = internal_strdup(buffer);
+ return s;
+}
+
+// Always claim we succeeded, so that RenderDataInfo will be called.
+bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
+ info->Clear();
+ info->start = addr;
+ return true;
+}
+
+// We ignore the format argument to __sanitizer_symbolize_global.
+void RenderData(InternalScopedString *buffer, const char *format,
+ const DataInfo *DI, const char *strip_path_prefix) {
+ buffer->append(kFormatData, DI->start);
+}
+
+// We don't support the stack_trace_format flag at all.
+void RenderFrame(InternalScopedString *buffer, const char *format, int frame_no,
+ const AddressInfo &info, bool vs_style,
+ const char *strip_path_prefix, const char *strip_func_prefix) {
+ buffer->append(kFormatFrame, frame_no, info.address);
+}
+
+Symbolizer *Symbolizer::PlatformInit() {
+ return new (symbolizer_allocator_) Symbolizer({});
+}
+
+void Symbolizer::LateInitialize() { Symbolizer::GetOrInit(); }
+
+} // namespace __sanitizer
+
+#endif // SANITIZER_FUCHSIA
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
index 119cb68..eae7509 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_internal.h
@@ -13,6 +13,7 @@
#define SANITIZER_SYMBOLIZER_INTERNAL_H
#include "sanitizer_symbolizer.h"
+#include "sanitizer_file.h"
namespace __sanitizer {
@@ -122,8 +123,8 @@ class LLVMSymbolizer : public SymbolizerTool {
bool SymbolizeData(uptr addr, DataInfo *info) override;
private:
- const char *SendCommand(bool is_data, const char *module_name,
- uptr module_offset);
+ const char *FormatAndSendCommand(bool is_data, const char *module_name,
+ uptr module_offset, ModuleArch arch);
LLVMSymbolizerProcess *symbolizer_process_;
static const uptr kBufferSize = 16 * 1024;
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
index b5bcfdb..eebc30b 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libbacktrace.cc
@@ -93,7 +93,8 @@ struct SymbolizeCodeCallbackArg {
if (frames_symbolized > 0) {
SymbolizedStack *cur = SymbolizedStack::New(addr);
AddressInfo *info = &cur->info;
- info->FillModuleInfo(first->info.module, first->info.module_offset);
+ info->FillModuleInfo(first->info.module, first->info.module_offset,
+ first->info.module_arch);
last->next = cur;
last = cur;
}
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc
index 45eb11a..df93441 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_libcdep.cc
@@ -15,6 +15,18 @@
namespace __sanitizer {
+Symbolizer *Symbolizer::GetOrInit() {
+ SpinMutexLock l(&init_mu_);
+ if (symbolizer_)
+ return symbolizer_;
+ symbolizer_ = PlatformInit();
+ CHECK(symbolizer_);
+ return symbolizer_;
+}
+
+// See sanitizer_symbolizer_fuchsia.cc.
+#if !SANITIZER_FUCHSIA
+
const char *ExtractToken(const char *str, const char *delims, char **result) {
uptr prefix_len = internal_strcspn(str, delims);
*result = (char*)InternalAlloc(prefix_len + 1);
@@ -62,11 +74,13 @@ SymbolizedStack *Symbolizer::SymbolizePC(uptr addr) {
BlockingMutexLock l(&mu_);
const char *module_name;
uptr module_offset;
+ ModuleArch arch;
SymbolizedStack *res = SymbolizedStack::New(addr);
- if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
+ if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset,
+ &arch))
return res;
// Always fill data about module name and offset.
- res->info.FillModuleInfo(module_name, module_offset);
+ res->info.FillModuleInfo(module_name, module_offset, arch);
for (auto &tool : tools_) {
SymbolizerScope sym_scope(this);
if (tool.SymbolizePC(addr, res)) {
@@ -80,11 +94,14 @@ bool Symbolizer::SymbolizeData(uptr addr, DataInfo *info) {
BlockingMutexLock l(&mu_);
const char *module_name;
uptr module_offset;
- if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset))
+ ModuleArch arch;
+ if (!FindModuleNameAndOffsetForAddress(addr, &module_name, &module_offset,
+ &arch))
return false;
info->Clear();
info->module = internal_strdup(module_name);
info->module_offset = module_offset;
+ info->module_arch = arch;
for (auto &tool : tools_) {
SymbolizerScope sym_scope(this);
if (tool.SymbolizeData(addr, info)) {
@@ -98,8 +115,9 @@ bool Symbolizer::GetModuleNameAndOffsetForPC(uptr pc, const char **module_name,
uptr *module_address) {
BlockingMutexLock l(&mu_);
const char *internal_module_name = nullptr;
+ ModuleArch arch;
if (!FindModuleNameAndOffsetForAddress(pc, &internal_module_name,
- module_address))
+ module_address, &arch))
return false;
if (module_name)
@@ -132,46 +150,58 @@ void Symbolizer::PrepareForSandboxing() {
bool Symbolizer::FindModuleNameAndOffsetForAddress(uptr address,
const char **module_name,
- uptr *module_offset) {
+ uptr *module_offset,
+ ModuleArch *module_arch) {
const LoadedModule *module = FindModuleForAddress(address);
if (module == nullptr)
return false;
*module_name = module->full_name();
*module_offset = address - module->base_address();
+ *module_arch = module->arch();
return true;
}
+void Symbolizer::RefreshModules() {
+ modules_.init();
+ fallback_modules_.fallbackInit();
+ RAW_CHECK(modules_.size() > 0);
+ modules_fresh_ = true;
+}
+
+static const LoadedModule *SearchForModule(const ListOfModules &modules,
+ uptr address) {
+ for (uptr i = 0; i < modules.size(); i++) {
+ if (modules[i].containsAddress(address)) {
+ return &modules[i];
+ }
+ }
+ return nullptr;
+}
+
const LoadedModule *Symbolizer::FindModuleForAddress(uptr address) {
bool modules_were_reloaded = false;
if (!modules_fresh_) {
- modules_.init();
- RAW_CHECK(modules_.size() > 0);
- modules_fresh_ = true;
+ RefreshModules();
modules_were_reloaded = true;
}
- for (uptr i = 0; i < modules_.size(); i++) {
- if (modules_[i].containsAddress(address)) {
- return &modules_[i];
- }
- }
- // Reload the modules and look up again, if we haven't tried it yet.
+ const LoadedModule *module = SearchForModule(modules_, address);
+ if (module) return module;
+
+ // dlopen/dlclose interceptors invalidate the module list, but when
+ // interception is disabled, we need to retry if the lookup fails in
+ // case the module list changed.
+#if !SANITIZER_INTERCEPT_DLOPEN_DLCLOSE
if (!modules_were_reloaded) {
- // FIXME: set modules_fresh_ from dlopen()/dlclose() interceptors.
- // It's too aggressive to reload the list of modules each time we fail
- // to find a module for a given address.
- modules_fresh_ = false;
- return FindModuleForAddress(address);
+ RefreshModules();
+ module = SearchForModule(modules_, address);
+ if (module) return module;
}
- return 0;
-}
+#endif
-Symbolizer *Symbolizer::GetOrInit() {
- SpinMutexLock l(&init_mu_);
- if (symbolizer_)
- return symbolizer_;
- symbolizer_ = PlatformInit();
- CHECK(symbolizer_);
- return symbolizer_;
+ if (fallback_modules_.size()) {
+ module = SearchForModule(fallback_modules_, address);
+ }
+ return module;
}
// For now we assume the following protocol:
@@ -195,6 +225,8 @@ class LLVMSymbolizerProcess : public SymbolizerProcess {
buffer[length - 2] == '\n';
}
+ // When adding a new architecture, don't forget to also update
+ // script/asan_symbolize.py and sanitizer_common.h.
void GetArgV(const char *path_to_binary,
const char *(&argv)[kArgVMax]) const override {
#if defined(__x86_64h__)
@@ -240,25 +272,21 @@ static const char *ParseFileLineInfo(AddressInfo *info, const char *str) {
char *file_line_info = 0;
str = ExtractToken(str, "\n", &file_line_info);
CHECK(file_line_info);
- // Parse the last :<int>, which must be there.
- char *last_colon = internal_strrchr(file_line_info, ':');
- CHECK(last_colon);
- int line_or_column = internal_atoll(last_colon + 1);
- // Truncate the string at the last colon and find the next-to-last colon.
- *last_colon = '\0';
- last_colon = internal_strrchr(file_line_info, ':');
- if (last_colon && IsDigit(last_colon[1])) {
- // If the second-to-last colon is followed by a digit, it must be the line
- // number, and the previous parsed number was a column.
- info->line = internal_atoll(last_colon + 1);
- info->column = line_or_column;
- *last_colon = '\0';
- } else {
- // Otherwise, we have line info but no column info.
- info->line = line_or_column;
- info->column = 0;
+
+ if (uptr size = internal_strlen(file_line_info)) {
+ char *back = file_line_info + size - 1;
+ for (int i = 0; i < 2; ++i) {
+ while (back > file_line_info && IsDigit(*back)) --back;
+ if (*back != ':' || !IsDigit(back[1])) break;
+ info->column = info->line;
+ info->line = internal_atoll(back + 1);
+ // Truncate the string at the colon to keep only filename.
+ *back = '\0';
+ --back;
+ }
+ ExtractToken(file_line_info, "", &info->file);
}
- ExtractToken(file_line_info, "", &info->file);
+
InternalFree(file_line_info);
return str;
}
@@ -286,7 +314,8 @@ void ParseSymbolizePCOutput(const char *str, SymbolizedStack *res) {
top_frame = false;
} else {
cur = SymbolizedStack::New(res->info.address);
- cur->info.FillModuleInfo(res->info.module, res->info.module_offset);
+ cur->info.FillModuleInfo(res->info.module, res->info.module_offset,
+ res->info.module_arch);
last->next = cur;
last = cur;
}
@@ -319,8 +348,10 @@ void ParseSymbolizeDataOutput(const char *str, DataInfo *info) {
}
bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
- if (const char *buf = SendCommand(/*is_data*/ false, stack->info.module,
- stack->info.module_offset)) {
+ AddressInfo *info = &stack->info;
+ const char *buf = FormatAndSendCommand(
+ /*is_data*/ false, info->module, info->module_offset, info->module_arch);
+ if (buf) {
ParseSymbolizePCOutput(buf, stack);
return true;
}
@@ -328,8 +359,9 @@ bool LLVMSymbolizer::SymbolizePC(uptr addr, SymbolizedStack *stack) {
}
bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
- if (const char *buf =
- SendCommand(/*is_data*/ true, info->module, info->module_offset)) {
+ const char *buf = FormatAndSendCommand(
+ /*is_data*/ true, info->module, info->module_offset, info->module_arch);
+ if (buf) {
ParseSymbolizeDataOutput(buf, info);
info->start += (addr - info->module_offset); // Add the base address.
return true;
@@ -337,11 +369,27 @@ bool LLVMSymbolizer::SymbolizeData(uptr addr, DataInfo *info) {
return false;
}
-const char *LLVMSymbolizer::SendCommand(bool is_data, const char *module_name,
- uptr module_offset) {
+const char *LLVMSymbolizer::FormatAndSendCommand(bool is_data,
+ const char *module_name,
+ uptr module_offset,
+ ModuleArch arch) {
CHECK(module_name);
- internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n",
- is_data ? "DATA " : "", module_name, module_offset);
+ const char *is_data_str = is_data ? "DATA " : "";
+ if (arch == kModuleArchUnknown) {
+ if (internal_snprintf(buffer_, kBufferSize, "%s\"%s\" 0x%zx\n", is_data_str,
+ module_name,
+ module_offset) >= static_cast<int>(kBufferSize)) {
+ Report("WARNING: Command buffer too small");
+ return nullptr;
+ }
+ } else {
+ if (internal_snprintf(buffer_, kBufferSize, "%s\"%s:%s\" 0x%zx\n",
+ is_data_str, module_name, ModuleArchToString(arch),
+ module_offset) >= static_cast<int>(kBufferSize)) {
+ Report("WARNING: Command buffer too small");
+ return nullptr;
+ }
+ }
return symbolizer_process_->SendCommand(buffer_);
}
@@ -357,7 +405,23 @@ SymbolizerProcess::SymbolizerProcess(const char *path, bool use_forkpty)
CHECK_NE(path_[0], '\0');
}
+static bool IsSameModule(const char* path) {
+ if (const char* ProcessName = GetProcessName()) {
+ if (const char* SymbolizerName = StripModuleName(path)) {
+ return !internal_strcmp(ProcessName, SymbolizerName);
+ }
+ }
+ return false;
+}
+
const char *SymbolizerProcess::SendCommand(const char *command) {
+ if (failed_to_start_)
+ return nullptr;
+ if (IsSameModule(path_)) {
+ Report("WARNING: Symbolizer was blocked from starting itself!\n");
+ failed_to_start_ = true;
+ return nullptr;
+ }
for (; times_restarted_ < kMaxTimesRestarted; times_restarted_++) {
// Start or restart symbolizer if we failed to send command to it.
if (const char *res = SendCommandImpl(command))
@@ -406,6 +470,11 @@ bool SymbolizerProcess::ReadFromSymbolizer(char *buffer, uptr max_length) {
read_len += just_read;
if (ReachedEndOfOutput(buffer, read_len))
break;
+ if (read_len + 1 == max_length) {
+ Report("WARNING: Symbolizer buffer too small\n");
+ read_len = 0;
+ break;
+ }
}
buffer[read_len] = '\0';
return true;
@@ -423,4 +492,6 @@ bool SymbolizerProcess::WriteToSymbolizer(const char *buffer, uptr length) {
return true;
}
+#endif // !SANITIZER_FUCHSIA
+
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
index 3fcd7d0..afd6bbe 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cc
@@ -14,6 +14,7 @@
#if SANITIZER_POSIX
#include "sanitizer_allocator_internal.h"
#include "sanitizer_common.h"
+#include "sanitizer_file.h"
#include "sanitizer_flags.h"
#include "sanitizer_internal_defs.h"
#include "sanitizer_linux.h"
@@ -53,7 +54,7 @@ const char *DemangleCXXABI(const char *name) {
// own demangler (libc++abi's implementation could be adapted so that
// it does not allocate). For now, we just call it anyway, and we leak
// the returned value.
- if (__cxxabiv1::__cxa_demangle)
+ if (&__cxxabiv1::__cxa_demangle)
if (const char *demangled_name =
__cxxabiv1::__cxa_demangle(name, 0, 0, 0))
return demangled_name;
@@ -99,6 +100,46 @@ const char *DemangleSwiftAndCXX(const char *name) {
return DemangleCXXABI(name);
}
+static bool CreateTwoHighNumberedPipes(int *infd_, int *outfd_) {
+ int *infd = NULL;
+ int *outfd = NULL;
+ // The client program may close its stdin and/or stdout and/or stderr
+ // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
+ // In this case the communication between the forked processes may be
+ // broken if either the parent or the child tries to close or duplicate
+ // these descriptors. The loop below produces two pairs of file
+ // descriptors, each greater than 2 (stderr).
+ int sock_pair[5][2];
+ for (int i = 0; i < 5; i++) {
+ if (pipe(sock_pair[i]) == -1) {
+ for (int j = 0; j < i; j++) {
+ internal_close(sock_pair[j][0]);
+ internal_close(sock_pair[j][1]);
+ }
+ return false;
+ } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
+ if (infd == NULL) {
+ infd = sock_pair[i];
+ } else {
+ outfd = sock_pair[i];
+ for (int j = 0; j < i; j++) {
+ if (sock_pair[j] == infd) continue;
+ internal_close(sock_pair[j][0]);
+ internal_close(sock_pair[j][1]);
+ }
+ break;
+ }
+ }
+ }
+ CHECK(infd);
+ CHECK(outfd);
+ infd_[0] = infd[0];
+ infd_[1] = infd[1];
+ outfd_[0] = outfd[0];
+ outfd_[1] = outfd[1];
+ return true;
+}
+
bool SymbolizerProcess::StartSymbolizerSubprocess() {
if (!FileExists(path_)) {
if (!reported_invalid_path_) {
@@ -108,7 +149,18 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
return false;
}
- int pid;
+ int pid = -1;
+
+ int infd[2];
+ internal_memset(&infd, 0, sizeof(infd));
+ int outfd[2];
+ internal_memset(&outfd, 0, sizeof(outfd));
+ if (!CreateTwoHighNumberedPipes(infd, outfd)) {
+ Report("WARNING: Can't create a socket pair to start "
+ "external symbolizer (errno: %d)\n", errno);
+ return false;
+ }
+
if (use_forkpty_) {
#if SANITIZER_MAC
fd_t fd = kInvalidFd;
@@ -119,6 +171,10 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
int saved_stderr = dup(STDERR_FILENO);
CHECK_GE(saved_stderr, 0);
+ // We only need one pipe, for stdin of the child.
+ close(outfd[0]);
+ close(outfd[1]);
+
// Use forkpty to disable buffering in the new terminal.
pid = internal_forkpty(&fd);
if (pid == -1) {
@@ -129,6 +185,13 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
} else if (pid == 0) {
// Child subprocess.
+ // infd[0] is the child's reading end.
+ close(infd[1]);
+
+ // Set up stdin to read from the pipe.
+ CHECK_GE(dup2(infd[0], STDIN_FILENO), 0);
+ close(infd[0]);
+
// Restore stderr.
CHECK_GE(dup2(saved_stderr, STDERR_FILENO), 0);
close(saved_stderr);
@@ -139,8 +202,12 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
internal__exit(1);
}
+ // Input for the child, infd[1] is our writing end.
+ output_fd_ = infd[1];
+ close(infd[0]);
+
// Continue execution in parent process.
- input_fd_ = output_fd_ = fd;
+ input_fd_ = fd;
close(saved_stderr);
@@ -154,41 +221,6 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
UNIMPLEMENTED();
#endif // SANITIZER_MAC
} else {
- int *infd = NULL;
- int *outfd = NULL;
- // The client program may close its stdin and/or stdout and/or stderr
- // thus allowing socketpair to reuse file descriptors 0, 1 or 2.
- // In this case the communication between the forked processes may be
- // broken if either the parent or the child tries to close or duplicate
- // these descriptors. The loop below produces two pairs of file
- // descriptors, each greater than 2 (stderr).
- int sock_pair[5][2];
- for (int i = 0; i < 5; i++) {
- if (pipe(sock_pair[i]) == -1) {
- for (int j = 0; j < i; j++) {
- internal_close(sock_pair[j][0]);
- internal_close(sock_pair[j][1]);
- }
- Report("WARNING: Can't create a socket pair to start "
- "external symbolizer (errno: %d)\n", errno);
- return false;
- } else if (sock_pair[i][0] > 2 && sock_pair[i][1] > 2) {
- if (infd == NULL) {
- infd = sock_pair[i];
- } else {
- outfd = sock_pair[i];
- for (int j = 0; j < i; j++) {
- if (sock_pair[j] == infd) continue;
- internal_close(sock_pair[j][0]);
- internal_close(sock_pair[j][1]);
- }
- break;
- }
- }
- }
- CHECK(infd);
- CHECK(outfd);
-
const char *argv[kArgVMax];
GetArgV(path_, argv);
pid = StartSubprocess(path_, argv, /* stdin */ outfd[0],
@@ -203,6 +235,8 @@ bool SymbolizerProcess::StartSymbolizerSubprocess() {
output_fd_ = outfd[1];
}
+ CHECK_GT(pid, 0);
+
// Check that symbolizer subprocess started successfully.
SleepForMillis(kSymbolizerStartupTimeMillis);
if (!IsProcessRunning(pid)) {
@@ -236,6 +270,10 @@ class Addr2LineProcess : public SymbolizerProcess {
bool ReadFromSymbolizer(char *buffer, uptr max_length) override {
if (!SymbolizerProcess::ReadFromSymbolizer(buffer, max_length))
return false;
+ // The returned buffer is empty when output is valid, but exceeds
+ // max_length.
+ if (*buffer == '\0')
+ return true;
// We should cut out output_terminator_ at the end of given buffer,
// appended by addr2line to mark the end of its meaningful output.
// We cannot scan buffer from it's beginning, because it is legal for it
@@ -389,7 +427,6 @@ class InternalSymbolizer : public SymbolizerTool {
InternalSymbolizer() { }
static const int kBufferSize = 16 * 1024;
- static const int kMaxDemangledNameSize = 1024;
char buffer_[kBufferSize];
};
#else // SANITIZER_SUPPORTS_WEAK_HOOKS
@@ -436,16 +473,16 @@ static SymbolizerTool *ChooseExternalSymbolizer(LowLevelAllocator *allocator) {
// Otherwise symbolizer program is unknown, let's search $PATH
CHECK(path == nullptr);
- if (const char *found_path = FindPathToBinary("llvm-symbolizer")) {
- VReport(2, "Using llvm-symbolizer found at: %s\n", found_path);
- return new(*allocator) LLVMSymbolizer(found_path, allocator);
- }
#if SANITIZER_MAC
if (const char *found_path = FindPathToBinary("atos")) {
VReport(2, "Using atos found at: %s\n", found_path);
return new(*allocator) AtosSymbolizer(found_path, allocator);
}
#endif // SANITIZER_MAC
+ if (const char *found_path = FindPathToBinary("llvm-symbolizer")) {
+ VReport(2, "Using llvm-symbolizer found at: %s\n", found_path);
+ return new(*allocator) LLVMSymbolizer(found_path, allocator);
+ }
if (common_flags()->allow_addr2line) {
if (const char *found_path = FindPathToBinary("addr2line")) {
VReport(2, "Using addr2line found at: %s\n", found_path);
@@ -461,7 +498,7 @@ static void ChooseSymbolizerTools(IntrusiveList<SymbolizerTool> *list,
VReport(2, "Symbolizer is disabled.\n");
return;
}
- if (IsReportingOOM()) {
+ if (IsAllocatorOutOfMemory()) {
VReport(2, "Cannot use internal symbolizer: out of memory\n");
} else if (SymbolizerTool *tool = InternalSymbolizer::get(allocator)) {
VReport(2, "Using internal symbolizer.\n");
diff --git a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
index 95fda7e..06375fc 100644
--- a/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_symbolizer_win.cc
@@ -12,15 +12,24 @@
#include "sanitizer_platform.h"
#if SANITIZER_WINDOWS
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-#include <dbghelp.h>
-#pragma comment(lib, "dbghelp.lib")
+#include "sanitizer_dbghelp.h"
#include "sanitizer_symbolizer_internal.h"
namespace __sanitizer {
+decltype(::StackWalk64) *StackWalk64;
+decltype(::SymCleanup) *SymCleanup;
+decltype(::SymFromAddr) *SymFromAddr;
+decltype(::SymFunctionTableAccess64) *SymFunctionTableAccess64;
+decltype(::SymGetLineFromAddr64) *SymGetLineFromAddr64;
+decltype(::SymGetModuleBase64) *SymGetModuleBase64;
+decltype(::SymGetSearchPathW) *SymGetSearchPathW;
+decltype(::SymInitialize) *SymInitialize;
+decltype(::SymSetOptions) *SymSetOptions;
+decltype(::SymSetSearchPathW) *SymSetSearchPathW;
+decltype(::UnDecorateSymbolName) *UnDecorateSymbolName;
+
namespace {
class WinSymbolizerTool : public SymbolizerTool {
@@ -48,6 +57,29 @@ bool TrySymInitialize() {
void InitializeDbgHelpIfNeeded() {
if (is_dbghelp_initialized)
return;
+
+ HMODULE dbghelp = LoadLibraryA("dbghelp.dll");
+ CHECK(dbghelp && "failed to load dbghelp.dll");
+
+#define DBGHELP_IMPORT(name) \
+ do { \
+ name = \
+ reinterpret_cast<decltype(::name) *>(GetProcAddress(dbghelp, #name)); \
+ CHECK(name != nullptr); \
+ } while (0)
+ DBGHELP_IMPORT(StackWalk64);
+ DBGHELP_IMPORT(SymCleanup);
+ DBGHELP_IMPORT(SymFromAddr);
+ DBGHELP_IMPORT(SymFunctionTableAccess64);
+ DBGHELP_IMPORT(SymGetLineFromAddr64);
+ DBGHELP_IMPORT(SymGetModuleBase64);
+ DBGHELP_IMPORT(SymGetSearchPathW);
+ DBGHELP_IMPORT(SymInitialize);
+ DBGHELP_IMPORT(SymSetOptions);
+ DBGHELP_IMPORT(SymSetSearchPathW);
+ DBGHELP_IMPORT(UnDecorateSymbolName);
+#undef DBGHELP_IMPORT
+
if (!TrySymInitialize()) {
// OK, maybe the client app has called SymInitialize already.
// That's a bit unfortunate for us as all the DbgHelp functions are
diff --git a/libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc b/libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc
index 3bc50d9..7c9a271 100644
--- a/libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc
+++ b/libsanitizer/sanitizer_common/sanitizer_syscall_generic.inc
@@ -5,17 +5,41 @@
//
//===----------------------------------------------------------------------===//
//
-// Generic implementations of internal_syscall and internal_iserror.
+// Generic implementations of internal_syscall* and internal_iserror.
//
//===----------------------------------------------------------------------===//
-#if SANITIZER_FREEBSD || SANITIZER_MAC
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD
# define SYSCALL(name) SYS_ ## name
#else
# define SYSCALL(name) __NR_ ## name
#endif
-#if (SANITIZER_FREEBSD || SANITIZER_MAC) && defined(__x86_64__)
+#if SANITIZER_NETBSD
+// We use 3 kinds of internal_syscall's for different types of retval in order
+// to address differences in calling conventions (e.g. registers to place the
+// return value in).
+// - internal_syscall for 32-bit length (int, pid_t)
+// - internal_syscall64 for 64-bit length (off_t)
+// - internal_syscall_ptr for pointer and (s)size_t
+# define internal_syscall syscall
+# define internal_syscall64 __syscall
+// Handle syscall renames manually
+# define SYS_stat SYS___stat50
+# define SYS_lstat SYS___lstat50
+# define SYS_fstat SYS___fstat50
+# define SYS_gettimeofday SYS___gettimeofday50
+# define SYS_wait4 SYS___wait450
+# define SYS_getdents SYS___getdents30
+# define SYS_sigaltstack SYS___sigaltstack14
+# define SYS_sigprocmask SYS___sigprocmask14
+# define SYS_nanosleep SYS___nanosleep50
+# if SANITIZER_WORDSIZE == 64
+# define internal_syscall_ptr __syscall
+# else
+# define internal_syscall_ptr syscall
+# endif
+#elif defined(__x86_64__) && (SANITIZER_FREEBSD || SANITIZER_MAC)
# define internal_syscall __syscall
# else
# define internal_syscall syscall
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
index c865d2c..d58c939 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.cc
@@ -17,7 +17,7 @@ namespace __sanitizer {
ThreadContextBase::ThreadContextBase(u32 tid)
: tid(tid), unique_id(0), reuse_count(), os_id(0), user_id(0),
status(ThreadStatusInvalid),
- detached(false), parent_tid(0), next(0) {
+ detached(false), workerthread(false), parent_tid(0), next(0) {
name[0] = '\0';
}
@@ -52,14 +52,19 @@ void ThreadContextBase::SetJoined(void *arg) {
}
void ThreadContextBase::SetFinished() {
- if (!detached)
- status = ThreadStatusFinished;
+ // ThreadRegistry::FinishThread calls here in ThreadStatusCreated state
+ // for a thread that never actually started. In that case the thread
+ // should go to ThreadStatusFinished regardless of whether it was created
+ // as detached.
+ if (!detached || status == ThreadStatusCreated) status = ThreadStatusFinished;
OnFinished();
}
-void ThreadContextBase::SetStarted(uptr _os_id, void *arg) {
+void ThreadContextBase::SetStarted(tid_t _os_id, bool _workerthread,
+ void *arg) {
status = ThreadStatusRunning;
os_id = _os_id;
+ workerthread = _workerthread;
OnStarted(arg);
}
@@ -190,7 +195,7 @@ static bool FindThreadContextByOsIdCallback(ThreadContextBase *tctx,
tctx->status != ThreadStatusDead);
}
-ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(uptr os_id) {
+ThreadContextBase *ThreadRegistry::FindThreadContextByOsIDLocked(tid_t os_id) {
return FindThreadContextLocked(FindThreadContextByOsIdCallback,
(void *)os_id);
}
@@ -200,7 +205,8 @@ void ThreadRegistry::SetThreadName(u32 tid, const char *name) {
CHECK_LT(tid, n_contexts_);
ThreadContextBase *tctx = threads_[tid];
CHECK_NE(tctx, 0);
- CHECK_EQ(ThreadStatusRunning, tctx->status);
+ CHECK_EQ(SANITIZER_FUCHSIA ? ThreadStatusCreated : ThreadStatusRunning,
+ tctx->status);
tctx->SetName(name);
}
@@ -247,31 +253,43 @@ void ThreadRegistry::JoinThread(u32 tid, void *arg) {
QuarantinePush(tctx);
}
+// Normally this is called when the thread is about to exit. If
+// called in ThreadStatusCreated state, then this thread was never
+// really started. We just did CreateThread for a prospective new
+// thread before trying to create it, and then failed to actually
+// create it, and so never called StartThread.
void ThreadRegistry::FinishThread(u32 tid) {
BlockingMutexLock l(&mtx_);
CHECK_GT(alive_threads_, 0);
alive_threads_--;
- CHECK_GT(running_threads_, 0);
- running_threads_--;
CHECK_LT(tid, n_contexts_);
ThreadContextBase *tctx = threads_[tid];
CHECK_NE(tctx, 0);
- CHECK_EQ(ThreadStatusRunning, tctx->status);
+ bool dead = tctx->detached;
+ if (tctx->status == ThreadStatusRunning) {
+ CHECK_GT(running_threads_, 0);
+ running_threads_--;
+ } else {
+ // The thread never really existed.
+ CHECK_EQ(tctx->status, ThreadStatusCreated);
+ dead = true;
+ }
tctx->SetFinished();
- if (tctx->detached) {
+ if (dead) {
tctx->SetDead();
QuarantinePush(tctx);
}
}
-void ThreadRegistry::StartThread(u32 tid, uptr os_id, void *arg) {
+void ThreadRegistry::StartThread(u32 tid, tid_t os_id, bool workerthread,
+ void *arg) {
BlockingMutexLock l(&mtx_);
running_threads_++;
CHECK_LT(tid, n_contexts_);
ThreadContextBase *tctx = threads_[tid];
CHECK_NE(tctx, 0);
CHECK_EQ(ThreadStatusCreated, tctx->status);
- tctx->SetStarted(os_id, arg);
+ tctx->SetStarted(os_id, workerthread, arg);
}
void ThreadRegistry::QuarantinePush(ThreadContextBase *tctx) {
diff --git a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
index 8d5f1ea..16c2f86 100644
--- a/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
+++ b/libsanitizer/sanitizer_common/sanitizer_thread_registry.h
@@ -37,12 +37,13 @@ class ThreadContextBase {
const u32 tid; // Thread ID. Main thread should have tid = 0.
u64 unique_id; // Unique thread ID.
u32 reuse_count; // Number of times this tid was reused.
- uptr os_id; // PID (used for reporting).
+ tid_t os_id; // PID (used for reporting).
uptr user_id; // Some opaque user thread id (e.g. pthread_t).
char name[64]; // As annotated by user.
ThreadStatus status;
bool detached;
+ bool workerthread;
u32 parent_tid;
ThreadContextBase *next; // For storing thread contexts in a list.
@@ -52,7 +53,7 @@ class ThreadContextBase {
void SetDead();
void SetJoined(void *arg);
void SetFinished();
- void SetStarted(uptr _os_id, void *arg);
+ void SetStarted(tid_t _os_id, bool _workerthread, void *arg);
void SetCreated(uptr _user_id, u64 _unique_id, bool _detached,
u32 _parent_tid, void *arg);
void Reset();
@@ -106,14 +107,14 @@ class ThreadRegistry {
// is found.
ThreadContextBase *FindThreadContextLocked(FindThreadCallback cb,
void *arg);
- ThreadContextBase *FindThreadContextByOsIDLocked(uptr os_id);
+ ThreadContextBase *FindThreadContextByOsIDLocked(tid_t os_id);
void SetThreadName(u32 tid, const char *name);
void SetThreadNameByUserId(uptr user_id, const char *name);
void DetachThread(u32 tid, void *arg);
void JoinThread(u32 tid, void *arg);
void FinishThread(u32 tid);
- void StartThread(u32 tid, uptr os_id, void *arg);
+ void StartThread(u32 tid, tid_t os_id, bool workerthread, void *arg);
private:
const ThreadContextFactory context_factory_;
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc
index 229225d..ebf5ec0 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.cc
@@ -43,7 +43,7 @@ static const uptr kDestroyedThread = -1;
static inline void DTLS_Deallocate(DTLS::DTV *dtv, uptr size) {
if (!size) return;
- VPrintf(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
+ VReport(2, "__tls_get_addr: DTLS_Deallocate %p %zd\n", dtv, size);
UnmapOrDie(dtv, size * sizeof(DTLS::DTV));
atomic_fetch_sub(&number_of_live_dtls, 1, memory_order_relaxed);
}
@@ -56,7 +56,7 @@ static inline void DTLS_Resize(uptr new_size) {
(DTLS::DTV *)MmapOrDie(new_size * sizeof(DTLS::DTV), "DTLS_Resize");
uptr num_live_dtls =
atomic_fetch_add(&number_of_live_dtls, 1, memory_order_relaxed);
- VPrintf(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
+ VReport(2, "__tls_get_addr: DTLS_Resize %p %zd\n", &dtls, num_live_dtls);
CHECK_LT(num_live_dtls, 1 << 20);
uptr old_dtv_size = dtls.dtv_size;
DTLS::DTV *old_dtv = dtls.dtv;
@@ -70,7 +70,7 @@ static inline void DTLS_Resize(uptr new_size) {
void DTLS_Destroy() {
if (!common_flags()->intercept_tls_get_addr) return;
- VPrintf(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
+ VReport(2, "__tls_get_addr: DTLS_Destroy %p %zd\n", &dtls, dtls.dtv_size);
uptr s = dtls.dtv_size;
dtls.dtv_size = kDestroyedThread; // Do this before unmap for AS-safety.
DTLS_Deallocate(dtls.dtv, s);
@@ -95,28 +95,28 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
if (dtls.dtv[dso_id].beg) return 0;
uptr tls_size = 0;
uptr tls_beg = reinterpret_cast<uptr>(res) - arg->offset - kDtvOffset;
- VPrintf(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
+ VReport(2, "__tls_get_addr: %p {%p,%p} => %p; tls_beg: %p; sp: %p "
"num_live_dtls %zd\n",
arg, arg->dso_id, arg->offset, res, tls_beg, &tls_beg,
atomic_load(&number_of_live_dtls, memory_order_relaxed));
if (dtls.last_memalign_ptr == tls_beg) {
tls_size = dtls.last_memalign_size;
- VPrintf(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n",
+ VReport(2, "__tls_get_addr: glibc <=2.18 suspected; tls={%p,%p}\n",
tls_beg, tls_size);
} else if (tls_beg >= static_tls_begin && tls_beg < static_tls_end) {
// This is the static TLS block which was initialized / unpoisoned at thread
// creation.
- VPrintf(2, "__tls_get_addr: static tls: %p\n", tls_beg);
+ VReport(2, "__tls_get_addr: static tls: %p\n", tls_beg);
tls_size = 0;
} else if ((tls_beg % 4096) == sizeof(Glibc_2_19_tls_header)) {
// We may want to check gnu_get_libc_version().
Glibc_2_19_tls_header *header = (Glibc_2_19_tls_header *)tls_beg - 1;
tls_size = header->size;
tls_beg = header->start;
- VPrintf(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n",
+ VReport(2, "__tls_get_addr: glibc >=2.19 suspected; tls={%p %p}\n",
tls_beg, tls_size);
} else {
- VPrintf(2, "__tls_get_addr: Can't guess glibc version\n");
+ VReport(2, "__tls_get_addr: Can't guess glibc version\n");
// This may happen inside the DTOR of main thread, so just ignore it.
tls_size = 0;
}
@@ -127,18 +127,26 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg_void, void *res,
void DTLS_on_libc_memalign(void *ptr, uptr size) {
if (!common_flags()->intercept_tls_get_addr) return;
- VPrintf(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size);
+ VReport(2, "DTLS_on_libc_memalign: %p %p\n", ptr, size);
dtls.last_memalign_ptr = reinterpret_cast<uptr>(ptr);
dtls.last_memalign_size = size;
}
DTLS *DTLS_Get() { return &dtls; }
+bool DTLSInDestruction(DTLS *dtls) {
+ return dtls->dtv_size == kDestroyedThread;
+}
+
#else
void DTLS_on_libc_memalign(void *ptr, uptr size) {}
DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res) { return 0; }
DTLS *DTLS_Get() { return 0; }
void DTLS_Destroy() {}
+bool DTLSInDestruction(DTLS *dtls) {
+ UNREACHABLE("dtls is unsupported on this platform!");
+}
+
#endif // SANITIZER_INTERCEPT_TLS_GET_ADDR
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
index e4f8c0c..19c8472 100644
--- a/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
+++ b/libsanitizer/sanitizer_common/sanitizer_tls_get_addr.h
@@ -53,6 +53,8 @@ DTLS::DTV *DTLS_on_tls_get_addr(void *arg, void *res, uptr static_tls_begin,
void DTLS_on_libc_memalign(void *ptr, uptr size);
DTLS *DTLS_Get();
void DTLS_Destroy(); // Make sure to call this before the thread is destroyed.
+// Returns true if DTLS of suspended thread is in destruction process.
+bool DTLSInDestruction(DTLS *dtls);
} // namespace __sanitizer
diff --git a/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc b/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc
index eb1c133..7dba9e7 100644
--- a/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_unwind_linux_libcdep.cc
@@ -6,11 +6,11 @@
//===----------------------------------------------------------------------===//
//
// This file contains the unwind.h-based (aka "slow") stack unwinding routines
-// available to the tools on Linux, Android, and FreeBSD.
+// available to the tools on Linux, Android, NetBSD and FreeBSD.
//===----------------------------------------------------------------------===//
#include "sanitizer_platform.h"
-#if SANITIZER_FREEBSD || SANITIZER_LINUX
+#if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
#include "sanitizer_common.h"
#include "sanitizer_stacktrace.h"
@@ -76,7 +76,8 @@ void SanitizerInitializeUnwinder() {
}
#endif
-#ifdef __arm__
+#if defined(__arm__) && !SANITIZER_NETBSD
+// NetBSD uses dwarf EH
#define UNWIND_STOP _URC_END_OF_STACK
#define UNWIND_CONTINUE _URC_NO_REASON
#else
@@ -163,4 +164,4 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
} // namespace __sanitizer
-#endif // SANITIZER_FREEBSD || SANITIZER_LINUX
+#endif // SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.cc b/libsanitizer/sanitizer_common/sanitizer_win.cc
index 785883c..84e66b4 100644
--- a/libsanitizer/sanitizer_common/sanitizer_win.cc
+++ b/libsanitizer/sanitizer_common/sanitizer_win.cc
@@ -16,18 +16,34 @@
#define WIN32_LEAN_AND_MEAN
#define NOGDI
#include <windows.h>
-#include <dbghelp.h>
#include <io.h>
#include <psapi.h>
#include <stdlib.h>
#include "sanitizer_common.h"
+#include "sanitizer_dbghelp.h"
+#include "sanitizer_file.h"
#include "sanitizer_libc.h"
#include "sanitizer_mutex.h"
#include "sanitizer_placement_new.h"
-#include "sanitizer_procmaps.h"
#include "sanitizer_stacktrace.h"
#include "sanitizer_symbolizer.h"
+#include "sanitizer_win_defs.h"
+
+// A macro to tell the compiler that this part of the code cannot be reached,
+// if the compiler supports this feature. Since we're using this in
+// code that is called when terminating the process, the expansion of the
+// macro should not terminate the process to avoid infinite recursion.
+#if defined(__clang__)
+# define BUILTIN_UNREACHABLE() __builtin_unreachable()
+#elif defined(__GNUC__) && \
+ (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
+# define BUILTIN_UNREACHABLE() __builtin_unreachable()
+#elif defined(_MSC_VER)
+# define BUILTIN_UNREACHABLE() __assume(0)
+#else
+# define BUILTIN_UNREACHABLE()
+#endif
namespace __sanitizer {
@@ -62,7 +78,7 @@ uptr internal_getpid() {
// In contrast to POSIX, on Windows GetCurrentThreadId()
// returns a system-unique identifier.
-uptr GetTid() {
+tid_t GetTid() {
return GetCurrentThreadId();
}
@@ -113,8 +129,24 @@ void UnmapOrDie(void *addr, uptr size) {
}
}
+static void *ReturnNullptrOnOOMOrDie(uptr size, const char *mem_type,
+ const char *mmap_type) {
+ error_t last_error = GetLastError();
+ if (last_error == ERROR_NOT_ENOUGH_MEMORY)
+ return nullptr;
+ ReportMmapFailureAndDie(size, mem_type, mmap_type, last_error);
+}
+
+void *MmapOrDieOnFatalError(uptr size, const char *mem_type) {
+ void *rv = VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
+ if (rv == 0)
+ return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate");
+ return rv;
+}
+
// We want to map a chunk of address space aligned to 'alignment'.
-void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
+void *MmapAlignedOrDieOnFatalError(uptr size, uptr alignment,
+ const char *mem_type) {
CHECK(IsPowerOfTwo(size));
CHECK(IsPowerOfTwo(alignment));
@@ -124,7 +156,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
uptr mapped_addr =
(uptr)VirtualAlloc(0, size, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
if (!mapped_addr)
- ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError());
+ return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned");
// If we got it right on the first try, return. Otherwise, unmap it and go to
// the slow path.
@@ -144,8 +176,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
mapped_addr =
(uptr)VirtualAlloc(0, size + alignment, MEM_RESERVE, PAGE_NOACCESS);
if (!mapped_addr)
- ReportMmapFailureAndDie(size, mem_type, "allocate aligned",
- GetLastError());
+ return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned");
// Find the aligned address.
uptr aligned_addr = RoundUpTo(mapped_addr, alignment);
@@ -163,7 +194,7 @@ void *MmapAlignedOrDie(uptr size, uptr alignment, const char *mem_type) {
// Fail if we can't make this work quickly.
if (retries == kMaxRetries && mapped_addr == 0)
- ReportMmapFailureAndDie(size, mem_type, "allocate aligned", GetLastError());
+ return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate aligned");
return (void *)mapped_addr;
}
@@ -202,6 +233,18 @@ void *MmapFixedOrDie(uptr fixed_addr, uptr size) {
return p;
}
+void *MmapFixedOrDieOnFatalError(uptr fixed_addr, uptr size) {
+ void *p = VirtualAlloc((LPVOID)fixed_addr, size,
+ MEM_COMMIT, PAGE_READWRITE);
+ if (p == 0) {
+ char mem_type[30];
+ internal_snprintf(mem_type, sizeof(mem_type), "memory at address 0x%zx",
+ fixed_addr);
+ return ReturnNullptrOnOOMOrDie(size, mem_type, "allocate");
+ }
+ return p;
+}
+
void *MmapNoReserveOrDie(uptr size, const char *mem_type) {
// FIXME: make this really NoReserve?
return MmapOrDie(size, mem_type);
@@ -232,8 +275,7 @@ bool MprotectNoAccess(uptr addr, uptr size) {
return VirtualProtect((LPVOID)addr, size, PAGE_NOACCESS, &old_protection);
}
-
-void ReleaseMemoryToOS(uptr addr, uptr size) {
+void ReleaseMemoryPagesToOS(uptr beg, uptr end) {
// This is almost useless on 32-bits.
// FIXME: add madvise-analog when we move to 64-bits.
}
@@ -247,7 +289,8 @@ void DontDumpShadowMemory(uptr addr, uptr length) {
// FIXME: add madvise-analog when we move to 64-bits.
}
-uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding) {
+uptr FindAvailableMemoryRange(uptr size, uptr alignment, uptr left_padding,
+ uptr *largest_gap_found) {
uptr address = 0;
while (true) {
MEMORY_BASIC_INFORMATION info;
@@ -372,6 +415,8 @@ void DumpProcessMap() {
}
#endif
+void PrintModuleMap() { }
+
void DisableCoreDumperIfNecessary() {
// Do nothing.
}
@@ -381,9 +426,6 @@ void ReExec() {
}
void PrepareForSandboxing(__sanitizer_sandbox_arguments *args) {
-#if !SANITIZER_GO
- CovPrepareForSandboxing(args);
-#endif
}
bool StackSizeIsUnlimited() {
@@ -423,8 +465,6 @@ u64 NanoTime() {
}
void Abort() {
- if (::IsDebuggerPresent())
- __debugbreak();
internal__exit(3);
}
@@ -482,7 +522,7 @@ static uptr GetPreferredBase(const char *modname) {
}
void ListOfModules::init() {
- clear();
+ clearOrInit();
HANDLE cur_process = GetCurrentProcess();
// Query the list of modules. Start by assuming there are no more than 256
@@ -536,11 +576,14 @@ void ListOfModules::init() {
LoadedModule cur_module;
cur_module.set(module_name, adjusted_base);
// We add the whole module as one single address range.
- cur_module.addAddressRange(base_address, end_address, /*executable*/ true);
+ cur_module.addAddressRange(base_address, end_address, /*executable*/ true,
+ /*writable*/ true);
modules_.push_back(cur_module);
}
UnmapOrDie(hmodules, modules_buffer_size);
-};
+}
+
+void ListOfModules::fallbackInit() { clear(); }
// We can't use atexit() directly at __asan_init time as the CRT is not fully
// initialized at this point. Place the functions into a vector and use
@@ -654,7 +697,13 @@ uptr internal_sched_yield() {
}
void internal__exit(int exitcode) {
- ExitProcess(exitcode);
+ // ExitProcess runs some finalizers, so use TerminateProcess to avoid that.
+ // The debugger doesn't stop on TerminateProcess like it does on ExitProcess,
+ // so add our own breakpoint here.
+ if (::IsDebuggerPresent())
+ __debugbreak();
+ TerminateProcess(GetCurrentProcess(), exitcode);
+ BUILTIN_UNREACHABLE();
}
uptr internal_ftruncate(fd_t fd, uptr size) {
@@ -776,8 +825,8 @@ void BufferedStackTrace::SlowUnwindStackWithContext(uptr pc, void *context,
stack_frame.AddrFrame.Mode = AddrModeFlat;
stack_frame.AddrStack.Mode = AddrModeFlat;
while (StackWalk64(machine_type, GetCurrentProcess(), GetCurrentThread(),
- &stack_frame, &ctx, NULL, &SymFunctionTableAccess64,
- &SymGetModuleBase64, NULL) &&
+ &stack_frame, &ctx, NULL, SymFunctionTableAccess64,
+ SymGetModuleBase64, NULL) &&
size < Min(max_depth, kStackTraceMax)) {
trace_buffer[size++] = (uptr)stack_frame.AddrPC.Offset;
}
@@ -808,8 +857,35 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) {
// FIXME: Decide what to do on Windows.
}
-bool IsHandledDeadlySignal(int signum) {
+HandleSignalMode GetHandleSignalMode(int signum) {
// FIXME: Decide what to do on Windows.
+ return kHandleSignalNo;
+}
+
+// Check based on flags if we should handle this exception.
+bool IsHandledDeadlyException(DWORD exceptionCode) {
+ switch (exceptionCode) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ case EXCEPTION_STACK_OVERFLOW:
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ case EXCEPTION_IN_PAGE_ERROR:
+ return common_flags()->handle_segv;
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ case EXCEPTION_PRIV_INSTRUCTION:
+ case EXCEPTION_BREAKPOINT:
+ return common_flags()->handle_sigill;
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ case EXCEPTION_FLT_OVERFLOW:
+ case EXCEPTION_FLT_STACK_CHECK:
+ case EXCEPTION_FLT_UNDERFLOW:
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ case EXCEPTION_INT_OVERFLOW:
+ return common_flags()->handle_sigfpe;
+ }
return false;
}
@@ -838,33 +914,99 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) {
return true;
}
-SignalContext SignalContext::Create(void *siginfo, void *context) {
+bool SignalContext::IsStackOverflow() const {
+ return GetType() == EXCEPTION_STACK_OVERFLOW;
+}
+
+void SignalContext::InitPcSpBp() {
EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
CONTEXT *context_record = (CONTEXT *)context;
- uptr pc = (uptr)exception_record->ExceptionAddress;
+ pc = (uptr)exception_record->ExceptionAddress;
#ifdef _WIN64
- uptr bp = (uptr)context_record->Rbp;
- uptr sp = (uptr)context_record->Rsp;
+ bp = (uptr)context_record->Rbp;
+ sp = (uptr)context_record->Rsp;
#else
- uptr bp = (uptr)context_record->Ebp;
- uptr sp = (uptr)context_record->Esp;
+ bp = (uptr)context_record->Ebp;
+ sp = (uptr)context_record->Esp;
#endif
- uptr access_addr = exception_record->ExceptionInformation[1];
+}
+uptr SignalContext::GetAddress() const {
+ EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
+ return exception_record->ExceptionInformation[1];
+}
+
+bool SignalContext::IsMemoryAccess() const {
+ return GetWriteFlag() != SignalContext::UNKNOWN;
+}
+
+SignalContext::WriteFlag SignalContext::GetWriteFlag() const {
+ EXCEPTION_RECORD *exception_record = (EXCEPTION_RECORD *)siginfo;
// The contents of this array are documented at
// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363082(v=vs.85).aspx
// The first element indicates read as 0, write as 1, or execute as 8. The
// second element is the faulting address.
- WriteFlag write_flag = SignalContext::UNKNOWN;
switch (exception_record->ExceptionInformation[0]) {
- case 0: write_flag = SignalContext::READ; break;
- case 1: write_flag = SignalContext::WRITE; break;
- case 8: write_flag = SignalContext::UNKNOWN; break;
+ case 0:
+ return SignalContext::READ;
+ case 1:
+ return SignalContext::WRITE;
+ case 8:
+ return SignalContext::UNKNOWN;
}
- bool is_memory_access = write_flag != SignalContext::UNKNOWN;
- return SignalContext(context, access_addr, pc, sp, bp, is_memory_access,
- write_flag);
+ return SignalContext::UNKNOWN;
+}
+
+void SignalContext::DumpAllRegisters(void *context) {
+ // FIXME: Implement this.
+}
+
+int SignalContext::GetType() const {
+ return static_cast<const EXCEPTION_RECORD *>(siginfo)->ExceptionCode;
+}
+
+const char *SignalContext::Describe() const {
+ unsigned code = GetType();
+ // Get the string description of the exception if this is a known deadly
+ // exception.
+ switch (code) {
+ case EXCEPTION_ACCESS_VIOLATION:
+ return "access-violation";
+ case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:
+ return "array-bounds-exceeded";
+ case EXCEPTION_STACK_OVERFLOW:
+ return "stack-overflow";
+ case EXCEPTION_DATATYPE_MISALIGNMENT:
+ return "datatype-misalignment";
+ case EXCEPTION_IN_PAGE_ERROR:
+ return "in-page-error";
+ case EXCEPTION_ILLEGAL_INSTRUCTION:
+ return "illegal-instruction";
+ case EXCEPTION_PRIV_INSTRUCTION:
+ return "priv-instruction";
+ case EXCEPTION_BREAKPOINT:
+ return "breakpoint";
+ case EXCEPTION_FLT_DENORMAL_OPERAND:
+ return "flt-denormal-operand";
+ case EXCEPTION_FLT_DIVIDE_BY_ZERO:
+ return "flt-divide-by-zero";
+ case EXCEPTION_FLT_INEXACT_RESULT:
+ return "flt-inexact-result";
+ case EXCEPTION_FLT_INVALID_OPERATION:
+ return "flt-invalid-operation";
+ case EXCEPTION_FLT_OVERFLOW:
+ return "flt-overflow";
+ case EXCEPTION_FLT_STACK_CHECK:
+ return "flt-stack-check";
+ case EXCEPTION_FLT_UNDERFLOW:
+ return "flt-underflow";
+ case EXCEPTION_INT_DIVIDE_BY_ZERO:
+ return "int-divide-by-zero";
+ case EXCEPTION_INT_OVERFLOW:
+ return "int-overflow";
+ }
+ return "unknown exception";
}
uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) {
@@ -910,21 +1052,15 @@ int WaitForProcess(pid_t pid) { return -1; }
// FIXME implement on this platform.
void GetMemoryProfile(fill_profile_f cb, uptr *stats, uptr stats_size) { }
+void CheckNoDeepBind(const char *filename, int flag) {
+ // Do nothing.
+}
-} // namespace __sanitizer
-
-#if !SANITIZER_GO
-// Workaround to implement weak hooks on Windows. COFF doesn't directly support
-// weak symbols, but it does support /alternatename, which is similar. If the
-// user does not override the hook, we will use this default definition instead
-// of null.
-extern "C" void __sanitizer_print_memory_profile(int top_percent) {}
+// FIXME: implement on this platform.
+bool GetRandom(void *buffer, uptr length, bool blocking) {
+ UNIMPLEMENTED();
+}
-#ifdef _WIN64
-#pragma comment(linker, "/alternatename:__sanitizer_print_memory_profile=__sanitizer_default_print_memory_profile") // NOLINT
-#else
-#pragma comment(linker, "/alternatename:___sanitizer_print_memory_profile=___sanitizer_default_print_memory_profile") // NOLINT
-#endif
-#endif
+} // namespace __sanitizer
#endif // _WIN32
diff --git a/libsanitizer/sanitizer_common/sanitizer_win.h b/libsanitizer/sanitizer_common/sanitizer_win.h
new file mode 100644
index 0000000..c2d53a4
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win.h
@@ -0,0 +1,24 @@
+//===-- sanitizer_win.h -----------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Windows-specific declarations.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_WIN_H
+#define SANITIZER_WIN_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+// Check based on flags if we should handle the exception.
+bool IsHandledDeadlyException(DWORD exceptionCode);
+} // namespace __sanitizer
+
+#endif // SANITIZER_WINDOWS
+#endif // SANITIZER_WIN_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_defs.h b/libsanitizer/sanitizer_common/sanitizer_win_defs.h
new file mode 100644
index 0000000..e71081d
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_defs.h
@@ -0,0 +1,151 @@
+//===-- sanitizer_win_defs.h ------------------------------------*- C++ -*-===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Common definitions for Windows-specific code.
+//
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_WIN_DEFS_H
+#define SANITIZER_WIN_DEFS_H
+
+#include "sanitizer_platform.h"
+#if SANITIZER_WINDOWS
+
+#ifndef WINAPI
+#ifdef _M_IX86
+#define WINAPI __stdcall
+#else
+#define WINAPI
+#endif
+#endif
+
+#if defined(_WIN64)
+#define WIN_SYM_PREFIX
+#else
+#define WIN_SYM_PREFIX "_"
+#endif
+
+// Intermediate macro to ensure the parameter is expanded before stringified.
+#define STRINGIFY_(A) #A
+#define STRINGIFY(A) STRINGIFY_(A)
+
+// ----------------- A workaround for the absence of weak symbols --------------
+// We don't have a direct equivalent of weak symbols when using MSVC, but we can
+// use the /alternatename directive to tell the linker to default a specific
+// symbol to a specific value.
+// Take into account that this is a pragma directive for the linker, so it will
+// be ignored by the compiler and the function will be marked as UNDEF in the
+// symbol table of the resulting object file. The linker won't find the default
+// implementation until it links with that object file.
+// So, suppose we provide a default implementation "fundef" for "fun", and this
+// is compiled into the object file "test.obj" including the pragma directive.
+// If we have some code with references to "fun" and we link that code with
+// "test.obj", it will work because the linker always link object files.
+// But, if "test.obj" is included in a static library, like "test.lib", then the
+// liker will only link to "test.obj" if necessary. If we only included the
+// definition of "fun", it won't link to "test.obj" (from test.lib) because
+// "fun" appears as UNDEF, so it doesn't resolve the symbol "fun", and will
+// result in a link error (the linker doesn't find the pragma directive).
+// So, a workaround is to force linkage with the modules that include weak
+// definitions, with the following macro: WIN_FORCE_LINK()
+
+#define WIN_WEAK_ALIAS(Name, Default) \
+ __pragma(comment(linker, "/alternatename:" WIN_SYM_PREFIX STRINGIFY(Name) "="\
+ WIN_SYM_PREFIX STRINGIFY(Default)))
+
+#define WIN_FORCE_LINK(Name) \
+ __pragma(comment(linker, "/include:" WIN_SYM_PREFIX STRINGIFY(Name)))
+
+#define WIN_EXPORT(ExportedName, Name) \
+ __pragma(comment(linker, "/export:" WIN_SYM_PREFIX STRINGIFY(ExportedName) \
+ "=" WIN_SYM_PREFIX STRINGIFY(Name)))
+
+// We cannot define weak functions on Windows, but we can use WIN_WEAK_ALIAS()
+// which defines an alias to a default implementation, and only works when
+// linking statically.
+// So, to define a weak function "fun", we define a default implementation with
+// a different name "fun__def" and we create a "weak alias" fun = fun__def.
+// Then, users can override it just defining "fun".
+// We impose "extern "C"" because otherwise WIN_WEAK_ALIAS() will fail because
+// of name mangling.
+
+// Dummy name for default implementation of weak function.
+# define WEAK_DEFAULT_NAME(Name) Name##__def
+// Name for exported implementation of weak function.
+# define WEAK_EXPORT_NAME(Name) Name##__dll
+
+// Use this macro when you need to define and export a weak function from a
+// library. For example:
+// WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; }
+# define WIN_WEAK_EXPORT_DEF(ReturnType, Name, ...) \
+ WIN_WEAK_ALIAS(Name, WEAK_DEFAULT_NAME(Name)) \
+ WIN_EXPORT(WEAK_EXPORT_NAME(Name), Name) \
+ extern "C" ReturnType Name(__VA_ARGS__); \
+ extern "C" ReturnType WEAK_DEFAULT_NAME(Name)(__VA_ARGS__)
+
+// Use this macro when you need to import a weak function from a library. It
+// defines a weak alias to the imported function from the dll. For example:
+// WIN_WEAK_IMPORT_DEF(compare)
+# define WIN_WEAK_IMPORT_DEF(Name) \
+ WIN_WEAK_ALIAS(Name, WEAK_EXPORT_NAME(Name))
+
+// So, for Windows we provide something similar to weak symbols in Linux, with
+// some differences:
+// + A default implementation must always be provided.
+//
+// + When linking statically it works quite similarly. For example:
+//
+// // libExample.cc
+// WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; }
+//
+// // client.cc
+// // We can use the default implementation from the library:
+// compare(1, 2);
+// // Or we can override it:
+// extern "C" bool compare (int a, int b) { return a >= b; }
+//
+// And it will work fine. If we don't override the function, we need to ensure
+// that the linker includes the object file with the default implementation.
+// We can do so with the linker option "-wholearchive:".
+//
+// + When linking dynamically with a library (dll), weak functions are exported
+// with "__dll" suffix. Clients can use the macro WIN_WEAK_IMPORT_DEF(fun)
+// which defines a "weak alias" fun = fun__dll.
+//
+// // libExample.cc
+// WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; }
+//
+// // client.cc
+// WIN_WEAK_IMPORT_DEF(compare)
+// // We can use the default implementation from the library:
+// compare(1, 2);
+// // Or we can override it:
+// extern "C" bool compare (int a, int b) { return a >= b; }
+//
+// But if we override the function, the dlls don't have access to it (which
+// is different in linux). If that is desired, the strong definition must be
+// exported and interception can be used from the rest of the dlls.
+//
+// // libExample.cc
+// WIN_WEAK_EXPORT_DEF(bool, compare, int a, int b) { return a > b; }
+// // When initialized, check if the main executable defined "compare".
+// int libExample_init() {
+// uptr fnptr = __interception::InternalGetProcAddress(
+// (void *)GetModuleHandleA(0), "compare");
+// if (fnptr && !__interception::OverrideFunction((uptr)compare, fnptr, 0))
+// abort();
+// return 0;
+// }
+//
+// // client.cc
+// WIN_WEAK_IMPORT_DEF(compare)
+// // We override and export compare:
+// extern "C" __declspec(dllexport) bool compare (int a, int b) {
+// return a >= b;
+// }
+//
+#endif // SANITIZER_WINDOWS
+#endif // SANITIZER_WIN_DEFS_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cc b/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cc
new file mode 100644
index 0000000..6577a36
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.cc
@@ -0,0 +1,100 @@
+//===-- sanitizer_win_dll_thunk.cc ----------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This file defines a family of thunks that should be statically linked into
+// the DLLs that have instrumentation in order to delegate the calls to the
+// shared runtime that lives in the main binary.
+// See https://github.com/google/sanitizers/issues/209 for the details.
+//===----------------------------------------------------------------------===//
+
+#ifdef SANITIZER_DLL_THUNK
+#include "sanitizer_win_defs.h"
+#include "sanitizer_win_dll_thunk.h"
+#include "interception/interception.h"
+
+extern "C" {
+void *WINAPI GetModuleHandleA(const char *module_name);
+void abort();
+}
+
+namespace __sanitizer {
+uptr dllThunkGetRealAddrOrDie(const char *name) {
+ uptr ret =
+ __interception::InternalGetProcAddress((void *)GetModuleHandleA(0), name);
+ if (!ret)
+ abort();
+ return ret;
+}
+
+int dllThunkIntercept(const char* main_function, uptr dll_function) {
+ uptr wrapper = dllThunkGetRealAddrOrDie(main_function);
+ if (!__interception::OverrideFunction(dll_function, wrapper, 0))
+ abort();
+ return 0;
+}
+
+int dllThunkInterceptWhenPossible(const char* main_function,
+ const char* default_function, uptr dll_function) {
+ uptr wrapper = __interception::InternalGetProcAddress(
+ (void *)GetModuleHandleA(0), main_function);
+ if (!wrapper)
+ wrapper = dllThunkGetRealAddrOrDie(default_function);
+ if (!__interception::OverrideFunction(dll_function, wrapper, 0))
+ abort();
+ return 0;
+}
+} // namespace __sanitizer
+
+// Include Sanitizer Common interface.
+#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
+#include "sanitizer_common_interface.inc"
+
+#pragma section(".DLLTH$A", read) // NOLINT
+#pragma section(".DLLTH$Z", read) // NOLINT
+
+typedef void (*DllThunkCB)();
+extern "C" {
+__declspec(allocate(".DLLTH$A")) DllThunkCB __start_dll_thunk;
+__declspec(allocate(".DLLTH$Z")) DllThunkCB __stop_dll_thunk;
+}
+
+// Disable compiler warnings that show up if we declare our own version
+// of a compiler intrinsic (e.g. strlen).
+#pragma warning(disable: 4391)
+#pragma warning(disable: 4392)
+
+extern "C" int __dll_thunk_init() {
+ static bool flag = false;
+ // __dll_thunk_init is expected to be called by only one thread.
+ if (flag) return 0;
+ flag = true;
+
+ for (DllThunkCB *it = &__start_dll_thunk; it < &__stop_dll_thunk; ++it)
+ if (*it)
+ (*it)();
+
+ // In DLLs, the callbacks are expected to return 0,
+ // otherwise CRT initialization fails.
+ return 0;
+}
+
+// We want to call dll_thunk_init before C/C++ initializers / constructors are
+// executed, otherwise functions like memset might be invoked.
+#pragma section(".CRT$XIB", long, read) // NOLINT
+__declspec(allocate(".CRT$XIB")) int (*__dll_thunk_preinit)() =
+ __dll_thunk_init;
+
+static void WINAPI dll_thunk_thread_init(void *mod, unsigned long reason,
+ void *reserved) {
+ if (reason == /*DLL_PROCESS_ATTACH=*/1) __dll_thunk_init();
+}
+
+#pragma section(".CRT$XLAB", long, read) // NOLINT
+__declspec(allocate(".CRT$XLAB")) void (WINAPI *__dll_thunk_tls_init)(void *,
+ unsigned long, void *) = dll_thunk_thread_init;
+
+#endif // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h b/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h
new file mode 100644
index 0000000..5a475e0
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_dll_thunk.h
@@ -0,0 +1,180 @@
+//===-- sanitizer_win_dll_thunk.h -----------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This header provide helper macros to delegate calls to the shared runtime
+// that lives in the main executable. It should be included to dll_thunks that
+// will be linked to the dlls, when the sanitizer is a static library included
+// in the main executable.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_WIN_DLL_THUNK_H
+#define SANITIZER_WIN_DLL_THUNK_H
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+uptr dllThunkGetRealAddrOrDie(const char *name);
+
+int dllThunkIntercept(const char* main_function, uptr dll_function);
+
+int dllThunkInterceptWhenPossible(const char* main_function,
+ const char* default_function, uptr dll_function);
+}
+
+extern "C" int __dll_thunk_init();
+
+// ----------------- Function interception helper macros -------------------- //
+// Override dll_function with main_function from main executable.
+#define INTERCEPT_OR_DIE(main_function, dll_function) \
+ static int intercept_##dll_function() { \
+ return __sanitizer::dllThunkIntercept(main_function, (__sanitizer::uptr) \
+ dll_function); \
+ } \
+ __pragma(section(".DLLTH$M", long, read)) \
+ __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \
+ intercept_##dll_function;
+
+// Try to override dll_function with main_function from main executable.
+// If main_function is not present, override dll_function with default_function.
+#define INTERCEPT_WHEN_POSSIBLE(main_function, default_function, dll_function) \
+ static int intercept_##dll_function() { \
+ return __sanitizer::dllThunkInterceptWhenPossible(main_function, \
+ default_function, (__sanitizer::uptr)dll_function); \
+ } \
+ __pragma(section(".DLLTH$M", long, read)) \
+ __declspec(allocate(".DLLTH$M")) int (*__dll_thunk_##dll_function)() = \
+ intercept_##dll_function;
+
+// -------------------- Function interception macros ------------------------ //
+// Special case of hooks -- ASan own interface functions. Those are only called
+// after __asan_init, thus an empty implementation is sufficient.
+#define INTERCEPT_SANITIZER_FUNCTION(name) \
+ extern "C" __declspec(noinline) void name() { \
+ volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \
+ static const char function_name[] = #name; \
+ for (const char* ptr = &function_name[0]; *ptr; ++ptr) \
+ prevent_icf ^= *ptr; \
+ (void)prevent_icf; \
+ __debugbreak(); \
+ } \
+ INTERCEPT_OR_DIE(#name, name)
+
+// Special case of hooks -- Weak functions, could be redefined in the main
+// executable, but that is not necessary, so we shouldn't die if we can not find
+// a reference. Instead, when the function is not present in the main executable
+// we consider the default impl provided by asan library.
+#define INTERCEPT_SANITIZER_WEAK_FUNCTION(name) \
+ extern "C" __declspec(noinline) void name() { \
+ volatile int prevent_icf = (__LINE__ << 8) ^ __COUNTER__; \
+ static const char function_name[] = #name; \
+ for (const char* ptr = &function_name[0]; *ptr; ++ptr) \
+ prevent_icf ^= *ptr; \
+ (void)prevent_icf; \
+ __debugbreak(); \
+ } \
+ INTERCEPT_WHEN_POSSIBLE(#name, STRINGIFY(WEAK_EXPORT_NAME(name)), name)
+
+// We can't define our own version of strlen etc. because that would lead to
+// link-time or even type mismatch errors. Instead, we can declare a function
+// just to be able to get its address. Me may miss the first few calls to the
+// functions since it can be called before __dll_thunk_init, but that would lead
+// to false negatives in the startup code before user's global initializers,
+// which isn't a big deal.
+#define INTERCEPT_LIBRARY_FUNCTION(name) \
+ extern "C" void name(); \
+ INTERCEPT_OR_DIE(WRAPPER_NAME(name), name)
+
+// Use these macros for functions that could be called before __dll_thunk_init()
+// is executed and don't lead to errors if defined (free, malloc, etc).
+#define INTERCEPT_WRAP_V_V(name) \
+ extern "C" void name() { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ fn(); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_V_W(name) \
+ extern "C" void name(void *arg) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ fn(arg); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_V_WW(name) \
+ extern "C" void name(void *arg1, void *arg2) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ fn(arg1, arg2); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_V_WWW(name) \
+ extern "C" void name(void *arg1, void *arg2, void *arg3) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_W_V(name) \
+ extern "C" void *name() { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ return fn(); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_W_W(name) \
+ extern "C" void *name(void *arg) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ return fn(arg); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_W_WW(name) \
+ extern "C" void *name(void *arg1, void *arg2) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ return fn(arg1, arg2); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_W_WWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ return fn(arg1, arg2, arg3); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_W_WWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_W_WWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#define INTERCEPT_WRAP_W_WWWWWW(name) \
+ extern "C" void *name(void *arg1, void *arg2, void *arg3, void *arg4, \
+ void *arg5, void *arg6) { \
+ typedef decltype(name) *fntype; \
+ static fntype fn = (fntype)__sanitizer::dllThunkGetRealAddrOrDie(#name); \
+ return fn(arg1, arg2, arg3, arg4, arg5, arg6); \
+ } \
+ INTERCEPT_OR_DIE(#name, name);
+
+#endif // SANITIZER_WIN_DLL_THUNK_H
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cc b/libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cc
new file mode 100644
index 0000000..f3b3037
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_dynamic_runtime_thunk.cc
@@ -0,0 +1,19 @@
+//===-- santizer_win_dynamic_runtime_thunk.cc -----------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines things that need to be present in the application modules
+// to interact with Sanitizer Common, when it is included in a dll.
+//
+//===----------------------------------------------------------------------===//
+#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
+#define SANITIZER_IMPORT_INTERFACE 1
+#include "sanitizer_win_defs.h"
+// Define weak alias for all weak functions imported from sanitizer common.
+#define INTERFACE_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
+#include "sanitizer_common_interface.inc"
+#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cc b/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cc
new file mode 100644
index 0000000..dffec0c
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.cc
@@ -0,0 +1,92 @@
+//===-- sanitizer_win_weak_interception.cc --------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This module should be included in the sanitizer when it is implemented as a
+// shared library on Windows (dll), in order to delegate the calls of weak
+// functions to the implementation in the main executable when a strong
+// definition is provided.
+//===----------------------------------------------------------------------===//
+
+#include "sanitizer_common/sanitizer_platform.h"
+#if SANITIZER_WINDOWS && SANITIZER_DYNAMIC
+#include "sanitizer_win_weak_interception.h"
+#include "sanitizer_allocator_interface.h"
+#include "sanitizer_interface_internal.h"
+#include "sanitizer_win_defs.h"
+#include "interception/interception.h"
+
+extern "C" {
+void *WINAPI GetModuleHandleA(const char *module_name);
+void abort();
+}
+
+namespace __sanitizer {
+// Try to get a pointer to real_function in the main module and override
+// dll_function with that pointer. If the function isn't found, nothing changes.
+int interceptWhenPossible(uptr dll_function, const char *real_function) {
+ uptr real = __interception::InternalGetProcAddress(
+ (void *)GetModuleHandleA(0), real_function);
+ if (real && !__interception::OverrideFunction((uptr)dll_function, real, 0))
+ abort();
+ return 0;
+}
+} // namespace __sanitizer
+
+// Declare weak hooks.
+extern "C" {
+void __sanitizer_weak_hook_memcmp(uptr called_pc, const void *s1,
+ const void *s2, uptr n, int result);
+void __sanitizer_weak_hook_strcmp(uptr called_pc, const char *s1,
+ const char *s2, int result);
+void __sanitizer_weak_hook_strncmp(uptr called_pc, const char *s1,
+ const char *s2, uptr n, int result);
+void __sanitizer_weak_hook_strstr(uptr called_pc, const char *s1,
+ const char *s2, char *result);
+}
+
+// Include Sanitizer Common interface.
+#define INTERFACE_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
+#include "sanitizer_common_interface.inc"
+
+#pragma section(".WEAK$A", read) // NOLINT
+#pragma section(".WEAK$Z", read) // NOLINT
+
+typedef void (*InterceptCB)();
+extern "C" {
+__declspec(allocate(".WEAK$A")) InterceptCB __start_weak_list;
+__declspec(allocate(".WEAK$Z")) InterceptCB __stop_weak_list;
+}
+
+static int weak_intercept_init() {
+ static bool flag = false;
+ // weak_interception_init is expected to be called by only one thread.
+ if (flag) return 0;
+ flag = true;
+
+ for (InterceptCB *it = &__start_weak_list; it < &__stop_weak_list; ++it)
+ if (*it)
+ (*it)();
+
+ // In DLLs, the callbacks are expected to return 0,
+ // otherwise CRT initialization fails.
+ return 0;
+}
+
+#pragma section(".CRT$XIB", long, read) // NOLINT
+__declspec(allocate(".CRT$XIB")) int (*__weak_intercept_preinit)() =
+ weak_intercept_init;
+
+static void WINAPI weak_intercept_thread_init(void *mod, unsigned long reason,
+ void *reserved) {
+ if (reason == /*DLL_PROCESS_ATTACH=*/1) weak_intercept_init();
+}
+
+#pragma section(".CRT$XLAB", long, read) // NOLINT
+__declspec(allocate(".CRT$XLAB")) void(WINAPI *__weak_intercept_tls_init)(
+ void *, unsigned long, void *) = weak_intercept_thread_init;
+
+#endif // SANITIZER_WINDOWS && SANITIZER_DYNAMIC
diff --git a/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h b/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h
new file mode 100644
index 0000000..873f9b8
--- /dev/null
+++ b/libsanitizer/sanitizer_common/sanitizer_win_weak_interception.h
@@ -0,0 +1,31 @@
+//===-- sanitizer_win_weak_interception.h ---------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This header provide helper macros to delegate calls of weak functions to the
+// implementation in the main executable when a strong definition is present.
+//===----------------------------------------------------------------------===//
+#ifndef SANITIZER_WIN_WEAK_INTERCEPTION_H
+#define SANITIZER_WIN_WEAK_INTERCEPTION_H
+#include "sanitizer_internal_defs.h"
+
+namespace __sanitizer {
+int interceptWhenPossible(uptr dll_function, const char *real_function);
+}
+
+// ----------------- Function interception helper macros -------------------- //
+// Weak functions, could be redefined in the main executable, but that is not
+// necessary, so we shouldn't die if we can not find a reference.
+#define INTERCEPT_WEAK(Name) interceptWhenPossible((uptr) Name, #Name);
+
+#define INTERCEPT_SANITIZER_WEAK_FUNCTION(Name) \
+ static int intercept_##Name() { \
+ return __sanitizer::interceptWhenPossible((__sanitizer::uptr) Name, #Name);\
+ } \
+ __pragma(section(".WEAK$M", long, read)) \
+ __declspec(allocate(".WEAK$M")) int (*__weak_intercept_##Name)() = \
+ intercept_##Name;
+
+#endif // SANITIZER_WIN_WEAK_INTERCEPTION_H
diff --git a/libsanitizer/tsan/Makefile.am b/libsanitizer/tsan/Makefile.am
index 53a8d1c..c218983 100644
--- a/libsanitizer/tsan/Makefile.am
+++ b/libsanitizer/tsan/Makefile.am
@@ -15,6 +15,7 @@ nodist_toolexeclib_HEADERS = libtsan_preinit.o
tsan_files = \
tsan_clock.cc \
tsan_debugging.cc \
+ tsan_external.cc \
tsan_fd.cc \
tsan_flags.cc \
tsan_ignoreset.cc \
diff --git a/libsanitizer/tsan/Makefile.in b/libsanitizer/tsan/Makefile.in
index 770c053..e32e9c0 100644
--- a/libsanitizer/tsan/Makefile.in
+++ b/libsanitizer/tsan/Makefile.in
@@ -106,18 +106,19 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)" \
"$(DESTDIR)$(toolexeclibdir)"
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
am__DEPENDENCIES_1 =
-am__objects_1 = tsan_clock.lo tsan_debugging.lo tsan_fd.lo \
- tsan_flags.lo tsan_ignoreset.lo tsan_interceptors.lo \
- tsan_interceptors_mac.lo tsan_interface_ann.lo \
- tsan_interface_atomic.lo tsan_interface.lo \
- tsan_interface_java.lo tsan_libdispatch_mac.lo \
- tsan_malloc_mac.lo tsan_md5.lo tsan_mman.lo tsan_mutex.lo \
- tsan_mutexset.lo tsan_new_delete.lo tsan_platform_linux.lo \
- tsan_platform_mac.lo tsan_platform_posix.lo \
- tsan_platform_windows.lo tsan_report.lo tsan_rtl.lo \
- tsan_rtl_mutex.lo tsan_rtl_proc.lo tsan_rtl_report.lo \
- tsan_rtl_thread.lo tsan_stack_trace.lo tsan_stat.lo \
- tsan_suppressions.lo tsan_symbolize.lo tsan_sync.lo
+am__objects_1 = tsan_clock.lo tsan_debugging.lo tsan_external.lo \
+ tsan_fd.lo tsan_flags.lo tsan_ignoreset.lo \
+ tsan_interceptors.lo tsan_interceptors_mac.lo \
+ tsan_interface_ann.lo tsan_interface_atomic.lo \
+ tsan_interface.lo tsan_interface_java.lo \
+ tsan_libdispatch_mac.lo tsan_malloc_mac.lo tsan_md5.lo \
+ tsan_mman.lo tsan_mutex.lo tsan_mutexset.lo tsan_new_delete.lo \
+ tsan_platform_linux.lo tsan_platform_mac.lo \
+ tsan_platform_posix.lo tsan_platform_windows.lo tsan_report.lo \
+ tsan_rtl.lo tsan_rtl_mutex.lo tsan_rtl_proc.lo \
+ tsan_rtl_report.lo tsan_rtl_thread.lo tsan_stack_trace.lo \
+ tsan_stat.lo tsan_suppressions.lo tsan_symbolize.lo \
+ tsan_sync.lo
am_libtsan_la_OBJECTS = $(am__objects_1)
libtsan_la_OBJECTS = $(am_libtsan_la_OBJECTS)
libtsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -319,6 +320,7 @@ nodist_toolexeclib_HEADERS = libtsan_preinit.o
tsan_files = \
tsan_clock.cc \
tsan_debugging.cc \
+ tsan_external.cc \
tsan_fd.cc \
tsan_flags.cc \
tsan_ignoreset.cc \
@@ -480,6 +482,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_clock.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_debugging.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_external.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_fd.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_flags.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsan_ignoreset.Plo@am__quote@
diff --git a/libsanitizer/tsan/tsan_clock.cc b/libsanitizer/tsan/tsan_clock.cc
index 23f9228a..c2b5b58 100644
--- a/libsanitizer/tsan/tsan_clock.cc
+++ b/libsanitizer/tsan/tsan_clock.cc
@@ -59,20 +59,13 @@
// an exclusive lock; ThreadClock's are private to respective threads and so
// do not need any protection.
//
-// Description of ThreadClock state:
-// clk_ - fixed size vector clock.
-// nclk_ - effective size of the vector clock (the rest is zeros).
-// tid_ - index of the thread associated with he clock ("current thread").
-// last_acquire_ - current thread time when it acquired something from
-// other threads.
-//
// Description of SyncClock state:
// clk_ - variable size vector clock, low kClkBits hold timestamp,
// the remaining bits hold "acquired" flag (the actual value is thread's
// reused counter);
// if acquried == thr->reused_, then the respective thread has already
-// acquired this clock (except possibly dirty_tids_).
-// dirty_tids_ - holds up to two indeces in the vector clock that other threads
+// acquired this clock (except possibly for dirty elements).
+// dirty_ - holds up to two indeces in the vector clock that other threads
// need to acquire regardless of "acquired" flag value;
// release_store_tid_ - denotes that the clock state is a result of
// release-store operation by the thread with release_store_tid_ index.
@@ -88,18 +81,51 @@
namespace __tsan {
+static atomic_uint32_t *ref_ptr(ClockBlock *cb) {
+ return reinterpret_cast<atomic_uint32_t *>(&cb->table[ClockBlock::kRefIdx]);
+}
+
+// Drop reference to the first level block idx.
+static void UnrefClockBlock(ClockCache *c, u32 idx, uptr blocks) {
+ ClockBlock *cb = ctx->clock_alloc.Map(idx);
+ atomic_uint32_t *ref = ref_ptr(cb);
+ u32 v = atomic_load(ref, memory_order_acquire);
+ for (;;) {
+ CHECK_GT(v, 0);
+ if (v == 1)
+ break;
+ if (atomic_compare_exchange_strong(ref, &v, v - 1, memory_order_acq_rel))
+ return;
+ }
+ // First level block owns second level blocks, so them as well.
+ for (uptr i = 0; i < blocks; i++)
+ ctx->clock_alloc.Free(c, cb->table[ClockBlock::kBlockIdx - i]);
+ ctx->clock_alloc.Free(c, idx);
+}
+
ThreadClock::ThreadClock(unsigned tid, unsigned reused)
: tid_(tid)
- , reused_(reused + 1) { // 0 has special meaning
+ , reused_(reused + 1) // 0 has special meaning
+ , cached_idx_()
+ , cached_size_()
+ , cached_blocks_() {
CHECK_LT(tid, kMaxTidInClock);
CHECK_EQ(reused_, ((u64)reused_ << kClkBits) >> kClkBits);
nclk_ = tid_ + 1;
last_acquire_ = 0;
internal_memset(clk_, 0, sizeof(clk_));
- clk_[tid_].reused = reused_;
}
-void ThreadClock::acquire(ClockCache *c, const SyncClock *src) {
+void ThreadClock::ResetCached(ClockCache *c) {
+ if (cached_idx_) {
+ UnrefClockBlock(c, cached_idx_, cached_blocks_);
+ cached_idx_ = 0;
+ cached_size_ = 0;
+ cached_blocks_ = 0;
+ }
+}
+
+void ThreadClock::acquire(ClockCache *c, SyncClock *src) {
DCHECK_LE(nclk_, kMaxTid);
DCHECK_LE(src->size_, kMaxTid);
CPP_STAT_INC(StatClockAcquire);
@@ -111,52 +137,46 @@ void ThreadClock::acquire(ClockCache *c, const SyncClock *src) {
return;
}
- // Check if we've already acquired src after the last release operation on src
bool acquired = false;
- if (nclk > tid_) {
- CPP_STAT_INC(StatClockAcquireLarge);
- if (src->elem(tid_).reused == reused_) {
- CPP_STAT_INC(StatClockAcquireRepeat);
- for (unsigned i = 0; i < kDirtyTids; i++) {
- unsigned tid = src->dirty_tids_[i];
- if (tid != kInvalidTid) {
- u64 epoch = src->elem(tid).epoch;
- if (clk_[tid].epoch < epoch) {
- clk_[tid].epoch = epoch;
- acquired = true;
- }
- }
- }
- if (acquired) {
- CPP_STAT_INC(StatClockAcquiredSomething);
- last_acquire_ = clk_[tid_].epoch;
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ SyncClock::Dirty dirty = src->dirty_[i];
+ unsigned tid = dirty.tid;
+ if (tid != kInvalidTid) {
+ if (clk_[tid] < dirty.epoch) {
+ clk_[tid] = dirty.epoch;
+ acquired = true;
}
- return;
}
}
- // O(N) acquire.
- CPP_STAT_INC(StatClockAcquireFull);
- nclk_ = max(nclk_, nclk);
- for (uptr i = 0; i < nclk; i++) {
- u64 epoch = src->elem(i).epoch;
- if (clk_[i].epoch < epoch) {
- clk_[i].epoch = epoch;
- acquired = true;
+ // Check if we've already acquired src after the last release operation on src
+ if (tid_ >= nclk || src->elem(tid_).reused != reused_) {
+ // O(N) acquire.
+ CPP_STAT_INC(StatClockAcquireFull);
+ nclk_ = max(nclk_, nclk);
+ u64 *dst_pos = &clk_[0];
+ for (ClockElem &src_elem : *src) {
+ u64 epoch = src_elem.epoch;
+ if (*dst_pos < epoch) {
+ *dst_pos = epoch;
+ acquired = true;
+ }
+ dst_pos++;
}
- }
- // Remember that this thread has acquired this clock.
- if (nclk > tid_)
- src->elem(tid_).reused = reused_;
+ // Remember that this thread has acquired this clock.
+ if (nclk > tid_)
+ src->elem(tid_).reused = reused_;
+ }
if (acquired) {
CPP_STAT_INC(StatClockAcquiredSomething);
- last_acquire_ = clk_[tid_].epoch;
+ last_acquire_ = clk_[tid_];
+ ResetCached(c);
}
}
-void ThreadClock::release(ClockCache *c, SyncClock *dst) const {
+void ThreadClock::release(ClockCache *c, SyncClock *dst) {
DCHECK_LE(nclk_, kMaxTid);
DCHECK_LE(dst->size_, kMaxTid);
@@ -176,7 +196,7 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) const {
// since the last release on dst. If so, we need to update
// only dst->elem(tid_).
if (dst->elem(tid_).epoch > last_acquire_) {
- UpdateCurrentThread(dst);
+ UpdateCurrentThread(c, dst);
if (dst->release_store_tid_ != tid_ ||
dst->release_store_reused_ != reused_)
dst->release_store_tid_ = kInvalidTid;
@@ -185,23 +205,24 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) const {
// O(N) release.
CPP_STAT_INC(StatClockReleaseFull);
+ dst->Unshare(c);
// First, remember whether we've acquired dst.
bool acquired = IsAlreadyAcquired(dst);
if (acquired)
CPP_STAT_INC(StatClockReleaseAcquired);
// Update dst->clk_.
- for (uptr i = 0; i < nclk_; i++) {
- ClockElem &ce = dst->elem(i);
- ce.epoch = max(ce.epoch, clk_[i].epoch);
+ dst->FlushDirty();
+ uptr i = 0;
+ for (ClockElem &ce : *dst) {
+ ce.epoch = max(ce.epoch, clk_[i]);
ce.reused = 0;
+ i++;
}
// Clear 'acquired' flag in the remaining elements.
if (nclk_ < dst->size_)
CPP_STAT_INC(StatClockReleaseClearTail);
for (uptr i = nclk_; i < dst->size_; i++)
dst->elem(i).reused = 0;
- for (unsigned i = 0; i < kDirtyTids; i++)
- dst->dirty_tids_[i] = kInvalidTid;
dst->release_store_tid_ = kInvalidTid;
dst->release_store_reused_ = 0;
// If we've acquired dst, remember this fact,
@@ -210,11 +231,37 @@ void ThreadClock::release(ClockCache *c, SyncClock *dst) const {
dst->elem(tid_).reused = reused_;
}
-void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) const {
+void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) {
DCHECK_LE(nclk_, kMaxTid);
DCHECK_LE(dst->size_, kMaxTid);
CPP_STAT_INC(StatClockStore);
+ if (dst->size_ == 0 && cached_idx_ != 0) {
+ // Reuse the cached clock.
+ // Note: we could reuse/cache the cached clock in more cases:
+ // we could update the existing clock and cache it, or replace it with the
+ // currently cached clock and release the old one. And for a shared
+ // existing clock, we could replace it with the currently cached;
+ // or unshare, update and cache. But, for simplicity, we currnetly reuse
+ // cached clock only when the target clock is empty.
+ dst->tab_ = ctx->clock_alloc.Map(cached_idx_);
+ dst->tab_idx_ = cached_idx_;
+ dst->size_ = cached_size_;
+ dst->blocks_ = cached_blocks_;
+ CHECK_EQ(dst->dirty_[0].tid, kInvalidTid);
+ // The cached clock is shared (immutable),
+ // so this is where we store the current clock.
+ dst->dirty_[0].tid = tid_;
+ dst->dirty_[0].epoch = clk_[tid_];
+ dst->release_store_tid_ = tid_;
+ dst->release_store_reused_ = reused_;
+ // Rememeber that we don't need to acquire it in future.
+ dst->elem(tid_).reused = reused_;
+ // Grab a reference.
+ atomic_fetch_add(ref_ptr(dst->tab_), 1, memory_order_relaxed);
+ return;
+ }
+
// Check if we need to resize dst.
if (dst->size_ < nclk_)
dst->Resize(c, nclk_);
@@ -223,32 +270,41 @@ void ThreadClock::ReleaseStore(ClockCache *c, SyncClock *dst) const {
dst->release_store_reused_ == reused_ &&
dst->elem(tid_).epoch > last_acquire_) {
CPP_STAT_INC(StatClockStoreFast);
- UpdateCurrentThread(dst);
+ UpdateCurrentThread(c, dst);
return;
}
// O(N) release-store.
CPP_STAT_INC(StatClockStoreFull);
- for (uptr i = 0; i < nclk_; i++) {
- ClockElem &ce = dst->elem(i);
- ce.epoch = clk_[i].epoch;
+ dst->Unshare(c);
+ // Note: dst can be larger than this ThreadClock.
+ // This is fine since clk_ beyond size is all zeros.
+ uptr i = 0;
+ for (ClockElem &ce : *dst) {
+ ce.epoch = clk_[i];
ce.reused = 0;
+ i++;
}
- // Clear the tail of dst->clk_.
- if (nclk_ < dst->size_) {
- for (uptr i = nclk_; i < dst->size_; i++) {
- ClockElem &ce = dst->elem(i);
- ce.epoch = 0;
- ce.reused = 0;
- }
- CPP_STAT_INC(StatClockStoreTail);
- }
- for (unsigned i = 0; i < kDirtyTids; i++)
- dst->dirty_tids_[i] = kInvalidTid;
+ for (uptr i = 0; i < kDirtyTids; i++)
+ dst->dirty_[i].tid = kInvalidTid;
dst->release_store_tid_ = tid_;
dst->release_store_reused_ = reused_;
// Rememeber that we don't need to acquire it in future.
dst->elem(tid_).reused = reused_;
+
+ // If the resulting clock is cachable, cache it for future release operations.
+ // The clock is always cachable if we released to an empty sync object.
+ if (cached_idx_ == 0 && dst->Cachable()) {
+ // Grab a reference to the ClockBlock.
+ atomic_uint32_t *ref = ref_ptr(dst->tab_);
+ if (atomic_load(ref, memory_order_acquire) == 1)
+ atomic_store_relaxed(ref, 2);
+ else
+ atomic_fetch_add(ref_ptr(dst->tab_), 1, memory_order_relaxed);
+ cached_idx_ = dst->tab_idx_;
+ cached_size_ = dst->size_;
+ cached_blocks_ = dst->blocks_;
+ }
}
void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) {
@@ -258,157 +314,248 @@ void ThreadClock::acq_rel(ClockCache *c, SyncClock *dst) {
}
// Updates only single element related to the current thread in dst->clk_.
-void ThreadClock::UpdateCurrentThread(SyncClock *dst) const {
+void ThreadClock::UpdateCurrentThread(ClockCache *c, SyncClock *dst) const {
// Update the threads time, but preserve 'acquired' flag.
- dst->elem(tid_).epoch = clk_[tid_].epoch;
-
for (unsigned i = 0; i < kDirtyTids; i++) {
- if (dst->dirty_tids_[i] == tid_) {
- CPP_STAT_INC(StatClockReleaseFast1);
- return;
- }
- if (dst->dirty_tids_[i] == kInvalidTid) {
- CPP_STAT_INC(StatClockReleaseFast2);
- dst->dirty_tids_[i] = tid_;
+ SyncClock::Dirty *dirty = &dst->dirty_[i];
+ const unsigned tid = dirty->tid;
+ if (tid == tid_ || tid == kInvalidTid) {
+ CPP_STAT_INC(StatClockReleaseFast);
+ dirty->tid = tid_;
+ dirty->epoch = clk_[tid_];
return;
}
}
// Reset all 'acquired' flags, O(N).
+ // We are going to touch dst elements, so we need to unshare it.
+ dst->Unshare(c);
CPP_STAT_INC(StatClockReleaseSlow);
+ dst->elem(tid_).epoch = clk_[tid_];
for (uptr i = 0; i < dst->size_; i++)
dst->elem(i).reused = 0;
- for (unsigned i = 0; i < kDirtyTids; i++)
- dst->dirty_tids_[i] = kInvalidTid;
+ dst->FlushDirty();
}
-// Checks whether the current threads has already acquired src.
+// Checks whether the current thread has already acquired src.
bool ThreadClock::IsAlreadyAcquired(const SyncClock *src) const {
if (src->elem(tid_).reused != reused_)
return false;
for (unsigned i = 0; i < kDirtyTids; i++) {
- unsigned tid = src->dirty_tids_[i];
- if (tid != kInvalidTid) {
- if (clk_[tid].epoch < src->elem(tid).epoch)
+ SyncClock::Dirty dirty = src->dirty_[i];
+ if (dirty.tid != kInvalidTid) {
+ if (clk_[dirty.tid] < dirty.epoch)
return false;
}
}
return true;
}
+// Sets a single element in the vector clock.
+// This function is called only from weird places like AcquireGlobal.
+void ThreadClock::set(ClockCache *c, unsigned tid, u64 v) {
+ DCHECK_LT(tid, kMaxTid);
+ DCHECK_GE(v, clk_[tid]);
+ clk_[tid] = v;
+ if (nclk_ <= tid)
+ nclk_ = tid + 1;
+ last_acquire_ = clk_[tid_];
+ ResetCached(c);
+}
+
+void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) {
+ printf("clock=[");
+ for (uptr i = 0; i < nclk_; i++)
+ printf("%s%llu", i == 0 ? "" : ",", clk_[i]);
+ printf("] tid=%u/%u last_acq=%llu", tid_, reused_, last_acquire_);
+}
+
+SyncClock::SyncClock() {
+ ResetImpl();
+}
+
+SyncClock::~SyncClock() {
+ // Reset must be called before dtor.
+ CHECK_EQ(size_, 0);
+ CHECK_EQ(blocks_, 0);
+ CHECK_EQ(tab_, 0);
+ CHECK_EQ(tab_idx_, 0);
+}
+
+void SyncClock::Reset(ClockCache *c) {
+ if (size_)
+ UnrefClockBlock(c, tab_idx_, blocks_);
+ ResetImpl();
+}
+
+void SyncClock::ResetImpl() {
+ tab_ = 0;
+ tab_idx_ = 0;
+ size_ = 0;
+ blocks_ = 0;
+ release_store_tid_ = kInvalidTid;
+ release_store_reused_ = 0;
+ for (uptr i = 0; i < kDirtyTids; i++)
+ dirty_[i].tid = kInvalidTid;
+}
+
void SyncClock::Resize(ClockCache *c, uptr nclk) {
CPP_STAT_INC(StatClockReleaseResize);
- if (RoundUpTo(nclk, ClockBlock::kClockCount) <=
- RoundUpTo(size_, ClockBlock::kClockCount)) {
- // Growing within the same block.
+ Unshare(c);
+ if (nclk <= capacity()) {
// Memory is already allocated, just increase the size.
size_ = nclk;
return;
}
- if (nclk <= ClockBlock::kClockCount) {
+ if (size_ == 0) {
// Grow from 0 to one-level table.
CHECK_EQ(size_, 0);
+ CHECK_EQ(blocks_, 0);
CHECK_EQ(tab_, 0);
CHECK_EQ(tab_idx_, 0);
- size_ = nclk;
tab_idx_ = ctx->clock_alloc.Alloc(c);
tab_ = ctx->clock_alloc.Map(tab_idx_);
internal_memset(tab_, 0, sizeof(*tab_));
- return;
- }
- // Growing two-level table.
- if (size_ == 0) {
- // Allocate first level table.
- tab_idx_ = ctx->clock_alloc.Alloc(c);
- tab_ = ctx->clock_alloc.Map(tab_idx_);
- internal_memset(tab_, 0, sizeof(*tab_));
- } else if (size_ <= ClockBlock::kClockCount) {
- // Transform one-level table to two-level table.
- u32 old = tab_idx_;
- tab_idx_ = ctx->clock_alloc.Alloc(c);
- tab_ = ctx->clock_alloc.Map(tab_idx_);
- internal_memset(tab_, 0, sizeof(*tab_));
- tab_->table[0] = old;
+ atomic_store_relaxed(ref_ptr(tab_), 1);
+ size_ = 1;
+ } else if (size_ > blocks_ * ClockBlock::kClockCount) {
+ u32 idx = ctx->clock_alloc.Alloc(c);
+ ClockBlock *new_cb = ctx->clock_alloc.Map(idx);
+ uptr top = size_ - blocks_ * ClockBlock::kClockCount;
+ CHECK_LT(top, ClockBlock::kClockCount);
+ const uptr move = top * sizeof(tab_->clock[0]);
+ internal_memcpy(&new_cb->clock[0], tab_->clock, move);
+ internal_memset(&new_cb->clock[top], 0, sizeof(*new_cb) - move);
+ internal_memset(tab_->clock, 0, move);
+ append_block(idx);
}
- // At this point we have first level table allocated.
+ // At this point we have first level table allocated and all clock elements
+ // are evacuated from it to a second level block.
// Add second level tables as necessary.
- for (uptr i = RoundUpTo(size_, ClockBlock::kClockCount);
- i < nclk; i += ClockBlock::kClockCount) {
+ while (nclk > capacity()) {
u32 idx = ctx->clock_alloc.Alloc(c);
ClockBlock *cb = ctx->clock_alloc.Map(idx);
internal_memset(cb, 0, sizeof(*cb));
- CHECK_EQ(tab_->table[i/ClockBlock::kClockCount], 0);
- tab_->table[i/ClockBlock::kClockCount] = idx;
+ append_block(idx);
}
size_ = nclk;
}
-// Sets a single element in the vector clock.
-// This function is called only from weird places like AcquireGlobal.
-void ThreadClock::set(unsigned tid, u64 v) {
- DCHECK_LT(tid, kMaxTid);
- DCHECK_GE(v, clk_[tid].epoch);
- clk_[tid].epoch = v;
- if (nclk_ <= tid)
- nclk_ = tid + 1;
- last_acquire_ = clk_[tid_].epoch;
-}
-
-void ThreadClock::DebugDump(int(*printf)(const char *s, ...)) {
- printf("clock=[");
- for (uptr i = 0; i < nclk_; i++)
- printf("%s%llu", i == 0 ? "" : ",", clk_[i].epoch);
- printf("] reused=[");
- for (uptr i = 0; i < nclk_; i++)
- printf("%s%llu", i == 0 ? "" : ",", clk_[i].reused);
- printf("] tid=%u/%u last_acq=%llu",
- tid_, reused_, last_acquire_);
+// Flushes all dirty elements into the main clock array.
+void SyncClock::FlushDirty() {
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ Dirty *dirty = &dirty_[i];
+ if (dirty->tid != kInvalidTid) {
+ CHECK_LT(dirty->tid, size_);
+ elem(dirty->tid).epoch = dirty->epoch;
+ dirty->tid = kInvalidTid;
+ }
+ }
}
-SyncClock::SyncClock()
- : release_store_tid_(kInvalidTid)
- , release_store_reused_()
- , tab_()
- , tab_idx_()
- , size_() {
- for (uptr i = 0; i < kDirtyTids; i++)
- dirty_tids_[i] = kInvalidTid;
+bool SyncClock::IsShared() const {
+ if (size_ == 0)
+ return false;
+ atomic_uint32_t *ref = ref_ptr(tab_);
+ u32 v = atomic_load(ref, memory_order_acquire);
+ CHECK_GT(v, 0);
+ return v > 1;
}
-SyncClock::~SyncClock() {
- // Reset must be called before dtor.
- CHECK_EQ(size_, 0);
- CHECK_EQ(tab_, 0);
- CHECK_EQ(tab_idx_, 0);
+// Unshares the current clock if it's shared.
+// Shared clocks are immutable, so they need to be unshared before any updates.
+// Note: this does not apply to dirty entries as they are not shared.
+void SyncClock::Unshare(ClockCache *c) {
+ if (!IsShared())
+ return;
+ // First, copy current state into old.
+ SyncClock old;
+ old.tab_ = tab_;
+ old.tab_idx_ = tab_idx_;
+ old.size_ = size_;
+ old.blocks_ = blocks_;
+ old.release_store_tid_ = release_store_tid_;
+ old.release_store_reused_ = release_store_reused_;
+ for (unsigned i = 0; i < kDirtyTids; i++)
+ old.dirty_[i] = dirty_[i];
+ // Then, clear current object.
+ ResetImpl();
+ // Allocate brand new clock in the current object.
+ Resize(c, old.size_);
+ // Now copy state back into this object.
+ Iter old_iter(&old);
+ for (ClockElem &ce : *this) {
+ ce = *old_iter;
+ ++old_iter;
+ }
+ release_store_tid_ = old.release_store_tid_;
+ release_store_reused_ = old.release_store_reused_;
+ for (unsigned i = 0; i < kDirtyTids; i++)
+ dirty_[i] = old.dirty_[i];
+ // Drop reference to old and delete if necessary.
+ old.Reset(c);
}
-void SyncClock::Reset(ClockCache *c) {
- if (size_ == 0) {
- // nothing
- } else if (size_ <= ClockBlock::kClockCount) {
- // One-level table.
- ctx->clock_alloc.Free(c, tab_idx_);
- } else {
- // Two-level table.
- for (uptr i = 0; i < size_; i += ClockBlock::kClockCount)
- ctx->clock_alloc.Free(c, tab_->table[i / ClockBlock::kClockCount]);
- ctx->clock_alloc.Free(c, tab_idx_);
+// Can we cache this clock for future release operations?
+ALWAYS_INLINE bool SyncClock::Cachable() const {
+ if (size_ == 0)
+ return false;
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ if (dirty_[i].tid != kInvalidTid)
+ return false;
}
- tab_ = 0;
- tab_idx_ = 0;
- size_ = 0;
- release_store_tid_ = kInvalidTid;
- release_store_reused_ = 0;
- for (uptr i = 0; i < kDirtyTids; i++)
- dirty_tids_[i] = kInvalidTid;
+ return atomic_load_relaxed(ref_ptr(tab_)) == 1;
}
-ClockElem &SyncClock::elem(unsigned tid) const {
+// elem linearizes the two-level structure into linear array.
+// Note: this is used only for one time accesses, vector operations use
+// the iterator as it is much faster.
+ALWAYS_INLINE ClockElem &SyncClock::elem(unsigned tid) const {
DCHECK_LT(tid, size_);
- if (size_ <= ClockBlock::kClockCount)
+ const uptr block = tid / ClockBlock::kClockCount;
+ DCHECK_LE(block, blocks_);
+ tid %= ClockBlock::kClockCount;
+ if (block == blocks_)
return tab_->clock[tid];
- u32 idx = tab_->table[tid / ClockBlock::kClockCount];
+ u32 idx = get_block(block);
ClockBlock *cb = ctx->clock_alloc.Map(idx);
- return cb->clock[tid % ClockBlock::kClockCount];
+ return cb->clock[tid];
+}
+
+ALWAYS_INLINE uptr SyncClock::capacity() const {
+ if (size_ == 0)
+ return 0;
+ uptr ratio = sizeof(ClockBlock::clock[0]) / sizeof(ClockBlock::table[0]);
+ // How many clock elements we can fit into the first level block.
+ // +1 for ref counter.
+ uptr top = ClockBlock::kClockCount - RoundUpTo(blocks_ + 1, ratio) / ratio;
+ return blocks_ * ClockBlock::kClockCount + top;
+}
+
+ALWAYS_INLINE u32 SyncClock::get_block(uptr bi) const {
+ DCHECK(size_);
+ DCHECK_LT(bi, blocks_);
+ return tab_->table[ClockBlock::kBlockIdx - bi];
+}
+
+ALWAYS_INLINE void SyncClock::append_block(u32 idx) {
+ uptr bi = blocks_++;
+ CHECK_EQ(get_block(bi), 0);
+ tab_->table[ClockBlock::kBlockIdx - bi] = idx;
+}
+
+// Used only by tests.
+u64 SyncClock::get(unsigned tid) const {
+ for (unsigned i = 0; i < kDirtyTids; i++) {
+ Dirty dirty = dirty_[i];
+ if (dirty.tid == tid)
+ return dirty.epoch;
+ }
+ return elem(tid).epoch;
+}
+
+// Used only by Iter test.
+u64 SyncClock::get_clean(unsigned tid) const {
+ return elem(tid).epoch;
}
void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
@@ -418,8 +565,32 @@ void SyncClock::DebugDump(int(*printf)(const char *s, ...)) {
printf("] reused=[");
for (uptr i = 0; i < size_; i++)
printf("%s%llu", i == 0 ? "" : ",", elem(i).reused);
- printf("] release_store_tid=%d/%d dirty_tids=%d/%d",
+ printf("] release_store_tid=%d/%d dirty_tids=%d[%llu]/%d[%llu]",
release_store_tid_, release_store_reused_,
- dirty_tids_[0], dirty_tids_[1]);
+ dirty_[0].tid, dirty_[0].epoch,
+ dirty_[1].tid, dirty_[1].epoch);
+}
+
+void SyncClock::Iter::Next() {
+ // Finished with the current block, move on to the next one.
+ block_++;
+ if (block_ < parent_->blocks_) {
+ // Iterate over the next second level block.
+ u32 idx = parent_->get_block(block_);
+ ClockBlock *cb = ctx->clock_alloc.Map(idx);
+ pos_ = &cb->clock[0];
+ end_ = pos_ + min(parent_->size_ - block_ * ClockBlock::kClockCount,
+ ClockBlock::kClockCount);
+ return;
+ }
+ if (block_ == parent_->blocks_ &&
+ parent_->size_ > parent_->blocks_ * ClockBlock::kClockCount) {
+ // Iterate over elements in the first level block.
+ pos_ = &parent_->tab_->clock[0];
+ end_ = pos_ + min(parent_->size_ - block_ * ClockBlock::kClockCount,
+ ClockBlock::kClockCount);
+ return;
+ }
+ parent_ = nullptr; // denotes end
}
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_clock.h b/libsanitizer/tsan/tsan_clock.h
index 3deb7f5..c8eb8ee 100644
--- a/libsanitizer/tsan/tsan_clock.h
+++ b/libsanitizer/tsan/tsan_clock.h
@@ -16,25 +16,6 @@
namespace __tsan {
-struct ClockElem {
- u64 epoch : kClkBits;
- u64 reused : 64 - kClkBits;
-};
-
-struct ClockBlock {
- static const uptr kSize = 512;
- static const uptr kTableSize = kSize / sizeof(u32);
- static const uptr kClockCount = kSize / sizeof(ClockElem);
-
- union {
- u32 table[kTableSize];
- ClockElem clock[kClockCount];
- };
-
- ClockBlock() {
- }
-};
-
typedef DenseSlabAlloc<ClockBlock, 1<<16, 1<<10> ClockAlloc;
typedef DenseSlabAllocCache ClockCache;
@@ -44,84 +25,200 @@ class SyncClock {
SyncClock();
~SyncClock();
- uptr size() const {
- return size_;
- }
+ uptr size() const;
- u64 get(unsigned tid) const {
- return elem(tid).epoch;
- }
+ // These are used only in tests.
+ u64 get(unsigned tid) const;
+ u64 get_clean(unsigned tid) const;
void Resize(ClockCache *c, uptr nclk);
void Reset(ClockCache *c);
void DebugDump(int(*printf)(const char *s, ...));
+ // Clock element iterator.
+ // Note: it iterates only over the table without regard to dirty entries.
+ class Iter {
+ public:
+ explicit Iter(SyncClock* parent);
+ Iter& operator++();
+ bool operator!=(const Iter& other);
+ ClockElem &operator*();
+
+ private:
+ SyncClock *parent_;
+ // [pos_, end_) is the current continuous range of clock elements.
+ ClockElem *pos_;
+ ClockElem *end_;
+ int block_; // Current number of second level block.
+
+ NOINLINE void Next();
+ };
+
+ Iter begin();
+ Iter end();
+
private:
- friend struct ThreadClock;
+ friend class ThreadClock;
+ friend class Iter;
static const uptr kDirtyTids = 2;
+ struct Dirty {
+ u64 epoch : kClkBits;
+ u64 tid : 64 - kClkBits; // kInvalidId if not active
+ };
+
unsigned release_store_tid_;
unsigned release_store_reused_;
- unsigned dirty_tids_[kDirtyTids];
- // tab_ contains indirect pointer to a 512b block using DenseSlabAlloc.
- // If size_ <= 64, then tab_ points to an array with 64 ClockElem's.
- // Otherwise, tab_ points to an array with 128 u32 elements,
+ Dirty dirty_[kDirtyTids];
+ // If size_ is 0, tab_ is nullptr.
+ // If size <= 64 (kClockCount), tab_ contains pointer to an array with
+ // 64 ClockElem's (ClockBlock::clock).
+ // Otherwise, tab_ points to an array with up to 127 u32 elements,
// each pointing to the second-level 512b block with 64 ClockElem's.
+ // Unused space in the first level ClockBlock is used to store additional
+ // clock elements.
+ // The last u32 element in the first level ClockBlock is always used as
+ // reference counter.
+ //
+ // See the following scheme for details.
+ // All memory blocks are 512 bytes (allocated from ClockAlloc).
+ // Clock (clk) elements are 64 bits.
+ // Idx and ref are 32 bits.
+ //
+ // tab_
+ // |
+ // \/
+ // +----------------------------------------------------+
+ // | clk128 | clk129 | ...unused... | idx1 | idx0 | ref |
+ // +----------------------------------------------------+
+ // | |
+ // | \/
+ // | +----------------+
+ // | | clk0 ... clk63 |
+ // | +----------------+
+ // \/
+ // +------------------+
+ // | clk64 ... clk127 |
+ // +------------------+
+ //
+ // Note: dirty entries, if active, always override what's stored in the clock.
ClockBlock *tab_;
u32 tab_idx_;
- u32 size_;
-
+ u16 size_;
+ u16 blocks_; // Number of second level blocks.
+
+ void Unshare(ClockCache *c);
+ bool IsShared() const;
+ bool Cachable() const;
+ void ResetImpl();
+ void FlushDirty();
+ uptr capacity() const;
+ u32 get_block(uptr bi) const;
+ void append_block(u32 idx);
ClockElem &elem(unsigned tid) const;
};
// The clock that lives in threads.
-struct ThreadClock {
+class ThreadClock {
public:
typedef DenseSlabAllocCache Cache;
explicit ThreadClock(unsigned tid, unsigned reused = 0);
- u64 get(unsigned tid) const {
- DCHECK_LT(tid, kMaxTidInClock);
- return clk_[tid].epoch;
- }
-
- void set(unsigned tid, u64 v);
-
- void set(u64 v) {
- DCHECK_GE(v, clk_[tid_].epoch);
- clk_[tid_].epoch = v;
- }
+ u64 get(unsigned tid) const;
+ void set(ClockCache *c, unsigned tid, u64 v);
+ void set(u64 v);
+ void tick();
+ uptr size() const;
- void tick() {
- clk_[tid_].epoch++;
- }
-
- uptr size() const {
- return nclk_;
- }
-
- void acquire(ClockCache *c, const SyncClock *src);
- void release(ClockCache *c, SyncClock *dst) const;
+ void acquire(ClockCache *c, SyncClock *src);
+ void release(ClockCache *c, SyncClock *dst);
void acq_rel(ClockCache *c, SyncClock *dst);
- void ReleaseStore(ClockCache *c, SyncClock *dst) const;
+ void ReleaseStore(ClockCache *c, SyncClock *dst);
+ void ResetCached(ClockCache *c);
void DebugReset();
void DebugDump(int(*printf)(const char *s, ...));
private:
static const uptr kDirtyTids = SyncClock::kDirtyTids;
+ // Index of the thread associated with he clock ("current thread").
const unsigned tid_;
- const unsigned reused_;
+ const unsigned reused_; // tid_ reuse count.
+ // Current thread time when it acquired something from other threads.
u64 last_acquire_;
+
+ // Cached SyncClock (without dirty entries and release_store_tid_).
+ // We reuse it for subsequent store-release operations without intervening
+ // acquire operations. Since it is shared (and thus constant), clock value
+ // for the current thread is then stored in dirty entries in the SyncClock.
+ // We host a refernece to the table while it is cached here.
+ u32 cached_idx_;
+ u16 cached_size_;
+ u16 cached_blocks_;
+
+ // Number of active elements in the clk_ table (the rest is zeros).
uptr nclk_;
- ClockElem clk_[kMaxTidInClock];
+ u64 clk_[kMaxTidInClock]; // Fixed size vector clock.
bool IsAlreadyAcquired(const SyncClock *src) const;
- void UpdateCurrentThread(SyncClock *dst) const;
+ void UpdateCurrentThread(ClockCache *c, SyncClock *dst) const;
};
+ALWAYS_INLINE u64 ThreadClock::get(unsigned tid) const {
+ DCHECK_LT(tid, kMaxTidInClock);
+ return clk_[tid];
+}
+
+ALWAYS_INLINE void ThreadClock::set(u64 v) {
+ DCHECK_GE(v, clk_[tid_]);
+ clk_[tid_] = v;
+}
+
+ALWAYS_INLINE void ThreadClock::tick() {
+ clk_[tid_]++;
+}
+
+ALWAYS_INLINE uptr ThreadClock::size() const {
+ return nclk_;
+}
+
+ALWAYS_INLINE SyncClock::Iter SyncClock::begin() {
+ return Iter(this);
+}
+
+ALWAYS_INLINE SyncClock::Iter SyncClock::end() {
+ return Iter(nullptr);
+}
+
+ALWAYS_INLINE uptr SyncClock::size() const {
+ return size_;
+}
+
+ALWAYS_INLINE SyncClock::Iter::Iter(SyncClock* parent)
+ : parent_(parent)
+ , pos_(nullptr)
+ , end_(nullptr)
+ , block_(-1) {
+ if (parent)
+ Next();
+}
+
+ALWAYS_INLINE SyncClock::Iter& SyncClock::Iter::operator++() {
+ pos_++;
+ if (UNLIKELY(pos_ >= end_))
+ Next();
+ return *this;
+}
+
+ALWAYS_INLINE bool SyncClock::Iter::operator!=(const SyncClock::Iter& other) {
+ return parent_ != other.parent_;
+}
+
+ALWAYS_INLINE ClockElem &SyncClock::Iter::operator*() {
+ return *pos_;
+}
} // namespace __tsan
#endif // TSAN_CLOCK_H
diff --git a/libsanitizer/tsan/tsan_debugging.cc b/libsanitizer/tsan/tsan_debugging.cc
index d26d482..9a9c67f 100644
--- a/libsanitizer/tsan/tsan_debugging.cc
+++ b/libsanitizer/tsan/tsan_debugging.cc
@@ -13,6 +13,8 @@
#include "tsan_report.h"
#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
+
using namespace __tsan;
static const char *ReportTypeDescription(ReportType typ) {
@@ -20,6 +22,7 @@ static const char *ReportTypeDescription(ReportType typ) {
if (typ == ReportTypeVptrRace) return "data-race-vptr";
if (typ == ReportTypeUseAfterFree) return "heap-use-after-free";
if (typ == ReportTypeVptrUseAfterFree) return "heap-use-after-free-vptr";
+ if (typ == ReportTypeExternalRace) return "external-race";
if (typ == ReportTypeThreadLeak) return "thread-leak";
if (typ == ReportTypeMutexDestroyLocked) return "locked-mutex-destroy";
if (typ == ReportTypeMutexDoubleLock) return "mutex-double-lock";
@@ -123,6 +126,16 @@ int __tsan_get_report_loc(void *report, uptr idx, const char **type,
}
SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_loc_object_type(void *report, uptr idx,
+ const char **object_type) {
+ const ReportDesc *rep = (ReportDesc *)report;
+ CHECK_LT(idx, rep->locs.Size());
+ ReportLocation *loc = rep->locs[idx];
+ *object_type = GetObjectTypeFromTag(loc->external_tag);
+ return 1;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
int *destroyed, void **trace, uptr trace_size) {
const ReportDesc *rep = (ReportDesc *)report;
@@ -136,7 +149,7 @@ int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
}
SANITIZER_INTERFACE_ATTRIBUTE
-int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *os_id,
+int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id,
int *running, const char **name, int *parent_tid,
void **trace, uptr trace_size) {
const ReportDesc *rep = (ReportDesc *)report;
@@ -158,3 +171,78 @@ int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid) {
*tid = rep->unique_tids[idx];
return 1;
}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+const char *__tsan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address_ptr,
+ uptr *region_size_ptr) {
+ uptr region_address = 0;
+ uptr region_size = 0;
+ const char *region_kind = nullptr;
+ if (name && name_size > 0) name[0] = 0;
+
+ if (IsMetaMem(addr)) {
+ region_kind = "meta shadow";
+ } else if (IsShadowMem(addr)) {
+ region_kind = "shadow";
+ } else {
+ bool is_stack = false;
+ MBlock *b = 0;
+ Allocator *a = allocator();
+ if (a->PointerIsMine((void *)addr)) {
+ void *block_begin = a->GetBlockBegin((void *)addr);
+ if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
+ }
+
+ if (b != 0) {
+ region_address = (uptr)allocator()->GetBlockBegin((void *)addr);
+ region_size = b->siz;
+ region_kind = "heap";
+ } else {
+ // TODO(kuba.brecka): We should not lock. This is supposed to be called
+ // from within the debugger when other threads are stopped.
+ ctx->thread_registry->Lock();
+ ThreadContext *tctx = IsThreadStackOrTls(addr, &is_stack);
+ ctx->thread_registry->Unlock();
+ if (tctx) {
+ region_kind = is_stack ? "stack" : "tls";
+ } else {
+ region_kind = "global";
+ DataInfo info;
+ if (Symbolizer::GetOrInit()->SymbolizeData(addr, &info)) {
+ internal_strncpy(name, info.name, name_size);
+ region_address = info.start;
+ region_size = info.size;
+ }
+ }
+ }
+ }
+
+ CHECK(region_kind);
+ if (region_address_ptr) *region_address_ptr = region_address;
+ if (region_size_ptr) *region_size_ptr = region_size;
+ return region_kind;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id,
+ tid_t *os_id) {
+ MBlock *b = 0;
+ Allocator *a = allocator();
+ if (a->PointerIsMine((void *)addr)) {
+ void *block_begin = a->GetBlockBegin((void *)addr);
+ if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
+ }
+ if (b == 0) return 0;
+
+ *thread_id = b->tid;
+ // No locking. This is supposed to be called from within the debugger when
+ // other threads are stopped.
+ ThreadContextBase *tctx = ctx->thread_registry->GetThreadLocked(b->tid);
+ *os_id = tctx->os_id;
+
+ StackTrace stack = StackDepotGet(b->stk);
+ size = Min(size, (uptr)stack.size);
+ for (uptr i = 0; i < size; i++) trace[i] = stack.trace[stack.size - i - 1];
+ return size;
+}
diff --git a/libsanitizer/tsan/tsan_defs.h b/libsanitizer/tsan/tsan_defs.h
index e540526..2c7eda6 100644
--- a/libsanitizer/tsan/tsan_defs.h
+++ b/libsanitizer/tsan/tsan_defs.h
@@ -36,15 +36,40 @@
namespace __tsan {
+const int kClkBits = 42;
+const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1;
+
+struct ClockElem {
+ u64 epoch : kClkBits;
+ u64 reused : 64 - kClkBits; // tid reuse count
+};
+
+struct ClockBlock {
+ static const uptr kSize = 512;
+ static const uptr kTableSize = kSize / sizeof(u32);
+ static const uptr kClockCount = kSize / sizeof(ClockElem);
+ static const uptr kRefIdx = kTableSize - 1;
+ static const uptr kBlockIdx = kTableSize - 2;
+
+ union {
+ u32 table[kTableSize];
+ ClockElem clock[kClockCount];
+ };
+
+ ClockBlock() {
+ }
+};
+
const int kTidBits = 13;
-const unsigned kMaxTid = 1 << kTidBits;
+// Reduce kMaxTid by kClockCount because one slot in ClockBlock table is
+// occupied by reference counter, so total number of elements we can store
+// in SyncClock is kClockCount * (kTableSize - 1).
+const unsigned kMaxTid = (1 << kTidBits) - ClockBlock::kClockCount;
#if !SANITIZER_GO
const unsigned kMaxTidInClock = kMaxTid * 2; // This includes msb 'freed' bit.
#else
const unsigned kMaxTidInClock = kMaxTid; // Go does not track freed memory.
#endif
-const int kClkBits = 42;
-const unsigned kMaxTidReuse = (1 << (64 - kClkBits)) - 1;
const uptr kShadowStackSize = 64 * 1024;
// Count of shadow values in a shadow cell.
@@ -72,7 +97,7 @@ const bool kCollectHistory = false;
const bool kCollectHistory = true;
#endif
-const unsigned kInvalidTid = (unsigned)-1;
+const u16 kInvalidTid = kMaxTid + 1;
// The following "build consistency" machinery ensures that all source files
// are built in the same configuration. Inconsistent builds lead to
@@ -147,13 +172,23 @@ class RegionAlloc;
// Descriptor of user's memory block.
struct MBlock {
- u64 siz;
+ u64 siz : 48;
+ u64 tag : 16;
u32 stk;
u16 tid;
};
COMPILER_CHECK(sizeof(MBlock) == 16);
+enum ExternalTag : uptr {
+ kExternalTagNone = 0,
+ kExternalTagSwiftModifyingAccess = 1,
+ kExternalTagFirstUserAvailable = 2,
+ kExternalTagMax = 1024,
+ // Don't set kExternalTagMax over 65,536, since MBlock only stores tags
+ // as 16-bit values, see tsan_defs.h.
+};
+
} // namespace __tsan
#endif // TSAN_DEFS_H
diff --git a/libsanitizer/tsan/tsan_dense_alloc.h b/libsanitizer/tsan/tsan_dense_alloc.h
index 780ff6f..197b96f 100644
--- a/libsanitizer/tsan/tsan_dense_alloc.h
+++ b/libsanitizer/tsan/tsan_dense_alloc.h
@@ -37,7 +37,7 @@ class DenseSlabAlloc {
typedef DenseSlabAllocCache Cache;
typedef typename Cache::IndexT IndexT;
- DenseSlabAlloc() {
+ explicit DenseSlabAlloc(const char *name) {
// Check that kL1Size and kL2Size are sane.
CHECK_EQ(kL1Size & (kL1Size - 1), 0);
CHECK_EQ(kL2Size & (kL2Size - 1), 0);
@@ -47,6 +47,7 @@ class DenseSlabAlloc {
internal_memset(map_, 0, sizeof(map_));
freelist_ = 0;
fillpos_ = 0;
+ name_ = name;
}
~DenseSlabAlloc() {
@@ -94,15 +95,19 @@ class DenseSlabAlloc {
SpinMutex mtx_;
IndexT freelist_;
uptr fillpos_;
+ const char *name_;
void Refill(Cache *c) {
SpinMutexLock lock(&mtx_);
if (freelist_ == 0) {
if (fillpos_ == kL1Size) {
- Printf("ThreadSanitizer: DenseSlabAllocator overflow. Dying.\n");
+ Printf("ThreadSanitizer: %s overflow (%zu*%zu). Dying.\n",
+ name_, kL1Size, kL2Size);
Die();
}
- T *batch = (T*)MmapOrDie(kL2Size * sizeof(T), "DenseSlabAllocator");
+ VPrintf(2, "ThreadSanitizer: growing %s: %zu out of %zu*%zu\n",
+ name_, fillpos_, kL1Size, kL2Size);
+ T *batch = (T*)MmapOrDie(kL2Size * sizeof(T), name_);
// Reserve 0 as invalid index.
IndexT start = fillpos_ == 0 ? 1 : 0;
for (IndexT i = start; i < kL2Size; i++) {
diff --git a/libsanitizer/tsan/tsan_external.cc b/libsanitizer/tsan/tsan_external.cc
new file mode 100644
index 0000000..3dddc3a
--- /dev/null
+++ b/libsanitizer/tsan/tsan_external.cc
@@ -0,0 +1,123 @@
+//===-- tsan_external.cc --------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is a part of ThreadSanitizer (TSan), a race detector.
+//
+//===----------------------------------------------------------------------===//
+#include "tsan_rtl.h"
+#include "tsan_interceptors.h"
+
+namespace __tsan {
+
+#define CALLERPC ((uptr)__builtin_return_address(0))
+
+struct TagData {
+ const char *object_type;
+ const char *header;
+};
+
+static TagData registered_tags[kExternalTagMax] = {
+ {},
+ {"Swift variable", "Swift access race"},
+};
+static atomic_uint32_t used_tags{kExternalTagFirstUserAvailable}; // NOLINT.
+static TagData *GetTagData(uptr tag) {
+ // Invalid/corrupted tag? Better return NULL and let the caller deal with it.
+ if (tag >= atomic_load(&used_tags, memory_order_relaxed)) return nullptr;
+ return &registered_tags[tag];
+}
+
+const char *GetObjectTypeFromTag(uptr tag) {
+ TagData *tag_data = GetTagData(tag);
+ return tag_data ? tag_data->object_type : nullptr;
+}
+
+const char *GetReportHeaderFromTag(uptr tag) {
+ TagData *tag_data = GetTagData(tag);
+ return tag_data ? tag_data->header : nullptr;
+}
+
+void InsertShadowStackFrameForTag(ThreadState *thr, uptr tag) {
+ FuncEntry(thr, (uptr)&registered_tags[tag]);
+}
+
+uptr TagFromShadowStackFrame(uptr pc) {
+ uptr tag_count = atomic_load(&used_tags, memory_order_relaxed);
+ void *pc_ptr = (void *)pc;
+ if (pc_ptr < GetTagData(0) || pc_ptr > GetTagData(tag_count - 1))
+ return 0;
+ return (TagData *)pc_ptr - GetTagData(0);
+}
+
+#if !SANITIZER_GO
+
+typedef void(*AccessFunc)(ThreadState *, uptr, uptr, int);
+void ExternalAccess(void *addr, void *caller_pc, void *tag, AccessFunc access) {
+ CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
+ ThreadState *thr = cur_thread();
+ if (caller_pc) FuncEntry(thr, (uptr)caller_pc);
+ InsertShadowStackFrameForTag(thr, (uptr)tag);
+ bool in_ignored_lib;
+ if (!caller_pc || !libignore()->IsIgnored((uptr)caller_pc, &in_ignored_lib)) {
+ access(thr, CALLERPC, (uptr)addr, kSizeLog1);
+ }
+ FuncExit(thr);
+ if (caller_pc) FuncExit(thr);
+}
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_external_register_tag(const char *object_type) {
+ uptr new_tag = atomic_fetch_add(&used_tags, 1, memory_order_relaxed);
+ CHECK_LT(new_tag, kExternalTagMax);
+ GetTagData(new_tag)->object_type = internal_strdup(object_type);
+ char header[127] = {0};
+ internal_snprintf(header, sizeof(header), "race on %s", object_type);
+ GetTagData(new_tag)->header = internal_strdup(header);
+ return (void *)new_tag;
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_register_header(void *tag, const char *header) {
+ CHECK_GE((uptr)tag, kExternalTagFirstUserAvailable);
+ CHECK_LT((uptr)tag, kExternalTagMax);
+ atomic_uintptr_t *header_ptr =
+ (atomic_uintptr_t *)&GetTagData((uptr)tag)->header;
+ header = internal_strdup(header);
+ char *old_header =
+ (char *)atomic_exchange(header_ptr, (uptr)header, memory_order_seq_cst);
+ if (old_header) internal_free(old_header);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_assign_tag(void *addr, void *tag) {
+ CHECK_LT(tag, atomic_load(&used_tags, memory_order_relaxed));
+ Allocator *a = allocator();
+ MBlock *b = nullptr;
+ if (a->PointerIsMine((void *)addr)) {
+ void *block_begin = a->GetBlockBegin((void *)addr);
+ if (block_begin) b = ctx->metamap.GetBlock((uptr)block_begin);
+ }
+ if (b) {
+ b->tag = (uptr)tag;
+ }
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_read(void *addr, void *caller_pc, void *tag) {
+ ExternalAccess(addr, caller_pc, tag, MemoryRead);
+}
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_write(void *addr, void *caller_pc, void *tag) {
+ ExternalAccess(addr, caller_pc, tag, MemoryWrite);
+}
+} // extern "C"
+
+#endif // !SANITIZER_GO
+
+} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_fd.cc b/libsanitizer/tsan/tsan_fd.cc
index 8f75a28..effa35d 100644
--- a/libsanitizer/tsan/tsan_fd.cc
+++ b/libsanitizer/tsan/tsan_fd.cc
@@ -46,8 +46,8 @@ static bool bogusfd(int fd) {
}
static FdSync *allocsync(ThreadState *thr, uptr pc) {
- FdSync *s = (FdSync*)user_alloc(thr, pc, sizeof(FdSync), kDefaultAlignment,
- false);
+ FdSync *s = (FdSync*)user_alloc_internal(thr, pc, sizeof(FdSync),
+ kDefaultAlignment, false);
atomic_store(&s->rc, 1, memory_order_relaxed);
return s;
}
@@ -77,7 +77,7 @@ static FdDesc *fddesc(ThreadState *thr, uptr pc, int fd) {
if (l1 == 0) {
uptr size = kTableSizeL2 * sizeof(FdDesc);
// We need this to reside in user memory to properly catch races on it.
- void *p = user_alloc(thr, pc, size, kDefaultAlignment, false);
+ void *p = user_alloc_internal(thr, pc, size, kDefaultAlignment, false);
internal_memset(p, 0, size);
MemoryResetRange(thr, (uptr)&fddesc, (uptr)p, size);
if (atomic_compare_exchange_strong(pl1, &l1, (uptr)p, memory_order_acq_rel))
diff --git a/libsanitizer/tsan/tsan_flags.cc b/libsanitizer/tsan/tsan_flags.cc
index 5064a0f..4217691 100644
--- a/libsanitizer/tsan/tsan_flags.cc
+++ b/libsanitizer/tsan/tsan_flags.cc
@@ -19,10 +19,6 @@
namespace __tsan {
-Flags *flags() {
- return &ctx->flags;
-}
-
// Can be overriden in frontend.
#ifdef TSAN_EXTERNAL_HOOKS
extern "C" const char* __tsan_default_options();
diff --git a/libsanitizer/tsan/tsan_flags.h b/libsanitizer/tsan/tsan_flags.h
index 3d58ff3..35b0efc 100644
--- a/libsanitizer/tsan/tsan_flags.h
+++ b/libsanitizer/tsan/tsan_flags.h
@@ -26,7 +26,6 @@ struct Flags : DDFlags {
void ParseFromString(const char *str);
};
-Flags *flags();
void InitializeFlags(Flags *flags, const char *env);
} // namespace __tsan
diff --git a/libsanitizer/tsan/tsan_flags.inc b/libsanitizer/tsan/tsan_flags.inc
index 78f5e80..e9873f1 100644
--- a/libsanitizer/tsan/tsan_flags.inc
+++ b/libsanitizer/tsan/tsan_flags.inc
@@ -77,5 +77,8 @@ TSAN_FLAG(bool, die_after_fork, true,
TSAN_FLAG(const char *, suppressions, "", "Suppressions file name.")
TSAN_FLAG(bool, ignore_interceptors_accesses, false,
"Ignore reads and writes from all interceptors.")
+TSAN_FLAG(bool, ignore_noninstrumented_modules, SANITIZER_MAC ? true : false,
+ "Interceptors should only detect races when called from instrumented "
+ "modules.")
TSAN_FLAG(bool, shared_ptr_interceptor, true,
"Track atomic reference counting in libc++ shared_ptr and weak_ptr.")
diff --git a/libsanitizer/tsan/tsan_interceptors.cc b/libsanitizer/tsan/tsan_interceptors.cc
index bf5f2d5..15f20d4 100644
--- a/libsanitizer/tsan/tsan_interceptors.cc
+++ b/libsanitizer/tsan/tsan_interceptors.cc
@@ -12,10 +12,13 @@
//===----------------------------------------------------------------------===//
#include "sanitizer_common/sanitizer_atomic.h"
+#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_linux.h"
+#include "sanitizer_common/sanitizer_platform_limits_netbsd.h"
#include "sanitizer_common/sanitizer_platform_limits_posix.h"
#include "sanitizer_common/sanitizer_placement_new.h"
+#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_stacktrace.h"
#include "sanitizer_common/sanitizer_tls_get_addr.h"
#include "interception/interception.h"
@@ -27,30 +30,25 @@
#include "tsan_mman.h"
#include "tsan_fd.h"
-#if SANITIZER_POSIX
-#include "sanitizer_common/sanitizer_posix.h"
-#endif
using namespace __tsan; // NOLINT
#if SANITIZER_FREEBSD || SANITIZER_MAC
-#define __errno_location __error
#define stdout __stdoutp
#define stderr __stderrp
#endif
-#if SANITIZER_ANDROID
-#define __errno_location __errno
-#define mallopt(a, b)
+#if SANITIZER_NETBSD
+#define dirfd(dirp) (*(int *)(dirp))
+#define fileno_unlocked fileno
+#define stdout __sF[1]
+#define stderr __sF[2]
#endif
-#if SANITIZER_LINUX || SANITIZER_FREEBSD
-#define PTHREAD_CREATE_DETACHED 1
-#elif SANITIZER_MAC
-#define PTHREAD_CREATE_DETACHED 2
+#if SANITIZER_ANDROID
+#define mallopt(a, b)
#endif
-
#ifdef __mips__
const int kSigCount = 129;
#else
@@ -91,24 +89,26 @@ DECLARE_REAL_AND_INTERCEPTOR(void *, malloc, uptr size)
DECLARE_REAL_AND_INTERCEPTOR(void, free, void *ptr)
extern "C" void *pthread_self();
extern "C" void _exit(int status);
-extern "C" int *__errno_location();
extern "C" int fileno_unlocked(void *stream);
+#if !SANITIZER_NETBSD
extern "C" int dirfd(void *dirp);
-#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID
+#endif
+#if !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_NETBSD
extern "C" int mallopt(int param, int value);
#endif
+#if SANITIZER_NETBSD
+extern __sanitizer_FILE **__sF;
+#else
extern __sanitizer_FILE *stdout, *stderr;
-#if !SANITIZER_FREEBSD && !SANITIZER_MAC
+#endif
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD
const int PTHREAD_MUTEX_RECURSIVE = 1;
const int PTHREAD_MUTEX_RECURSIVE_NP = 1;
#else
const int PTHREAD_MUTEX_RECURSIVE = 2;
const int PTHREAD_MUTEX_RECURSIVE_NP = 2;
#endif
-const int EINVAL = 22;
-const int EBUSY = 16;
-const int EOWNERDEAD = 130;
-#if !SANITIZER_FREEBSD && !SANITIZER_MAC
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD
const int EPOLL_CTL_ADD = 1;
#endif
const int SIGILL = 4;
@@ -117,7 +117,7 @@ const int SIGFPE = 8;
const int SIGSEGV = 11;
const int SIGPIPE = 13;
const int SIGTERM = 15;
-#if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_MAC
+#if defined(__mips__) || SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD
const int SIGBUS = 10;
const int SIGSYS = 12;
#else
@@ -125,7 +125,9 @@ const int SIGBUS = 7;
const int SIGSYS = 31;
#endif
void *const MAP_FAILED = (void*)-1;
-#if !SANITIZER_MAC
+#if SANITIZER_NETBSD
+const int PTHREAD_BARRIER_SERIAL_THREAD = 1234567;
+#elif !SANITIZER_MAC
const int PTHREAD_BARRIER_SERIAL_THREAD = -1;
#endif
const int MAP_FIXED = 0x10;
@@ -137,8 +139,6 @@ typedef long long_t; // NOLINT
# define F_TLOCK 2 /* Test and lock a region for exclusive use. */
# define F_TEST 3 /* Test a region for other processes locks. */
-#define errno (*__errno_location())
-
typedef void (*sighandler_t)(int sig);
typedef void (*sigactionhandler_t)(int sig, my_siginfo_t *siginfo, void *uctx);
@@ -152,6 +152,15 @@ struct sigaction_t {
__sanitizer_sigset_t sa_mask;
void (*sa_restorer)();
};
+#elif SANITIZER_NETBSD
+struct sigaction_t {
+ union {
+ sighandler_t sa_handler;
+ sigactionhandler_t sa_sigaction;
+ };
+ __sanitizer_sigset_t sa_mask;
+ int sa_flags;
+};
#else
struct sigaction_t {
#ifdef __mips__
@@ -180,7 +189,7 @@ struct sigaction_t {
const sighandler_t SIG_DFL = (sighandler_t)0;
const sighandler_t SIG_IGN = (sighandler_t)1;
const sighandler_t SIG_ERR = (sighandler_t)-1;
-#if SANITIZER_FREEBSD || SANITIZER_MAC
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_NETBSD
const int SA_SIGINFO = 0x40;
const int SIG_SETMASK = 3;
#elif defined(__mips__)
@@ -217,7 +226,7 @@ struct ThreadSignalContext {
// The object is 64-byte aligned, because we want hot data to be located in
// a single cache line if possible (it's accessed in every interceptor).
static ALIGNED(64) char libignore_placeholder[sizeof(LibIgnore)];
-static LibIgnore *libignore() {
+LibIgnore *libignore() {
return reinterpret_cast<LibIgnore*>(&libignore_placeholder[0]);
}
@@ -229,6 +238,8 @@ void InitializeLibIgnore() {
if (0 == internal_strcmp(s->type, kSuppressionLib))
libignore()->AddIgnoredLibrary(s->templ);
}
+ if (flags()->ignore_noninstrumented_modules)
+ libignore()->IgnoreNoninstrumentedModules(true);
libignore()->OnLibraryLoaded(0);
}
@@ -250,31 +261,20 @@ static unsigned g_thread_finalize_key;
ScopedInterceptor::ScopedInterceptor(ThreadState *thr, const char *fname,
uptr pc)
- : thr_(thr)
- , pc_(pc)
- , in_ignored_lib_(false) {
+ : thr_(thr), pc_(pc), in_ignored_lib_(false), ignoring_(false) {
Initialize(thr);
- if (!thr_->is_inited)
- return;
- if (!thr_->ignore_interceptors)
- FuncEntry(thr, pc);
+ if (!thr_->is_inited) return;
+ if (!thr_->ignore_interceptors) FuncEntry(thr, pc);
DPrintf("#%d: intercept %s()\n", thr_->tid, fname);
- if (!thr_->in_ignored_lib && libignore()->IsIgnored(pc)) {
- in_ignored_lib_ = true;
- thr_->in_ignored_lib = true;
- ThreadIgnoreBegin(thr_, pc_);
- }
- if (flags()->ignore_interceptors_accesses) ThreadIgnoreBegin(thr_, pc_);
+ ignoring_ =
+ !thr_->in_ignored_lib && (flags()->ignore_interceptors_accesses ||
+ libignore()->IsIgnored(pc, &in_ignored_lib_));
+ EnableIgnores();
}
ScopedInterceptor::~ScopedInterceptor() {
- if (!thr_->is_inited)
- return;
- if (flags()->ignore_interceptors_accesses) ThreadIgnoreEnd(thr_, pc_);
- if (in_ignored_lib_) {
- thr_->in_ignored_lib = false;
- ThreadIgnoreEnd(thr_, pc_);
- }
+ if (!thr_->is_inited) return;
+ DisableIgnores();
if (!thr_->ignore_interceptors) {
ProcessPendingSignals(thr_);
FuncExit(thr_);
@@ -282,24 +282,30 @@ ScopedInterceptor::~ScopedInterceptor() {
}
}
-void ScopedInterceptor::UserCallbackStart() {
- if (flags()->ignore_interceptors_accesses) ThreadIgnoreEnd(thr_, pc_);
- if (in_ignored_lib_) {
- thr_->in_ignored_lib = false;
- ThreadIgnoreEnd(thr_, pc_);
+void ScopedInterceptor::EnableIgnores() {
+ if (ignoring_) {
+ ThreadIgnoreBegin(thr_, pc_, /*save_stack=*/false);
+ if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports++;
+ if (in_ignored_lib_) {
+ DCHECK(!thr_->in_ignored_lib);
+ thr_->in_ignored_lib = true;
+ }
}
}
-void ScopedInterceptor::UserCallbackEnd() {
- if (in_ignored_lib_) {
- thr_->in_ignored_lib = true;
- ThreadIgnoreBegin(thr_, pc_);
+void ScopedInterceptor::DisableIgnores() {
+ if (ignoring_) {
+ ThreadIgnoreEnd(thr_, pc_);
+ if (flags()->ignore_noninstrumented_modules) thr_->suppress_reports--;
+ if (in_ignored_lib_) {
+ DCHECK(thr_->in_ignored_lib);
+ thr_->in_ignored_lib = false;
+ }
}
- if (flags()->ignore_interceptors_accesses) ThreadIgnoreBegin(thr_, pc_);
}
#define TSAN_INTERCEPT(func) INTERCEPT_FUNCTION(func)
-#if SANITIZER_FREEBSD
+#if SANITIZER_FREEBSD || SANITIZER_NETBSD
# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION(func)
#else
# define TSAN_INTERCEPT_VER(func, ver) INTERCEPT_FUNCTION_VER(func, ver)
@@ -363,6 +369,11 @@ TSAN_INTERCEPTOR(int, nanosleep, void *req, void *rem) {
return res;
}
+TSAN_INTERCEPTOR(int, pause) {
+ SCOPED_TSAN_INTERCEPTOR(pause);
+ return BLOCK_REAL(pause)();
+}
+
// The sole reason tsan wraps atexit callbacks is to establish synchronization
// between callback setup and callback execution.
struct AtExitCtx {
@@ -476,8 +487,14 @@ static void SetJmp(ThreadState *thr, uptr sp, uptr mangled_sp) {
static void LongJmp(ThreadState *thr, uptr *env) {
#ifdef __powerpc__
uptr mangled_sp = env[0];
-#elif SANITIZER_FREEBSD || SANITIZER_MAC
+#elif SANITIZER_FREEBSD || SANITIZER_NETBSD
uptr mangled_sp = env[2];
+#elif SANITIZER_MAC
+# ifdef __aarch64__
+ uptr mangled_sp = env[13];
+# else
+ uptr mangled_sp = env[2];
+# endif
#elif defined(SANITIZER_LINUX)
# ifdef __aarch64__
uptr mangled_sp = env[13];
@@ -595,7 +612,7 @@ TSAN_INTERCEPTOR(void*, malloc, uptr size) {
TSAN_INTERCEPTOR(void*, __libc_memalign, uptr align, uptr sz) {
SCOPED_TSAN_INTERCEPTOR(__libc_memalign, align, sz);
- return user_alloc(thr, pc, sz, align);
+ return user_memalign(thr, pc, align, sz);
}
TSAN_INTERCEPTOR(void*, calloc, uptr size, uptr n) {
@@ -675,7 +692,7 @@ static bool fix_mmap_addr(void **addr, long_t sz, int flags) {
if (*addr) {
if (!IsAppMem((uptr)*addr) || !IsAppMem((uptr)*addr + sz - 1)) {
if (flags & MAP_FIXED) {
- errno = EINVAL;
+ errno = errno_EINVAL;
return false;
} else {
*addr = 0;
@@ -741,7 +758,7 @@ TSAN_INTERCEPTOR(int, munmap, void *addr, long_t sz) {
#if SANITIZER_LINUX
TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
- return user_alloc(thr, pc, sz, align);
+ return user_memalign(thr, pc, align, sz);
}
#define TSAN_MAYBE_INTERCEPT_MEMALIGN TSAN_INTERCEPT(memalign)
#else
@@ -750,21 +767,20 @@ TSAN_INTERCEPTOR(void*, memalign, uptr align, uptr sz) {
#if !SANITIZER_MAC
TSAN_INTERCEPTOR(void*, aligned_alloc, uptr align, uptr sz) {
- SCOPED_INTERCEPTOR_RAW(memalign, align, sz);
- return user_alloc(thr, pc, sz, align);
+ SCOPED_INTERCEPTOR_RAW(aligned_alloc, align, sz);
+ return user_aligned_alloc(thr, pc, align, sz);
}
TSAN_INTERCEPTOR(void*, valloc, uptr sz) {
SCOPED_INTERCEPTOR_RAW(valloc, sz);
- return user_alloc(thr, pc, sz, GetPageSizeCached());
+ return user_valloc(thr, pc, sz);
}
#endif
#if SANITIZER_LINUX
TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
SCOPED_INTERCEPTOR_RAW(pvalloc, sz);
- sz = RoundUp(sz, GetPageSizeCached());
- return user_alloc(thr, pc, sz, GetPageSizeCached());
+ return user_pvalloc(thr, pc, sz);
}
#define TSAN_MAYBE_INTERCEPT_PVALLOC TSAN_INTERCEPT(pvalloc)
#else
@@ -774,8 +790,7 @@ TSAN_INTERCEPTOR(void*, pvalloc, uptr sz) {
#if !SANITIZER_MAC
TSAN_INTERCEPTOR(int, posix_memalign, void **memptr, uptr align, uptr sz) {
SCOPED_INTERCEPTOR_RAW(posix_memalign, memptr, align, sz);
- *memptr = user_alloc(thr, pc, sz, align);
- return 0;
+ return user_posix_memalign(thr, pc, memptr, align, sz);
}
#endif
@@ -884,7 +899,7 @@ extern "C" void *__tsan_thread_start_func(void *arg) {
internal_sched_yield();
Processor *proc = ProcCreate();
ProcWire(proc, thr);
- ThreadStart(thr, tid, GetTid());
+ ThreadStart(thr, tid, GetTid(), /*workerthread*/ false);
atomic_store(&p->tid, 0, memory_order_release);
}
void *res = callback(param);
@@ -931,8 +946,7 @@ TSAN_INTERCEPTOR(int, pthread_create,
ThreadIgnoreEnd(thr, pc);
}
if (res == 0) {
- int tid = ThreadCreate(thr, pc, *(uptr*)th,
- detached == PTHREAD_CREATE_DETACHED);
+ int tid = ThreadCreate(thr, pc, *(uptr*)th, IsStateDetached(detached));
CHECK_NE(tid, 0);
// Synchronization on p.tid serves two purposes:
// 1. ThreadCreate must finish before the new thread starts.
@@ -1028,7 +1042,7 @@ static void cond_mutex_unlock(CondMutexUnlockCtx *arg) {
ThreadSignalContext *ctx = SigCtx(arg->thr);
CHECK_EQ(atomic_load(&ctx->in_blocking_func, memory_order_relaxed), 1);
atomic_store(&ctx->in_blocking_func, 0, memory_order_relaxed);
- MutexLock(arg->thr, arg->pc, (uptr)arg->m);
+ MutexPostLock(arg->thr, arg->pc, (uptr)arg->m, MutexFlagDoPreLockOnPostLock);
// Undo BlockingCall ctor effects.
arg->thr->ignore_interceptors--;
arg->si->~ScopedInterceptor();
@@ -1057,7 +1071,7 @@ static int cond_wait(ThreadState *thr, uptr pc, ScopedInterceptor *si,
fn, c, m, t, (void (*)(void *arg))cond_mutex_unlock, &arg);
}
if (res == errno_EOWNERDEAD) MutexRepair(thr, pc, (uptr)m);
- MutexLock(thr, pc, (uptr)m);
+ MutexPostLock(thr, pc, (uptr)m, MutexFlagDoPreLockOnPostLock);
return res;
}
@@ -1117,14 +1131,15 @@ TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_init, m, a);
int res = REAL(pthread_mutex_init)(m, a);
if (res == 0) {
- bool recursive = false;
+ u32 flagz = 0;
if (a) {
int type = 0;
if (REAL(pthread_mutexattr_gettype)(a, &type) == 0)
- recursive = (type == PTHREAD_MUTEX_RECURSIVE
- || type == PTHREAD_MUTEX_RECURSIVE_NP);
+ if (type == PTHREAD_MUTEX_RECURSIVE ||
+ type == PTHREAD_MUTEX_RECURSIVE_NP)
+ flagz |= MutexFlagWriteReentrant;
}
- MutexCreate(thr, pc, (uptr)m, false, recursive, false);
+ MutexCreate(thr, pc, (uptr)m, flagz);
}
return res;
}
@@ -1132,7 +1147,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_init, void *m, void *a) {
TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_destroy, m);
int res = REAL(pthread_mutex_destroy)(m);
- if (res == 0 || res == EBUSY) {
+ if (res == 0 || res == errno_EBUSY) {
MutexDestroy(thr, pc, (uptr)m);
}
return res;
@@ -1141,10 +1156,10 @@ TSAN_INTERCEPTOR(int, pthread_mutex_destroy, void *m) {
TSAN_INTERCEPTOR(int, pthread_mutex_trylock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_trylock, m);
int res = REAL(pthread_mutex_trylock)(m);
- if (res == EOWNERDEAD)
+ if (res == errno_EOWNERDEAD)
MutexRepair(thr, pc, (uptr)m);
- if (res == 0 || res == EOWNERDEAD)
- MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
+ if (res == 0 || res == errno_EOWNERDEAD)
+ MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
return res;
}
@@ -1153,7 +1168,7 @@ TSAN_INTERCEPTOR(int, pthread_mutex_timedlock, void *m, void *abstime) {
SCOPED_TSAN_INTERCEPTOR(pthread_mutex_timedlock, m, abstime);
int res = REAL(pthread_mutex_timedlock)(m, abstime);
if (res == 0) {
- MutexLock(thr, pc, (uptr)m);
+ MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
}
return res;
}
@@ -1164,7 +1179,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_init, void *m, int pshared) {
SCOPED_TSAN_INTERCEPTOR(pthread_spin_init, m, pshared);
int res = REAL(pthread_spin_init)(m, pshared);
if (res == 0) {
- MutexCreate(thr, pc, (uptr)m, false, false, false);
+ MutexCreate(thr, pc, (uptr)m);
}
return res;
}
@@ -1180,9 +1195,10 @@ TSAN_INTERCEPTOR(int, pthread_spin_destroy, void *m) {
TSAN_INTERCEPTOR(int, pthread_spin_lock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_spin_lock, m);
+ MutexPreLock(thr, pc, (uptr)m);
int res = REAL(pthread_spin_lock)(m);
if (res == 0) {
- MutexLock(thr, pc, (uptr)m);
+ MutexPostLock(thr, pc, (uptr)m);
}
return res;
}
@@ -1191,7 +1207,7 @@ TSAN_INTERCEPTOR(int, pthread_spin_trylock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_spin_trylock, m);
int res = REAL(pthread_spin_trylock)(m);
if (res == 0) {
- MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
+ MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
}
return res;
}
@@ -1208,7 +1224,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_init, void *m, void *a) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_init, m, a);
int res = REAL(pthread_rwlock_init)(m, a);
if (res == 0) {
- MutexCreate(thr, pc, (uptr)m, true, false, false);
+ MutexCreate(thr, pc, (uptr)m);
}
return res;
}
@@ -1224,9 +1240,10 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_destroy, void *m) {
TSAN_INTERCEPTOR(int, pthread_rwlock_rdlock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_rdlock, m);
+ MutexPreReadLock(thr, pc, (uptr)m);
int res = REAL(pthread_rwlock_rdlock)(m);
if (res == 0) {
- MutexReadLock(thr, pc, (uptr)m);
+ MutexPostReadLock(thr, pc, (uptr)m);
}
return res;
}
@@ -1235,7 +1252,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_tryrdlock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_tryrdlock, m);
int res = REAL(pthread_rwlock_tryrdlock)(m);
if (res == 0) {
- MutexReadLock(thr, pc, (uptr)m, /*try_lock=*/true);
+ MutexPostReadLock(thr, pc, (uptr)m, MutexFlagTryLock);
}
return res;
}
@@ -1245,7 +1262,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedrdlock, m, abstime);
int res = REAL(pthread_rwlock_timedrdlock)(m, abstime);
if (res == 0) {
- MutexReadLock(thr, pc, (uptr)m);
+ MutexPostReadLock(thr, pc, (uptr)m);
}
return res;
}
@@ -1253,9 +1270,10 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedrdlock, void *m, void *abstime) {
TSAN_INTERCEPTOR(int, pthread_rwlock_wrlock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_wrlock, m);
+ MutexPreLock(thr, pc, (uptr)m);
int res = REAL(pthread_rwlock_wrlock)(m);
if (res == 0) {
- MutexLock(thr, pc, (uptr)m);
+ MutexPostLock(thr, pc, (uptr)m);
}
return res;
}
@@ -1264,7 +1282,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_trywrlock, void *m) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_trywrlock, m);
int res = REAL(pthread_rwlock_trywrlock)(m);
if (res == 0) {
- MutexLock(thr, pc, (uptr)m, /*rec=*/1, /*try_lock=*/true);
+ MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
}
return res;
}
@@ -1274,7 +1292,7 @@ TSAN_INTERCEPTOR(int, pthread_rwlock_timedwrlock, void *m, void *abstime) {
SCOPED_TSAN_INTERCEPTOR(pthread_rwlock_timedwrlock, m, abstime);
int res = REAL(pthread_rwlock_timedwrlock)(m, abstime);
if (res == 0) {
- MutexLock(thr, pc, (uptr)m);
+ MutexPostLock(thr, pc, (uptr)m, MutexFlagTryLock);
}
return res;
}
@@ -1318,7 +1336,7 @@ TSAN_INTERCEPTOR(int, pthread_barrier_wait, void *b) {
TSAN_INTERCEPTOR(int, pthread_once, void *o, void (*f)()) {
SCOPED_INTERCEPTOR_RAW(pthread_once, o, f);
if (o == 0 || f == 0)
- return EINVAL;
+ return errno_EINVAL;
atomic_uint32_t *a;
if (!SANITIZER_MAC)
a = static_cast<atomic_uint32_t*>(o);
@@ -1355,7 +1373,7 @@ TSAN_INTERCEPTOR(int, __fxstat, int version, int fd, void *buf) {
#endif
TSAN_INTERCEPTOR(int, fstat, int fd, void *buf) {
-#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID
+#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_ANDROID || SANITIZER_NETBSD
SCOPED_TSAN_INTERCEPTOR(fstat, fd, buf);
if (fd > 0)
FdAccess(thr, pc, fd);
@@ -1647,24 +1665,6 @@ TSAN_INTERCEPTOR(void*, tmpfile64, int fake) {
#define TSAN_MAYBE_INTERCEPT_TMPFILE64
#endif
-TSAN_INTERCEPTOR(uptr, fread, void *ptr, uptr size, uptr nmemb, void *f) {
- // libc file streams can call user-supplied functions, see fopencookie.
- {
- SCOPED_TSAN_INTERCEPTOR(fread, ptr, size, nmemb, f);
- MemoryAccessRange(thr, pc, (uptr)ptr, size * nmemb, true);
- }
- return REAL(fread)(ptr, size, nmemb, f);
-}
-
-TSAN_INTERCEPTOR(uptr, fwrite, const void *p, uptr size, uptr nmemb, void *f) {
- // libc file streams can call user-supplied functions, see fopencookie.
- {
- SCOPED_TSAN_INTERCEPTOR(fwrite, p, size, nmemb, f);
- MemoryAccessRange(thr, pc, (uptr)p, size * nmemb, false);
- }
- return REAL(fwrite)(p, size, nmemb, f);
-}
-
static void FlushStreams() {
// Flushing all the streams here may freeze the process if a child thread is
// performing file stream operations at the same time.
@@ -1954,7 +1954,7 @@ TSAN_INTERCEPTOR(int, sigaction, int sig, sigaction_t *act, sigaction_t *old) {
sigactions[sig].sa_flags = *(volatile int*)&act->sa_flags;
internal_memcpy(&sigactions[sig].sa_mask, &act->sa_mask,
sizeof(sigactions[sig].sa_mask));
-#if !SANITIZER_FREEBSD && !SANITIZER_MAC
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD
sigactions[sig].sa_restorer = act->sa_restorer;
#endif
sigaction_t newact;
@@ -2254,8 +2254,12 @@ static void HandleRecvmsg(ThreadState *thr, uptr pc,
#define COMMON_INTERCEPTOR_ON_EXIT(ctx) \
OnExit(((TsanInterceptorContext *) ctx)->thr)
-#define COMMON_INTERCEPTOR_MUTEX_LOCK(ctx, m) \
- MutexLock(((TsanInterceptorContext *)ctx)->thr, \
+#define COMMON_INTERCEPTOR_MUTEX_PRE_LOCK(ctx, m) \
+ MutexPreLock(((TsanInterceptorContext *)ctx)->thr, \
+ ((TsanInterceptorContext *)ctx)->pc, (uptr)m)
+
+#define COMMON_INTERCEPTOR_MUTEX_POST_LOCK(ctx, m) \
+ MutexPostLock(((TsanInterceptorContext *)ctx)->thr, \
((TsanInterceptorContext *)ctx)->pc, (uptr)m)
#define COMMON_INTERCEPTOR_MUTEX_UNLOCK(ctx, m) \
@@ -2312,7 +2316,7 @@ struct ScopedSyscall {
}
};
-#if !SANITIZER_FREEBSD && !SANITIZER_MAC
+#if !SANITIZER_FREEBSD && !SANITIZER_MAC && !SANITIZER_NETBSD
static void syscall_access_range(uptr pc, uptr p, uptr s, bool write) {
TSAN_SYSCALL();
MemoryAccessRange(thr, pc, p, s, write);
@@ -2582,6 +2586,7 @@ void InitializeInterceptors() {
TSAN_INTERCEPT(sleep);
TSAN_INTERCEPT(usleep);
TSAN_INTERCEPT(nanosleep);
+ TSAN_INTERCEPT(pause);
TSAN_INTERCEPT(gettimeofday);
TSAN_INTERCEPT(getaddrinfo);
diff --git a/libsanitizer/tsan/tsan_interceptors.h b/libsanitizer/tsan/tsan_interceptors.h
index a0f9a07..de47466 100644
--- a/libsanitizer/tsan/tsan_interceptors.h
+++ b/libsanitizer/tsan/tsan_interceptors.h
@@ -10,14 +10,17 @@ class ScopedInterceptor {
public:
ScopedInterceptor(ThreadState *thr, const char *fname, uptr pc);
~ScopedInterceptor();
- void UserCallbackStart();
- void UserCallbackEnd();
+ void DisableIgnores();
+ void EnableIgnores();
private:
ThreadState *const thr_;
const uptr pc_;
bool in_ignored_lib_;
+ bool ignoring_;
};
+LibIgnore *libignore();
+
} // namespace __tsan
#define SCOPED_INTERCEPTOR_RAW(func, ...) \
@@ -39,10 +42,10 @@ class ScopedInterceptor {
/**/
#define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START() \
- si.UserCallbackStart();
+ si.DisableIgnores();
#define SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END() \
- si.UserCallbackEnd();
+ si.EnableIgnores();
#define TSAN_INTERCEPTOR(ret, func, ...) INTERCEPTOR(ret, func, __VA_ARGS__)
diff --git a/libsanitizer/tsan/tsan_interceptors_mac.cc b/libsanitizer/tsan/tsan_interceptors_mac.cc
index eaf866d..913e9ed 100644
--- a/libsanitizer/tsan/tsan_interceptors_mac.cc
+++ b/libsanitizer/tsan/tsan_interceptors_mac.cc
@@ -19,7 +19,10 @@
#include "tsan_interface_ann.h"
#include <libkern/OSAtomic.h>
+
+#if defined(__has_include) && __has_include(<xpc/xpc.h>)
#include <xpc/xpc.h>
+#endif // #if defined(__has_include) && __has_include(<xpc/xpc.h>)
typedef long long_t; // NOLINT
@@ -233,6 +236,8 @@ TSAN_INTERCEPTOR(void, os_lock_unlock, void *lock) {
REAL(os_lock_unlock)(lock);
}
+#if defined(__has_include) && __has_include(<xpc/xpc.h>)
+
TSAN_INTERCEPTOR(void, xpc_connection_set_event_handler,
xpc_connection_t connection, xpc_handler_t handler) {
SCOPED_TSAN_INTERCEPTOR(xpc_connection_set_event_handler, connection,
@@ -279,6 +284,14 @@ TSAN_INTERCEPTOR(void, xpc_connection_send_message_with_reply,
(connection, message, replyq, new_handler);
}
+TSAN_INTERCEPTOR(void, xpc_connection_cancel, xpc_connection_t connection) {
+ SCOPED_TSAN_INTERCEPTOR(xpc_connection_cancel, connection);
+ Release(thr, pc, (uptr)connection);
+ REAL(xpc_connection_cancel)(connection);
+}
+
+#endif // #if defined(__has_include) && __has_include(<xpc/xpc.h>)
+
// On macOS, libc++ is always linked dynamically, so intercepting works the
// usual way.
#define STDCXX_INTERCEPTOR TSAN_INTERCEPTOR
@@ -295,18 +308,20 @@ struct fake_shared_weak_count {
};
} // namespace
-// This adds a libc++ interceptor for:
+// The following code adds libc++ interceptors for:
// void __shared_weak_count::__release_shared() _NOEXCEPT;
+// bool __shared_count::__release_shared() _NOEXCEPT;
// Shared and weak pointers in C++ maintain reference counts via atomics in
// libc++.dylib, which are TSan-invisible, and this leads to false positives in
-// destructor code. This interceptor re-implements the whole function so that
+// destructor code. These interceptors re-implements the whole functions so that
// the mo_acq_rel semantics of the atomic decrement are visible.
//
-// Unfortunately, this interceptor cannot simply Acquire/Release some sync
+// Unfortunately, the interceptors cannot simply Acquire/Release some sync
// object and call the original function, because it would have a race between
// the sync and the destruction of the object. Calling both under a lock will
// not work because the destructor can invoke this interceptor again (and even
// in a different thread, so recursive locks don't help).
+
STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv,
fake_shared_weak_count *o) {
if (!flags()->shared_ptr_interceptor)
@@ -325,6 +340,20 @@ STDCXX_INTERCEPTOR(void, _ZNSt3__119__shared_weak_count16__release_sharedEv,
}
}
+STDCXX_INTERCEPTOR(bool, _ZNSt3__114__shared_count16__release_sharedEv,
+ fake_shared_weak_count *o) {
+ if (!flags()->shared_ptr_interceptor)
+ return REAL(_ZNSt3__114__shared_count16__release_sharedEv)(o);
+
+ SCOPED_TSAN_INTERCEPTOR(_ZNSt3__114__shared_count16__release_sharedEv, o);
+ if (__tsan_atomic64_fetch_add(&o->shared_owners, -1, mo_release) == 0) {
+ Acquire(thr, pc, (uptr)&o->shared_owners);
+ o->on_zero_shared();
+ return true;
+ }
+ return false;
+}
+
namespace {
struct call_once_callback_args {
void (*orig_func)(void *arg);
diff --git a/libsanitizer/tsan/tsan_interface.cc b/libsanitizer/tsan/tsan_interface.cc
index ee9a627..d98ff15 100644
--- a/libsanitizer/tsan/tsan_interface.cc
+++ b/libsanitizer/tsan/tsan_interface.cc
@@ -26,6 +26,10 @@ void __tsan_init() {
Initialize(cur_thread());
}
+void __tsan_flush_memory() {
+ FlushShadowMemory();
+}
+
void __tsan_read16(void *addr) {
MemoryRead(cur_thread(), CALLERPC, (uptr)addr, kSizeLog8);
MemoryRead(cur_thread(), CALLERPC, (uptr)addr + 8, kSizeLog8);
diff --git a/libsanitizer/tsan/tsan_interface.h b/libsanitizer/tsan/tsan_interface.h
index 066dde6..7dc6765 100644
--- a/libsanitizer/tsan/tsan_interface.h
+++ b/libsanitizer/tsan/tsan_interface.h
@@ -16,6 +16,7 @@
#include <sanitizer_common/sanitizer_internal_defs.h>
using __sanitizer::uptr;
+using __sanitizer::tid_t;
// This header should NOT include any other headers.
// All functions in this header are extern "C" and start with __tsan_.
@@ -30,6 +31,8 @@ extern "C" {
// before any instrumented code is executed and before any call to malloc.
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_init();
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_flush_memory();
+
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read1(void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read2(void *addr);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_read4(void *addr);
@@ -71,6 +74,20 @@ void __tsan_vptr_update(void **vptr_p, void *new_val);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_entry(void *call_pc);
SANITIZER_INTERFACE_ATTRIBUTE void __tsan_func_exit();
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_ignore_thread_begin();
+SANITIZER_INTERFACE_ATTRIBUTE void __tsan_ignore_thread_end();
+
+SANITIZER_INTERFACE_ATTRIBUTE
+void *__tsan_external_register_tag(const char *object_type);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_register_header(void *tag, const char *header);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_assign_tag(void *addr, void *tag);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_read(void *addr, void *caller_pc, void *tag);
+SANITIZER_INTERFACE_ATTRIBUTE
+void __tsan_external_write(void *addr, void *caller_pc, void *tag);
+
SANITIZER_INTERFACE_ATTRIBUTE
void __tsan_read_range(void *addr, unsigned long size); // NOLINT
SANITIZER_INTERFACE_ATTRIBUTE
@@ -116,6 +133,10 @@ int __tsan_get_report_loc(void *report, uptr idx, const char **type,
int *fd, int *suppressable, void **trace,
uptr trace_size);
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_report_loc_object_type(void *report, uptr idx,
+ const char **object_type);
+
// Returns information about mutexes included in the report.
SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
@@ -123,7 +144,7 @@ int __tsan_get_report_mutex(void *report, uptr idx, uptr *mutex_id, void **addr,
// Returns information about threads included in the report.
SANITIZER_INTERFACE_ATTRIBUTE
-int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *os_id,
+int __tsan_get_report_thread(void *report, uptr idx, int *tid, tid_t *os_id,
int *running, const char **name, int *parent_tid,
void **trace, uptr trace_size);
@@ -131,6 +152,17 @@ int __tsan_get_report_thread(void *report, uptr idx, int *tid, uptr *os_id,
SANITIZER_INTERFACE_ATTRIBUTE
int __tsan_get_report_unique_tid(void *report, uptr idx, int *tid);
+// Returns the type of the pointer (heap, stack, global, ...) and if possible
+// also the starting address (e.g. of a heap allocation) and size.
+SANITIZER_INTERFACE_ATTRIBUTE
+const char *__tsan_locate_address(uptr addr, char *name, uptr name_size,
+ uptr *region_address, uptr *region_size);
+
+// Returns the allocation stack for a heap pointer.
+SANITIZER_INTERFACE_ATTRIBUTE
+int __tsan_get_alloc_stack(uptr addr, uptr *trace, uptr size, int *thread_id,
+ tid_t *os_id);
+
#endif // SANITIZER_GO
#ifdef __cplusplus
diff --git a/libsanitizer/tsan/tsan_interface_ann.cc b/libsanitizer/tsan/tsan_interface_ann.cc
index 19ff405..083138f 100644
--- a/libsanitizer/tsan/tsan_interface_ann.cc
+++ b/libsanitizer/tsan/tsan_interface_ann.cc
@@ -29,11 +29,10 @@ namespace __tsan {
class ScopedAnnotation {
public:
- ScopedAnnotation(ThreadState *thr, const char *aname, const char *f, int l,
- uptr pc)
+ ScopedAnnotation(ThreadState *thr, const char *aname, uptr pc)
: thr_(thr) {
FuncEntry(thr_, pc);
- DPrintf("#%d: annotation %s() %s:%d\n", thr_->tid, aname, f, l);
+ DPrintf("#%d: annotation %s()\n", thr_->tid, aname);
}
~ScopedAnnotation() {
@@ -44,18 +43,20 @@ class ScopedAnnotation {
ThreadState *const thr_;
};
-#define SCOPED_ANNOTATION(typ) \
+#define SCOPED_ANNOTATION_RET(typ, ret) \
if (!flags()->enable_annotations) \
- return; \
+ return ret; \
ThreadState *thr = cur_thread(); \
const uptr caller_pc = (uptr)__builtin_return_address(0); \
StatInc(thr, StatAnnotation); \
StatInc(thr, Stat##typ); \
- ScopedAnnotation sa(thr, __func__, f, l, caller_pc); \
+ ScopedAnnotation sa(thr, __func__, caller_pc); \
const uptr pc = StackTrace::GetCurrentPc(); \
(void)pc; \
/**/
+#define SCOPED_ANNOTATION(typ) SCOPED_ANNOTATION_RET(typ, )
+
static const int kMaxDescLen = 128;
struct ExpectRace {
@@ -250,12 +251,12 @@ void INTERFACE_ATTRIBUTE AnnotateCondVarWait(char *f, int l, uptr cv,
void INTERFACE_ATTRIBUTE AnnotateRWLockCreate(char *f, int l, uptr m) {
SCOPED_ANNOTATION(AnnotateRWLockCreate);
- MutexCreate(thr, pc, m, true, true, false);
+ MutexCreate(thr, pc, m, MutexFlagWriteReentrant);
}
void INTERFACE_ATTRIBUTE AnnotateRWLockCreateStatic(char *f, int l, uptr m) {
SCOPED_ANNOTATION(AnnotateRWLockCreateStatic);
- MutexCreate(thr, pc, m, true, true, true);
+ MutexCreate(thr, pc, m, MutexFlagWriteReentrant | MutexFlagLinkerInit);
}
void INTERFACE_ATTRIBUTE AnnotateRWLockDestroy(char *f, int l, uptr m) {
@@ -267,9 +268,9 @@ void INTERFACE_ATTRIBUTE AnnotateRWLockAcquired(char *f, int l, uptr m,
uptr is_w) {
SCOPED_ANNOTATION(AnnotateRWLockAcquired);
if (is_w)
- MutexLock(thr, pc, m);
+ MutexPostLock(thr, pc, m, MutexFlagDoPreLockOnPostLock);
else
- MutexReadLock(thr, pc, m);
+ MutexPostReadLock(thr, pc, m, MutexFlagDoPreLockOnPostLock);
}
void INTERFACE_ATTRIBUTE AnnotateRWLockReleased(char *f, int l, uptr m,
@@ -456,4 +457,95 @@ void INTERFACE_ATTRIBUTE
AnnotateMemoryIsInitialized(char *f, int l, uptr mem, uptr sz) {}
void INTERFACE_ATTRIBUTE
AnnotateMemoryIsUninitialized(char *f, int l, uptr mem, uptr sz) {}
+
+// Note: the parameter is called flagz, because flags is already taken
+// by the global function that returns flags.
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_create(void *m, unsigned flagz) {
+ SCOPED_ANNOTATION(__tsan_mutex_create);
+ MutexCreate(thr, pc, (uptr)m, flagz & MutexCreationFlagMask);
+}
+
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_destroy(void *m, unsigned flagz) {
+ SCOPED_ANNOTATION(__tsan_mutex_destroy);
+ MutexDestroy(thr, pc, (uptr)m, flagz);
+}
+
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_pre_lock(void *m, unsigned flagz) {
+ SCOPED_ANNOTATION(__tsan_mutex_pre_lock);
+ if (!(flagz & MutexFlagTryLock)) {
+ if (flagz & MutexFlagReadLock)
+ MutexPreReadLock(thr, pc, (uptr)m);
+ else
+ MutexPreLock(thr, pc, (uptr)m);
+ }
+ ThreadIgnoreBegin(thr, pc, /*save_stack=*/false);
+ ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false);
+}
+
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_post_lock(void *m, unsigned flagz, int rec) {
+ SCOPED_ANNOTATION(__tsan_mutex_post_lock);
+ ThreadIgnoreSyncEnd(thr, pc);
+ ThreadIgnoreEnd(thr, pc);
+ if (!(flagz & MutexFlagTryLockFailed)) {
+ if (flagz & MutexFlagReadLock)
+ MutexPostReadLock(thr, pc, (uptr)m, flagz);
+ else
+ MutexPostLock(thr, pc, (uptr)m, flagz, rec);
+ }
+}
+
+INTERFACE_ATTRIBUTE
+int __tsan_mutex_pre_unlock(void *m, unsigned flagz) {
+ SCOPED_ANNOTATION_RET(__tsan_mutex_pre_unlock, 0);
+ int ret = 0;
+ if (flagz & MutexFlagReadLock) {
+ CHECK(!(flagz & MutexFlagRecursiveUnlock));
+ MutexReadUnlock(thr, pc, (uptr)m);
+ } else {
+ ret = MutexUnlock(thr, pc, (uptr)m, flagz);
+ }
+ ThreadIgnoreBegin(thr, pc, /*save_stack=*/false);
+ ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false);
+ return ret;
+}
+
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_post_unlock(void *m, unsigned flagz) {
+ SCOPED_ANNOTATION(__tsan_mutex_post_unlock);
+ ThreadIgnoreSyncEnd(thr, pc);
+ ThreadIgnoreEnd(thr, pc);
+}
+
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_pre_signal(void *addr, unsigned flagz) {
+ SCOPED_ANNOTATION(__tsan_mutex_pre_signal);
+ ThreadIgnoreBegin(thr, pc, /*save_stack=*/false);
+ ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false);
+}
+
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_post_signal(void *addr, unsigned flagz) {
+ SCOPED_ANNOTATION(__tsan_mutex_post_signal);
+ ThreadIgnoreSyncEnd(thr, pc);
+ ThreadIgnoreEnd(thr, pc);
+}
+
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_pre_divert(void *addr, unsigned flagz) {
+ SCOPED_ANNOTATION(__tsan_mutex_pre_divert);
+ // Exit from ignore region started in __tsan_mutex_pre_lock/unlock/signal.
+ ThreadIgnoreSyncEnd(thr, pc);
+ ThreadIgnoreEnd(thr, pc);
+}
+
+INTERFACE_ATTRIBUTE
+void __tsan_mutex_post_divert(void *addr, unsigned flagz) {
+ SCOPED_ANNOTATION(__tsan_mutex_post_divert);
+ ThreadIgnoreBegin(thr, pc, /*save_stack=*/false);
+ ThreadIgnoreSyncBegin(thr, pc, /*save_stack=*/false);
+}
} // extern "C"
diff --git a/libsanitizer/tsan/tsan_interface_atomic.cc b/libsanitizer/tsan/tsan_interface_atomic.cc
index deb4206..c175d61 100644
--- a/libsanitizer/tsan/tsan_interface_atomic.cc
+++ b/libsanitizer/tsan/tsan_interface_atomic.cc
@@ -218,8 +218,7 @@ static a128 NoTsanAtomicLoad(const volatile a128 *a, morder mo) {
#endif
template<typename T>
-static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
- morder mo) {
+static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a, morder mo) {
CHECK(IsLoadOrder(mo));
// This fast-path is critical for performance.
// Assume the access is atomic.
@@ -227,10 +226,17 @@ static T AtomicLoad(ThreadState *thr, uptr pc, const volatile T *a,
MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
return NoTsanAtomicLoad(a, mo);
}
- SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, (uptr)a, false);
- AcquireImpl(thr, pc, &s->clock);
+ // Don't create sync object if it does not exist yet. For example, an atomic
+ // pointer is initialized to nullptr and then periodically acquire-loaded.
T v = NoTsanAtomicLoad(a, mo);
- s->mtx.ReadUnlock();
+ SyncVar *s = ctx->metamap.GetIfExistsAndLock((uptr)a, false);
+ if (s) {
+ AcquireImpl(thr, pc, &s->clock);
+ // Re-read under sync mutex because we need a consistent snapshot
+ // of the value and the clock we acquire.
+ v = NoTsanAtomicLoad(a, mo);
+ s->mtx.ReadUnlock();
+ }
MemoryReadAtomic(thr, pc, (uptr)a, SizeLog<T>());
return v;
}
@@ -265,7 +271,7 @@ static void AtomicStore(ThreadState *thr, uptr pc, volatile T *a, T v,
thr->fast_state.IncrementEpoch();
// Can't increment epoch w/o writing to the trace as well.
TraceAddEvent(thr, thr->fast_state, EventTypeMop, 0);
- ReleaseImpl(thr, pc, &s->clock);
+ ReleaseStoreImpl(thr, pc, &s->clock);
NoTsanAtomicStore(a, v, mo);
s->mtx.Unlock();
}
@@ -448,7 +454,7 @@ static void AtomicFence(ThreadState *thr, uptr pc, morder mo) {
// C/C++
-static morder covert_morder(morder mo) {
+static morder convert_morder(morder mo) {
if (flags()->force_seq_cst_atomics)
return (morder)mo_seq_cst;
@@ -466,12 +472,14 @@ static morder covert_morder(morder mo) {
}
#define SCOPED_ATOMIC(func, ...) \
- const uptr callpc = (uptr)__builtin_return_address(0); \
- uptr pc = StackTrace::GetCurrentPc(); \
- mo = covert_morder(mo); \
ThreadState *const thr = cur_thread(); \
- if (thr->ignore_interceptors) \
+ if (thr->ignore_sync || thr->ignore_interceptors) { \
+ ProcessPendingSignals(thr); \
return NoTsanAtomic##func(__VA_ARGS__); \
+ } \
+ const uptr callpc = (uptr)__builtin_return_address(0); \
+ uptr pc = StackTrace::GetCurrentPc(); \
+ mo = convert_morder(mo); \
AtomicStatInc(thr, sizeof(*a), mo, StatAtomic##func); \
ScopedAtomic sa(thr, callpc, a, mo, __func__); \
return Atomic##func(thr, pc, __VA_ARGS__); \
diff --git a/libsanitizer/tsan/tsan_interface_inl.h b/libsanitizer/tsan/tsan_interface_inl.h
index 67a91aa..bf70cdc 100644
--- a/libsanitizer/tsan/tsan_interface_inl.h
+++ b/libsanitizer/tsan/tsan_interface_inl.h
@@ -106,6 +106,14 @@ void __tsan_func_exit() {
FuncExit(cur_thread());
}
+void __tsan_ignore_thread_begin() {
+ ThreadIgnoreBegin(cur_thread(), CALLERPC);
+}
+
+void __tsan_ignore_thread_end() {
+ ThreadIgnoreEnd(cur_thread(), CALLERPC);
+}
+
void __tsan_read_range(void *addr, uptr size) {
MemoryAccessRange(cur_thread(), CALLERPC, (uptr)addr, size, false);
}
diff --git a/libsanitizer/tsan/tsan_interface_java.cc b/libsanitizer/tsan/tsan_interface_java.cc
index d1638f2..d3f35a9 100644
--- a/libsanitizer/tsan/tsan_interface_java.cc
+++ b/libsanitizer/tsan/tsan_interface_java.cc
@@ -148,6 +148,23 @@ void __tsan_java_move(jptr src, jptr dst, jptr size) {
}
}
+jptr __tsan_java_find(jptr *from_ptr, jptr to) {
+ SCOPED_JAVA_FUNC(__tsan_java_find);
+ DPrintf("#%d: java_find(&%p, %p)\n", *from_ptr, to);
+ CHECK_EQ((*from_ptr) % kHeapAlignment, 0);
+ CHECK_EQ(to % kHeapAlignment, 0);
+ CHECK_GE(*from_ptr, jctx->heap_begin);
+ CHECK_LE(to, jctx->heap_begin + jctx->heap_size);
+ for (uptr from = *from_ptr; from < to; from += kHeapAlignment) {
+ MBlock *b = ctx->metamap.GetBlock(from);
+ if (b) {
+ *from_ptr = from;
+ return b->siz;
+ }
+ }
+ return 0;
+}
+
void __tsan_java_finalize() {
SCOPED_JAVA_FUNC(__tsan_java_finalize);
DPrintf("#%d: java_mutex_finalize()\n", thr->tid);
@@ -161,8 +178,8 @@ void __tsan_java_mutex_lock(jptr addr) {
CHECK_GE(addr, jctx->heap_begin);
CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
- MutexCreate(thr, pc, addr, true, true, true);
- MutexLock(thr, pc, addr);
+ MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant |
+ MutexFlagDoPreLockOnPostLock);
}
void __tsan_java_mutex_unlock(jptr addr) {
@@ -182,8 +199,8 @@ void __tsan_java_mutex_read_lock(jptr addr) {
CHECK_GE(addr, jctx->heap_begin);
CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
- MutexCreate(thr, pc, addr, true, true, true);
- MutexReadLock(thr, pc, addr);
+ MutexPostReadLock(thr, pc, addr, MutexFlagLinkerInit |
+ MutexFlagWriteReentrant | MutexFlagDoPreLockOnPostLock);
}
void __tsan_java_mutex_read_unlock(jptr addr) {
@@ -204,8 +221,8 @@ void __tsan_java_mutex_lock_rec(jptr addr, int rec) {
CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
CHECK_GT(rec, 0);
- MutexCreate(thr, pc, addr, true, true, true);
- MutexLock(thr, pc, addr, rec);
+ MutexPostLock(thr, pc, addr, MutexFlagLinkerInit | MutexFlagWriteReentrant |
+ MutexFlagDoPreLockOnPostLock | MutexFlagRecursiveLock, rec);
}
int __tsan_java_mutex_unlock_rec(jptr addr) {
@@ -215,7 +232,7 @@ int __tsan_java_mutex_unlock_rec(jptr addr) {
CHECK_GE(addr, jctx->heap_begin);
CHECK_LT(addr, jctx->heap_begin + jctx->heap_size);
- return MutexUnlock(thr, pc, addr, true);
+ return MutexUnlock(thr, pc, addr, MutexFlagRecursiveUnlock);
}
void __tsan_java_acquire(jptr addr) {
diff --git a/libsanitizer/tsan/tsan_interface_java.h b/libsanitizer/tsan/tsan_interface_java.h
index 04e5203..2dd49f0 100644
--- a/libsanitizer/tsan/tsan_interface_java.h
+++ b/libsanitizer/tsan/tsan_interface_java.h
@@ -55,6 +55,10 @@ void __tsan_java_move(jptr src, jptr dst, jptr size) INTERFACE_ATTRIBUTE;
// It ensures necessary synchronization between
// java object creation and finalization.
void __tsan_java_finalize() INTERFACE_ATTRIBUTE;
+// Finds the first allocated memory block in the [*from_ptr, to) range, saves
+// its address in *from_ptr and returns its size. Returns 0 if there are no
+// allocated memory blocks in the range.
+jptr __tsan_java_find(jptr *from_ptr, jptr to) INTERFACE_ATTRIBUTE;
// Mutex lock.
// Addr is any unique address associated with the mutex.
diff --git a/libsanitizer/tsan/tsan_libdispatch_mac.cc b/libsanitizer/tsan/tsan_libdispatch_mac.cc
index 10c70a8..5200a79 100644
--- a/libsanitizer/tsan/tsan_libdispatch_mac.cc
+++ b/libsanitizer/tsan/tsan_libdispatch_mac.cc
@@ -66,13 +66,17 @@ static bool IsQueueSerial(dispatch_queue_t q) {
return width == 1;
}
-static dispatch_queue_t GetTargetQueueFromSource(dispatch_source_t source) {
+static dispatch_queue_t GetTargetQueueFromQueue(dispatch_queue_t q) {
CHECK_EQ(dispatch_queue_offsets.dqo_target_queue_size, 8);
- dispatch_queue_t target_queue =
- *(dispatch_queue_t *)(((uptr)source) +
- dispatch_queue_offsets.dqo_target_queue);
- CHECK_NE(target_queue, 0);
- return target_queue;
+ dispatch_queue_t tq = *(
+ dispatch_queue_t *)(((uptr)q) + dispatch_queue_offsets.dqo_target_queue);
+ return tq;
+}
+
+static dispatch_queue_t GetTargetQueueFromSource(dispatch_source_t source) {
+ dispatch_queue_t tq = GetTargetQueueFromQueue((dispatch_queue_t)source);
+ CHECK_NE(tq, 0);
+ return tq;
}
static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc,
@@ -80,37 +84,66 @@ static tsan_block_context_t *AllocContext(ThreadState *thr, uptr pc,
void *orig_context,
dispatch_function_t orig_work) {
tsan_block_context_t *new_context =
- (tsan_block_context_t *)user_alloc(thr, pc, sizeof(tsan_block_context_t));
+ (tsan_block_context_t *)user_alloc_internal(thr, pc,
+ sizeof(tsan_block_context_t));
new_context->queue = queue;
new_context->orig_context = orig_context;
new_context->orig_work = orig_work;
new_context->free_context_in_callback = true;
new_context->submitted_synchronously = false;
new_context->is_barrier_block = false;
+ new_context->non_queue_sync_object = 0;
return new_context;
}
+#define GET_QUEUE_SYNC_VARS(context, q) \
+ bool is_queue_serial = q && IsQueueSerial(q); \
+ uptr sync_ptr = (uptr)q ?: context->non_queue_sync_object; \
+ uptr serial_sync = (uptr)sync_ptr; \
+ uptr concurrent_sync = sync_ptr ? ((uptr)sync_ptr) + sizeof(uptr) : 0; \
+ bool serial_task = context->is_barrier_block || is_queue_serial
+
+static void dispatch_sync_pre_execute(ThreadState *thr, uptr pc,
+ tsan_block_context_t *context) {
+ uptr submit_sync = (uptr)context;
+ Acquire(thr, pc, submit_sync);
+
+ dispatch_queue_t q = context->queue;
+ do {
+ GET_QUEUE_SYNC_VARS(context, q);
+ if (serial_sync) Acquire(thr, pc, serial_sync);
+ if (serial_task && concurrent_sync) Acquire(thr, pc, concurrent_sync);
+
+ if (q) q = GetTargetQueueFromQueue(q);
+ } while (q);
+}
+
+static void dispatch_sync_post_execute(ThreadState *thr, uptr pc,
+ tsan_block_context_t *context) {
+ uptr submit_sync = (uptr)context;
+ if (context->submitted_synchronously) Release(thr, pc, submit_sync);
+
+ dispatch_queue_t q = context->queue;
+ do {
+ GET_QUEUE_SYNC_VARS(context, q);
+ if (serial_task && serial_sync) Release(thr, pc, serial_sync);
+ if (!serial_task && concurrent_sync) Release(thr, pc, concurrent_sync);
+
+ if (q) q = GetTargetQueueFromQueue(q);
+ } while (q);
+}
+
static void dispatch_callback_wrap(void *param) {
SCOPED_INTERCEPTOR_RAW(dispatch_callback_wrap);
tsan_block_context_t *context = (tsan_block_context_t *)param;
- bool is_queue_serial = context->queue && IsQueueSerial(context->queue);
- uptr sync_ptr = (uptr)context->queue ?: context->non_queue_sync_object;
-
- uptr serial_sync = (uptr)sync_ptr;
- uptr concurrent_sync = ((uptr)sync_ptr) + sizeof(uptr);
- uptr submit_sync = (uptr)context;
- bool serial_task = context->is_barrier_block || is_queue_serial;
- Acquire(thr, pc, submit_sync);
- Acquire(thr, pc, serial_sync);
- if (serial_task) Acquire(thr, pc, concurrent_sync);
+ dispatch_sync_pre_execute(thr, pc, context);
SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START();
context->orig_work(context->orig_context);
SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_END();
- Release(thr, pc, serial_task ? serial_sync : concurrent_sync);
- if (context->submitted_synchronously) Release(thr, pc, submit_sync);
+ dispatch_sync_post_execute(thr, pc, context);
if (context->free_context_in_callback) user_free(thr, pc, context);
}
@@ -142,7 +175,8 @@ static void invoke_and_release_block(void *param) {
}
#define DISPATCH_INTERCEPT_SYNC_B(name, barrier) \
- TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, dispatch_block_t block) { \
+ TSAN_INTERCEPTOR(void, name, dispatch_queue_t q, \
+ DISPATCH_NOESCAPE dispatch_block_t block) { \
SCOPED_TSAN_INTERCEPTOR(name, q, block); \
SCOPED_TSAN_INTERCEPTOR_USER_CALLBACK_START(); \
dispatch_block_t heap_block = Block_copy(block); \
@@ -232,7 +266,7 @@ TSAN_INTERCEPTOR(void, dispatch_after_f, dispatch_time_t when,
// need to undefine the macro.
#undef dispatch_once
TSAN_INTERCEPTOR(void, dispatch_once, dispatch_once_t *predicate,
- dispatch_block_t block) {
+ DISPATCH_NOESCAPE dispatch_block_t block) {
SCOPED_INTERCEPTOR_RAW(dispatch_once, predicate, block);
atomic_uint32_t *a = reinterpret_cast<atomic_uint32_t *>(predicate);
u32 v = atomic_load(a, memory_order_acquire);
@@ -442,7 +476,8 @@ TSAN_INTERCEPTOR(void, dispatch_source_set_registration_handler_f,
}
TSAN_INTERCEPTOR(void, dispatch_apply, size_t iterations,
- dispatch_queue_t queue, void (^block)(size_t)) {
+ dispatch_queue_t queue,
+ DISPATCH_NOESCAPE void (^block)(size_t)) {
SCOPED_TSAN_INTERCEPTOR(dispatch_apply, iterations, queue, block);
void *parent_to_child_sync = nullptr;
@@ -674,6 +709,15 @@ TSAN_INTERCEPTOR(void, dispatch_io_close, dispatch_io_t channel,
return REAL(dispatch_io_close)(channel, flags);
}
+// Resuming a suspended queue needs to synchronize with all subsequent
+// executions of blocks in that queue.
+TSAN_INTERCEPTOR(void, dispatch_resume, dispatch_object_t o) {
+ SCOPED_TSAN_INTERCEPTOR(dispatch_resume, o);
+ Release(thr, pc, (uptr)o); // Synchronizes with the Acquire() on serial_sync
+ // in dispatch_sync_pre_execute
+ return REAL(dispatch_resume)(o);
+}
+
} // namespace __tsan
#endif // SANITIZER_MAC
diff --git a/libsanitizer/tsan/tsan_malloc_mac.cc b/libsanitizer/tsan/tsan_malloc_mac.cc
index cc1031a..b418a21 100644
--- a/libsanitizer/tsan/tsan_malloc_mac.cc
+++ b/libsanitizer/tsan/tsan_malloc_mac.cc
@@ -24,7 +24,7 @@ using namespace __tsan;
#define COMMON_MALLOC_FORCE_UNLOCK()
#define COMMON_MALLOC_MEMALIGN(alignment, size) \
void *p = \
- user_alloc(cur_thread(), StackTrace::GetCurrentPc(), size, alignment)
+ user_memalign(cur_thread(), StackTrace::GetCurrentPc(), alignment, size)
#define COMMON_MALLOC_MALLOC(size) \
if (cur_thread()->in_symbolizer) return InternalAlloc(size); \
SCOPED_INTERCEPTOR_RAW(malloc, size); \
@@ -41,7 +41,7 @@ using namespace __tsan;
if (cur_thread()->in_symbolizer) \
return InternalAlloc(size, nullptr, GetPageSizeCached()); \
SCOPED_INTERCEPTOR_RAW(valloc, size); \
- void *p = user_alloc(thr, pc, size, GetPageSizeCached())
+ void *p = user_valloc(thr, pc, size)
#define COMMON_MALLOC_FREE(ptr) \
if (cur_thread()->in_symbolizer) return InternalFree(ptr); \
SCOPED_INTERCEPTOR_RAW(free, ptr); \
diff --git a/libsanitizer/tsan/tsan_mman.cc b/libsanitizer/tsan/tsan_mman.cc
index 152c2de..18505ac 100644
--- a/libsanitizer/tsan/tsan_mman.cc
+++ b/libsanitizer/tsan/tsan_mman.cc
@@ -8,8 +8,10 @@
// This file is a part of ThreadSanitizer (TSan), a race detector.
//
//===----------------------------------------------------------------------===//
+#include "sanitizer_common/sanitizer_allocator_checks.h"
#include "sanitizer_common/sanitizer_allocator_interface.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_errno.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "tsan_mman.h"
#include "tsan_rtl.h"
@@ -52,7 +54,8 @@ struct MapUnmapCallback {
diff = p + size - RoundDown(p + size, kPageSize);
if (diff != 0)
size -= diff;
- ReleaseMemoryToOS((uptr)MemToMeta(p), size / kMetaRatio);
+ uptr p_meta = (uptr)MemToMeta(p);
+ ReleaseMemoryPagesToOS(p_meta, p_meta + size / kMetaRatio);
}
};
@@ -109,7 +112,8 @@ ScopedGlobalProcessor::~ScopedGlobalProcessor() {
}
void InitializeAllocator() {
- allocator()->Init(common_flags()->allocator_may_return_null);
+ SetAllocatorMayReturnNull(common_flags()->allocator_may_return_null);
+ allocator()->Init(common_flags()->allocator_release_to_os_interval_ms);
}
void InitializeAllocatorLate() {
@@ -144,11 +148,12 @@ static void SignalUnsafeCall(ThreadState *thr, uptr pc) {
OutputReport(thr, rep);
}
-void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
+void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz, uptr align,
+ bool signal) {
if ((sz >= (1ull << 40)) || (align >= (1ull << 40)))
- return allocator()->ReturnNullOrDieOnBadRequest();
+ return Allocator::FailureHandler::OnBadRequest();
void *p = allocator()->Allocate(&thr->proc()->alloc_cache, sz, align);
- if (p == 0)
+ if (UNLIKELY(p == 0))
return 0;
if (ctx && ctx->initialized)
OnUserAlloc(thr, pc, (uptr)p, sz, true);
@@ -157,15 +162,6 @@ void *user_alloc(ThreadState *thr, uptr pc, uptr sz, uptr align, bool signal) {
return p;
}
-void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) {
- if (CallocShouldReturnNullDueToOverflow(size, n))
- return allocator()->ReturnNullOrDieOnBadRequest();
- void *p = user_alloc(thr, pc, n * size);
- if (p)
- internal_memset(p, 0, n * size);
- return p;
-}
-
void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
ScopedGlobalProcessor sgp;
if (ctx && ctx->initialized)
@@ -175,6 +171,19 @@ void user_free(ThreadState *thr, uptr pc, void *p, bool signal) {
SignalUnsafeCall(thr, pc);
}
+void *user_alloc(ThreadState *thr, uptr pc, uptr sz) {
+ return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, kDefaultAlignment));
+}
+
+void *user_calloc(ThreadState *thr, uptr pc, uptr size, uptr n) {
+ if (UNLIKELY(CheckForCallocOverflow(size, n)))
+ return SetErrnoOnNull(Allocator::FailureHandler::OnBadRequest());
+ void *p = user_alloc_internal(thr, pc, n * size);
+ if (p)
+ internal_memset(p, 0, n * size);
+ return SetErrnoOnNull(p);
+}
+
void OnUserAlloc(ThreadState *thr, uptr pc, uptr p, uptr sz, bool write) {
DPrintf("#%d: alloc(%zu) = %p\n", thr->tid, sz, p);
ctx->metamap.AllocBlock(thr, pc, p, sz);
@@ -195,15 +204,64 @@ void OnUserFree(ThreadState *thr, uptr pc, uptr p, bool write) {
void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz) {
// FIXME: Handle "shrinking" more efficiently,
// it seems that some software actually does this.
- void *p2 = user_alloc(thr, pc, sz);
- if (p2 == 0)
- return 0;
- if (p) {
- uptr oldsz = user_alloc_usable_size(p);
- internal_memcpy(p2, p, min(oldsz, sz));
+ if (!p)
+ return SetErrnoOnNull(user_alloc_internal(thr, pc, sz));
+ if (!sz) {
user_free(thr, pc, p);
+ return nullptr;
+ }
+ void *new_p = user_alloc_internal(thr, pc, sz);
+ if (new_p) {
+ uptr old_sz = user_alloc_usable_size(p);
+ internal_memcpy(new_p, p, min(old_sz, sz));
+ user_free(thr, pc, p);
+ }
+ return SetErrnoOnNull(new_p);
+}
+
+void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz) {
+ if (UNLIKELY(!IsPowerOfTwo(align))) {
+ errno = errno_EINVAL;
+ return Allocator::FailureHandler::OnBadRequest();
+ }
+ return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align));
+}
+
+int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align,
+ uptr sz) {
+ if (UNLIKELY(!CheckPosixMemalignAlignment(align))) {
+ Allocator::FailureHandler::OnBadRequest();
+ return errno_EINVAL;
+ }
+ void *ptr = user_alloc_internal(thr, pc, sz, align);
+ if (UNLIKELY(!ptr))
+ return errno_ENOMEM;
+ CHECK(IsAligned((uptr)ptr, align));
+ *memptr = ptr;
+ return 0;
+}
+
+void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz) {
+ if (UNLIKELY(!CheckAlignedAllocAlignmentAndSize(align, sz))) {
+ errno = errno_EINVAL;
+ return Allocator::FailureHandler::OnBadRequest();
+ }
+ return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, align));
+}
+
+void *user_valloc(ThreadState *thr, uptr pc, uptr sz) {
+ return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, GetPageSizeCached()));
+}
+
+void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz) {
+ uptr PageSize = GetPageSizeCached();
+ if (UNLIKELY(CheckForPvallocOverflow(sz, PageSize))) {
+ errno = errno_ENOMEM;
+ return Allocator::FailureHandler::OnBadRequest();
}
- return p2;
+ // pvalloc(0) should allocate one page.
+ sz = sz ? RoundUpTo(sz, PageSize) : PageSize;
+ return SetErrnoOnNull(user_alloc_internal(thr, pc, sz, PageSize));
}
uptr user_alloc_usable_size(const void *p) {
@@ -290,6 +348,8 @@ uptr __sanitizer_get_allocated_size(const void *p) {
void __tsan_on_thread_idle() {
ThreadState *thr = cur_thread();
+ thr->clock.ResetCached(&thr->proc()->clock_cache);
+ thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache);
allocator()->SwallowCache(&thr->proc()->alloc_cache);
internal_allocator()->SwallowCache(&thr->proc()->internal_alloc_cache);
ctx->metamap.OnProcIdle(thr->proc());
diff --git a/libsanitizer/tsan/tsan_mman.h b/libsanitizer/tsan/tsan_mman.h
index d49c9a9..3443cb0 100644
--- a/libsanitizer/tsan/tsan_mman.h
+++ b/libsanitizer/tsan/tsan_mman.h
@@ -25,13 +25,20 @@ void AllocatorProcFinish(Processor *proc);
void AllocatorPrintStats();
// For user allocations.
-void *user_alloc(ThreadState *thr, uptr pc, uptr sz,
- uptr align = kDefaultAlignment, bool signal = true);
-void *user_calloc(ThreadState *thr, uptr pc, uptr sz, uptr n);
+void *user_alloc_internal(ThreadState *thr, uptr pc, uptr sz,
+ uptr align = kDefaultAlignment, bool signal = true);
// Does not accept NULL.
void user_free(ThreadState *thr, uptr pc, void *p, bool signal = true);
+// Interceptor implementations.
+void *user_alloc(ThreadState *thr, uptr pc, uptr sz);
+void *user_calloc(ThreadState *thr, uptr pc, uptr sz, uptr n);
void *user_realloc(ThreadState *thr, uptr pc, void *p, uptr sz);
-void *user_alloc_aligned(ThreadState *thr, uptr pc, uptr sz, uptr align);
+void *user_memalign(ThreadState *thr, uptr pc, uptr align, uptr sz);
+int user_posix_memalign(ThreadState *thr, uptr pc, void **memptr, uptr align,
+ uptr sz);
+void *user_aligned_alloc(ThreadState *thr, uptr pc, uptr align, uptr sz);
+void *user_valloc(ThreadState *thr, uptr pc, uptr sz);
+void *user_pvalloc(ThreadState *thr, uptr pc, uptr sz);
uptr user_alloc_usable_size(const void *p);
// Invoking malloc/free hooks that may be installed by the user.
diff --git a/libsanitizer/tsan/tsan_new_delete.cc b/libsanitizer/tsan/tsan_new_delete.cc
index 606cdd6..65ae61b 100644
--- a/libsanitizer/tsan/tsan_new_delete.cc
+++ b/libsanitizer/tsan/tsan_new_delete.cc
@@ -10,6 +10,7 @@
// Interceptors for operators new and delete.
//===----------------------------------------------------------------------===//
#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_allocator.h"
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "tsan_interceptors.h"
@@ -22,13 +23,15 @@ struct nothrow_t {};
DECLARE_REAL(void *, malloc, uptr size)
DECLARE_REAL(void, free, void *ptr)
-#define OPERATOR_NEW_BODY(mangled_name) \
+// TODO(alekseys): throw std::bad_alloc instead of dying on OOM.
+#define OPERATOR_NEW_BODY(mangled_name, nothrow) \
if (cur_thread()->in_symbolizer) \
return InternalAlloc(size); \
void *p = 0; \
{ \
SCOPED_INTERCEPTOR_RAW(mangled_name, size); \
p = user_alloc(thr, pc, size); \
+ if (!nothrow && UNLIKELY(!p)) DieOnFailure::OnOOM(); \
} \
invoke_malloc_hook(p, size); \
return p;
@@ -36,25 +39,25 @@ DECLARE_REAL(void, free, void *ptr)
SANITIZER_INTERFACE_ATTRIBUTE
void *operator new(__sanitizer::uptr size);
void *operator new(__sanitizer::uptr size) {
- OPERATOR_NEW_BODY(_Znwm);
+ OPERATOR_NEW_BODY(_Znwm, false /*nothrow*/);
}
SANITIZER_INTERFACE_ATTRIBUTE
void *operator new[](__sanitizer::uptr size);
void *operator new[](__sanitizer::uptr size) {
- OPERATOR_NEW_BODY(_Znam);
+ OPERATOR_NEW_BODY(_Znam, false /*nothrow*/);
}
SANITIZER_INTERFACE_ATTRIBUTE
void *operator new(__sanitizer::uptr size, std::nothrow_t const&);
void *operator new(__sanitizer::uptr size, std::nothrow_t const&) {
- OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t);
+ OPERATOR_NEW_BODY(_ZnwmRKSt9nothrow_t, true /*nothrow*/);
}
SANITIZER_INTERFACE_ATTRIBUTE
void *operator new[](__sanitizer::uptr size, std::nothrow_t const&);
void *operator new[](__sanitizer::uptr size, std::nothrow_t const&) {
- OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t);
+ OPERATOR_NEW_BODY(_ZnamRKSt9nothrow_t, true /*nothrow*/);
}
#define OPERATOR_DELETE_BODY(mangled_name) \
diff --git a/libsanitizer/tsan/tsan_platform.h b/libsanitizer/tsan/tsan_platform.h
index 368edc2..ddf4b13 100644
--- a/libsanitizer/tsan/tsan_platform.h
+++ b/libsanitizer/tsan/tsan_platform.h
@@ -98,6 +98,37 @@ struct Mapping {
};
#define TSAN_MID_APP_RANGE 1
+#elif defined(__aarch64__) && defined(__APPLE__)
+/*
+C/C++ on Darwin/iOS/ARM64 (36-bit VMA, 64 GB VM)
+0000 0000 00 - 0100 0000 00: - (4 GB)
+0100 0000 00 - 0200 0000 00: main binary, modules, thread stacks (4 GB)
+0200 0000 00 - 0300 0000 00: heap (4 GB)
+0300 0000 00 - 0400 0000 00: - (4 GB)
+0400 0000 00 - 0c00 0000 00: shadow memory (32 GB)
+0c00 0000 00 - 0d00 0000 00: - (4 GB)
+0d00 0000 00 - 0e00 0000 00: metainfo (4 GB)
+0e00 0000 00 - 0f00 0000 00: - (4 GB)
+0f00 0000 00 - 1000 0000 00: traces (4 GB)
+*/
+struct Mapping {
+ static const uptr kLoAppMemBeg = 0x0100000000ull;
+ static const uptr kLoAppMemEnd = 0x0200000000ull;
+ static const uptr kHeapMemBeg = 0x0200000000ull;
+ static const uptr kHeapMemEnd = 0x0300000000ull;
+ static const uptr kShadowBeg = 0x0400000000ull;
+ static const uptr kShadowEnd = 0x0c00000000ull;
+ static const uptr kMetaShadowBeg = 0x0d00000000ull;
+ static const uptr kMetaShadowEnd = 0x0e00000000ull;
+ static const uptr kTraceMemBeg = 0x0f00000000ull;
+ static const uptr kTraceMemEnd = 0x1000000000ull;
+ static const uptr kHiAppMemBeg = 0x1000000000ull;
+ static const uptr kHiAppMemEnd = 0x1000000000ull;
+ static const uptr kAppMemMsk = 0x0ull;
+ static const uptr kAppMemXor = 0x0ull;
+ static const uptr kVdsoBeg = 0x7000000000000000ull;
+};
+
#elif defined(__aarch64__)
// AArch64 supports multiple VMA which leads to multiple address transformation
// functions. To support these multiple VMAS transformations and mappings TSAN
@@ -387,7 +418,7 @@ uptr MappingImpl(void) {
template<int Type>
uptr MappingArchImpl(void) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return MappingImpl<Mapping39, Type>();
case 42: return MappingImpl<Mapping42, Type>();
@@ -540,7 +571,7 @@ bool IsAppMemImpl(uptr mem) {
ALWAYS_INLINE
bool IsAppMem(uptr mem) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return IsAppMemImpl<Mapping39>(mem);
case 42: return IsAppMemImpl<Mapping42>(mem);
@@ -567,7 +598,7 @@ bool IsShadowMemImpl(uptr mem) {
ALWAYS_INLINE
bool IsShadowMem(uptr mem) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return IsShadowMemImpl<Mapping39>(mem);
case 42: return IsShadowMemImpl<Mapping42>(mem);
@@ -594,7 +625,7 @@ bool IsMetaMemImpl(uptr mem) {
ALWAYS_INLINE
bool IsMetaMem(uptr mem) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return IsMetaMemImpl<Mapping39>(mem);
case 42: return IsMetaMemImpl<Mapping42>(mem);
@@ -631,7 +662,7 @@ uptr MemToShadowImpl(uptr x) {
ALWAYS_INLINE
uptr MemToShadow(uptr x) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return MemToShadowImpl<Mapping39>(x);
case 42: return MemToShadowImpl<Mapping42>(x);
@@ -670,7 +701,7 @@ u32 *MemToMetaImpl(uptr x) {
ALWAYS_INLINE
u32 *MemToMeta(uptr x) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return MemToMetaImpl<Mapping39>(x);
case 42: return MemToMetaImpl<Mapping42>(x);
@@ -722,7 +753,7 @@ uptr ShadowToMemImpl(uptr s) {
ALWAYS_INLINE
uptr ShadowToMem(uptr s) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return ShadowToMemImpl<Mapping39>(s);
case 42: return ShadowToMemImpl<Mapping42>(s);
@@ -757,7 +788,7 @@ uptr GetThreadTraceImpl(int tid) {
ALWAYS_INLINE
uptr GetThreadTrace(int tid) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return GetThreadTraceImpl<Mapping39>(tid);
case 42: return GetThreadTraceImpl<Mapping42>(tid);
@@ -787,7 +818,7 @@ uptr GetThreadTraceHeaderImpl(int tid) {
ALWAYS_INLINE
uptr GetThreadTraceHeader(int tid) {
-#ifdef __aarch64__
+#if defined(__aarch64__) && !defined(__APPLE__)
switch (vmaSize) {
case 39: return GetThreadTraceHeaderImpl<Mapping39>(tid);
case 42: return GetThreadTraceHeaderImpl<Mapping42>(tid);
@@ -814,6 +845,7 @@ void FlushShadowMemory();
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive);
int ExtractResolvFDs(void *state, int *fds, int nfd);
int ExtractRecvmsgFDs(void *msg, int *fds, int nfd);
+void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size);
int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
void *abstime), void *c, void *m, void *abstime,
diff --git a/libsanitizer/tsan/tsan_platform_linux.cc b/libsanitizer/tsan/tsan_platform_linux.cc
index 6f972ab..f8ae256 100644
--- a/libsanitizer/tsan/tsan_platform_linux.cc
+++ b/libsanitizer/tsan/tsan_platform_linux.cc
@@ -45,7 +45,6 @@
#include <sys/resource.h>
#include <sys/stat.h>
#include <unistd.h>
-#include <errno.h>
#include <sched.h>
#include <dlfcn.h>
#if SANITIZER_LINUX
@@ -132,7 +131,7 @@ void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
void FlushShadowMemoryCallback(
const SuspendedThreadsList &suspended_threads_list,
void *argument) {
- ReleaseMemoryToOS(ShadowBeg(), ShadowEnd() - ShadowBeg());
+ ReleaseMemoryPagesToOS(ShadowBeg(), ShadowEnd());
}
#endif
@@ -180,17 +179,15 @@ static void MapRodata() {
}
// Map the file into shadow of .rodata sections.
MemoryMappingLayout proc_maps(/*cache_enabled*/true);
- uptr start, end, offset, prot;
// Reusing the buffer 'name'.
- while (proc_maps.Next(&start, &end, &offset, name, ARRAY_SIZE(name), &prot)) {
- if (name[0] != 0 && name[0] != '['
- && (prot & MemoryMappingLayout::kProtectionRead)
- && (prot & MemoryMappingLayout::kProtectionExecute)
- && !(prot & MemoryMappingLayout::kProtectionWrite)
- && IsAppMem(start)) {
+ MemoryMappedSegment segment(name, ARRAY_SIZE(name));
+ while (proc_maps.Next(&segment)) {
+ if (segment.filename[0] != 0 && segment.filename[0] != '[' &&
+ segment.IsReadable() && segment.IsExecutable() &&
+ !segment.IsWritable() && IsAppMem(segment.start)) {
// Assume it's .rodata
- char *shadow_start = (char*)MemToShadow(start);
- char *shadow_end = (char*)MemToShadow(end);
+ char *shadow_start = (char *)MemToShadow(segment.start);
+ char *shadow_end = (char *)MemToShadow(segment.end);
for (char *p = shadow_start; p < shadow_end; p += marker.size()) {
internal_mmap(p, Min<uptr>(marker.size(), shadow_end - p),
PROT_READ, MAP_PRIVATE | MAP_FIXED, fd, 0);
@@ -318,6 +315,20 @@ int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
return res;
}
+void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
+ // Check that the thr object is in tls;
+ const uptr thr_beg = (uptr)thr;
+ const uptr thr_end = (uptr)thr + sizeof(*thr);
+ CHECK_GE(thr_beg, tls_addr);
+ CHECK_LE(thr_beg, tls_addr + tls_size);
+ CHECK_GE(thr_end, tls_addr);
+ CHECK_LE(thr_end, tls_addr + tls_size);
+ // Since the thr object is huge, skip it.
+ MemoryRangeImitateWrite(thr, /*pc=*/2, tls_addr, thr_beg - tls_addr);
+ MemoryRangeImitateWrite(thr, /*pc=*/2, thr_end,
+ tls_addr + tls_size - thr_end);
+}
+
// Note: this function runs with async signals enabled,
// so it must not touch any tsan state.
int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
@@ -339,36 +350,22 @@ void ReplaceSystemMalloc() { }
#if !SANITIZER_GO
#if SANITIZER_ANDROID
-
-#if defined(__aarch64__)
-# define __get_tls() \
- ({ void** __val; __asm__("mrs %0, tpidr_el0" : "=r"(__val)); __val; })
-#elif defined(__x86_64__)
-# define __get_tls() \
- ({ void** __val; __asm__("mov %%fs:0, %0" : "=r"(__val)); __val; })
-#else
-#error unsupported architecture
-#endif
-
-// On Android, __thread is not supported. So we store the pointer to ThreadState
-// in TLS_SLOT_TSAN, which is the tls slot allocated by Android bionic for tsan.
-static const int TLS_SLOT_TSAN = 8;
// On Android, one thread can call intercepted functions after
// DestroyThreadState(), so add a fake thread state for "dead" threads.
static ThreadState *dead_thread_state = nullptr;
ThreadState *cur_thread() {
- ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN];
+ ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr == nullptr) {
__sanitizer_sigset_t emptyset;
internal_sigfillset(&emptyset);
__sanitizer_sigset_t oldset;
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
- thr = reinterpret_cast<ThreadState*>(__get_tls()[TLS_SLOT_TSAN]);
+ thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr == nullptr) {
thr = reinterpret_cast<ThreadState*>(MmapOrDie(sizeof(ThreadState),
"ThreadState"));
- __get_tls()[TLS_SLOT_TSAN] = thr;
+ *get_android_tls_ptr() = reinterpret_cast<uptr>(thr);
if (dead_thread_state == nullptr) {
dead_thread_state = reinterpret_cast<ThreadState*>(
MmapOrDie(sizeof(ThreadState), "ThreadState"));
@@ -390,9 +387,9 @@ void cur_thread_finalize() {
internal_sigfillset(&emptyset);
__sanitizer_sigset_t oldset;
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &emptyset, &oldset));
- ThreadState* thr = (ThreadState*)__get_tls()[TLS_SLOT_TSAN];
+ ThreadState* thr = reinterpret_cast<ThreadState*>(*get_android_tls_ptr());
if (thr != dead_thread_state) {
- __get_tls()[TLS_SLOT_TSAN] = dead_thread_state;
+ *get_android_tls_ptr() = reinterpret_cast<uptr>(dead_thread_state);
UnmapOrDie(thr, sizeof(ThreadState));
}
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));
diff --git a/libsanitizer/tsan/tsan_platform_mac.cc b/libsanitizer/tsan/tsan_platform_mac.cc
index ff5131e..8eb22fa 100644
--- a/libsanitizer/tsan/tsan_platform_mac.cc
+++ b/libsanitizer/tsan/tsan_platform_mac.cc
@@ -18,10 +18,12 @@
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_posix.h"
#include "sanitizer_common/sanitizer_procmaps.h"
+#include "sanitizer_common/sanitizer_stackdepot.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
#include "tsan_flags.h"
+#include <mach/mach.h>
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
@@ -71,12 +73,18 @@ static void *SignalSafeGetOrAllocate(uptr *dst, uptr size) {
static uptr main_thread_identity = 0;
ALIGNED(64) static char main_thread_state[sizeof(ThreadState)];
+ThreadState **cur_thread_location() {
+ ThreadState **thread_identity = (ThreadState **)pthread_self();
+ return ((uptr)thread_identity == main_thread_identity) ? nullptr
+ : thread_identity;
+}
+
ThreadState *cur_thread() {
- uptr thread_identity = (uptr)pthread_self();
- if (thread_identity == main_thread_identity || main_thread_identity == 0) {
+ ThreadState **thr_state_loc = cur_thread_location();
+ if (thr_state_loc == nullptr || main_thread_identity == 0) {
return (ThreadState *)&main_thread_state;
}
- ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
+ ThreadState **fake_tls = (ThreadState **)MemToShadow((uptr)thr_state_loc);
ThreadState *thr = (ThreadState *)SignalSafeGetOrAllocate(
(uptr *)fake_tls, sizeof(ThreadState));
return thr;
@@ -86,26 +94,92 @@ ThreadState *cur_thread() {
// munmap first and then clear `fake_tls`; if we receive a signal in between,
// handler will try to access the unmapped ThreadState.
void cur_thread_finalize() {
- uptr thread_identity = (uptr)pthread_self();
- if (thread_identity == main_thread_identity) {
+ ThreadState **thr_state_loc = cur_thread_location();
+ if (thr_state_loc == nullptr) {
// Calling dispatch_main() or xpc_main() actually invokes pthread_exit to
// exit the main thread. Let's keep the main thread's ThreadState.
return;
}
- ThreadState **fake_tls = (ThreadState **)MemToShadow(thread_identity);
+ ThreadState **fake_tls = (ThreadState **)MemToShadow((uptr)thr_state_loc);
internal_munmap(*fake_tls, sizeof(ThreadState));
*fake_tls = nullptr;
}
#endif
-uptr GetShadowMemoryConsumption() {
- return 0;
+void FlushShadowMemory() {
}
-void FlushShadowMemory() {
+static void RegionMemUsage(uptr start, uptr end, uptr *res, uptr *dirty) {
+ vm_address_t address = start;
+ vm_address_t end_address = end;
+ uptr resident_pages = 0;
+ uptr dirty_pages = 0;
+ while (address < end_address) {
+ vm_size_t vm_region_size;
+ mach_msg_type_number_t count = VM_REGION_EXTENDED_INFO_COUNT;
+ vm_region_extended_info_data_t vm_region_info;
+ mach_port_t object_name;
+ kern_return_t ret = vm_region_64(
+ mach_task_self(), &address, &vm_region_size, VM_REGION_EXTENDED_INFO,
+ (vm_region_info_t)&vm_region_info, &count, &object_name);
+ if (ret != KERN_SUCCESS) break;
+
+ resident_pages += vm_region_info.pages_resident;
+ dirty_pages += vm_region_info.pages_dirtied;
+
+ address += vm_region_size;
+ }
+ *res = resident_pages * GetPageSizeCached();
+ *dirty = dirty_pages * GetPageSizeCached();
}
void WriteMemoryProfile(char *buf, uptr buf_size, uptr nthread, uptr nlive) {
+ uptr shadow_res, shadow_dirty;
+ uptr meta_res, meta_dirty;
+ uptr trace_res, trace_dirty;
+ RegionMemUsage(ShadowBeg(), ShadowEnd(), &shadow_res, &shadow_dirty);
+ RegionMemUsage(MetaShadowBeg(), MetaShadowEnd(), &meta_res, &meta_dirty);
+ RegionMemUsage(TraceMemBeg(), TraceMemEnd(), &trace_res, &trace_dirty);
+
+#if !SANITIZER_GO
+ uptr low_res, low_dirty;
+ uptr high_res, high_dirty;
+ uptr heap_res, heap_dirty;
+ RegionMemUsage(LoAppMemBeg(), LoAppMemEnd(), &low_res, &low_dirty);
+ RegionMemUsage(HiAppMemBeg(), HiAppMemEnd(), &high_res, &high_dirty);
+ RegionMemUsage(HeapMemBeg(), HeapMemEnd(), &heap_res, &heap_dirty);
+#else // !SANITIZER_GO
+ uptr app_res, app_dirty;
+ RegionMemUsage(AppMemBeg(), AppMemEnd(), &app_res, &app_dirty);
+#endif
+
+ StackDepotStats *stacks = StackDepotGetStats();
+ internal_snprintf(buf, buf_size,
+ "shadow (0x%016zx-0x%016zx): resident %zd kB, dirty %zd kB\n"
+ "meta (0x%016zx-0x%016zx): resident %zd kB, dirty %zd kB\n"
+ "traces (0x%016zx-0x%016zx): resident %zd kB, dirty %zd kB\n"
+#if !SANITIZER_GO
+ "low app (0x%016zx-0x%016zx): resident %zd kB, dirty %zd kB\n"
+ "high app (0x%016zx-0x%016zx): resident %zd kB, dirty %zd kB\n"
+ "heap (0x%016zx-0x%016zx): resident %zd kB, dirty %zd kB\n"
+#else // !SANITIZER_GO
+ "app (0x%016zx-0x%016zx): resident %zd kB, dirty %zd kB\n"
+#endif
+ "stacks: %zd unique IDs, %zd kB allocated\n"
+ "threads: %zd total, %zd live\n"
+ "------------------------------\n",
+ ShadowBeg(), ShadowEnd(), shadow_res / 1024, shadow_dirty / 1024,
+ MetaShadowBeg(), MetaShadowEnd(), meta_res / 1024, meta_dirty / 1024,
+ TraceMemBeg(), TraceMemEnd(), trace_res / 1024, trace_dirty / 1024,
+#if !SANITIZER_GO
+ LoAppMemBeg(), LoAppMemEnd(), low_res / 1024, low_dirty / 1024,
+ HiAppMemBeg(), HiAppMemEnd(), high_res / 1024, high_dirty / 1024,
+ HeapMemBeg(), HeapMemEnd(), heap_res / 1024, heap_dirty / 1024,
+#else // !SANITIZER_GO
+ AppMemBeg(), AppMemEnd(), app_res / 1024, app_dirty / 1024,
+#endif
+ stacks->n_uniq_ids, stacks->allocated / 1024,
+ nthread, nlive);
}
#if !SANITIZER_GO
@@ -137,7 +211,7 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
ThreadState *parent_thread_state = nullptr; // No parent.
int tid = ThreadCreate(parent_thread_state, 0, (uptr)thread, true);
CHECK_NE(tid, 0);
- ThreadStart(thr, tid, GetTid());
+ ThreadStart(thr, tid, GetTid(), /*workerthread*/ true);
}
} else if (event == PTHREAD_INTROSPECTION_THREAD_TERMINATE) {
if (thread == pthread_self()) {
@@ -154,6 +228,14 @@ static void my_pthread_introspection_hook(unsigned int event, pthread_t thread,
#endif
void InitializePlatformEarly() {
+#if defined(__aarch64__)
+ uptr max_vm = GetMaxVirtualAddress() + 1;
+ if (max_vm != Mapping::kHiAppMemEnd) {
+ Printf("ThreadSanitizer: unsupported vm address limit %p, expected %p.\n",
+ max_vm, Mapping::kHiAppMemEnd);
+ Die();
+ }
+#endif
}
void InitializePlatform() {
@@ -170,6 +252,29 @@ void InitializePlatform() {
}
#if !SANITIZER_GO
+void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
+ // The pointer to the ThreadState object is stored in the shadow memory
+ // of the tls.
+ uptr tls_end = tls_addr + tls_size;
+ ThreadState **thr_state_loc = cur_thread_location();
+ if (thr_state_loc == nullptr) {
+ MemoryRangeImitateWrite(thr, /*pc=*/2, tls_addr, tls_size);
+ } else {
+ uptr thr_state_start = (uptr)thr_state_loc;
+ uptr thr_state_end = thr_state_start + sizeof(uptr);
+ CHECK_GE(thr_state_start, tls_addr);
+ CHECK_LE(thr_state_start, tls_addr + tls_size);
+ CHECK_GE(thr_state_end, tls_addr);
+ CHECK_LE(thr_state_end, tls_addr + tls_size);
+ MemoryRangeImitateWrite(thr, /*pc=*/2, tls_addr,
+ thr_state_start - tls_addr);
+ MemoryRangeImitateWrite(thr, /*pc=*/2, thr_state_end,
+ tls_end - thr_state_end);
+ }
+}
+#endif
+
+#if !SANITIZER_GO
// Note: this function runs with async signals enabled,
// so it must not touch any tsan state.
int call_pthread_cancel_with_cleanup(int(*fn)(void *c, void *m,
diff --git a/libsanitizer/tsan/tsan_platform_posix.cc b/libsanitizer/tsan/tsan_platform_posix.cc
index 0a3b61a..6e62575 100644
--- a/libsanitizer/tsan/tsan_platform_posix.cc
+++ b/libsanitizer/tsan/tsan_platform_posix.cc
@@ -44,6 +44,9 @@ void InitializeShadowMemory() {
#elif defined(__mips64)
const uptr kMadviseRangeBeg = 0xff00000000ull;
const uptr kMadviseRangeSize = 0x0100000000ull;
+#elif defined(__aarch64__) && defined(__APPLE__)
+ uptr kMadviseRangeBeg = LoAppMemBeg();
+ uptr kMadviseRangeSize = LoAppMemEnd() - LoAppMemBeg();
#elif defined(__aarch64__)
uptr kMadviseRangeBeg = 0;
uptr kMadviseRangeSize = 0;
@@ -113,21 +116,24 @@ static void ProtectRange(uptr beg, uptr end) {
void CheckAndProtect() {
// Ensure that the binary is indeed compiled with -pie.
MemoryMappingLayout proc_maps(true);
- uptr p, end, prot;
- while (proc_maps.Next(&p, &end, 0, 0, 0, &prot)) {
- if (IsAppMem(p))
+ MemoryMappedSegment segment;
+ while (proc_maps.Next(&segment)) {
+ if (IsAppMem(segment.start)) continue;
+ if (segment.start >= HeapMemEnd() && segment.start < HeapEnd()) continue;
+ if (segment.protection == 0) // Zero page or mprotected.
continue;
- if (p >= HeapMemEnd() &&
- p < HeapEnd())
- continue;
- if (prot == 0) // Zero page or mprotected.
- continue;
- if (p >= VdsoBeg()) // vdso
+ if (segment.start >= VdsoBeg()) // vdso
break;
- Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n", p, end);
+ Printf("FATAL: ThreadSanitizer: unexpected memory mapping %p-%p\n",
+ segment.start, segment.end);
Die();
}
+#if defined(__aarch64__) && defined(__APPLE__)
+ ProtectRange(HeapMemEnd(), ShadowBeg());
+ ProtectRange(ShadowEnd(), MetaShadowBeg());
+ ProtectRange(MetaShadowEnd(), TraceMemBeg());
+#else
ProtectRange(LoAppMemEnd(), ShadowBeg());
ProtectRange(ShadowEnd(), MetaShadowBeg());
#ifdef TSAN_MID_APP_RANGE
@@ -141,6 +147,7 @@ void CheckAndProtect() {
ProtectRange(TraceMemBeg(), TraceMemEnd());
ProtectRange(TraceMemEnd(), HeapMemBeg());
ProtectRange(HeapEnd(), HiAppMemBeg());
+#endif
}
#endif
diff --git a/libsanitizer/tsan/tsan_platform_windows.cc b/libsanitizer/tsan/tsan_platform_windows.cc
index 54ec6a6..76883ca 100644
--- a/libsanitizer/tsan/tsan_platform_windows.cc
+++ b/libsanitizer/tsan/tsan_platform_windows.cc
@@ -19,10 +19,6 @@
namespace __tsan {
-uptr GetShadowMemoryConsumption() {
- return 0;
-}
-
void FlushShadowMemory() {
}
diff --git a/libsanitizer/tsan/tsan_report.cc b/libsanitizer/tsan/tsan_report.cc
index ba3e34f..f8cb3e7 100644
--- a/libsanitizer/tsan/tsan_report.cc
+++ b/libsanitizer/tsan/tsan_report.cc
@@ -11,6 +11,7 @@
#include "tsan_report.h"
#include "tsan_platform.h"
#include "tsan_rtl.h"
+#include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_placement_new.h"
#include "sanitizer_common/sanitizer_report_decorator.h"
#include "sanitizer_common/sanitizer_stacktrace_printer.h"
@@ -36,22 +37,16 @@ ReportLocation *ReportLocation::New(ReportLocationType type) {
class Decorator: public __sanitizer::SanitizerCommonDecorator {
public:
Decorator() : SanitizerCommonDecorator() { }
- const char *Warning() { return Red(); }
- const char *EndWarning() { return Default(); }
const char *Access() { return Blue(); }
- const char *EndAccess() { return Default(); }
const char *ThreadDescription() { return Cyan(); }
- const char *EndThreadDescription() { return Default(); }
const char *Location() { return Green(); }
- const char *EndLocation() { return Default(); }
const char *Sleep() { return Yellow(); }
- const char *EndSleep() { return Default(); }
const char *Mutex() { return Magenta(); }
- const char *EndMutex() { return Default(); }
};
ReportDesc::ReportDesc()
- : stacks(MBlockReportStack)
+ : tag(kExternalTagNone)
+ , stacks(MBlockReportStack)
, mops(MBlockReportMop)
, locs(MBlockReportLoc)
, mutexes(MBlockReportMutex)
@@ -79,7 +74,7 @@ const char *thread_name(char *buf, int tid) {
return buf;
}
-static const char *ReportTypeString(ReportType typ) {
+static const char *ReportTypeString(ReportType typ, uptr tag) {
if (typ == ReportTypeRace)
return "data race";
if (typ == ReportTypeVptrRace)
@@ -88,6 +83,10 @@ static const char *ReportTypeString(ReportType typ) {
return "heap-use-after-free";
if (typ == ReportTypeVptrUseAfterFree)
return "heap-use-after-free (virtual call vs free)";
+ if (typ == ReportTypeExternalRace) {
+ const char *str = GetReportHeaderFromTag(tag);
+ return str ? str : "race on external object";
+ }
if (typ == ReportTypeThreadLeak)
return "thread leak";
if (typ == ReportTypeMutexDestroyLocked)
@@ -150,17 +149,30 @@ static const char *MopDesc(bool first, bool write, bool atomic) {
: (write ? "Previous write" : "Previous read"));
}
+static const char *ExternalMopDesc(bool first, bool write) {
+ return first ? (write ? "Modifying" : "Read-only")
+ : (write ? "Previous modifying" : "Previous read-only");
+}
+
static void PrintMop(const ReportMop *mop, bool first) {
Decorator d;
char thrbuf[kThreadBufSize];
Printf("%s", d.Access());
- Printf(" %s of size %d at %p by %s",
- MopDesc(first, mop->write, mop->atomic),
- mop->size, (void*)mop->addr,
- thread_name(thrbuf, mop->tid));
+ if (mop->external_tag == kExternalTagNone) {
+ Printf(" %s of size %d at %p by %s",
+ MopDesc(first, mop->write, mop->atomic), mop->size,
+ (void *)mop->addr, thread_name(thrbuf, mop->tid));
+ } else {
+ const char *object_type = GetObjectTypeFromTag(mop->external_tag);
+ if (object_type == nullptr)
+ object_type = "external object";
+ Printf(" %s access of %s at %p by %s",
+ ExternalMopDesc(first, mop->write), object_type,
+ (void *)mop->addr, thread_name(thrbuf, mop->tid));
+ }
PrintMutexSet(mop->mset);
Printf(":\n");
- Printf("%s", d.EndAccess());
+ Printf("%s", d.Default());
PrintStack(mop->stack);
}
@@ -181,9 +193,16 @@ static void PrintLocation(const ReportLocation *loc) {
global.module_offset);
} else if (loc->type == ReportLocationHeap) {
char thrbuf[kThreadBufSize];
- Printf(" Location is heap block of size %zu at %p allocated by %s:\n",
- loc->heap_chunk_size, loc->heap_chunk_start,
- thread_name(thrbuf, loc->tid));
+ const char *object_type = GetObjectTypeFromTag(loc->external_tag);
+ if (!object_type) {
+ Printf(" Location is heap block of size %zu at %p allocated by %s:\n",
+ loc->heap_chunk_size, loc->heap_chunk_start,
+ thread_name(thrbuf, loc->tid));
+ } else {
+ Printf(" Location is %s of size %zu at %p allocated by %s:\n",
+ object_type, loc->heap_chunk_size, loc->heap_chunk_start,
+ thread_name(thrbuf, loc->tid));
+ }
print_stack = true;
} else if (loc->type == ReportLocationStack) {
Printf(" Location is stack of %s.\n\n", thread_name(thrbuf, loc->tid));
@@ -194,20 +213,20 @@ static void PrintLocation(const ReportLocation *loc) {
loc->fd, thread_name(thrbuf, loc->tid));
print_stack = true;
}
- Printf("%s", d.EndLocation());
+ Printf("%s", d.Default());
if (print_stack)
PrintStack(loc->stack);
}
static void PrintMutexShort(const ReportMutex *rm, const char *after) {
Decorator d;
- Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.EndMutex(), after);
+ Printf("%sM%zd%s%s", d.Mutex(), rm->id, d.Default(), after);
}
static void PrintMutexShortWithAddress(const ReportMutex *rm,
const char *after) {
Decorator d;
- Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.EndMutex(), after);
+ Printf("%sM%zd (%p)%s%s", d.Mutex(), rm->id, rm->addr, d.Default(), after);
}
static void PrintMutex(const ReportMutex *rm) {
@@ -215,11 +234,11 @@ static void PrintMutex(const ReportMutex *rm) {
if (rm->destroyed) {
Printf("%s", d.Mutex());
Printf(" Mutex M%llu is already destroyed.\n\n", rm->id);
- Printf("%s", d.EndMutex());
+ Printf("%s", d.Default());
} else {
Printf("%s", d.Mutex());
Printf(" Mutex M%llu (%p) created at:\n", rm->id, rm->addr);
- Printf("%s", d.EndMutex());
+ Printf("%s", d.Default());
PrintStack(rm->stack);
}
}
@@ -233,13 +252,19 @@ static void PrintThread(const ReportThread *rt) {
if (rt->name && rt->name[0] != '\0')
Printf(" '%s'", rt->name);
char thrbuf[kThreadBufSize];
- Printf(" (tid=%zu, %s) created by %s",
- rt->os_id, rt->running ? "running" : "finished",
- thread_name(thrbuf, rt->parent_tid));
+ const char *thread_status = rt->running ? "running" : "finished";
+ if (rt->workerthread) {
+ Printf(" (tid=%zu, %s) is a GCD worker thread\n", rt->os_id, thread_status);
+ Printf("\n");
+ Printf("%s", d.Default());
+ return;
+ }
+ Printf(" (tid=%zu, %s) created by %s", rt->os_id, thread_status,
+ thread_name(thrbuf, rt->parent_tid));
if (rt->stack)
Printf(" at:");
Printf("\n");
- Printf("%s", d.EndThreadDescription());
+ Printf("%s", d.Default());
PrintStack(rt->stack);
}
@@ -247,7 +272,7 @@ static void PrintSleep(const ReportStack *s) {
Decorator d;
Printf("%s", d.Sleep());
Printf(" As if synchronized via sleep:\n");
- Printf("%s", d.EndSleep());
+ Printf("%s", d.Default());
PrintStack(s);
}
@@ -287,11 +312,11 @@ static SymbolizedStack *SkipTsanInternalFrames(SymbolizedStack *frames) {
void PrintReport(const ReportDesc *rep) {
Decorator d;
Printf("==================\n");
- const char *rep_typ_str = ReportTypeString(rep->typ);
+ const char *rep_typ_str = ReportTypeString(rep->typ, rep->tag);
Printf("%s", d.Warning());
Printf("WARNING: ThreadSanitizer: %s (pid=%d)\n", rep_typ_str,
(int)internal_getpid());
- Printf("%s", d.EndWarning());
+ Printf("%s", d.Default());
if (rep->typ == ReportTypeDeadlock) {
char thrbuf[kThreadBufSize];
@@ -309,7 +334,7 @@ void PrintReport(const ReportDesc *rep) {
PrintMutexShort(rep->mutexes[i], " in ");
Printf("%s", d.ThreadDescription());
Printf("%s:\n", thread_name(thrbuf, rep->unique_tids[i]));
- Printf("%s", d.EndThreadDescription());
+ Printf("%s", d.Default());
if (flags()->second_deadlock_stack) {
PrintStack(rep->stacks[2*i]);
Printf(" Mutex ");
@@ -356,6 +381,8 @@ void PrintReport(const ReportDesc *rep) {
ReportErrorSummary(rep_typ_str, frame->info);
}
+ if (common_flags()->print_module_map == 2) PrintModuleMap();
+
Printf("==================\n");
}
diff --git a/libsanitizer/tsan/tsan_report.h b/libsanitizer/tsan/tsan_report.h
index e51ed4f..6eb043f 100644
--- a/libsanitizer/tsan/tsan_report.h
+++ b/libsanitizer/tsan/tsan_report.h
@@ -22,6 +22,7 @@ enum ReportType {
ReportTypeVptrRace,
ReportTypeUseAfterFree,
ReportTypeVptrUseAfterFree,
+ ReportTypeExternalRace,
ReportTypeThreadLeak,
ReportTypeMutexDestroyLocked,
ReportTypeMutexDoubleLock,
@@ -54,6 +55,7 @@ struct ReportMop {
int size;
bool write;
bool atomic;
+ uptr external_tag;
Vector<ReportMopMutex> mset;
ReportStack *stack;
@@ -73,6 +75,7 @@ struct ReportLocation {
DataInfo global;
uptr heap_chunk_start;
uptr heap_chunk_size;
+ uptr external_tag;
int tid;
int fd;
bool suppressable;
@@ -85,10 +88,11 @@ struct ReportLocation {
struct ReportThread {
int id;
- uptr os_id;
+ tid_t os_id;
bool running;
+ bool workerthread;
char *name;
- int parent_tid;
+ u32 parent_tid;
ReportStack *stack;
};
@@ -102,6 +106,7 @@ struct ReportMutex {
class ReportDesc {
public:
ReportType typ;
+ uptr tag;
Vector<ReportStack*> stacks;
Vector<ReportMop*> mops;
Vector<ReportLocation*> locs;
diff --git a/libsanitizer/tsan/tsan_rtl.cc b/libsanitizer/tsan/tsan_rtl.cc
index 5be28ce..4a1f500 100644
--- a/libsanitizer/tsan/tsan_rtl.cc
+++ b/libsanitizer/tsan/tsan_rtl.cc
@@ -12,6 +12,7 @@
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
+#include "sanitizer_common/sanitizer_file.h"
#include "sanitizer_common/sanitizer_libc.h"
#include "sanitizer_common/sanitizer_stackdepot.h"
#include "sanitizer_common/sanitizer_placement_new.h"
@@ -43,7 +44,7 @@ extern "C" void __tsan_resume() {
namespace __tsan {
#if !SANITIZER_GO && !SANITIZER_MAC
- __attribute__((tls_model("initial-exec")))
+__attribute__((tls_model("initial-exec")))
THREADLOCAL char cur_thread_placeholder[sizeof(ThreadState)] ALIGNED(64);
#endif
static char ctx_placeholder[sizeof(Context)] ALIGNED(64);
@@ -102,7 +103,8 @@ Context::Context()
, racy_stacks(MBlockRacyStacks)
, racy_addresses(MBlockRacyAddresses)
, fired_suppressions_mtx(MutexTypeFired, StatMtxFired)
- , fired_suppressions(8) {
+ , fired_suppressions(8)
+ , clock_alloc("clock allocator") {
}
// The objects are allocated in TLS, so one may rely on zero-initialization.
@@ -232,9 +234,7 @@ static void StopBackgroundThread() {
#endif
void DontNeedShadowFor(uptr addr, uptr size) {
- uptr shadow_beg = MemToShadow(addr);
- uptr shadow_end = MemToShadow(addr + size);
- ReleaseMemoryToOS(shadow_beg, shadow_end - shadow_beg);
+ ReleaseMemoryPagesToOS(MemToShadow(addr), MemToShadow(addr + size));
}
void MapShadow(uptr addr, uptr size) {
@@ -381,7 +381,7 @@ void Initialize(ThreadState *thr) {
// Initialize thread 0.
int tid = ThreadCreate(thr, 0, 0, true);
CHECK_EQ(tid, 0);
- ThreadStart(thr, tid, internal_getpid());
+ ThreadStart(thr, tid, GetTid(), /*workerthread*/ false);
#if TSAN_CONTAINS_UBSAN
__ubsan::InitAsPlugin();
#endif
@@ -404,6 +404,8 @@ void Initialize(ThreadState *thr) {
int Finalize(ThreadState *thr) {
bool failed = false;
+ if (common_flags()->print_module_map == 1) PrintModuleMap();
+
if (flags()->atexit_sleep_ms > 0 && ThreadCount(thr) > 1)
SleepForMillis(flags()->atexit_sleep_ms);
@@ -864,9 +866,8 @@ static void MemoryRangeSet(ThreadState *thr, uptr pc, uptr addr, uptr size,
// Don't want to touch lots of shadow memory.
// If a program maps 10MB stack, there is no need reset the whole range.
size = (size + (kShadowCell - 1)) & ~(kShadowCell - 1);
- // UnmapOrDie/MmapFixedNoReserve does not work on Windows,
- // so we do it only for C/C++.
- if (SANITIZER_GO || size < common_flags()->clear_shadow_mmap_threshold) {
+ // UnmapOrDie/MmapFixedNoReserve does not work on Windows.
+ if (SANITIZER_WINDOWS || size < common_flags()->clear_shadow_mmap_threshold) {
u64 *p = (u64*)MemToShadow(addr);
CHECK(IsShadowMem((uptr)p));
CHECK(IsShadowMem((uptr)(p + size * kShadowCnt / kShadowCell - 1)));
@@ -978,21 +979,21 @@ void FuncExit(ThreadState *thr) {
thr->shadow_stack_pos--;
}
-void ThreadIgnoreBegin(ThreadState *thr, uptr pc) {
+void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack) {
DPrintf("#%d: ThreadIgnoreBegin\n", thr->tid);
thr->ignore_reads_and_writes++;
CHECK_GT(thr->ignore_reads_and_writes, 0);
thr->fast_state.SetIgnoreBit();
#if !SANITIZER_GO
- if (!ctx->after_multithreaded_fork)
+ if (save_stack && !ctx->after_multithreaded_fork)
thr->mop_ignore_set.Add(CurrentStackId(thr, pc));
#endif
}
void ThreadIgnoreEnd(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreEnd\n", thr->tid);
+ CHECK_GT(thr->ignore_reads_and_writes, 0);
thr->ignore_reads_and_writes--;
- CHECK_GE(thr->ignore_reads_and_writes, 0);
if (thr->ignore_reads_and_writes == 0) {
thr->fast_state.ClearIgnoreBit();
#if !SANITIZER_GO
@@ -1001,20 +1002,28 @@ void ThreadIgnoreEnd(ThreadState *thr, uptr pc) {
}
}
-void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc) {
+#if !SANITIZER_GO
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE
+uptr __tsan_testonly_shadow_stack_current_size() {
+ ThreadState *thr = cur_thread();
+ return thr->shadow_stack_pos - thr->shadow_stack;
+}
+#endif
+
+void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc, bool save_stack) {
DPrintf("#%d: ThreadIgnoreSyncBegin\n", thr->tid);
thr->ignore_sync++;
CHECK_GT(thr->ignore_sync, 0);
#if !SANITIZER_GO
- if (!ctx->after_multithreaded_fork)
+ if (save_stack && !ctx->after_multithreaded_fork)
thr->sync_ignore_set.Add(CurrentStackId(thr, pc));
#endif
}
void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc) {
DPrintf("#%d: ThreadIgnoreSyncEnd\n", thr->tid);
+ CHECK_GT(thr->ignore_sync, 0);
thr->ignore_sync--;
- CHECK_GE(thr->ignore_sync, 0);
#if !SANITIZER_GO
if (thr->ignore_sync == 0)
thr->sync_ignore_set.Reset();
diff --git a/libsanitizer/tsan/tsan_rtl.h b/libsanitizer/tsan/tsan_rtl.h
index 522c760..7dd9779 100644
--- a/libsanitizer/tsan/tsan_rtl.h
+++ b/libsanitizer/tsan/tsan_rtl.h
@@ -53,16 +53,22 @@ namespace __tsan {
#if !SANITIZER_GO
struct MapUnmapCallback;
#if defined(__mips64) || defined(__aarch64__) || defined(__powerpc__)
-static const uptr kAllocatorSpace = 0;
-static const uptr kAllocatorSize = SANITIZER_MMAP_RANGE_SIZE;
static const uptr kAllocatorRegionSizeLog = 20;
static const uptr kAllocatorNumRegions =
- kAllocatorSize >> kAllocatorRegionSizeLog;
+ SANITIZER_MMAP_RANGE_SIZE >> kAllocatorRegionSizeLog;
typedef TwoLevelByteMap<(kAllocatorNumRegions >> 12), 1 << 12,
MapUnmapCallback> ByteMap;
-typedef SizeClassAllocator32<kAllocatorSpace, kAllocatorSize, 0,
- CompactSizeClassMap, kAllocatorRegionSizeLog, ByteMap,
- MapUnmapCallback> PrimaryAllocator;
+struct AP32 {
+ static const uptr kSpaceBeg = 0;
+ static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE;
+ static const uptr kMetadataSize = 0;
+ typedef __sanitizer::CompactSizeClassMap SizeClassMap;
+ static const uptr kRegionSizeLog = kAllocatorRegionSizeLog;
+ typedef __tsan::ByteMap ByteMap;
+ typedef __tsan::MapUnmapCallback MapUnmapCallback;
+ static const uptr kFlags = 0;
+};
+typedef SizeClassAllocator32<AP32> PrimaryAllocator;
#else
struct AP64 { // Allocator64 parameters. Deliberately using a short name.
static const uptr kSpaceBeg = Mapping::kHeapMemBeg;
@@ -379,6 +385,7 @@ struct ThreadState {
// for better performance.
int ignore_reads_and_writes;
int ignore_sync;
+ int suppress_reports;
// Go does not support ignores.
#if !SANITIZER_GO
IgnoreSet mop_ignore_set;
@@ -543,6 +550,10 @@ struct Context {
extern Context *ctx; // The one and the only global runtime context.
+ALWAYS_INLINE Flags *flags() {
+ return &ctx->flags;
+}
+
struct ScopedIgnoreInterceptors {
ScopedIgnoreInterceptors() {
#if !SANITIZER_GO
@@ -557,12 +568,16 @@ struct ScopedIgnoreInterceptors {
}
};
+const char *GetObjectTypeFromTag(uptr tag);
+const char *GetReportHeaderFromTag(uptr tag);
+uptr TagFromShadowStackFrame(uptr pc);
+
class ScopedReport {
public:
- explicit ScopedReport(ReportType typ);
+ explicit ScopedReport(ReportType typ, uptr tag = kExternalTagNone);
~ScopedReport();
- void AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
+ void AddMemoryAccess(uptr addr, uptr external_tag, Shadow s, StackTrace stack,
const MutexSet *mset);
void AddStack(StackTrace stack, bool suppressable = false);
void AddThread(const ThreadContext *tctx, bool suppressable = false);
@@ -588,11 +603,28 @@ class ScopedReport {
void operator = (const ScopedReport&);
};
+ThreadContext *IsThreadStackOrTls(uptr addr, bool *is_stack);
void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
- MutexSet *mset);
+ MutexSet *mset, uptr *tag = nullptr);
+
+// The stack could look like:
+// <start> | <main> | <foo> | tag | <bar>
+// This will extract the tag and keep:
+// <start> | <main> | <foo> | <bar>
+template<typename StackTraceTy>
+void ExtractTagFromStack(StackTraceTy *stack, uptr *tag = nullptr) {
+ if (stack->size < 2) return;
+ uptr possible_tag_pc = stack->trace[stack->size - 2];
+ uptr possible_tag = TagFromShadowStackFrame(possible_tag_pc);
+ if (possible_tag == kExternalTagNone) return;
+ stack->trace_buffer[stack->size - 2] = stack->trace_buffer[stack->size - 1];
+ stack->size -= 1;
+ if (tag) *tag = possible_tag;
+}
template<typename StackTraceTy>
-void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
+void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack,
+ uptr *tag = nullptr) {
uptr size = thr->shadow_stack_pos - thr->shadow_stack;
uptr start = 0;
if (size + !!toppc > kStackTraceMax) {
@@ -600,6 +632,7 @@ void ObtainCurrentStack(ThreadState *thr, uptr toppc, StackTraceTy *stack) {
size = kStackTraceMax - !!toppc;
}
stack->Init(&thr->shadow_stack[start], size, toppc);
+ ExtractTagFromStack(stack, tag);
}
@@ -701,16 +734,16 @@ void MemoryResetRange(ThreadState *thr, uptr pc, uptr addr, uptr size);
void MemoryRangeFreed(ThreadState *thr, uptr pc, uptr addr, uptr size);
void MemoryRangeImitateWrite(ThreadState *thr, uptr pc, uptr addr, uptr size);
-void ThreadIgnoreBegin(ThreadState *thr, uptr pc);
+void ThreadIgnoreBegin(ThreadState *thr, uptr pc, bool save_stack = true);
void ThreadIgnoreEnd(ThreadState *thr, uptr pc);
-void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc);
+void ThreadIgnoreSyncBegin(ThreadState *thr, uptr pc, bool save_stack = true);
void ThreadIgnoreSyncEnd(ThreadState *thr, uptr pc);
void FuncEntry(ThreadState *thr, uptr pc);
void FuncExit(ThreadState *thr);
int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached);
-void ThreadStart(ThreadState *thr, int tid, uptr os_id);
+void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread);
void ThreadFinish(ThreadState *thr);
int ThreadTid(ThreadState *thr, uptr pc, uptr uid);
void ThreadJoin(ThreadState *thr, uptr pc, int tid);
@@ -725,13 +758,16 @@ void ProcDestroy(Processor *proc);
void ProcWire(Processor *proc, ThreadState *thr);
void ProcUnwire(Processor *proc, ThreadState *thr);
-void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
- bool rw, bool recursive, bool linker_init);
-void MutexDestroy(ThreadState *thr, uptr pc, uptr addr);
-void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec = 1,
- bool try_lock = false);
-int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all = false);
-void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool try_lock = false);
+// Note: the parameter is called flagz, because flags is already taken
+// by the global function that returns flags.
+void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
+void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
+void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
+void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0,
+ int rec = 1);
+int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
+void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
+void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz = 0);
void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr);
void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr);
void MutexRepair(ThreadState *thr, uptr pc, uptr addr); // call on EOWNERDEAD
@@ -787,7 +823,7 @@ void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
return;
DCHECK_GE((int)typ, 0);
DCHECK_LE((int)typ, 7);
- DCHECK_EQ(GetLsb(addr, 61), addr);
+ DCHECK_EQ(GetLsb(addr, kEventPCBits), addr);
StatInc(thr, StatEvents);
u64 pos = fs.GetTracePos();
if (UNLIKELY((pos % kTracePartSize) == 0)) {
@@ -799,7 +835,7 @@ void ALWAYS_INLINE TraceAddEvent(ThreadState *thr, FastState fs,
}
Event *trace = (Event*)GetThreadTrace(fs.tid());
Event *evp = &trace[pos];
- Event ev = (u64)addr | ((u64)typ << 61);
+ Event ev = (u64)addr | ((u64)typ << kEventPCBits);
*evp = ev;
}
diff --git a/libsanitizer/tsan/tsan_rtl_aarch64.S b/libsanitizer/tsan/tsan_rtl_aarch64.S
index ef06f04..61171d6 100644
--- a/libsanitizer/tsan/tsan_rtl_aarch64.S
+++ b/libsanitizer/tsan/tsan_rtl_aarch64.S
@@ -1,13 +1,46 @@
+// The content of this file is AArch64-only:
+#if defined(__aarch64__)
+
#include "sanitizer_common/sanitizer_asm.h"
+#if !defined(__APPLE__)
.section .bss
.type __tsan_pointer_chk_guard, %object
-.size __tsan_pointer_chk_guard, 8
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__tsan_pointer_chk_guard))
__tsan_pointer_chk_guard:
.zero 8
+#endif
+
+#if defined(__APPLE__)
+.align 2
+
+.section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers
+.long _setjmp$non_lazy_ptr
+_setjmp$non_lazy_ptr:
+.indirect_symbol _setjmp
+.long 0
+
+.section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers
+.long __setjmp$non_lazy_ptr
+__setjmp$non_lazy_ptr:
+.indirect_symbol __setjmp
+.long 0
+
+.section __DATA,__nl_symbol_ptr,non_lazy_symbol_pointers
+.long _sigsetjmp$non_lazy_ptr
+_sigsetjmp$non_lazy_ptr:
+.indirect_symbol _sigsetjmp
+.long 0
+#endif
+#if !defined(__APPLE__)
.section .text
+#else
+.section __TEXT,__text
+.align 3
+#endif
+#if !defined(__APPLE__)
// GLIBC mangles the function pointers in jmp_buf (used in {set,long}*jmp
// functions) by XORing them with a random guard pointer. For AArch64 it is a
// global variable rather than a TCB one (as for x86_64/powerpc) and althought
@@ -16,9 +49,9 @@ __tsan_pointer_chk_guard:
// not stable). So InitializeGuardPtr obtains the pointer guard value by
// issuing a setjmp and checking the resulting pointers values against the
// original ones.
-.hidden _Z18InitializeGuardPtrv
+ASM_HIDDEN(_Z18InitializeGuardPtrv)
.global _Z18InitializeGuardPtrv
-.type _Z18InitializeGuardPtrv, @function
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv))
_Z18InitializeGuardPtrv:
CFI_STARTPROC
// Allocates a jmp_buf for the setjmp call.
@@ -55,12 +88,14 @@ _Z18InitializeGuardPtrv:
CFI_DEF_CFA (31, 0)
ret
CFI_ENDPROC
-.size _Z18InitializeGuardPtrv, .-_Z18InitializeGuardPtrv
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_Z18InitializeGuardPtrv))
+#endif
-.hidden __tsan_setjmp
+ASM_HIDDEN(__tsan_setjmp)
.comm _ZN14__interception11real_setjmpE,8,8
-.type setjmp, @function
-setjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp):
CFI_STARTPROC
// save env parameters for function call
@@ -78,14 +113,19 @@ setjmp:
CFI_OFFSET (19, -16)
mov x19, x0
+#if !defined(__APPLE__)
// SP pointer mangling (see glibc setjmp)
adrp x2, __tsan_pointer_chk_guard
ldr x2, [x2, #:lo12:__tsan_pointer_chk_guard]
add x0, x29, 32
eor x1, x2, x0
+#else
+ add x0, x29, 32
+ mov x1, x0
+#endif
// call tsan interceptor
- bl __tsan_setjmp
+ bl ASM_TSAN_SYMBOL(__tsan_setjmp)
// restore env parameter
mov x0, x19
@@ -96,18 +136,24 @@ setjmp:
CFI_DEF_CFA (31, 0)
// tail jump to libc setjmp
+#if !defined(__APPLE__)
adrp x1, :got:_ZN14__interception11real_setjmpE
ldr x1, [x1, #:got_lo12:_ZN14__interception11real_setjmpE]
ldr x1, [x1]
+#else
+ adrp x1, _setjmp$non_lazy_ptr@page
+ add x1, x1, _setjmp$non_lazy_ptr@pageoff
+ ldr x1, [x1]
+#endif
br x1
CFI_ENDPROC
-.size setjmp, .-setjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(setjmp))
.comm _ZN14__interception12real__setjmpE,8,8
-.globl _setjmp
-.type _setjmp, @function
-_setjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp):
CFI_STARTPROC
// save env parameters for function call
@@ -125,14 +171,19 @@ _setjmp:
CFI_OFFSET (19, -16)
mov x19, x0
+#if !defined(__APPLE__)
// SP pointer mangling (see glibc setjmp)
adrp x2, __tsan_pointer_chk_guard
ldr x2, [x2, #:lo12:__tsan_pointer_chk_guard]
add x0, x29, 32
eor x1, x2, x0
+#else
+ add x0, x29, 32
+ mov x1, x0
+#endif
// call tsan interceptor
- bl __tsan_setjmp
+ bl ASM_TSAN_SYMBOL(__tsan_setjmp)
// Restore jmp_buf parameter
mov x0, x19
@@ -143,18 +194,24 @@ _setjmp:
CFI_DEF_CFA (31, 0)
// tail jump to libc setjmp
+#if !defined(__APPLE__)
adrp x1, :got:_ZN14__interception12real__setjmpE
ldr x1, [x1, #:got_lo12:_ZN14__interception12real__setjmpE]
ldr x1, [x1]
+#else
+ adrp x1, __setjmp$non_lazy_ptr@page
+ add x1, x1, __setjmp$non_lazy_ptr@pageoff
+ ldr x1, [x1]
+#endif
br x1
CFI_ENDPROC
-.size _setjmp, .-_setjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(_setjmp))
.comm _ZN14__interception14real_sigsetjmpE,8,8
-.globl sigsetjmp
-.type sigsetjmp, @function
-sigsetjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp):
CFI_STARTPROC
// save env parameters for function call
@@ -174,14 +231,19 @@ sigsetjmp:
mov w20, w1
mov x19, x0
+#if !defined(__APPLE__)
// SP pointer mangling (see glibc setjmp)
adrp x2, __tsan_pointer_chk_guard
ldr x2, [x2, #:lo12:__tsan_pointer_chk_guard]
add x0, x29, 32
eor x1, x2, x0
+#else
+ add x0, x29, 32
+ mov x1, x0
+#endif
// call tsan interceptor
- bl __tsan_setjmp
+ bl ASM_TSAN_SYMBOL(__tsan_setjmp)
// restore env parameter
mov w1, w20
@@ -195,17 +257,24 @@ sigsetjmp:
CFI_DEF_CFA (31, 0)
// tail jump to libc sigsetjmp
+#if !defined(__APPLE__)
adrp x2, :got:_ZN14__interception14real_sigsetjmpE
ldr x2, [x2, #:got_lo12:_ZN14__interception14real_sigsetjmpE]
ldr x2, [x2]
+#else
+ adrp x2, _sigsetjmp$non_lazy_ptr@page
+ add x2, x2, _sigsetjmp$non_lazy_ptr@pageoff
+ ldr x2, [x2]
+#endif
br x2
CFI_ENDPROC
-.size sigsetjmp, .-sigsetjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(sigsetjmp))
+#if !defined(__APPLE__)
.comm _ZN14__interception16real___sigsetjmpE,8,8
-.globl __sigsetjmp
-.type __sigsetjmp, @function
-__sigsetjmp:
+.globl ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp)
+ASM_TYPE_FUNCTION(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp))
+ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp):
CFI_STARTPROC
// save env parameters for function call
@@ -225,14 +294,16 @@ __sigsetjmp:
mov w20, w1
mov x19, x0
+#if !defined(__APPLE__)
// SP pointer mangling (see glibc setjmp)
adrp x2, __tsan_pointer_chk_guard
ldr x2, [x2, #:lo12:__tsan_pointer_chk_guard]
add x0, x29, 32
eor x1, x2, x0
+#endif
// call tsan interceptor
- bl __tsan_setjmp
+ bl ASM_TSAN_SYMBOL(__tsan_setjmp)
mov w1, w20
mov x0, x19
@@ -245,14 +316,22 @@ __sigsetjmp:
CFI_DEF_CFA (31, 0)
// tail jump to libc __sigsetjmp
+#if !defined(__APPLE__)
adrp x2, :got:_ZN14__interception16real___sigsetjmpE
ldr x2, [x2, #:got_lo12:_ZN14__interception16real___sigsetjmpE]
ldr x2, [x2]
+#else
+ adrp x2, ASM_TSAN_SYMBOL(__sigsetjmp)@page
+ add x2, x2, ASM_TSAN_SYMBOL(__sigsetjmp)@pageoff
+#endif
br x2
CFI_ENDPROC
-.size __sigsetjmp, .-__sigsetjmp
+ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp))
+#endif
#if defined(__linux__)
/* We do not need executable stack. */
.section .note.GNU-stack,"",@progbits
#endif
+
+#endif
diff --git a/libsanitizer/tsan/tsan_rtl_amd64.S b/libsanitizer/tsan/tsan_rtl_amd64.S
index caa8323..98947fd 100644
--- a/libsanitizer/tsan/tsan_rtl_amd64.S
+++ b/libsanitizer/tsan/tsan_rtl_amd64.S
@@ -1,4 +1,8 @@
+// The content of this file is x86_64-only:
+#if defined(__x86_64__)
+
#include "sanitizer_common/sanitizer_asm.h"
+
#if !defined(__APPLE__)
.section .text
#else
@@ -357,3 +361,5 @@ ASM_SIZE(ASM_TSAN_SYMBOL_INTERCEPTOR(__sigsetjmp))
/* We do not need executable stack. */
.section .note.GNU-stack,"",@progbits
#endif
+
+#endif
diff --git a/libsanitizer/tsan/tsan_rtl_mutex.cc b/libsanitizer/tsan/tsan_rtl_mutex.cc
index e575bbf..d10a873 100644
--- a/libsanitizer/tsan/tsan_rtl_mutex.cc
+++ b/libsanitizer/tsan/tsan_rtl_mutex.cc
@@ -60,32 +60,29 @@ static void ReportMutexMisuse(ThreadState *thr, uptr pc, ReportType typ,
OutputReport(thr, rep);
}
-void MutexCreate(ThreadState *thr, uptr pc, uptr addr,
- bool rw, bool recursive, bool linker_init) {
- DPrintf("#%d: MutexCreate %zx\n", thr->tid, addr);
+void MutexCreate(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
+ DPrintf("#%d: MutexCreate %zx flagz=0x%x\n", thr->tid, addr, flagz);
StatInc(thr, StatMutexCreate);
- if (!linker_init && IsAppMem(addr)) {
+ if (!(flagz & MutexFlagLinkerInit) && IsAppMem(addr)) {
CHECK(!thr->is_freeing);
thr->is_freeing = true;
MemoryWrite(thr, pc, addr, kSizeLog1);
thr->is_freeing = false;
}
SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
- s->is_rw = rw;
- s->is_recursive = recursive;
- s->is_linker_init = linker_init;
+ s->SetFlags(flagz & MutexCreationFlagMask);
if (!SANITIZER_GO && s->creation_stack_id == 0)
s->creation_stack_id = CurrentStackId(thr, pc);
s->mtx.Unlock();
}
-void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
+void MutexDestroy(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
DPrintf("#%d: MutexDestroy %zx\n", thr->tid, addr);
StatInc(thr, StatMutexDestroy);
SyncVar *s = ctx->metamap.GetIfExistsAndLock(addr, true);
if (s == 0)
return;
- if (s->is_linker_init) {
+ if ((flagz & MutexFlagLinkerInit) || s->IsFlagSet(MutexFlagLinkerInit)) {
// Destroy is no-op for linker-initialized mutexes.
s->mtx.Unlock();
return;
@@ -98,8 +95,8 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
bool unlock_locked = false;
if (flags()->report_destroy_locked
&& s->owner_tid != SyncVar::kInvalidTid
- && !s->is_broken) {
- s->is_broken = true;
+ && !s->IsFlagSet(MutexFlagBroken)) {
+ s->SetFlags(MutexFlagBroken);
unlock_locked = true;
}
u64 mid = s->GetId();
@@ -139,12 +136,33 @@ void MutexDestroy(ThreadState *thr, uptr pc, uptr addr) {
// s will be destroyed and freed in MetaMap::FreeBlock.
}
-void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
- DPrintf("#%d: MutexLock %zx rec=%d\n", thr->tid, addr, rec);
- CHECK_GT(rec, 0);
+void MutexPreLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
+ DPrintf("#%d: MutexPreLock %zx flagz=0x%x\n", thr->tid, addr, flagz);
+ if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) {
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
+ s->UpdateFlags(flagz);
+ if (s->owner_tid != thr->tid) {
+ Callback cb(thr, pc);
+ ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
+ s->mtx.ReadUnlock();
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ } else {
+ s->mtx.ReadUnlock();
+ }
+ }
+}
+
+void MutexPostLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz, int rec) {
+ DPrintf("#%d: MutexPostLock %zx flag=0x%x rec=%d\n",
+ thr->tid, addr, flagz, rec);
+ if (flagz & MutexFlagRecursiveLock)
+ CHECK_GT(rec, 0);
+ else
+ rec = 1;
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
+ s->UpdateFlags(flagz);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeLock, s->GetId());
bool report_double_lock = false;
@@ -154,38 +172,43 @@ void MutexLock(ThreadState *thr, uptr pc, uptr addr, int rec, bool try_lock) {
s->last_lock = thr->fast_state.raw();
} else if (s->owner_tid == thr->tid) {
CHECK_GT(s->recursion, 0);
- } else if (flags()->report_mutex_bugs && !s->is_broken) {
- s->is_broken = true;
+ } else if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
+ s->SetFlags(MutexFlagBroken);
report_double_lock = true;
}
- if (s->recursion == 0) {
+ const bool first = s->recursion == 0;
+ s->recursion += rec;
+ if (first) {
StatInc(thr, StatMutexLock);
AcquireImpl(thr, pc, &s->clock);
AcquireImpl(thr, pc, &s->read_clock);
- } else if (!s->is_recursive) {
+ } else if (!s->IsFlagSet(MutexFlagWriteReentrant)) {
StatInc(thr, StatMutexRecLock);
}
- s->recursion += rec;
thr->mset.Add(s->GetId(), true, thr->fast_state.epoch());
- if (common_flags()->detect_deadlocks && (s->recursion - rec) == 0) {
+ bool pre_lock = false;
+ if (first && common_flags()->detect_deadlocks) {
+ pre_lock = (flagz & MutexFlagDoPreLockOnPostLock) &&
+ !(flagz & MutexFlagTryLock);
Callback cb(thr, pc);
- if (!try_lock)
+ if (pre_lock)
ctx->dd->MutexBeforeLock(&cb, &s->dd, true);
- ctx->dd->MutexAfterLock(&cb, &s->dd, true, try_lock);
+ ctx->dd->MutexAfterLock(&cb, &s->dd, true, flagz & MutexFlagTryLock);
}
u64 mid = s->GetId();
s->mtx.Unlock();
// Can't touch s after this point.
+ s = 0;
if (report_double_lock)
ReportMutexMisuse(thr, pc, ReportTypeMutexDoubleLock, addr, mid);
- if (common_flags()->detect_deadlocks) {
+ if (first && pre_lock && common_flags()->detect_deadlocks) {
Callback cb(thr, pc);
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
}
}
-int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
- DPrintf("#%d: MutexUnlock %zx all=%d\n", thr->tid, addr, all);
+int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
+ DPrintf("#%d: MutexUnlock %zx flagz=0x%x\n", thr->tid, addr, flagz);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, true);
@@ -194,12 +217,12 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
int rec = 0;
bool report_bad_unlock = false;
if (!SANITIZER_GO && (s->recursion == 0 || s->owner_tid != thr->tid)) {
- if (flags()->report_mutex_bugs && !s->is_broken) {
- s->is_broken = true;
+ if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
+ s->SetFlags(MutexFlagBroken);
report_bad_unlock = true;
}
} else {
- rec = all ? s->recursion : 1;
+ rec = (flagz & MutexFlagRecursiveUnlock) ? s->recursion : 1;
s->recursion -= rec;
if (s->recursion == 0) {
StatInc(thr, StatMutexUnlock);
@@ -227,36 +250,53 @@ int MutexUnlock(ThreadState *thr, uptr pc, uptr addr, bool all) {
return rec;
}
-void MutexReadLock(ThreadState *thr, uptr pc, uptr addr, bool trylock) {
- DPrintf("#%d: MutexReadLock %zx\n", thr->tid, addr);
+void MutexPreReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
+ DPrintf("#%d: MutexPreReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz);
+ if (!(flagz & MutexFlagTryLock) && common_flags()->detect_deadlocks) {
+ SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
+ s->UpdateFlags(flagz);
+ Callback cb(thr, pc);
+ ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
+ s->mtx.ReadUnlock();
+ ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
+ }
+}
+
+void MutexPostReadLock(ThreadState *thr, uptr pc, uptr addr, u32 flagz) {
+ DPrintf("#%d: MutexPostReadLock %zx flagz=0x%x\n", thr->tid, addr, flagz);
StatInc(thr, StatMutexReadLock);
if (IsAppMem(addr))
MemoryReadAtomic(thr, pc, addr, kSizeLog1);
SyncVar *s = ctx->metamap.GetOrCreateAndLock(thr, pc, addr, false);
+ s->UpdateFlags(flagz);
thr->fast_state.IncrementEpoch();
TraceAddEvent(thr, thr->fast_state, EventTypeRLock, s->GetId());
bool report_bad_lock = false;
if (s->owner_tid != SyncVar::kInvalidTid) {
- if (flags()->report_mutex_bugs && !s->is_broken) {
- s->is_broken = true;
+ if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
+ s->SetFlags(MutexFlagBroken);
report_bad_lock = true;
}
}
AcquireImpl(thr, pc, &s->clock);
s->last_lock = thr->fast_state.raw();
thr->mset.Add(s->GetId(), false, thr->fast_state.epoch());
- if (common_flags()->detect_deadlocks && s->recursion == 0) {
+ bool pre_lock = false;
+ if (common_flags()->detect_deadlocks) {
+ pre_lock = (flagz & MutexFlagDoPreLockOnPostLock) &&
+ !(flagz & MutexFlagTryLock);
Callback cb(thr, pc);
- if (!trylock)
+ if (pre_lock)
ctx->dd->MutexBeforeLock(&cb, &s->dd, false);
- ctx->dd->MutexAfterLock(&cb, &s->dd, false, trylock);
+ ctx->dd->MutexAfterLock(&cb, &s->dd, false, flagz & MutexFlagTryLock);
}
u64 mid = s->GetId();
s->mtx.ReadUnlock();
// Can't touch s after this point.
+ s = 0;
if (report_bad_lock)
ReportMutexMisuse(thr, pc, ReportTypeMutexBadReadLock, addr, mid);
- if (common_flags()->detect_deadlocks) {
+ if (pre_lock && common_flags()->detect_deadlocks) {
Callback cb(thr, pc);
ReportDeadlock(thr, pc, ctx->dd->GetReport(&cb));
}
@@ -272,8 +312,8 @@ void MutexReadUnlock(ThreadState *thr, uptr pc, uptr addr) {
TraceAddEvent(thr, thr->fast_state, EventTypeRUnlock, s->GetId());
bool report_bad_unlock = false;
if (s->owner_tid != SyncVar::kInvalidTid) {
- if (flags()->report_mutex_bugs && !s->is_broken) {
- s->is_broken = true;
+ if (flags()->report_mutex_bugs && !s->IsFlagSet(MutexFlagBroken)) {
+ s->SetFlags(MutexFlagBroken);
report_bad_unlock = true;
}
}
@@ -321,8 +361,8 @@ void MutexReadOrWriteUnlock(ThreadState *thr, uptr pc, uptr addr) {
} else {
StatInc(thr, StatMutexRecUnlock);
}
- } else if (!s->is_broken) {
- s->is_broken = true;
+ } else if (!s->IsFlagSet(MutexFlagBroken)) {
+ s->SetFlags(MutexFlagBroken);
report_bad_unlock = true;
}
thr->mset.Del(s->GetId(), write);
@@ -371,10 +411,10 @@ void Acquire(ThreadState *thr, uptr pc, uptr addr) {
static void UpdateClockCallback(ThreadContextBase *tctx_base, void *arg) {
ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
+ u64 epoch = tctx->epoch1;
if (tctx->status == ThreadStatusRunning)
- thr->clock.set(tctx->tid, tctx->thr->fast_state.epoch());
- else
- thr->clock.set(tctx->tid, tctx->epoch1);
+ epoch = tctx->thr->fast_state.epoch();
+ thr->clock.set(&thr->proc()->clock_cache, tctx->tid, epoch);
}
void AcquireGlobal(ThreadState *thr, uptr pc) {
@@ -414,10 +454,10 @@ void ReleaseStore(ThreadState *thr, uptr pc, uptr addr) {
static void UpdateSleepClockCallback(ThreadContextBase *tctx_base, void *arg) {
ThreadState *thr = reinterpret_cast<ThreadState*>(arg);
ThreadContext *tctx = static_cast<ThreadContext*>(tctx_base);
+ u64 epoch = tctx->epoch1;
if (tctx->status == ThreadStatusRunning)
- thr->last_sleep_clock.set(tctx->tid, tctx->thr->fast_state.epoch());
- else
- thr->last_sleep_clock.set(tctx->tid, tctx->epoch1);
+ epoch = tctx->thr->fast_state.epoch();
+ thr->last_sleep_clock.set(&thr->proc()->clock_cache, tctx->tid, epoch);
}
void AfterSleep(ThreadState *thr, uptr pc) {
diff --git a/libsanitizer/tsan/tsan_rtl_report.cc b/libsanitizer/tsan/tsan_rtl_report.cc
index 8f28824..a961139 100644
--- a/libsanitizer/tsan/tsan_rtl_report.cc
+++ b/libsanitizer/tsan/tsan_rtl_report.cc
@@ -141,11 +141,12 @@ static ReportStack *SymbolizeStack(StackTrace trace) {
return stack;
}
-ScopedReport::ScopedReport(ReportType typ) {
+ScopedReport::ScopedReport(ReportType typ, uptr tag) {
ctx->thread_registry->CheckLocked();
void *mem = internal_alloc(MBlockReport, sizeof(ReportDesc));
rep_ = new(mem) ReportDesc;
rep_->typ = typ;
+ rep_->tag = tag;
ctx->report_mtx.Lock();
CommonSanitizerReportMutex.Lock();
}
@@ -162,8 +163,8 @@ void ScopedReport::AddStack(StackTrace stack, bool suppressable) {
(*rs)->suppressable = suppressable;
}
-void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
- const MutexSet *mset) {
+void ScopedReport::AddMemoryAccess(uptr addr, uptr external_tag, Shadow s,
+ StackTrace stack, const MutexSet *mset) {
void *mem = internal_alloc(MBlockReportMop, sizeof(ReportMop));
ReportMop *mop = new(mem) ReportMop;
rep_->mops.PushBack(mop);
@@ -173,6 +174,7 @@ void ScopedReport::AddMemoryAccess(uptr addr, Shadow s, StackTrace stack,
mop->write = s.IsWrite();
mop->atomic = s.IsAtomic();
mop->stack = SymbolizeStack(stack);
+ mop->external_tag = external_tag;
if (mop->stack)
mop->stack->suppressable = true;
for (uptr i = 0; i < mset->Size(); i++) {
@@ -200,6 +202,7 @@ void ScopedReport::AddThread(const ThreadContext *tctx, bool suppressable) {
rt->running = (tctx->status == ThreadStatusRunning);
rt->name = internal_strdup(tctx->name);
rt->parent_tid = tctx->parent_tid;
+ rt->workerthread = tctx->workerthread;
rt->stack = 0;
rt->stack = SymbolizeStackId(tctx->creation_stack_id);
if (rt->stack)
@@ -309,7 +312,7 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
return;
#if !SANITIZER_GO
int fd = -1;
- int creat_tid = -1;
+ int creat_tid = kInvalidTid;
u32 creat_stack = 0;
if (FdLocation(addr, &fd, &creat_tid, &creat_stack)) {
ReportLocation *loc = ReportLocation::New(ReportLocationFD);
@@ -334,6 +337,7 @@ void ScopedReport::AddLocation(uptr addr, uptr size) {
ReportLocation *loc = ReportLocation::New(ReportLocationHeap);
loc->heap_chunk_start = (uptr)allocator()->GetBlockBegin((void *)addr);
loc->heap_chunk_size = b->siz;
+ loc->external_tag = b->tag;
loc->tid = tctx ? tctx->tid : b->tid;
loc->stack = SymbolizeStackId(b->stk);
rep_->locs.PushBack(loc);
@@ -372,7 +376,7 @@ const ReportDesc *ScopedReport::GetReport() const {
}
void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
- MutexSet *mset) {
+ MutexSet *mset, uptr *tag) {
// This function restores stack trace and mutex set for the thread/epoch.
// It does so by getting stack trace and mutex set at the beginning of
// trace part, and then replaying the trace till the given epoch.
@@ -400,8 +404,8 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
Event *events = (Event*)GetThreadTrace(tid);
for (uptr i = ebegin; i <= eend; i++) {
Event ev = events[i];
- EventType typ = (EventType)(ev >> 61);
- uptr pc = (uptr)(ev & ((1ull << 61) - 1));
+ EventType typ = (EventType)(ev >> kEventPCBits);
+ uptr pc = (uptr)(ev & ((1ull << kEventPCBits) - 1));
DPrintf2(" %zu typ=%d pc=%zx\n", i, typ, pc);
if (typ == EventTypeMop) {
stack[pos] = pc;
@@ -431,6 +435,7 @@ void RestoreStack(int tid, const u64 epoch, VarSizeStackTrace *stk,
return;
pos++;
stk->Init(&stack[0], pos);
+ ExtractTagFromStack(stk, tag);
}
static bool HandleRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
@@ -495,7 +500,7 @@ static void AddRacyStacks(ThreadState *thr, VarSizeStackTrace traces[2],
}
bool OutputReport(ThreadState *thr, const ScopedReport &srep) {
- if (!flags()->report_bugs)
+ if (!flags()->report_bugs || thr->suppress_reports)
return false;
atomic_store_relaxed(&ctx->last_symbolize_time_ns, NanoTime());
const ReportDesc *rep = srep.GetReport();
@@ -626,8 +631,29 @@ void ReportRace(ThreadState *thr) {
const uptr kMop = 2;
VarSizeStackTrace traces[kMop];
- const uptr toppc = TraceTopPC(thr);
- ObtainCurrentStack(thr, toppc, &traces[0]);
+ uptr tags[kMop] = {kExternalTagNone};
+ uptr toppc = TraceTopPC(thr);
+ if (toppc >> kEventPCBits) {
+ // This is a work-around for a known issue.
+ // The scenario where this happens is rather elaborate and requires
+ // an instrumented __sanitizer_report_error_summary callback and
+ // a __tsan_symbolize_external callback and a race during a range memory
+ // access larger than 8 bytes. MemoryAccessRange adds the current PC to
+ // the trace and starts processing memory accesses. A first memory access
+ // triggers a race, we report it and call the instrumented
+ // __sanitizer_report_error_summary, which adds more stuff to the trace
+ // since it is intrumented. Then a second memory access in MemoryAccessRange
+ // also triggers a race and we get here and call TraceTopPC to get the
+ // current PC, however now it contains some unrelated events from the
+ // callback. Most likely, TraceTopPC will now return a EventTypeFuncExit
+ // event. Later we subtract -1 from it (in GetPreviousInstructionPc)
+ // and the resulting PC has kExternalPCBit set, so we pass it to
+ // __tsan_symbolize_external. __tsan_symbolize_external is within its rights
+ // to crash since the PC is completely bogus.
+ // test/tsan/double_race.cc contains a test case for this.
+ toppc = 0;
+ }
+ ObtainCurrentStack(thr, toppc, &traces[0], &tags[0]);
if (IsFiredSuppression(ctx, typ, traces[0]))
return;
@@ -637,18 +663,29 @@ void ReportRace(ThreadState *thr) {
MutexSet *mset2 = new(&mset_buffer[0]) MutexSet();
Shadow s2(thr->racy_state[1]);
- RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2);
+ RestoreStack(s2.tid(), s2.epoch(), &traces[1], mset2, &tags[1]);
if (IsFiredSuppression(ctx, typ, traces[1]))
return;
if (HandleRacyStacks(thr, traces, addr_min, addr_max))
return;
+ // If any of the accesses has a tag, treat this as an "external" race.
+ uptr tag = kExternalTagNone;
+ for (uptr i = 0; i < kMop; i++) {
+ if (tags[i] != kExternalTagNone) {
+ typ = ReportTypeExternalRace;
+ tag = tags[i];
+ break;
+ }
+ }
+
ThreadRegistryLock l0(ctx->thread_registry);
- ScopedReport rep(typ);
+ ScopedReport rep(typ, tag);
for (uptr i = 0; i < kMop; i++) {
Shadow s(thr->racy_state[i]);
- rep.AddMemoryAccess(addr, s, traces[i], i == 0 ? &thr->mset : mset2);
+ rep.AddMemoryAccess(addr, tags[i], s, traces[i],
+ i == 0 ? &thr->mset : mset2);
}
for (uptr i = 0; i < kMop; i++) {
diff --git a/libsanitizer/tsan/tsan_rtl_thread.cc b/libsanitizer/tsan/tsan_rtl_thread.cc
index 6c4b74e..e81669d 100644
--- a/libsanitizer/tsan/tsan_rtl_thread.cc
+++ b/libsanitizer/tsan/tsan_rtl_thread.cc
@@ -66,7 +66,8 @@ void ThreadContext::OnCreated(void *arg) {
void ThreadContext::OnReset() {
CHECK_EQ(sync.size(), 0);
- ReleaseMemoryToOS(GetThreadTrace(tid), TraceSize() * sizeof(Event));
+ uptr trace_p = GetThreadTrace(tid);
+ ReleaseMemoryPagesToOS(trace_p, trace_p + TraceSize() * sizeof(Event));
//!!! ReleaseMemoryToOS(GetThreadTraceHeader(tid), sizeof(Trace));
}
@@ -139,6 +140,10 @@ void ThreadContext::OnFinished() {
if (common_flags()->detect_deadlocks)
ctx->dd->DestroyLogicalThread(thr->dd_lt);
+ thr->clock.ResetCached(&thr->proc()->clock_cache);
+#if !SANITIZER_GO
+ thr->last_sleep_clock.ResetCached(&thr->proc()->clock_cache);
+#endif
thr->~ThreadState();
#if TSAN_COLLECT_STATS
StatAggregate(ctx->stat, thr->stat);
@@ -233,7 +238,7 @@ int ThreadCreate(ThreadState *thr, uptr pc, uptr uid, bool detached) {
return tid;
}
-void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
+void ThreadStart(ThreadState *thr, int tid, tid_t os_id, bool workerthread) {
uptr stk_addr = 0;
uptr stk_size = 0;
uptr tls_addr = 0;
@@ -245,25 +250,13 @@ void ThreadStart(ThreadState *thr, int tid, uptr os_id) {
if (stk_addr && stk_size)
MemoryRangeImitateWrite(thr, /*pc=*/ 1, stk_addr, stk_size);
- if (tls_addr && tls_size) {
- // Check that the thr object is in tls;
- const uptr thr_beg = (uptr)thr;
- const uptr thr_end = (uptr)thr + sizeof(*thr);
- CHECK_GE(thr_beg, tls_addr);
- CHECK_LE(thr_beg, tls_addr + tls_size);
- CHECK_GE(thr_end, tls_addr);
- CHECK_LE(thr_end, tls_addr + tls_size);
- // Since the thr object is huge, skip it.
- MemoryRangeImitateWrite(thr, /*pc=*/ 2, tls_addr, thr_beg - tls_addr);
- MemoryRangeImitateWrite(thr, /*pc=*/ 2,
- thr_end, tls_addr + tls_size - thr_end);
- }
+ if (tls_addr && tls_size) ImitateTlsWrite(thr, tls_addr, tls_size);
}
#endif
ThreadRegistry *tr = ctx->thread_registry;
OnStartedArgs args = { thr, stk_addr, stk_size, tls_addr, tls_size };
- tr->StartThread(tid, os_id, &args);
+ tr->StartThread(tid, os_id, workerthread, &args);
tr->Lock();
thr->tctx = (ThreadContext*)tr->GetThreadLocked(tid);
@@ -354,6 +347,7 @@ void MemoryAccessRange(ThreadState *thr, uptr pc, uptr addr,
StatInc(thr, StatMopRange);
if (*shadow_mem == kShadowRodata) {
+ DCHECK(!is_write);
// Access to .rodata section, no races here.
// Measurements show that it can be 10-20% of all memory accesses.
StatInc(thr, StatMopRangeRodata);
diff --git a/libsanitizer/tsan/tsan_stat.cc b/libsanitizer/tsan/tsan_stat.cc
index 740cb86..decb7a2 100644
--- a/libsanitizer/tsan/tsan_stat.cc
+++ b/libsanitizer/tsan/tsan_stat.cc
@@ -73,14 +73,11 @@ void StatOutput(u64 *stat) {
name[StatClockAcquire] = "Clock acquire ";
name[StatClockAcquireEmpty] = " empty clock ";
name[StatClockAcquireFastRelease] = " fast from release-store ";
- name[StatClockAcquireLarge] = " contains my tid ";
- name[StatClockAcquireRepeat] = " repeated (fast) ";
name[StatClockAcquireFull] = " full (slow) ";
name[StatClockAcquiredSomething] = " acquired something ";
name[StatClockRelease] = "Clock release ";
name[StatClockReleaseResize] = " resize ";
- name[StatClockReleaseFast1] = " fast1 ";
- name[StatClockReleaseFast2] = " fast2 ";
+ name[StatClockReleaseFast] = " fast ";
name[StatClockReleaseSlow] = " dirty overflow (slow) ";
name[StatClockReleaseFull] = " full (slow) ";
name[StatClockReleaseAcquired] = " was acquired ";
@@ -151,6 +148,16 @@ void StatOutput(u64 *stat) {
name[StatAnnotatePublishMemoryRange] = " PublishMemoryRange ";
name[StatAnnotateUnpublishMemoryRange] = " UnpublishMemoryRange ";
name[StatAnnotateThreadName] = " ThreadName ";
+ name[Stat__tsan_mutex_create] = " __tsan_mutex_create ";
+ name[Stat__tsan_mutex_destroy] = " __tsan_mutex_destroy ";
+ name[Stat__tsan_mutex_pre_lock] = " __tsan_mutex_pre_lock ";
+ name[Stat__tsan_mutex_post_lock] = " __tsan_mutex_post_lock ";
+ name[Stat__tsan_mutex_pre_unlock] = " __tsan_mutex_pre_unlock ";
+ name[Stat__tsan_mutex_post_unlock] = " __tsan_mutex_post_unlock ";
+ name[Stat__tsan_mutex_pre_signal] = " __tsan_mutex_pre_signal ";
+ name[Stat__tsan_mutex_post_signal] = " __tsan_mutex_post_signal ";
+ name[Stat__tsan_mutex_pre_divert] = " __tsan_mutex_pre_divert ";
+ name[Stat__tsan_mutex_post_divert] = " __tsan_mutex_post_divert ";
name[StatMtxTotal] = "Contentionz ";
name[StatMtxTrace] = " Trace ";
diff --git a/libsanitizer/tsan/tsan_stat.h b/libsanitizer/tsan/tsan_stat.h
index 788adeb..c4859df 100644
--- a/libsanitizer/tsan/tsan_stat.h
+++ b/libsanitizer/tsan/tsan_stat.h
@@ -72,15 +72,12 @@ enum StatType {
StatClockAcquire,
StatClockAcquireEmpty,
StatClockAcquireFastRelease,
- StatClockAcquireLarge,
- StatClockAcquireRepeat,
StatClockAcquireFull,
StatClockAcquiredSomething,
// Clocks - release.
StatClockRelease,
StatClockReleaseResize,
- StatClockReleaseFast1,
- StatClockReleaseFast2,
+ StatClockReleaseFast,
StatClockReleaseSlow,
StatClockReleaseFull,
StatClockReleaseAcquired,
@@ -155,6 +152,16 @@ enum StatType {
StatAnnotatePublishMemoryRange,
StatAnnotateUnpublishMemoryRange,
StatAnnotateThreadName,
+ Stat__tsan_mutex_create,
+ Stat__tsan_mutex_destroy,
+ Stat__tsan_mutex_pre_lock,
+ Stat__tsan_mutex_post_lock,
+ Stat__tsan_mutex_pre_unlock,
+ Stat__tsan_mutex_post_unlock,
+ Stat__tsan_mutex_pre_signal,
+ Stat__tsan_mutex_post_signal,
+ Stat__tsan_mutex_pre_divert,
+ Stat__tsan_mutex_post_divert,
// Internal mutex contentionz.
StatMtxTotal,
diff --git a/libsanitizer/tsan/tsan_suppressions.cc b/libsanitizer/tsan/tsan_suppressions.cc
index dc862b1..e40eb70 100644
--- a/libsanitizer/tsan/tsan_suppressions.cc
+++ b/libsanitizer/tsan/tsan_suppressions.cc
@@ -72,6 +72,8 @@ static const char *conv(ReportType typ) {
return kSuppressionRace;
else if (typ == ReportTypeVptrUseAfterFree)
return kSuppressionRace;
+ else if (typ == ReportTypeExternalRace)
+ return kSuppressionRace;
else if (typ == ReportTypeThreadLeak)
return kSuppressionThread;
else if (typ == ReportTypeMutexDestroyLocked)
diff --git a/libsanitizer/tsan/tsan_sync.cc b/libsanitizer/tsan/tsan_sync.cc
index 0ee2295..0f840de 100644
--- a/libsanitizer/tsan/tsan_sync.cc
+++ b/libsanitizer/tsan/tsan_sync.cc
@@ -40,10 +40,7 @@ void SyncVar::Reset(Processor *proc) {
owner_tid = kInvalidTid;
last_lock = 0;
recursion = 0;
- is_rw = 0;
- is_recursive = 0;
- is_broken = 0;
- is_linker_init = 0;
+ atomic_store_relaxed(&flags, 0);
if (proc == 0) {
CHECK_EQ(clock.size(), 0);
@@ -54,7 +51,9 @@ void SyncVar::Reset(Processor *proc) {
}
}
-MetaMap::MetaMap() {
+MetaMap::MetaMap()
+ : block_alloc_("heap block allocator")
+ , sync_alloc_("sync allocator") {
atomic_store(&uid_gen_, 0, memory_order_relaxed);
}
@@ -62,6 +61,7 @@ void MetaMap::AllocBlock(ThreadState *thr, uptr pc, uptr p, uptr sz) {
u32 idx = block_alloc_.Alloc(&thr->proc()->block_cache);
MBlock *b = block_alloc_.Map(idx);
b->siz = sz;
+ b->tag = 0;
b->tid = thr->tid;
b->stk = CurrentStackId(thr, pc);
u32 *meta = MemToMeta(p);
diff --git a/libsanitizer/tsan/tsan_sync.h b/libsanitizer/tsan/tsan_sync.h
index 48d7027..195279f 100644
--- a/libsanitizer/tsan/tsan_sync.h
+++ b/libsanitizer/tsan/tsan_sync.h
@@ -21,6 +21,29 @@
namespace __tsan {
+// These need to match __tsan_mutex_* flags defined in tsan_interface.h.
+// See documentation there as well.
+enum MutexFlags {
+ MutexFlagLinkerInit = 1 << 0, // __tsan_mutex_linker_init
+ MutexFlagWriteReentrant = 1 << 1, // __tsan_mutex_write_reentrant
+ MutexFlagReadReentrant = 1 << 2, // __tsan_mutex_read_reentrant
+ MutexFlagReadLock = 1 << 3, // __tsan_mutex_read_lock
+ MutexFlagTryLock = 1 << 4, // __tsan_mutex_try_lock
+ MutexFlagTryLockFailed = 1 << 5, // __tsan_mutex_try_lock_failed
+ MutexFlagRecursiveLock = 1 << 6, // __tsan_mutex_recursive_lock
+ MutexFlagRecursiveUnlock = 1 << 7, // __tsan_mutex_recursive_unlock
+
+ // The following flags are runtime private.
+ // Mutex API misuse was detected, so don't report any more.
+ MutexFlagBroken = 1 << 30,
+ // We did not intercept pre lock event, so handle it on post lock.
+ MutexFlagDoPreLockOnPostLock = 1 << 29,
+ // Must list all mutex creation flags.
+ MutexCreationFlagMask = MutexFlagLinkerInit |
+ MutexFlagWriteReentrant |
+ MutexFlagReadReentrant,
+};
+
struct SyncVar {
SyncVar();
@@ -33,10 +56,7 @@ struct SyncVar {
int owner_tid; // Set only by exclusive owners.
u64 last_lock;
int recursion;
- bool is_rw;
- bool is_recursive;
- bool is_broken;
- bool is_linker_init;
+ atomic_uint32_t flags;
u32 next; // in MetaMap
DDMutex dd;
SyncClock read_clock; // Used for rw mutexes only.
@@ -59,6 +79,26 @@ struct SyncVar {
*uid = id >> 48;
return (uptr)GetLsb(id, 48);
}
+
+ bool IsFlagSet(u32 f) const {
+ return atomic_load_relaxed(&flags) & f;
+ }
+
+ void SetFlags(u32 f) {
+ atomic_store_relaxed(&flags, atomic_load_relaxed(&flags) | f);
+ }
+
+ void UpdateFlags(u32 flagz) {
+ // Filter out operation flags.
+ if (!(flagz & MutexCreationFlagMask))
+ return;
+ u32 current = atomic_load_relaxed(&flags);
+ if (current & MutexCreationFlagMask)
+ return;
+ // Note: this can be called from MutexPostReadLock which holds only read
+ // lock on the SyncVar.
+ atomic_store_relaxed(&flags, current | (flagz & MutexCreationFlagMask));
+ }
};
/* MetaMap allows to map arbitrary user pointers onto various descriptors.
diff --git a/libsanitizer/tsan/tsan_trace.h b/libsanitizer/tsan/tsan_trace.h
index 1ea733b..5cc3f8f 100644
--- a/libsanitizer/tsan/tsan_trace.h
+++ b/libsanitizer/tsan/tsan_trace.h
@@ -39,6 +39,8 @@ enum EventType {
// u64 addr : 61; // Associated pc.
typedef u64 Event;
+const uptr kEventPCBits = 61;
+
struct TraceHeader {
#if !SANITIZER_GO
BufferedStackTrace stack0; // Start stack for the trace.
diff --git a/libsanitizer/ubsan/Makefile.am b/libsanitizer/ubsan/Makefile.am
index cb27091..cce728c 100644
--- a/libsanitizer/ubsan/Makefile.am
+++ b/libsanitizer/ubsan/Makefile.am
@@ -3,7 +3,7 @@ AM_CPPFLAGS = -I $(top_srcdir) -I $(top_srcdir)/include
# May be used by toolexeclibdir.
gcc_version := $(shell @get_gcc_base_ver@ $(top_srcdir)/../gcc/BASE-VER)
-DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DPIC -DCAN_SANITIZE_UB=1
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DPIC -DCAN_SANITIZE_UB=1 -DUBSAN_CAN_USE_CXXABI=1
AM_CXXFLAGS = -Wall -W -Wno-unused-parameter -Wwrite-strings -pedantic -Wno-long-long -fPIC -fno-builtin -fno-exceptions -fno-rtti -fomit-frame-pointer -funwind-tables -fvisibility=hidden -Wno-variadic-macros
AM_CXXFLAGS += $(LIBSTDCXX_RAW_CXX_CXXFLAGS)
AM_CXXFLAGS += -std=gnu++11
@@ -24,7 +24,8 @@ ubsan_plugin_files = \
ubsan_files = \
$(ubsan_plugin_files) \
- ubsan_init_standalone.cc
+ ubsan_init_standalone.cc \
+ ubsan_signals_standalone.cc
libubsan_la_SOURCES = $(ubsan_files)
libubsan_la_LIBADD = $(top_builddir)/sanitizer_common/libsanitizer_common.la
diff --git a/libsanitizer/ubsan/Makefile.in b/libsanitizer/ubsan/Makefile.in
index 1664ce9..9552ec1 100644
--- a/libsanitizer/ubsan/Makefile.in
+++ b/libsanitizer/ubsan/Makefile.in
@@ -111,7 +111,8 @@ am__objects_1 = ubsan_diag.lo ubsan_flags.lo ubsan_handlers.lo \
ubsan_handlers_cxx.lo ubsan_init.lo ubsan_type_hash.lo \
ubsan_type_hash_itanium.lo ubsan_type_hash_win.lo \
ubsan_value.lo
-am__objects_2 = $(am__objects_1) ubsan_init_standalone.lo
+am__objects_2 = $(am__objects_1) ubsan_init_standalone.lo \
+ ubsan_signals_standalone.lo
am_libubsan_la_OBJECTS = $(am__objects_2)
libubsan_la_OBJECTS = $(am_libubsan_la_OBJECTS)
libubsan_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \
@@ -162,7 +163,7 @@ CXXCPP = @CXXCPP@
CXXDEPMODE = @CXXDEPMODE@
CXXFLAGS = @CXXFLAGS@
CYGPATH_W = @CYGPATH_W@
-DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DPIC -DCAN_SANITIZE_UB=1
+DEFS = -D_GNU_SOURCE -D_DEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS -DPIC -DCAN_SANITIZE_UB=1 -DUBSAN_CAN_USE_CXXABI=1
DEPDIR = @DEPDIR@
DSYMUTIL = @DSYMUTIL@
DUMPBIN = @DUMPBIN@
@@ -307,7 +308,8 @@ ubsan_plugin_files = \
ubsan_files = \
$(ubsan_plugin_files) \
- ubsan_init_standalone.cc
+ ubsan_init_standalone.cc \
+ ubsan_signals_standalone.cc
libubsan_la_SOURCES = $(ubsan_files)
libubsan_la_LIBADD = \
@@ -435,6 +437,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_handlers_cxx.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_init.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_init_standalone.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_signals_standalone.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_type_hash.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_type_hash_itanium.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ubsan_type_hash_win.Plo@am__quote@
diff --git a/libsanitizer/ubsan/libtool-version b/libsanitizer/ubsan/libtool-version
index 204fdd2..4b49476 100644
--- a/libsanitizer/ubsan/libtool-version
+++ b/libsanitizer/ubsan/libtool-version
@@ -3,4 +3,4 @@
# a separate file so that version updates don't involve re-running
# automake.
# CURRENT:REVISION:AGE
-0:0:0
+1:0:0
diff --git a/libsanitizer/ubsan/ubsan_checks.inc b/libsanitizer/ubsan/ubsan_checks.inc
index 31e9495..c445924 100644
--- a/libsanitizer/ubsan/ubsan_checks.inc
+++ b/libsanitizer/ubsan/ubsan_checks.inc
@@ -27,6 +27,7 @@ UBSAN_CHECK(UnsignedIntegerOverflow, "unsigned-integer-overflow",
UBSAN_CHECK(IntegerDivideByZero, "integer-divide-by-zero",
"integer-divide-by-zero")
UBSAN_CHECK(FloatDivideByZero, "float-divide-by-zero", "float-divide-by-zero")
+UBSAN_CHECK(InvalidBuiltin, "invalid-builtin-use", "invalid-builtin-use")
UBSAN_CHECK(InvalidShiftBase, "invalid-shift-base", "shift-base")
UBSAN_CHECK(InvalidShiftExponent, "invalid-shift-exponent", "shift-exponent")
UBSAN_CHECK(OutOfBoundsIndex, "out-of-bounds-index", "bounds")
diff --git a/libsanitizer/ubsan/ubsan_diag.cc b/libsanitizer/ubsan/ubsan_diag.cc
index b6e982a..978d966 100644
--- a/libsanitizer/ubsan/ubsan_diag.cc
+++ b/libsanitizer/ubsan/ubsan_diag.cc
@@ -24,20 +24,25 @@
using namespace __ubsan;
+void __ubsan::GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack,
+ uptr max_depth, uptr pc, uptr bp,
+ void *context, bool fast) {
+ uptr top = 0;
+ uptr bottom = 0;
+ if (fast)
+ GetThreadStackTopAndBottom(false, &top, &bottom);
+ stack->Unwind(max_depth, pc, bp, context, top, bottom, fast);
+}
+
static void MaybePrintStackTrace(uptr pc, uptr bp) {
// We assume that flags are already parsed, as UBSan runtime
// will definitely be called when we print the first diagnostics message.
if (!flags()->print_stacktrace)
return;
- // We can only use slow unwind, as we don't have any information about stack
- // top/bottom.
- // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
- // fetch stack top/bottom information if we have it (e.g. if we're running
- // under ASan).
- if (StackTrace::WillUseFastUnwind(false))
- return;
+
BufferedStackTrace stack;
- stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
+ GetStackTraceWithPcBpAndContext(&stack, kStackTraceMax, pc, bp, nullptr,
+ common_flags()->fast_unwind_on_fatal);
stack.Print();
}
@@ -77,16 +82,16 @@ static void MaybeReportErrorSummary(Location Loc, ErrorType Type) {
AI.line = SLoc.getLine();
AI.column = SLoc.getColumn();
AI.function = internal_strdup(""); // Avoid printing ?? as function name.
- ReportErrorSummary(ErrorKind, AI);
+ ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName());
AI.Clear();
return;
}
} else if (Loc.isSymbolizedStack()) {
const AddressInfo &AI = Loc.getSymbolizedStack()->info;
- ReportErrorSummary(ErrorKind, AI);
+ ReportErrorSummary(ErrorKind, AI, GetSanititizerToolName());
return;
}
- ReportErrorSummary(ErrorKind);
+ ReportErrorSummary(ErrorKind, GetSanititizerToolName());
}
namespace {
@@ -94,9 +99,7 @@ class Decorator : public SanitizerCommonDecorator {
public:
Decorator() : SanitizerCommonDecorator() {}
const char *Highlight() const { return Green(); }
- const char *EndHighlight() const { return Default(); }
const char *Note() const { return Black(); }
- const char *EndNote() const { return Default(); }
};
}
@@ -155,7 +158,7 @@ static void RenderLocation(InternalScopedString *Buffer, Location Loc) {
common_flags()->strip_path_prefix);
else if (Info.module)
RenderModuleLocation(Buffer, Info.module, Info.module_offset,
- common_flags()->strip_path_prefix);
+ Info.module_arch, common_flags()->strip_path_prefix);
else
Buffer->append("%p", Info.address);
return;
@@ -292,7 +295,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
Buffer.append("%c", P == Loc ? '^' : Byte);
Buffer.append("%c", Byte);
}
- Buffer.append("%s\n", Decor.EndHighlight());
+ Buffer.append("%s\n", Decor.Default());
// Go over the line again, and print names for the ranges.
InRange = 0;
@@ -332,7 +335,7 @@ static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
Diag::~Diag() {
// All diagnostics should be printed under report mutex.
- CommonSanitizerReportMutex.CheckLocked();
+ ScopedReport::CheckLocked();
Decorator Decor;
InternalScopedString Buffer(1024);
@@ -342,12 +345,12 @@ Diag::~Diag() {
switch (Level) {
case DL_Error:
- Buffer.append("%s runtime error: %s%s", Decor.Warning(), Decor.EndWarning(),
+ Buffer.append("%s runtime error: %s%s", Decor.Warning(), Decor.Default(),
Decor.Bold());
break;
case DL_Note:
- Buffer.append("%s note: %s", Decor.Note(), Decor.EndNote());
+ Buffer.append("%s note: %s", Decor.Note(), Decor.Default());
break;
}
@@ -360,17 +363,15 @@ Diag::~Diag() {
PrintMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args);
}
+ScopedReport::Initializer::Initializer() { InitAsStandaloneIfNecessary(); }
+
ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
ErrorType Type)
- : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {
- InitAsStandaloneIfNecessary();
- CommonSanitizerReportMutex.Lock();
-}
+ : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {}
ScopedReport::~ScopedReport() {
MaybePrintStackTrace(Opts.pc, Opts.bp);
MaybeReportErrorSummary(SummaryLoc, Type);
- CommonSanitizerReportMutex.Unlock();
if (flags()->halt_on_error)
Die();
}
diff --git a/libsanitizer/ubsan/ubsan_diag.h b/libsanitizer/ubsan/ubsan_diag.h
index 3456aaa..e9e5ab6 100644
--- a/libsanitizer/ubsan/ubsan_diag.h
+++ b/libsanitizer/ubsan/ubsan_diag.h
@@ -229,10 +229,20 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);
GET_CALLER_PC_BP; \
ReportOptions Opts = {unrecoverable_handler, pc, bp}
+void GetStackTraceWithPcBpAndContext(BufferedStackTrace *stack, uptr max_depth,
+ uptr pc, uptr bp, void *context,
+ bool fast);
+
/// \brief Instantiate this class before printing diagnostics in the error
/// report. This class ensures that reports from different threads and from
/// different sanitizers won't be mixed.
class ScopedReport {
+ struct Initializer {
+ Initializer();
+ };
+ Initializer initializer_;
+ ScopedErrorReportLock report_lock_;
+
ReportOptions Opts;
Location SummaryLoc;
ErrorType Type;
@@ -240,6 +250,8 @@ class ScopedReport {
public:
ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);
~ScopedReport();
+
+ static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); }
};
void InitializeSuppressions();
diff --git a/libsanitizer/ubsan/ubsan_diag_standalone.cc b/libsanitizer/ubsan/ubsan_diag_standalone.cc
new file mode 100644
index 0000000..ddc1be7
--- /dev/null
+++ b/libsanitizer/ubsan/ubsan_diag_standalone.cc
@@ -0,0 +1,36 @@
+//===-- ubsan_diag_standalone.cc ------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Diagnostic reporting for the standalone UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
+#include "ubsan_diag.h"
+
+using namespace __ubsan;
+
+extern "C" {
+SANITIZER_INTERFACE_ATTRIBUTE
+void __sanitizer_print_stack_trace() {
+ uptr top = 0;
+ uptr bottom = 0;
+ bool request_fast_unwind = common_flags()->fast_unwind_on_fatal;
+ if (request_fast_unwind)
+ __sanitizer::GetThreadStackTopAndBottom(false, &top, &bottom);
+
+ GET_CURRENT_PC_BP_SP;
+ (void)sp;
+ BufferedStackTrace stack;
+ stack.Unwind(kStackTraceMax, pc, bp, nullptr, top, bottom,
+ request_fast_unwind);
+ stack.Print();
+}
+} // extern "C"
+
+#endif // CAN_SANITIZE_UB
diff --git a/libsanitizer/ubsan/ubsan_flags.cc b/libsanitizer/ubsan/ubsan_flags.cc
index 19f5de1..9a3ea4b 100644
--- a/libsanitizer/ubsan/ubsan_flags.cc
+++ b/libsanitizer/ubsan/ubsan_flags.cc
@@ -43,6 +43,7 @@ void InitializeFlags() {
CommonFlags cf;
cf.CopyFrom(*common_flags());
cf.print_summary = false;
+ cf.external_symbolizer_path = GetEnv("UBSAN_SYMBOLIZER_PATH");
OverrideCommonFlags(cf);
}
@@ -65,22 +66,8 @@ void InitializeFlags() {
} // namespace __ubsan
-extern "C" {
-
-#if !SANITIZER_SUPPORTS_WEAK_HOOKS
-SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
-const char *__ubsan_default_options() { return ""; }
-#endif
-
-#if SANITIZER_WINDOWS
-const char *__ubsan_default_default_options() { return ""; }
-# ifdef _WIN64
-# pragma comment(linker, "/alternatename:__ubsan_default_options=__ubsan_default_default_options")
-# else
-# pragma comment(linker, "/alternatename:___ubsan_default_options=___ubsan_default_default_options")
-# endif
-#endif
-
-} // extern "C"
+SANITIZER_INTERFACE_WEAK_DEF(const char *, __ubsan_default_options, void) {
+ return "";
+}
#endif // CAN_SANITIZE_UB
diff --git a/libsanitizer/ubsan/ubsan_handlers.cc b/libsanitizer/ubsan/ubsan_handlers.cc
index 761ccef..4d29832 100644
--- a/libsanitizer/ubsan/ubsan_handlers.cc
+++ b/libsanitizer/ubsan/ubsan_handlers.cc
@@ -36,17 +36,18 @@ bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET) {
const char *TypeCheckKinds[] = {
"load of", "store to", "reference binding to", "member access within",
"member call on", "constructor call on", "downcast of", "downcast of",
- "upcast of", "cast to virtual base of"};
+ "upcast of", "cast to virtual base of", "_Nonnull binding to"};
}
static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
ReportOptions Opts) {
Location Loc = Data->Loc.acquire();
+ uptr Alignment = (uptr)1 << Data->LogAlignment;
ErrorType ET;
if (!Pointer)
ET = ErrorType::NullPointerUse;
- else if (Data->Alignment && (Pointer & (Data->Alignment - 1)))
+ else if (Pointer & (Alignment - 1))
ET = ErrorType::MisalignedPointerUse;
else
ET = ErrorType::InsufficientObjectSize;
@@ -72,8 +73,8 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
case ErrorType::MisalignedPointerUse:
Diag(Loc, DL_Error, "%0 misaligned address %1 for type %3, "
"which requires %2 byte alignment")
- << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer
- << Data->Alignment << Data->Type;
+ << TypeCheckKinds[Data->TypeCheckKind] << (void *)Pointer << Alignment
+ << Data->Type;
break;
case ErrorType::InsufficientObjectSize:
Diag(Loc, DL_Error, "%0 address %1 with insufficient space "
@@ -88,13 +89,13 @@ static void handleTypeMismatchImpl(TypeMismatchData *Data, ValueHandle Pointer,
Diag(Pointer, DL_Note, "pointer points here");
}
-void __ubsan::__ubsan_handle_type_mismatch(TypeMismatchData *Data,
- ValueHandle Pointer) {
+void __ubsan::__ubsan_handle_type_mismatch_v1(TypeMismatchData *Data,
+ ValueHandle Pointer) {
GET_REPORT_OPTIONS(false);
handleTypeMismatchImpl(Data, Pointer, Opts);
}
-void __ubsan::__ubsan_handle_type_mismatch_abort(TypeMismatchData *Data,
- ValueHandle Pointer) {
+void __ubsan::__ubsan_handle_type_mismatch_v1_abort(TypeMismatchData *Data,
+ ValueHandle Pointer) {
GET_REPORT_OPTIONS(true);
handleTypeMismatchImpl(Data, Pointer, Opts);
Die();
@@ -387,7 +388,7 @@ static void handleFloatCastOverflow(void *DataPtr, ValueHandle From,
ScopedReport R(Opts, Loc, ET);
Diag(Loc, DL_Error,
- "value %0 is outside the range of representable values of type %2")
+ "%0 is outside the range of representable values of type %2")
<< Value(*FromType, From) << *FromType << *ToType;
}
@@ -407,7 +408,8 @@ static void handleLoadInvalidValue(InvalidValueData *Data, ValueHandle Val,
SourceLocation Loc = Data->Loc.acquire();
// This check could be more precise if we used different handlers for
// -fsanitize=bool and -fsanitize=enum.
- bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'"));
+ bool IsBool = (0 == internal_strcmp(Data->Type.getTypeName(), "'bool'")) ||
+ (0 == internal_strncmp(Data->Type.getTypeName(), "'BOOL'", 6));
ErrorType ET =
IsBool ? ErrorType::InvalidBoolLoad : ErrorType::InvalidEnumLoad;
@@ -433,6 +435,30 @@ void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data,
Die();
}
+static void handleInvalidBuiltin(InvalidBuiltinData *Data, ReportOptions Opts) {
+ SourceLocation Loc = Data->Loc.acquire();
+ ErrorType ET = ErrorType::InvalidBuiltin;
+
+ if (ignoreReport(Loc, Opts, ET))
+ return;
+
+ ScopedReport R(Opts, Loc, ET);
+
+ Diag(Loc, DL_Error,
+ "passing zero to %0, which is not a valid argument")
+ << ((Data->Kind == BCK_CTZPassedZero) ? "ctz()" : "clz()");
+}
+
+void __ubsan::__ubsan_handle_invalid_builtin(InvalidBuiltinData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleInvalidBuiltin(Data, Opts);
+}
+void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleInvalidBuiltin(Data, Opts);
+ Die();
+}
+
static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
ValueHandle Function,
ReportOptions Opts) {
@@ -469,8 +495,12 @@ void __ubsan::__ubsan_handle_function_type_mismatch_abort(
Die();
}
-static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
- SourceLocation Loc = Data->Loc.acquire();
+static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,
+ ReportOptions Opts, bool IsAttr) {
+ if (!LocPtr)
+ UNREACHABLE("source location pointer is null!");
+
+ SourceLocation Loc = LocPtr->acquire();
ErrorType ET = ErrorType::InvalidNullReturn;
if (ignoreReport(Loc, Opts, ET))
@@ -481,21 +511,39 @@ static void handleNonNullReturn(NonNullReturnData *Data, ReportOptions Opts) {
Diag(Loc, DL_Error, "null pointer returned from function declared to never "
"return null");
if (!Data->AttrLoc.isInvalid())
- Diag(Data->AttrLoc, DL_Note, "returns_nonnull attribute specified here");
+ Diag(Data->AttrLoc, DL_Note, "%0 specified here")
+ << (IsAttr ? "returns_nonnull attribute"
+ : "_Nonnull return type annotation");
+}
+
+void __ubsan::__ubsan_handle_nonnull_return_v1(NonNullReturnData *Data,
+ SourceLocation *LocPtr) {
+ GET_REPORT_OPTIONS(false);
+ handleNonNullReturn(Data, LocPtr, Opts, true);
}
-void __ubsan::__ubsan_handle_nonnull_return(NonNullReturnData *Data) {
+void __ubsan::__ubsan_handle_nonnull_return_v1_abort(NonNullReturnData *Data,
+ SourceLocation *LocPtr) {
+ GET_REPORT_OPTIONS(true);
+ handleNonNullReturn(Data, LocPtr, Opts, true);
+ Die();
+}
+
+void __ubsan::__ubsan_handle_nullability_return_v1(NonNullReturnData *Data,
+ SourceLocation *LocPtr) {
GET_REPORT_OPTIONS(false);
- handleNonNullReturn(Data, Opts);
+ handleNonNullReturn(Data, LocPtr, Opts, false);
}
-void __ubsan::__ubsan_handle_nonnull_return_abort(NonNullReturnData *Data) {
+void __ubsan::__ubsan_handle_nullability_return_v1_abort(
+ NonNullReturnData *Data, SourceLocation *LocPtr) {
GET_REPORT_OPTIONS(true);
- handleNonNullReturn(Data, Opts);
+ handleNonNullReturn(Data, LocPtr, Opts, false);
Die();
}
-static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
+static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts,
+ bool IsAttr) {
SourceLocation Loc = Data->Loc.acquire();
ErrorType ET = ErrorType::InvalidNullArgument;
@@ -504,20 +552,34 @@ static void handleNonNullArg(NonNullArgData *Data, ReportOptions Opts) {
ScopedReport R(Opts, Loc, ET);
- Diag(Loc, DL_Error, "null pointer passed as argument %0, which is declared to "
- "never be null") << Data->ArgIndex;
+ Diag(Loc, DL_Error,
+ "null pointer passed as argument %0, which is declared to "
+ "never be null")
+ << Data->ArgIndex;
if (!Data->AttrLoc.isInvalid())
- Diag(Data->AttrLoc, DL_Note, "nonnull attribute specified here");
+ Diag(Data->AttrLoc, DL_Note, "%0 specified here")
+ << (IsAttr ? "nonnull attribute" : "_Nonnull type annotation");
}
void __ubsan::__ubsan_handle_nonnull_arg(NonNullArgData *Data) {
GET_REPORT_OPTIONS(false);
- handleNonNullArg(Data, Opts);
+ handleNonNullArg(Data, Opts, true);
}
void __ubsan::__ubsan_handle_nonnull_arg_abort(NonNullArgData *Data) {
GET_REPORT_OPTIONS(true);
- handleNonNullArg(Data, Opts);
+ handleNonNullArg(Data, Opts, true);
+ Die();
+}
+
+void __ubsan::__ubsan_handle_nullability_arg(NonNullArgData *Data) {
+ GET_REPORT_OPTIONS(false);
+ handleNonNullArg(Data, Opts, false);
+}
+
+void __ubsan::__ubsan_handle_nullability_arg_abort(NonNullArgData *Data) {
+ GET_REPORT_OPTIONS(true);
+ handleNonNullArg(Data, Opts, false);
Die();
}
@@ -533,8 +595,19 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data,
ScopedReport R(Opts, Loc, ET);
- Diag(Loc, DL_Error, "pointer index expression with base %0 overflowed to %1")
- << (void *)Base << (void*)Result;
+ if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) {
+ if (Base > Result)
+ Diag(Loc, DL_Error, "addition of unsigned offset to %0 overflowed to %1")
+ << (void *)Base << (void *)Result;
+ else
+ Diag(Loc, DL_Error,
+ "subtraction of unsigned offset from %0 overflowed to %1")
+ << (void *)Base << (void *)Result;
+ } else {
+ Diag(Loc, DL_Error,
+ "pointer index expression with base %0 overflowed to %1")
+ << (void *)Base << (void *)Result;
+ }
}
void __ubsan::__ubsan_handle_pointer_overflow(PointerOverflowData *Data,
@@ -577,32 +650,33 @@ static void handleCFIBadIcall(CFICheckFailData *Data, ValueHandle Function,
}
namespace __ubsan {
+
#ifdef UBSAN_CAN_USE_CXXABI
-SANITIZER_WEAK_ATTRIBUTE
-void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
- bool ValidVtable, ReportOptions Opts);
-#else
-static void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
- bool ValidVtable, ReportOptions Opts) {
+
+#ifdef _WIN32
+
+extern "C" void __ubsan_handle_cfi_bad_type_default(CFICheckFailData *Data,
+ ValueHandle Vtable,
+ bool ValidVtable,
+ ReportOptions Opts) {
Die();
}
-#endif
-} // namespace __ubsan
-void __ubsan::__ubsan_handle_cfi_bad_icall(CFIBadIcallData *CallData,
- ValueHandle Function) {
- GET_REPORT_OPTIONS(false);
- CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
- handleCFIBadIcall(&Data, Function, Opts);
-}
+WIN_WEAK_ALIAS(__ubsan_handle_cfi_bad_type, __ubsan_handle_cfi_bad_type_default)
+#else
+SANITIZER_WEAK_ATTRIBUTE
+#endif
+void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
+ bool ValidVtable, ReportOptions Opts);
-void __ubsan::__ubsan_handle_cfi_bad_icall_abort(CFIBadIcallData *CallData,
- ValueHandle Function) {
- GET_REPORT_OPTIONS(true);
- CFICheckFailData Data = {CFITCK_ICall, CallData->Loc, CallData->Type};
- handleCFIBadIcall(&Data, Function, Opts);
+#else
+void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
+ bool ValidVtable, ReportOptions Opts) {
Die();
}
+#endif
+
+} // namespace __ubsan
void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
ValueHandle Value,
@@ -611,7 +685,7 @@ void __ubsan::__ubsan_handle_cfi_check_fail(CFICheckFailData *Data,
if (Data->CheckKind == CFITCK_ICall)
handleCFIBadIcall(Data, Value, Opts);
else
- HandleCFIBadType(Data, Value, ValidVtable, Opts);
+ __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);
}
void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,
@@ -621,7 +695,7 @@ void __ubsan::__ubsan_handle_cfi_check_fail_abort(CFICheckFailData *Data,
if (Data->CheckKind == CFITCK_ICall)
handleCFIBadIcall(Data, Value, Opts);
else
- HandleCFIBadType(Data, Value, ValidVtable, Opts);
+ __ubsan_handle_cfi_bad_type(Data, Value, ValidVtable, Opts);
Die();
}
diff --git a/libsanitizer/ubsan/ubsan_handlers.h b/libsanitizer/ubsan/ubsan_handlers.h
index d04554a..c5e499c 100644
--- a/libsanitizer/ubsan/ubsan_handlers.h
+++ b/libsanitizer/ubsan/ubsan_handlers.h
@@ -18,7 +18,7 @@ namespace __ubsan {
struct TypeMismatchData {
SourceLocation Loc;
const TypeDescriptor &Type;
- uptr Alignment;
+ unsigned char LogAlignment;
unsigned char TypeCheckKind;
};
@@ -35,7 +35,7 @@ struct TypeMismatchData {
/// \brief Handle a runtime type check failure, caused by either a misaligned
/// pointer, a null pointer, or a pointer to insufficient storage for the
/// type.
-RECOVERABLE(type_mismatch, TypeMismatchData *Data, ValueHandle Pointer)
+RECOVERABLE(type_mismatch_v1, TypeMismatchData *Data, ValueHandle Pointer)
struct OverflowData {
SourceLocation Loc;
@@ -120,6 +120,21 @@ struct InvalidValueData {
/// \brief Handle a load of an invalid value for the type.
RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val)
+/// Known builtin check kinds.
+/// Keep in sync with the enum of the same name in CodeGenFunction.h
+enum BuiltinCheckKind : unsigned char {
+ BCK_CTZPassedZero,
+ BCK_CLZPassedZero,
+};
+
+struct InvalidBuiltinData {
+ SourceLocation Loc;
+ unsigned char Kind;
+};
+
+/// Handle a builtin called in an invalid way.
+RECOVERABLE(invalid_builtin, InvalidBuiltinData *Data)
+
struct FunctionTypeMismatchData {
SourceLocation Loc;
const TypeDescriptor &Type;
@@ -130,12 +145,13 @@ RECOVERABLE(function_type_mismatch,
ValueHandle Val)
struct NonNullReturnData {
- SourceLocation Loc;
SourceLocation AttrLoc;
};
-/// \brief Handle returning null from function with returns_nonnull attribute.
-RECOVERABLE(nonnull_return, NonNullReturnData *Data)
+/// \brief Handle returning null from function with the returns_nonnull
+/// attribute, or a return type annotated with _Nonnull.
+RECOVERABLE(nonnull_return_v1, NonNullReturnData *Data, SourceLocation *Loc)
+RECOVERABLE(nullability_return_v1, NonNullReturnData *Data, SourceLocation *Loc)
struct NonNullArgData {
SourceLocation Loc;
@@ -143,8 +159,10 @@ struct NonNullArgData {
int ArgIndex;
};
-/// \brief Handle passing null pointer to function with nonnull attribute.
+/// \brief Handle passing null pointer to a function parameter with the nonnull
+/// attribute, or a _Nonnull type annotation.
RECOVERABLE(nonnull_arg, NonNullArgData *Data)
+RECOVERABLE(nullability_arg, NonNullArgData *Data)
struct PointerOverflowData {
SourceLocation Loc;
@@ -163,23 +181,22 @@ enum CFITypeCheckKind : unsigned char {
CFITCK_ICall,
};
-struct CFIBadIcallData {
- SourceLocation Loc;
- const TypeDescriptor &Type;
-};
-
struct CFICheckFailData {
CFITypeCheckKind CheckKind;
SourceLocation Loc;
const TypeDescriptor &Type;
};
-/// \brief Handle control flow integrity failure for indirect function calls.
-RECOVERABLE(cfi_bad_icall, CFIBadIcallData *Data, ValueHandle Function)
-
/// \brief Handle control flow integrity failures.
RECOVERABLE(cfi_check_fail, CFICheckFailData *Data, ValueHandle Function,
uptr VtableIsValid)
+
+struct ReportOptions;
+
+extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __ubsan_handle_cfi_bad_type(
+ CFICheckFailData *Data, ValueHandle Vtable, bool ValidVtable,
+ ReportOptions Opts);
+
}
#endif // UBSAN_HANDLERS_H
diff --git a/libsanitizer/ubsan/ubsan_handlers_cxx.cc b/libsanitizer/ubsan/ubsan_handlers_cxx.cc
index 007a1d6..bf729db 100644
--- a/libsanitizer/ubsan/ubsan_handlers_cxx.cc
+++ b/libsanitizer/ubsan/ubsan_handlers_cxx.cc
@@ -93,8 +93,8 @@ void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
}
namespace __ubsan {
-void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
- bool ValidVtable, ReportOptions Opts) {
+void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
+ bool ValidVtable, ReportOptions Opts) {
SourceLocation Loc = Data->Loc.acquire();
ErrorType ET = ErrorType::CFIBadType;
@@ -121,6 +121,7 @@ void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
CheckKindStr = "cast to unrelated type";
break;
case CFITCK_ICall:
+ default:
Die();
}
@@ -142,22 +143,4 @@ void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
}
} // namespace __ubsan
-void __ubsan::__ubsan_handle_cfi_bad_type(CFIBadTypeData *TypeData,
- ValueHandle Vtable) {
- GET_REPORT_OPTIONS(false);
- CFITypeCheckKind TypeCheckKind
- = static_cast<CFITypeCheckKind> (TypeData->TypeCheckKind);
- CFICheckFailData Data = {TypeCheckKind, TypeData->Loc, TypeData->Type};
- HandleCFIBadType(&Data, Vtable, false, Opts);
-}
-
-void __ubsan::__ubsan_handle_cfi_bad_type_abort(CFIBadTypeData *TypeData,
- ValueHandle Vtable) {
- GET_REPORT_OPTIONS(true);
- CFITypeCheckKind TypeCheckKind
- = static_cast<CFITypeCheckKind> (TypeData->TypeCheckKind);
- CFICheckFailData Data = {TypeCheckKind, TypeData->Loc, TypeData->Type};
- HandleCFIBadType(&Data, Vtable, false, Opts);
-}
-
#endif // CAN_SANITIZE_UB
diff --git a/libsanitizer/ubsan/ubsan_handlers_cxx.h b/libsanitizer/ubsan/ubsan_handlers_cxx.h
index 6ace2b3..3738235 100644
--- a/libsanitizer/ubsan/ubsan_handlers_cxx.h
+++ b/libsanitizer/ubsan/ubsan_handlers_cxx.h
@@ -23,12 +23,6 @@ struct DynamicTypeCacheMissData {
unsigned char TypeCheckKind;
};
-struct CFIBadTypeData {
- SourceLocation Loc;
- const TypeDescriptor &Type;
- unsigned char TypeCheckKind;
-};
-
/// \brief Handle a runtime type check failure, caused by an incorrect vptr.
/// When this handler is called, all we know is that the type was not in the
/// cache; this does not necessarily imply the existence of a bug.
@@ -38,13 +32,6 @@ void __ubsan_handle_dynamic_type_cache_miss(
extern "C" SANITIZER_INTERFACE_ATTRIBUTE
void __ubsan_handle_dynamic_type_cache_miss_abort(
DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash);
-
-/// \brief Handle a control flow integrity check failure by printing a
-/// diagnostic.
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
-__ubsan_handle_cfi_bad_type(CFIBadTypeData *Data, ValueHandle Vtable);
-extern "C" SANITIZER_INTERFACE_ATTRIBUTE void
-__ubsan_handle_cfi_bad_type_abort(CFIBadTypeData *Data, ValueHandle Vtable);
}
#endif // UBSAN_HANDLERS_H
diff --git a/libsanitizer/ubsan/ubsan_init.cc b/libsanitizer/ubsan/ubsan_init.cc
index 07f7481..9ae17f5 100644
--- a/libsanitizer/ubsan/ubsan_init.cc
+++ b/libsanitizer/ubsan/ubsan_init.cc
@@ -21,11 +21,11 @@
using namespace __ubsan;
-static enum {
- UBSAN_MODE_UNKNOWN = 0,
- UBSAN_MODE_STANDALONE,
- UBSAN_MODE_PLUGIN
-} ubsan_mode;
+const char *__ubsan::GetSanititizerToolName() {
+ return "UndefinedBehaviorSanitizer";
+}
+
+static bool ubsan_initialized;
static StaticSpinMutex ubsan_init_mu;
static void CommonInit() {
@@ -33,45 +33,31 @@ static void CommonInit() {
}
static void CommonStandaloneInit() {
- SanitizerToolName = "UndefinedBehaviorSanitizer";
- InitializeFlags();
+ SanitizerToolName = GetSanititizerToolName();
CacheBinaryName();
+ InitializeFlags();
__sanitizer_set_report_path(common_flags()->log_path);
AndroidLogInit();
InitializeCoverage(common_flags()->coverage, common_flags()->coverage_dir);
CommonInit();
- ubsan_mode = UBSAN_MODE_STANDALONE;
}
void __ubsan::InitAsStandalone() {
- if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
- CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode);
- CommonStandaloneInit();
- return;
- }
SpinMutexLock l(&ubsan_init_mu);
- CHECK_NE(UBSAN_MODE_PLUGIN, ubsan_mode);
- if (ubsan_mode == UBSAN_MODE_UNKNOWN)
+ if (!ubsan_initialized) {
CommonStandaloneInit();
-}
-
-void __ubsan::InitAsStandaloneIfNecessary() {
- if (SANITIZER_CAN_USE_PREINIT_ARRAY) {
- CHECK_NE(UBSAN_MODE_UNKNOWN, ubsan_mode);
- return;
+ ubsan_initialized = true;
}
- SpinMutexLock l(&ubsan_init_mu);
- if (ubsan_mode == UBSAN_MODE_UNKNOWN)
- CommonStandaloneInit();
}
+void __ubsan::InitAsStandaloneIfNecessary() { return InitAsStandalone(); }
+
void __ubsan::InitAsPlugin() {
-#if !SANITIZER_CAN_USE_PREINIT_ARRAY
SpinMutexLock l(&ubsan_init_mu);
-#endif
- CHECK_EQ(UBSAN_MODE_UNKNOWN, ubsan_mode);
- CommonInit();
- ubsan_mode = UBSAN_MODE_PLUGIN;
+ if (!ubsan_initialized) {
+ CommonInit();
+ ubsan_initialized = true;
+ }
}
#endif // CAN_SANITIZE_UB
diff --git a/libsanitizer/ubsan/ubsan_init.h b/libsanitizer/ubsan/ubsan_init.h
index 6a8366f..73bd3f3 100644
--- a/libsanitizer/ubsan/ubsan_init.h
+++ b/libsanitizer/ubsan/ubsan_init.h
@@ -13,6 +13,9 @@
namespace __ubsan {
+// Get the full tool name for UBSan.
+const char *GetSanititizerToolName();
+
// Initialize UBSan as a standalone tool. Typically should be called early
// during initialization.
void InitAsStandalone();
diff --git a/libsanitizer/ubsan/ubsan_init_standalone.cc b/libsanitizer/ubsan/ubsan_init_standalone.cc
index 1630fd7..67223be 100644
--- a/libsanitizer/ubsan/ubsan_init_standalone.cc
+++ b/libsanitizer/ubsan/ubsan_init_standalone.cc
@@ -16,17 +16,17 @@
#include "sanitizer_common/sanitizer_internal_defs.h"
#include "ubsan_init.h"
+#include "ubsan_signals_standalone.h"
+
+namespace __ubsan {
-#if SANITIZER_CAN_USE_PREINIT_ARRAY
-__attribute__((section(".preinit_array"), used))
-void (*__local_ubsan_preinit)(void) = __ubsan::InitAsStandalone;
-#else
-// Use a dynamic initializer.
class UbsanStandaloneInitializer {
public:
UbsanStandaloneInitializer() {
- __ubsan::InitAsStandalone();
+ InitAsStandalone();
+ InitializeDeadlySignals();
}
};
static UbsanStandaloneInitializer ubsan_standalone_initializer;
-#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
+
+} // namespace __ubsan
diff --git a/libsanitizer/ubsan/ubsan_init_standalone_preinit.cc b/libsanitizer/ubsan/ubsan_init_standalone_preinit.cc
new file mode 100644
index 0000000..80b2f3c
--- /dev/null
+++ b/libsanitizer/ubsan/ubsan_init_standalone_preinit.cc
@@ -0,0 +1,35 @@
+//===-- ubsan_init_standalone_preinit.cc
+//------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Initialization of standalone UBSan runtime.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_platform.h"
+#if !CAN_SANITIZE_UB
+#error "UBSan is not supported on this platform!"
+#endif
+
+#include "sanitizer_common/sanitizer_internal_defs.h"
+#include "ubsan_init.h"
+#include "ubsan_signals_standalone.h"
+
+#if SANITIZER_CAN_USE_PREINIT_ARRAY
+
+namespace __ubsan {
+
+static void PreInitAsStandalone() {
+ InitAsStandalone();
+ InitializeDeadlySignals();
+}
+
+} // namespace __ubsan
+
+__attribute__((section(".preinit_array"), used)) void (*__local_ubsan_preinit)(
+ void) = __ubsan::PreInitAsStandalone;
+#endif // SANITIZER_CAN_USE_PREINIT_ARRAY
diff --git a/libsanitizer/ubsan/ubsan_interface.inc b/libsanitizer/ubsan/ubsan_interface.inc
new file mode 100644
index 0000000..1b0bc425
--- /dev/null
+++ b/libsanitizer/ubsan/ubsan_interface.inc
@@ -0,0 +1,52 @@
+//===-- ubsan_interface.inc -----------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// Ubsan interface list.
+//===----------------------------------------------------------------------===//
+INTERFACE_FUNCTION(__ubsan_handle_add_overflow)
+INTERFACE_FUNCTION(__ubsan_handle_add_overflow_abort)
+INTERFACE_FUNCTION(__ubsan_handle_builtin_unreachable)
+INTERFACE_FUNCTION(__ubsan_handle_cfi_bad_type)
+INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail)
+INTERFACE_FUNCTION(__ubsan_handle_cfi_check_fail_abort)
+INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow)
+INTERFACE_FUNCTION(__ubsan_handle_divrem_overflow_abort)
+INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss)
+INTERFACE_FUNCTION(__ubsan_handle_dynamic_type_cache_miss_abort)
+INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow)
+INTERFACE_FUNCTION(__ubsan_handle_float_cast_overflow_abort)
+INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch)
+INTERFACE_FUNCTION(__ubsan_handle_function_type_mismatch_abort)
+INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin)
+INTERFACE_FUNCTION(__ubsan_handle_invalid_builtin_abort)
+INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value)
+INTERFACE_FUNCTION(__ubsan_handle_load_invalid_value_abort)
+INTERFACE_FUNCTION(__ubsan_handle_missing_return)
+INTERFACE_FUNCTION(__ubsan_handle_mul_overflow)
+INTERFACE_FUNCTION(__ubsan_handle_mul_overflow_abort)
+INTERFACE_FUNCTION(__ubsan_handle_negate_overflow)
+INTERFACE_FUNCTION(__ubsan_handle_negate_overflow_abort)
+INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg)
+INTERFACE_FUNCTION(__ubsan_handle_nonnull_arg_abort)
+INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_v1)
+INTERFACE_FUNCTION(__ubsan_handle_nonnull_return_v1_abort)
+INTERFACE_FUNCTION(__ubsan_handle_nullability_arg)
+INTERFACE_FUNCTION(__ubsan_handle_nullability_arg_abort)
+INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1)
+INTERFACE_FUNCTION(__ubsan_handle_nullability_return_v1_abort)
+INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds)
+INTERFACE_FUNCTION(__ubsan_handle_out_of_bounds_abort)
+INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow)
+INTERFACE_FUNCTION(__ubsan_handle_pointer_overflow_abort)
+INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds)
+INTERFACE_FUNCTION(__ubsan_handle_shift_out_of_bounds_abort)
+INTERFACE_FUNCTION(__ubsan_handle_sub_overflow)
+INTERFACE_FUNCTION(__ubsan_handle_sub_overflow_abort)
+INTERFACE_FUNCTION(__ubsan_handle_type_mismatch_v1)
+INTERFACE_FUNCTION(__ubsan_handle_type_mismatch_v1_abort)
+INTERFACE_FUNCTION(__ubsan_handle_vla_bound_not_positive)
+INTERFACE_FUNCTION(__ubsan_handle_vla_bound_not_positive_abort)
+INTERFACE_WEAK_FUNCTION(__ubsan_default_options)
diff --git a/libsanitizer/ubsan/ubsan_platform.h b/libsanitizer/ubsan/ubsan_platform.h
index fa4e1a1..e73df63 100644
--- a/libsanitizer/ubsan/ubsan_platform.h
+++ b/libsanitizer/ubsan/ubsan_platform.h
@@ -13,12 +13,13 @@
#ifndef CAN_SANITIZE_UB
// Other platforms should be easy to add, and probably work as-is.
-#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__)) && \
- (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \
- defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__) || \
+#if (defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \
+ defined(__NetBSD__)) && \
+ (defined(__x86_64__) || defined(__i386__) || defined(__arm__) || \
+ defined(__aarch64__) || defined(__mips__) || defined(__powerpc64__) || \
defined(__s390__))
# define CAN_SANITIZE_UB 1
-#elif defined(_WIN32)
+#elif defined(_WIN32) || defined(__Fuchsia__)
# define CAN_SANITIZE_UB 1
#else
# define CAN_SANITIZE_UB 0
diff --git a/libsanitizer/ubsan/ubsan_signals_standalone.cc b/libsanitizer/ubsan/ubsan_signals_standalone.cc
new file mode 100644
index 0000000..eb9b99c
--- /dev/null
+++ b/libsanitizer/ubsan/ubsan_signals_standalone.cc
@@ -0,0 +1,52 @@
+//=-- ubsan_signals_standalone.cc
+//------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Installs signal handlers and related interceptors for UBSan standalone.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ubsan_platform.h"
+#if CAN_SANITIZE_UB
+#include "interception/interception.h"
+#include "sanitizer_common/sanitizer_stacktrace.h"
+#include "ubsan_diag.h"
+#include "ubsan_init.h"
+
+#define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name)
+#include "sanitizer_common/sanitizer_signal_interceptors.inc"
+
+namespace __ubsan {
+
+#if SANITIZER_FUCHSIA
+void InitializeDeadlySignals() {}
+#else
+static void OnStackUnwind(const SignalContext &sig, const void *,
+ BufferedStackTrace *stack) {
+ GetStackTraceWithPcBpAndContext(stack, kStackTraceMax, sig.pc, sig.bp,
+ sig.context,
+ common_flags()->fast_unwind_on_fatal);
+}
+
+static void UBsanOnDeadlySignal(int signo, void *siginfo, void *context) {
+ HandleDeadlySignal(siginfo, context, GetTid(), &OnStackUnwind, nullptr);
+}
+
+static bool is_initialized = false;
+
+void InitializeDeadlySignals() {
+ if (is_initialized)
+ return;
+ is_initialized = true;
+ InitializeSignalInterceptors();
+ InstallDeadlySignalHandlers(&UBsanOnDeadlySignal);
+}
+#endif
+
+} // namespace __ubsan
+
+#endif // CAN_SANITIZE_UB
diff --git a/libsanitizer/ubsan/ubsan_signals_standalone.h b/libsanitizer/ubsan/ubsan_signals_standalone.h
new file mode 100644
index 0000000..65e64f2
--- /dev/null
+++ b/libsanitizer/ubsan/ubsan_signals_standalone.h
@@ -0,0 +1,23 @@
+//=-- ubsan_signals_standalone.h
+//------------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Installs signal handlers and related interceptors for UBSan standalone.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef UBSAN_SIGNALS_STANDALONE_H
+#define UBSAN_SIGNALS_STANDALONE_H
+
+namespace __ubsan {
+
+// Initializes signal handlers and interceptors.
+void InitializeDeadlySignals();
+
+} // namespace __ubsan
+
+#endif // UBSAN_SIGNALS_STANDALONE_H
diff --git a/libsanitizer/ubsan/ubsan_type_hash_itanium.cc b/libsanitizer/ubsan/ubsan_type_hash_itanium.cc
index 790b126..9df316e 100644
--- a/libsanitizer/ubsan/ubsan_type_hash_itanium.cc
+++ b/libsanitizer/ubsan/ubsan_type_hash_itanium.cc
@@ -195,9 +195,9 @@ struct VtablePrefix {
};
VtablePrefix *getVtablePrefix(void *Vtable) {
VtablePrefix *Vptr = reinterpret_cast<VtablePrefix*>(Vtable);
- if (!Vptr)
- return nullptr;
VtablePrefix *Prefix = Vptr - 1;
+ if (!IsAccessibleMemoryRange((uptr)Prefix, sizeof(VtablePrefix)))
+ return nullptr;
if (!Prefix->TypeInfo)
// This can't possibly be a valid vtable.
return nullptr;
diff --git a/libsanitizer/ubsan/ubsan_win_dll_thunk.cc b/libsanitizer/ubsan/ubsan_win_dll_thunk.cc
new file mode 100644
index 0000000..1091ac0
--- /dev/null
+++ b/libsanitizer/ubsan/ubsan_win_dll_thunk.cc
@@ -0,0 +1,19 @@
+//===-- ubsan_win_dll_thunk.cc --------------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines a family of thunks that should be statically linked into
+// the DLLs that have instrumentation in order to delegate the calls to the
+// shared runtime that lives in the main binary.
+// See https://github.com/google/sanitizers/issues/209 for the details.
+//===----------------------------------------------------------------------===//
+#ifdef SANITIZER_DLL_THUNK
+#include "sanitizer_common/sanitizer_win_dll_thunk.h"
+// Ubsan interface functions.
+#define INTERFACE_FUNCTION(Name) INTERCEPT_SANITIZER_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
+#include "ubsan_interface.inc"
+#endif // SANITIZER_DLL_THUNK
diff --git a/libsanitizer/ubsan/ubsan_win_dynamic_runtime_thunk.cc b/libsanitizer/ubsan/ubsan_win_dynamic_runtime_thunk.cc
new file mode 100644
index 0000000..6ab5ae3
--- /dev/null
+++ b/libsanitizer/ubsan/ubsan_win_dynamic_runtime_thunk.cc
@@ -0,0 +1,19 @@
+//===-- ubsan_win_dynamic_runtime_thunk.cc --------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines things that need to be present in the application modules
+// to interact with Ubsan, when it is included in a dll.
+//
+//===----------------------------------------------------------------------===//
+#ifdef SANITIZER_DYNAMIC_RUNTIME_THUNK
+#define SANITIZER_IMPORT_INTERFACE 1
+#include "sanitizer_common/sanitizer_win_defs.h"
+// Define weak alias for all weak functions imported from ubsan.
+#define INTERFACE_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) WIN_WEAK_IMPORT_DEF(Name)
+#include "ubsan_interface.inc"
+#endif // SANITIZER_DYNAMIC_RUNTIME_THUNK
diff --git a/libsanitizer/ubsan/ubsan_win_weak_interception.cc b/libsanitizer/ubsan/ubsan_win_weak_interception.cc
new file mode 100644
index 0000000..98c8c27
--- /dev/null
+++ b/libsanitizer/ubsan/ubsan_win_weak_interception.cc
@@ -0,0 +1,21 @@
+//===-- ubsan_win_weak_interception.cc ------------------------------------===//
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+// This module should be included in Ubsan when it is implemented as a shared
+// library on Windows (dll), in order to delegate the calls of weak functions to
+// the implementation in the main executable when a strong definition is
+// provided.
+//===----------------------------------------------------------------------===//
+#ifdef SANITIZER_DYNAMIC
+#include "sanitizer_common/sanitizer_win_weak_interception.h"
+#include "ubsan_flags.h"
+// Check if strong definitions for weak functions are present in the main
+// executable. If that is the case, override dll functions to point to strong
+// implementations.
+#define INTERFACE_FUNCTION(Name)
+#define INTERFACE_WEAK_FUNCTION(Name) INTERCEPT_SANITIZER_WEAK_FUNCTION(Name)
+#include "ubsan_interface.inc"
+#endif // SANITIZER_DYNAMIC
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index f9424a5..e00eabe 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -1,3 +1,350 @@
+2017-10-24 Jonathan Wakely <jwakely@redhat.com>
+
+ * config/locale/gnu/c_locale.cc [_GLIBCXX_LONG_DOUBLE_COMPAT]: Ignore
+ -Wattribute-alias warnings.
+ * src/c++11/istream-inst.cc: Likewise.
+ * src/c++11/locale-inst.cc: Likewise.
+ * src/c++11/ostream-inst.cc: Likewise.
+ * src/c++11/wlocale-inst.cc: Likewise.
+ * src/c++98/hash-long-double-tr1-aux.cc: Likewise.
+
+ * include/bits/string_view.tcc (find_first_of, find_last_of)
+ (find_first_not_of, find_last_not_of): Add noexcept.
+ * include/std/string_view (basic_string_view(const _CharT*))
+ (basic_string_view(const _CharT*, size_type))
+ (front, back, remove_prefix, remove_suffix, find, rfind)
+ (find_first_of, find_first_not_of): Add noexcept.
+ (at(size_type), _S_compare(size_type, size_type)): Replace conditional
+ expressions with if statements.
+ (copy(_CharT*, size_type, size_type), substr(size_type, size_type)):
+ Use _M_check for length checks.
+ (compare(basic_string_view)): Reformat.
+ (_M_check(size_type, const char)): Add noexcept(false).
+ (_M_limit(size_type, size_type)): Use noexcept not _GLIBCXX_NOEXCEPT.
+
+ PR libstdc++/82685
+ * include/experimental/string_view (operator""sv): Add noexcept.
+ * include/std/string_view (operator""sv): Likewise.
+
+2017-10-23 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/Makefile.am: Add new headers for C++17 filesystem library.
+ * include/Makefile.in: Regenerate.
+ * include/bits/fs_dir.h: New header, based on Filesystem TS code in
+ include/experimental/bits directory.
+ * include/bits/fs_fwd.h: Likewise.
+ * include/bits/fs_ops.h: Likewise.
+ * include/bits/fs_path.h: Likewise.
+ * include/experimental/bits/fs_dir.h: Rename Doxygen group.
+ * include/experimental/bits/fs_fwd.h: Likewise.
+ * include/experimental/bits/fs_ops.h: Likewise.
+ * include/experimental/bits/fs_path.h: Likewise.
+ * include/experimental/filesystem (filesystem_error::_M_gen_what):
+ Remove inline definition.
+ * include/precompiled/stdc++.h: Add <filesystem> to precompiled
+ header.
+ * include/std/filesystem: New header.
+ * python/libstdcxx/v6/printers.py: Enable printer for std::filesystem
+ paths.
+ * src/filesystem/Makefile.am: Add new files. Compile as C++17.
+ * src/filesystem/Makefile.in: Regenerate.
+ * src/filesystem/cow-dir.cc: Update comment.
+ * src/filesystem/cow-ops.cc: Likewise.
+ * src/filesystem/cow-path.cc: Likewise.
+ * src/filesystem/cow-std-dir.cc: New file.
+ * src/filesystem/cow-std-ops.cc: New file.
+ * src/filesystem/cow-std-path.cc: New file.
+ * src/filesystem/dir-common.h (_Dir_base, get_file_type): New header
+ for common code.
+ * src/filesystem/dir.cc (_Dir): Derive from _Dir_base.
+ (open_dir): Move to _Dir_base constructor.
+ (get_file_type): Move to dir-common.h.
+ (recurse): Move to _Dir_base::should_recurse.
+ * src/filesystem/ops-common.h: New header for common code.
+ * src/filesystem/ops.cc (is_set, make_file_type, make_file_status)
+ (is_not_found_errno, file_time, do_copy_file): Move to ops-common.h.
+ * src/filesystem/path.cc (filesystem_error::_M_gen_what): Define.
+ * src/filesystem/std-dir.cc: New file, based on Filesystem TS code.
+ * src/filesystem/std-ops.cc: Likewise.
+ * src/filesystem/std-dir.cc: Likewise.
+ * testsuite/27_io/filesystem/iterators/directory_iterator.cc: New
+ test.
+ * testsuite/27_io/filesystem/iterators/pop.cc: New test.
+ * testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc:
+ New test.
+ * testsuite/27_io/filesystem/operations/absolute.cc: New test.
+ * testsuite/27_io/filesystem/operations/canonical.cc: New test.
+ * testsuite/27_io/filesystem/operations/copy.cc: New test.
+ * testsuite/27_io/filesystem/operations/copy_file.cc: New test.
+ * testsuite/27_io/filesystem/operations/create_directories.cc: New
+ test.
+ * testsuite/27_io/filesystem/operations/create_directory.cc: New test.
+ * testsuite/27_io/filesystem/operations/create_symlink.cc: New test.
+ * testsuite/27_io/filesystem/operations/current_path.cc: New test.
+ * testsuite/27_io/filesystem/operations/equivalent.cc: New test.
+ * testsuite/27_io/filesystem/operations/exists.cc: New test.
+ * testsuite/27_io/filesystem/operations/file_size.cc: New test.
+ * testsuite/27_io/filesystem/operations/is_empty.cc: New test.
+ * testsuite/27_io/filesystem/operations/last_write_time.cc: New test.
+ * testsuite/27_io/filesystem/operations/permissions.cc: New test.
+ * testsuite/27_io/filesystem/operations/proximate.cc: New test.
+ * testsuite/27_io/filesystem/operations/read_symlink.cc: New test.
+ * testsuite/27_io/filesystem/operations/relative.cc: New test.
+ * testsuite/27_io/filesystem/operations/remove_all.cc: New test.
+ * testsuite/27_io/filesystem/operations/space.cc: New test.
+ * testsuite/27_io/filesystem/operations/status.cc: New test.
+ * testsuite/27_io/filesystem/operations/symlink_status.cc: New test.
+ * testsuite/27_io/filesystem/operations/temp_directory_path.cc: New
+ test.
+ * testsuite/27_io/filesystem/operations/weakly_canonical.cc: New test.
+ * testsuite/27_io/filesystem/path/append/path.cc: New test.
+ * testsuite/27_io/filesystem/path/assign/assign.cc: New test.
+ * testsuite/27_io/filesystem/path/assign/copy.cc: New test.
+ * testsuite/27_io/filesystem/path/compare/compare.cc: New test.
+ * testsuite/27_io/filesystem/path/compare/path.cc: New test.
+ * testsuite/27_io/filesystem/path/compare/strings.cc: New test.
+ * testsuite/27_io/filesystem/path/concat/path.cc: New test.
+ * testsuite/27_io/filesystem/path/concat/strings.cc: New test.
+ * testsuite/27_io/filesystem/path/construct/copy.cc: New test.
+ * testsuite/27_io/filesystem/path/construct/default.cc: New test.
+ * testsuite/27_io/filesystem/path/construct/locale.cc: New test.
+ * testsuite/27_io/filesystem/path/construct/range.cc: New test.
+ * testsuite/27_io/filesystem/path/construct/string_view.cc: New test.
+ * testsuite/27_io/filesystem/path/decompose/extension.cc: New test.
+ * testsuite/27_io/filesystem/path/decompose/filename.cc: New test.
+ * testsuite/27_io/filesystem/path/decompose/parent_path.cc: New test.
+ * testsuite/27_io/filesystem/path/decompose/relative_path.cc: New
+ test.
+ * testsuite/27_io/filesystem/path/decompose/root_directory.cc: New
+ test.
+ * testsuite/27_io/filesystem/path/decompose/root_name.cc: New test.
+ * testsuite/27_io/filesystem/path/decompose/root_path.cc: New test.
+ * testsuite/27_io/filesystem/path/decompose/stem.cc: New test.
+ * testsuite/27_io/filesystem/path/generation/normal.cc: New test.
+ * testsuite/27_io/filesystem/path/generation/proximate.cc: New test.
+ * testsuite/27_io/filesystem/path/generation/relative.cc: New test.
+ * testsuite/27_io/filesystem/path/generic/generic_string.cc: New test.
+ * testsuite/27_io/filesystem/path/itr/traversal.cc: New test.
+ * testsuite/27_io/filesystem/path/modifiers/clear.cc: New test.
+ * testsuite/27_io/filesystem/path/modifiers/make_preferred.cc: New
+ test.
+ * testsuite/27_io/filesystem/path/modifiers/remove_filename.cc: New
+ test.
+ * testsuite/27_io/filesystem/path/modifiers/replace_extension.cc: New
+ test.
+ * testsuite/27_io/filesystem/path/modifiers/replace_filename.cc: New
+ test.
+ * testsuite/27_io/filesystem/path/modifiers/swap.cc: New test.
+ * testsuite/27_io/filesystem/path/native/string.cc: New test.
+ * testsuite/27_io/filesystem/path/nonmember/hash_value.cc: New test.
+ * testsuite/27_io/filesystem/path/query/empty.cc: New test.
+ * testsuite/27_io/filesystem/path/query/has_extension.cc: New test.
+ * testsuite/27_io/filesystem/path/query/has_filename.cc: New test.
+ * testsuite/27_io/filesystem/path/query/has_parent_path.cc: New test.
+ * testsuite/27_io/filesystem/path/query/has_relative_path.cc: New
+ test.
+ * testsuite/27_io/filesystem/path/query/has_root_directory.cc: New
+ test.
+ * testsuite/27_io/filesystem/path/query/has_root_name.cc: New test.
+ * testsuite/27_io/filesystem/path/query/has_root_path.cc: New test.
+ * testsuite/27_io/filesystem/path/query/has_stem.cc: New test.
+ * testsuite/27_io/filesystem/path/query/is_relative.cc: New test.
+ * testsuite/experimental/filesystem/path/construct/string_view.cc:
+ Define USE_FILESYSTEM_TS.
+ * testsuite/util/testsuite_fs.h: Allow use with C++17 paths as well
+ as Filesystem TS.
+
+ PR libstdc++/82644
+ * doc/xml/manual/intro.xml: Include new section.
+ * doc/xml/manual/status_cxxis29124.xml: New section on IS 29124
+ status.
+ * include/bits/specfun.h [__STRICT_ANSI__] (hyperg, hypergf, hypergl)
+ (conf_hyperg, conf_hypergf, conf_hypergl): Don't declare.
+ * include/c_compatibility/math.h: Import special functions into
+ global namespace for C++17.
+ * testsuite/26_numerics/headers/cmath/82644.cc: New test.
+ * testsuite/26_numerics/headers/cmath/functions_global_c++17.cc: New
+ test.
+
+2017-10-21 Jonathan Wakely <jwakely@redhat.com>
+
+ * testsuite/experimental/filesystem/path/itr/traversal.cc: Do not
+ increment past-the-end iterators.
+
+2017-10-20 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/std/chrono (__cpp_lib_chrono): Update macro value to
+ indicate support for P0505R0.
+ * testsuite/20_util/duration/arithmetic/constexpr_c++17.cc: Check
+ for updated macro.
+
+ * include/c_global/cstddef: Define __cpp_lib_byte feature-test macro.
+ * testsuite/18_support/byte/requirements.cc: Check macro.
+
+2017-10-19 Jonathan Wakely <jwakely@redhat.com>
+
+ * testsuite/experimental/filesystem/iterators/
+ recursive_directory_iterator.cc: Ensure that error_code arguments are
+ cleared when required.
+ * testsuite/experimental/filesystem/operations/create_directory.cc:
+ Remove redundant check.
+ * testsuite/experimental/filesystem/operations/temp_directory_path.cc:
+ Ensure that error_code argument is cleared when required.
+
+ * include/experimental/bits/fs_path.h (path::iterator++(int))
+ (path::iterator--(int)): Fix for paths with only one component.
+ * testsuite/experimental/filesystem/path/itr/traversal.cc: Test
+ post-increment and post-decrement.
+
+ * doc/xml/manual/status_cxx2017.xml: Update references to C++17
+ section numbers.
+
+ * testsuite/decimal/conversion-to-integral.cc: Use predefined macro
+ instead of non-standard glibc one.
+
+2017-10-16 François Dumont <fdumont@gcc.gnu.org>
+
+ PR libstdc++/82558
+ * include/bits/stl_bvector.h (fill): Add iterator offset check.
+ * testsuite/23_containers/vector/bool/82558.cc: New.
+
+2017-10-13 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/82522
+ * doc/xml/manual/intro.xml: Document LWG 2354 changes.
+ * include/bits/stl_map.h (map::insert(value_type&&))
+ (map::insert(const_iterator, value_type&&)): Add overload for rvalues.
+ * include/bits/stl_multimap.h (multimap::insert(value_type&&))
+ (multimap::insert(const_iterator, value_type&&)): Likewise.
+ * include/bits/unordered_map.h (unordered_map::insert(value_type&&))
+ (unordered_map::insert(const_iterator, value_type&&))
+ (unordered_multimap::insert(value_type&&))
+ (unordered_multimap::insert(const_iterator, value_type&&)): Likewise.
+ * testsuite/23_containers/map/modifiers/insert/dr2354.cc: New test.
+ * testsuite/23_containers/multimap/modifiers/insert/dr2354.cc: New
+ test.
+ * testsuite/23_containers/unordered_map/insert/dr2354.cc: New test.
+ * testsuite/23_containers/unordered_multimap/insert/dr2354.cc: New
+ test.
+
+ PR libstdc++/82481
+ * include/std/mutex (call_once): Suppress clang-tidy warnings about
+ dangling references.
+
+2017-10-10 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/bits/streambuf_iterator.h (istreambuf_iterator::equal):
+ Update comment about NAD issue.
+
+ PR libstdc++/59087
+ PR libstdc++/82417
+ * include/c_compatibility/complex.h [!C++98 && __STRICT_ANSI__]: Do
+ not include C library's <complex.h>.
+ * testsuite/26_numerics/complex/c99.cc: Depend on __STRICT_ANSI__.
+ * testsuite/26_numerics/headers/complex.h/std_c++11.h: New test.
+ * testsuite/26_numerics/headers/complex.h/std_gnu++11.h: New test.
+ * testsuite/26_numerics/headers/complex.h/std_c++98.h: New test.
+
+2017-10-05 Jonathan Wakely <jwakely@redhat.com>
+
+ * testsuite/20_util/to_chars/1.cc: Add dg-require-string-conversions.
+
+2017-10-04 Petr Ovtchenkov <ptr@void-ptr.info>
+ François Dumont <fdumont@gcc.gnu.org>
+
+ * include/bits/streambuf_iterator.h
+ (istreambuf_iterator<>::operator*()): Do not capture iterator state
+ in Debug assertion.
+ (istreambuf_iterator<>::operator++()): Likewise and remove _M_sbuf check.
+ (istreambuf_iterator<>::operator++(int)): Likewise.
+ (istreambuf_iterator<>::_M_get()): Remove _M_c assignment.
+ (istreambuf_iterator<>::_S_is_eof()): New.
+ (istreambuf_iterator<>::_M_at_eof()): Adapt, use latter.
+ (find(istreambuf_iterator<>, istreambuf_iterator<>, _CharT)):
+ Return an iterator with _M_c set to eof to capture streambuf state
+ on evaluation.
+ (testsuite/24_iterators/istreambuf_iterator/2.cc): Add checks.
+
+2017-10-03 Jakub Jelinek <jakub@redhat.com>
+
+ * include/std/charconv (__unsigned_least_t): Fix number of closing >s for
+ !_GLIBCXX_USE_INT128.
+
+2017-10-02 Jonathan Wakely <jwakely@redhat.com>
+
+ * include/Makefile.am: Add new <charconv> header.
+ * include/Makefile.in: Regenerate.
+ * include/precompiled/stdc++.h: Include <charconv>.
+ * include/std/charconv: New file.
+ (to_chars_result, to_chars, from_chars_result, from_chars): Define.
+ * testsuite/20_util/from_chars/1.cc: New test.
+ * testsuite/20_util/from_chars/1_neg.cc: New test.
+ * testsuite/20_util/from_chars/2.cc: New test.
+ * testsuite/20_util/from_chars/requirements.cc: New test.
+ * testsuite/20_util/to_chars/1.cc: New test.
+ * testsuite/20_util/to_chars/1_neg.cc: New test.
+ * testsuite/20_util/to_chars/2.cc: New test.
+ * testsuite/20_util/to_chars/requirements.cc: New test.
+
+2017-09-27 François Dumont <fdumont@gcc.gnu.org>
+
+ * testsuite/22_locale/money_get/get/char/22131.cc: Make test less
+ istreambuf_iterator implementation dependent.
+ * testsuite/22_locale/money_get/get/wchar_t/22131.cc: Likewise.
+
+2017-09-25 Uros Bizjak <ubizjak@gmail.com>
+
+ PR c/81854
+ * src/c++98/complex_io.cc (_GLIBCXX_LDBL_COMPAT): Declare alias
+ target as a C++ function with no prototype.
+
+2017-09-21 Jonathan Wakely <jwakely@redhat.com>
+
+ * testsuite/25_algorithms/clamp/1.cc: Fix order of arguments and
+ expected results when using predicate defining reverse order.
+ * testsuite/25_algorithms/clamp/constexpr.cc: Likewise.
+
+2017-09-20 Jonathan Wakely <jwakely@redhat.com>
+
+ PR libstdc++/79162
+ * include/bits/basic_string.h [!_GLIBCXX_USE_CXX11_ABI]
+ (basic_string::_If_sv): Remove from the overload set when the
+ argument is derived from basic_string.
+
+ PR libstdc++/79162
+ * include/bits/basic_string.h (basic_string::_If_sv): Remove from the
+ overload set when the argument is derived from basic_string.
+ * testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc: New
+ test.
+ * testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc:
+ New test.
+
+ * testsuite/24_iterators/range_access_cpp17.cc: Fix order of dg-do
+ and dg-options directives. Fix invalid test.
+
+ PR libstdc++/81469
+ * libsupc++/exception (uncaught_exception): Deprecate for C++17.
+ * testsuite/18_support/exception_ptr/62258.cc: Add -Wno-deprecated.
+ * testsuite/18_support/uncaught_exception/14026.cc: Likewise.
+
+ * include/bits/c++config (_GLIBCXX17_DEPRECATED): Define.
+ * include/bits/functional_hash.h (__hash_base::result_type)
+ (__hash_base::argument_type): Add _GLIBCXX17_DEPRECATED.
+ * include/std/optional (hash<optional<T>>::result_type)
+ (hash<optional<T>>::argument_type): Add deprecated attribute.
+ (__is_fast_hash<hash<optional<T>>>): Add partial specialization.
+ * include/std/variant (hash<variant<Types...>>::result_type)
+ (hash<variant<Types...>>::argument_type): Add deprecated attribute.
+ (__is_fast_hash<hash<variant<Types...>>>): Add partial specialization.
+
+ * libsupc++/exception_ptr.h (copy_exception): Remove deprecated
+ non-standard function.
+
+ PR libstdc++/82262
+ * include/std/optional (__optional_hash_call_base): Add template
+ parameter for remove_const_t<_Tp> and use it consistently.
+ * testsuite/20_util/optional/hash.cc: Test optional<const T>.
+
2017-09-19 Jonathan Wakely <jwakely@redhat.com>
PR libstdc++/71500
diff --git a/libstdc++-v3/config/locale/gnu/c_locale.cc b/libstdc++-v3/config/locale/gnu/c_locale.cc
index 7c334e3..9aba3c2 100644
--- a/libstdc++-v3/config/locale/gnu/c_locale.cc
+++ b/libstdc++-v3/config/locale/gnu/c_locale.cc
@@ -289,6 +289,7 @@ _GLIBCXX_END_NAMESPACE_VERSION
// XXX GLIBCXX_ABI Deprecated
#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
+#pragma GCC diagnostic ignored "-Wattribute-alias"
#define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
extern "C" void ldbl (void) __attribute__ ((alias (#dbl)))
_GLIBCXX_LDBL_COMPAT(_ZSt14__convert_to_vIdEvPKcRT_RSt12_Ios_IostateRKP15__locale_struct, _ZSt14__convert_to_vIeEvPKcRT_RSt12_Ios_IostateRKP15__locale_struct);
diff --git a/libstdc++-v3/doc/xml/manual/intro.xml b/libstdc++-v3/doc/xml/manual/intro.xml
index 782817e..2df9c5f 100644
--- a/libstdc++-v3/doc/xml/manual/intro.xml
+++ b/libstdc++-v3/doc/xml/manual/intro.xml
@@ -50,6 +50,10 @@
<!-- Section 01.6 : Status C++ TR24733 -->
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml" href="status_cxxtr24733.xml">
</xi:include>
+
+ <!-- Section 01.7 : Status C++ IS 24733 -->
+ <xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="xml" href="status_cxxis29124.xml">
+ </xi:include>
</section>
<!-- Section 02 : License -->
@@ -988,6 +992,12 @@ requirements of the license of GCC.
<listitem><para>Add deleted constructors.
</para></listitem></varlistentry>
+ <varlistentry xml:id="manual.bugs.dr2354"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2354">2332</link>:
+ <emphasis>Unnecessary copying when inserting into maps with braced-init syntax</emphasis>
+ </term>
+ <listitem><para>Add overloads of <code>insert</code> taking <code>value_type&amp;&amp;</code> rvalues.
+ </para></listitem></varlistentry>
+
<varlistentry xml:id="manual.bugs.dr2399"><term><link xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="&DR;#2399">2399</link>:
<emphasis><code>shared_ptr</code>'s constructor from <code>unique_ptr</code> should be constrained</emphasis>
</term>
diff --git a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
index fd66ac5..b5a65be 100644
--- a/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
+++ b/libstdc++-v3/doc/xml/manual/status_cxx2017.xml
@@ -935,49 +935,49 @@ Feature-testing recommendations for C++</link>.
</para>
<para>
- <emphasis>20.6.5 [optional.bad_optional_access]</emphasis>
+ <emphasis>23.6.5 [optional.bad_optional_access]</emphasis>
<code>what()</code> returns <literal>"bad optional access"</literal>.
</para>
<para>
- <emphasis>20.7.2 [variant.variant]</emphasis>
+ <emphasis>23.7.3 [variant.variant]</emphasis>
Whether <classname>variant</classname> supports over-aligned types
should be documented here.
</para>
<para>
- <emphasis>20.7.10 [variant.bad.access]</emphasis>
+ <emphasis>23.7.10 [variant.bad.access]</emphasis>
<code>what()</code> returns <literal>"Unexpected index"</literal>.
</para>
<para>
- <emphasis>20.12.5.2 [memory.resource.pool.options]</emphasis>
+ <emphasis>23.12.5.2 [memory.resource.pool.options]</emphasis>
The limits for maximum number of blocks and largest allocation size
supported by <classname>pool_options</classname> should be documented
here.
</para>
<para>
- <emphasis>20.12.6.1 [memory.resource.monotonic.buffer.ctor]</emphasis>
+ <emphasis>23.12.6.1 [memory.resource.monotonic.buffer.ctor]</emphasis>
The default <code>next_buffer_size</code> and growth factor should
be documented here.
</para>
<para>
- <emphasis>20.15.4.3 [meta.unary.prop]</emphasis>
+ <emphasis>23.15.4.3 [meta.unary.prop]</emphasis>
The predicate condition for
<code>has_unique_object_representations</code> is true for all scalar
types except floating point types.
</para>
<para>
- <emphasis>20.19.3 [execpol.type],
- 25.2.3 [algorithms.parallel.exec]</emphasis>
+ <emphasis>23.19.3 [execpol.type],
+ 28.4.3 [algorithms.parallel.exec]</emphasis>
There are no implementation-defined execution policies.
</para>
<para>
- <emphasis>22.4.2 [string.view.template]</emphasis>
+ <emphasis>24.4.2 [string.view.template]</emphasis>
<classname>basic_string_view&lt;C, T&gt;::iterator</classname> is
<code>C*</code> and
<classname>basic_string_view&lt;C, T&gt;::const_iterator</classname> is
@@ -986,7 +986,7 @@ Feature-testing recommendations for C++</link>.
<para>
- <emphasis>25.2.3 [algorithms.parallel.exec]</emphasis>
+ <emphasis>28.4.3 [algorithms.parallel.exec]</emphasis>
Threads of execution created by <classname>std::thread</classname>
provide concurrent forward progress guarantees, so threads of execution
implicitly created by the library will provide parallel forward
@@ -994,39 +994,39 @@ Feature-testing recommendations for C++</link>.
</para>
<para>
- <emphasis>26.4.1 [cfenv.syn]</emphasis>
+ <emphasis>29.4.1 [cfenv.syn]</emphasis>
The effects of the <filename>&lt;cfenv&gt;</filename> functions
depends on whether the <code>FENV_ACCESS</code> pragma is supported,
and on the C library that provides the header.
</para>
<para>
- <emphasis>26.6.9 [c.math.rand]</emphasis>
+ <emphasis>29.6.9 [c.math.rand]</emphasis>
Whether the <function>rand</function> function may introduce data
races depends on the target C library that provides the function.
</para>
<para>
- <emphasis>26.9.5 [sf.cmath]</emphasis>
+ <emphasis>29.9.5 [sf.cmath]</emphasis>
The effect of calling the mathematical special functions with large
inputs should be documented here.
</para>
<para>
- <emphasis>27.10.2.1 [fs.conform.9945]</emphasis>
+ <emphasis>30.10.2.1 [fs.conform.9945]</emphasis>
The behavior of the filesystem library implementation will depend on
the target operating system. Some features will not be not supported
on some targets.
</para>
<para>
- <emphasis>27.10.6 [fs.filesystem.syn]</emphasis>
+ <emphasis>30.10.5 [fs.filesystem.syn]</emphasis>
The clock used for file times is
<classname>std::chrono::system_clock</classname>.
</para>
<para>
- <emphasis>27.10.8 [path.generic]</emphasis>
+ <emphasis>30.10.7.1 [fs.path.generic]</emphasis>
dot-dot in the root-directory refers to the root-directory itself.
</para>
diff --git a/libstdc++-v3/doc/xml/manual/status_cxxis29124.xml b/libstdc++-v3/doc/xml/manual/status_cxxis29124.xml
new file mode 100644
index 0000000..40a90fc
--- /dev/null
+++ b/libstdc++-v3/doc/xml/manual/status_cxxis29124.xml
@@ -0,0 +1,315 @@
+<section xmlns="http://docbook.org/ns/docbook" version="5.0"
+ xml:id="status.iso.specfun" xreflabel="Status C++ 29124">
+<?dbhtml filename="status_iso_cxxis29124.html"?>
+
+<info><title>C++ IS 29124</title>
+ <keywordset>
+ <keyword>ISO C++</keyword>
+ <keyword>Special Functions</keyword>
+ </keywordset>
+</info>
+
+<para>
+This table is based on the table of contents of ISO/IEC FDIS 29124
+Doc No: N3060 Date: 2010-03-06
+Extensions to the C++ Library to support mathematical special functions
+</para>
+
+<para>
+Complete support for IS 29124 is in GCC 6.1 and later releases, when using
+at least C++11 (for older releases or C++98/C++03 use TR1 instead).
+For C++11 and C++14 the additions to the library are not declared by their
+respective headers unless <code>__STDCPP_WANT_MATH_SPEC_FUNCS__</code>
+is defined as a macro that expands to a non-zero integer constant.
+For C++17 the special functions are always declared (since GCC 7.1).
+</para>
+
+<para>
+When the special functions are declared the macro
+<code>__STDCPP_MATH_SPEC_FUNCS__</code> is defined to <code>201003L</code>.
+</para>
+
+<para>
+In addition to the special functions defined in IS 29124, for
+non-strict modes (i.e. <code>-std=gnu++NN</code> modes) the
+hypergeometric functions and confluent hypergeometric functions
+from TR1 are also provided, defined in namespace
+<code>__gnu_cxx</code>.
+</para>
+
+<!-- Status is Yes or No, Broken/Partial-->
+<!--
+ Yes
+
+ No
+ <?dbhtml bgcolor="#C8B0B0" ?>
+ Broken/Partial
+ <?dbhtml bgcolor="#B0B0B0" ?>
+-->
+<table frame="all" xml:id="table.specfun_status">
+<title>C++ Special Functions Implementation Status</title>
+
+<tgroup cols="4" align="left" colsep="0" rowsep="1">
+<colspec colname="c1"/>
+<colspec colname="c2"/>
+<colspec colname="c3"/>
+<colspec colname="c4"/>
+
+ <thead>
+ <row>
+ <entry>Section</entry>
+ <entry>Description</entry>
+ <entry>Status</entry>
+ <entry>Comments</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <?dbhtml bgcolor="#B0B0B0" ?>
+ <entry>7</entry>
+ <entry>Macro names</entry>
+ <entry>Partial</entry>
+ <entry>No diagnostic for inconsistent definitions of
+ <code>__STDCPP_WANT_MATH_SPEC_FUNCS__</code></entry>
+ </row>
+ <row>
+ <entry>8</entry>
+ <entry>Mathematical special functions</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1</entry>
+ <entry>Additions to header <code>&lt;cmath&gt;</code> synopsis</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.1</entry>
+ <entry>associated Laguerre polynomials</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.2</entry>
+ <entry>associated Legendre functions</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.3</entry>
+ <entry>beta function</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.4</entry>
+ <entry>(complete) elliptic integral of the first kind</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.5</entry>
+ <entry>(complete) elliptic integral of the second kind</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.6</entry>
+ <entry>(complete) elliptic integral of the third kind</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.7</entry>
+ <entry>regular modified cylindrical Bessel functions</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.8</entry>
+ <entry>cylindrical Bessel functions (of the first kind)</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.9</entry>
+ <entry>irregular modified cylindrical Bessel functions</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.10</entry>
+ <entry>cylindrical Neumann functions</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.11</entry>
+ <entry>(incomplete) elliptic integral of the first kind</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.12</entry>
+ <entry>(incomplete) elliptic integral of the second kind</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.13</entry>
+ <entry>(incomplete) elliptic integral of the third kind</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.14</entry>
+ <entry>exponential integral</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.15</entry>
+ <entry>Hermite polynomials</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.16</entry>
+ <entry>Laguerre polynomials</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.17</entry>
+ <entry>Legendre polynomials</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.18</entry>
+ <entry>Riemann zeta function</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.19</entry>
+ <entry>spherical Bessel functions (of the first kind)</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.20</entry>
+ <entry>spherical associated Legendre functions</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.1.21</entry>
+ <entry>spherical Neumann functions</entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <entry>8.2</entry>
+ <entry>Additions to header <code>&lt;math.h&gt;</code></entry>
+ <entry>Y</entry>
+ <entry/>
+ </row>
+ <row>
+ <?dbhtml bgcolor="#B0B0B0" ?>
+ <entry>8.3</entry>
+ <entry>The header <code>&lt;ctgmath&gt;</code></entry>
+ <entry>Partial</entry>
+ <entry>Conflicts with C++ 2011 requirements.</entry>
+ </row>
+ <row>
+ <?dbhtml bgcolor="#C8B0B0" ?>
+ <entry>8.4</entry>
+ <entry>The header <code>&lt;tgmath.h&gt;</code></entry>
+ <entry>N</entry>
+ <entry>Conflicts with C++ 2011 requirements.</entry>
+ </row>
+ </tbody>
+</tgroup>
+</table>
+
+<section xml:id="iso.specfun.specific" xreflabel="Implementation Specific"><info><title>Implementation Specific Behavior</title></info>
+
+ <para>For behaviour which is specified by the 2011 standard,
+ see <link linkend="iso.2011.specific">C++ 2011 Implementation
+ Specific Behavior</link>. This section documents behaviour which
+ is required by IS 29124.
+ </para>
+
+ <para>
+ <emphasis>7.2 [macro.user]/3 /4</emphasis> The functions declared in
+ Clause 8 are only declared when
+ <code>__STDCPP_WANT_MATH_SPEC_FUNCS__ == 1</code>
+ (or in C++17 mode, for GCC 7.1 and later).
+ </para>
+
+ <para>
+ <emphasis>8.1.1 [sf.cmath.Lnm]/1</emphasis> The effect of calling
+ these functions with <code>n >= 128</code> or <code>m >= 128</code>
+ should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.2 [sf.cmath.Plm]/3</emphasis> The effect of calling
+ these functions with <code>l >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.3 [sf.cmath.I]/3</emphasis> The effect of calling
+ these functions with <code>nu >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.8 [sf.cmath.J]/3</emphasis> The effect of calling
+ these functions with <code>nu >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.9 [sf.cmath.K]/3</emphasis> The effect of calling
+ these functions with <code>nu >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.10 [sf.cmath.N]/3</emphasis> The effect of calling
+ these functions with <code>nu >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.15 [sf.cmath.Hn]/3</emphasis> The effect of calling
+ these functions with <code>n >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.16 [sf.cmath.Ln]/3</emphasis> The effect of calling
+ these functions with <code>n >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.17 [sf.cmath.Pl]/3</emphasis> The effect of calling
+ these functions with <code>l >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.19 [sf.cmath.j]/3</emphasis> The effect of calling
+ these functions with <code>n >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.20 [sf.cmath.Ylm]/3</emphasis> The effect of calling
+ these functions with <code>l >= 128</code> should be described here.
+ </para>
+
+ <para>
+ <emphasis>8.1.21 [sf.cmath.n]/3</emphasis> The effect of calling
+ these functions with <code>n >= 128</code> should be described here.
+ </para>
+
+</section>
+
+</section>
diff --git a/libstdc++-v3/include/Makefile.am b/libstdc++-v3/include/Makefile.am
index 87a41f5..2c4d193 100644
--- a/libstdc++-v3/include/Makefile.am
+++ b/libstdc++-v3/include/Makefile.am
@@ -31,11 +31,13 @@ std_headers = \
${std_srcdir}/array \
${std_srcdir}/atomic \
${std_srcdir}/bitset \
+ ${std_srcdir}/charconv \
${std_srcdir}/chrono \
${std_srcdir}/codecvt \
${std_srcdir}/complex \
${std_srcdir}/condition_variable \
${std_srcdir}/deque \
+ ${std_srcdir}/filesystem \
${std_srcdir}/forward_list \
${std_srcdir}/fstream \
${std_srcdir}/functional \
@@ -103,6 +105,10 @@ bits_headers = \
${bits_srcdir}/enable_special_members.h \
${bits_srcdir}/forward_list.h \
${bits_srcdir}/forward_list.tcc \
+ ${bits_srcdir}/fs_dir.h \
+ ${bits_srcdir}/fs_fwd.h \
+ ${bits_srcdir}/fs_ops.h \
+ ${bits_srcdir}/fs_path.h \
${bits_srcdir}/fstream.tcc \
${bits_srcdir}/functexcept.h \
${bits_srcdir}/functional_hash.h \
diff --git a/libstdc++-v3/include/Makefile.in b/libstdc++-v3/include/Makefile.in
index 7bc4606..bc8556c 100644
--- a/libstdc++-v3/include/Makefile.in
+++ b/libstdc++-v3/include/Makefile.in
@@ -324,11 +324,13 @@ std_headers = \
${std_srcdir}/array \
${std_srcdir}/atomic \
${std_srcdir}/bitset \
+ ${std_srcdir}/charconv \
${std_srcdir}/chrono \
${std_srcdir}/codecvt \
${std_srcdir}/complex \
${std_srcdir}/condition_variable \
${std_srcdir}/deque \
+ ${std_srcdir}/filesystem \
${std_srcdir}/forward_list \
${std_srcdir}/fstream \
${std_srcdir}/functional \
@@ -396,6 +398,10 @@ bits_headers = \
${bits_srcdir}/enable_special_members.h \
${bits_srcdir}/forward_list.h \
${bits_srcdir}/forward_list.tcc \
+ ${bits_srcdir}/fs_dir.h \
+ ${bits_srcdir}/fs_fwd.h \
+ ${bits_srcdir}/fs_ops.h \
+ ${bits_srcdir}/fs_path.h \
${bits_srcdir}/fstream.tcc \
${bits_srcdir}/functexcept.h \
${bits_srcdir}/functional_hash.h \
diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h
index 0ef139b..a4b81137 100644
--- a/libstdc++-v3/include/bits/basic_string.h
+++ b/libstdc++-v3/include/bits/basic_string.h
@@ -115,6 +115,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
template<typename _Tp, typename _Res>
using _If_sv = enable_if_t<
__and_<is_convertible<const _Tp&, __sv_type>,
+ __not_<is_convertible<const _Tp*, const basic_string*>>,
__not_<is_convertible<const _Tp&, const _CharT*>>>::value,
_Res>;
@@ -3438,6 +3439,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
template<typename _Tp, typename _Res>
using _If_sv = enable_if_t<
__and_<is_convertible<const _Tp&, __sv_type>,
+ __not_<is_convertible<const _Tp*, const basic_string*>>,
__not_<is_convertible<const _Tp&, const _CharT*>>>::value,
_Res>;
diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config
index d5d1d24..21e3fbb 100644
--- a/libstdc++-v3/include/bits/c++config
+++ b/libstdc++-v3/include/bits/c++config
@@ -77,6 +77,7 @@
// Macros for deprecated attributes.
// _GLIBCXX_USE_DEPRECATED
// _GLIBCXX_DEPRECATED
+// _GLIBCXX17_DEPRECATED
#ifndef _GLIBCXX_USE_DEPRECATED
# define _GLIBCXX_USE_DEPRECATED 1
#endif
@@ -87,6 +88,12 @@
# define _GLIBCXX_DEPRECATED
#endif
+#if defined(__DEPRECATED) && (__cplusplus >= 201703L)
+# define _GLIBCXX17_DEPRECATED [[__deprecated__]]
+#else
+# define _GLIBCXX17_DEPRECATED
+#endif
+
// Macros for ABI tag attributes.
#ifndef _GLIBCXX_ABI_TAG_CXX11
# define _GLIBCXX_ABI_TAG_CXX11 __attribute ((__abi_tag__ ("cxx11")))
diff --git a/libstdc++-v3/include/bits/fs_dir.h b/libstdc++-v3/include/bits/fs_dir.h
new file mode 100644
index 0000000..20ce9be
--- /dev/null
+++ b/libstdc++-v3/include/bits/fs_dir.h
@@ -0,0 +1,526 @@
+// Filesystem directory utilities -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/fs_dir.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{filesystem}
+ */
+
+#ifndef _GLIBCXX_FS_DIR_H
+#define _GLIBCXX_FS_DIR_H 1
+
+#if __cplusplus >= 201703L
+# include <typeinfo>
+# include <ext/concurrence.h>
+# include <bits/unique_ptr.h>
+# include <bits/shared_ptr.h>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace filesystem
+{
+ /**
+ * @ingroup filesystem
+ * @{
+ */
+
+ class file_status
+ {
+ public:
+ // constructors
+ explicit
+ file_status(file_type __ft = file_type::none,
+ perms __prms = perms::unknown) noexcept
+ : _M_type(__ft), _M_perms(__prms) { }
+
+ file_status(const file_status&) noexcept = default;
+ file_status(file_status&&) noexcept = default;
+ ~file_status() = default;
+
+ file_status& operator=(const file_status&) noexcept = default;
+ file_status& operator=(file_status&&) noexcept = default;
+
+ // observers
+ file_type type() const noexcept { return _M_type; }
+ perms permissions() const noexcept { return _M_perms; }
+
+ // modifiers
+ void type(file_type __ft) noexcept { _M_type = __ft; }
+ void permissions(perms __prms) noexcept { _M_perms = __prms; }
+
+ private:
+ file_type _M_type;
+ perms _M_perms;
+ };
+
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+ struct _Dir;
+ class directory_iterator;
+ class recursive_directory_iterator;
+
+ class directory_entry
+ {
+ public:
+ // constructors and destructor
+ directory_entry() noexcept = default;
+ directory_entry(const directory_entry&) = default;
+ directory_entry(directory_entry&&) noexcept = default;
+
+ explicit
+ directory_entry(const filesystem::path& __p)
+ : _M_path(__p)
+ { refresh(); }
+
+ directory_entry(const filesystem::path& __p, error_code& __ec)
+ : _M_path(__p)
+ {
+ refresh(__ec);
+ if (__ec)
+ _M_path.clear();
+ }
+
+ ~directory_entry() = default;
+
+ // modifiers
+ directory_entry& operator=(const directory_entry&) = default;
+ directory_entry& operator=(directory_entry&&) noexcept = default;
+
+ void
+ assign(const filesystem::path& __p)
+ {
+ _M_path = __p;
+ refresh();
+ }
+
+ void
+ assign(const filesystem::path& __p, error_code& __ec)
+ {
+ _M_path = __p;
+ refresh(__ec);
+ }
+
+ void
+ replace_filename(const filesystem::path& __p)
+ {
+ _M_path.replace_filename(__p);
+ refresh();
+ }
+
+ void
+ replace_filename(const filesystem::path& __p, error_code& __ec)
+ {
+ _M_path.replace_filename(__p);
+ refresh(__ec);
+ }
+
+ void refresh() { _M_type = symlink_status().type(); }
+ void refresh(error_code& __ec) { _M_type = symlink_status(__ec).type(); }
+
+ // observers
+ const filesystem::path& path() const noexcept { return _M_path; }
+ operator const filesystem::path& () const noexcept { return _M_path; }
+
+ bool
+ exists() const
+ { return filesystem::exists(file_status{_M_file_type()}); }
+
+ bool
+ exists(error_code& __ec) const noexcept
+ { return filesystem::exists(file_status{_M_file_type(__ec)}); }
+
+ bool
+ is_block_file() const
+ { return _M_file_type() == file_type::block; }
+
+ bool
+ is_block_file(error_code& __ec) const noexcept
+ { return _M_file_type(__ec) == file_type::block; }
+
+ bool
+ is_character_file() const
+ { return _M_file_type() == file_type::character; }
+
+ bool
+ is_character_file(error_code& __ec) const noexcept
+ { return _M_file_type(__ec) == file_type::character; }
+
+ bool
+ is_directory() const
+ { return _M_file_type() == file_type::directory; }
+
+ bool
+ is_directory(error_code& __ec) const noexcept
+ { return _M_file_type(__ec) == file_type::directory; }
+
+ bool
+ is_fifo() const
+ { return _M_file_type() == file_type::fifo; }
+
+ bool
+ is_fifo(error_code& __ec) const noexcept
+ { return _M_file_type(__ec) == file_type::fifo; }
+
+ bool
+ is_other() const
+ { return filesystem::is_other(file_status{_M_file_type()}); }
+
+ bool
+ is_other(error_code& __ec) const noexcept
+ { return filesystem::is_other(file_status{_M_file_type(__ec)}); }
+
+ bool
+ is_regular_file() const
+ { return _M_file_type() == file_type::regular; }
+
+ bool
+ is_regular_file(error_code& __ec) const noexcept
+ { return _M_file_type(__ec) == file_type::regular; }
+
+ bool
+ is_socket() const
+ { return _M_file_type() == file_type::socket; }
+
+ bool
+ is_socket(error_code& __ec) const noexcept
+ { return _M_file_type(__ec) == file_type::socket; }
+
+ bool
+ is_symlink() const
+ {
+ if (_M_type != file_type::none)
+ return _M_type == file_type::symlink;
+ return symlink_status().type() == file_type::symlink;
+ }
+
+ bool
+ is_symlink(error_code& __ec) const noexcept
+ {
+ if (_M_type != file_type::none)
+ return _M_type == file_type::symlink;
+ return symlink_status(__ec).type() == file_type::symlink;
+ }
+
+ uintmax_t
+ file_size() const
+ { return filesystem::file_size(_M_path); }
+
+ uintmax_t
+ file_size(error_code& __ec) const noexcept
+ { return filesystem::file_size(_M_path, __ec); }
+
+ uintmax_t
+ hard_link_count() const
+ { return filesystem::hard_link_count(_M_path); }
+
+ uintmax_t
+ hard_link_count(error_code& __ec) const noexcept
+ { return filesystem::hard_link_count(_M_path, __ec); }
+
+ file_time_type
+ last_write_time() const
+ { return filesystem::last_write_time(_M_path); }
+
+
+ file_time_type
+ last_write_time(error_code& __ec) const noexcept
+ { return filesystem::last_write_time(_M_path, __ec); }
+
+ file_status
+ status() const
+ { return filesystem::status(_M_path); }
+
+ file_status
+ status(error_code& __ec) const noexcept
+ { return filesystem::status(_M_path, __ec); }
+
+ file_status
+ symlink_status() const
+ { return filesystem::symlink_status(_M_path); }
+
+ file_status
+ symlink_status(error_code& __ec) const noexcept
+ { return filesystem::symlink_status(_M_path, __ec); }
+
+ bool
+ operator< (const directory_entry& __rhs) const noexcept
+ { return _M_path < __rhs._M_path; }
+
+ bool
+ operator==(const directory_entry& __rhs) const noexcept
+ { return _M_path == __rhs._M_path; }
+
+ bool
+ operator!=(const directory_entry& __rhs) const noexcept
+ { return _M_path != __rhs._M_path; }
+
+ bool
+ operator<=(const directory_entry& __rhs) const noexcept
+ { return _M_path <= __rhs._M_path; }
+
+ bool
+ operator> (const directory_entry& __rhs) const noexcept
+ { return _M_path > __rhs._M_path; }
+
+ bool
+ operator>=(const directory_entry& __rhs) const noexcept
+ { return _M_path >= __rhs._M_path; }
+
+ private:
+ friend class _Dir;
+ friend class directory_iterator;
+ friend class recursive_directory_iterator;
+
+ directory_entry(const filesystem::path& __p, file_type __t)
+ : _M_path(__p), _M_type(__t)
+ { }
+
+ // Equivalent to status().type() but uses cached value, if any.
+ file_type
+ _M_file_type() const
+ {
+ if (_M_type != file_type::none && _M_type != file_type::symlink)
+ return _M_type;
+ return status().type();
+ }
+
+ // Equivalent to status(__ec).type() but uses cached value, if any.
+ file_type
+ _M_file_type(error_code& __ec) const noexcept
+ {
+ if (_M_type != file_type::none && _M_type != file_type::symlink)
+ return _M_type;
+ return status(__ec).type();
+ }
+
+ filesystem::path _M_path;
+ file_type _M_type = file_type::none;
+ };
+
+ struct __directory_iterator_proxy
+ {
+ const directory_entry& operator*() const& noexcept { return _M_entry; }
+
+ directory_entry operator*() && noexcept { return std::move(_M_entry); }
+
+ private:
+ friend class directory_iterator;
+ friend class recursive_directory_iterator;
+
+ explicit
+ __directory_iterator_proxy(const directory_entry& __e) : _M_entry(__e) { }
+
+ directory_entry _M_entry;
+ };
+
+ class directory_iterator
+ {
+ public:
+ typedef directory_entry value_type;
+ typedef ptrdiff_t difference_type;
+ typedef const directory_entry* pointer;
+ typedef const directory_entry& reference;
+ typedef input_iterator_tag iterator_category;
+
+ directory_iterator() = default;
+
+ explicit
+ directory_iterator(const path& __p)
+ : directory_iterator(__p, directory_options::none, nullptr) { }
+
+ directory_iterator(const path& __p, directory_options __options)
+ : directory_iterator(__p, __options, nullptr) { }
+
+ directory_iterator(const path& __p, error_code& __ec) noexcept
+ : directory_iterator(__p, directory_options::none, __ec) { }
+
+ directory_iterator(const path& __p,
+ directory_options __options,
+ error_code& __ec) noexcept
+ : directory_iterator(__p, __options, &__ec) { }
+
+ directory_iterator(const directory_iterator& __rhs) = default;
+
+ directory_iterator(directory_iterator&& __rhs) noexcept = default;
+
+ ~directory_iterator() = default;
+
+ directory_iterator&
+ operator=(const directory_iterator& __rhs) = default;
+
+ directory_iterator&
+ operator=(directory_iterator&& __rhs) noexcept = default;
+
+ const directory_entry& operator*() const;
+ const directory_entry* operator->() const { return &**this; }
+ directory_iterator& operator++();
+ directory_iterator& increment(error_code& __ec) noexcept;
+
+ __directory_iterator_proxy operator++(int)
+ {
+ __directory_iterator_proxy __pr{**this};
+ ++*this;
+ return __pr;
+ }
+
+ private:
+ directory_iterator(const path&, directory_options, error_code*);
+
+ friend bool
+ operator==(const directory_iterator& __lhs,
+ const directory_iterator& __rhs);
+
+ friend class recursive_directory_iterator;
+
+ std::shared_ptr<_Dir> _M_dir;
+ };
+
+ inline directory_iterator
+ begin(directory_iterator __iter) noexcept
+ { return __iter; }
+
+ inline directory_iterator
+ end(directory_iterator) noexcept
+ { return directory_iterator(); }
+
+ inline bool
+ operator==(const directory_iterator& __lhs, const directory_iterator& __rhs)
+ {
+ return !__rhs._M_dir.owner_before(__lhs._M_dir)
+ && !__lhs._M_dir.owner_before(__rhs._M_dir);
+ }
+
+ inline bool
+ operator!=(const directory_iterator& __lhs, const directory_iterator& __rhs)
+ { return !(__lhs == __rhs); }
+
+ class recursive_directory_iterator
+ {
+ public:
+ typedef directory_entry value_type;
+ typedef ptrdiff_t difference_type;
+ typedef const directory_entry* pointer;
+ typedef const directory_entry& reference;
+ typedef input_iterator_tag iterator_category;
+
+ recursive_directory_iterator() = default;
+
+ explicit
+ recursive_directory_iterator(const path& __p)
+ : recursive_directory_iterator(__p, directory_options::none, nullptr) { }
+
+ recursive_directory_iterator(const path& __p, directory_options __options)
+ : recursive_directory_iterator(__p, __options, nullptr) { }
+
+ recursive_directory_iterator(const path& __p,
+ directory_options __options,
+ error_code& __ec) noexcept
+ : recursive_directory_iterator(__p, __options, &__ec) { }
+
+ recursive_directory_iterator(const path& __p, error_code& __ec) noexcept
+ : recursive_directory_iterator(__p, directory_options::none, &__ec) { }
+
+ recursive_directory_iterator(
+ const recursive_directory_iterator&) = default;
+
+ recursive_directory_iterator(recursive_directory_iterator&&) = default;
+
+ ~recursive_directory_iterator();
+
+ // observers
+ directory_options options() const { return _M_options; }
+ int depth() const;
+ bool recursion_pending() const { return _M_pending; }
+
+ const directory_entry& operator*() const;
+ const directory_entry* operator->() const { return &**this; }
+
+ // modifiers
+ recursive_directory_iterator&
+ operator=(const recursive_directory_iterator& __rhs) noexcept;
+ recursive_directory_iterator&
+ operator=(recursive_directory_iterator&& __rhs) noexcept;
+
+ recursive_directory_iterator& operator++();
+ recursive_directory_iterator& increment(error_code& __ec) noexcept;
+
+ __directory_iterator_proxy operator++(int)
+ {
+ __directory_iterator_proxy __pr{**this};
+ ++*this;
+ return __pr;
+ }
+
+ void pop();
+ void pop(error_code&);
+
+ void disable_recursion_pending() { _M_pending = false; }
+
+ private:
+ recursive_directory_iterator(const path&, directory_options, error_code*);
+
+ friend bool
+ operator==(const recursive_directory_iterator& __lhs,
+ const recursive_directory_iterator& __rhs);
+
+ struct _Dir_stack;
+ std::shared_ptr<_Dir_stack> _M_dirs;
+ directory_options _M_options = {};
+ bool _M_pending = false;
+ };
+
+ inline recursive_directory_iterator
+ begin(recursive_directory_iterator __iter) noexcept
+ { return __iter; }
+
+ inline recursive_directory_iterator
+ end(recursive_directory_iterator) noexcept
+ { return recursive_directory_iterator(); }
+
+ inline bool
+ operator==(const recursive_directory_iterator& __lhs,
+ const recursive_directory_iterator& __rhs)
+ {
+ return !__rhs._M_dirs.owner_before(__lhs._M_dirs)
+ && !__lhs._M_dirs.owner_before(__rhs._M_dirs);
+ }
+
+ inline bool
+ operator!=(const recursive_directory_iterator& __lhs,
+ const recursive_directory_iterator& __rhs)
+ { return !(__lhs == __rhs); }
+
+_GLIBCXX_END_NAMESPACE_CXX11
+
+ // @} group filesystem
+} // namespace filesystem
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_FS_DIR_H
diff --git a/libstdc++-v3/include/bits/fs_fwd.h b/libstdc++-v3/include/bits/fs_fwd.h
new file mode 100644
index 0000000..f408a39
--- /dev/null
+++ b/libstdc++-v3/include/bits/fs_fwd.h
@@ -0,0 +1,348 @@
+// Filesystem declarations -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/fs_fwd.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{filesystem}
+ */
+
+#ifndef _GLIBCXX_FS_FWD_H
+#define _GLIBCXX_FS_FWD_H 1
+
+#if __cplusplus >= 201703L
+
+#include <system_error>
+#include <cstdint>
+#include <chrono>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace filesystem
+{
+#if _GLIBCXX_USE_CXX11_ABI
+inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
+#endif
+
+ /**
+ * @defgroup filesystem Filesystem
+ *
+ * Utilities for performing operations on file systems and their components,
+ * such as paths, regular files, and directories.
+ *
+ * @{
+ */
+
+ class file_status;
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+ class path;
+ class filesystem_error;
+ class directory_entry;
+ class directory_iterator;
+ class recursive_directory_iterator;
+_GLIBCXX_END_NAMESPACE_CXX11
+
+ struct space_info
+ {
+ uintmax_t capacity;
+ uintmax_t free;
+ uintmax_t available;
+ };
+
+ enum class file_type : signed char {
+ none = 0, not_found = -1, regular = 1, directory = 2, symlink = 3,
+ block = 4, character = 5, fifo = 6, socket = 7, unknown = 8
+ };
+
+ /// Bitmask type
+ enum class copy_options : unsigned short {
+ none = 0,
+ skip_existing = 1, overwrite_existing = 2, update_existing = 4,
+ recursive = 8,
+ copy_symlinks = 16, skip_symlinks = 32,
+ directories_only = 64, create_symlinks = 128, create_hard_links = 256
+ };
+
+ constexpr copy_options
+ operator&(copy_options __x, copy_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<copy_options>::type;
+ return static_cast<copy_options>(
+ static_cast<__utype>(__x) & static_cast<__utype>(__y));
+ }
+
+ constexpr copy_options
+ operator|(copy_options __x, copy_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<copy_options>::type;
+ return static_cast<copy_options>(
+ static_cast<__utype>(__x) | static_cast<__utype>(__y));
+ }
+
+ constexpr copy_options
+ operator^(copy_options __x, copy_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<copy_options>::type;
+ return static_cast<copy_options>(
+ static_cast<__utype>(__x) ^ static_cast<__utype>(__y));
+ }
+
+ constexpr copy_options
+ operator~(copy_options __x) noexcept
+ {
+ using __utype = typename std::underlying_type<copy_options>::type;
+ return static_cast<copy_options>(~static_cast<__utype>(__x));
+ }
+
+ inline copy_options&
+ operator&=(copy_options& __x, copy_options __y) noexcept
+ { return __x = __x & __y; }
+
+ inline copy_options&
+ operator|=(copy_options& __x, copy_options __y) noexcept
+ { return __x = __x | __y; }
+
+ inline copy_options&
+ operator^=(copy_options& __x, copy_options __y) noexcept
+ { return __x = __x ^ __y; }
+
+
+ /// Bitmask type
+ enum class perms : unsigned {
+ none = 0,
+ owner_read = 0400,
+ owner_write = 0200,
+ owner_exec = 0100,
+ owner_all = 0700,
+ group_read = 040,
+ group_write = 020,
+ group_exec = 010,
+ group_all = 070,
+ others_read = 04,
+ others_write = 02,
+ others_exec = 01,
+ others_all = 07,
+ all = 0777,
+ set_uid = 04000,
+ set_gid = 02000,
+ sticky_bit = 01000,
+ mask = 07777,
+ unknown = 0xFFFF,
+ };
+
+ constexpr perms
+ operator&(perms __x, perms __y) noexcept
+ {
+ using __utype = typename std::underlying_type<perms>::type;
+ return static_cast<perms>(
+ static_cast<__utype>(__x) & static_cast<__utype>(__y));
+ }
+
+ constexpr perms
+ operator|(perms __x, perms __y) noexcept
+ {
+ using __utype = typename std::underlying_type<perms>::type;
+ return static_cast<perms>(
+ static_cast<__utype>(__x) | static_cast<__utype>(__y));
+ }
+
+ constexpr perms
+ operator^(perms __x, perms __y) noexcept
+ {
+ using __utype = typename std::underlying_type<perms>::type;
+ return static_cast<perms>(
+ static_cast<__utype>(__x) ^ static_cast<__utype>(__y));
+ }
+
+ constexpr perms
+ operator~(perms __x) noexcept
+ {
+ using __utype = typename std::underlying_type<perms>::type;
+ return static_cast<perms>(~static_cast<__utype>(__x));
+ }
+
+ inline perms&
+ operator&=(perms& __x, perms __y) noexcept
+ { return __x = __x & __y; }
+
+ inline perms&
+ operator|=(perms& __x, perms __y) noexcept
+ { return __x = __x | __y; }
+
+ inline perms&
+ operator^=(perms& __x, perms __y) noexcept
+ { return __x = __x ^ __y; }
+
+ /// Bitmask type
+ enum class perm_options : unsigned {
+ replace = 0x1,
+ add = 0x2,
+ remove = 0x4,
+ nofollow = 0x8
+ };
+
+ constexpr perm_options
+ operator&(perm_options __x, perm_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<perm_options>::type;
+ return static_cast<perm_options>(
+ static_cast<__utype>(__x) & static_cast<__utype>(__y));
+ }
+
+ constexpr perm_options
+ operator|(perm_options __x, perm_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<perm_options>::type;
+ return static_cast<perm_options>(
+ static_cast<__utype>(__x) | static_cast<__utype>(__y));
+ }
+
+ constexpr perm_options
+ operator^(perm_options __x, perm_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<perm_options>::type;
+ return static_cast<perm_options>(
+ static_cast<__utype>(__x) ^ static_cast<__utype>(__y));
+ }
+
+ constexpr perm_options
+ operator~(perm_options __x) noexcept
+ {
+ using __utype = typename std::underlying_type<perm_options>::type;
+ return static_cast<perm_options>(~static_cast<__utype>(__x));
+ }
+
+ inline perm_options&
+ operator&=(perm_options& __x, perm_options __y) noexcept
+ { return __x = __x & __y; }
+
+ inline perm_options&
+ operator|=(perm_options& __x, perm_options __y) noexcept
+ { return __x = __x | __y; }
+
+ inline perm_options&
+ operator^=(perm_options& __x, perm_options __y) noexcept
+ { return __x = __x ^ __y; }
+
+ // Bitmask type
+ enum class directory_options : unsigned char {
+ none = 0, follow_directory_symlink = 1, skip_permission_denied = 2
+ };
+
+ constexpr directory_options
+ operator&(directory_options __x, directory_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<directory_options>::type;
+ return static_cast<directory_options>(
+ static_cast<__utype>(__x) & static_cast<__utype>(__y));
+ }
+
+ constexpr directory_options
+ operator|(directory_options __x, directory_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<directory_options>::type;
+ return static_cast<directory_options>(
+ static_cast<__utype>(__x) | static_cast<__utype>(__y));
+ }
+
+ constexpr directory_options
+ operator^(directory_options __x, directory_options __y) noexcept
+ {
+ using __utype = typename std::underlying_type<directory_options>::type;
+ return static_cast<directory_options>(
+ static_cast<__utype>(__x) ^ static_cast<__utype>(__y));
+ }
+
+ constexpr directory_options
+ operator~(directory_options __x) noexcept
+ {
+ using __utype = typename std::underlying_type<directory_options>::type;
+ return static_cast<directory_options>(~static_cast<__utype>(__x));
+ }
+
+ inline directory_options&
+ operator&=(directory_options& __x, directory_options __y) noexcept
+ { return __x = __x & __y; }
+
+ inline directory_options&
+ operator|=(directory_options& __x, directory_options __y) noexcept
+ { return __x = __x | __y; }
+
+ inline directory_options&
+ operator^=(directory_options& __x, directory_options __y) noexcept
+ { return __x = __x ^ __y; }
+
+ using file_time_type = std::chrono::system_clock::time_point;
+
+ // operational functions
+
+ void copy(const path& __from, const path& __to, copy_options __options);
+ void copy(const path& __from, const path& __to, copy_options __options,
+ error_code&) noexcept;
+
+ bool copy_file(const path& __from, const path& __to, copy_options __option);
+ bool copy_file(const path& __from, const path& __to, copy_options __option,
+ error_code&) noexcept;
+
+ path current_path();
+
+ bool exists(file_status) noexcept;
+
+ bool is_other(file_status) noexcept;
+
+ uintmax_t file_size(const path&);
+ uintmax_t file_size(const path&, error_code&) noexcept;
+ uintmax_t hard_link_count(const path&);
+ uintmax_t hard_link_count(const path&, error_code&) noexcept;
+ file_time_type last_write_time(const path&);
+ file_time_type last_write_time(const path&, error_code&) noexcept;
+
+ void permissions(const path&, perms, perm_options, error_code&);
+
+ path proximate(const path& __p, const path& __base, error_code& __ec);
+ path proximate(const path& __p, const path& __base, error_code& __ec);
+
+ path relative(const path& __p, const path& __base, error_code& __ec);
+
+ file_status status(const path&);
+ file_status status(const path&, error_code&) noexcept;
+
+ bool status_known(file_status) noexcept;
+
+ file_status symlink_status(const path&);
+ file_status symlink_status(const path&, error_code&) noexcept;
+
+ bool is_regular_file(file_status) noexcept;
+ bool is_symlink(file_status) noexcept;
+
+ // @} group filesystem
+} // namespace filesystem
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_FS_FWD_H
diff --git a/libstdc++-v3/include/bits/fs_ops.h b/libstdc++-v3/include/bits/fs_ops.h
new file mode 100644
index 0000000..563d63d
--- /dev/null
+++ b/libstdc++-v3/include/bits/fs_ops.h
@@ -0,0 +1,311 @@
+// Filesystem operational functions -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/fs_fwd.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{filesystem}
+ */
+
+#ifndef _GLIBCXX_FS_OPS_H
+#define _GLIBCXX_FS_OPS_H 1
+
+#if __cplusplus >= 201703L
+
+#include <cstdint>
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace filesystem
+{
+ /**
+ * @ingroup filesystem
+ * @{
+ */
+
+ path absolute(const path& __p);
+ path absolute(const path& __p, error_code& __ec);
+
+ path canonical(const path& __p);
+ path canonical(const path& __p, error_code& __ec);
+
+ inline void
+ copy(const path& __from, const path& __to)
+ { copy(__from, __to, copy_options::none); }
+
+ inline void
+ copy(const path& __from, const path& __to, error_code& __ec) noexcept
+ { copy(__from, __to, copy_options::none, __ec); }
+
+ void copy(const path& __from, const path& __to, copy_options __options);
+ void copy(const path& __from, const path& __to, copy_options __options,
+ error_code& __ec) noexcept;
+
+ inline bool
+ copy_file(const path& __from, const path& __to)
+ { return copy_file(__from, __to, copy_options::none); }
+
+ inline bool
+ copy_file(const path& __from, const path& __to, error_code& __ec) noexcept
+ { return copy_file(__from, __to, copy_options::none, __ec); }
+
+ bool copy_file(const path& __from, const path& __to, copy_options __option);
+ bool copy_file(const path& __from, const path& __to, copy_options __option,
+ error_code& __ec) noexcept;
+
+ void copy_symlink(const path& __existing_symlink, const path& __new_symlink);
+ void copy_symlink(const path& __existing_symlink, const path& __new_symlink,
+ error_code& __ec) noexcept;
+
+ bool create_directories(const path& __p);
+ bool create_directories(const path& __p, error_code& __ec) noexcept;
+
+ bool create_directory(const path& __p);
+ bool create_directory(const path& __p, error_code& __ec) noexcept;
+
+ bool create_directory(const path& __p, const path& attributes);
+ bool create_directory(const path& __p, const path& attributes,
+ error_code& __ec) noexcept;
+
+ void create_directory_symlink(const path& __to, const path& __new_symlink);
+ void create_directory_symlink(const path& __to, const path& __new_symlink,
+ error_code& __ec) noexcept;
+
+ void create_hard_link(const path& __to, const path& __new_hard_link);
+ void create_hard_link(const path& __to, const path& __new_hard_link,
+ error_code& __ec) noexcept;
+
+ void create_symlink(const path& __to, const path& __new_symlink);
+ void create_symlink(const path& __to, const path& __new_symlink,
+ error_code& __ec) noexcept;
+
+ path current_path();
+ path current_path(error_code& __ec);
+ void current_path(const path& __p);
+ void current_path(const path& __p, error_code& __ec) noexcept;
+
+ bool
+ equivalent(const path& __p1, const path& __p2);
+
+ bool
+ equivalent(const path& __p1, const path& __p2, error_code& __ec) noexcept;
+
+ inline bool
+ exists(file_status __s) noexcept
+ { return status_known(__s) && __s.type() != file_type::not_found; }
+
+ inline bool
+ exists(const path& __p)
+ { return exists(status(__p)); }
+
+ inline bool
+ exists(const path& __p, error_code& __ec) noexcept
+ {
+ auto __s = status(__p, __ec);
+ if (status_known(__s))
+ __ec.clear();
+ return exists(__s);
+ }
+
+ uintmax_t file_size(const path& __p);
+ uintmax_t file_size(const path& __p, error_code& __ec) noexcept;
+
+ uintmax_t hard_link_count(const path& __p);
+ uintmax_t hard_link_count(const path& __p, error_code& __ec) noexcept;
+
+ inline bool
+ is_block_file(file_status __s) noexcept
+ { return __s.type() == file_type::block; }
+
+ inline bool
+ is_block_file(const path& __p)
+ { return is_block_file(status(__p)); }
+
+ inline bool
+ is_block_file(const path& __p, error_code& __ec) noexcept
+ { return is_block_file(status(__p, __ec)); }
+
+ inline bool
+ is_character_file(file_status __s) noexcept
+ { return __s.type() == file_type::character; }
+
+ inline bool
+ is_character_file(const path& __p)
+ { return is_character_file(status(__p)); }
+
+ inline bool
+ is_character_file(const path& __p, error_code& __ec) noexcept
+ { return is_character_file(status(__p, __ec)); }
+
+ inline bool
+ is_directory(file_status __s) noexcept
+ { return __s.type() == file_type::directory; }
+
+ inline bool
+ is_directory(const path& __p)
+ { return is_directory(status(__p)); }
+
+ inline bool
+ is_directory(const path& __p, error_code& __ec) noexcept
+ { return is_directory(status(__p, __ec)); }
+
+ bool is_empty(const path& __p);
+ bool is_empty(const path& __p, error_code& __ec) noexcept;
+
+ inline bool
+ is_fifo(file_status __s) noexcept
+ { return __s.type() == file_type::fifo; }
+
+ inline bool
+ is_fifo(const path& __p)
+ { return is_fifo(status(__p)); }
+
+ inline bool
+ is_fifo(const path& __p, error_code& __ec) noexcept
+ { return is_fifo(status(__p, __ec)); }
+
+ inline bool
+ is_other(file_status __s) noexcept
+ {
+ return exists(__s) && !is_regular_file(__s) && !is_directory(__s)
+ && !is_symlink(__s);
+ }
+
+ inline bool
+ is_other(const path& __p)
+ { return is_other(status(__p)); }
+
+ inline bool
+ is_other(const path& __p, error_code& __ec) noexcept
+ { return is_other(status(__p, __ec)); }
+
+ inline bool
+ is_regular_file(file_status __s) noexcept
+ { return __s.type() == file_type::regular; }
+
+ inline bool
+ is_regular_file(const path& __p)
+ { return is_regular_file(status(__p)); }
+
+ inline bool
+ is_regular_file(const path& __p, error_code& __ec) noexcept
+ { return is_regular_file(status(__p, __ec)); }
+
+ inline bool
+ is_socket(file_status __s) noexcept
+ { return __s.type() == file_type::socket; }
+
+ inline bool
+ is_socket(const path& __p)
+ { return is_socket(status(__p)); }
+
+ inline bool
+ is_socket(const path& __p, error_code& __ec) noexcept
+ { return is_socket(status(__p, __ec)); }
+
+ inline bool
+ is_symlink(file_status __s) noexcept
+ { return __s.type() == file_type::symlink; }
+
+ inline bool
+ is_symlink(const path& __p)
+ { return is_symlink(symlink_status(__p)); }
+
+ inline bool
+ is_symlink(const path& __p, error_code& __ec) noexcept
+ { return is_symlink(symlink_status(__p, __ec)); }
+
+ file_time_type last_write_time(const path& __p);
+ file_time_type last_write_time(const path& __p, error_code& __ec) noexcept;
+ void last_write_time(const path& __p, file_time_type __new_time);
+ void last_write_time(const path& __p, file_time_type __new_time,
+ error_code& __ec) noexcept;
+
+ void
+ permissions(const path& __p, perms __prms,
+ perm_options __opts = perm_options::replace);
+
+ inline void
+ permissions(const path& __p, perms __prms, error_code& __ec) noexcept
+ { permissions(__p, __prms, perm_options::replace, __ec); }
+
+ void
+ permissions(const path& __p, perms __prms, perm_options __opts,
+ error_code& __ec);
+
+ inline path proximate(const path& __p, error_code& __ec)
+ { return proximate(__p, current_path(), __ec); }
+
+ path proximate(const path& __p, const path& __base = current_path());
+ path proximate(const path& __p, const path& __base, error_code& __ec);
+
+ path read_symlink(const path& __p);
+ path read_symlink(const path& __p, error_code& __ec);
+
+ inline path relative(const path& __p, error_code& __ec)
+ { return relative(__p, current_path(), __ec); }
+
+ path relative(const path& __p, const path& __base = current_path());
+ path relative(const path& __p, const path& __base, error_code& __ec);
+
+ bool remove(const path& __p);
+ bool remove(const path& __p, error_code& __ec) noexcept;
+
+ uintmax_t remove_all(const path& __p);
+ uintmax_t remove_all(const path& __p, error_code& __ec) noexcept;
+
+ void rename(const path& __from, const path& __to);
+ void rename(const path& __from, const path& __to, error_code& __ec) noexcept;
+
+ void resize_file(const path& __p, uintmax_t __size);
+ void resize_file(const path& __p, uintmax_t __size, error_code& __ec) noexcept;
+
+ space_info space(const path& __p);
+ space_info space(const path& __p, error_code& __ec) noexcept;
+
+ file_status status(const path& __p);
+ file_status status(const path& __p, error_code& __ec) noexcept;
+
+ inline bool status_known(file_status __s) noexcept
+ { return __s.type() != file_type::none; }
+
+ file_status symlink_status(const path& __p);
+ file_status symlink_status(const path& __p, error_code& __ec) noexcept;
+
+ path temp_directory_path();
+ path temp_directory_path(error_code& __ec);
+
+ path weakly_canonical(const path& __p);
+ path weakly_canonical(const path& __p, error_code& __ec);
+
+ // @} group filesystem
+} // namespace filesystem
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_FS_OPS_H
diff --git a/libstdc++-v3/include/bits/fs_path.h b/libstdc++-v3/include/bits/fs_path.h
new file mode 100644
index 0000000..6ba2bd2
--- /dev/null
+++ b/libstdc++-v3/include/bits/fs_path.h
@@ -0,0 +1,1163 @@
+// Class filesystem::path -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/bits/fs_path.h
+ * This is an internal header file, included by other library headers.
+ * Do not attempt to use it directly. @headername{filesystem}
+ */
+
+#ifndef _GLIBCXX_FS_PATH_H
+#define _GLIBCXX_FS_PATH_H 1
+
+#if __cplusplus >= 201703L
+
+#include <utility>
+#include <type_traits>
+#include <vector>
+#include <locale>
+#include <iosfwd>
+#include <codecvt>
+#include <string_view>
+#include <system_error>
+#include <bits/stl_algobase.h>
+#include <bits/quoted_string.h>
+#include <bits/locale_conv.h>
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+# define _GLIBCXX_FILESYSTEM_IS_WINDOWS 1
+# include <algorithm>
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+namespace filesystem
+{
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+ /**
+ * @ingroup filesystem
+ * @{
+ */
+
+ /// A filesystem path.
+ class path
+ {
+ template<typename _CharT>
+ struct __is_encoded_char : std::false_type { };
+
+ template<typename _Iter,
+ typename _Iter_traits = std::iterator_traits<_Iter>>
+ using __is_path_iter_src
+ = __and_<__is_encoded_char<typename _Iter_traits::value_type>,
+ std::is_base_of<std::input_iterator_tag,
+ typename _Iter_traits::iterator_category>>;
+
+ template<typename _Iter>
+ static __is_path_iter_src<_Iter>
+ __is_path_src(_Iter, int);
+
+ template<typename _CharT, typename _Traits, typename _Alloc>
+ static __is_encoded_char<_CharT>
+ __is_path_src(const basic_string<_CharT, _Traits, _Alloc>&, int);
+
+ template<typename _CharT, typename _Traits>
+ static __is_encoded_char<_CharT>
+ __is_path_src(const basic_string_view<_CharT, _Traits>&, int);
+
+ template<typename _Unknown>
+ static std::false_type
+ __is_path_src(const _Unknown&, ...);
+
+ template<typename _Tp1, typename _Tp2>
+ struct __constructible_from;
+
+ template<typename _Iter>
+ struct __constructible_from<_Iter, _Iter>
+ : __is_path_iter_src<_Iter>
+ { };
+
+ template<typename _Source>
+ struct __constructible_from<_Source, void>
+ : decltype(__is_path_src(std::declval<_Source>(), 0))
+ { };
+
+ template<typename _Tp1, typename _Tp2 = void>
+ using _Path = typename
+ std::enable_if<__and_<__not_<is_same<_Tp1, path>>,
+ __constructible_from<_Tp1, _Tp2>>::value,
+ path>::type;
+
+ template<typename _Source>
+ static _Source
+ _S_range_begin(_Source __begin) { return __begin; }
+
+ struct __null_terminated { };
+
+ template<typename _Source>
+ static __null_terminated
+ _S_range_end(_Source) { return {}; }
+
+ template<typename _CharT, typename _Traits, typename _Alloc>
+ static const _CharT*
+ _S_range_begin(const basic_string<_CharT, _Traits, _Alloc>& __str)
+ { return __str.data(); }
+
+ template<typename _CharT, typename _Traits, typename _Alloc>
+ static const _CharT*
+ _S_range_end(const basic_string<_CharT, _Traits, _Alloc>& __str)
+ { return __str.data() + __str.size(); }
+
+ template<typename _CharT, typename _Traits>
+ static const _CharT*
+ _S_range_begin(const basic_string_view<_CharT, _Traits>& __str)
+ { return __str.data(); }
+
+ template<typename _CharT, typename _Traits>
+ static const _CharT*
+ _S_range_end(const basic_string_view<_CharT, _Traits>& __str)
+ { return __str.data() + __str.size(); }
+
+ template<typename _Tp,
+ typename _Iter = decltype(_S_range_begin(std::declval<_Tp>())),
+ typename _Val = typename std::iterator_traits<_Iter>::value_type>
+ using __value_type_is_char
+ = typename std::enable_if<std::is_same<_Val, char>::value>::type;
+
+ public:
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ typedef wchar_t value_type;
+ static constexpr value_type preferred_separator = L'\\';
+#else
+ typedef char value_type;
+ static constexpr value_type preferred_separator = '/';
+#endif
+ typedef std::basic_string<value_type> string_type;
+
+ // constructors and destructor
+
+ path() noexcept { }
+
+ path(const path& __p) = default;
+
+ path(path&& __p) noexcept
+ : _M_pathname(std::move(__p._M_pathname)), _M_type(__p._M_type)
+ {
+ _M_split_cmpts();
+ __p.clear();
+ }
+
+ path(string_type&& __source)
+ : _M_pathname(std::move(__source))
+ { _M_split_cmpts(); }
+
+ template<typename _Source,
+ typename _Require = _Path<_Source>>
+ path(_Source const& __source)
+ : _M_pathname(_S_convert(_S_range_begin(__source),
+ _S_range_end(__source)))
+ { _M_split_cmpts(); }
+
+ template<typename _InputIterator,
+ typename _Require = _Path<_InputIterator, _InputIterator>>
+ path(_InputIterator __first, _InputIterator __last)
+ : _M_pathname(_S_convert(__first, __last))
+ { _M_split_cmpts(); }
+
+ template<typename _Source,
+ typename _Require = _Path<_Source>,
+ typename _Require2 = __value_type_is_char<_Source>>
+ path(_Source const& __source, const locale& __loc)
+ : _M_pathname(_S_convert_loc(_S_range_begin(__source),
+ _S_range_end(__source), __loc))
+ { _M_split_cmpts(); }
+
+ template<typename _InputIterator,
+ typename _Require = _Path<_InputIterator, _InputIterator>,
+ typename _Require2 = __value_type_is_char<_InputIterator>>
+ path(_InputIterator __first, _InputIterator __last, const locale& __loc)
+ : _M_pathname(_S_convert_loc(__first, __last, __loc))
+ { _M_split_cmpts(); }
+
+ ~path() = default;
+
+ // assignments
+
+ path& operator=(const path& __p) = default;
+ path& operator=(path&& __p) noexcept;
+ path& operator=(string_type&& __source);
+ path& assign(string_type&& __source);
+
+ template<typename _Source>
+ _Path<_Source>&
+ operator=(_Source const& __source)
+ { return *this = path(__source); }
+
+ template<typename _Source>
+ _Path<_Source>&
+ assign(_Source const& __source)
+ { return *this = path(__source); }
+
+ template<typename _InputIterator>
+ _Path<_InputIterator, _InputIterator>&
+ assign(_InputIterator __first, _InputIterator __last)
+ { return *this = path(__first, __last); }
+
+ // appends
+
+ path& operator/=(const path& __p)
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (__p.is_absolute()
+ || (__p.has_root_name() && __p.root_name() != root_name()))
+ operator=(__p);
+ else
+ {
+ string_type __pathname;
+ if (__p.has_root_directory())
+ __pathname = root_name().native();
+ else if (has_filename() || (!has_root_directory() && is_absolute()))
+ __pathname = _M_pathname + preferred_separator;
+ __pathname += __p.relative_path().native(); // XXX is this right?
+ _M_pathname.swap(__pathname);
+ _M_split_cmpts();
+ }
+#else
+ // Much simpler, as any path with root-name or root-dir is absolute.
+ if (__p.is_absolute())
+ operator=(__p);
+ else
+ {
+ if (has_filename() || (_M_type == _Type::_Root_name))
+ _M_pathname += preferred_separator;
+ _M_pathname += __p.native();
+ _M_split_cmpts();
+ }
+#endif
+ return *this;
+ }
+
+ template <class _Source>
+ _Path<_Source>&
+ operator/=(_Source const& __source)
+ { return append(__source); }
+
+ template<typename _Source>
+ _Path<_Source>&
+ append(_Source const& __source)
+ {
+ return _M_append(_S_convert(_S_range_begin(__source),
+ _S_range_end(__source)));
+ }
+
+ template<typename _InputIterator>
+ _Path<_InputIterator, _InputIterator>&
+ append(_InputIterator __first, _InputIterator __last)
+ { return _M_append(_S_convert(__first, __last)); }
+
+ // concatenation
+
+ path& operator+=(const path& __x);
+ path& operator+=(const string_type& __x);
+ path& operator+=(const value_type* __x);
+ path& operator+=(value_type __x);
+ path& operator+=(basic_string_view<value_type> __x);
+
+ template<typename _Source>
+ _Path<_Source>&
+ operator+=(_Source const& __x) { return concat(__x); }
+
+ template<typename _CharT>
+ _Path<_CharT*, _CharT*>&
+ operator+=(_CharT __x);
+
+ template<typename _Source>
+ _Path<_Source>&
+ concat(_Source const& __x)
+ { return *this += _S_convert(_S_range_begin(__x), _S_range_end(__x)); }
+
+ template<typename _InputIterator>
+ _Path<_InputIterator, _InputIterator>&
+ concat(_InputIterator __first, _InputIterator __last)
+ { return *this += _S_convert(__first, __last); }
+
+ // modifiers
+
+ void clear() noexcept { _M_pathname.clear(); _M_split_cmpts(); }
+
+ path& make_preferred();
+ path& remove_filename();
+ path& replace_filename(const path& __replacement);
+ path& replace_extension(const path& __replacement = path());
+
+ void swap(path& __rhs) noexcept;
+
+ // native format observers
+
+ const string_type& native() const noexcept { return _M_pathname; }
+ const value_type* c_str() const noexcept { return _M_pathname.c_str(); }
+ operator string_type() const { return _M_pathname; }
+
+ template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
+ typename _Allocator = std::allocator<_CharT>>
+ std::basic_string<_CharT, _Traits, _Allocator>
+ string(const _Allocator& __a = _Allocator()) const;
+
+ std::string string() const;
+#if _GLIBCXX_USE_WCHAR_T
+ std::wstring wstring() const;
+#endif
+ std::string u8string() const;
+ std::u16string u16string() const;
+ std::u32string u32string() const;
+
+ // generic format observers
+ template<typename _CharT, typename _Traits = std::char_traits<_CharT>,
+ typename _Allocator = std::allocator<_CharT>>
+ std::basic_string<_CharT, _Traits, _Allocator>
+ generic_string(const _Allocator& __a = _Allocator()) const;
+
+ std::string generic_string() const;
+#if _GLIBCXX_USE_WCHAR_T
+ std::wstring generic_wstring() const;
+#endif
+ std::string generic_u8string() const;
+ std::u16string generic_u16string() const;
+ std::u32string generic_u32string() const;
+
+ // compare
+
+ int compare(const path& __p) const noexcept;
+ int compare(const string_type& __s) const;
+ int compare(const value_type* __s) const;
+ int compare(const basic_string_view<value_type> __s) const;
+
+ // decomposition
+
+ path root_name() const;
+ path root_directory() const;
+ path root_path() const;
+ path relative_path() const;
+ path parent_path() const;
+ path filename() const;
+ path stem() const;
+ path extension() const;
+
+ // query
+
+ bool empty() const noexcept { return _M_pathname.empty(); }
+ bool has_root_name() const;
+ bool has_root_directory() const;
+ bool has_root_path() const;
+ bool has_relative_path() const;
+ bool has_parent_path() const;
+ bool has_filename() const;
+ bool has_stem() const;
+ bool has_extension() const;
+ bool is_absolute() const;
+ bool is_relative() const { return !is_absolute(); }
+
+ // generation
+ path lexically_normal() const;
+ path lexically_relative(const path& base) const;
+ path lexically_proximate(const path& base) const;
+
+ // iterators
+ class iterator;
+ typedef iterator const_iterator;
+
+ iterator begin() const;
+ iterator end() const;
+
+ private:
+ enum class _Type : unsigned char {
+ _Multi, _Root_name, _Root_dir, _Filename
+ };
+
+ path(string_type __str, _Type __type) : _M_pathname(__str), _M_type(__type)
+ {
+ __glibcxx_assert(_M_type != _Type::_Multi);
+ }
+
+ enum class _Split { _Stem, _Extension };
+
+ path& _M_append(string_type&& __str)
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ operator/=(path(std::move(__str)));
+#else
+ if (!_M_pathname.empty() && !_S_is_dir_sep(_M_pathname.back())
+ && (__str.empty() || !_S_is_dir_sep(__str.front())))
+ _M_pathname += preferred_separator;
+ _M_pathname += __str;
+ _M_split_cmpts();
+#endif
+ return *this;
+ }
+
+ pair<const string_type*, size_t> _M_find_extension() const;
+
+ template<typename _CharT>
+ struct _Cvt;
+
+ static string_type
+ _S_convert(value_type* __src, __null_terminated)
+ { return string_type(__src); }
+
+ static string_type
+ _S_convert(const value_type* __src, __null_terminated)
+ { return string_type(__src); }
+
+ template<typename _Iter>
+ static string_type
+ _S_convert(_Iter __first, _Iter __last)
+ {
+ using __value_type = typename std::iterator_traits<_Iter>::value_type;
+ return _Cvt<typename remove_cv<__value_type>::type>::
+ _S_convert(__first, __last);
+ }
+
+ template<typename _InputIterator>
+ static string_type
+ _S_convert(_InputIterator __src, __null_terminated)
+ {
+ using _Tp = typename std::iterator_traits<_InputIterator>::value_type;
+ std::basic_string<typename remove_cv<_Tp>::type> __tmp;
+ for (; *__src != _Tp{}; ++__src)
+ __tmp.push_back(*__src);
+ return _S_convert(__tmp.c_str(), __tmp.c_str() + __tmp.size());
+ }
+
+ static string_type
+ _S_convert_loc(const char* __first, const char* __last,
+ const std::locale& __loc);
+
+ template<typename _Iter>
+ static string_type
+ _S_convert_loc(_Iter __first, _Iter __last, const std::locale& __loc)
+ {
+ const std::string __str(__first, __last);
+ return _S_convert_loc(__str.data(), __str.data()+__str.size(), __loc);
+ }
+
+ template<typename _InputIterator>
+ static string_type
+ _S_convert_loc(_InputIterator __src, __null_terminated,
+ const std::locale& __loc)
+ {
+ std::string __tmp;
+ while (*__src != '\0')
+ __tmp.push_back(*__src++);
+ return _S_convert_loc(__tmp.data(), __tmp.data()+__tmp.size(), __loc);
+ }
+
+ template<typename _CharT, typename _Traits, typename _Allocator>
+ static basic_string<_CharT, _Traits, _Allocator>
+ _S_str_convert(const string_type&, const _Allocator& __a);
+
+ bool _S_is_dir_sep(value_type __ch)
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ return __ch == L'/' || __ch == preferred_separator;
+#else
+ return __ch == '/';
+#endif
+ }
+
+ void _M_split_cmpts();
+ void _M_trim();
+ void _M_add_root_name(size_t __n);
+ void _M_add_root_dir(size_t __pos);
+ void _M_add_filename(size_t __pos, size_t __n);
+
+ string_type _M_pathname;
+
+ struct _Cmpt;
+ using _List = _GLIBCXX_STD_C::vector<_Cmpt>;
+ _List _M_cmpts; // empty unless _M_type == _Type::_Multi
+ _Type _M_type = _Type::_Multi;
+ };
+
+ template<>
+ struct path::__is_encoded_char<char> : std::true_type
+ { using value_type = char; };
+
+ template<>
+ struct path::__is_encoded_char<wchar_t> : std::true_type
+ { using value_type = wchar_t; };
+
+ template<>
+ struct path::__is_encoded_char<char16_t> : std::true_type
+ { using value_type = char16_t; };
+
+ template<>
+ struct path::__is_encoded_char<char32_t> : std::true_type
+ { using value_type = char32_t; };
+
+ template<typename _Tp>
+ struct path::__is_encoded_char<const _Tp> : __is_encoded_char<_Tp> { };
+
+ inline void swap(path& __lhs, path& __rhs) noexcept { __lhs.swap(__rhs); }
+
+ size_t hash_value(const path& __p) noexcept;
+
+ /// Compare paths
+ inline bool operator<(const path& __lhs, const path& __rhs) noexcept
+ { return __lhs.compare(__rhs) < 0; }
+
+ /// Compare paths
+ inline bool operator<=(const path& __lhs, const path& __rhs) noexcept
+ { return !(__rhs < __lhs); }
+
+ /// Compare paths
+ inline bool operator>(const path& __lhs, const path& __rhs) noexcept
+ { return __rhs < __lhs; }
+
+ /// Compare paths
+ inline bool operator>=(const path& __lhs, const path& __rhs) noexcept
+ { return !(__lhs < __rhs); }
+
+ /// Compare paths
+ inline bool operator==(const path& __lhs, const path& __rhs) noexcept
+ { return __lhs.compare(__rhs) == 0; }
+
+ /// Compare paths
+ inline bool operator!=(const path& __lhs, const path& __rhs) noexcept
+ { return !(__lhs == __rhs); }
+
+ /// Append one path to another
+ inline path operator/(const path& __lhs, const path& __rhs)
+ { return path(__lhs) /= __rhs; }
+
+ /// Write a path to a stream
+ template<typename _CharT, typename _Traits>
+ basic_ostream<_CharT, _Traits>&
+ operator<<(basic_ostream<_CharT, _Traits>& __os, const path& __p)
+ {
+ auto __tmp = __p.string<_CharT, _Traits>();
+ using __quoted_string
+ = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
+ __os << __quoted_string{__tmp, '"', '\\'};
+ return __os;
+ }
+
+ /// Read a path from a stream
+ template<typename _CharT, typename _Traits>
+ basic_istream<_CharT, _Traits>&
+ operator>>(basic_istream<_CharT, _Traits>& __is, path& __p)
+ {
+ basic_string<_CharT, _Traits> __tmp;
+ using __quoted_string
+ = std::__detail::_Quoted_string<decltype(__tmp)&, _CharT>;
+ if (__is >> __quoted_string{ __tmp, '"', '\\' })
+ __p = std::move(__tmp);
+ return __is;
+ }
+
+ template<typename _Source>
+ inline auto
+ u8path(const _Source& __source)
+ -> decltype(filesystem::path(__source, std::locale::classic()))
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ const std::string __u8str{__source};
+ return std::filesystem::u8path(__u8str.begin(), __u8str.end());
+#else
+ return path{ __source };
+#endif
+ }
+
+ template<typename _InputIterator>
+ inline auto
+ u8path(_InputIterator __first, _InputIterator __last)
+ -> decltype(filesystem::path(__first, __last, std::locale::classic()))
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ codecvt_utf8<value_type> __cvt;
+ string_type __tmp;
+ if (__str_codecvt_in(__first, __last, __tmp, __cvt))
+ return path{ __tmp };
+ else
+ return {};
+#else
+ return path{ __first, __last };
+#endif
+ }
+
+ class filesystem_error : public std::system_error
+ {
+ public:
+ filesystem_error(const string& __what_arg, error_code __ec)
+ : system_error(__ec, __what_arg) { }
+
+ filesystem_error(const string& __what_arg, const path& __p1,
+ error_code __ec)
+ : system_error(__ec, __what_arg), _M_path1(__p1) { }
+
+ filesystem_error(const string& __what_arg, const path& __p1,
+ const path& __p2, error_code __ec)
+ : system_error(__ec, __what_arg), _M_path1(__p1), _M_path2(__p2)
+ { }
+
+ ~filesystem_error();
+
+ const path& path1() const noexcept { return _M_path1; }
+ const path& path2() const noexcept { return _M_path2; }
+ const char* what() const noexcept { return _M_what.c_str(); }
+
+ private:
+ std::string _M_gen_what();
+
+ path _M_path1;
+ path _M_path2;
+ std::string _M_what = _M_gen_what();
+ };
+
+ struct path::_Cmpt : path
+ {
+ _Cmpt(string_type __s, _Type __t, size_t __pos)
+ : path(std::move(__s), __t), _M_pos(__pos) { }
+
+ _Cmpt() : _M_pos(-1) { }
+
+ size_t _M_pos;
+ };
+
+ // specialize _Cvt for degenerate 'noconv' case
+ template<>
+ struct path::_Cvt<path::value_type>
+ {
+ template<typename _Iter>
+ static string_type
+ _S_convert(_Iter __first, _Iter __last)
+ { return string_type{__first, __last}; }
+ };
+
+ template<typename _CharT>
+ struct path::_Cvt
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ static string_type
+ _S_wconvert(const char* __f, const char* __l, true_type)
+ {
+ using _Cvt = std::codecvt<wchar_t, char, mbstate_t>;
+ const auto& __cvt = std::use_facet<_Cvt>(std::locale{});
+ std::wstring __wstr;
+ if (__str_codecvt_in(__f, __l, __wstr, __cvt))
+ return __wstr;
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "Cannot convert character sequence",
+ std::make_error_code(errc::illegal_byte_sequence)));
+ }
+
+ static string_type
+ _S_wconvert(const _CharT* __f, const _CharT* __l, false_type)
+ {
+ std::codecvt_utf8<_CharT> __cvt;
+ std::string __str;
+ if (__str_codecvt_out(__f, __l, __str, __cvt))
+ {
+ const char* __f2 = __str.data();
+ const char* __l2 = __f2 + __str.size();
+ std::codecvt_utf8<wchar_t> __wcvt;
+ std::wstring __wstr;
+ if (__str_codecvt_in(__f2, __l2, __wstr, __wcvt))
+ return __wstr;
+ }
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "Cannot convert character sequence",
+ std::make_error_code(errc::illegal_byte_sequence)));
+ }
+
+ static string_type
+ _S_convert(const _CharT* __f, const _CharT* __l)
+ {
+ return _S_wconvert(__f, __l, is_same<_CharT, char>{});
+ }
+#else
+ static string_type
+ _S_convert(const _CharT* __f, const _CharT* __l)
+ {
+ std::codecvt_utf8<_CharT> __cvt;
+ std::string __str;
+ if (__str_codecvt_out(__f, __l, __str, __cvt))
+ return __str;
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "Cannot convert character sequence",
+ std::make_error_code(errc::illegal_byte_sequence)));
+ }
+#endif
+
+ static string_type
+ _S_convert(_CharT* __f, _CharT* __l)
+ {
+ return _S_convert(const_cast<const _CharT*>(__f),
+ const_cast<const _CharT*>(__l));
+ }
+
+ template<typename _Iter>
+ static string_type
+ _S_convert(_Iter __first, _Iter __last)
+ {
+ const std::basic_string<_CharT> __str(__first, __last);
+ return _S_convert(__str.data(), __str.data() + __str.size());
+ }
+
+ template<typename _Iter, typename _Cont>
+ static string_type
+ _S_convert(__gnu_cxx::__normal_iterator<_Iter, _Cont> __first,
+ __gnu_cxx::__normal_iterator<_Iter, _Cont> __last)
+ { return _S_convert(__first.base(), __last.base()); }
+ };
+
+ /// An iterator for the components of a path
+ class path::iterator
+ {
+ public:
+ using difference_type = std::ptrdiff_t;
+ using value_type = path;
+ using reference = const path&;
+ using pointer = const path*;
+ using iterator_category = std::bidirectional_iterator_tag;
+
+ iterator() : _M_path(nullptr), _M_cur(), _M_at_end() { }
+
+ iterator(const iterator&) = default;
+ iterator& operator=(const iterator&) = default;
+
+ reference operator*() const;
+ pointer operator->() const { return std::__addressof(**this); }
+
+ iterator& operator++();
+ iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
+
+ iterator& operator--();
+ iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; }
+
+ friend bool operator==(const iterator& __lhs, const iterator& __rhs)
+ { return __lhs._M_equals(__rhs); }
+
+ friend bool operator!=(const iterator& __lhs, const iterator& __rhs)
+ { return !__lhs._M_equals(__rhs); }
+
+ private:
+ friend class path;
+
+ iterator(const path* __path, path::_List::const_iterator __iter)
+ : _M_path(__path), _M_cur(__iter), _M_at_end()
+ { }
+
+ iterator(const path* __path, bool __at_end)
+ : _M_path(__path), _M_cur(), _M_at_end(__at_end)
+ { }
+
+ bool _M_equals(iterator) const;
+
+ const path* _M_path;
+ path::_List::const_iterator _M_cur;
+ bool _M_at_end; // only used when type != _Multi
+ };
+
+
+ inline path&
+ path::operator=(path&& __p) noexcept
+ {
+ _M_pathname = std::move(__p._M_pathname);
+ _M_cmpts = std::move(__p._M_cmpts);
+ _M_type = __p._M_type;
+ __p.clear();
+ return *this;
+ }
+
+ inline path&
+ path::operator=(string_type&& __source)
+ { return *this = path(std::move(__source)); }
+
+ inline path&
+ path::assign(string_type&& __source)
+ { return *this = path(std::move(__source)); }
+
+ inline path&
+ path::operator+=(const path& __p)
+ {
+ return operator+=(__p.native());
+ }
+
+ inline path&
+ path::operator+=(const string_type& __x)
+ {
+ _M_pathname += __x;
+ _M_split_cmpts();
+ return *this;
+ }
+
+ inline path&
+ path::operator+=(const value_type* __x)
+ {
+ _M_pathname += __x;
+ _M_split_cmpts();
+ return *this;
+ }
+
+ inline path&
+ path::operator+=(value_type __x)
+ {
+ _M_pathname += __x;
+ _M_split_cmpts();
+ return *this;
+ }
+
+ inline path&
+ path::operator+=(basic_string_view<value_type> __x)
+ {
+ _M_pathname.append(__x.data(), __x.size());
+ _M_split_cmpts();
+ return *this;
+ }
+
+ template<typename _CharT>
+ inline path::_Path<_CharT*, _CharT*>&
+ path::operator+=(_CharT __x)
+ {
+ auto* __addr = std::__addressof(__x);
+ return concat(__addr, __addr + 1);
+ }
+
+ inline path&
+ path::make_preferred()
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ std::replace(_M_pathname.begin(), _M_pathname.end(), L'/',
+ preferred_separator);
+#endif
+ return *this;
+ }
+
+ inline void path::swap(path& __rhs) noexcept
+ {
+ _M_pathname.swap(__rhs._M_pathname);
+ _M_cmpts.swap(__rhs._M_cmpts);
+ std::swap(_M_type, __rhs._M_type);
+ }
+
+ template<typename _CharT, typename _Traits, typename _Allocator>
+ std::basic_string<_CharT, _Traits, _Allocator>
+ path::_S_str_convert(const string_type& __str, const _Allocator& __a)
+ {
+ if (__str.size() == 0)
+ return std::basic_string<_CharT, _Traits, _Allocator>(__a);
+
+ const value_type* __first = __str.data();
+ const value_type* __last = __first + __str.size();
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ using _CharAlloc = __alloc_rebind<_Allocator, char>;
+ using _String = basic_string<char, char_traits<char>, _CharAlloc>;
+ using _WString = basic_string<_CharT, _Traits, _Allocator>;
+
+ // use codecvt_utf8<wchar_t> to convert native string to UTF-8
+ codecvt_utf8<value_type> __cvt;
+ _String __u8str{_CharAlloc{__a}};
+ if (__str_codecvt_out(__first, __last, __u8str, __cvt))
+ {
+ if constexpr (is_same_v<_CharT, char>)
+ return __u8str;
+ else
+ {
+ _WString __wstr;
+ // use codecvt_utf8<_CharT> to convert UTF-8 to wide string
+ codecvt_utf8<_CharT> __cvt;
+ const char* __f = __u8str.data();
+ const char* __l = __f + __u8str.size();
+ if (__str_codecvt_in(__f, __l, __wstr, __cvt))
+ return __wstr;
+ }
+ }
+#else
+ codecvt_utf8<_CharT> __cvt;
+ basic_string<_CharT, _Traits, _Allocator> __wstr{__a};
+ if (__str_codecvt_in(__first, __last, __wstr, __cvt))
+ return __wstr;
+#endif
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "Cannot convert character sequence",
+ std::make_error_code(errc::illegal_byte_sequence)));
+ }
+
+ template<typename _CharT, typename _Traits, typename _Allocator>
+ inline basic_string<_CharT, _Traits, _Allocator>
+ path::string(const _Allocator& __a) const
+ {
+ if constexpr (is_same_v<_CharT, value_type>)
+#if _GLIBCXX_USE_CXX11_ABI
+ return { _M_pathname, __a };
+#else
+ return { _M_pathname, string_type::size_type(0), __a };
+#endif
+ else
+ return _S_str_convert<_CharT, _Traits>(_M_pathname, __a);
+ }
+
+ inline std::string
+ path::string() const { return string<char>(); }
+
+#if _GLIBCXX_USE_WCHAR_T
+ inline std::wstring
+ path::wstring() const { return string<wchar_t>(); }
+#endif
+
+ inline std::string
+ path::u8string() const
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ std::string __str;
+ // convert from native encoding to UTF-8
+ codecvt_utf8<value_type> __cvt;
+ const value_type* __first = _M_pathname.data();
+ const value_type* __last = __first + _M_pathname.size();
+ if (__str_codecvt_out(__first, __last, __str, __cvt))
+ return __str;
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "Cannot convert character sequence",
+ std::make_error_code(errc::illegal_byte_sequence)));
+#else
+ return _M_pathname;
+#endif
+ }
+
+ inline std::u16string
+ path::u16string() const { return string<char16_t>(); }
+
+ inline std::u32string
+ path::u32string() const { return string<char32_t>(); }
+
+ template<typename _CharT, typename _Traits, typename _Allocator>
+ inline std::basic_string<_CharT, _Traits, _Allocator>
+ path::generic_string(const _Allocator& __a) const
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ const value_type __slash = L'/';
+#else
+ const value_type __slash = '/';
+#endif
+ string_type __str(__a);
+
+ if (_M_type == _Type::_Root_dir)
+ __str.assign(1, __slash);
+ else
+ {
+ __str.reserve(_M_pathname.size());
+ bool __add_slash = false;
+ for (auto& __elem : *this)
+ {
+ if (__add_slash)
+ __str += __slash;
+ __str += __elem._M_pathname;
+ __add_slash = __elem._M_type == _Type::_Filename;
+ }
+ }
+
+ if constexpr (is_same_v<_CharT, value_type>)
+ return __str;
+ else
+ return _S_str_convert<_CharT, _Traits>(__str, __a);
+ }
+
+ inline std::string
+ path::generic_string() const
+ { return generic_string<char>(); }
+
+#if _GLIBCXX_USE_WCHAR_T
+ inline std::wstring
+ path::generic_wstring() const
+ { return generic_string<wchar_t>(); }
+#endif
+
+ inline std::string
+ path::generic_u8string() const
+ { return generic_string(); }
+
+ inline std::u16string
+ path::generic_u16string() const
+ { return generic_string<char16_t>(); }
+
+ inline std::u32string
+ path::generic_u32string() const
+ { return generic_string<char32_t>(); }
+
+ inline int
+ path::compare(const string_type& __s) const { return compare(path(__s)); }
+
+ inline int
+ path::compare(const value_type* __s) const { return compare(path(__s)); }
+
+ inline int
+ path::compare(basic_string_view<value_type> __s) const
+ { return compare(path(__s)); }
+
+ inline path
+ path::filename() const
+ {
+ if (empty())
+ return {};
+ else if (_M_type == _Type::_Filename)
+ return *this;
+ else if (_M_type == _Type::_Multi)
+ {
+ if (_M_pathname.back() == preferred_separator)
+ return {};
+ auto& __last = *--end();
+ if (__last._M_type == _Type::_Filename)
+ return __last;
+ }
+ return {};
+ }
+
+ inline path
+ path::stem() const
+ {
+ auto ext = _M_find_extension();
+ if (ext.first && ext.second != 0)
+ return path{ext.first->substr(0, ext.second)};
+ return {};
+ }
+
+ inline path
+ path::extension() const
+ {
+ auto ext = _M_find_extension();
+ if (ext.first && ext.second != string_type::npos)
+ return path{ext.first->substr(ext.second)};
+ return {};
+ }
+
+ inline bool
+ path::has_stem() const
+ {
+ auto ext = _M_find_extension();
+ return ext.first && ext.second != 0;
+ }
+
+ inline bool
+ path::has_extension() const
+ {
+ auto ext = _M_find_extension();
+ return ext.first && ext.second != string_type::npos;
+ }
+
+ inline bool
+ path::is_absolute() const
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ return has_root_name();
+#else
+ return has_root_directory();
+#endif
+ }
+
+ inline path::iterator
+ path::begin() const
+ {
+ if (_M_type == _Type::_Multi)
+ return iterator(this, _M_cmpts.begin());
+ return iterator(this, false);
+ }
+
+ inline path::iterator
+ path::end() const
+ {
+ if (_M_type == _Type::_Multi)
+ return iterator(this, _M_cmpts.end());
+ return iterator(this, true);
+ }
+
+ inline path::iterator&
+ path::iterator::operator++()
+ {
+ __glibcxx_assert(_M_path != nullptr);
+ if (_M_path->_M_type == _Type::_Multi)
+ {
+ __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
+ ++_M_cur;
+ }
+ else
+ {
+ __glibcxx_assert(!_M_at_end);
+ _M_at_end = true;
+ }
+ return *this;
+ }
+
+ inline path::iterator&
+ path::iterator::operator--()
+ {
+ __glibcxx_assert(_M_path != nullptr);
+ if (_M_path->_M_type == _Type::_Multi)
+ {
+ __glibcxx_assert(_M_cur != _M_path->_M_cmpts.begin());
+ --_M_cur;
+ }
+ else
+ {
+ __glibcxx_assert(_M_at_end);
+ _M_at_end = false;
+ }
+ return *this;
+ }
+
+ inline path::iterator::reference
+ path::iterator::operator*() const
+ {
+ __glibcxx_assert(_M_path != nullptr);
+ if (_M_path->_M_type == _Type::_Multi)
+ {
+ __glibcxx_assert(_M_cur != _M_path->_M_cmpts.end());
+ return *_M_cur;
+ }
+ return *_M_path;
+ }
+
+ inline bool
+ path::iterator::_M_equals(iterator __rhs) const
+ {
+ if (_M_path != __rhs._M_path)
+ return false;
+ if (_M_path == nullptr)
+ return true;
+ if (_M_path->_M_type == path::_Type::_Multi)
+ return _M_cur == __rhs._M_cur;
+ return _M_at_end == __rhs._M_at_end;
+ }
+
+ // @} group filesystem
+_GLIBCXX_END_NAMESPACE_CXX11
+} // namespace filesystem
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // C++17
+
+#endif // _GLIBCXX_FS_PATH_H
diff --git a/libstdc++-v3/include/bits/functional_hash.h b/libstdc++-v3/include/bits/functional_hash.h
index 38be172..c093684 100644
--- a/libstdc++-v3/include/bits/functional_hash.h
+++ b/libstdc++-v3/include/bits/functional_hash.h
@@ -49,8 +49,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Result, typename _Arg>
struct __hash_base
{
- typedef _Result result_type;
- typedef _Arg argument_type;
+ typedef _Result result_type _GLIBCXX17_DEPRECATED;
+ typedef _Arg argument_type _GLIBCXX17_DEPRECATED;
};
/// Primary class template hash.
diff --git a/libstdc++-v3/include/bits/specfun.h b/libstdc++-v3/include/bits/specfun.h
index 0aaebea..6bb3ec0 100644
--- a/libstdc++-v3/include/bits/specfun.h
+++ b/libstdc++-v3/include/bits/specfun.h
@@ -1201,6 +1201,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
+#ifndef __STRICT_ANSI__
namespace __gnu_cxx _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION
@@ -1305,6 +1306,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace __gnu_cxx
+#endif // __STRICT_ANSI__
#pragma GCC visibility pop
diff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h
index d24e760..ac54884 100644
--- a/libstdc++-v3/include/bits/stl_bvector.h
+++ b/libstdc++-v3/include/bits/stl_bvector.h
@@ -417,7 +417,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
if (__last._M_offset != 0)
__fill_bvector(__last._M_p, 0, __last._M_offset, __x);
}
- else
+ else if (__first._M_offset != __last._M_offset)
__fill_bvector(__first._M_p, __first._M_offset, __last._M_offset, __x);
}
diff --git a/libstdc++-v3/include/bits/stl_map.h b/libstdc++-v3/include/bits/stl_map.h
index 0e8a98a..bad6020 100644
--- a/libstdc++-v3/include/bits/stl_map.h
+++ b/libstdc++-v3/include/bits/stl_map.h
@@ -778,7 +778,6 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
/**
* @brief Attempts to insert a std::pair into the %map.
-
* @param __x Pair to be inserted (see std::make_pair for easy
* creation of pairs).
*
@@ -791,12 +790,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* first element (the key) is not already present in the %map.
*
* Insertion requires logarithmic time.
+ * @{
*/
std::pair<iterator, bool>
insert(const value_type& __x)
{ return _M_t._M_insert_unique(__x); }
#if __cplusplus >= 201103L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2354. Unnecessary copying when inserting into maps with braced-init
+ std::pair<iterator, bool>
+ insert(value_type&& __x)
+ { return _M_t._M_insert_unique(std::move(__x)); }
+
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
@@ -804,6 +810,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
insert(_Pair&& __x)
{ return _M_t._M_insert_unique(std::forward<_Pair>(__x)); }
#endif
+ // @}
#if __cplusplus >= 201103L
/**
@@ -840,6 +847,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* for more on @a hinting.
*
* Insertion requires logarithmic time (if the hint is not taken).
+ * @{
*/
iterator
#if __cplusplus >= 201103L
@@ -850,6 +858,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{ return _M_t._M_insert_unique_(__position, __x); }
#if __cplusplus >= 201103L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2354. Unnecessary copying when inserting into maps with braced-init
+ iterator
+ insert(const_iterator __position, value_type&& __x)
+ { return _M_t._M_insert_unique_(__position, std::move(__x)); }
+
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
@@ -858,6 +872,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{ return _M_t._M_insert_unique_(__position,
std::forward<_Pair>(__x)); }
#endif
+ // @}
/**
* @brief Template function that attempts to insert a range of elements.
diff --git a/libstdc++-v3/include/bits/stl_multimap.h b/libstdc++-v3/include/bits/stl_multimap.h
index 7e3cea4..6f5cb7a 100644
--- a/libstdc++-v3/include/bits/stl_multimap.h
+++ b/libstdc++-v3/include/bits/stl_multimap.h
@@ -526,12 +526,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* thus multiple pairs with the same key can be inserted.
*
* Insertion requires logarithmic time.
+ * @{
*/
iterator
insert(const value_type& __x)
{ return _M_t._M_insert_equal(__x); }
#if __cplusplus >= 201103L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2354. Unnecessary copying when inserting into maps with braced-init
+ iterator
+ insert(value_type&& __x)
+ { return _M_t._M_insert_equal(std::move(__x)); }
+
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
@@ -539,6 +546,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
insert(_Pair&& __x)
{ return _M_t._M_insert_equal(std::forward<_Pair>(__x)); }
#endif
+ // @}
/**
* @brief Inserts a std::pair into the %multimap.
@@ -559,6 +567,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
* https://gcc.gnu.org/onlinedocs/libstdc++/manual/associative.html#containers.associative.insert_hints
*
* Insertion requires logarithmic time (if the hint is not taken).
+ * @{
*/
iterator
#if __cplusplus >= 201103L
@@ -569,6 +578,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{ return _M_t._M_insert_equal_(__position, __x); }
#if __cplusplus >= 201103L
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2354. Unnecessary copying when inserting into maps with braced-init
+ iterator
+ insert(const_iterator __position, value_type&& __x)
+ { return _M_t._M_insert_equal_(__position, std::move(__x)); }
+
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
@@ -577,6 +592,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
{ return _M_t._M_insert_equal_(__position,
std::forward<_Pair>(__x)); }
#endif
+ // @}
/**
* @brief A template function that attempts to insert a range
diff --git a/libstdc++-v3/include/bits/streambuf_iterator.h b/libstdc++-v3/include/bits/streambuf_iterator.h
index f0451b1..081afe5 100644
--- a/libstdc++-v3/include/bits/streambuf_iterator.h
+++ b/libstdc++-v3/include/bits/streambuf_iterator.h
@@ -95,7 +95,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// NB: This implementation assumes the "end of stream" value
// is EOF, or -1.
mutable streambuf_type* _M_sbuf;
- mutable int_type _M_c;
+ int_type _M_c;
public:
/// Construct end of input stream iterator.
@@ -122,28 +122,29 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
char_type
operator*() const
{
+ int_type __c = _M_get();
+
#ifdef _GLIBCXX_DEBUG_PEDANTIC
// Dereferencing a past-the-end istreambuf_iterator is a
// libstdc++ extension
- __glibcxx_requires_cond(!_M_at_eof(),
+ __glibcxx_requires_cond(!_S_is_eof(__c),
_M_message(__gnu_debug::__msg_deref_istreambuf)
._M_iterator(*this));
#endif
- return traits_type::to_char_type(_M_get());
+ return traits_type::to_char_type(__c);
}
/// Advance the iterator. Calls streambuf.sbumpc().
istreambuf_iterator&
operator++()
{
- __glibcxx_requires_cond(!_M_at_eof(),
+ __glibcxx_requires_cond(_M_sbuf &&
+ (!_S_is_eof(_M_c) || !_S_is_eof(_M_sbuf->sgetc())),
_M_message(__gnu_debug::__msg_inc_istreambuf)
._M_iterator(*this));
- if (_M_sbuf)
- {
- _M_sbuf->sbumpc();
- _M_c = traits_type::eof();
- }
+
+ _M_sbuf->sbumpc();
+ _M_c = traits_type::eof();
return *this;
}
@@ -151,22 +152,20 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
istreambuf_iterator
operator++(int)
{
- __glibcxx_requires_cond(!_M_at_eof(),
+ __glibcxx_requires_cond(_M_sbuf &&
+ (!_S_is_eof(_M_c) || !_S_is_eof(_M_sbuf->sgetc())),
_M_message(__gnu_debug::__msg_inc_istreambuf)
._M_iterator(*this));
istreambuf_iterator __old = *this;
- if (_M_sbuf)
- {
- __old._M_c = _M_sbuf->sbumpc();
- _M_c = traits_type::eof();
- }
+ __old._M_c = _M_sbuf->sbumpc();
+ _M_c = traits_type::eof();
return __old;
}
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 110 istreambuf_iterator::equal not const
- // NB: there is also number 111 (NAD, Future) pending on this function.
+ // NB: there is also number 111 (NAD) relevant to this function.
/// Return true both iterators are end or both are not end.
bool
equal(const istreambuf_iterator& __b) const
@@ -176,26 +175,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
int_type
_M_get() const
{
- const int_type __eof = traits_type::eof();
- int_type __ret = __eof;
- if (_M_sbuf)
- {
- if (!traits_type::eq_int_type(_M_c, __eof))
- __ret = _M_c;
- else if (!traits_type::eq_int_type((__ret = _M_sbuf->sgetc()),
- __eof))
- _M_c = __ret;
- else
- _M_sbuf = 0;
- }
+ int_type __ret = _M_c;
+ if (_M_sbuf && _S_is_eof(__ret) && _S_is_eof(__ret = _M_sbuf->sgetc()))
+ _M_sbuf = 0;
return __ret;
}
bool
_M_at_eof() const
+ { return _S_is_eof(_M_get()); }
+
+ static bool
+ _S_is_eof(int_type __c)
{
const int_type __eof = traits_type::eof();
- return traits_type::eq_int_type(_M_get(), __eof);
+ return traits_type::eq_int_type(__c, __eof);
}
};
@@ -373,13 +367,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
typedef typename __is_iterator_type::traits_type traits_type;
typedef typename __is_iterator_type::streambuf_type streambuf_type;
typedef typename traits_type::int_type int_type;
+ const int_type __eof = traits_type::eof();
if (__first._M_sbuf && !__last._M_sbuf)
{
const int_type __ival = traits_type::to_int_type(__val);
streambuf_type* __sb = __first._M_sbuf;
int_type __c = __sb->sgetc();
- while (!traits_type::eq_int_type(__c, traits_type::eof())
+ while (!traits_type::eq_int_type(__c, __eof)
&& !traits_type::eq_int_type(__c, __ival))
{
streamsize __n = __sb->egptr() - __sb->gptr();
@@ -396,11 +391,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__c = __sb->snextc();
}
- if (!traits_type::eq_int_type(__c, traits_type::eof()))
- __first._M_c = __c;
- else
- __first._M_sbuf = 0;
+ __first._M_c = __eof;
}
+
return __first;
}
diff --git a/libstdc++-v3/include/bits/string_view.tcc b/libstdc++-v3/include/bits/string_view.tcc
index 4d98f86..5c53c58 100644
--- a/libstdc++-v3/include/bits/string_view.tcc
+++ b/libstdc++-v3/include/bits/string_view.tcc
@@ -119,7 +119,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits>
constexpr typename basic_string_view<_CharT, _Traits>::size_type
basic_string_view<_CharT, _Traits>::
- find_first_of(const _CharT* __str, size_type __pos, size_type __n) const
+ find_first_of(const _CharT* __str, size_type __pos,
+ size_type __n) const noexcept
{
__glibcxx_requires_string_len(__str, __n);
for (; __n && __pos < this->_M_len; ++__pos)
@@ -135,7 +136,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits>
constexpr typename basic_string_view<_CharT, _Traits>::size_type
basic_string_view<_CharT, _Traits>::
- find_last_of(const _CharT* __str, size_type __pos, size_type __n) const
+ find_last_of(const _CharT* __str, size_type __pos,
+ size_type __n) const noexcept
{
__glibcxx_requires_string_len(__str, __n);
size_type __size = this->size();
@@ -156,7 +158,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits>
constexpr typename basic_string_view<_CharT, _Traits>::size_type
basic_string_view<_CharT, _Traits>::
- find_first_not_of(const _CharT* __str, size_type __pos, size_type __n) const
+ find_first_not_of(const _CharT* __str, size_type __pos,
+ size_type __n) const noexcept
{
__glibcxx_requires_string_len(__str, __n);
for (; __pos < this->_M_len; ++__pos)
@@ -179,7 +182,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _CharT, typename _Traits>
constexpr typename basic_string_view<_CharT, _Traits>::size_type
basic_string_view<_CharT, _Traits>::
- find_last_not_of(const _CharT* __str, size_type __pos, size_type __n) const
+ find_last_not_of(const _CharT* __str, size_type __pos,
+ size_type __n) const noexcept
{
__glibcxx_requires_string_len(__str, __n);
size_type __size = this->_M_len;
diff --git a/libstdc++-v3/include/bits/unordered_map.h b/libstdc++-v3/include/bits/unordered_map.h
index df1302c..2fd4cd5 100644
--- a/libstdc++-v3/include/bits/unordered_map.h
+++ b/libstdc++-v3/include/bits/unordered_map.h
@@ -579,6 +579,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
insert(const value_type& __x)
{ return _M_h.insert(__x); }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2354. Unnecessary copying when inserting into maps with braced-init
+ std::pair<iterator, bool>
+ insert(value_type&& __x)
+ { return _M_h.insert(std::move(__x)); }
+
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
@@ -613,6 +619,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
insert(const_iterator __hint, const value_type& __x)
{ return _M_h.insert(__hint, __x); }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2354. Unnecessary copying when inserting into maps with braced-init
+ iterator
+ insert(const_iterator __hint, value_type&& __x)
+ { return _M_h.insert(__hint, std::move(__x)); }
+
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
@@ -1468,6 +1480,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
insert(const value_type& __x)
{ return _M_h.insert(__x); }
+ iterator
+ insert(value_type&& __x)
+ { return _M_h.insert(std::move(__x)); }
+
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
@@ -1500,6 +1516,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
insert(const_iterator __hint, const value_type& __x)
{ return _M_h.insert(__hint, __x); }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2354. Unnecessary copying when inserting into maps with braced-init
+ iterator
+ insert(const_iterator __hint, value_type&& __x)
+ { return _M_h.insert(__hint, std::move(__x)); }
+
template<typename _Pair, typename = typename
std::enable_if<std::is_constructible<value_type,
_Pair&&>::value>::type>
diff --git a/libstdc++-v3/include/c_compatibility/complex.h b/libstdc++-v3/include/c_compatibility/complex.h
index b9af847..4b23439 100644
--- a/libstdc++-v3/include/c_compatibility/complex.h
+++ b/libstdc++-v3/include/c_compatibility/complex.h
@@ -32,7 +32,9 @@
# include <ccomplex>
#endif
-#if _GLIBCXX_HAVE_COMPLEX_H
+#if __cplusplus >= 201103L && defined(__STRICT_ANSI__)
+// For strict modes do not include the C library's <complex.h>, see PR 82417.
+#elif _GLIBCXX_HAVE_COMPLEX_H
# include_next <complex.h>
# ifdef _GLIBCXX_COMPLEX
// See PR56111, keep the macro in C++03 if possible.
diff --git a/libstdc++-v3/include/c_compatibility/math.h b/libstdc++-v3/include/c_compatibility/math.h
index 84755c8..28c7c83 100644
--- a/libstdc++-v3/include/c_compatibility/math.h
+++ b/libstdc++-v3/include/c_compatibility/math.h
@@ -111,7 +111,7 @@ using std::tgamma;
using std::trunc;
#endif // C++11 && _GLIBCXX_USE_C99_MATH_TR1
-#if __STDCPP_WANT_MATH_SPEC_FUNCS__ == 1
+#if _GLIBCXX_USE_STD_SPEC_FUNCS
using std::assoc_laguerref;
using std::assoc_laguerrel;
using std::assoc_laguerre;
@@ -175,7 +175,7 @@ using std::sph_legendre;
using std::sph_neumannf;
using std::sph_neumannl;
using std::sph_neumann;
-#endif // __STDCPP_WANT_MATH_SPEC_FUNCS__
+#endif // _GLIBCXX_USE_STD_SPEC_FUNCS
#endif // _GLIBCXX_MATH_H
#endif // __cplusplus
diff --git a/libstdc++-v3/include/c_global/cstddef b/libstdc++-v3/include/c_global/cstddef
index 09754ee..11d268b 100644
--- a/libstdc++-v3/include/c_global/cstddef
+++ b/libstdc++-v3/include/c_global/cstddef
@@ -57,9 +57,11 @@ namespace std
}
#endif
-#if __cplusplus > 201402L
+#if __cplusplus >= 201703L
namespace std
{
+#define __cpp_lib_byte 201603
+
/// std::byte
enum class byte : unsigned char {};
diff --git a/libstdc++-v3/include/experimental/bits/fs_dir.h b/libstdc++-v3/include/experimental/bits/fs_dir.h
index 1ff0d9b..ecadf37 100644
--- a/libstdc++-v3/include/experimental/bits/fs_dir.h
+++ b/libstdc++-v3/include/experimental/bits/fs_dir.h
@@ -49,7 +49,7 @@ namespace filesystem
inline namespace v1
{
/**
- * @ingroup filesystem
+ * @ingroup filesystem-ts
* @{
*/
@@ -351,7 +351,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
_GLIBCXX_END_NAMESPACE_CXX11
- // @} group filesystem
+ // @} group filesystem-ts
} // namespace v1
} // namespace filesystem
} // namespace experimental
diff --git a/libstdc++-v3/include/experimental/bits/fs_fwd.h b/libstdc++-v3/include/experimental/bits/fs_fwd.h
index 7b851a3..ac43c5f 100644
--- a/libstdc++-v3/include/experimental/bits/fs_fwd.h
+++ b/libstdc++-v3/include/experimental/bits/fs_fwd.h
@@ -53,7 +53,7 @@ inline namespace __cxx11 __attribute__((__abi_tag__ ("cxx11"))) { }
#endif
/**
- * @defgroup filesystem Filesystem
+ * @defgroup filesystem-ts Filesystem TS
* @ingroup experimental
*
* Utilities for performing operations on file systems and their components,
@@ -278,7 +278,7 @@ _GLIBCXX_END_NAMESPACE_CXX11
bool is_regular_file(file_status) noexcept;
bool is_symlink(file_status) noexcept;
- // @} group filesystem
+ // @} group filesystem-ts
} // namespace v1
} // namespace filesystem
} // namespace experimental
diff --git a/libstdc++-v3/include/experimental/bits/fs_ops.h b/libstdc++-v3/include/experimental/bits/fs_ops.h
index 3875372..fa7f1de 100644
--- a/libstdc++-v3/include/experimental/bits/fs_ops.h
+++ b/libstdc++-v3/include/experimental/bits/fs_ops.h
@@ -47,7 +47,7 @@ namespace filesystem
inline namespace v1
{
/**
- * @ingroup filesystem
+ * @ingroup filesystem-ts
* @{
*/
@@ -285,7 +285,7 @@ inline namespace v1
path temp_directory_path();
path temp_directory_path(error_code& __ec);
- // @} group filesystem
+ // @} group filesystem-ts
} // namespace v1
} // namespace filesystem
} // namespace experimental
diff --git a/libstdc++-v3/include/experimental/bits/fs_path.h b/libstdc++-v3/include/experimental/bits/fs_path.h
index cde3897..3e9bc63 100644
--- a/libstdc++-v3/include/experimental/bits/fs_path.h
+++ b/libstdc++-v3/include/experimental/bits/fs_path.h
@@ -72,7 +72,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
#endif
/**
- * @ingroup filesystem
+ * @ingroup filesystem-ts
* @{
*/
@@ -725,10 +725,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
pointer operator->() const { return std::__addressof(**this); }
iterator& operator++();
- iterator operator++(int) { auto __tmp = *this; ++_M_cur; return __tmp; }
+ iterator operator++(int) { auto __tmp = *this; ++*this; return __tmp; }
iterator& operator--();
- iterator operator--(int) { auto __tmp = *this; --_M_cur; return __tmp; }
+ iterator operator--(int) { auto __tmp = *this; --*this; return __tmp; }
friend bool operator==(const iterator& __lhs, const iterator& __rhs)
{ return __lhs._M_equals(__rhs); }
@@ -1079,7 +1079,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11
return _M_at_end == __rhs._M_at_end;
}
- // @} group filesystem
+ // @} group filesystem-ts
_GLIBCXX_END_NAMESPACE_CXX11
} // namespace v1
} // namespace filesystem
diff --git a/libstdc++-v3/include/experimental/filesystem b/libstdc++-v3/include/experimental/filesystem
index f0b19dd..90f6f9e 100644
--- a/libstdc++-v3/include/experimental/filesystem
+++ b/libstdc++-v3/include/experimental/filesystem
@@ -40,36 +40,6 @@
#define __cpp_lib_experimental_filesystem 201406
-namespace std _GLIBCXX_VISIBILITY(default)
-{
-_GLIBCXX_BEGIN_NAMESPACE_VERSION
-
-namespace experimental
-{
-namespace filesystem
-{
-inline namespace v1
-{
- /**
- * @ingroup filesystem
- */
- inline std::string filesystem_error::_M_gen_what()
- {
- std::string __what = "filesystem error: ";
- __what += system_error::what();
- if (!_M_path1.empty())
- __what += " [" + _M_path1.string() + ']';
- if (!_M_path2.empty())
- __what += " [" + _M_path2.string() + ']';
- return __what;
- }
-} // namespace v1
-} // namespace filesystem
-} // namespace experimental
-
-_GLIBCXX_END_NAMESPACE_VERSION
-} // namespace std
-
#endif // C++11
#endif // _GLIBCXX_EXPERIMENTAL_FILESYSTEM
diff --git a/libstdc++-v3/include/experimental/string_view b/libstdc++-v3/include/experimental/string_view
index f05f152..8eaf9ec 100644
--- a/libstdc++-v3/include/experimental/string_view
+++ b/libstdc++-v3/include/experimental/string_view
@@ -645,22 +645,22 @@ namespace experimental
inline namespace string_view_literals
{
inline constexpr basic_string_view<char>
- operator""sv(const char* __str, size_t __len)
+ operator""sv(const char* __str, size_t __len) noexcept
{ return basic_string_view<char>{__str, __len}; }
#ifdef _GLIBCXX_USE_WCHAR_T
inline constexpr basic_string_view<wchar_t>
- operator""sv(const wchar_t* __str, size_t __len)
+ operator""sv(const wchar_t* __str, size_t __len) noexcept
{ return basic_string_view<wchar_t>{__str, __len}; }
#endif
#ifdef _GLIBCXX_USE_C99_STDINT_TR1
inline constexpr basic_string_view<char16_t>
- operator""sv(const char16_t* __str, size_t __len)
+ operator""sv(const char16_t* __str, size_t __len) noexcept
{ return basic_string_view<char16_t>{__str, __len}; }
inline constexpr basic_string_view<char32_t>
- operator""sv(const char32_t* __str, size_t __len)
+ operator""sv(const char32_t* __str, size_t __len) noexcept
{ return basic_string_view<char32_t>{__str, __len}; }
#endif
} // namespace string_literals
diff --git a/libstdc++-v3/include/precompiled/stdc++.h b/libstdc++-v3/include/precompiled/stdc++.h
index 262743a..4e1a71a 100644
--- a/libstdc++-v3/include/precompiled/stdc++.h
+++ b/libstdc++-v3/include/precompiled/stdc++.h
@@ -121,3 +121,8 @@
#if __cplusplus >= 201402L
#include <shared_mutex>
#endif
+
+#if __cplusplus >= 201703L
+#include <charconv>
+#include <filesystem>
+#endif
diff --git a/libstdc++-v3/include/std/charconv b/libstdc++-v3/include/std/charconv
new file mode 100644
index 0000000..e5d6c10
--- /dev/null
+++ b/libstdc++-v3/include/std/charconv
@@ -0,0 +1,658 @@
+// Primitive numeric conversions (to_chars and from_chars) -*- C++ -*-
+
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+/** @file include/charconv
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_CHARCONV
+#define _GLIBCXX_CHARCONV 1
+
+#pragma GCC system_header
+
+#if __cplusplus >= 201402L
+
+#include <type_traits>
+#include <limits>
+#include <cctype>
+#include <bits/error_constants.h> // for std::errc
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+
+ /// Result type of std::to_chars
+ struct to_chars_result
+ {
+ char* ptr;
+ errc ec;
+ };
+
+ /// Result type of std::from_chars
+ struct from_chars_result
+ {
+ const char* ptr;
+ errc ec;
+ };
+
+namespace __detail
+{
+ template<typename _Tp, typename... _Types>
+ using __is_one_of = __or_<is_same<_Tp, _Types>...>;
+
+ template<typename _Tp>
+ using __is_int_to_chars_type = __and_<is_integral<_Tp>,
+ __not_<__is_one_of<_Tp, bool, char16_t, char32_t
+#if _GLIBCXX_USE_WCHAR_T
+ , wchar_t
+#endif
+ >>>;
+
+ template<typename _Tp>
+ using __integer_to_chars_result_type
+ = enable_if_t<__is_int_to_chars_type<_Tp>::value, to_chars_result>;
+
+ template<typename _Tp>
+ using __unsigned_least_t
+ = conditional_t<(sizeof(_Tp) <= sizeof(int)), unsigned int,
+ conditional_t<(sizeof(_Tp) <= sizeof(long)), unsigned long,
+ conditional_t<(sizeof(_Tp) <= sizeof(long long)), unsigned long long,
+#if _GLIBCXX_USE_INT128
+ conditional_t<(sizeof(_Tp) <= sizeof(__int128)), unsigned __int128,
+#endif
+ void
+#if _GLIBCXX_USE_INT128
+ >
+#endif
+ >>>;
+
+ // Generic implementation for arbitrary bases.
+ template<typename _Tp>
+ constexpr unsigned
+ __to_chars_len(_Tp __value, int __base = 10) noexcept
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ unsigned __n = 1;
+ const int __b2 = __base * __base;
+ const int __b3 = __b2 * __base;
+ const int __b4 = __b3 * __base;
+ for (;;)
+ {
+ if (__value < __base) return __n;
+ if (__value < __b2) return __n + 1;
+ if (__value < __b3) return __n + 2;
+ if (__value < __b4) return __n + 3;
+ __value /= (unsigned)__b4;
+ __n += 4;
+ }
+ }
+
+ template<typename _Tp>
+ constexpr unsigned
+ __to_chars_len_2(_Tp __value) noexcept
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ constexpr size_t __nbits = __CHAR_BIT__ * sizeof(_Tp);
+
+ // N.B. __builtin_clzll is undefined if __value == 0, but std::to_chars
+ // handles zero values directly.
+
+ // For sizeof(_Tp) > 1 this is an order of magnitude faster than
+ // the generic __to_chars_len.
+ return __nbits
+ - (__builtin_clzll(__value)
+ - ((__CHAR_BIT__ * sizeof(long long)) - __nbits));
+ }
+
+ template<typename _Tp>
+ constexpr unsigned
+ __to_chars_len_8(_Tp __value) noexcept
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ constexpr size_t __nbits = __CHAR_BIT__ * sizeof(_Tp);
+
+ if _GLIBCXX17_CONSTEXPR (__nbits <= 16)
+ {
+ return __value > 077777u ? 6u
+ : __value > 07777u ? 5u
+ : __value > 0777u ? 4u
+ : __value > 077u ? 3u
+ : __value > 07u ? 2u
+ : 1u;
+ }
+ else
+ return __to_chars_len(__value, 8);
+ }
+
+ // Generic implementation for arbitrary bases.
+ template<typename _Tp>
+ to_chars_result
+ __to_chars(char* __first, char* __last, _Tp __val, int __base) noexcept
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ to_chars_result __res;
+
+ const unsigned __len = __to_chars_len(__val, __base);
+
+ if (__builtin_expect((__last - __first) < __len, 0))
+ {
+ __res.ptr = __last;
+ __res.ec = errc::value_too_large;
+ return __res;
+ }
+
+ unsigned __pos = __len - 1;
+
+ static constexpr char __digits[]
+ = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+ while (__val >= __base)
+ {
+ auto const __quo = __val / __base;
+ auto const __rem = __val % __base;
+ __first[__pos--] = __digits[__rem];
+ __val = __quo;
+ }
+ *__first = __digits[__val];
+
+ __res.ptr = __first + __len;
+ __res.ec = {};
+ return __res;
+ }
+
+ template<typename _Tp>
+ __integer_to_chars_result_type<_Tp>
+ __to_chars_16(char* __first, char* __last, _Tp __val) noexcept
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ to_chars_result __res;
+
+ const unsigned __len = __to_chars_len(__val, 0x10);
+
+ if (__builtin_expect((__last - __first) < __len, 0))
+ {
+ __res.ptr = __last;
+ __res.ec = errc::value_too_large;
+ return __res;
+ }
+
+ static constexpr char __digits[513] =
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f"
+ "404142434445464748494a4b4c4d4e4f505152535455565758595a5b5c5d5e5f"
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f"
+ "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f"
+ "a0a1a2a3a4a5a6a7a8a9aaabacadaeafb0b1b2b3b4b5b6b7b8b9babbbcbdbebf"
+ "c0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedf"
+ "e0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff";
+ unsigned __pos = __len - 1;
+ while (__val >= 0x100)
+ {
+ auto const __num = (__val % 0x100) * 2;
+ __val /= 0x100;
+ __first[__pos] = __digits[__num + 1];
+ __first[__pos - 1] = __digits[__num];
+ __pos -= 2;
+ }
+ if (__val >= 0x10)
+ {
+ auto const __num = __val * 2;
+ __first[__pos] = __digits[__num + 1];
+ __first[__pos - 1] = __digits[__num];
+ }
+ else
+ __first[__pos] = "0123456789abcdef"[__val];
+ __res.ptr = __first + __len;
+ __res.ec = {};
+ return __res;
+ }
+
+ template<typename _Tp>
+ __integer_to_chars_result_type<_Tp>
+ __to_chars_10(char* __first, char* __last, _Tp __val) noexcept
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ to_chars_result __res;
+
+ const unsigned __len = __to_chars_len(__val, 10);
+
+ if (__builtin_expect((__last - __first) < __len, 0))
+ {
+ __res.ptr = __last;
+ __res.ec = errc::value_too_large;
+ return __res;
+ }
+
+ static constexpr char __digits[201] =
+ "0001020304050607080910111213141516171819"
+ "2021222324252627282930313233343536373839"
+ "4041424344454647484950515253545556575859"
+ "6061626364656667686970717273747576777879"
+ "8081828384858687888990919293949596979899";
+ unsigned __pos = __len - 1;
+ while (__val >= 100)
+ {
+ auto const __num = (__val % 100) * 2;
+ __val /= 100;
+ __first[__pos] = __digits[__num + 1];
+ __first[__pos - 1] = __digits[__num];
+ __pos -= 2;
+ }
+ if (__val >= 10)
+ {
+ auto const __num = __val * 2;
+ __first[__pos] = __digits[__num + 1];
+ __first[__pos - 1] = __digits[__num];
+ }
+ else
+ __first[__pos] = '0' + __val;
+ __res.ptr = __first + __len;
+ __res.ec = {};
+ return __res;
+ }
+
+ template<typename _Tp>
+ __integer_to_chars_result_type<_Tp>
+ __to_chars_8(char* __first, char* __last, _Tp __val) noexcept
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ to_chars_result __res;
+
+ const unsigned __len = __to_chars_len_8(__val);
+
+ if (__builtin_expect((__last - __first) < __len, 0))
+ {
+ __res.ptr = __last;
+ __res.ec = errc::value_too_large;
+ return __res;
+ }
+
+ static constexpr char __digits[129] =
+ "00010203040506071011121314151617"
+ "20212223242526273031323334353637"
+ "40414243444546475051525354555657"
+ "60616263646566677071727374757677";
+ unsigned __pos = __len - 1;
+ while (__val >= 0100)
+ {
+ auto const __num = (__val % 0100) * 2;
+ __val /= 0100;
+ __first[__pos] = __digits[__num + 1];
+ __first[__pos - 1] = __digits[__num];
+ __pos -= 2;
+ }
+ if (__val >= 010)
+ {
+ auto const __num = __val * 2;
+ __first[__pos] = __digits[__num + 1];
+ __first[__pos - 1] = __digits[__num];
+ }
+ else
+ __first[__pos] = '0' + __val;
+ __res.ptr = __first + __len;
+ __res.ec = {};
+ return __res;
+ }
+
+ template<typename _Tp>
+ __integer_to_chars_result_type<_Tp>
+ __to_chars_2(char* __first, char* __last, _Tp __val) noexcept
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ to_chars_result __res;
+
+ const unsigned __len = __to_chars_len_2(__val);
+
+ if (__builtin_expect((__last - __first) < __len, 0))
+ {
+ __res.ptr = __last;
+ __res.ec = errc::value_too_large;
+ return __res;
+ }
+
+ unsigned __pos = __len - 1;
+
+ while (__pos)
+ {
+ __first[__pos--] = '0' + (__val & 1);
+ __val >>= 1;
+ }
+ *__first = '0' + (__val & 1);
+
+ __res.ptr = __first + __len;
+ __res.ec = {};
+ return __res;
+ }
+
+} // namespace __detail
+
+ template<typename _Tp>
+ __detail::__integer_to_chars_result_type<_Tp>
+ to_chars(char* __first, char* __last, _Tp __value, int __base = 10)
+ {
+ __glibcxx_assert(2 <= __base && __base <= 36);
+
+ using _Up = __detail::__unsigned_least_t<_Tp>;
+ _Up __unsigned_val = __value;
+
+ if (__value == 0 && __first != __last)
+ {
+ *__first = '0';
+ return { __first + 1, errc{} };
+ }
+
+ if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+ if (__value < 0)
+ {
+ if (__builtin_expect(__first != __last, 1))
+ *__first++ = '-';
+ __unsigned_val = _Up(~__value) + _Up(1);
+ }
+
+ switch (__base)
+ {
+ case 16:
+ return __detail::__to_chars_16(__first, __last, __unsigned_val);
+ case 10:
+ return __detail::__to_chars_10(__first, __last, __unsigned_val);
+ case 8:
+ return __detail::__to_chars_8(__first, __last, __unsigned_val);
+ case 2:
+ return __detail::__to_chars_2(__first, __last, __unsigned_val);
+ default:
+ return __detail::__to_chars(__first, __last, __unsigned_val, __base);
+ }
+ }
+
+namespace __detail
+{
+ template<typename _Tp>
+ bool
+ __raise_and_add(_Tp& __val, int __base, unsigned char __c)
+ {
+ if (__builtin_mul_overflow(__val, __base, &__val)
+ || __builtin_add_overflow(__val, __c, &__val))
+ return false;
+ return true;
+ }
+
+ /// std::from_chars implementation for integers in base 2.
+ template<typename _Tp>
+ bool
+ __from_chars_binary(const char*& __first, const char* __last, _Tp& __val)
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ const ptrdiff_t __len = __last - __first;
+ int __i = 0;
+ while (__i < __len)
+ {
+ const unsigned char __c = (unsigned)__first[__i] - '0';
+ if (__c < 2)
+ __val = (__val << 1) | __c;
+ else
+ break;
+ __i++;
+ }
+ __first += __i;
+ return __i <= (sizeof(_Tp) * __CHAR_BIT__);
+ }
+
+ /// std::from_chars implementation for integers in bases 3 to 10.
+ template<typename _Tp>
+ bool
+ __from_chars_digit(const char*& __first, const char* __last, _Tp& __val,
+ int __base)
+ {
+ static_assert(is_integral<_Tp>::value, "implementation bug");
+ static_assert(is_unsigned<_Tp>::value, "implementation bug");
+
+ auto __matches = [__base](char __c) {
+ return '0' <= __c && __c <= ('0' + (__base - 1));
+ };
+
+ while (__first != __last)
+ {
+ const char __c = *__first;
+ if (__matches(__c))
+ {
+ if (!__raise_and_add(__val, __base, __c - '0'))
+ {
+ while (++__first != __last && __matches(*__first))
+ ;
+ return false;
+ }
+ __first++;
+ }
+ else
+ return true;
+ }
+ return true;
+ }
+
+ constexpr unsigned char
+ __from_chars_alpha_to_num(char __c)
+ {
+ switch (__c)
+ {
+ case 'a':
+ case 'A':
+ return 10;
+ case 'b':
+ case 'B':
+ return 11;
+ case 'c':
+ case 'C':
+ return 12;
+ case 'd':
+ case 'D':
+ return 13;
+ case 'e':
+ case 'E':
+ return 14;
+ case 'f':
+ case 'F':
+ return 15;
+ case 'g':
+ case 'G':
+ return 16;
+ case 'h':
+ case 'H':
+ return 17;
+ case 'i':
+ case 'I':
+ return 18;
+ case 'j':
+ case 'J':
+ return 19;
+ case 'k':
+ case 'K':
+ return 20;
+ case 'l':
+ case 'L':
+ return 21;
+ case 'm':
+ case 'M':
+ return 22;
+ case 'n':
+ case 'N':
+ return 23;
+ case 'o':
+ case 'O':
+ return 24;
+ case 'p':
+ case 'P':
+ return 25;
+ case 'q':
+ case 'Q':
+ return 26;
+ case 'r':
+ case 'R':
+ return 27;
+ case 's':
+ case 'S':
+ return 28;
+ case 't':
+ case 'T':
+ return 29;
+ case 'u':
+ case 'U':
+ return 30;
+ case 'v':
+ case 'V':
+ return 31;
+ case 'w':
+ case 'W':
+ return 32;
+ case 'x':
+ case 'X':
+ return 33;
+ case 'y':
+ case 'Y':
+ return 34;
+ case 'z':
+ case 'Z':
+ return 35;
+ }
+ return std::numeric_limits<unsigned char>::max();
+ }
+
+ /// std::from_chars implementation for integers in bases 11 to 26.
+ template<typename _Tp>
+ bool
+ __from_chars_alnum(const char*& __first, const char* __last, _Tp& __val,
+ int __base)
+ {
+ bool __valid = true;
+ while (__first != __last)
+ {
+ unsigned char __c = *__first;
+ if (std::isdigit(__c))
+ __c -= '0';
+ else
+ {
+ __c = __from_chars_alpha_to_num(__c);
+ if (__c >= __base)
+ break;
+ }
+
+ if (__builtin_expect(__valid, 1))
+ __valid = __raise_and_add(__val, __base, __c);
+ __first++;
+ }
+ return __valid;
+ }
+
+ template<typename _Tp>
+ using __integer_from_chars_result_type
+ = enable_if_t<__is_int_to_chars_type<_Tp>::value, from_chars_result>;
+
+} // namespace __detail
+
+ /// std::from_chars for integral types.
+ template<typename _Tp>
+ __detail::__integer_from_chars_result_type<_Tp>
+ from_chars(const char* __first, const char* __last, _Tp& __value,
+ int __base = 10)
+ {
+ __glibcxx_assert(2 <= __base && __base <= 36);
+
+ from_chars_result __res{__first, {}};
+
+ int __sign = 1;
+ if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+ if (__first != __last && *__first == '-')
+ {
+ __sign = -1;
+ ++__first;
+ }
+
+ using _Up = __detail::__unsigned_least_t<_Tp>;
+ _Up __val = 0;
+
+ const auto __start = __first;
+ bool __valid;
+ if (__base == 2)
+ __valid = __detail::__from_chars_binary(__first, __last, __val);
+ else if (__base <= 10)
+ __valid = __detail::__from_chars_digit(__first, __last, __val, __base);
+ else
+ __valid = __detail::__from_chars_alnum(__first, __last, __val, __base);
+
+ if (__builtin_expect(__first == __start, 0))
+ __res.ec = errc::invalid_argument;
+ else
+ {
+ __res.ptr = __first;
+ if (!__valid)
+ __res.ec = errc::result_out_of_range;
+ else
+ {
+ if _GLIBCXX17_CONSTEXPR (std::is_signed<_Tp>::value)
+ {
+ _Tp __tmp;
+ if (__builtin_mul_overflow(__val, __sign, &__tmp))
+ __res.ec = errc::result_out_of_range;
+ else
+ __value = __tmp;
+ }
+ else
+ {
+ if _GLIBCXX17_CONSTEXPR
+ (numeric_limits<_Up>::max() > numeric_limits<_Tp>::max())
+ {
+ if (__val > numeric_limits<_Tp>::max())
+ __res.ec = errc::result_out_of_range;
+ else
+ __value = __val;
+ }
+ else
+ __value = __val;
+ }
+ }
+ }
+ return __res;
+ }
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+#endif // C++14
+#endif // _GLIBCXX_CHARCONV
diff --git a/libstdc++-v3/include/std/chrono b/libstdc++-v3/include/std/chrono
index fc058fc..9491508 100644
--- a/libstdc++-v3/include/std/chrono
+++ b/libstdc++-v3/include/std/chrono
@@ -214,8 +214,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
treat_as_floating_point<_Rep>::value;
#endif // C++17
-#if __cplusplus > 201402L
-# define __cpp_lib_chrono 201510
+#if __cplusplus >= 201703L
+# define __cpp_lib_chrono 201611
template<typename _ToDur, typename _Rep, typename _Period>
constexpr __enable_if_is_duration<_ToDur>
diff --git a/libstdc++-v3/include/std/filesystem b/libstdc++-v3/include/std/filesystem
new file mode 100644
index 0000000..b099977
--- /dev/null
+++ b/libstdc++-v3/include/std/filesystem
@@ -0,0 +1,45 @@
+// <filesystem> -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+/** @file filesystem
+ * This is a Standard C++ Library header.
+ */
+
+#ifndef _GLIBCXX_FILESYSTEM
+#define _GLIBCXX_FILESYSTEM 1
+
+#pragma GCC system_header
+
+#if __cplusplus >= 201703L
+
+#include <bits/fs_fwd.h>
+#include <bits/fs_path.h>
+#include <bits/fs_dir.h>
+#include <bits/fs_ops.h>
+
+#define __cpp_lib_filesystem 201703
+
+#endif // C++17
+
+#endif // _GLIBCXX_FILESYSTEM
diff --git a/libstdc++-v3/include/std/mutex b/libstdc++-v3/include/std/mutex
index 8c692a8..50420ee 100644
--- a/libstdc++-v3/include/std/mutex
+++ b/libstdc++-v3/include/std/mutex
@@ -688,6 +688,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__set_once_functor_lock_ptr(0);
#endif
+#ifdef __clang_analyzer__
+ // PR libstdc++/82481
+ __once_callable = nullptr;
+ __once_call = nullptr;
+#endif
+
if (__e)
__throw_system_error(__e);
}
diff --git a/libstdc++-v3/include/std/optional b/libstdc++-v3/include/std/optional
index 2743ef9..e017eed 100644
--- a/libstdc++-v3/include/std/optional
+++ b/libstdc++-v3/include/std/optional
@@ -1005,33 +1005,37 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Hash.
- template<typename _Tp, bool
- = __poison_hash<remove_const_t<_Tp>>::__enable_hash_call>
+ template<typename _Tp, typename _Up = remove_const_t<_Tp>,
+ bool = __poison_hash<_Up>::__enable_hash_call>
struct __optional_hash_call_base
{
size_t
operator()(const optional<_Tp>& __t) const
- noexcept(noexcept(hash<_Tp> {}(*__t)))
+ noexcept(noexcept(hash<_Up>{}(*__t)))
{
// We pick an arbitrary hash for disengaged optionals which hopefully
// usual values of _Tp won't typically hash to.
constexpr size_t __magic_disengaged_hash = static_cast<size_t>(-3333);
- return __t ? hash<_Tp> {}(*__t) : __magic_disengaged_hash;
+ return __t ? hash<_Up>{}(*__t) : __magic_disengaged_hash;
}
};
- template<typename _Tp>
- struct __optional_hash_call_base<_Tp, false> {};
+ template<typename _Tp, typename _Up>
+ struct __optional_hash_call_base<_Tp, _Up, false> {};
template<typename _Tp>
struct hash<optional<_Tp>>
: private __poison_hash<remove_const_t<_Tp>>,
public __optional_hash_call_base<_Tp>
{
- using result_type = size_t;
- using argument_type = optional<_Tp>;
+ using result_type [[__deprecated__]] = size_t;
+ using argument_type [[__deprecated__]] = optional<_Tp>;
};
+ template<typename _Tp>
+ struct __is_fast_hash<hash<optional<_Tp>>> : __is_fast_hash<hash<_Tp>>
+ { };
+
/// @}
template <typename _Tp> optional(_Tp) -> optional<_Tp>;
diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view
index 97316ef..1900b86 100644
--- a/libstdc++-v3/include/std/string_view
+++ b/libstdc++-v3/include/std/string_view
@@ -96,14 +96,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr basic_string_view(const basic_string_view&) noexcept = default;
- constexpr basic_string_view(const _CharT* __str)
+ constexpr basic_string_view(const _CharT* __str) noexcept
: _M_len{__str == nullptr ? 0 : traits_type::length(__str)},
_M_str{__str}
{ }
- constexpr basic_string_view(const _CharT* __str, size_type __len)
- : _M_len{__len},
- _M_str{__str}
+ constexpr
+ basic_string_view(const _CharT* __str, size_type __len) noexcept
+ : _M_len{__len}, _M_str{__str}
{ }
constexpr basic_string_view&
@@ -177,17 +177,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr const _CharT&
at(size_type __pos) const
{
- return __pos < this->_M_len
- ? *(this->_M_str + __pos)
- : (__throw_out_of_range_fmt(__N("basic_string_view::at: __pos "
- "(which is %zu) >= this->size() "
- "(which is %zu)"),
- __pos, this->size()),
- *this->_M_str);
+ if (__pos >= _M_len)
+ __throw_out_of_range_fmt(__N("basic_string_view::at: __pos "
+ "(which is %zu) >= this->size() "
+ "(which is %zu)"), __pos, this->size());
+ return *(this->_M_str + __pos);
}
constexpr const _CharT&
- front() const
+ front() const noexcept
{
// TODO: Assert to restore in a way compatible with the constexpr.
// __glibcxx_assert(this->_M_len > 0);
@@ -195,7 +193,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
constexpr const _CharT&
- back() const
+ back() const noexcept
{
// TODO: Assert to restore in a way compatible with the constexpr.
// __glibcxx_assert(this->_M_len > 0);
@@ -209,7 +207,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// [string.view.modifiers], modifiers:
constexpr void
- remove_prefix(size_type __n)
+ remove_prefix(size_type __n) noexcept
{
__glibcxx_assert(this->_M_len >= __n);
this->_M_str += __n;
@@ -217,7 +215,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
constexpr void
- remove_suffix(size_type __n)
+ remove_suffix(size_type __n) noexcept
{ this->_M_len -= __n; }
constexpr void
@@ -235,38 +233,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
copy(_CharT* __str, size_type __n, size_type __pos = 0) const
{
__glibcxx_requires_string_len(__str, __n);
- if (__pos > this->_M_len)
- __throw_out_of_range_fmt(__N("basic_string_view::copy: __pos "
- "(which is %zu) > this->size() "
- "(which is %zu)"),
- __pos, this->size());
- size_type __rlen{std::min(__n, size_type{this->_M_len - __pos})};
+ __pos = _M_check(__pos, "basic_string_view::copy");
+ const size_type __rlen = std::min(__n, _M_len - __pos);
for (auto __begin = this->_M_str + __pos,
__end = __begin + __rlen; __begin != __end;)
*__str++ = *__begin++;
return __rlen;
}
-
- // [string.view.ops], string operations:
-
constexpr basic_string_view
- substr(size_type __pos, size_type __n=npos) const
+ substr(size_type __pos, size_type __n = npos) const noexcept(false)
{
- return __pos <= this->_M_len
- ? basic_string_view{this->_M_str + __pos,
- std::min(__n, size_type{this->_M_len - __pos})}
- : (__throw_out_of_range_fmt(__N("basic_string_view::substr: __pos "
- "(which is %zu) > this->size() "
- "(which is %zu)"),
- __pos, this->size()), basic_string_view{});
+ __pos = _M_check(__pos, "basic_string_view::substr");
+ const size_type __rlen = std::min(__n, _M_len - __pos);
+ return basic_string_view{_M_str + __pos, __rlen};
}
constexpr int
compare(basic_string_view __str) const noexcept
{
- int __ret = traits_type::compare(this->_M_str, __str._M_str,
- std::min(this->_M_len, __str._M_len));
+ const size_type __rlen = std::min(this->_M_len, __str._M_len);
+ int __ret = traits_type::compare(this->_M_str, __str._M_str, __rlen);
if (__ret == 0)
__ret = _S_compare(this->_M_len, __str._M_len);
return __ret;
@@ -279,7 +266,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr int
compare(size_type __pos1, size_type __n1,
basic_string_view __str, size_type __pos2, size_type __n2) const
- { return this->substr(__pos1, __n1).compare(__str.substr(__pos2, __n2)); }
+ {
+ return this->substr(__pos1, __n1).compare(__str.substr(__pos2, __n2));
+ }
constexpr int
compare(const _CharT* __str) const noexcept
@@ -291,7 +280,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr int
compare(size_type __pos1, size_type __n1,
- const _CharT* __str, size_type __n2) const
+ const _CharT* __str, size_type __n2) const noexcept(false)
{
return this->substr(__pos1, __n1)
.compare(basic_string_view(__str, __n2));
@@ -302,13 +291,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return this->find(__str._M_str, __pos, __str._M_len); }
constexpr size_type
- find(_CharT __c, size_type __pos=0) const noexcept;
+ find(_CharT __c, size_type __pos = 0) const noexcept;
constexpr size_type
find(const _CharT* __str, size_type __pos, size_type __n) const noexcept;
constexpr size_type
- find(const _CharT* __str, size_type __pos=0) const noexcept
+ find(const _CharT* __str, size_type __pos = 0) const noexcept
{ return this->find(__str, __pos, traits_type::length(__str)); }
constexpr size_type
@@ -350,7 +339,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ return this->rfind(__c, __pos); }
constexpr size_type
- find_last_of(const _CharT* __str, size_type __pos, size_type __n) const;
+ find_last_of(const _CharT* __str, size_type __pos,
+ size_type __n) const noexcept;
constexpr size_type
find_last_of(const _CharT* __str, size_type __pos = npos) const noexcept
@@ -366,7 +356,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr size_type
find_first_not_of(const _CharT* __str,
- size_type __pos, size_type __n) const;
+ size_type __pos, size_type __n) const noexcept;
constexpr size_type
find_first_not_of(const _CharT* __str, size_type __pos = 0) const noexcept
@@ -385,7 +375,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
constexpr size_type
find_last_not_of(const _CharT* __str,
- size_type __pos, size_type __n) const;
+ size_type __pos, size_type __n) const noexcept;
constexpr size_type
find_last_not_of(const _CharT* __str,
@@ -396,7 +386,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
}
constexpr size_type
- _M_check(size_type __pos, const char* __s) const
+ _M_check(size_type __pos, const char* __s) const noexcept(false)
{
if (__pos > this->size())
__throw_out_of_range_fmt(__N("%s: __pos (which is %zu) > "
@@ -407,7 +397,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// NB: _M_limit doesn't check for a bad __pos value.
constexpr size_type
- _M_limit(size_type __pos, size_type __off) const _GLIBCXX_NOEXCEPT
+ _M_limit(size_type __pos, size_type __off) const noexcept
{
const bool __testoff = __off < this->size() - __pos;
return __testoff ? __off : this->size() - __pos;
@@ -418,11 +408,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
static constexpr int
_S_compare(size_type __n1, size_type __n2) noexcept
{
- return difference_type{__n1 - __n2} > std::numeric_limits<int>::max()
- ? std::numeric_limits<int>::max()
- : difference_type{__n1 - __n2} < std::numeric_limits<int>::min()
- ? std::numeric_limits<int>::min()
- : static_cast<int>(difference_type{__n1 - __n2});
+ const difference_type __diff{__n1 - __n2};
+ if (__diff > std::numeric_limits<int>::max())
+ return std::numeric_limits<int>::max();
+ if (__diff < std::numeric_limits<int>::min())
+ return std::numeric_limits<int>::min();
+ return static_cast<int>(__diff);
}
size_t _M_len;
@@ -636,22 +627,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline namespace string_view_literals
{
inline constexpr basic_string_view<char>
- operator""sv(const char* __str, size_t __len)
+ operator""sv(const char* __str, size_t __len) noexcept
{ return basic_string_view<char>{__str, __len}; }
#ifdef _GLIBCXX_USE_WCHAR_T
inline constexpr basic_string_view<wchar_t>
- operator""sv(const wchar_t* __str, size_t __len)
+ operator""sv(const wchar_t* __str, size_t __len) noexcept
{ return basic_string_view<wchar_t>{__str, __len}; }
#endif
#ifdef _GLIBCXX_USE_C99_STDINT_TR1
inline constexpr basic_string_view<char16_t>
- operator""sv(const char16_t* __str, size_t __len)
+ operator""sv(const char16_t* __str, size_t __len) noexcept
{ return basic_string_view<char16_t>{__str, __len}; }
inline constexpr basic_string_view<char32_t>
- operator""sv(const char32_t* __str, size_t __len)
+ operator""sv(const char32_t* __str, size_t __len) noexcept
{ return basic_string_view<char32_t>{__str, __len}; }
#endif
} // namespace string_literals
diff --git a/libstdc++-v3/include/std/variant b/libstdc++-v3/include/std/variant
index ee2571b..8f574f6 100644
--- a/libstdc++-v3/include/std/variant
+++ b/libstdc++-v3/include/std/variant
@@ -1420,15 +1420,15 @@ namespace __variant
variant<_Types...>, std::index_sequence_for<_Types...>>,
public __variant_hash_call_base<_Types...>
{
- using result_type = size_t;
- using argument_type = variant<_Types...>;
+ using result_type [[__deprecated__]] = size_t;
+ using argument_type [[__deprecated__]] = variant<_Types...>;
};
template<>
struct hash<monostate>
{
- using result_type = size_t;
- using argument_type = monostate;
+ using result_type [[__deprecated__]] = size_t;
+ using argument_type [[__deprecated__]] = monostate;
size_t
operator()(const monostate& __t) const noexcept
@@ -1438,6 +1438,11 @@ namespace __variant
}
};
+ template<typename... _Types>
+ struct __is_fast_hash<hash<variant<_Types...>>>
+ : bool_constant<(__is_fast_hash<_Types>::value && ...)>
+ { };
+
_GLIBCXX_END_NAMESPACE_VERSION
} // namespace std
diff --git a/libstdc++-v3/libsupc++/exception b/libstdc++-v3/libsupc++/exception
index e51d31c..9b177c7 100644
--- a/libstdc++-v3/libsupc++/exception
+++ b/libstdc++-v3/libsupc++/exception
@@ -98,9 +98,10 @@ namespace std
* %exception can result in a call of @c terminate()
* (15.5.1).'
*/
+ _GLIBCXX17_DEPRECATED
bool uncaught_exception() _GLIBCXX_USE_NOEXCEPT __attribute__ ((__pure__));
-#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++1z or gnu++98
+#if __cplusplus > 201402L || !defined(__STRICT_ANSI__) // c++17 or gnu++98
#define __cpp_lib_uncaught_exceptions 201411
/// The number of uncaught exceptions.
int uncaught_exceptions() _GLIBCXX_USE_NOEXCEPT __attribute__ ((__pure__));
diff --git a/libstdc++-v3/libsupc++/exception_ptr.h b/libstdc++-v3/libsupc++/exception_ptr.h
index 0ece81d..dae4ca6 100644
--- a/libstdc++-v3/libsupc++/exception_ptr.h
+++ b/libstdc++-v3/libsupc++/exception_ptr.h
@@ -201,19 +201,6 @@ namespace std
#endif
}
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 1130. copy_exception name misleading
- /// Obtain an exception_ptr pointing to a copy of the supplied object.
- /// This function is deprecated, use std::make_exception_ptr instead.
- template<typename _Ex>
- exception_ptr
- copy_exception(_Ex __ex) _GLIBCXX_USE_NOEXCEPT _GLIBCXX_DEPRECATED;
-
- template<typename _Ex>
- exception_ptr
- copy_exception(_Ex __ex) _GLIBCXX_USE_NOEXCEPT
- { return std::make_exception_ptr<_Ex>(__ex); }
-
// @} group exceptions
} // namespace std
diff --git a/libstdc++-v3/python/libstdcxx/v6/printers.py b/libstdc++-v3/python/libstdcxx/v6/printers.py
index 04f413a..9d21196 100644
--- a/libstdc++-v3/python/libstdcxx/v6/printers.py
+++ b/libstdc++-v3/python/libstdcxx/v6/printers.py
@@ -1592,6 +1592,10 @@ def build_libstdcxx_dictionary ():
'path', StdExpPathPrinter)
libstdcxx_printer.add_version('std::experimental::filesystem::v1::__cxx11::',
'path', StdExpPathPrinter)
+ libstdcxx_printer.add_version('std::filesystem::',
+ 'path', StdExpPathPrinter)
+ libstdcxx_printer.add_version('std::filesystem::__cxx11::',
+ 'path', StdExpPathPrinter)
# C++17 components
libstdcxx_printer.add_version('std::',
diff --git a/libstdc++-v3/src/c++11/istream-inst.cc b/libstdc++-v3/src/c++11/istream-inst.cc
index 9605304..f5a9666 100644
--- a/libstdc++-v3/src/c++11/istream-inst.cc
+++ b/libstdc++-v3/src/c++11/istream-inst.cc
@@ -97,6 +97,8 @@ _GLIBCXX_END_NAMESPACE_VERSION
// XXX GLIBCXX_ABI Deprecated
#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
+#pragma GCC diagnostic ignored "-Wattribute-alias"
+
#define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
extern "C" void ldbl (void) __attribute__ ((alias (#dbl), weak))
_GLIBCXX_LDBL_COMPAT (_ZNSirsERd, _ZNSirsERe);
diff --git a/libstdc++-v3/src/c++11/locale-inst.cc b/libstdc++-v3/src/c++11/locale-inst.cc
index b0f79ff..c1b8e8d 100644
--- a/libstdc++-v3/src/c++11/locale-inst.cc
+++ b/libstdc++-v3/src/c++11/locale-inst.cc
@@ -383,6 +383,8 @@ _GLIBCXX_END_NAMESPACE_VERSION
#if defined _GLIBCXX_LONG_DOUBLE_COMPAT && defined C_is_char \
&& _GLIBCXX_USE_CXX11_ABI == 0
+#pragma GCC diagnostic ignored "-Wattribute-alias"
+
#define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
extern "C" void ldbl (void) __attribute__ ((alias (#dbl), weak))
diff --git a/libstdc++-v3/src/c++11/ostream-inst.cc b/libstdc++-v3/src/c++11/ostream-inst.cc
index ef0038b..12ddc8d 100644
--- a/libstdc++-v3/src/c++11/ostream-inst.cc
+++ b/libstdc++-v3/src/c++11/ostream-inst.cc
@@ -100,6 +100,8 @@ _GLIBCXX_END_NAMESPACE_VERSION
// XXX GLIBCXX_ABI Deprecated
#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
+#pragma GCC diagnostic ignored "-Wattribute-alias"
+
#define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
extern "C" void ldbl (void) __attribute__ ((alias (#dbl), weak))
_GLIBCXX_LDBL_COMPAT (_ZNSolsEd, _ZNSolsEe);
diff --git a/libstdc++-v3/src/c++11/wlocale-inst.cc b/libstdc++-v3/src/c++11/wlocale-inst.cc
index 26fdf34..5a565cb 100644
--- a/libstdc++-v3/src/c++11/wlocale-inst.cc
+++ b/libstdc++-v3/src/c++11/wlocale-inst.cc
@@ -37,6 +37,8 @@
// XXX GLIBCXX_ABI Deprecated
#if defined _GLIBCXX_LONG_DOUBLE_COMPAT
+#pragma GCC diagnostic ignored "-Wattribute-alias"
+
#define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
extern "C" void ldbl (void) __attribute__ ((alias (#dbl), weak))
diff --git a/libstdc++-v3/src/c++98/complex_io.cc b/libstdc++-v3/src/c++98/complex_io.cc
index bb09ca5..f55e322 100644
--- a/libstdc++-v3/src/c++98/complex_io.cc
+++ b/libstdc++-v3/src/c++98/complex_io.cc
@@ -95,7 +95,7 @@ _GLIBCXX_END_NAMESPACE_VERSION
#ifdef _GLIBCXX_LONG_DOUBLE_COMPAT
#define _GLIBCXX_LDBL_COMPAT(dbl, ldbl) \
- extern "C" void ldbl (void) __attribute__ ((alias (#dbl), weak))
+ extern "C" void ldbl (...) __attribute__ ((alias (#dbl), weak))
_GLIBCXX_LDBL_COMPAT (_ZStlsIdcSt11char_traitsIcEERSt13basic_ostreamIT0_T1_ES6_RKSt7complexIT_E,
_ZStlsIecSt11char_traitsIcEERSt13basic_ostreamIT0_T1_ES6_RKSt7complexIT_E);
diff --git a/libstdc++-v3/src/c++98/hash-long-double-tr1-aux.cc b/libstdc++-v3/src/c++98/hash-long-double-tr1-aux.cc
index 28ee175..4612a44 100644
--- a/libstdc++-v3/src/c++98/hash-long-double-tr1-aux.cc
+++ b/libstdc++-v3/src/c++98/hash-long-double-tr1-aux.cc
@@ -22,6 +22,8 @@
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
// <http://www.gnu.org/licenses/>.
+#pragma GCC diagnostic ignored "-Wattribute-alias"
+
namespace std _GLIBCXX_VISIBILITY(default)
{
namespace tr1
diff --git a/libstdc++-v3/src/filesystem/Makefile.am b/libstdc++-v3/src/filesystem/Makefile.am
index 836bdd3..19de2a3 100644
--- a/libstdc++-v3/src/filesystem/Makefile.am
+++ b/libstdc++-v3/src/filesystem/Makefile.am
@@ -30,7 +30,10 @@ if ENABLE_DUAL_ABI
cxx11_abi_sources = \
cow-dir.cc \
cow-ops.cc \
- cow-path.cc
+ cow-path.cc \
+ cow-std-dir.cc \
+ cow-std-ops.cc \
+ cow-std-path.cc
else
cxx11_abi_sources =
endif
@@ -39,6 +42,9 @@ sources = \
dir.cc \
ops.cc \
path.cc \
+ std-dir.cc \
+ std-ops.cc \
+ std-path.cc \
${cxx11_abi_sources}
# vpath % $(top_srcdir)/src/filesystem
@@ -52,7 +58,7 @@ libstdc__fs_la_SOURCES = $(sources)
# as the occasion call for it.
AM_CXXFLAGS = \
$(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
- -std=gnu++14 \
+ -std=gnu++17 \
$(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS)
AM_MAKEFLAGS = \
diff --git a/libstdc++-v3/src/filesystem/Makefile.in b/libstdc++-v3/src/filesystem/Makefile.in
index a4fdf79..847b19b 100644
--- a/libstdc++-v3/src/filesystem/Makefile.in
+++ b/libstdc++-v3/src/filesystem/Makefile.in
@@ -114,8 +114,10 @@ am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
LTLIBRARIES = $(toolexeclib_LTLIBRARIES)
libstdc__fs_la_LIBADD =
@ENABLE_DUAL_ABI_TRUE@am__objects_1 = cow-dir.lo cow-ops.lo \
-@ENABLE_DUAL_ABI_TRUE@ cow-path.lo
-am__objects_2 = dir.lo ops.lo path.lo $(am__objects_1)
+@ENABLE_DUAL_ABI_TRUE@ cow-path.lo cow-std-dir.lo \
+@ENABLE_DUAL_ABI_TRUE@ cow-std-ops.lo cow-std-path.lo
+am__objects_2 = dir.lo ops.lo path.lo std-dir.lo std-ops.lo \
+ std-path.lo $(am__objects_1)
am_libstdc__fs_la_OBJECTS = $(am__objects_2)
libstdc__fs_la_OBJECTS = $(am_libstdc__fs_la_OBJECTS)
DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
@@ -362,12 +364,18 @@ headers =
@ENABLE_DUAL_ABI_TRUE@cxx11_abi_sources = \
@ENABLE_DUAL_ABI_TRUE@ cow-dir.cc \
@ENABLE_DUAL_ABI_TRUE@ cow-ops.cc \
-@ENABLE_DUAL_ABI_TRUE@ cow-path.cc
+@ENABLE_DUAL_ABI_TRUE@ cow-path.cc \
+@ENABLE_DUAL_ABI_TRUE@ cow-std-dir.cc \
+@ENABLE_DUAL_ABI_TRUE@ cow-std-ops.cc \
+@ENABLE_DUAL_ABI_TRUE@ cow-std-path.cc
sources = \
dir.cc \
ops.cc \
path.cc \
+ std-dir.cc \
+ std-ops.cc \
+ std-path.cc \
${cxx11_abi_sources}
@@ -381,7 +389,7 @@ libstdc__fs_la_SOURCES = $(sources)
# as the occasion call for it.
AM_CXXFLAGS = \
$(glibcxx_lt_pic_flag) $(glibcxx_compiler_shared_flag) \
- -std=gnu++14 \
+ -std=gnu++17 \
$(WARN_CXXFLAGS) $(OPTIMIZE_CXXFLAGS) $(CONFIG_CXXFLAGS)
AM_MAKEFLAGS = \
diff --git a/libstdc++-v3/src/filesystem/cow-dir.cc b/libstdc++-v3/src/filesystem/cow-dir.cc
index 4e47bbd..96907ab 100644
--- a/libstdc++-v3/src/filesystem/cow-dir.cc
+++ b/libstdc++-v3/src/filesystem/cow-dir.cc
@@ -1,4 +1,4 @@
-// Class filesystem::directory_entry etc. -*- C++ -*-
+// Class experimental::filesystem::directory_entry etc. -*- C++ -*-
// Copyright (C) 2015-2017 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/src/filesystem/cow-ops.cc b/libstdc++-v3/src/filesystem/cow-ops.cc
index 9ad91f0..3b41d7c 100644
--- a/libstdc++-v3/src/filesystem/cow-ops.cc
+++ b/libstdc++-v3/src/filesystem/cow-ops.cc
@@ -1,4 +1,4 @@
-// Filesystem operations -*- C++ -*-
+// Filesystem TS operations -*- C++ -*-
// Copyright (C) 2015-2017 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/src/filesystem/cow-path.cc b/libstdc++-v3/src/filesystem/cow-path.cc
index b216088..0817b0a 100644
--- a/libstdc++-v3/src/filesystem/cow-path.cc
+++ b/libstdc++-v3/src/filesystem/cow-path.cc
@@ -1,4 +1,4 @@
-// Class filesystem::path -*- C++ -*-
+// Class experimental::filesystem::path -*- C++ -*-
// Copyright (C) 2015-2017 Free Software Foundation, Inc.
//
diff --git a/libstdc++-v3/src/filesystem/cow-std-dir.cc b/libstdc++-v3/src/filesystem/cow-std-dir.cc
new file mode 100644
index 0000000..edcf245
--- /dev/null
+++ b/libstdc++-v3/src/filesystem/cow-std-dir.cc
@@ -0,0 +1,26 @@
+// Class filesystem::directory_entry etc. -*- C++ -*-
+
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "std-dir.cc"
diff --git a/libstdc++-v3/src/filesystem/cow-std-ops.cc b/libstdc++-v3/src/filesystem/cow-std-ops.cc
new file mode 100644
index 0000000..bea5470
--- /dev/null
+++ b/libstdc++-v3/src/filesystem/cow-std-ops.cc
@@ -0,0 +1,26 @@
+// Filesystem operations -*- C++ -*-
+
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "std-ops.cc"
diff --git a/libstdc++-v3/src/filesystem/cow-std-path.cc b/libstdc++-v3/src/filesystem/cow-std-path.cc
new file mode 100644
index 0000000..718ff95
--- /dev/null
+++ b/libstdc++-v3/src/filesystem/cow-std-path.cc
@@ -0,0 +1,26 @@
+// Class filesystem::path -*- C++ -*-
+
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+#define _GLIBCXX_USE_CXX11_ABI 0
+#include "std-path.cc"
diff --git a/libstdc++-v3/src/filesystem/dir-common.h b/libstdc++-v3/src/filesystem/dir-common.h
new file mode 100644
index 0000000..e803632
--- /dev/null
+++ b/libstdc++-v3/src/filesystem/dir-common.h
@@ -0,0 +1,149 @@
+// Filesystem directory iterator utilities -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_DIR_COMMON_H
+#define _GLIBCXX_DIR_COMMON_H 1
+
+#include <string.h> // strcmp
+#ifdef _GLIBCXX_HAVE_DIRENT_H
+# ifdef _GLIBCXX_HAVE_SYS_TYPES_H
+# include <sys/types.h>
+# endif
+# include <dirent.h>
+#else
+# error "the <dirent.h> header is needed to build the Filesystem TS"
+#endif
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef opendir
+# define opendir _wopendir
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace filesystem
+{
+
+struct _Dir_base
+{
+ _Dir_base(DIR* dirp = nullptr) : dirp(dirp) { }
+
+ // If no error occurs then dirp is non-null,
+ // otherwise null (whether error ignored or not).
+ _Dir_base(const char* p, bool skip_permission_denied,
+ error_code& ec) noexcept
+ : dirp(::opendir(p))
+ {
+ if (dirp)
+ ec.clear();
+ else
+ {
+ const int err = errno;
+ if (err == EACCES && skip_permission_denied)
+ ec.clear();
+ else
+ ec.assign(err, std::generic_category());
+ }
+ }
+
+ _Dir_base(_Dir_base&& d) : dirp(std::exchange(d.dirp, nullptr)) { }
+
+ _Dir_base& operator=(_Dir_base&&) = delete;
+
+ ~_Dir_base() { if (dirp) ::closedir(dirp); }
+
+ const struct ::dirent*
+ advance(bool skip_permission_denied, error_code& ec) noexcept
+ {
+ ec.clear();
+
+ int err = std::exchange(errno, 0);
+ const struct ::dirent* entp = readdir(dirp);
+ // std::swap cannot be used with Bionic's errno
+ err = std::exchange(errno, err);
+
+ if (entp)
+ {
+ // skip past dot and dot-dot
+ if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, ".."))
+ return advance(skip_permission_denied, ec);
+ return entp;
+ }
+ else if (err)
+ {
+ if (err == EACCES && skip_permission_denied)
+ return nullptr;
+ ec.assign(err, std::generic_category());
+ return nullptr;
+ }
+ else
+ {
+ // reached the end
+ return nullptr;
+ }
+ }
+
+ DIR* dirp;
+};
+
+} // namespace filesystem
+
+// BEGIN/END macros must be defined before including this file.
+_GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
+inline file_type
+get_file_type(const ::dirent& d __attribute__((__unused__)))
+{
+#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
+ switch (d.d_type)
+ {
+ case DT_BLK:
+ return file_type::block;
+ case DT_CHR:
+ return file_type::character;
+ case DT_DIR:
+ return file_type::directory;
+ case DT_FIFO:
+ return file_type::fifo;
+ case DT_LNK:
+ return file_type::symlink;
+ case DT_REG:
+ return file_type::regular;
+ case DT_SOCK:
+ return file_type::socket;
+ case DT_UNKNOWN:
+ return file_type::unknown;
+ default:
+ return file_type::none;
+ }
+#else
+ return file_type::none;
+#endif
+}
+_GLIBCXX_END_NAMESPACE_FILESYSTEM
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // _GLIBCXX_DIR_COMMON_H
diff --git a/libstdc++-v3/src/filesystem/dir.cc b/libstdc++-v3/src/filesystem/dir.cc
index 9aecd80..42f63e7 100644
--- a/libstdc++-v3/src/filesystem/dir.cc
+++ b/libstdc++-v3/src/filesystem/dir.cc
@@ -31,40 +31,76 @@
#include <stack>
#include <string.h>
#include <errno.h>
-#ifdef _GLIBCXX_HAVE_DIRENT_H
-# ifdef _GLIBCXX_HAVE_SYS_TYPES_H
-# include <sys/types.h>
-# endif
-# include <dirent.h>
-#else
-# error "the <dirent.h> header is needed to build the Filesystem TS"
-#endif
-
-#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
-# undef opendir
-# define opendir _wopendir
-#endif
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
+ namespace experimental { namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
+#include "dir-common.h"
namespace fs = std::experimental::filesystem;
-struct fs::_Dir
+struct fs::_Dir : std::filesystem::_Dir_base
{
- _Dir() : dirp(nullptr) { }
+ _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec)
+ : _Dir_base(p.c_str(), skip_permission_denied, ec)
+ {
+ if (!ec)
+ path = p;
+ }
- _Dir(DIR* dirp, const fs::path& path) : dirp(dirp), path(path) { }
+ _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
- _Dir(_Dir&& d)
- : dirp(std::exchange(d.dirp, nullptr)), path(std::move(d.path)),
- entry(std::move(d.entry)), type(d.type)
- { }
+ _Dir(_Dir&&) = default;
- _Dir& operator=(_Dir&&) = delete;
+ // Returns false when the end of the directory entries is reached.
+ // Reports errors by setting ec.
+ bool advance(bool skip_permission_denied, error_code& ec) noexcept
+ {
+ if (const auto entp = _Dir_base::advance(skip_permission_denied, ec))
+ {
+ entry = fs::directory_entry{path / entp->d_name};
+ type = get_file_type(*entp);
+ return true;
+ }
+ else if (!ec)
+ {
+ // reached the end
+ entry = {};
+ type = file_type::none;
+ }
+ return false;
+ }
+
+ bool advance(error_code& ec) noexcept { return advance(false, ec); }
- ~_Dir() { if (dirp) ::closedir(dirp); }
+ // Returns false when the end of the directory entries is reached.
+ // Reports errors by throwing.
+ bool advance(bool skip_permission_denied = false)
+ {
+ error_code ec;
+ const bool ok = advance(skip_permission_denied, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "directory iterator cannot advance", ec));
+ return ok;
+ }
- bool advance(std::error_code*, directory_options = directory_options::none);
+ bool should_recurse(bool follow_symlink, error_code& ec) const
+ {
+ file_type type = this->type;
+ if (type == file_type::none || type == file_type::unknown)
+ {
+ type = entry.symlink_status(ec).type();
+ if (ec)
+ return false;
+ }
+
+ if (type == file_type::directory)
+ return true;
+ if (type == file_type::symlink)
+ return follow_symlink && is_directory(entry.status(ec));
+ return false;
+ }
- DIR* dirp;
fs::path path;
directory_entry entry;
file_type type = file_type::none;
@@ -78,119 +114,28 @@ namespace
{
return (obj & bits) != Bitmask::none;
}
-
- // Returns {dirp, p} on success, {} on error (whether ignored or not).
- inline fs::_Dir
- open_dir(const fs::path& p, fs::directory_options options,
- std::error_code* ec)
- {
- if (ec)
- ec->clear();
-
- if (DIR* dirp = ::opendir(p.c_str()))
- return {dirp, p};
-
- const int err = errno;
- if (err == EACCES
- && is_set(options, fs::directory_options::skip_permission_denied))
- return {};
-
- if (!ec)
- _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
- "directory iterator cannot open directory", p,
- std::error_code(err, std::generic_category())));
-
- ec->assign(err, std::generic_category());
- return {};
- }
-
- inline fs::file_type
- get_file_type(const ::dirent& d __attribute__((__unused__)))
- {
-#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
- switch (d.d_type)
- {
- case DT_BLK:
- return fs::file_type::block;
- case DT_CHR:
- return fs::file_type::character;
- case DT_DIR:
- return fs::file_type::directory;
- case DT_FIFO:
- return fs::file_type::fifo;
- case DT_LNK:
- return fs::file_type::symlink;
- case DT_REG:
- return fs::file_type::regular;
- case DT_SOCK:
- return fs::file_type::socket;
- case DT_UNKNOWN:
- return fs::file_type::unknown;
- default:
- return fs::file_type::none;
- }
-#else
- return fs::file_type::none;
-#endif
- }
-}
-
-
-// Returns false when the end of the directory entries is reached.
-// Reports errors by setting ec or throwing.
-bool
-fs::_Dir::advance(error_code* ec, directory_options options)
-{
- if (ec)
- ec->clear();
-
- int err = std::exchange(errno, 0);
- const auto entp = readdir(dirp);
- // std::swap cannot be used with Bionic's errno
- err = std::exchange(errno, err);
-
- if (entp)
- {
- // skip past dot and dot-dot
- if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, ".."))
- return advance(ec, options);
- entry = fs::directory_entry{path / entp->d_name};
- type = get_file_type(*entp);
- return true;
- }
- else if (err)
- {
- if (err == EACCES
- && is_set(options, directory_options::skip_permission_denied))
- return false;
-
- if (!ec)
- _GLIBCXX_THROW_OR_ABORT(filesystem_error(
- "directory iterator cannot advance",
- std::error_code(err, std::generic_category())));
- ec->assign(err, std::generic_category());
- return false;
- }
- else
- {
- // reached the end
- entry = {};
- type = fs::file_type::none;
- return false;
- }
}
fs::directory_iterator::
-directory_iterator(const path& p, directory_options options, error_code* ec)
+directory_iterator(const path& p, directory_options options, error_code* ecptr)
{
- _Dir dir = open_dir(p, options, ec);
+ const bool skip_permission_denied
+ = is_set(options, directory_options::skip_permission_denied);
+
+ error_code ec;
+ _Dir dir(p, skip_permission_denied, ec);
if (dir.dirp)
{
auto sp = std::make_shared<fs::_Dir>(std::move(dir));
- if (sp->advance(ec, options))
+ if (sp->advance(skip_permission_denied, ec))
_M_dir.swap(sp);
}
+ if (ecptr)
+ *ecptr = ec;
+ else if (ec)
+ _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
+ "directory iterator cannot open directory", p, ec));
}
const fs::directory_entry&
@@ -210,7 +155,7 @@ fs::directory_iterator::operator++()
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
"cannot advance non-dereferenceable directory iterator",
std::make_error_code(errc::invalid_argument)));
- if (!_M_dir->advance(nullptr))
+ if (!_M_dir->advance())
_M_dir.reset();
return *this;
}
@@ -223,13 +168,11 @@ fs::directory_iterator::increment(error_code& ec) noexcept
ec = std::make_error_code(errc::invalid_argument);
return *this;
}
- if (!_M_dir->advance(&ec))
+ if (!_M_dir->advance(ec))
_M_dir.reset();
return *this;
}
-using Dir_iter_pair = std::pair<fs::_Dir, fs::directory_iterator>;
-
struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir>
{
void clear() { c.clear(); }
@@ -240,6 +183,8 @@ recursive_directory_iterator(const path& p, directory_options options,
error_code* ec)
: _M_options(options), _M_pending(true)
{
+ if (ec)
+ ec->clear();
if (DIR* dirp = ::opendir(p.c_str()))
{
auto sp = std::make_shared<_Dir_stack>();
@@ -252,11 +197,7 @@ recursive_directory_iterator(const path& p, directory_options options,
const int err = errno;
if (err == EACCES
&& is_set(options, fs::directory_options::skip_permission_denied))
- {
- if (ec)
- ec->clear();
- return;
- }
+ return;
if (!ec)
_GLIBCXX_THROW_OR_ABORT(filesystem_error(
@@ -300,35 +241,6 @@ fs::recursive_directory_iterator::operator++()
return *this;
}
-namespace
-{
- bool
- recurse(const fs::_Dir& d, fs::directory_options options, std::error_code& ec)
- {
- bool follow_symlink
- = is_set(options, fs::directory_options::follow_directory_symlink);
-#ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
- if (d.type == fs::file_type::directory)
- return true;
- if (d.type == fs::file_type::symlink && follow_symlink)
- return d.entry.status().type() == fs::file_type::directory;
- if (d.type != fs::file_type::none && d.type != fs::file_type::unknown)
- return false;
-#endif
- const fs::path& path = d.entry.path();
- auto type = fs::symlink_status(path, ec).type();
- if (ec.value())
- return false;
- if (type == fs::file_type::symlink)
- {
- if (!follow_symlink)
- return false;
- type = fs::status(path, ec).type();
- }
- return type == fs::file_type::directory;
- }
-}
-
fs::recursive_directory_iterator&
fs::recursive_directory_iterator::increment(error_code& ec) noexcept
{
@@ -338,11 +250,16 @@ fs::recursive_directory_iterator::increment(error_code& ec) noexcept
return *this;
}
+ const bool follow
+ = is_set(_M_options, directory_options::follow_directory_symlink);
+ const bool skip_permission_denied
+ = is_set(_M_options, directory_options::skip_permission_denied);
+
auto& top = _M_dirs->top();
- if (std::exchange(_M_pending, true) && recurse(top, _M_options, ec))
+ if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec))
{
- _Dir dir = open_dir(top.entry.path(), _M_options, &ec);
+ _Dir dir(top.entry.path(), skip_permission_denied, ec);
if (ec)
{
_M_dirs.reset();
@@ -352,7 +269,7 @@ fs::recursive_directory_iterator::increment(error_code& ec) noexcept
_M_dirs->push(std::move(dir));
}
- while (!_M_dirs->top().advance(&ec, _M_options) && !ec)
+ while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec)
{
_M_dirs->pop();
if (_M_dirs->empty())
@@ -373,6 +290,9 @@ fs::recursive_directory_iterator::pop(error_code& ec)
return;
}
+ const bool skip_permission_denied
+ = is_set(_M_options, directory_options::skip_permission_denied);
+
do {
_M_dirs->pop();
if (_M_dirs->empty())
@@ -381,7 +301,7 @@ fs::recursive_directory_iterator::pop(error_code& ec)
ec.clear();
return;
}
- } while (!_M_dirs->top().advance(&ec, _M_options));
+ } while (!_M_dirs->top().advance(skip_permission_denied, ec));
}
void
diff --git a/libstdc++-v3/src/filesystem/ops-common.h b/libstdc++-v3/src/filesystem/ops-common.h
new file mode 100644
index 0000000..12c12b0
--- /dev/null
+++ b/libstdc++-v3/src/filesystem/ops-common.h
@@ -0,0 +1,148 @@
+// Filesystem operation utilities -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_OPS_COMMON_H
+#define _GLIBCXX_OPS_COMMON_H 1
+
+#include <chrono>
+
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+# include <unistd.h>
+# if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
+# include <sys/types.h>
+# include <sys/stat.h>
+# endif
+#endif
+
+namespace std _GLIBCXX_VISIBILITY(default)
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace filesystem
+{
+ template<typename Bitmask>
+ inline bool is_set(Bitmask obj, Bitmask bits)
+ {
+ return (obj & bits) != Bitmask::none;
+ }
+
+ inline bool
+ is_not_found_errno(int err) noexcept
+ {
+ return err == ENOENT || err == ENOTDIR;
+ }
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ typedef struct ::stat stat_type;
+
+ inline std::chrono::system_clock::time_point
+ file_time(const stat_type& st, std::error_code& ec) noexcept
+ {
+ using namespace std::chrono;
+#ifdef _GLIBCXX_USE_ST_MTIM
+ time_t s = st.st_mtim.tv_sec;
+ nanoseconds ns{st.st_mtim.tv_nsec};
+#else
+ time_t s = st.st_mtime;
+ nanoseconds ns{};
+#endif
+
+ if (s >= (nanoseconds::max().count() / 1e9))
+ {
+ ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
+ return system_clock::time_point::min();
+ }
+ ec.clear();
+ return system_clock::time_point{seconds{s} + ns};
+ }
+
+ struct copy_options_existing_file
+ {
+ bool skip, update, overwrite;
+ };
+
+ bool
+ do_copy_file(const char* from, const char* to,
+ copy_options_existing_file options,
+ stat_type* from_st, stat_type* to_st,
+ std::error_code& ec) noexcept;
+
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+
+} // namespace filesystem
+
+// BEGIN/END macros must be defined before including this file.
+_GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ typedef struct ::stat stat_type;
+
+ inline file_type
+ make_file_type(const stat_type& st) noexcept
+ {
+#ifdef _GLIBCXX_HAVE_S_ISREG
+ if (S_ISREG(st.st_mode))
+ return file_type::regular;
+ else if (S_ISDIR(st.st_mode))
+ return file_type::directory;
+ else if (S_ISCHR(st.st_mode))
+ return file_type::character;
+ else if (S_ISBLK(st.st_mode))
+ return file_type::block;
+ else if (S_ISFIFO(st.st_mode))
+ return file_type::fifo;
+ else if (S_ISLNK(st.st_mode))
+ return file_type::symlink;
+ else if (S_ISSOCK(st.st_mode))
+ return file_type::socket;
+#endif
+ return file_type::unknown;
+ }
+
+ inline file_status
+ make_file_status(const stat_type& st) noexcept
+ {
+ return file_status{
+ make_file_type(st),
+ static_cast<perms>(st.st_mode) & perms::mask
+ };
+ }
+
+ inline std::filesystem::copy_options_existing_file
+ copy_file_options(copy_options opt)
+ {
+ using std::filesystem::is_set;
+ return {
+ is_set(opt, copy_options::skip_existing),
+ is_set(opt, copy_options::update_existing),
+ is_set(opt, copy_options::overwrite_existing)
+ };
+ }
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+
+_GLIBCXX_END_NAMESPACE_FILESYSTEM
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
+
+#endif // _GLIBCXX_OPS_COMMON_H
diff --git a/libstdc++-v3/src/filesystem/ops.cc b/libstdc++-v3/src/filesystem/ops.cc
index c711de1..61d9c89 100644
--- a/libstdc++-v3/src/filesystem/ops.cc
+++ b/libstdc++-v3/src/filesystem/ops.cc
@@ -1,4 +1,4 @@
-// Filesystem operations -*- C++ -*-
+// Filesystem TS operations -*- C++ -*-
// Copyright (C) 2014-2017 Free Software Foundation, Inc.
//
@@ -35,26 +35,24 @@
#include <stdio.h>
#include <errno.h>
#include <limits.h> // PATH_MAX
-#ifdef _GLIBCXX_HAVE_UNISTD_H
-# include <unistd.h>
-# if defined(_GLIBCXX_HAVE_SYS_STAT_H) && defined(_GLIBCXX_HAVE_SYS_TYPES_H)
-# include <sys/types.h>
-# include <sys/stat.h>
-# endif
-#endif
#ifdef _GLIBCXX_HAVE_FCNTL_H
-# include <fcntl.h>
+# include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
#endif
-#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
-# include <sys/statvfs.h>
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+# include <sys/stat.h> // stat, utimensat, fchmodat
#endif
-#ifdef _GLIBCXX_USE_SENDFILE
-# include <sys/sendfile.h>
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h> // statvfs
#endif
-#if _GLIBCXX_HAVE_UTIME_H
-# include <utime.h>
+#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+# include <utime.h> // utime
#endif
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM \
+ namespace experimental { namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM } }
+#include "ops-common.h"
+
#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
# undef utime
# define utime _wutime
@@ -240,254 +238,16 @@ fs::copy(const path& from, const path& to, copy_options options)
namespace
{
- template<typename Bitmask>
- inline bool is_set(Bitmask obj, Bitmask bits)
- {
- return (obj & bits) != Bitmask::none;
- }
-}
+ using std::filesystem::is_set;
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
-namespace
-{
typedef struct ::stat stat_type;
- inline fs::file_type
- make_file_type(const stat_type& st) noexcept
- {
- using fs::file_type;
-#ifdef _GLIBCXX_HAVE_S_ISREG
- if (S_ISREG(st.st_mode))
- return file_type::regular;
- else if (S_ISDIR(st.st_mode))
- return file_type::directory;
- else if (S_ISCHR(st.st_mode))
- return file_type::character;
- else if (S_ISBLK(st.st_mode))
- return file_type::block;
- else if (S_ISFIFO(st.st_mode))
- return file_type::fifo;
- else if (S_ISLNK(st.st_mode))
- return file_type::symlink;
- else if (S_ISSOCK(st.st_mode))
- return file_type::socket;
-#endif
- return file_type::unknown;
-
- }
-
- inline fs::file_status
- make_file_status(const stat_type& st) noexcept
- {
- return fs::file_status{
- make_file_type(st),
- static_cast<fs::perms>(st.st_mode) & fs::perms::mask
- };
- }
-
- inline bool
- is_not_found_errno(int err) noexcept
- {
- return err == ENOENT || err == ENOTDIR;
- }
-
- inline fs::file_time_type
- file_time(const stat_type& st, std::error_code& ec) noexcept
- {
- using namespace std::chrono;
-#ifdef _GLIBCXX_USE_ST_MTIM
- time_t s = st.st_mtim.tv_sec;
- nanoseconds ns{st.st_mtim.tv_nsec};
-#else
- time_t s = st.st_mtime;
- nanoseconds ns{};
-#endif
-
- if (s >= (nanoseconds::max().count() / 1e9))
- {
- ec = std::make_error_code(std::errc::value_too_large); // EOVERFLOW
- return fs::file_time_type::min();
- }
- ec.clear();
- return fs::file_time_type{seconds{s} + ns};
- }
-
- bool
- do_copy_file(const fs::path& from, const fs::path& to,
- fs::copy_options option,
- stat_type* from_st, stat_type* to_st,
- std::error_code& ec) noexcept
- {
- stat_type st1, st2;
- fs::file_status t, f;
-
- if (to_st == nullptr)
- {
- if (::stat(to.c_str(), &st1))
- {
- int err = errno;
- if (!is_not_found_errno(err))
- {
- ec.assign(err, std::generic_category());
- return false;
- }
- }
- else
- to_st = &st1;
- }
- else if (to_st == from_st)
- to_st = nullptr;
-
- if (to_st == nullptr)
- t = fs::file_status{fs::file_type::not_found};
- else
- t = make_file_status(*to_st);
-
- if (from_st == nullptr)
- {
- if (::stat(from.c_str(), &st2))
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- else
- from_st = &st2;
- }
- f = make_file_status(*from_st);
- // _GLIBCXX_RESOLVE_LIB_DEFECTS
- // 2712. copy_file() has a number of unspecified error conditions
- if (!is_regular_file(f))
- {
- ec = std::make_error_code(std::errc::not_supported);
- return false;
- }
-
- using opts = fs::copy_options;
-
- if (exists(t))
- {
- if (!is_regular_file(t))
- {
- ec = std::make_error_code(std::errc::not_supported);
- return false;
- }
-
- if (to_st->st_dev == from_st->st_dev
- && to_st->st_ino == from_st->st_ino)
- {
- ec = std::make_error_code(std::errc::file_exists);
- return false;
- }
-
- if (is_set(option, opts::skip_existing))
- {
- ec.clear();
- return false;
- }
- else if (is_set(option, opts::update_existing))
- {
- const auto from_mtime = file_time(*from_st, ec);
- if (ec)
- return false;
- if ((from_mtime <= file_time(*to_st, ec)) || ec)
- return false;
- }
- else if (!is_set(option, opts::overwrite_existing))
- {
- ec = std::make_error_code(std::errc::file_exists);
- return false;
- }
- else if (!is_regular_file(t))
- {
- ec = std::make_error_code(std::errc::not_supported);
- return false;
- }
- }
-
- struct CloseFD {
- ~CloseFD() { if (fd != -1) ::close(fd); }
- bool close() { return ::close(std::exchange(fd, -1)) == 0; }
- int fd;
- };
-
- CloseFD in = { ::open(from.c_str(), O_RDONLY) };
- if (in.fd == -1)
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- int oflag = O_WRONLY|O_CREAT;
- if (is_set(option, opts::overwrite_existing|opts::update_existing))
- oflag |= O_TRUNC;
- else
- oflag |= O_EXCL;
- CloseFD out = { ::open(to.c_str(), oflag, S_IWUSR) };
- if (out.fd == -1)
- {
- if (errno == EEXIST && is_set(option, opts::skip_existing))
- ec.clear();
- else
- ec.assign(errno, std::generic_category());
- return false;
- }
-
-#ifdef _GLIBCXX_USE_FCHMOD
- if (::fchmod(out.fd, from_st->st_mode))
-#elif defined _GLIBCXX_USE_FCHMODAT
- if (::fchmodat(AT_FDCWD, to.c_str(), from_st->st_mode, 0))
-#else
- if (::chmod(to.c_str(), from_st->st_mode))
-#endif
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
-
-#ifdef _GLIBCXX_USE_SENDFILE
- off_t offset = 0;
- const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size);
- if (n < 0 && (errno == ENOSYS || errno == EINVAL))
- {
-#endif
- __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
- __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
- if (sbin.is_open())
- in.fd = -1;
- if (sbout.is_open())
- out.fd = -1;
- if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
- {
- ec = std::make_error_code(std::errc::io_error);
- return false;
- }
- if (!sbout.close() || !sbin.close())
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
-
- ec.clear();
- return true;
-
-#ifdef _GLIBCXX_USE_SENDFILE
- }
- if (n != from_st->st_size)
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
- if (!out.close() || !in.close())
- {
- ec.assign(errno, std::generic_category());
- return false;
- }
-
- ec.clear();
- return true;
-#endif
- }
-}
-#endif
+ using std::filesystem::is_not_found_errno;
+ using std::filesystem::file_time;
+ using std::filesystem::do_copy_file;
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+} // namespace
void
fs::copy(const path& from, const path& to, copy_options options,
@@ -561,11 +321,13 @@ fs::copy(const path& from, const path& to, copy_options options,
else if (is_set(options, copy_options::create_hard_links))
create_hard_link(from, to, ec);
else if (is_directory(t))
- do_copy_file(from, to / from.filename(), options, &from_st, 0, ec);
+ do_copy_file(from.c_str(), (to / from.filename()).c_str(),
+ copy_file_options(options), &from_st, nullptr, ec);
else
{
auto ptr = exists(t) ? &to_st : &from_st;
- do_copy_file(from, to, options, &from_st, ptr, ec);
+ do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+ &from_st, ptr, ec);
}
}
// _GLIBCXX_RESOLVE_LIB_DEFECTS
@@ -602,11 +364,12 @@ fs::copy_file(const path& from, const path& to, copy_options option)
}
bool
-fs::copy_file(const path& from, const path& to, copy_options option,
+fs::copy_file(const path& from, const path& to, copy_options options,
error_code& ec) noexcept
{
#ifdef _GLIBCXX_HAVE_SYS_STAT_H
- return do_copy_file(from, to, option, nullptr, nullptr, ec);
+ return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+ nullptr, nullptr, ec);
#else
ec = std::make_error_code(std::errc::not_supported);
return false;
diff --git a/libstdc++-v3/src/filesystem/path.cc b/libstdc++-v3/src/filesystem/path.cc
index c66d52b..a519667 100644
--- a/libstdc++-v3/src/filesystem/path.cc
+++ b/libstdc++-v3/src/filesystem/path.cc
@@ -1,4 +1,4 @@
-// Class filesystem::path -*- C++ -*-
+// Class experimental::filesystem::path -*- C++ -*-
// Copyright (C) 2014-2017 Free Software Foundation, Inc.
//
@@ -28,9 +28,10 @@
#include <experimental/filesystem>
-using std::experimental::filesystem::path;
+namespace fs = std::experimental::filesystem;
+using fs::path;
-std::experimental::filesystem::filesystem_error::~filesystem_error() = default;
+fs::filesystem_error::~filesystem_error() = default;
constexpr path::value_type path::preferred_separator;
@@ -461,7 +462,7 @@ path::_S_convert_loc(const char* __first, const char* __last,
}
std::size_t
-std::experimental::filesystem::hash_value(const path& p) noexcept
+fs::hash_value(const path& p) noexcept
{
// [path.non-member]
// "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)."
@@ -477,3 +478,29 @@ std::experimental::filesystem::hash_value(const path& p) noexcept
}
return seed;
}
+
+namespace std
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace filesystem
+{
+ extern string
+ fs_err_concat(const string& __what, const string& __path1,
+ const string& __path2);
+} // namespace filesystem
+
+namespace experimental::filesystem::v1 {
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+ std::string filesystem_error::_M_gen_what()
+ {
+ using std::filesystem::fs_err_concat;
+ return fs_err_concat(system_error::what(), _M_path1.native(),
+ _M_path2.native());
+ }
+
+_GLIBCXX_END_NAMESPACE_CXX11
+} // namespace experimental::filesystem::v1
+
+_GLIBCXX_END_NAMESPACE_VERSION
+} // namespace std
diff --git a/libstdc++-v3/src/filesystem/std-dir.cc b/libstdc++-v3/src/filesystem/std-dir.cc
new file mode 100644
index 0000000..8e45890
--- /dev/null
+++ b/libstdc++-v3/src/filesystem/std-dir.cc
@@ -0,0 +1,318 @@
+// Class filesystem::directory_entry etc. -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_USE_CXX11_ABI 1
+#endif
+
+#include <filesystem>
+#include <experimental/filesystem>
+#include <utility>
+#include <stack>
+#include <string.h>
+#include <errno.h>
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
+#include "dir-common.h"
+
+namespace fs = std::filesystem;
+
+struct fs::_Dir : _Dir_base
+{
+ _Dir(const fs::path& p, bool skip_permission_denied, error_code& ec)
+ : _Dir_base(p.c_str(), skip_permission_denied, ec)
+ {
+ if (!ec)
+ path = p;
+ }
+
+ _Dir(DIR* dirp, const path& p) : _Dir_base(dirp), path(p) { }
+
+ _Dir(_Dir&&) = default;
+
+ // Returns false when the end of the directory entries is reached.
+ // Reports errors by setting ec.
+ bool advance(bool skip_permission_denied, error_code& ec) noexcept
+ {
+ if (const auto entp = _Dir_base::advance(skip_permission_denied, ec))
+ {
+ entry = fs::directory_entry{path / entp->d_name, get_file_type(*entp)};
+ return true;
+ }
+ else if (!ec)
+ {
+ // reached the end
+ entry = {};
+ }
+ return false;
+ }
+
+ bool advance(error_code& ec) noexcept { return advance(false, ec); }
+
+ // Returns false when the end of the directory entries is reached.
+ // Reports errors by throwing.
+ bool advance(bool skip_permission_denied = false)
+ {
+ error_code ec;
+ const bool ok = advance(skip_permission_denied, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "directory iterator cannot advance", ec));
+ return ok;
+ }
+
+ bool should_recurse(bool follow_symlink, error_code& ec) const
+ {
+ file_type type = entry._M_type;
+ if (type == file_type::none || type == file_type::unknown)
+ {
+ type = entry.symlink_status(ec).type();
+ if (ec)
+ return false;
+ }
+
+ if (type == file_type::directory)
+ return true;
+ if (type == file_type::symlink)
+ return follow_symlink && is_directory(entry.status(ec));
+ return false;
+ }
+
+ fs::path path;
+ directory_entry entry;
+};
+
+namespace
+{
+ template<typename Bitmask>
+ inline bool
+ is_set(Bitmask obj, Bitmask bits)
+ {
+ return (obj & bits) != Bitmask::none;
+ }
+}
+
+fs::directory_iterator::
+directory_iterator(const path& p, directory_options options, error_code* ecptr)
+{
+ const bool skip_permission_denied
+ = is_set(options, directory_options::skip_permission_denied);
+
+ error_code ec;
+ _Dir dir(p, skip_permission_denied, ec);
+
+ if (dir.dirp)
+ {
+ auto sp = std::make_shared<fs::_Dir>(std::move(dir));
+ if (sp->advance(skip_permission_denied, ec))
+ _M_dir.swap(sp);
+ }
+ if (ecptr)
+ *ecptr = ec;
+ else if (ec)
+ _GLIBCXX_THROW_OR_ABORT(fs::filesystem_error(
+ "directory iterator cannot open directory", p, ec));
+}
+
+const fs::directory_entry&
+fs::directory_iterator::operator*() const
+{
+ if (!_M_dir)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "non-dereferenceable directory iterator",
+ std::make_error_code(errc::invalid_argument)));
+ return _M_dir->entry;
+}
+
+fs::directory_iterator&
+fs::directory_iterator::operator++()
+{
+ if (!_M_dir)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "cannot advance non-dereferenceable directory iterator",
+ std::make_error_code(errc::invalid_argument)));
+ if (!_M_dir->advance())
+ _M_dir.reset();
+ return *this;
+}
+
+fs::directory_iterator&
+fs::directory_iterator::increment(error_code& ec) noexcept
+{
+ if (!_M_dir)
+ {
+ ec = std::make_error_code(errc::invalid_argument);
+ return *this;
+ }
+ if (!_M_dir->advance(ec))
+ _M_dir.reset();
+ return *this;
+}
+
+struct fs::recursive_directory_iterator::_Dir_stack : std::stack<_Dir>
+{
+ void clear() { c.clear(); }
+};
+
+fs::recursive_directory_iterator::
+recursive_directory_iterator(const path& p, directory_options options,
+ error_code* ecptr)
+: _M_options(options), _M_pending(true)
+{
+ if (DIR* dirp = ::opendir(p.c_str()))
+ {
+ if (ecptr)
+ ecptr->clear();
+ auto sp = std::make_shared<_Dir_stack>();
+ sp->push(_Dir{ dirp, p });
+ if (ecptr ? sp->top().advance(*ecptr) : sp->top().advance())
+ _M_dirs.swap(sp);
+ }
+ else
+ {
+ const int err = errno;
+ if (err == EACCES
+ && is_set(options, fs::directory_options::skip_permission_denied))
+ {
+ if (ecptr)
+ ecptr->clear();
+ return;
+ }
+
+ if (!ecptr)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "recursive directory iterator cannot open directory", p,
+ std::error_code(err, std::generic_category())));
+
+ ecptr->assign(err, std::generic_category());
+ }
+}
+
+fs::recursive_directory_iterator::~recursive_directory_iterator() = default;
+
+int
+fs::recursive_directory_iterator::depth() const
+{
+ return int(_M_dirs->size()) - 1;
+}
+
+const fs::directory_entry&
+fs::recursive_directory_iterator::operator*() const
+{
+ return _M_dirs->top().entry;
+}
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::
+operator=(const recursive_directory_iterator& other) noexcept = default;
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::
+operator=(recursive_directory_iterator&& other) noexcept = default;
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::operator++()
+{
+ error_code ec;
+ increment(ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "cannot increment recursive directory iterator", ec));
+ return *this;
+}
+
+fs::recursive_directory_iterator&
+fs::recursive_directory_iterator::increment(error_code& ec) noexcept
+{
+ if (!_M_dirs)
+ {
+ ec = std::make_error_code(errc::invalid_argument);
+ return *this;
+ }
+
+ const bool follow
+ = is_set(_M_options, directory_options::follow_directory_symlink);
+ const bool skip_permission_denied
+ = is_set(_M_options, directory_options::skip_permission_denied);
+
+ auto& top = _M_dirs->top();
+
+ if (std::exchange(_M_pending, true) && top.should_recurse(follow, ec))
+ {
+ _Dir dir(top.entry.path(), skip_permission_denied, ec);
+ if (ec)
+ {
+ _M_dirs.reset();
+ return *this;
+ }
+ if (dir.dirp)
+ _M_dirs->push(std::move(dir));
+ }
+
+ while (!_M_dirs->top().advance(skip_permission_denied, ec) && !ec)
+ {
+ _M_dirs->pop();
+ if (_M_dirs->empty())
+ {
+ _M_dirs.reset();
+ return *this;
+ }
+ }
+ return *this;
+}
+
+void
+fs::recursive_directory_iterator::pop(error_code& ec)
+{
+ if (!_M_dirs)
+ {
+ ec = std::make_error_code(errc::invalid_argument);
+ return;
+ }
+
+ const bool skip_permission_denied
+ = is_set(_M_options, directory_options::skip_permission_denied);
+
+ do {
+ _M_dirs->pop();
+ if (_M_dirs->empty())
+ {
+ _M_dirs.reset();
+ ec.clear();
+ return;
+ }
+ } while (!_M_dirs->top().advance(skip_permission_denied, ec));
+}
+
+void
+fs::recursive_directory_iterator::pop()
+{
+ error_code ec;
+ pop(ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(_M_dirs
+ ? "recursive directory iterator cannot pop"
+ : "non-dereferenceable recursive directory iterator cannot pop",
+ ec));
+}
diff --git a/libstdc++-v3/src/filesystem/std-ops.cc b/libstdc++-v3/src/filesystem/std-ops.cc
new file mode 100644
index 0000000..ff7acbf
--- /dev/null
+++ b/libstdc++-v3/src/filesystem/std-ops.cc
@@ -0,0 +1,1513 @@
+// Filesystem operations -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_USE_CXX11_ABI 1
+#endif
+
+#include <filesystem>
+#include <experimental/filesystem>
+#include <functional>
+#include <ostream>
+#include <stack>
+#include <ext/stdio_filebuf.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h> // PATH_MAX
+#ifdef _GLIBCXX_HAVE_FCNTL_H
+# include <fcntl.h> // AT_FDCWD, AT_SYMLINK_NOFOLLOW
+#endif
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+# include <sys/stat.h> // stat, utimensat, fchmodat
+#endif
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+# include <sys/statvfs.h> // statvfs
+#endif
+#ifdef _GLIBCXX_USE_SENDFILE
+# include <sys/sendfile.h> // sendfile
+#endif
+#if !_GLIBCXX_USE_UTIMENSAT && _GLIBCXX_HAVE_UTIME_H
+# include <utime.h> // utime
+#endif
+
+#define _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM namespace filesystem {
+#define _GLIBCXX_END_NAMESPACE_FILESYSTEM }
+#include "ops-common.h"
+
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# undef utime
+# define utime _wutime
+# undef chmod
+# define chmod _wchmod
+#endif
+
+namespace fs = std::filesystem;
+
+fs::path
+fs::absolute(const path& p)
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ error_code ec;
+ path ret = absolute(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make absolute path", p,
+ std::make_error_code(errc::not_supported)));
+ return ret;
+#else
+ return current_path() / p;
+#endif
+}
+
+fs::path
+fs::absolute(const path& p, error_code& ec)
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ ec = std::make_error_code(errc::not_supported);
+ return {};
+#else
+ ec.clear();
+ return current_path() / p;
+#endif
+}
+
+namespace
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ inline bool is_dot(wchar_t c) { return c == L'.'; }
+#else
+ inline bool is_dot(char c) { return c == '.'; }
+#endif
+
+ inline bool is_dot(const fs::path& path)
+ {
+ const auto& filename = path.native();
+ return filename.size() == 1 && is_dot(filename[0]);
+ }
+
+ inline bool is_dotdot(const fs::path& path)
+ {
+ const auto& filename = path.native();
+ return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
+ }
+
+ struct free_as_in_malloc
+ {
+ void operator()(void* p) const { ::free(p); }
+ };
+
+ using char_ptr = std::unique_ptr<char[], free_as_in_malloc>;
+}
+
+fs::path
+fs::canonical(const path& p, error_code& ec)
+{
+ path result;
+ const path pa = absolute(p, ec);
+ if (ec)
+ return result;
+
+#ifdef _GLIBCXX_USE_REALPATH
+ char_ptr buf{ nullptr };
+# if _XOPEN_VERSION < 700
+ // Not safe to call realpath(path, NULL)
+ buf.reset( (char*)::malloc(PATH_MAX) );
+# endif
+ if (char* rp = ::realpath(pa.c_str(), buf.get()))
+ {
+ if (buf == nullptr)
+ buf.reset(rp);
+ result.assign(rp);
+ ec.clear();
+ return result;
+ }
+ if (errno != ENAMETOOLONG)
+ {
+ ec.assign(errno, std::generic_category());
+ return result;
+ }
+#endif
+
+ if (!exists(pa, ec))
+ {
+ if (!ec)
+ ec = make_error_code(std::errc::no_such_file_or_directory);
+ return result;
+ }
+ // else: we know there are (currently) no unresolvable symlink loops
+
+ result = pa.root_path();
+
+ deque<path> cmpts;
+ for (auto& f : pa.relative_path())
+ cmpts.push_back(f);
+
+ int max_allowed_symlinks = 40;
+
+ while (!cmpts.empty() && !ec)
+ {
+ path f = std::move(cmpts.front());
+ cmpts.pop_front();
+
+ if (f.empty())
+ {
+ // ignore empty element
+ }
+ else if (is_dot(f))
+ {
+ if (!is_directory(result, ec) && !ec)
+ ec.assign(ENOTDIR, std::generic_category());
+ }
+ else if (is_dotdot(f))
+ {
+ auto parent = result.parent_path();
+ if (parent.empty())
+ result = pa.root_path();
+ else
+ result.swap(parent);
+ }
+ else
+ {
+ result /= f;
+
+ if (is_symlink(result, ec))
+ {
+ path link = read_symlink(result, ec);
+ if (!ec)
+ {
+ if (--max_allowed_symlinks == 0)
+ ec.assign(ELOOP, std::generic_category());
+ else
+ {
+ if (link.is_absolute())
+ {
+ result = link.root_path();
+ link = link.relative_path();
+ }
+ else
+ result = result.parent_path();
+
+ cmpts.insert(cmpts.begin(), link.begin(), link.end());
+ }
+ }
+ }
+ }
+ }
+
+ if (ec || !exists(result, ec))
+ result.clear();
+
+ return result;
+}
+
+fs::path
+fs::canonical(const path& p)
+{
+ error_code ec;
+ path res = canonical(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot make canonical path",
+ p, ec));
+ return res;
+}
+
+void
+fs::copy(const path& from, const path& to, copy_options options)
+{
+ error_code ec;
+ copy(from, to, options, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy", from, to, ec));
+}
+
+namespace std::filesystem
+{
+ // Need this as there's no 'perm_options::none' enumerator.
+ inline bool is_set(fs::perm_options obj, fs::perm_options bits)
+ {
+ return (obj & bits) != fs::perm_options{};
+ }
+}
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+bool
+fs::do_copy_file(const char* from, const char* to,
+ copy_options_existing_file options,
+ stat_type* from_st, stat_type* to_st,
+ std::error_code& ec) noexcept
+{
+ stat_type st1, st2;
+ fs::file_status t, f;
+
+ if (to_st == nullptr)
+ {
+ if (::stat(to, &st1))
+ {
+ const int err = errno;
+ if (!is_not_found_errno(err))
+ {
+ ec.assign(err, std::generic_category());
+ return false;
+ }
+ }
+ else
+ to_st = &st1;
+ }
+ else if (to_st == from_st)
+ to_st = nullptr;
+
+ if (to_st == nullptr)
+ t = fs::file_status{fs::file_type::not_found};
+ else
+ t = make_file_status(*to_st);
+
+ if (from_st == nullptr)
+ {
+ if (::stat(from, &st2))
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ else
+ from_st = &st2;
+ }
+ f = make_file_status(*from_st);
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2712. copy_file() has a number of unspecified error conditions
+ if (!is_regular_file(f))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+ }
+
+ if (exists(t))
+ {
+ if (!is_regular_file(t))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+ }
+
+ if (to_st->st_dev == from_st->st_dev
+ && to_st->st_ino == from_st->st_ino)
+ {
+ ec = std::make_error_code(std::errc::file_exists);
+ return false;
+ }
+
+ if (options.skip)
+ {
+ ec.clear();
+ return false;
+ }
+ else if (options.update)
+ {
+ const auto from_mtime = file_time(*from_st, ec);
+ if (ec)
+ return false;
+ if ((from_mtime <= file_time(*to_st, ec)) || ec)
+ return false;
+ }
+ else if (!options.overwrite)
+ {
+ ec = std::make_error_code(std::errc::file_exists);
+ return false;
+ }
+ else if (!is_regular_file(t))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+ }
+ }
+
+ struct CloseFD {
+ ~CloseFD() { if (fd != -1) ::close(fd); }
+ bool close() { return ::close(std::exchange(fd, -1)) == 0; }
+ int fd;
+ };
+
+ CloseFD in = { ::open(from, O_RDONLY) };
+ if (in.fd == -1)
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ int oflag = O_WRONLY|O_CREAT;
+ if (options.overwrite || options.update)
+ oflag |= O_TRUNC;
+ else
+ oflag |= O_EXCL;
+ CloseFD out = { ::open(to, oflag, S_IWUSR) };
+ if (out.fd == -1)
+ {
+ if (errno == EEXIST && options.skip)
+ ec.clear();
+ else
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+
+#ifdef _GLIBCXX_USE_FCHMOD
+ if (::fchmod(out.fd, from_st->st_mode))
+#elif defined _GLIBCXX_USE_FCHMODAT
+ if (::fchmodat(AT_FDCWD, to, from_st->st_mode, 0))
+#else
+ if (::chmod(to, from_st->st_mode))
+#endif
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+
+#ifdef _GLIBCXX_USE_SENDFILE
+ off_t offset = 0;
+ const auto n = ::sendfile(out.fd, in.fd, &offset, from_st->st_size);
+ if (n < 0 && (errno == ENOSYS || errno == EINVAL))
+ {
+#endif // _GLIBCXX_USE_SENDFILE
+ __gnu_cxx::stdio_filebuf<char> sbin(in.fd, std::ios::in);
+ __gnu_cxx::stdio_filebuf<char> sbout(out.fd, std::ios::out);
+ if (sbin.is_open())
+ in.fd = -1;
+ if (sbout.is_open())
+ out.fd = -1;
+ if (from_st->st_size && !(std::ostream(&sbout) << &sbin))
+ {
+ ec = std::make_error_code(std::errc::io_error);
+ return false;
+ }
+ if (!sbout.close() || !sbin.close())
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+
+ ec.clear();
+ return true;
+
+#ifdef _GLIBCXX_USE_SENDFILE
+ }
+ if (n != from_st->st_size)
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ if (!out.close() || !in.close())
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+
+ ec.clear();
+ return true;
+#endif // _GLIBCXX_USE_SENDFILE
+}
+#endif // _GLIBCXX_HAVE_SYS_STAT_H
+
+void
+fs::copy(const path& from, const path& to, copy_options options,
+ error_code& ec) noexcept
+{
+ const bool skip_symlinks = is_set(options, copy_options::skip_symlinks);
+ const bool create_symlinks = is_set(options, copy_options::create_symlinks);
+ const bool copy_symlinks = is_set(options, copy_options::copy_symlinks);
+ const bool use_lstat = create_symlinks || skip_symlinks;
+
+ file_status f, t;
+ stat_type from_st, to_st;
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2681. filesystem::copy() cannot copy symlinks
+ if (use_lstat || copy_symlinks
+ ? ::lstat(from.c_str(), &from_st)
+ : ::stat(from.c_str(), &from_st))
+ {
+ ec.assign(errno, std::generic_category());
+ return;
+ }
+ if (use_lstat
+ ? ::lstat(to.c_str(), &to_st)
+ : ::stat(to.c_str(), &to_st))
+ {
+ if (!is_not_found_errno(errno))
+ {
+ ec.assign(errno, std::generic_category());
+ return;
+ }
+ t = file_status{file_type::not_found};
+ }
+ else
+ t = make_file_status(to_st);
+ f = make_file_status(from_st);
+
+ if (exists(t) && !is_other(t) && !is_other(f)
+ && to_st.st_dev == from_st.st_dev && to_st.st_ino == from_st.st_ino)
+ {
+ ec = std::make_error_code(std::errc::file_exists);
+ return;
+ }
+ if (is_other(f) || is_other(t))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return;
+ }
+ if (is_directory(f) && is_regular_file(t))
+ {
+ ec = std::make_error_code(std::errc::is_a_directory);
+ return;
+ }
+
+ if (is_symlink(f))
+ {
+ if (skip_symlinks)
+ ec.clear();
+ else if (!exists(t) && copy_symlinks)
+ copy_symlink(from, to, ec);
+ else
+ // Not clear what should be done here.
+ // "Otherwise report an error as specified in Error reporting (7)."
+ ec = std::make_error_code(std::errc::invalid_argument);
+ }
+ else if (is_regular_file(f))
+ {
+ if (is_set(options, copy_options::directories_only))
+ ec.clear();
+ else if (create_symlinks)
+ create_symlink(from, to, ec);
+ else if (is_set(options, copy_options::create_hard_links))
+ create_hard_link(from, to, ec);
+ else if (is_directory(t))
+ do_copy_file(from.c_str(), (to / from.filename()).c_str(),
+ copy_file_options(options), &from_st, nullptr, ec);
+ else
+ {
+ auto ptr = exists(t) ? &to_st : &from_st;
+ do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+ &from_st, ptr, ec);
+ }
+ }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2682. filesystem::copy() won't create a symlink to a directory
+ else if (is_directory(f) && create_symlinks)
+ ec = std::make_error_code(errc::is_a_directory);
+ else if (is_directory(f) && (is_set(options, copy_options::recursive)
+ || options == copy_options::none))
+ {
+ if (!exists(t))
+ if (!create_directory(to, from, ec))
+ return;
+ // set an unused bit in options to disable further recursion
+ if (!is_set(options, copy_options::recursive))
+ options |= static_cast<copy_options>(4096);
+ for (const directory_entry& x : directory_iterator(from))
+ copy(x.path(), to/x.path().filename(), options, ec);
+ }
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2683. filesystem::copy() says "no effects"
+ else
+ ec.clear();
+}
+
+bool
+fs::copy_file(const path& from, const path& to, copy_options option)
+{
+ error_code ec;
+ bool result = copy_file(from, to, option, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy file", from, to,
+ ec));
+ return result;
+}
+
+bool
+fs::copy_file(const path& from, const path& to, copy_options options,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ return do_copy_file(from.c_str(), to.c_str(), copy_file_options(options),
+ nullptr, nullptr, ec);
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+#endif
+}
+
+
+void
+fs::copy_symlink(const path& existing_symlink, const path& new_symlink)
+{
+ error_code ec;
+ copy_symlink(existing_symlink, new_symlink, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot copy symlink",
+ existing_symlink, new_symlink, ec));
+}
+
+void
+fs::copy_symlink(const path& existing_symlink, const path& new_symlink,
+ error_code& ec) noexcept
+{
+ auto p = read_symlink(existing_symlink, ec);
+ if (ec)
+ return;
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ if (is_directory(p))
+ {
+ create_directory_symlink(p, new_symlink, ec);
+ return;
+ }
+#endif
+ create_symlink(p, new_symlink, ec);
+}
+
+
+bool
+fs::create_directories(const path& p)
+{
+ error_code ec;
+ bool result = create_directories(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directories", p,
+ ec));
+ return result;
+}
+
+bool
+fs::create_directories(const path& p, error_code& ec) noexcept
+{
+ if (p.empty())
+ {
+ ec = std::make_error_code(errc::invalid_argument);
+ return false;
+ }
+ std::stack<path> missing;
+ path pp = p;
+
+ while (pp.has_filename() && status(pp, ec).type() == file_type::not_found)
+ {
+ ec.clear();
+ const auto& filename = pp.filename();
+ if (!is_dot(filename) && !is_dotdot(filename))
+ missing.push(pp);
+ pp = pp.parent_path();
+
+ if (missing.size() > 1000) // sanity check
+ {
+ ec = std::make_error_code(std::errc::filename_too_long);
+ return false;
+ }
+ }
+
+ if (ec || missing.empty())
+ return false;
+
+ do
+ {
+ const path& top = missing.top();
+ create_directory(top, ec);
+ if (ec && is_directory(top))
+ ec.clear();
+ missing.pop();
+ }
+ while (!missing.empty() && !ec);
+
+ return missing.empty();
+}
+
+namespace
+{
+ bool
+ create_dir(const fs::path& p, fs::perms perm, std::error_code& ec)
+ {
+ bool created = false;
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ ::mode_t mode = static_cast<std::underlying_type_t<fs::perms>>(perm);
+ if (::mkdir(p.c_str(), mode))
+ {
+ const int err = errno;
+ if (err != EEXIST || !is_directory(p))
+ ec.assign(err, std::generic_category());
+ else
+ ec.clear();
+ }
+ else
+ {
+ ec.clear();
+ created = true;
+ }
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return created;
+ }
+} // namespace
+
+bool
+fs::create_directory(const path& p)
+{
+ error_code ec;
+ bool result = create_directory(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
+ ec));
+ return result;
+}
+
+bool
+fs::create_directory(const path& p, error_code& ec) noexcept
+{
+ return create_dir(p, perms::all, ec);
+}
+
+
+bool
+fs::create_directory(const path& p, const path& attributes)
+{
+ error_code ec;
+ bool result = create_directory(p, attributes, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory", p,
+ ec));
+ return result;
+}
+
+bool
+fs::create_directory(const path& p, const path& attributes,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ stat_type st;
+ if (::stat(attributes.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return false;
+ }
+ return create_dir(p, static_cast<perms>(st.st_mode), ec);
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+#endif
+}
+
+
+void
+fs::create_directory_symlink(const path& to, const path& new_symlink)
+{
+ error_code ec;
+ create_directory_symlink(to, new_symlink, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create directory symlink",
+ to, new_symlink, ec));
+}
+
+void
+fs::create_directory_symlink(const path& to, const path& new_symlink,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ ec = std::make_error_code(std::errc::not_supported);
+#else
+ create_symlink(to, new_symlink, ec);
+#endif
+}
+
+
+void
+fs::create_hard_link(const path& to, const path& new_hard_link)
+{
+ error_code ec;
+ create_hard_link(to, new_hard_link, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create hard link",
+ to, new_hard_link, ec));
+}
+
+void
+fs::create_hard_link(const path& to, const path& new_hard_link,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+ if (::link(to.c_str(), new_hard_link.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+void
+fs::create_symlink(const path& to, const path& new_symlink)
+{
+ error_code ec;
+ create_symlink(to, new_symlink, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot create symlink",
+ to, new_symlink, ec));
+}
+
+void
+fs::create_symlink(const path& to, const path& new_symlink,
+ error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+ if (::symlink(to.c_str(), new_symlink.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+
+fs::path
+fs::current_path()
+{
+ error_code ec;
+ path p = current_path(ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get current path", ec));
+ return p;
+}
+
+fs::path
+fs::current_path(error_code& ec)
+{
+ path p;
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+#ifdef __GLIBC__
+ if (char_ptr cwd = char_ptr{::getcwd(nullptr, 0)})
+ {
+ p.assign(cwd.get());
+ ec.clear();
+ }
+ else
+ ec.assign(errno, std::generic_category());
+#else
+ long path_max = pathconf(".", _PC_PATH_MAX);
+ size_t size;
+ if (path_max == -1)
+ size = 1024;
+ else if (path_max > 10240)
+ size = 10240;
+ else
+ size = path_max;
+ for (char_ptr buf; p.empty(); size *= 2)
+ {
+ buf.reset((char*)malloc(size));
+ if (buf)
+ {
+ if (getcwd(buf.get(), size))
+ {
+ p.assign(buf.get());
+ ec.clear();
+ }
+ else if (errno != ERANGE)
+ {
+ ec.assign(errno, std::generic_category());
+ return {};
+ }
+ }
+ else
+ {
+ ec = std::make_error_code(std::errc::not_enough_memory);
+ return {};
+ }
+ }
+#endif // __GLIBC__
+#else // _GLIBCXX_HAVE_UNISTD_H
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return p;
+}
+
+void
+fs::current_path(const path& p)
+{
+ error_code ec;
+ current_path(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set current path", ec));
+}
+
+void
+fs::current_path(const path& p, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+ if (::chdir(p.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+bool
+fs::equivalent(const path& p1, const path& p2)
+{
+ error_code ec;
+ auto result = equivalent(p1, p2, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check file equivalence",
+ p1, p2, ec));
+ return result;
+}
+
+bool
+fs::equivalent(const path& p1, const path& p2, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ int err = 0;
+ file_status s1, s2;
+ stat_type st1, st2;
+ if (::stat(p1.c_str(), &st1) == 0)
+ s1 = make_file_status(st1);
+ else if (is_not_found_errno(errno))
+ s1.type(file_type::not_found);
+ else
+ err = errno;
+
+ if (::stat(p2.c_str(), &st2) == 0)
+ s2 = make_file_status(st2);
+ else if (is_not_found_errno(errno))
+ s2.type(file_type::not_found);
+ else
+ err = errno;
+
+ if (exists(s1) && exists(s2))
+ {
+ if (is_other(s1) && is_other(s2))
+ {
+ ec = std::make_error_code(std::errc::not_supported);
+ return false;
+ }
+ ec.clear();
+ if (is_other(s1) || is_other(s2))
+ return false;
+ return st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino;
+ }
+ else if (!exists(s1) && !exists(s2))
+ ec = std::make_error_code(std::errc::no_such_file_or_directory);
+ else if (err)
+ ec.assign(err, std::generic_category());
+ else
+ ec.clear();
+ return false;
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return false;
+}
+
+std::uintmax_t
+fs::file_size(const path& p)
+{
+ error_code ec;
+ auto sz = file_size(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file size", p, ec));
+ return sz;
+}
+
+namespace
+{
+ template<typename Accessor, typename T>
+ inline T
+ do_stat(const fs::path& p, std::error_code& ec, Accessor f, T deflt)
+ {
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ fs::stat_type st;
+ if (::stat(p.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return deflt;
+ }
+ ec.clear();
+ return f(st);
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return deflt;
+#endif
+ }
+}
+
+std::uintmax_t
+fs::file_size(const path& p, error_code& ec) noexcept
+{
+ struct S
+ {
+ S(const stat_type& st) : type(make_file_type(st)), size(st.st_size) { }
+ S() : type(file_type::not_found) { }
+ file_type type;
+ size_t size;
+ };
+ auto s = do_stat(p, ec, [](const auto& st) { return S{st}; }, S{});
+ if (s.type == file_type::regular)
+ return s.size;
+ if (!ec)
+ {
+ if (s.type == file_type::directory)
+ ec = std::make_error_code(std::errc::is_a_directory);
+ else
+ ec = std::make_error_code(std::errc::not_supported);
+ }
+ return -1;
+}
+
+std::uintmax_t
+fs::hard_link_count(const path& p)
+{
+ error_code ec;
+ auto count = hard_link_count(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get link count", p, ec));
+ return count;
+}
+
+std::uintmax_t
+fs::hard_link_count(const path& p, error_code& ec) noexcept
+{
+ return do_stat(p, ec, std::mem_fn(&stat::st_nlink),
+ static_cast<uintmax_t>(-1));
+}
+
+bool
+fs::is_empty(const path& p)
+{
+ error_code ec;
+ bool e = is_empty(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot check if file is empty",
+ p, ec));
+ return e;
+}
+
+bool
+fs::is_empty(const path& p, error_code& ec) noexcept
+{
+ auto s = status(p, ec);
+ if (ec)
+ return false;
+ bool empty = fs::is_directory(s)
+ ? fs::directory_iterator(p, ec) == fs::directory_iterator()
+ : fs::file_size(p, ec) == 0;
+ return ec ? false : empty;
+}
+
+fs::file_time_type
+fs::last_write_time(const path& p)
+{
+ error_code ec;
+ auto t = last_write_time(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get file time", p, ec));
+ return t;
+}
+
+fs::file_time_type
+fs::last_write_time(const path& p, error_code& ec) noexcept
+{
+ return do_stat(p, ec, [&ec](const auto& st) { return file_time(st, ec); },
+ file_time_type::min());
+}
+
+void
+fs::last_write_time(const path& p, file_time_type new_time)
+{
+ error_code ec;
+ last_write_time(p, new_time, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set file time", p, ec));
+}
+
+void
+fs::last_write_time(const path& p __attribute__((__unused__)),
+ file_time_type new_time, error_code& ec) noexcept
+{
+ auto d = new_time.time_since_epoch();
+ auto s = chrono::duration_cast<chrono::seconds>(d);
+#if _GLIBCXX_USE_UTIMENSAT
+ auto ns = chrono::duration_cast<chrono::nanoseconds>(d - s);
+ if (ns < ns.zero()) // tv_nsec must be non-negative and less than 10e9.
+ {
+ --s;
+ ns += chrono::seconds(1);
+ }
+ struct ::timespec ts[2];
+ ts[0].tv_sec = 0;
+ ts[0].tv_nsec = UTIME_OMIT;
+ ts[1].tv_sec = static_cast<std::time_t>(s.count());
+ ts[1].tv_nsec = static_cast<long>(ns.count());
+ if (::utimensat(AT_FDCWD, p.c_str(), ts, 0))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#elif _GLIBCXX_HAVE_UTIME_H
+ ::utimbuf times;
+ times.modtime = s.count();
+ times.actime = do_stat(p, ec, [](const auto& st) { return st.st_atime; },
+ times.modtime);
+ if (::utime(p.c_str(), &times))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+void
+fs::permissions(const path& p, perms prms, perm_options opts)
+{
+ error_code ec;
+ permissions(p, prms, opts, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot set permissions", p, ec));
+}
+
+void
+fs::permissions(const path& p, perms prms, perm_options opts,
+ error_code& ec) noexcept
+{
+ const bool replace = is_set(opts, perm_options::replace);
+ const bool add = is_set(opts, perm_options::add);
+ const bool remove = is_set(opts, perm_options::remove);
+ const bool nofollow = is_set(opts, perm_options::nofollow);
+ if (((int)replace + (int)add + (int)remove) != 1)
+ {
+ ec = std::make_error_code(std::errc::invalid_argument);
+ return;
+ }
+
+ prms &= perms::mask;
+
+ file_status st;
+ if (add || remove || nofollow)
+ {
+ st = nofollow ? symlink_status(p, ec) : status(p, ec);
+ if (ec)
+ return;
+ auto curr = st.permissions();
+ if (add)
+ prms |= curr;
+ else if (remove)
+ prms = curr & ~prms;
+ }
+
+ int err = 0;
+#if _GLIBCXX_USE_FCHMODAT
+ const int flag = (nofollow && is_symlink(st)) ? AT_SYMLINK_NOFOLLOW : 0;
+ if (::fchmodat(AT_FDCWD, p.c_str(), static_cast<mode_t>(prms), flag))
+ err = errno;
+#else
+ if (nofollow && is_symlink(st))
+ ec = std::make_error_code(std::errc::operation_not_supported);
+ else if (::chmod(p.c_str(), static_cast<mode_t>(prms)))
+ err = errno;
+#endif
+
+ if (err)
+ ec.assign(err, std::generic_category());
+ else
+ ec.clear();
+}
+
+fs::path
+fs::proximate(const path& p, const path& base)
+{
+ return weakly_canonical(p).lexically_proximate(weakly_canonical(base));
+}
+
+fs::path
+fs::proximate(const path& p, const path& base, error_code& ec)
+{
+ path result;
+ const auto p2 = weakly_canonical(p, ec);
+ if (!ec)
+ {
+ const auto base2 = weakly_canonical(base, ec);
+ if (!ec)
+ result = p2.lexically_proximate(base2);
+ }
+ return result;
+}
+
+fs::path
+fs::read_symlink(const path& p)
+{
+ error_code ec;
+ path tgt = read_symlink(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("read_symlink", p, ec));
+ return tgt;
+}
+
+fs::path fs::read_symlink(const path& p, error_code& ec)
+{
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+ stat_type st;
+ if (::lstat(p.c_str(), &st))
+ {
+ ec.assign(errno, std::generic_category());
+ return {};
+ }
+ std::string buf(st.st_size, '\0');
+ ssize_t len = ::readlink(p.c_str(), &buf.front(), buf.size());
+ if (len == -1)
+ {
+ ec.assign(errno, std::generic_category());
+ return {};
+ }
+ ec.clear();
+ return path{buf.data(), buf.data()+len};
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+ return {};
+#endif
+}
+
+fs::path
+fs::relative(const path& p, const path& base)
+{
+ return weakly_canonical(p).lexically_relative(weakly_canonical(base));
+}
+
+fs::path
+fs::relative(const path& p, const path& base, error_code& ec)
+{
+ auto result = weakly_canonical(p, ec);
+ fs::path cbase;
+ if (!ec)
+ cbase = weakly_canonical(base, ec);
+ if (!ec)
+ result = result.lexically_relative(cbase);
+ if (ec)
+ result.clear();
+ return result;
+}
+
+bool
+fs::remove(const path& p)
+{
+ error_code ec;
+ bool result = fs::remove(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove", p, ec));
+ return result;
+}
+
+bool
+fs::remove(const path& p, error_code& ec) noexcept
+{
+ if (exists(symlink_status(p, ec)))
+ {
+ if (::remove(p.c_str()) == 0)
+ {
+ ec.clear();
+ return true;
+ }
+ else
+ ec.assign(errno, std::generic_category());
+ }
+ return false;
+}
+
+
+std::uintmax_t
+fs::remove_all(const path& p)
+{
+ error_code ec;
+ bool result = remove_all(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot remove all", p, ec));
+ return result;
+}
+
+std::uintmax_t
+fs::remove_all(const path& p, error_code& ec) noexcept
+{
+ auto fs = symlink_status(p, ec);
+ uintmax_t count = 0;
+ if (!ec && fs.type() == file_type::directory)
+ for (directory_iterator d(p, ec), end; !ec && d != end; ++d)
+ count += fs::remove_all(d->path(), ec);
+ if (ec)
+ return -1;
+ return fs::remove(p, ec) ? ++count : -1; // fs:remove() calls ec.clear()
+}
+
+void
+fs::rename(const path& from, const path& to)
+{
+ error_code ec;
+ rename(from, to, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot rename", from, to, ec));
+}
+
+void
+fs::rename(const path& from, const path& to, error_code& ec) noexcept
+{
+ if (::rename(from.c_str(), to.c_str()))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+}
+
+void
+fs::resize_file(const path& p, uintmax_t size)
+{
+ error_code ec;
+ resize_file(p, size, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot resize file", p, ec));
+}
+
+void
+fs::resize_file(const path& p, uintmax_t size, error_code& ec) noexcept
+{
+#ifdef _GLIBCXX_HAVE_UNISTD_H
+ if (size > static_cast<uintmax_t>(std::numeric_limits<off_t>::max()))
+ ec.assign(EINVAL, std::generic_category());
+ else if (::truncate(p.c_str(), size))
+ ec.assign(errno, std::generic_category());
+ else
+ ec.clear();
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+}
+
+
+fs::space_info
+fs::space(const path& p)
+{
+ error_code ec;
+ space_info s = space(p, ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("cannot get free space", p, ec));
+ return s;
+}
+
+fs::space_info
+fs::space(const path& p, error_code& ec) noexcept
+{
+ space_info info = {
+ static_cast<uintmax_t>(-1),
+ static_cast<uintmax_t>(-1),
+ static_cast<uintmax_t>(-1)
+ };
+#ifdef _GLIBCXX_HAVE_SYS_STATVFS_H
+ struct ::statvfs f;
+ if (::statvfs(p.c_str(), &f))
+ ec.assign(errno, std::generic_category());
+ else
+ {
+ info = space_info{
+ f.f_blocks * f.f_frsize,
+ f.f_bfree * f.f_frsize,
+ f.f_bavail * f.f_frsize
+ };
+ ec.clear();
+ }
+#else
+ ec = std::make_error_code(std::errc::not_supported);
+#endif
+ return info;
+}
+
+#ifdef _GLIBCXX_HAVE_SYS_STAT_H
+fs::file_status
+fs::status(const fs::path& p, error_code& ec) noexcept
+{
+ file_status status;
+ stat_type st;
+ if (::stat(p.c_str(), &st))
+ {
+ int err = errno;
+ ec.assign(err, std::generic_category());
+ if (is_not_found_errno(err))
+ status.type(file_type::not_found);
+#ifdef EOVERFLOW
+ else if (err == EOVERFLOW)
+ status.type(file_type::unknown);
+#endif
+ }
+ else
+ {
+ status = make_file_status(st);
+ ec.clear();
+ }
+ return status;
+}
+
+fs::file_status
+fs::symlink_status(const fs::path& p, std::error_code& ec) noexcept
+{
+ file_status status;
+ stat_type st;
+ if (::lstat(p.c_str(), &st))
+ {
+ int err = errno;
+ ec.assign(err, std::generic_category());
+ if (is_not_found_errno(err))
+ status.type(file_type::not_found);
+ }
+ else
+ {
+ status = make_file_status(st);
+ ec.clear();
+ }
+ return status;
+}
+#endif
+
+fs::file_status
+fs::status(const fs::path& p)
+{
+ std::error_code ec;
+ auto result = status(p, ec);
+ if (result.type() == file_type::none)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("status", p, ec));
+ return result;
+}
+
+fs::file_status
+fs::symlink_status(const fs::path& p)
+{
+ std::error_code ec;
+ auto result = symlink_status(p, ec);
+ if (result.type() == file_type::none)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("symlink_status", p, ec));
+ return result;
+}
+
+fs::path fs::temp_directory_path()
+{
+ error_code ec;
+ path tmp = temp_directory_path(ec);
+ if (ec)
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error("temp_directory_path", ec));
+ return tmp;
+}
+
+fs::path fs::temp_directory_path(error_code& ec)
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ ec = std::make_error_code(std::errc::not_supported);
+ return {}; // TODO
+#else
+ const char* tmpdir = nullptr;
+ const char* env[] = { "TMPDIR", "TMP", "TEMP", "TEMPDIR", nullptr };
+ for (auto e = env; tmpdir == nullptr && *e != nullptr; ++e)
+ tmpdir = ::getenv(*e);
+ path p = tmpdir ? tmpdir : "/tmp";
+ auto st = status(p, ec);
+ if (!ec)
+ {
+ if (is_directory(st))
+ {
+ ec.clear();
+ return p;
+ }
+ else
+ ec = std::make_error_code(std::errc::not_a_directory);
+ }
+ return {};
+#endif
+}
+
+fs::path
+fs::weakly_canonical(const path& p)
+{
+ path result;
+ if (exists(status(p)))
+ return canonical(p);
+
+ path tmp;
+ auto iter = p.begin(), end = p.end();
+ // find leading elements of p that exist:
+ while (iter != end)
+ {
+ tmp = result / *iter;
+ if (exists(status(tmp)))
+ swap(result, tmp);
+ else
+ break;
+ ++iter;
+ }
+ // canonicalize:
+ result = canonical(result);
+ // append the non-existing elements:
+ while (iter != end)
+ result /= *iter++;
+ // normalize:
+ return result.lexically_normal();
+}
+
+fs::path
+fs::weakly_canonical(const path& p, error_code& ec)
+{
+ path result;
+ file_status st = status(p, ec);
+ if (exists(st))
+ return canonical(p, ec);
+ else if (status_known(st))
+ ec.clear();
+ else
+ return result;
+
+ path tmp;
+ auto iter = p.begin(), end = p.end();
+ // find leading elements of p that exist:
+ while (iter != end)
+ {
+ tmp = result / *iter;
+ st = status(tmp, ec);
+ if (exists(st))
+ swap(result, tmp);
+ else
+ {
+ if (status_known(st))
+ ec.clear();
+ break;
+ }
+ ++iter;
+ }
+ // canonicalize:
+ if (!ec)
+ result = canonical(result, ec);
+ if (ec)
+ result.clear();
+ else
+ {
+ // append the non-existing elements:
+ while (iter != end)
+ result /= *iter++;
+ // normalize:
+ result = result.lexically_normal();
+ }
+ return result;
+}
diff --git a/libstdc++-v3/src/filesystem/std-path.cc b/libstdc++-v3/src/filesystem/std-path.cc
new file mode 100644
index 0000000..b5dd36d
--- /dev/null
+++ b/libstdc++-v3/src/filesystem/std-path.cc
@@ -0,0 +1,688 @@
+// Class filesystem::path -*- C++ -*-
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU 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
+// <http://www.gnu.org/licenses/>.
+
+#ifndef _GLIBCXX_USE_CXX11_ABI
+# define _GLIBCXX_USE_CXX11_ABI 1
+#endif
+
+#include <filesystem>
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+# include <algorithm>
+#endif
+
+namespace fs = std::filesystem;
+using fs::path;
+
+fs::filesystem_error::~filesystem_error() = default;
+
+constexpr path::value_type path::preferred_separator;
+
+path&
+path::remove_filename()
+{
+ if (_M_type == _Type::_Multi)
+ {
+ if (!_M_cmpts.empty())
+ {
+ auto cmpt = std::prev(_M_cmpts.end());
+ if (cmpt->_M_type == _Type::_Filename && !cmpt->empty())
+ {
+ _M_pathname.erase(cmpt->_M_pos);
+ auto prev = std::prev(cmpt);
+ if (prev->_M_type == _Type::_Root_dir
+ || prev->_M_type == _Type::_Root_name)
+ {
+ _M_cmpts.erase(cmpt);
+ _M_trim();
+ }
+ else
+ cmpt->clear();
+ }
+ }
+ }
+ else if (_M_type == _Type::_Filename)
+ clear();
+ if (!empty() && _M_pathname.back() != '/')
+ throw 1;
+ return *this;
+}
+
+path&
+path::replace_filename(const path& replacement)
+{
+ remove_filename();
+ operator/=(replacement);
+ return *this;
+}
+
+path&
+path::replace_extension(const path& replacement)
+{
+ auto ext = _M_find_extension();
+ // Any existing extension() is removed
+ if (ext.first && ext.second != string_type::npos)
+ {
+ if (ext.first == &_M_pathname)
+ _M_pathname.erase(ext.second);
+ else
+ {
+ const auto& back = _M_cmpts.back();
+ if (ext.first != &back._M_pathname)
+ _GLIBCXX_THROW_OR_ABORT(
+ std::logic_error("path::replace_extension failed"));
+ _M_pathname.erase(back._M_pos + ext.second);
+ }
+ }
+ // If replacement is not empty and does not begin with a dot character,
+ // a dot character is appended
+ if (!replacement.empty() && replacement.native()[0] != '.')
+ _M_pathname += '.';
+ operator+=(replacement);
+ return *this;
+}
+
+namespace
+{
+ template<typename Iter1, typename Iter2>
+ int do_compare(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2)
+ {
+ int cmpt = 1;
+ while (begin1 != end1 && begin2 != end2)
+ {
+ if (begin1->native() < begin2->native())
+ return -cmpt;
+ if (begin1->native() > begin2->native())
+ return +cmpt;
+ ++begin1;
+ ++begin2;
+ ++cmpt;
+ }
+ if (begin1 == end1)
+ {
+ if (begin2 == end2)
+ return 0;
+ return -cmpt;
+ }
+ return +cmpt;
+ }
+}
+
+int
+path::compare(const path& p) const noexcept
+{
+ struct CmptRef
+ {
+ const path* ptr;
+ const string_type& native() const noexcept { return ptr->native(); }
+ };
+
+ if (empty() && p.empty())
+ return 0;
+ else if (_M_type == _Type::_Multi && p._M_type == _Type::_Multi)
+ return do_compare(_M_cmpts.begin(), _M_cmpts.end(),
+ p._M_cmpts.begin(), p._M_cmpts.end());
+ else if (_M_type == _Type::_Multi)
+ {
+ CmptRef c[1] = { { &p } };
+ return do_compare(_M_cmpts.begin(), _M_cmpts.end(), c, c+1);
+ }
+ else if (p._M_type == _Type::_Multi)
+ {
+ CmptRef c[1] = { { this } };
+ return do_compare(c, c+1, p._M_cmpts.begin(), p._M_cmpts.end());
+ }
+ else
+ return _M_pathname.compare(p._M_pathname);
+}
+
+path
+path::root_name() const
+{
+ path __ret;
+ if (_M_type == _Type::_Root_name)
+ __ret = *this;
+ else if (_M_cmpts.size() && _M_cmpts.begin()->_M_type == _Type::_Root_name)
+ __ret = *_M_cmpts.begin();
+ return __ret;
+}
+
+path
+path::root_directory() const
+{
+ path __ret;
+ if (_M_type == _Type::_Root_dir)
+ {
+ __ret._M_type = _Type::_Root_dir;
+ __ret._M_pathname.assign(1, preferred_separator);
+ }
+ else if (!_M_cmpts.empty())
+ {
+ auto __it = _M_cmpts.begin();
+ if (__it->_M_type == _Type::_Root_name)
+ ++__it;
+ if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+ __ret = *__it;
+ }
+ return __ret;
+}
+
+path
+path::root_path() const
+{
+ path __ret;
+ if (_M_type == _Type::_Root_name)
+ __ret = *this;
+ else if (_M_type == _Type::_Root_dir)
+ {
+ __ret._M_pathname.assign(1, preferred_separator);
+ __ret._M_type = _Type::_Root_dir;
+ }
+ else if (!_M_cmpts.empty())
+ {
+ auto __it = _M_cmpts.begin();
+ if (__it->_M_type == _Type::_Root_name)
+ {
+ __ret = *__it++;
+ if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+ __ret /= *__it;
+ }
+ else if (__it->_M_type == _Type::_Root_dir)
+ __ret = *__it;
+ }
+ return __ret;
+}
+
+path
+path::relative_path() const
+{
+ path __ret;
+ if (_M_type == _Type::_Filename)
+ __ret = *this;
+ else if (!_M_cmpts.empty())
+ {
+ auto __it = _M_cmpts.begin();
+ if (__it->_M_type == _Type::_Root_name)
+ ++__it;
+ if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+ ++__it;
+ if (__it != _M_cmpts.end())
+ __ret.assign(_M_pathname.substr(__it->_M_pos));
+ }
+ return __ret;
+}
+
+path
+path::parent_path() const
+{
+ path __ret;
+ if (!has_relative_path())
+ __ret = *this;
+ else if (_M_cmpts.size() >= 2)
+ {
+ for (auto __it = _M_cmpts.begin(), __end = std::prev(_M_cmpts.end());
+ __it != __end; ++__it)
+ {
+ __ret /= *__it;
+ }
+ }
+ return __ret;
+}
+
+bool
+path::has_root_name() const
+{
+ if (_M_type == _Type::_Root_name)
+ return true;
+ if (!_M_cmpts.empty() && _M_cmpts.begin()->_M_type == _Type::_Root_name)
+ return true;
+ return false;
+}
+
+bool
+path::has_root_directory() const
+{
+ if (_M_type == _Type::_Root_dir)
+ return true;
+ if (!_M_cmpts.empty())
+ {
+ auto __it = _M_cmpts.begin();
+ if (__it->_M_type == _Type::_Root_name)
+ ++__it;
+ if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+ return true;
+ }
+ return false;
+}
+
+bool
+path::has_root_path() const
+{
+ if (_M_type == _Type::_Root_name || _M_type == _Type::_Root_dir)
+ return true;
+ if (!_M_cmpts.empty())
+ {
+ auto __type = _M_cmpts.front()._M_type;
+ if (__type == _Type::_Root_name || __type == _Type::_Root_dir)
+ return true;
+ }
+ return false;
+}
+
+bool
+path::has_relative_path() const
+{
+ if (_M_type == _Type::_Filename)
+ return true;
+ if (!_M_cmpts.empty())
+ {
+ auto __it = _M_cmpts.begin();
+ if (__it->_M_type == _Type::_Root_name)
+ ++__it;
+ if (__it != _M_cmpts.end() && __it->_M_type == _Type::_Root_dir)
+ ++__it;
+ if (__it != _M_cmpts.end())
+ return true;
+ }
+ return false;
+}
+
+
+bool
+path::has_parent_path() const
+{
+ if (!has_relative_path())
+ return !empty();
+ return _M_cmpts.size() >= 2;
+}
+
+bool
+path::has_filename() const
+{
+ if (empty())
+ return false;
+ if (_M_type == _Type::_Filename)
+ return !_M_pathname.empty();
+ if (_M_type == _Type::_Multi)
+ {
+ if (_M_pathname.back() == preferred_separator)
+ return false;
+ return _M_cmpts.back().has_filename();
+ }
+ return false;
+}
+
+namespace
+{
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ inline bool is_dot(wchar_t c) { return c == L'.'; }
+#else
+ inline bool is_dot(char c) { return c == '.'; }
+#endif
+
+ inline bool is_dot(const fs::path& path)
+ {
+ const auto& filename = path.native();
+ return filename.size() == 1 && is_dot(filename[0]);
+ }
+
+ inline bool is_dotdot(const fs::path& path)
+ {
+ const auto& filename = path.native();
+ return filename.size() == 2 && is_dot(filename[0]) && is_dot(filename[1]);
+ }
+} // namespace
+
+path
+path::lexically_normal() const
+{
+ /*
+ C++17 [fs.path.generic] p6
+ - If the path is empty, stop.
+ - Replace each slash character in the root-name with a preferred-separator.
+ - Replace each directory-separator with a preferred-separator.
+ - Remove each dot filename and any immediately following directory-separator.
+ - As long as any appear, remove a non-dot-dot filename immediately followed
+ by a directory-separator and a dot-dot filename, along with any immediately
+ following directory-separator.
+ - If the last filename is dot-dot, remove any trailing directory-separator.
+ - If the path is empty, add a dot.
+ */
+ path ret;
+ // If the path is empty, stop.
+ if (empty())
+ return ret;
+ for (auto& p : *this)
+ {
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ // Replace each slash character in the root-name
+ if (p.is_root_name())
+ {
+ string_type s = p.native();
+ std::replace(s.begin(), s.end(), L'/', L'\\');
+ ret /= s;
+ continue;
+ }
+#endif
+ if (is_dotdot(p))
+ {
+ if (ret.has_filename() && !is_dotdot(ret.filename()))
+ ret.remove_filename();
+ else
+ ret /= p;
+ }
+ else if (is_dot(p))
+ ret /= path();
+ else
+ ret /= p;
+ }
+
+ if (ret._M_cmpts.size() >= 2)
+ {
+ auto back = std::prev(ret.end());
+ // If the last filename is dot-dot, ...
+ if (back->empty() && is_dotdot(*std::prev(back)))
+ // ... remove any trailing directory-separator.
+ ret = ret.parent_path();
+ }
+ // If the path is empty, add a dot.
+ else if (ret.empty())
+ ret = ".";
+
+ return ret;
+}
+
+path
+path::lexically_relative(const path& base) const
+{
+ path ret;
+ if (root_name() != base.root_name())
+ return ret;
+ if (is_absolute() != base.is_absolute())
+ return ret;
+ if (!has_root_directory() && base.has_root_directory())
+ return ret;
+ auto [a, b] = std::mismatch(begin(), end(), base.begin(), base.end());
+ if (a == end() && b == base.end())
+ ret = ".";
+ else
+ {
+ int n = 0;
+ for (; b != base.end(); ++b)
+ {
+ const path& p = *b;
+ if (is_dotdot(p))
+ --n;
+ else if (!is_dot(p))
+ ++n;
+ }
+ if (n >= 0)
+ {
+ const path dotdot("..");
+ while (n--)
+ ret /= dotdot;
+ for (; a != end(); ++a)
+ ret /= *a;
+ }
+ }
+ return ret;
+}
+
+path
+path::lexically_proximate(const path& base) const
+{
+ path rel = lexically_relative(base);
+ if (rel.empty())
+ rel = *this;
+ return rel;
+}
+
+std::pair<const path::string_type*, std::size_t>
+path::_M_find_extension() const
+{
+ const std::string* s = nullptr;
+
+ if (_M_type == _Type::_Filename)
+ s = &_M_pathname;
+ else if (_M_type == _Type::_Multi && !_M_cmpts.empty())
+ {
+ const auto& c = _M_cmpts.back();
+ if (c._M_type == _Type::_Filename)
+ s = &c._M_pathname;
+ }
+
+ if (s)
+ {
+ if (auto sz = s->size())
+ {
+ if (sz <= 2 && (*s)[0] == '.')
+ return { s, string_type::npos };
+ const auto pos = s->rfind('.');
+ return { s, pos ? pos : string_type::npos };
+ }
+ }
+ return {};
+}
+
+void
+path::_M_split_cmpts()
+{
+ _M_type = _Type::_Multi;
+ _M_cmpts.clear();
+
+ if (_M_pathname.empty())
+ return;
+
+ size_t pos = 0;
+ const size_t len = _M_pathname.size();
+
+ // look for root name or root directory
+ if (_S_is_dir_sep(_M_pathname[0]))
+ {
+#ifdef __CYGWIN__
+ // look for root name, such as "//foo"
+ if (len > 2 && _M_pathname[1] == _M_pathname[0])
+ {
+ if (!_S_is_dir_sep(_M_pathname[2]))
+ {
+ // got root name, find its end
+ pos = 3;
+ while (pos < len && !_S_is_dir_sep(_M_pathname[pos]))
+ ++pos;
+ _M_add_root_name(pos);
+ if (pos < len) // also got root directory
+ _M_add_root_dir(pos);
+ }
+ else
+ {
+ // got something like "///foo" which is just a root directory
+ // composed of multiple redundant directory separators
+ _M_add_root_dir(0);
+ }
+ }
+ else
+#endif
+ {
+ // got root directory
+ if (_M_pathname.find_first_not_of('/') == string_type::npos)
+ {
+ // entire path is just slashes
+ _M_type = _Type::_Root_dir;
+ return;
+ }
+ _M_add_root_dir(0);
+ ++pos;
+ }
+ }
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ else if (len > 1 && _M_pathname[1] == L':')
+ {
+ // got disk designator
+ _M_add_root_name(2);
+ if (len > 2 && _S_is_dir_sep(_M_pathname[2]))
+ _M_add_root_dir(2);
+ pos = 2;
+ }
+#endif
+
+ size_t back = pos;
+ while (pos < len)
+ {
+ if (_S_is_dir_sep(_M_pathname[pos]))
+ {
+ if (back != pos)
+ _M_add_filename(back, pos - back);
+ back = ++pos;
+ }
+ else
+ ++pos;
+ }
+
+ if (back != pos)
+ _M_add_filename(back, pos - back);
+ else if (_S_is_dir_sep(_M_pathname.back()))
+ {
+ // [fs.path.itr]/4
+ // An empty element, if trailing non-root directory-separator present.
+ if (_M_cmpts.back()._M_type == _Type::_Filename)
+ {
+ const auto& last = _M_cmpts.back();
+ pos = last._M_pos + last._M_pathname.size();
+ _M_cmpts.emplace_back(string_type(), _Type::_Filename, pos);
+ }
+ }
+
+ _M_trim();
+}
+
+void
+path::_M_add_root_name(size_t n)
+{
+ _M_cmpts.emplace_back(_M_pathname.substr(0, n), _Type::_Root_name, 0);
+}
+
+void
+path::_M_add_root_dir(size_t pos)
+{
+ _M_cmpts.emplace_back(_M_pathname.substr(pos, 1), _Type::_Root_dir, pos);
+}
+
+void
+path::_M_add_filename(size_t pos, size_t n)
+{
+ _M_cmpts.emplace_back(_M_pathname.substr(pos, n), _Type::_Filename, pos);
+}
+
+void
+path::_M_trim()
+{
+ if (_M_cmpts.size() == 1)
+ {
+ _M_type = _M_cmpts.front()._M_type;
+ _M_cmpts.clear();
+ }
+}
+
+path::string_type
+path::_S_convert_loc(const char* __first, const char* __last,
+ const std::locale& __loc)
+{
+#if _GLIBCXX_USE_WCHAR_T
+ auto& __cvt = std::use_facet<codecvt<wchar_t, char, mbstate_t>>(__loc);
+ basic_string<wchar_t> __ws;
+ if (!__str_codecvt_in(__first, __last, __ws, __cvt))
+ _GLIBCXX_THROW_OR_ABORT(filesystem_error(
+ "Cannot convert character sequence",
+ std::make_error_code(errc::illegal_byte_sequence)));
+#ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
+ return __ws;
+#else
+ return _Cvt<wchar_t>::_S_convert(__ws.data(), __ws.data() + __ws.size());
+#endif
+#else
+ return {__first, __last};
+#endif
+}
+
+std::size_t
+fs::hash_value(const path& p) noexcept
+{
+ // [path.non-member]
+ // "If for two paths, p1 == p2 then hash_value(p1) == hash_value(p2)."
+ // Equality works as if by traversing the range [begin(), end()), meaning
+ // e.g. path("a//b") == path("a/b"), so we cannot simply hash _M_pathname
+ // but need to iterate over individual elements. Use the hash_combine from
+ // http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3876.pdf
+ size_t seed = 0;
+ for (const auto& x : p)
+ {
+ seed ^= std::hash<path::string_type>()(x.native()) + 0x9e3779b9
+ + (seed<<6) + (seed>>2);
+ }
+ return seed;
+}
+
+namespace std
+{
+_GLIBCXX_BEGIN_NAMESPACE_VERSION
+namespace filesystem
+{
+ string
+ fs_err_concat(const string& __what, const string& __path1,
+ const string& __path2)
+ {
+ const size_t __len = 18 + __what.length()
+ + (__path1.length() ? __path1.length() + 3 : 0)
+ + (__path2.length() ? __path2.length() + 3 : 0);
+ string __ret;
+ __ret.reserve(__len);
+ __ret = "filesystem error: ";
+ __ret += __what;
+ if (!__path1.empty())
+ {
+ __ret += " [";
+ __ret += __path1;
+ __ret += ']';
+ }
+ if (!__path2.empty())
+ {
+ __ret += " [";
+ __ret += __path2;
+ __ret += ']';
+ }
+ return __ret;
+ }
+
+_GLIBCXX_BEGIN_NAMESPACE_CXX11
+
+ std::string filesystem_error::_M_gen_what()
+ {
+ return fs_err_concat(system_error::what(), _M_path1.native(),
+ _M_path2.native());
+ }
+
+_GLIBCXX_END_NAMESPACE_CXX11
+
+} // filesystem
+_GLIBCXX_END_NAMESPACE_VERSION
+} // std
diff --git a/libstdc++-v3/testsuite/18_support/byte/requirements.cc b/libstdc++-v3/testsuite/18_support/byte/requirements.cc
index 4cb05df..74c8b64 100644
--- a/libstdc++-v3/testsuite/18_support/byte/requirements.cc
+++ b/libstdc++-v3/testsuite/18_support/byte/requirements.cc
@@ -20,6 +20,12 @@
#include <cstddef>
+#ifndef __cpp_lib_byte
+# error "Feature-test macro for byte missing"
+#elif __cpp_lib_byte != 201603
+# error "Feature-test macro for byte has wrong value"
+#endif
+
static_assert( sizeof(std::byte) == sizeof(unsigned char) );
static_assert( alignof(std::byte) == alignof(unsigned char) );
diff --git a/libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc b/libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc
index a53b066..635672c 100644
--- a/libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc
+++ b/libstdc++-v3/testsuite/18_support/exception_ptr/62258.cc
@@ -1,3 +1,4 @@
+// { dg-options "-Wno-deprecated" }
// { dg-do run { target c++11 } }
// Copyright (C) 2015-2017 Free Software Foundation, Inc.
diff --git a/libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc b/libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc
index 78581af..8bc4953 100644
--- a/libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc
+++ b/libstdc++-v3/testsuite/18_support/uncaught_exception/14026.cc
@@ -18,6 +18,8 @@
// PR 14026
// 18.6.4 uncaught_exception
+// { dg-options "-Wno-deprecated" }
+
#include <cstdlib>
#include <exception>
#include <testsuite_hooks.h>
diff --git a/libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc b/libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc
index 438d50a..0ba1b8c 100644
--- a/libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc
+++ b/libstdc++-v3/testsuite/20_util/duration/arithmetic/constexpr_c++17.cc
@@ -20,6 +20,13 @@
#include <chrono>
#include <testsuite_common_types.h>
+
+#ifndef __cpp_lib_chrono
+# error "Feature-test macro for constexpr <chrono> missing"
+#elif __cpp_lib_chrono != 201611
+# error "Feature-test macro for constexpr <chrono> has wrong value"
+#endif
+
constexpr auto test_operators()
{
std::chrono::nanoseconds d1 { 1 };
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/1.cc b/libstdc++-v3/testsuite/20_util/from_chars/1.cc
new file mode 100644
index 0000000..b552195
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/from_chars/1.cc
@@ -0,0 +1,80 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <charconv>
+#include <string_view>
+
+template<typename I>
+bool
+check_from_chars(I expected, std::string_view s, int base = 0, char term = '\0')
+{
+ I val;
+ std::from_chars_result r = base == 0
+ ? std::from_chars(s.begin(), s.end(), val)
+ : std::from_chars(s.begin(), s.end(), val, base);
+ return r.ec == std::errc{} && (r.ptr == s.end() || *r.ptr == term) && val == expected;
+}
+
+#include <climits>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ // Using base 10
+ VERIFY( check_from_chars(123, "123") );
+ VERIFY( check_from_chars(-123, "-123") );
+ VERIFY( check_from_chars(123, "123a", 10, 'a') );
+ VERIFY( check_from_chars(123, "0000000000000000000000000000123") );
+ VERIFY( check_from_chars(123, "0000000000000000000000000000123a", 10, 'a') );
+}
+
+void
+test02()
+{
+ // "0x" parsed as "0" not as hex prefix:
+ VERIFY( check_from_chars(0, "0x1", 10, 'x') );
+ VERIFY( check_from_chars(0, "0X1", 10, 'X') );
+ VERIFY( check_from_chars(0, "0x1", 16, 'x') );
+ VERIFY( check_from_chars(0, "0X1", 16, 'X') );
+
+ VERIFY( check_from_chars(1155, "xx", 34) );
+ VERIFY( check_from_chars(1155, "XX", 34) );
+ VERIFY( check_from_chars(1155, "Xx", 34) );
+ VERIFY( check_from_chars(1224, "yy", 35) );
+ VERIFY( check_from_chars(1224, "YY", 35) );
+ VERIFY( check_from_chars(1224, "yY", 35) );
+ VERIFY( check_from_chars(1295, "zz", 36) );
+ VERIFY( check_from_chars(1295, "ZZ", 36) );
+ VERIFY( check_from_chars(1295, "Zz", 36) );
+
+ // Parsing stops at first invalid digit for the given base:
+ VERIFY( check_from_chars(1, "01234", 2, '2') );
+ VERIFY( check_from_chars(27, "1234", 4, '4') );
+ VERIFY( check_from_chars(1155, "xxy", 34, 'y') );
+ VERIFY( check_from_chars(1224, "yyz", 35, 'z') );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/1_neg.cc b/libstdc++-v3/testsuite/20_util/from_chars/1_neg.cc
new file mode 100644
index 0000000..d826ba9
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/from_chars/1_neg.cc
@@ -0,0 +1,38 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <charconv>
+
+void
+test01(const char* first, const char* last)
+{
+#if _GLIBCXX_USE_WCHAR_T
+ wchar_t wc;
+ std::from_chars(first, last, wc); // { dg-error "no matching" }
+ std::from_chars(first, last, wc, 10); // { dg-error "no matching" }
+#endif
+
+ char16_t c16;
+ std::from_chars(first, last, c16); // { dg-error "no matching" }
+ std::from_chars(first, last, c16, 10); // { dg-error "no matching" }
+ char32_t c32;
+ std::from_chars(first, last, c32); // { dg-error "no matching" }
+ std::from_chars(first, last, c32, 10); // { dg-error "no matching" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/2.cc b/libstdc++-v3/testsuite/20_util/from_chars/2.cc
new file mode 100644
index 0000000..117cf74
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/from_chars/2.cc
@@ -0,0 +1,205 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <charconv>
+#include <string_view>
+#include <testsuite_hooks.h>
+
+// Test std::from_chars error handling.
+
+void
+test01()
+{
+ std::from_chars_result r;
+ int i = 999;
+ std::string_view s;
+
+ s = "";
+ r = std::from_chars(s.begin(), s.end(), i);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.begin() );
+ VERIFY( i == 999 );
+
+ s = "*";
+ r = std::from_chars(s.begin(), s.end(), i);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.begin() );
+ VERIFY( i == 999 );
+
+ s = "-";
+ r = std::from_chars(s.begin(), s.end(), i);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.begin() );
+ VERIFY( i == 999 );
+
+ s = "-*";
+ r = std::from_chars(s.begin(), s.end(), i);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.begin() );
+ VERIFY( i == 999 );
+
+ unsigned u = 888;
+ s = "-1";
+ r = std::from_chars(s.begin(), s.end(), u);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.begin() );
+ s = "-a";
+ r = std::from_chars(s.begin(), s.end(), u);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.begin() );
+ s = "-";
+ r = std::from_chars(s.begin(), s.end(), u);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == s.begin() );
+ VERIFY( u == 888 );
+
+ for (int base = 2; base <= 36; ++base)
+ {
+ const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz*";
+ const char buf[2] = { '-', digits[base] };
+ r = std::from_chars(buf, buf + 1, i, base);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == buf );
+ VERIFY( i == 999 );
+ r = std::from_chars(buf + 1, buf + 2, i, base);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == buf + 1 );
+ VERIFY( i == 999 );
+ r = std::from_chars(buf, buf + 2, i, base);
+ VERIFY( r.ec == std::errc::invalid_argument );
+ VERIFY( r.ptr == buf );
+ VERIFY( i == 999 );
+ }
+}
+
+void
+test02()
+{
+ std::from_chars_result r;
+ std::string_view s;
+
+ signed char c = -5;
+ s = "-10000001";
+ r = std::from_chars(s.begin(), s.end(), c, 2);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "-10000001*";
+ r = std::from_chars(s.begin(), s.end(), c, 2);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 9 );
+ s = "-10000001000*";
+ r = std::from_chars(s.begin(), s.end(), c, 2);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 12 );
+ s = "-129";
+ r = std::from_chars(s.begin(), s.end(), c, 10);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "-129*";
+ r = std::from_chars(s.begin(), s.end(), c, 10);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 4 );
+ s = "-100";
+ r = std::from_chars(s.begin(), s.end(), c, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "-100*";
+ r = std::from_chars(s.begin(), s.end(), c, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 4 );
+ s = "-81";
+ r = std::from_chars(s.begin(), s.end(), c, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "-81*";
+ r = std::from_chars(s.begin(), s.end(), c, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 3 );
+ s = "128";
+ r = std::from_chars(s.begin(), s.end(), c, 10);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "128*";
+ r = std::from_chars(s.begin(), s.end(), c, 10);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 3 );
+ s = "80";
+ r = std::from_chars(s.begin(), s.end(), c, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "80*";
+ r = std::from_chars(s.begin(), s.end(), c, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 2 );
+ VERIFY( c == -5 );
+
+ unsigned char uc = 9;
+ s = "100000000";
+ r = std::from_chars(s.begin(), s.end(), uc, 2);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "100000000*";
+ r = std::from_chars(s.begin(), s.end(), uc, 2);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 9 );
+ s = "100000000000*";
+ r = std::from_chars(s.begin(), s.end(), uc, 2);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 12 );
+ s = "256";
+ r = std::from_chars(s.begin(), s.end(), uc, 10);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "256**";
+ r = std::from_chars(s.begin(), s.end(), uc, 10);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 3 );
+ s = "256000**";
+ r = std::from_chars(s.begin(), s.end(), uc, 10);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 6 );
+ s = "100";
+ r = std::from_chars(s.begin(), s.end(), uc, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.end() );
+ s = "100**";
+ r = std::from_chars(s.begin(), s.end(), uc, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 3 );
+ s = "100000**";
+ r = std::from_chars(s.begin(), s.end(), uc, 16);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 6 );
+ VERIFY( uc == 9 );
+
+ unsigned long long ull = 123;
+ s = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz****";
+ r = std::from_chars(s.begin(), s.end(), ull, 36);
+ VERIFY( r.ec == std::errc::result_out_of_range );
+ VERIFY( r.ptr == s.begin() + 42 );
+ VERIFY( ull == 123 );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/20_util/from_chars/requirements.cc b/libstdc++-v3/testsuite/20_util/from_chars/requirements.cc
new file mode 100644
index 0000000..00b7d87
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/from_chars/requirements.cc
@@ -0,0 +1,61 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <charconv>
+
+namespace std
+{
+ struct from_chars_result;
+
+ const char* from_chars_result::*pm2 = &from_chars_result::ptr;
+ errc from_chars_result::*pm1 = &from_chars_result::ec;
+
+ from_chars_result (*f1)(const char*, const char*, char&, int)
+ = &from_chars;
+ from_chars_result (*f2)(const char*, const char*, signed char&, int)
+ = &from_chars;
+ from_chars_result (*f3)(const char*, const char*, unsigned char&, int)
+ = &from_chars;
+ from_chars_result (*f4)(const char*, const char*, signed short&, int)
+ = &from_chars;
+ from_chars_result (*f5)(const char*, const char*, unsigned short&, int)
+ = &from_chars;
+ from_chars_result (*f6)(const char*, const char*, signed int&, int)
+ = &from_chars;
+ from_chars_result (*f7)(const char*, const char*, unsigned int&, int)
+ = &from_chars;
+ from_chars_result (*f8)(const char*, const char*, signed long&, int)
+ = &from_chars;
+ from_chars_result (*f9)(const char*, const char*, unsigned long&, int)
+ = &from_chars;
+ from_chars_result (*f10)(const char*, const char*, signed long long&, int)
+ = &from_chars;
+ from_chars_result (*f11)(const char*, const char*, unsigned long long&, int)
+ = &from_chars;
+}
+
+void bind()
+{
+ const char buf[1] = "";
+ int i;
+ auto [p, e] = std::from_chars(buf, buf + 1, i, 10);
+ const char** pa = &p;
+ std::errc* ea = &e;
+}
diff --git a/libstdc++-v3/testsuite/20_util/optional/hash.cc b/libstdc++-v3/testsuite/20_util/optional/hash.cc
index c16f0b2..35ae51b 100644
--- a/libstdc++-v3/testsuite/20_util/optional/hash.cc
+++ b/libstdc++-v3/testsuite/20_util/optional/hash.cc
@@ -29,14 +29,23 @@ template<class T>
auto f(...) -> decltype(std::false_type());
static_assert(!decltype(f<S>(0))::value, "");
-static_assert(!std::is_invocable_v<
- std::hash<std::optional<S>>&, std::optional<S> const&> );
-static_assert(std::is_invocable_v<
- std::hash<std::optional<int>>&, std::optional<int> const&> );
+
+template<typename T>
+constexpr bool hashable()
+{ return std::is_invocable_v<std::hash<T>&, const T&>; }
+
+static_assert(!hashable<std::optional<S>>());
+static_assert(!hashable<std::optional<const S>>());
+static_assert(hashable<std::optional<int>>());
+static_assert(hashable<std::optional<const int>>());
int main()
{
int x = 42;
std::optional<int> x2 = 42;
VERIFY(std::hash<int>()(x) == std::hash<std::optional<int>>()(x2));
+
+ // PR libstdc++/82262
+ std::optional<const int> x3 = x2;
+ VERIFY(std::hash<int>()(x) == std::hash<std::optional<const int>>()(x3));
}
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/1.cc b/libstdc++-v3/testsuite/20_util/to_chars/1.cc
new file mode 100644
index 0000000..12dfd3d
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/to_chars/1.cc
@@ -0,0 +1,662 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+// { dg-require-string-conversions "" }
+
+#include <charconv>
+#include <string_view>
+
+template<typename I>
+bool
+check_to_chars(I val, std::string_view expected, int base = 0)
+{
+ // Space for minus sign, 64 binary digits, final '*', and null terminator:
+ char buf[67] = "******************************************************************";
+ std::to_chars_result r = base == 0
+ ? std::to_chars(buf, buf+sizeof(buf), val)
+ : std::to_chars(buf, buf+sizeof(buf), val, base);
+ return r.ec == std::errc{} && *r.ptr == '*' && std::string_view(buf, r.ptr - buf) == expected;
+}
+
+#include <string>
+#include <climits>
+#include <testsuite_hooks.h>
+
+// Using default base 10
+void
+test01()
+{
+ VERIFY( check_to_chars<char>(0, "0") );
+ VERIFY( check_to_chars<signed char>(0, "0") );
+ VERIFY( check_to_chars<unsigned char>(0, "0") );
+ VERIFY( check_to_chars<signed short>(0, "0") );
+ VERIFY( check_to_chars<unsigned short>(0, "0") );
+ VERIFY( check_to_chars<signed int>(0, "0") );
+ VERIFY( check_to_chars<unsigned int>(0, "0") );
+ VERIFY( check_to_chars<signed long>(0, "0") );
+ VERIFY( check_to_chars<unsigned long>(0, "0") );
+ VERIFY( check_to_chars<signed long long>(0, "0") );
+ VERIFY( check_to_chars<unsigned long long>(0, "0") );
+
+ VERIFY( check_to_chars<char>(1, "1") );
+ VERIFY( check_to_chars<signed char>(1, "1") );
+ VERIFY( check_to_chars<unsigned char>(1, "1") );
+ VERIFY( check_to_chars<signed short>(1, "1") );
+ VERIFY( check_to_chars<unsigned short>(1, "1") );
+ VERIFY( check_to_chars<signed int>(1, "1") );
+ VERIFY( check_to_chars<unsigned int>(1, "1") );
+ VERIFY( check_to_chars<signed long>(1, "1") );
+ VERIFY( check_to_chars<unsigned long>(1, "1") );
+ VERIFY( check_to_chars<signed long long>(1, "1") );
+ VERIFY( check_to_chars<unsigned long long>(1, "1") );
+
+ VERIFY( check_to_chars<char>(123, "123") );
+ VERIFY( check_to_chars<signed char>(123, "123") );
+ VERIFY( check_to_chars<unsigned char>(123, "123") );
+ VERIFY( check_to_chars<signed short>(123, "123") );
+ VERIFY( check_to_chars<unsigned short>(123, "123") );
+ VERIFY( check_to_chars<signed int>(123, "123") );
+ VERIFY( check_to_chars<unsigned int>(123, "123") );
+ VERIFY( check_to_chars<signed long>(123, "123") );
+ VERIFY( check_to_chars<unsigned long>(123, "123") );
+ VERIFY( check_to_chars<signed long long>(123, "123") );
+ VERIFY( check_to_chars<unsigned long long>(123, "123") );
+
+ if constexpr (std::is_signed_v<char>)
+ VERIFY( check_to_chars<char>(-79, "-79") );
+ VERIFY( check_to_chars<signed char>(-79, "-79") );
+ VERIFY( check_to_chars<signed short>(-79, "-79") );
+ VERIFY( check_to_chars<signed int>(-79, "-79") );
+ VERIFY( check_to_chars<signed long>(-79, "-79") );
+ VERIFY( check_to_chars<signed long long>(-79, "-79") );
+
+ using std::to_string;
+
+ VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX)) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX)) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX)) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX)) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX)) );
+ VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX)) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX)) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX)) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX)) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX)) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX)) );
+
+ VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN)) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN)) );
+ VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN)) );
+ VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN)) );
+ VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN)) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN)) );
+
+ VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2)) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2)) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2)) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2)) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2)) );
+ VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2)) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2)) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2)) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2)) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2)) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2)) );
+}
+
+// Using explicit base 10
+void
+test02()
+{
+ VERIFY( check_to_chars<char>(0, "0", 10) );
+ VERIFY( check_to_chars<signed char>(0, "0", 10) );
+ VERIFY( check_to_chars<unsigned char>(0, "0", 10) );
+ VERIFY( check_to_chars<signed short>(0, "0", 10) );
+ VERIFY( check_to_chars<unsigned short>(0, "0", 10) );
+ VERIFY( check_to_chars<signed int>(0, "0", 10) );
+ VERIFY( check_to_chars<unsigned int>(0, "0", 10) );
+ VERIFY( check_to_chars<signed long>(0, "0", 10) );
+ VERIFY( check_to_chars<unsigned long>(0, "0", 10) );
+ VERIFY( check_to_chars<signed long long>(0, "0", 10) );
+ VERIFY( check_to_chars<unsigned long long>(0, "0", 10) );
+
+ VERIFY( check_to_chars<char>(1, "1", 10) );
+ VERIFY( check_to_chars<signed char>(1, "1", 10) );
+ VERIFY( check_to_chars<unsigned char>(1, "1", 10) );
+ VERIFY( check_to_chars<signed short>(1, "1", 10) );
+ VERIFY( check_to_chars<unsigned short>(1, "1", 10) );
+ VERIFY( check_to_chars<signed int>(1, "1", 10) );
+ VERIFY( check_to_chars<unsigned int>(1, "1", 10) );
+ VERIFY( check_to_chars<signed long>(1, "1", 10) );
+ VERIFY( check_to_chars<unsigned long>(1, "1", 10) );
+ VERIFY( check_to_chars<signed long long>(1, "1", 10) );
+ VERIFY( check_to_chars<unsigned long long>(1, "1", 10) );
+
+ VERIFY( check_to_chars<char>(123, "123", 10) );
+ VERIFY( check_to_chars<signed char>(123, "123", 10) );
+ VERIFY( check_to_chars<unsigned char>(123, "123", 10) );
+ VERIFY( check_to_chars<signed short>(123, "123", 10) );
+ VERIFY( check_to_chars<unsigned short>(123, "123", 10) );
+ VERIFY( check_to_chars<signed int>(123, "123", 10) );
+ VERIFY( check_to_chars<unsigned int>(123, "123", 10) );
+ VERIFY( check_to_chars<signed long>(123, "123", 10) );
+ VERIFY( check_to_chars<unsigned long>(123, "123", 10) );
+ VERIFY( check_to_chars<signed long long>(123, "123", 10) );
+ VERIFY( check_to_chars<unsigned long long>(123, "123", 10) );
+
+ if constexpr (std::is_signed_v<char>)
+ VERIFY( check_to_chars<char>(-79, "-79", 10) );
+ VERIFY( check_to_chars<signed char>(-79, "-79", 10) );
+ VERIFY( check_to_chars<signed short>(-79, "-79", 10) );
+ VERIFY( check_to_chars<signed int>(-79, "-79", 10) );
+ VERIFY( check_to_chars<signed long>(-79, "-79", 10) );
+ VERIFY( check_to_chars<signed long long>(-79, "-79", 10) );
+
+ using std::to_string;
+
+ VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX), 10) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX), 10) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX), 10) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX), 10) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX), 10) );
+ VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX), 10) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX), 10) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX), 10) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX), 10) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX), 10) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX), 10) );
+
+ VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN), 10) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN), 10) );
+ VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN), 10) );
+ VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN), 10) );
+ VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN), 10) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN), 10) );
+
+ VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2), 10) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2), 10) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2), 10) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2), 10) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2), 10) );
+ VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2), 10) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2), 10) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2), 10) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2), 10) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2), 10) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2), 10) );
+}
+
+// Using all bases
+void
+test03()
+{
+ // -2017 in all bases from [2,36]
+ const char* str2017[37] = { nullptr, nullptr,
+ "-11111100001",
+ "-2202201",
+ "-133201",
+ "-31032",
+ "-13201",
+ "-5611",
+ "-3741",
+ "-2681",
+ "-2017",
+ "-1574",
+ "-1201",
+ "-bc2",
+ "-a41",
+ "-8e7",
+ "-7e1",
+ "-6gb",
+ "-641",
+ "-5b3",
+ "-50h",
+ "-4c1",
+ "-43f",
+ "-3ig",
+ "-3c1",
+ "-35h",
+ "-2pf",
+ "-2kj",
+ "-2g1",
+ "-2bg",
+ "-277",
+ "-232",
+ "-1v1",
+ "-1s4",
+ "-1pb",
+ "-1mm",
+ "-1k1"
+ };
+ // -12345 in all bases from [2,36]
+ const char* str12345[37] = { nullptr, nullptr,
+ "-11000000111001",
+ "-121221020",
+ "-3000321",
+ "-343340",
+ "-133053",
+ "-50664",
+ "-30071",
+ "-17836",
+ "-12345",
+ "-9303",
+ "-7189",
+ "-5808",
+ "-46db",
+ "-39d0",
+ "-3039",
+ "-28c3",
+ "-221f",
+ "-1f3e",
+ "-1ah5",
+ "-16ki",
+ "-13b3",
+ "-107h",
+ "-la9",
+ "-jik",
+ "-i6l",
+ "-gp6",
+ "-fkp",
+ "-ejk",
+ "-dlf",
+ "-cq7",
+ "-c1p",
+ "-bb3",
+ "-an3",
+ "-a2p",
+ "-9ix"
+ };
+ // -23456 in all bases from [2,36]
+ const char* str23456[37] = { nullptr, nullptr,
+ "-101101110100000",
+ "-1012011202",
+ "-11232200",
+ "-1222311",
+ "-300332",
+ "-125246",
+ "-55640",
+ "-35152",
+ "-23456",
+ "-16694",
+ "-116a8",
+ "-a8a4",
+ "-8796",
+ "-6e3b",
+ "-5ba0",
+ "-4d2d",
+ "-4072",
+ "-37ia",
+ "-2icg",
+ "-2b3k",
+ "-24a4",
+ "-1l7j",
+ "-1gh8",
+ "-1cd6",
+ "-18i4",
+ "-154k",
+ "-11pk",
+ "-rpo",
+ "-q1q",
+ "-ock",
+ "-mt0",
+ "-lhq",
+ "-k9u",
+ "-j56",
+ "-i3k"
+ };
+ // INT_MIN in all bases from [2,36]
+ const char* strINT_MIN[37] = { nullptr, nullptr,
+ "-10000000000000000000000000000000",
+ "-12112122212110202102",
+ "-2000000000000000",
+ "-13344223434043",
+ "-553032005532",
+ "-104134211162",
+ "-20000000000",
+ "-5478773672",
+ "-2147483648",
+ "-a02220282",
+ "-4bb2308a8",
+ "-282ba4aab",
+ "-1652ca932",
+ "-c87e66b8",
+ "-80000000",
+ "-53g7f549",
+ "-3928g3h2",
+ "-27c57h33",
+ "-1db1f928",
+ "-140h2d92",
+ "-ikf5bf2",
+ "-ebelf96",
+ "-b5gge58",
+ "-8jmdnkn",
+ "-6oj8ioo",
+ "-5ehnckb",
+ "-4clm98g",
+ "-3hk7988",
+ "-2sb6cs8",
+ "-2d09uc2",
+ "-2000000",
+ "-1lsqtl2",
+ "-1d8xqrq",
+ "-15v22un",
+ "-zik0zk"
+ };
+
+ for (int base = 2; base <= 36; ++base)
+ {
+ VERIFY( check_to_chars<char>(0, "0", base) );
+ VERIFY( check_to_chars<signed char>(0, "0", base) );
+ VERIFY( check_to_chars<unsigned char>(0, "0", base) );
+ VERIFY( check_to_chars<signed short>(0, "0", base) );
+ VERIFY( check_to_chars<unsigned short>(0, "0", base) );
+ VERIFY( check_to_chars<signed int>(0, "0", base) );
+ VERIFY( check_to_chars<unsigned int>(0, "0", base) );
+ VERIFY( check_to_chars<signed long>(0, "0", base) );
+ VERIFY( check_to_chars<unsigned long>(0, "0", base) );
+ VERIFY( check_to_chars<signed long long>(0, "0", base) );
+ VERIFY( check_to_chars<unsigned long long>(0, "0", base) );
+
+ VERIFY( check_to_chars<char>(1, "1", base) );
+ VERIFY( check_to_chars<signed char>(1, "1", base) );
+ VERIFY( check_to_chars<unsigned char>(1, "1", base) );
+ VERIFY( check_to_chars<signed short>(1, "1", base) );
+ VERIFY( check_to_chars<unsigned short>(1, "1", base) );
+ VERIFY( check_to_chars<signed int>(1, "1", base) );
+ VERIFY( check_to_chars<unsigned int>(1, "1", base) );
+ VERIFY( check_to_chars<signed long>(1, "1", base) );
+ VERIFY( check_to_chars<unsigned long>(1, "1", base) );
+ VERIFY( check_to_chars<signed long long>(1, "1", base) );
+ VERIFY( check_to_chars<unsigned long long>(1, "1", base) );
+
+ if constexpr (std::is_signed_v<char>)
+ VERIFY( check_to_chars<char>(-1, "-1", base) );
+ VERIFY( check_to_chars<signed char>(-1, "-1", base) );
+ VERIFY( check_to_chars<signed short>(-1, "-1", base) );
+ VERIFY( check_to_chars<signed int>(-1, "-1", base) );
+ VERIFY( check_to_chars<signed long>(-1, "-1", base) );
+ VERIFY( check_to_chars<signed long long>(-1, "-1", base) );
+
+ if (base > 2)
+ {
+ VERIFY( check_to_chars<char>(2, "2", base) );
+ VERIFY( check_to_chars<signed char>(2, "2", base) );
+ VERIFY( check_to_chars<unsigned char>(2, "2", base) );
+ VERIFY( check_to_chars<signed short>(2, "2", base) );
+ VERIFY( check_to_chars<unsigned short>(2, "2", base) );
+ VERIFY( check_to_chars<signed int>(2, "2", base) );
+ VERIFY( check_to_chars<unsigned int>(2, "2", base) );
+ VERIFY( check_to_chars<signed long>(2, "2", base) );
+ VERIFY( check_to_chars<unsigned long>(2, "2", base) );
+ VERIFY( check_to_chars<signed long long>(2, "2", base) );
+ VERIFY( check_to_chars<unsigned long long>(2, "2", base) );
+
+ if constexpr (std::is_signed_v<char>)
+ VERIFY( check_to_chars<char>(-2, "-2", base) );
+ VERIFY( check_to_chars<signed char>(-2, "-2", base) );
+ VERIFY( check_to_chars<signed short>(-2, "-2", base) );
+ VERIFY( check_to_chars<signed int>(-2, "-2", base) );
+ VERIFY( check_to_chars<signed long>(-2, "-2", base) );
+ VERIFY( check_to_chars<signed long long>(-2, "-2", base) );
+ }
+
+ VERIFY( check_to_chars(2017u, str2017[base]+1, base) );
+ VERIFY( check_to_chars(2017, str2017[base]+1, base) );
+ VERIFY( check_to_chars(-2017, str2017[base], base) );
+ VERIFY( check_to_chars(12345u, str12345[base]+1, base) );
+ VERIFY( check_to_chars(12345, str12345[base]+1, base) );
+ VERIFY( check_to_chars(-12345, str12345[base], base) );
+ VERIFY( check_to_chars(23456u, str23456[base]+1, base) );
+ VERIFY( check_to_chars(23456, str23456[base]+1, base) );
+ VERIFY( check_to_chars(-23456, str23456[base], base) );
+ VERIFY( check_to_chars(INT_MAX + 1ull, strINT_MIN[base]+1, base) );
+ VERIFY( check_to_chars(INT_MAX + 1ll, strINT_MIN[base]+1, base) );
+ VERIFY( check_to_chars(INT_MIN, strINT_MIN[base], base) );
+ }
+
+ VERIFY( check_to_chars(1155, "xx", 34) );
+ VERIFY( check_to_chars(1224, "yy", 35) );
+ VERIFY( check_to_chars(1295, "zz", 36) );
+}
+
+#include <sstream>
+#include <ios>
+
+// base 8
+void
+test04()
+{
+ auto to_string = [](auto val) {
+ std::ostringstream ss;
+ ss << std::oct;
+ if (val < 0)
+ ss << '-' << (~val + 1ull);
+ else if (sizeof(val) == 1)
+ ss << (int)val;
+ else
+ ss << val;
+ return ss.str();
+ };
+
+ VERIFY( check_to_chars<char>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<signed char>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<unsigned char>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<signed short>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<unsigned short>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<signed int>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<unsigned int>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<signed long>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<unsigned long>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<signed long long>(123, to_string(123), 8) );
+ VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 8) );
+
+ if constexpr (std::is_signed_v<char>)
+ VERIFY( check_to_chars<char>(-79, to_string(-79), 8) );
+ VERIFY( check_to_chars<signed char>(-79, to_string(-79), 8) );
+ VERIFY( check_to_chars<signed short>(-79, to_string(-79), 8) );
+ VERIFY( check_to_chars<signed int>(-79, to_string(-79), 8) );
+ VERIFY( check_to_chars<signed long>(-79, to_string(-79), 8) );
+ VERIFY( check_to_chars<signed long long>(-79, to_string(-79), 8) );
+
+ VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX), 8) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX), 8) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX), 8) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX), 8) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX), 8) );
+ VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX), 8) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX), 8) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX), 8) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX), 8) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX), 8) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX), 8) );
+
+ VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN), 8) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN), 8) );
+ VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN), 8) );
+ VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN), 8) );
+ VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN), 8) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN), 8) );
+
+ VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2), 8) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2), 8) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2), 8) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2), 8) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2), 8) );
+ VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2), 8) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2), 8) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2), 8) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2), 8) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2), 8) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2), 8) );
+}
+
+// base 16
+void
+test05()
+{
+ auto to_string = [](auto val) {
+ std::ostringstream ss;
+ ss << std::hex;
+ if (val < 0)
+ ss << '-' << (~val + 1ull);
+ else if (sizeof(val) == 1)
+ ss << (int)val;
+ else
+ ss << val;
+ return ss.str();
+ };
+
+ VERIFY( check_to_chars<char>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<signed char>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<unsigned char>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<signed short>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<unsigned short>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<signed int>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<unsigned int>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<signed long>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<unsigned long>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<signed long long>(123, to_string(123), 16) );
+ VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 16) );
+
+ if constexpr (std::is_signed_v<char>)
+ VERIFY( check_to_chars<char>(-79, to_string(-79), 16) );
+ VERIFY( check_to_chars<signed char>(-79, to_string(-79), 16) );
+ VERIFY( check_to_chars<signed short>(-79, to_string(-79), 16) );
+ VERIFY( check_to_chars<signed int>(-79, to_string(-79), 16) );
+ VERIFY( check_to_chars<signed long>(-79, to_string(-79), 16) );
+ VERIFY( check_to_chars<signed long long>(-79, to_string(-79), 16) );
+
+ VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX), 16) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX), 16) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX), 16) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX), 16) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX), 16) );
+ VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX), 16) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX), 16) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX), 16) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX), 16) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX), 16) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX), 16) );
+
+ VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN), 16) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN), 16) );
+ VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN), 16) );
+ VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN), 16) );
+ VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN), 16) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN), 16) );
+
+ VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2), 16) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2), 16) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2), 16) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2), 16) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2), 16) );
+ VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2), 16) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2), 16) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2), 16) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2), 16) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2), 16) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2), 16) );
+}
+
+#include <bitset>
+
+// base 2
+void
+test06()
+{
+ auto to_string = [](auto val) {
+ std::string s, sign;
+ if (val < 0)
+ {
+ auto absval = ~val + 1ull;
+ s = std::bitset<sizeof(absval) * CHAR_BIT>(absval).to_string();
+ sign = '-';
+ }
+ else
+ s = std::bitset<sizeof(val) * CHAR_BIT>(val).to_string();
+ auto pos = s.find_first_not_of("0");
+ if (pos == std::string::npos)
+ s.resize(1);
+ else
+ s.erase(0, pos);
+ return sign + s;
+ };
+
+ VERIFY( check_to_chars<char>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<signed char>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<unsigned char>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<signed short>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<unsigned short>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<signed int>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<unsigned int>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<signed long>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<unsigned long>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<signed long long>(123, to_string(123), 2) );
+ VERIFY( check_to_chars<unsigned long long>(123, to_string(123), 2) );
+
+ if constexpr (std::is_signed_v<char>)
+ VERIFY( check_to_chars<char>(-79, to_string(-79), 2) );
+ VERIFY( check_to_chars<signed char>(-79, to_string(-79), 2) );
+ VERIFY( check_to_chars<signed short>(-79, to_string(-79), 2) );
+ VERIFY( check_to_chars<signed int>(-79, to_string(-79), 2) );
+ VERIFY( check_to_chars<signed long>(-79, to_string(-79), 2) );
+ VERIFY( check_to_chars<signed long long>(-79, to_string(-79), 2) );
+
+ VERIFY( check_to_chars<char>(CHAR_MAX, to_string(CHAR_MAX), 2) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX, to_string(SCHAR_MAX), 2) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX, to_string(UCHAR_MAX), 2) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX, to_string(SHRT_MAX), 2) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX, to_string(USHRT_MAX), 2) );
+ VERIFY( check_to_chars<signed int>(INT_MAX, to_string(INT_MAX), 2) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX, to_string(UINT_MAX), 2) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX, to_string(LONG_MAX), 2) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX, to_string(ULONG_MAX), 2) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX, to_string(LLONG_MAX), 2) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX, to_string(ULLONG_MAX), 2) );
+
+ VERIFY( check_to_chars<char>(CHAR_MIN, to_string(CHAR_MIN), 2) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MIN, to_string(SCHAR_MIN), 2) );
+ VERIFY( check_to_chars<signed short>(SHRT_MIN, to_string(SHRT_MIN), 2) );
+ VERIFY( check_to_chars<signed int>(INT_MIN, to_string(INT_MIN), 2) );
+ VERIFY( check_to_chars<signed long>(LONG_MIN, to_string(LONG_MIN), 2) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MIN, to_string(LLONG_MIN), 2) );
+
+ VERIFY( check_to_chars<char>(CHAR_MAX/2, to_string(CHAR_MAX/2), 2) );
+ VERIFY( check_to_chars<signed char>(SCHAR_MAX/2, to_string(SCHAR_MAX/2), 2) );
+ VERIFY( check_to_chars<unsigned char>(UCHAR_MAX/2, to_string(UCHAR_MAX/2), 2) );
+ VERIFY( check_to_chars<signed short>(SHRT_MAX/2, to_string(SHRT_MAX/2), 2) );
+ VERIFY( check_to_chars<unsigned short>(USHRT_MAX/2, to_string(USHRT_MAX/2), 2) );
+ VERIFY( check_to_chars<signed int>(INT_MAX/2, to_string(INT_MAX/2), 2) );
+ VERIFY( check_to_chars<unsigned int>(UINT_MAX/2, to_string(UINT_MAX/2), 2) );
+ VERIFY( check_to_chars<signed long>(LONG_MAX/2, to_string(LONG_MAX/2), 2) );
+ VERIFY( check_to_chars<unsigned long>(ULONG_MAX/2, to_string(ULONG_MAX/2), 2) );
+ VERIFY( check_to_chars<signed long long>(LLONG_MAX/2, to_string(LLONG_MAX/2), 2) );
+ VERIFY( check_to_chars<unsigned long long>(ULLONG_MAX/2, to_string(ULLONG_MAX/2), 2) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+ test06();
+}
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/1_neg.cc b/libstdc++-v3/testsuite/20_util/to_chars/1_neg.cc
new file mode 100644
index 0000000..8302b25
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/to_chars/1_neg.cc
@@ -0,0 +1,35 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <charconv>
+
+void
+test01(char* first, char* last)
+{
+#if _GLIBCXX_USE_WCHAR_T
+ std::to_chars(first, last, L'\x1'); // { dg-error "no matching" }
+ std::to_chars(first, last, L'\x1', 10); // { dg-error "no matching" }
+#endif
+
+ std::to_chars(first, last, u'\x1'); // { dg-error "no matching" }
+ std::to_chars(first, last, u'\x1', 10); // { dg-error "no matching" }
+ std::to_chars(first, last, U'\x1'); // { dg-error "no matching" }
+ std::to_chars(first, last, U'\x1', 10); // { dg-error "no matching" }
+}
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/2.cc b/libstdc++-v3/testsuite/20_util/to_chars/2.cc
new file mode 100644
index 0000000..b28320c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/to_chars/2.cc
@@ -0,0 +1,78 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <charconv>
+#include <testsuite_hooks.h>
+
+// Test std::to_chars error handling.
+
+void
+test01()
+{
+ char buf[9] = "********";
+ std::to_chars_result r;
+
+ r = std::to_chars(buf, buf, 1);
+ VERIFY( r.ec == std::errc::value_too_large );
+ VERIFY( r.ptr == buf );
+ VERIFY( *r.ptr == '*' );
+
+ r = std::to_chars(buf, buf + 3, 0b1000, 2);
+ VERIFY( r.ec == std::errc::value_too_large );
+ VERIFY( r.ptr == buf + 3 );
+ VERIFY( *r.ptr == '*' );
+ r = std::to_chars(buf, buf + 4, 0b1000, 2);
+ VERIFY( r.ec == std::errc{} );
+ VERIFY( r.ptr == buf + 4 );
+ VERIFY( *r.ptr == '*' );
+
+ r = std::to_chars(buf, buf + 4, 010000, 8);
+ VERIFY( r.ec == std::errc::value_too_large );
+ VERIFY( r.ptr == buf + 4 );
+ VERIFY( *r.ptr == '*' );
+ r = std::to_chars(buf, buf + 5, 010000, 8);
+ VERIFY( r.ec == std::errc{} );
+ VERIFY( r.ptr == buf + 5 );
+ VERIFY( *r.ptr == '*' );
+
+ r = std::to_chars(buf, buf + 5, 100000, 10);
+ VERIFY( r.ec == std::errc::value_too_large );
+ VERIFY( r.ptr == buf + 5 );
+ VERIFY( *r.ptr == '*' );
+ r = std::to_chars(buf, buf + 6, 100000, 10);
+ VERIFY( r.ec == std::errc{} );
+ VERIFY( r.ptr == buf + 6 );
+ VERIFY( *r.ptr == '*' );
+
+ r = std::to_chars(buf, buf + 6, 0x1000000, 16);
+ VERIFY( r.ec == std::errc::value_too_large );
+ VERIFY( r.ptr == buf + 6 );
+ VERIFY( *r.ptr == '*' );
+ r = std::to_chars(buf, buf + 7, 0x1000000, 16);
+ VERIFY( r.ec == std::errc{} );
+ VERIFY( r.ptr == buf + 7 );
+ VERIFY( *r.ptr == '*' );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/20_util/to_chars/requirements.cc b/libstdc++-v3/testsuite/20_util/to_chars/requirements.cc
new file mode 100644
index 0000000..d50588b
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/to_chars/requirements.cc
@@ -0,0 +1,49 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
+
+#include <charconv>
+
+namespace std
+{
+ struct to_chars_result;
+
+ char* to_chars_result::*pm2 = &to_chars_result::ptr;
+ errc to_chars_result::*pm1 = &to_chars_result::ec;
+
+ to_chars_result (*f1)(char*, char*, char, int) = &to_chars;
+ to_chars_result (*f2)(char*, char*, signed char, int) = &to_chars;
+ to_chars_result (*f3)(char*, char*, unsigned char, int) = &to_chars;
+ to_chars_result (*f4)(char*, char*, signed short, int) = &to_chars;
+ to_chars_result (*f5)(char*, char*, unsigned short, int) = &to_chars;
+ to_chars_result (*f6)(char*, char*, signed int, int) = &to_chars;
+ to_chars_result (*f7)(char*, char*, unsigned int, int) = &to_chars;
+ to_chars_result (*f8)(char*, char*, signed long, int) = &to_chars;
+ to_chars_result (*f9)(char*, char*, unsigned long, int) = &to_chars;
+ to_chars_result (*f10)(char*, char*, signed long long, int) = &to_chars;
+ to_chars_result (*f11)(char*, char*, unsigned long long, int) = &to_chars;
+}
+
+void bind()
+{
+ char buf[1];
+ auto [p, e] = std::to_chars(buf, buf + 1, 1, 10);
+ char** pa = &p;
+ std::errc* ea = &e;
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc
new file mode 100644
index 0000000..88be60d
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/char/moveable2_c++17.cc
@@ -0,0 +1,53 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+// Copyright (C) 2011-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// NOTE: This makes use of the fact that we know how moveable
+// is implemented on string (via swap). If the implementation changed
+// this test may begin to fail.
+
+#include <string>
+#include <utility>
+#include <testsuite_hooks.h>
+
+class tstring : public std::basic_string<char>
+{
+public:
+ tstring() : std::basic_string<char>() {}
+ tstring(tstring&& s) : std::basic_string<char>(std::move(s)) {}
+ tstring& operator=(tstring&& s) = default;
+};
+
+void test01()
+{
+ tstring a, b;
+ a.push_back('1');
+ b = std::move(a);
+ VERIFY( b.size() == 1 && b[0] == '1' && a.size() == 0 );
+
+ tstring c(std::move(b));
+ VERIFY( c.size() == 1 && c[0] == '1' );
+ VERIFY( b.size() == 0 );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc
new file mode 100644
index 0000000..63684de
--- /dev/null
+++ b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/moveable2_c++17.cc
@@ -0,0 +1,53 @@
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+// Copyright (C) 2011-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// NOTE: This makes use of the fact that we know how moveable
+// is implemented on string (via swap). If the implementation changed
+// this test may begin to fail.
+
+#include <string>
+#include <utility>
+#include <testsuite_hooks.h>
+
+class tstring : public std::basic_string<wchar_t>
+{
+public:
+ tstring() : std::basic_string<wchar_t>() {}
+ tstring(tstring&& s) : std::basic_string<wchar_t>(std::move(s)) {}
+ tstring& operator=(tstring&& s) = default;
+};
+
+void test01()
+{
+ tstring a, b;
+ a.push_back(L'1');
+ b = std::move(a);
+ VERIFY( b.size() == 1 && b[0] == L'1' && a.size() == 0 );
+
+ tstring c(std::move(b));
+ VERIFY( c.size() == 1 && c[0] == L'1' );
+ VERIFY( b.size() == 0 );
+}
+
+int main()
+{
+ test01();
+ return 0;
+}
diff --git a/libstdc++-v3/testsuite/22_locale/money_get/get/char/22131.cc b/libstdc++-v3/testsuite/22_locale/money_get/get/char/22131.cc
index 6f363ef..5a05817 100644
--- a/libstdc++-v3/testsuite/22_locale/money_get/get/char/22131.cc
+++ b/libstdc++-v3/testsuite/22_locale/money_get/get/char/22131.cc
@@ -67,7 +67,7 @@ void test01()
fmt2.imbue(loc);
InIt ibeg2(fmt2);
err2 = ios_base::goodbit;
- mg.get(ibeg2, iend2, intl, fmt2, err2, val2);
+ ibeg2 = mg.get(ibeg2, iend2, intl, fmt2, err2, val2);
VERIFY( err2 == ios_base::failbit );
VERIFY( *ibeg2 == '#' );
VERIFY( val2 == "" );
diff --git a/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/22131.cc b/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/22131.cc
index 3830cc3..0626e3c 100644
--- a/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/22131.cc
+++ b/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/22131.cc
@@ -67,7 +67,7 @@ void test01()
fmt2.imbue(loc);
InIt ibeg2(fmt2);
err2 = ios_base::goodbit;
- mg.get(ibeg2, iend2, intl, fmt2, err2, val2);
+ ibeg2 = mg.get(ibeg2, iend2, intl, fmt2, err2, val2);
VERIFY( err2 == ios_base::failbit );
VERIFY( *ibeg2 == L'#' );
VERIFY( val2 == L"" );
diff --git a/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/dr2354.cc b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/dr2354.cc
new file mode 100644
index 0000000..338d9fd
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/map/modifiers/insert/dr2354.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <map>
+
+struct MoveOnly {
+ MoveOnly(int) { }
+ MoveOnly(MoveOnly&&) = default;
+};
+
+void
+test01()
+{
+ std::map<int, MoveOnly> m;
+ m.insert({1, 2}); // PR libstdc++/82522 - LWG 2354
+}
diff --git a/libstdc++-v3/testsuite/23_containers/multimap/modifiers/insert/dr2354.cc b/libstdc++-v3/testsuite/23_containers/multimap/modifiers/insert/dr2354.cc
new file mode 100644
index 0000000..ca743ec
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/multimap/modifiers/insert/dr2354.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <map>
+
+struct MoveOnly {
+ MoveOnly(int) { }
+ MoveOnly(MoveOnly&&) = default;
+};
+
+void
+test01()
+{
+ std::multimap<int, MoveOnly> m;
+ m.insert({1, 2}); // PR libstdc++/82522 - LWG 2354
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_map/insert/dr2354.cc b/libstdc++-v3/testsuite/23_containers/unordered_map/insert/dr2354.cc
new file mode 100644
index 0000000..fe53565
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_map/insert/dr2354.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <unordered_map>
+
+struct MoveOnly {
+ MoveOnly(int) { }
+ MoveOnly(MoveOnly&&) = default;
+};
+
+void
+test01()
+{
+ std::unordered_map<int, MoveOnly> m;
+ m.insert({1, 2}); // PR libstdc++/82522 - LWG 2354
+}
diff --git a/libstdc++-v3/testsuite/23_containers/unordered_multimap/insert/dr2354.cc b/libstdc++-v3/testsuite/23_containers/unordered_multimap/insert/dr2354.cc
new file mode 100644
index 0000000..5a27242
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/unordered_multimap/insert/dr2354.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++11 } }
+
+#include <unordered_map>
+
+struct MoveOnly {
+ MoveOnly(int) { }
+ MoveOnly(MoveOnly&&) = default;
+};
+
+void
+test01()
+{
+ std::unordered_multimap<int, MoveOnly> m;
+ m.insert({1, 2}); // PR libstdc++/82522 - LWG 2354
+}
diff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/82558.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/82558.cc
new file mode 100644
index 0000000..6362688
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/82558.cc
@@ -0,0 +1,32 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 23.3.8 class vector<bool>
+
+#include <vector>
+
+// libstdc++/82558
+void test01()
+{
+ std::vector<bool> v;
+ std::fill(v.begin(), v.begin(), false);
+}
+
+int main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/2.cc b/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/2.cc
index b81f4d4..572ea9f 100644
--- a/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/2.cc
+++ b/libstdc++-v3/testsuite/24_iterators/istreambuf_iterator/2.cc
@@ -25,9 +25,7 @@
void test02(void)
{
-
typedef std::istreambuf_iterator<char> cistreambuf_iter;
- typedef cistreambuf_iter::streambuf_type cstreambuf_type;
const char slit01[] = "playa hermosa, liberia, guanacaste";
std::string str01(slit01);
std::istringstream istrs00(str01);
@@ -35,10 +33,14 @@ void test02(void)
// ctor sanity checks
cistreambuf_iter istrb_it01(istrs00);
- cistreambuf_iter istrb_it02;
- std::string tmp(istrb_it01, istrb_it02);
+ cistreambuf_iter istrb_eos;
+ VERIFY( istrb_it01 != istrb_eos );
+
+ std::string tmp(istrb_it01, istrb_eos);
VERIFY( tmp == str01 );
+ VERIFY( istrb_it01 == istrb_eos );
+
cistreambuf_iter istrb_it03(0);
cistreambuf_iter istrb_it04;
VERIFY( istrb_it03 == istrb_it04 );
diff --git a/libstdc++-v3/testsuite/24_iterators/range_access_cpp17.cc b/libstdc++-v3/testsuite/24_iterators/range_access_cpp17.cc
index 2402fa8..cb6b1c4 100644
--- a/libstdc++-v3/testsuite/24_iterators/range_access_cpp17.cc
+++ b/libstdc++-v3/testsuite/24_iterators/range_access_cpp17.cc
@@ -1,5 +1,5 @@
-// { dg-do compile { target c++17 } }
// { dg-options "-std=gnu++17" }
+// { dg-do compile { target c++17 } }
// Copyright (C) 2017 Free Software Foundation, Inc.
//
@@ -47,7 +47,7 @@ void
test03()
{
using std::reverse_iterator;
- static std::initializer_list<int> il{1};
+ static constexpr std::initializer_list<int> il{1};
static_assert(std::cbegin(il) == il.begin());
static_assert(std::cend(il) == il.end());
static_assert(std::rbegin(il) == reverse_iterator<const int*>(il.end()));
diff --git a/libstdc++-v3/testsuite/25_algorithms/clamp/1.cc b/libstdc++-v3/testsuite/25_algorithms/clamp/1.cc
index 991b10d..655c241 100644
--- a/libstdc++-v3/testsuite/25_algorithms/clamp/1.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/clamp/1.cc
@@ -30,12 +30,12 @@ void test01()
VERIFY( y == 3 );
VERIFY( z == 4 );
- const int xc = std::clamp(1, 2, 4, std::greater<int>());
- const int yc = std::clamp(3, 2, 4, std::greater<int>());
- const int zc = std::clamp(5, 2, 4, std::greater<int>());
- VERIFY( xc == 4 );
- VERIFY( yc == 2 );
- VERIFY( zc == 2 );
+ const int xc = std::clamp(1, 4, 2, std::greater<int>());
+ const int yc = std::clamp(3, 4, 2, std::greater<int>());
+ const int zc = std::clamp(5, 4, 2, std::greater<int>());
+ VERIFY( xc == 2 );
+ VERIFY( yc == 3 );
+ VERIFY( zc == 4 );
}
int
diff --git a/libstdc++-v3/testsuite/25_algorithms/clamp/constexpr.cc b/libstdc++-v3/testsuite/25_algorithms/clamp/constexpr.cc
index 0864b8e..606748e 100644
--- a/libstdc++-v3/testsuite/25_algorithms/clamp/constexpr.cc
+++ b/libstdc++-v3/testsuite/25_algorithms/clamp/constexpr.cc
@@ -27,5 +27,5 @@
# error "Feature-test macro for clamp has wrong value"
#endif
-static_assert(std::clamp(2, 0, 1) == 1, "");
-static_assert(std::clamp(2, 0, 1, std::greater<int>()) == 0, "");
+static_assert(std::clamp(2, 0, 1) == 1);
+static_assert(std::clamp(2, 1, 0, std::greater<int>()) == 1);
diff --git a/libstdc++-v3/testsuite/26_numerics/complex/c99.cc b/libstdc++-v3/testsuite/26_numerics/complex/c99.cc
index 7018962..9b0def4 100644
--- a/libstdc++-v3/testsuite/26_numerics/complex/c99.cc
+++ b/libstdc++-v3/testsuite/26_numerics/complex/c99.cc
@@ -26,7 +26,8 @@
int main()
{
-#if _GLIBCXX_HAVE_COMPLEX_H
+#if _GLIBCXX_HAVE_COMPLEX_H && !defined(__STRICT_ANSI__)
+ // This is a GNU extension.
double _Complex x = .5;
double _Complex y = cacos (x);
(void)y;
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc
new file mode 100644
index 0000000..956541a
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/82644.cc
@@ -0,0 +1,27 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-D__STDCPP_WANT_MATH_SPEC_FUNCS__ -D__STRICT_ANSI__" }
+// { dg-do compile { target c++11 } }
+
+#define conf_hyperg 1
+#define conf_hypergf 2
+#define conf_hypergl 3
+#define hyperg 4
+#define hypergf 5
+#define hypergl 6
+#include <cmath> // PR libstdc++/82644
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_global_c++17.cc b/libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_global_c++17.cc
new file mode 100644
index 0000000..ce3a0dd
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/headers/cmath/functions_global_c++17.cc
@@ -0,0 +1,111 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do compile }
+
+#include <math.h>
+
+namespace gnu
+{
+ using ::acos;
+ using ::asin;
+ using ::atan;
+ using ::atan2;
+ using ::ceil;
+ using ::cos;
+ using ::cosh;
+ using ::exp;
+ using ::fabs;
+ using ::floor;
+ using ::fmod;
+ using ::frexp;
+ using ::ldexp;
+ using ::log;
+ using ::log10;
+ using ::modf;
+ using ::pow;
+ using ::sin;
+ using ::sinh;
+ using ::sqrt;
+ using ::tan;
+ using ::tanh;
+
+ using ::assoc_laguerre;
+ using ::assoc_laguerref;
+ using ::assoc_laguerrel;
+ using ::assoc_legendre;
+ using ::assoc_legendref;
+ using ::assoc_legendrel;
+ using ::beta;
+ using ::betaf;
+ using ::betal;
+ using ::comp_ellint_1;
+ using ::comp_ellint_1f;
+ using ::comp_ellint_1l;
+ using ::comp_ellint_2;
+ using ::comp_ellint_2f;
+ using ::comp_ellint_2l;
+ using ::comp_ellint_3;
+ using ::comp_ellint_3f;
+ using ::comp_ellint_3l;
+ using ::cyl_bessel_i;
+ using ::cyl_bessel_if;
+ using ::cyl_bessel_il;
+ using ::cyl_bessel_j;
+ using ::cyl_bessel_jf;
+ using ::cyl_bessel_jl;
+ using ::cyl_bessel_k;
+ using ::cyl_bessel_kf;
+ using ::cyl_bessel_kl;
+ using ::cyl_neumann;
+ using ::cyl_neumannf;
+ using ::cyl_neumannl;
+ using ::ellint_1;
+ using ::ellint_1f;
+ using ::ellint_1l;
+ using ::ellint_2;
+ using ::ellint_2f;
+ using ::ellint_2l;
+ using ::ellint_3;
+ using ::ellint_3f;
+ using ::ellint_3l;
+ using ::expint;
+ using ::expintf;
+ using ::expintl;
+ using ::hermite;
+ using ::hermitef;
+ using ::hermitel;
+ using ::laguerre;
+ using ::laguerref;
+ using ::laguerrel;
+ using ::legendre;
+ using ::legendref;
+ using ::legendrel;
+ using ::riemann_zeta;
+ using ::riemann_zetaf;
+ using ::riemann_zetal;
+ using ::sph_bessel;
+ using ::sph_besself;
+ using ::sph_bessell;
+ using ::sph_legendre;
+ using ::sph_legendref;
+ using ::sph_legendrel;
+ using ::sph_neumann;
+ using ::sph_neumannf;
+ using ::sph_neumannl;
+}
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_c++11.h b/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_c++11.h
new file mode 100644
index 0000000..22d84b2
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_c++11.h
@@ -0,0 +1,33 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++11" }
+
+#include <complex.h>
+
+// Should be equivalent to #include <complex>
+template class std::complex<double>;
+
+#ifdef complex
+# error "'complex' is defined as a macro by <complex.h> for -std=c++11"
+#endif
+#ifdef imaginary
+# error "'imaginary' is defined as a macro by <complex.h> for -std=c++11"
+#endif
+#ifdef I
+# error "'I' is defined as a macro by <complex.h> for -std=c++11"
+#endif
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_c++98.h b/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_c++98.h
new file mode 100644
index 0000000..6267446
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_c++98.h
@@ -0,0 +1,55 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=c++98" }
+
+#include <complex.h>
+
+// Should be equivalent to C99 <complex>, not C++ <complex>
+namespace std
+{
+ struct complex;
+}
+
+#if _GLIBCXX_HAVE_COMPLEX_H
+namespace test
+{
+ using ::cacos;
+ using ::casin;
+ using ::catan;
+ using ::ccos;
+ using ::csin;
+ using ::ctan;
+ using ::ccosh;
+ using ::csinh;
+ using ::ctanh;
+ using ::cexp;
+ using ::clog;
+ using ::cabs;
+ using ::cpow;
+ using ::csqrt;
+ using ::carg;
+ using ::cimag;
+ using ::conj;
+ using ::cproj;
+ using ::creal;
+}
+#endif
+
+#ifndef complex
+# error "'complex' is not defined as a macro by <complex.h> for -std=c++98"
+#endif
diff --git a/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_gnu++11.h b/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_gnu++11.h
new file mode 100644
index 0000000..9110ae4
--- /dev/null
+++ b/libstdc++-v3/testsuite/26_numerics/headers/complex.h/std_gnu++11.h
@@ -0,0 +1,52 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++11" }
+
+#include <complex.h>
+
+// Should be equivalent to #include <complex>
+template class std::complex<double>;
+
+#if _GLIBCXX_HAVE_COMPLEX_H
+namespace test
+{
+ using ::cacos;
+ using ::casin;
+ using ::catan;
+ using ::ccos;
+ using ::csin;
+ using ::ctan;
+ using ::ccosh;
+ using ::csinh;
+ using ::ctanh;
+ using ::cexp;
+ using ::clog;
+ using ::cabs;
+ using ::cpow;
+ using ::csqrt;
+ using ::carg;
+ using ::cimag;
+ using ::conj;
+ using ::cproj;
+ using ::creal;
+}
+#endif
+
+#ifdef complex
+# error "'complex' is defined as a macro by <complex.h> for -std=gnu++11"
+#endif
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc
new file mode 100644
index 0000000..c3e6f01
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/directory_iterator.cc
@@ -0,0 +1,150 @@
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+
+ // Test non-existent path.
+ const auto p = __gnu_test::nonexistent_path();
+ fs::directory_iterator iter(p, ec);
+ VERIFY( ec );
+ VERIFY( iter == end(iter) );
+
+ // Test empty directory.
+ create_directory(p, fs::current_path(), ec);
+ VERIFY( !ec );
+ ec = bad_ec;
+ iter = fs::directory_iterator(p, ec);
+ VERIFY( !ec );
+ VERIFY( iter == end(iter) );
+
+ // Test non-empty directory.
+ ec = bad_ec;
+ create_directory_symlink(p, p / "l", ec);
+ VERIFY( !ec );
+ ec = bad_ec;
+ iter = fs::directory_iterator(p, ec);
+ VERIFY( !ec );
+ VERIFY( iter != fs::directory_iterator() );
+ VERIFY( iter->path() == p/"l" );
+ ++iter;
+ VERIFY( iter == end(iter) );
+
+ // Test inaccessible directory.
+ ec = bad_ec;
+ permissions(p, fs::perms::none, ec);
+ VERIFY( !ec );
+ ec = bad_ec;
+ iter = fs::directory_iterator(p, ec);
+ VERIFY( ec );
+ VERIFY( iter == end(iter) );
+
+ // Test inaccessible directory, skipping permission denied.
+ const auto opts = fs::directory_options::skip_permission_denied;
+ ec = bad_ec;
+ iter = fs::directory_iterator(p, opts, ec);
+ VERIFY( !ec );
+ VERIFY( iter == end(iter) );
+
+ permissions(p, fs::perms::owner_all, ec);
+ remove_all(p, ec);
+}
+
+void
+test02()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+ const auto p = __gnu_test::nonexistent_path();
+ ec = bad_ec;
+ create_directory(p, fs::current_path(), ec);
+ create_directory_symlink(p, p / "l", ec);
+ VERIFY( !ec );
+
+ // Test post-increment (libstdc++/71005)
+ ec = bad_ec;
+ auto iter = fs::directory_iterator(p, ec);
+ VERIFY( !ec );
+ VERIFY( iter != end(iter) );
+ const auto entry1 = *iter;
+ const auto entry2 = *iter++;
+ VERIFY( entry1 == entry2 );
+ VERIFY( entry1.path() == p/"l" );
+ VERIFY( iter == end(iter) );
+
+ remove_all(p, ec);
+}
+
+void
+test03()
+{
+ std::error_code ec = make_error_code(std::errc::invalid_argument);
+ const auto p = __gnu_test::nonexistent_path();
+ create_directories(p / "longer_than_small_string_buffer", ec);
+ VERIFY( !ec );
+
+ // Test for no reallocation on each dereference (this is a GNU extension)
+ auto iter = fs::directory_iterator(p, ec);
+ const auto* s1 = iter->path().c_str();
+ const auto* s2 = iter->path().c_str();
+ VERIFY( s1 == s2 );
+
+ remove_all(p, ec);
+}
+
+void
+test04()
+{
+ const fs::directory_iterator it;
+ VERIFY( it == fs::directory_iterator() );
+}
+
+void
+test05()
+{
+ auto p = __gnu_test::nonexistent_path();
+ create_directory(p);
+ create_directory_symlink(p, p / "l");
+ fs::directory_iterator it(p), endit;
+ VERIFY( begin(it) == it );
+ static_assert( noexcept(begin(it)), "begin is noexcept" );
+ VERIFY( end(it) == endit );
+ static_assert( noexcept(end(it)), "end is noexcept" );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc
new file mode 100644
index 0000000..02dc04f
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/pop.cc
@@ -0,0 +1,117 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ std::error_code ec;
+ fs::recursive_directory_iterator dir;
+ dir.pop(ec); // This is undefined, but our implementation
+ VERIFY( ec ); // checks and returns an error.
+ VERIFY( dir == end(dir) );
+
+ std::error_code ec2;
+ try
+ {
+ dir.pop();
+ }
+ catch (const fs::filesystem_error& ex)
+ {
+ ec2 = ex.code();
+ }
+ VERIFY( ec2 == ec );
+}
+
+void
+test02()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+ const auto p = __gnu_test::nonexistent_path();
+ create_directories(p / "d1/d2/d3");
+ for (int i = 0; i < 3; ++i)
+ {
+ fs::recursive_directory_iterator dir(p);
+ VERIFY( dir != end(dir) );
+ std::advance(dir, i);
+ VERIFY( dir != end(dir) );
+ VERIFY( dir.depth() == i );
+ ec = bad_ec;
+ dir.pop(ec);
+ VERIFY( !ec );
+ VERIFY( dir == end(dir) );
+
+ dir = fs::recursive_directory_iterator(p);
+ std::advance(dir, i);
+ VERIFY( dir != end(dir) );
+ VERIFY( dir.depth() == i );
+ dir.pop();
+ VERIFY( dir == end(dir) );
+ }
+ remove_all(p, ec);
+}
+
+void
+test03()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+ const auto p = __gnu_test::nonexistent_path();
+ create_directories(p / "d1/d2/d3");
+ create_directories(p / "d1/d2/e3");
+ create_directories(p / "d1/e2/d3");
+ for (int i = 0; i < 3; ++i)
+ {
+ fs::recursive_directory_iterator dir(p);
+ std::advance(dir, i);
+ VERIFY( dir != end(dir) );
+ int expected_depth = i;
+ VERIFY( dir.depth() == expected_depth );
+ ec = bad_ec;
+ dir.pop(ec);
+ VERIFY( !ec );
+ if (dir != end(dir))
+ VERIFY( dir.depth() == (expected_depth - 1) );
+
+ dir = fs::recursive_directory_iterator(p);
+ std::advance(dir, i);
+ VERIFY( dir != end(dir) );
+ VERIFY( dir.depth() == i );
+ dir.pop();
+ if (dir != end(dir))
+ VERIFY( dir.depth() == (i -1) );
+ }
+ remove_all(p, ec);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc b/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc
new file mode 100644
index 0000000..1ef450f
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/iterators/recursive_directory_iterator.cc
@@ -0,0 +1,188 @@
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+
+ // Test non-existent path.
+ const auto p = __gnu_test::nonexistent_path();
+ fs::recursive_directory_iterator iter(p, ec);
+ VERIFY( ec );
+ VERIFY( iter == end(iter) );
+
+ // Test empty directory.
+ ec = bad_ec;
+ create_directory(p, fs::current_path(), ec);
+ VERIFY( !ec );
+ ec = bad_ec;
+ iter = fs::recursive_directory_iterator(p, ec);
+ VERIFY( !ec );
+ VERIFY( iter == end(iter) );
+
+ // Test non-empty directory.
+ ec = bad_ec;
+ create_directories(p / "d1/d2", ec);
+ VERIFY( !ec );
+ ec = bad_ec;
+ iter = fs::recursive_directory_iterator(p, ec);
+ VERIFY( !ec );
+ VERIFY( iter != end(iter) );
+ VERIFY( iter->path() == p/"d1" );
+ ++iter;
+ VERIFY( iter->path() == p/"d1/d2" );
+ ++iter;
+ VERIFY( iter == end(iter) );
+
+ // Test inaccessible directory.
+ ec = bad_ec;
+ permissions(p, fs::perms::none, ec);
+ VERIFY( !ec );
+ iter = fs::recursive_directory_iterator(p, ec);
+ VERIFY( ec );
+ VERIFY( iter == end(iter) );
+
+ // Test inaccessible directory, skipping permission denied.
+ const auto opts = fs::directory_options::skip_permission_denied;
+ iter = fs::recursive_directory_iterator(p, opts, ec);
+ VERIFY( !ec );
+ VERIFY( iter == end(iter) );
+
+ // Test inaccessible sub-directory.
+ ec = bad_ec;
+ permissions(p, fs::perms::owner_all, ec);
+ VERIFY( !ec );
+ ec = bad_ec;
+ permissions(p/"d1/d2", fs::perms::none, ec);
+ VERIFY( !ec );
+ ec = bad_ec;
+ iter = fs::recursive_directory_iterator(p, ec);
+ VERIFY( !ec );
+ VERIFY( iter != end(iter) );
+ VERIFY( iter->path() == p/"d1" );
+ ++iter; // should recurse into d1
+ VERIFY( iter->path() == p/"d1/d2" );
+ iter.increment(ec); // should fail to recurse into p/d1/d2
+ VERIFY( ec );
+ VERIFY( iter == end(iter) );
+
+ // Test inaccessible sub-directory, skipping permission denied.
+ ec = bad_ec;
+ iter = fs::recursive_directory_iterator(p, opts, ec);
+ VERIFY( !ec );
+ VERIFY( iter != end(iter) );
+ VERIFY( iter->path() == p/"d1" );
+ ++iter; // should recurse into d1
+ VERIFY( iter->path() == p/"d1/d2" );
+ ec = bad_ec;
+ iter.increment(ec); // should fail to recurse into p/d1/d2, so skip it
+ VERIFY( !ec );
+ VERIFY( iter == end(iter) );
+
+ permissions(p/"d1/d2", fs::perms::owner_all, ec);
+ remove_all(p, ec);
+}
+
+void
+test02()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+ const auto p = __gnu_test::nonexistent_path();
+ ec = bad_ec;
+ create_directories(p / "d1/d2", ec);
+ VERIFY( !ec );
+
+ // Test post-increment (libstdc++/71005)
+ ec = bad_ec;
+ auto iter = fs::recursive_directory_iterator(p, ec);
+ VERIFY( !ec );
+ VERIFY( iter != end(iter) );
+ const auto entry1 = *iter;
+ const auto entry2 = *iter++;
+ VERIFY( entry1 == entry2 );
+ VERIFY( entry1.path() == p/"d1" );
+ const auto entry3 = *iter;
+ const auto entry4 = *iter++;
+ VERIFY( entry3 == entry4 );
+ VERIFY( entry3.path() == p/"d1/d2" );
+ VERIFY( iter == end(iter) );
+
+ remove_all(p, ec);
+}
+
+void
+test03()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+ const auto p = __gnu_test::nonexistent_path();
+ ec = bad_ec;
+ create_directories(p / "longer_than_small_string_buffer", ec);
+ VERIFY( !ec );
+
+ // Test for no reallocation on each dereference (this is a GNU extension)
+ auto iter = fs::recursive_directory_iterator(p, ec);
+ const auto* s1 = iter->path().c_str();
+ const auto* s2 = iter->path().c_str();
+ VERIFY( s1 == s2 );
+
+ remove_all(p, ec);
+}
+
+void
+test04()
+{
+ // libstdc++/71004
+ const fs::recursive_directory_iterator it;
+ VERIFY( it == end(it) );
+}
+
+void
+test05()
+{
+ auto p = __gnu_test::nonexistent_path();
+ create_directory(p);
+ create_directory_symlink(p, p / "l");
+ fs::recursive_directory_iterator it(p), endit;
+ VERIFY( begin(it) == it );
+ static_assert( noexcept(begin(it)), "begin is noexcept" );
+ VERIFY( end(it) == endit );
+ static_assert( noexcept(end(it)), "end is noexcept" );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc
new file mode 100644
index 0000000..de1cd31
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/absolute.cc
@@ -0,0 +1,54 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// C++17 30.10.14.1 Absolute [fs.op.absolute]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ VERIFY( absolute(p).is_absolute() );
+}
+
+void
+test02()
+{
+ path p1("/");
+ VERIFY( absolute(p1) == p1 );
+ path p2("/foo");
+ VERIFY( absolute(p2) == p2 );
+ path p3("foo");
+ VERIFY( absolute(p3) != p3 );
+ VERIFY( absolute(p3) == (std::filesystem::current_path()/p3) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc
new file mode 100644
index 0000000..646c37c
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/canonical.cc
@@ -0,0 +1,139 @@
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+ auto p = __gnu_test::nonexistent_path();
+ canonical( p, ec );
+ VERIFY( ec );
+
+ create_directory(p);
+ auto p2 = canonical( p, ec );
+ VERIFY( p2 == fs::current_path()/p );
+ VERIFY( !ec );
+
+ ec = bad_ec;
+ p2 = canonical( fs::current_path() / "." / (p.native() + "////././."), ec );
+ VERIFY( p2 == fs::current_path()/p );
+ VERIFY( !ec );
+
+ ec = bad_ec;
+ p = fs::current_path();
+ p2 = canonical( p, ec );
+ VERIFY( p2 == p );
+ VERIFY( !ec );
+
+ ec = bad_ec;
+ p = "/";
+ p = canonical( p, ec );
+ VERIFY( p == "/" );
+ VERIFY( !ec );
+
+ ec = bad_ec;
+ p = "/.";
+ p = canonical( p, ec );
+ VERIFY( p == "/" );
+ VERIFY( !ec );
+
+ ec = bad_ec;
+ p = "/..";
+ p = canonical( p, ec );
+ VERIFY( p == "/" );
+ VERIFY( !ec );
+
+ ec = bad_ec;
+ p = "/../.././.";
+ p = canonical( p, ec );
+ VERIFY( p == "/" );
+ VERIFY( !ec );
+}
+
+void
+test02()
+{
+ const fs::path p = __gnu_test::nonexistent_path();
+ std::error_code ec, ec2;
+ const fs::path res = canonical(p, ec);
+ VERIFY( ec );
+ VERIFY( res.empty() );
+
+#if __cpp_exceptions
+ fs::path e1, e2;
+ try {
+ canonical(p);
+ } catch (const fs::filesystem_error& e) {
+ e1 = e.path1();
+ e2 = e.path2();
+ ec2 = e.code();
+ }
+ VERIFY( e1 == p );
+ VERIFY( e2.empty() );
+ VERIFY( ec == ec2 );
+#endif
+}
+
+
+void
+test03()
+{
+ std::error_code ec;
+ auto dir = __gnu_test::nonexistent_path();
+ fs::create_directory(dir);
+ fs::path foo = dir/"foo", bar = dir/"bar";
+ fs::create_directory(foo);
+ fs::create_directory(bar);
+ fs::create_symlink("../bar", foo/"baz");
+
+ auto dirc = canonical(dir);
+ auto barc = canonical(bar);
+
+ auto p1 = fs::canonical(dir/"foo//.///..//./");
+ VERIFY( p1 == dirc );
+ auto p2 = fs::canonical(dir/"foo//./baz///..//./");
+ VERIFY( p2 == dirc );
+ auto p3 = fs::canonical(dir/"foo//./baz////./");
+ VERIFY( p3 == barc );
+ auto p4 = fs::canonical(dir/"foo//./baz///..//./bar");
+ VERIFY( p4 == barc );
+ auto p5 = fs::canonical(dir/"foo//./baz///..//./bar/");
+ VERIFY( p5 == p4 );
+ auto p6 = fs::canonical(dir/"foo//./baz///..//./bar/.");
+ VERIFY( p6 == p4 );
+
+ remove_all(dir);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc
new file mode 100644
index 0000000..7825a4e
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy.cc
@@ -0,0 +1,200 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 15.3 Copy [fs.op.copy]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+// Test error conditions.
+void
+test01()
+{
+ auto p = __gnu_test::nonexistent_path();
+ std::error_code ec;
+
+ VERIFY( !fs::exists(p) );
+ fs::copy(p, ".", fs::copy_options::none, ec);
+ VERIFY( ec );
+
+ ec.clear();
+ fs::copy(".", ".", fs::copy_options::none, ec);
+ VERIFY( ec );
+
+ __gnu_test::scoped_file f(p);
+ VERIFY( fs::is_directory(".") );
+ VERIFY( fs::is_regular_file(p) );
+ ec.clear();
+ fs::copy(".", p, fs::copy_options::none, ec);
+ VERIFY( ec );
+
+ auto to = __gnu_test::nonexistent_path();
+ ec.clear();
+ auto opts = fs::copy_options::create_symlinks;
+ fs::copy("/", to, opts, ec);
+ VERIFY( ec == std::make_error_code(std::errc::is_a_directory) );
+ VERIFY( !exists(to) );
+
+ ec.clear();
+ opts != fs::copy_options::recursive;
+ fs::copy("/", to, opts, ec);
+ VERIFY( ec == std::make_error_code(std::errc::is_a_directory) );
+ VERIFY( !exists(to) );
+}
+
+// Test is_symlink(f) case.
+void
+test02()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ auto from = __gnu_test::nonexistent_path();
+ auto to = __gnu_test::nonexistent_path();
+ std::error_code ec;
+
+ ec = bad_ec;
+ fs::create_symlink(".", from, ec);
+ VERIFY( !ec );
+ VERIFY( fs::exists(from) );
+
+ ec = bad_ec;
+ fs::copy(from, to, fs::copy_options::skip_symlinks, ec);
+ VERIFY( !ec );
+ VERIFY( !fs::exists(to) );
+
+ ec = bad_ec;
+ fs::copy(from, to, fs::copy_options::skip_symlinks, ec);
+ VERIFY( !ec );
+ VERIFY( !fs::exists(to) );
+
+ ec = bad_ec;
+ fs::copy(from, to,
+ fs::copy_options::skip_symlinks|fs::copy_options::copy_symlinks,
+ ec);
+ VERIFY( !ec );
+ VERIFY( !fs::exists(to) );
+
+ ec = bad_ec;
+ fs::copy(from, to, fs::copy_options::copy_symlinks, ec);
+ VERIFY( !ec );
+ VERIFY( fs::exists(to) );
+ VERIFY( is_symlink(to) );
+
+ ec.clear();
+ fs::copy(from, to, fs::copy_options::copy_symlinks, ec);
+ VERIFY( ec );
+
+ remove(from, ec);
+ remove(to, ec);
+}
+
+// Test is_regular_file(f) case.
+void
+test03()
+{
+ auto from = __gnu_test::nonexistent_path();
+ auto to = __gnu_test::nonexistent_path();
+
+ // test empty file
+ std::ofstream{from.native()};
+ VERIFY( fs::exists(from) );
+ VERIFY( fs::file_size(from) == 0 );
+ fs::copy(from, to);
+ VERIFY( fs::exists(to) );
+ VERIFY( fs::file_size(to) == 0 );
+
+ remove(to);
+ VERIFY( !fs::exists(to) );
+ std::ofstream{from.native()} << "Hello, filesystem!";
+ VERIFY( fs::file_size(from) != 0 );
+ fs::copy(from, to);
+ VERIFY( fs::exists(to) );
+ VERIFY( fs::file_size(to) == fs::file_size(from) );
+
+ remove(from);
+ remove(to);
+}
+
+// Test is_directory(f) case.
+void
+test04()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ auto from = __gnu_test::nonexistent_path();
+ auto to = __gnu_test::nonexistent_path();
+ std::error_code ec;
+
+ create_directories(from/"a/b/c");
+
+ {
+ __gnu_test::scoped_file f(to);
+ copy(from, to, ec);
+ VERIFY( ec );
+ }
+
+ __gnu_test::scoped_file f1(from/"a/f1");
+ std::ofstream{f1.path} << "file one";
+ __gnu_test::scoped_file f2(from/"a/b/f2");
+ std::ofstream{f2.path} << "file two";
+
+ copy(from, to, ec);
+ VERIFY( !ec );
+ VERIFY( exists(to) && is_empty(to) );
+ remove(to);
+
+ ec = bad_ec;
+ copy(from, to, fs::copy_options::recursive, ec);
+ VERIFY( !ec );
+ VERIFY( exists(to) && !is_empty(to) );
+ VERIFY( is_regular_file(to/"a/f1") && !is_empty(to/"a/f1") );
+ VERIFY( file_size(from/"a/f1") == file_size(to/"a/f1") );
+ VERIFY( is_regular_file(to/"a/b/f2") && !is_empty(to/"a/b/f2") );
+ VERIFY( file_size(from/"a/b/f2") == file_size(to/"a/b/f2") );
+ VERIFY( is_directory(to/"a/b/c") && is_empty(to/"a/b/c") );
+
+ f1.path.clear();
+ f2.path.clear();
+ remove_all(from, ec);
+ remove_all(to, ec);
+}
+
+// Test no-op cases.
+void
+test05()
+{
+ auto to = __gnu_test::nonexistent_path();
+ std::error_code ec = std::make_error_code(std::errc::invalid_argument);
+
+ fs::copy("/", to, fs::copy_options::copy_symlinks, ec);
+ VERIFY( !ec ); // Previous value should be cleared (LWG 2683)
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc
new file mode 100644
index 0000000..69ab7fb
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/copy_file.cc
@@ -0,0 +1,84 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// 15.4 Copy [fs.op.copy_file]
+
+#include <filesystem>
+#include <fstream>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ using std::filesystem::copy_options;
+ std::error_code ec;
+
+ auto from = __gnu_test::nonexistent_path();
+ auto to = __gnu_test::nonexistent_path();
+
+ // test non-existent file
+ bool b = copy_file(from, to, ec);
+ VERIFY( !b );
+ VERIFY( ec );
+ VERIFY( !exists(to) );
+
+ // test empty file
+ std::ofstream{from.native()};
+ VERIFY( exists(from) );
+ VERIFY( file_size(from) == 0 );
+
+ b = copy_file(from, to);
+ VERIFY( b );
+ VERIFY( exists(to) );
+ VERIFY( file_size(to) == 0 );
+ remove(to);
+ VERIFY( !exists(to) );
+ b = copy_file(from, to, copy_options::none, ec);
+ VERIFY( b );
+ VERIFY( !ec );
+ VERIFY( exists(to) );
+ VERIFY( file_size(to) == 0 );
+
+ std::ofstream{from.native()} << "Hello, filesystem!";
+ VERIFY( file_size(from) != 0 );
+ remove(to);
+ VERIFY( !exists(to) );
+ b = copy_file(from, to);
+ VERIFY( b );
+ VERIFY( exists(to) );
+ VERIFY( file_size(to) == file_size(from) );
+ remove(to);
+ VERIFY( !exists(to) );
+ b = copy_file(from, to);
+ VERIFY( b );
+ VERIFY( exists(to) );
+ VERIFY( file_size(to) == file_size(from) );
+
+ remove(from);
+ remove(to);
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc
new file mode 100644
index 0000000..9459678
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directories.cc
@@ -0,0 +1,83 @@
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+
+ // Test empty path.
+ bool b = fs::create_directories( "", ec );
+ VERIFY( ec );
+ VERIFY( !b );
+
+ // Test existing path.
+ ec = bad_ec;
+ b = fs::create_directories( fs::current_path(), ec );
+ VERIFY( !ec );
+ VERIFY( !b );
+
+ // Test non-existent path.
+ const auto p = __gnu_test::nonexistent_path();
+ ec = bad_ec;
+ b = fs::create_directories( p, ec );
+ VERIFY( !ec );
+ VERIFY( b );
+ VERIFY( is_directory(p) );
+
+ ec = bad_ec;
+ b = fs::create_directories( p/".", ec );
+ VERIFY( !ec );
+ VERIFY( !b );
+
+ ec = bad_ec;
+ b = fs::create_directories( p/"..", ec );
+ VERIFY( !ec );
+ VERIFY( !b );
+
+ ec = bad_ec;
+ b = fs::create_directories( p/"d1/d2/d3", ec );
+ VERIFY( !ec );
+ VERIFY( b );
+ VERIFY( is_directory(p/"d1/d2/d3") );
+
+ ec = bad_ec;
+ b = fs::create_directories( p/"./d4/../d5", ec );
+ VERIFY( !ec );
+ VERIFY( b );
+ VERIFY( is_directory(p/"./d4/../d5") );
+
+ std::uintmax_t count = remove_all(p, ec);
+ VERIFY( count == 6 );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc
new file mode 100644
index 0000000..927a97c
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_directory.cc
@@ -0,0 +1,65 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+
+ // Test empty path.
+ fs::path p;
+ bool b = create_directory( p, ec );
+ VERIFY( ec );
+ VERIFY( !b );
+
+ // Test non-existent path
+ p = __gnu_test::nonexistent_path();
+ VERIFY( !exists(p) );
+
+ ec = bad_ec;
+ b = create_directory(p, ec); // create the directory once
+ VERIFY( !ec );
+ VERIFY( b );
+ VERIFY( exists(p) );
+
+ // Test existing path (libstdc++/71036).
+ ec = bad_ec;
+ b = create_directory(p, ec);
+ VERIFY( !ec );
+ VERIFY( !b );
+ b = create_directory(p);
+ VERIFY( !b );
+
+ remove_all(p, ec);
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc
new file mode 100644
index 0000000..7eff356
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/create_symlink.cc
@@ -0,0 +1,96 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ std::error_code ec, ec2;
+ __gnu_test::scoped_file f;
+ auto tgt = f.path;
+
+ // Test empty path.
+ fs::path p;
+ create_symlink(tgt, p, ec );
+ VERIFY( ec );
+ try
+ {
+ create_symlink(tgt, p);
+ }
+ catch (const std::filesystem::filesystem_error& ex)
+ {
+ ec2 = ex.code();
+ VERIFY( ex.path1() == tgt );
+ VERIFY( ex.path2() == p );
+ }
+ VERIFY( ec2 == ec );
+}
+
+void
+test02()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec, ec2;
+ __gnu_test::scoped_file f;
+ auto tgt = f.path;
+
+ // Test non-existent path
+ auto p = __gnu_test::nonexistent_path();
+ VERIFY( !exists(p) );
+
+ ec = bad_ec;
+ create_symlink(tgt, p, ec); // create the symlink once
+ VERIFY( !ec );
+ VERIFY( exists(p) );
+ VERIFY( is_symlink(p) );
+ remove(p);
+ create_symlink(tgt, p); // create the symlink again
+ VERIFY( exists(p) );
+ VERIFY( is_symlink(p) );
+
+ ec.clear();
+ create_symlink(tgt, p, ec); // Try to create existing symlink
+ VERIFY( ec );
+ try
+ {
+ create_symlink(tgt, p);
+ }
+ catch (const std::filesystem::filesystem_error& ex)
+ {
+ ec2 = ex.code();
+ VERIFY( ex.path1() == tgt );
+ VERIFY( ex.path2() == p );
+ }
+ VERIFY( ec2 == ec );
+
+ remove(p);
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc
new file mode 100644
index 0000000..2ba3ff9
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/current_path.cc
@@ -0,0 +1,58 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 15.11 Current path [fs.op.current_path]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ fs::path dot(".");
+ fs::path cwd = fs::current_path();
+ std::error_code ec;
+ fs::path cwd2 = fs::current_path(ec);
+ VERIFY( cwd == cwd2 );
+}
+
+void
+test02()
+{
+ auto oldwd = fs::current_path();
+ auto tmpdir = fs::temp_directory_path();
+ current_path(tmpdir);
+ VERIFY( canonical(fs::current_path()) == canonical(tmpdir) );
+ std::error_code ec;
+ current_path(oldwd, ec);
+ VERIFY( canonical(fs::current_path()) == canonical(oldwd) );
+ VERIFY( canonical(fs::current_path(ec)) == canonical(oldwd) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc
new file mode 100644
index 0000000..92d69c60
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/equivalent.cc
@@ -0,0 +1,74 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ auto p1 = __gnu_test::nonexistent_path();
+ auto p2 = __gnu_test::nonexistent_path();
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+ bool result;
+
+ result = equivalent(p1, p2, ec);
+ VERIFY( ec );
+ VERIFY( !result );
+
+ __gnu_test::scoped_file f1(p1);
+ ec = bad_ec;
+ result = equivalent(p1, p2, ec);
+ VERIFY( !ec );
+ VERIFY( !result );
+
+ __gnu_test::scoped_file f2(p2);
+ ec = bad_ec;
+ result = equivalent(p1, p2, ec);
+ VERIFY( !ec );
+ VERIFY( !result );
+
+ auto p3 = __gnu_test::nonexistent_path();
+ create_hard_link(p1, p3, ec);
+ if (ec)
+ return; // hard links not supported
+ __gnu_test::scoped_file f3(p3, __gnu_test::scoped_file::adopt_file);
+
+ ec = bad_ec;
+ result = equivalent(p1, p3, ec);
+ VERIFY( !ec );
+ VERIFY( result );
+
+ ec = bad_ec;
+ result = equivalent(p2, p3, ec);
+ VERIFY( !ec );
+ VERIFY( !result );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc
new file mode 100644
index 0000000..0775eff
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/exists.cc
@@ -0,0 +1,115 @@
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+
+ VERIFY( exists(path{"/"}) );
+ VERIFY( exists(path{"/."}) );
+ VERIFY( exists(path{"."}) );
+ VERIFY( exists(path{".."}) );
+ VERIFY( exists(std::filesystem::current_path()) );
+
+ std::error_code ec;
+ ec = bad_ec;
+ VERIFY( exists(path{"/"}, ec) );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( exists(path{"/."}, ec) );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( exists(path{"."}, ec) );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( exists(path{".."}, ec) );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( exists(std::filesystem::current_path(), ec) );
+ VERIFY( !ec );
+}
+
+void
+test02()
+{
+ path rel = __gnu_test::nonexistent_path();
+ VERIFY( !exists(rel) );
+
+ std::error_code ec = std::make_error_code(std::errc::invalid_argument);
+ VERIFY( !exists(rel, ec) );
+ VERIFY( !ec ); // DR 2725
+}
+
+void
+test03()
+{
+ path abs = absolute(__gnu_test::nonexistent_path());
+ VERIFY( !exists(abs) );
+
+ std::error_code ec = std::make_error_code(std::errc::invalid_argument);
+ VERIFY( !exists(abs, ec) );
+ VERIFY( !ec ); // DR 2725
+}
+
+void
+test04()
+{
+ using std::filesystem::perms;
+ using std::filesystem::perm_options;
+ path p = __gnu_test::nonexistent_path();
+ create_directory(p);
+ permissions(p, perms::all, perm_options::remove);
+
+ auto unr = p / "unreachable";
+ std::error_code ec;
+ VERIFY( !exists(unr, ec) );
+ VERIFY( ec == std::errc::permission_denied );
+ ec.clear();
+ try
+ {
+ exists(unr);
+ }
+ catch(const std::filesystem::filesystem_error& ex)
+ {
+ ec = ex.code();
+ VERIFY( ex.path1() == unr );
+ }
+ VERIFY( ec == std::errc::permission_denied );
+
+ permissions(p, perms::owner_all);
+ remove(p);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc
new file mode 100644
index 0000000..250d318
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/file_size.cc
@@ -0,0 +1,71 @@
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ std::error_code ec;
+ size_t size = fs::file_size(".", ec);
+ VERIFY( ec == std::errc::is_a_directory );
+ VERIFY( size == -1 );
+
+ try {
+ size = fs::file_size(".");
+ ec.clear();
+ } catch (const fs::filesystem_error& e) {
+ ec = e.code();
+ }
+ VERIFY( ec == std::errc::is_a_directory );
+ VERIFY( size == -1 );
+}
+
+void
+test02()
+{
+ fs::path p = __gnu_test::nonexistent_path();
+
+ std::error_code ec;
+ size_t size = fs::file_size(p, ec);
+ VERIFY( ec );
+ VERIFY( size == -1 );
+
+ try {
+ size = fs::file_size(p);
+ ec.clear();
+ } catch (const fs::filesystem_error& e) {
+ ec = e.code();
+ }
+ VERIFY( ec );
+ VERIFY( size == -1 );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc
new file mode 100644
index 0000000..6d79a91
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/is_empty.cc
@@ -0,0 +1,109 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ auto p = __gnu_test::nonexistent_path();
+ create_directory(p);
+ permissions(p, fs::perms::none);
+ std::error_code ec, ec2;
+
+ bool result = fs::is_empty(p, ec);
+ VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
+ VERIFY( !result );
+
+ try {
+ fs::is_empty(p);
+ } catch (const fs::filesystem_error& e) {
+ ec2 = e.code();
+ }
+ VERIFY( ec2 == ec );
+
+ result = fs::is_empty(p/"f", ec);
+ VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
+ VERIFY( !result );
+
+ try {
+ fs::is_empty(p/"f");
+ } catch (const fs::filesystem_error& e) {
+ ec2 = e.code();
+ }
+ VERIFY( ec2 == ec );
+
+ permissions(p, fs::perms::owner_all, ec);
+ remove_all(p, ec);
+}
+
+void
+test02()
+{
+ auto p = __gnu_test::nonexistent_path();
+ create_directory(p);
+ std::error_code ec, bad_ec = make_error_code(std::errc::invalid_argument);
+ bool empty;
+
+ ec = bad_ec;
+ empty = is_empty(p, ec);
+ VERIFY( !ec );
+ VERIFY( empty );
+ empty = is_empty(p);
+ VERIFY( empty );
+
+ __gnu_test::scoped_file f(p/"f");
+ ec = bad_ec;
+ empty = is_empty(f.path, ec);
+ VERIFY( !ec );
+ VERIFY( empty );
+ empty = is_empty(f.path);
+ VERIFY( empty );
+
+ std::ofstream{f.path.native()} << "data";
+ ec = bad_ec;
+ empty = is_empty(p, ec);
+ VERIFY( !ec );
+ VERIFY( !empty );
+ empty = is_empty(p);
+ VERIFY( !empty );
+
+ ec = bad_ec;
+ empty = is_empty(p, ec);
+ VERIFY( !ec );
+ VERIFY( !empty );
+ empty = is_empty(p);
+ VERIFY( !empty );
+
+ f.path.clear();
+ remove_all(p, ec);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
new file mode 100644
index 0000000..ecef3f8
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/last_write_time.cc
@@ -0,0 +1,162 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// 15.25 Permissions [fs.op.last_write_time]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+#ifdef _GLIBCXX_HAVE_FCNTL_H
+# include <fcntl.h>
+#endif
+#if _GLIBCXX_HAVE_UTIME_H
+# include <utime.h>
+#endif
+
+using time_type = std::filesystem::file_time_type;
+
+void
+test01()
+{
+ // read times
+
+ auto p = __gnu_test::nonexistent_path();
+ std::error_code ec;
+ time_type mtime = last_write_time(p, ec);
+ VERIFY( ec );
+ VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
+#if __cpp_exceptions
+ bool caught = false;
+ try {
+ mtime = last_write_time(p);
+ } catch (std::system_error const& e) {
+ caught = true;
+ ec = e.code();
+ }
+ VERIFY( caught );
+ VERIFY( ec );
+ VERIFY( ec == std::make_error_code(std::errc::no_such_file_or_directory) );
+#endif
+
+ __gnu_test::scoped_file file(p);
+ VERIFY( exists(p) );
+ mtime = last_write_time(p, ec);
+ VERIFY( !ec );
+ VERIFY( mtime <= time_type::clock::now() );
+ VERIFY( mtime == last_write_time(p) );
+
+ auto end_of_time = time_type::duration::max();
+ auto last_second
+ = std::chrono::duration_cast<std::chrono::seconds>(end_of_time).count();
+ if (last_second > std::numeric_limits<std::time_t>::max())
+ return; // can't test overflow
+
+#if _GLIBCXX_USE_UTIMENSAT
+ struct ::timespec ts[2];
+ ts[0].tv_sec = 0;
+ ts[0].tv_nsec = UTIME_NOW;
+ ts[1].tv_sec = std::numeric_limits<std::time_t>::max() - 1;
+ ts[1].tv_nsec = 0;
+ VERIFY( !::utimensat(AT_FDCWD, p.c_str(), ts, 0) );
+#elif _GLIBCXX_HAVE_UTIME_H
+ ::utimbuf times;
+ times.modtime = std::numeric_limits<std::time_t>::max() - 1;
+ times.actime = std::numeric_limits<std::time_t>::max() - 1;
+ VERIFY( !::utime(p.c_str(), &times) );
+#else
+ return;
+#endif
+
+ mtime = last_write_time(p, ec);
+ VERIFY( ec );
+ VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
+ VERIFY( mtime == time_type::min() );
+
+#if __cpp_exceptions
+ caught = false;
+ try {
+ mtime = last_write_time(p);
+ } catch (std::system_error const& e) {
+ caught = true;
+ ec = e.code();
+ }
+ VERIFY( caught );
+ VERIFY( ec );
+ VERIFY( ec == std::make_error_code(std::errc::value_too_large) );
+#endif
+}
+
+bool approx_equal(time_type file_time, time_type expected)
+{
+ auto delta = expected - file_time;
+ if (delta < delta.zero())
+ delta = -delta;
+ return delta < std::chrono::seconds(1);
+}
+
+void
+test02()
+{
+ // write times
+
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ __gnu_test::scoped_file f;
+ std::error_code ec;
+ time_type time;
+
+ time = last_write_time(f.path);
+ ec = bad_ec;
+ last_write_time(f.path, time, ec);
+ VERIFY( !ec );
+ VERIFY( approx_equal(last_write_time(f.path), time) );
+
+ ec = bad_ec;
+ time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+ last_write_time(f.path, time, ec);
+ VERIFY( !ec );
+ VERIFY( approx_equal(last_write_time(f.path), time) );
+
+ ec = bad_ec;
+ time += std::chrono::milliseconds(1000 * 60 * 20 + 15);
+ last_write_time(f.path, time, ec);
+ VERIFY( !ec );
+ VERIFY( approx_equal(last_write_time(f.path), time) );
+
+ ec = bad_ec;
+ time = time_type();
+ last_write_time(f.path, time, ec);
+ VERIFY( !ec );
+ VERIFY( approx_equal(last_write_time(f.path), time) );
+
+ ec = bad_ec;
+ time -= std::chrono::milliseconds(1000 * 60 * 10 + 15);
+ last_write_time(f.path, time, ec);
+ VERIFY( !ec );
+ VERIFY( approx_equal(last_write_time(f.path), time) );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc
new file mode 100644
index 0000000..97b7a78
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/permissions.cc
@@ -0,0 +1,167 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// C++17 30.10.14.26 Permissions [fs.op.permissions]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ using std::filesystem::perms;
+ using std::filesystem::perm_options;
+
+ auto p = __gnu_test::nonexistent_path();
+
+ __gnu_test::scoped_file f(p);
+ VERIFY( exists(p) );
+ permissions(p, perms::owner_all);
+ VERIFY( status(p).permissions() == perms::owner_all );
+ permissions(p, perms::group_read, perm_options::add);
+ VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) );
+ permissions(p, perms::group_read, perm_options::remove);
+ VERIFY( status(p).permissions() == perms::owner_all );
+}
+
+void
+test02()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ using std::filesystem::perms;
+ using std::filesystem::perm_options;
+
+ auto p = __gnu_test::nonexistent_path();
+
+ std::error_code ec;
+ permissions(p, perms::owner_all, ec);
+ VERIFY( ec );
+
+ __gnu_test::scoped_file f(p);
+ VERIFY( exists(p) );
+
+ ec = bad_ec;
+ permissions(p, perms::owner_all, ec);
+ VERIFY( !ec );
+ VERIFY( status(p).permissions() == perms::owner_all );
+ ec = bad_ec;
+ permissions(p, perms::group_read, perm_options::add, ec);
+ VERIFY( !ec );
+ VERIFY( status(p).permissions() == (perms::owner_all | perms::group_read) );
+ ec = bad_ec;
+ permissions(p, perms::group_read, perm_options::remove, ec);
+ VERIFY( !ec );
+ VERIFY( status(p).permissions() == perms::owner_all );
+}
+
+void
+test03()
+{
+ using std::filesystem::perms;
+ using std::filesystem::perm_options;
+
+ __gnu_test::scoped_file f;
+ VERIFY( exists(f.path) );
+
+ auto p = __gnu_test::nonexistent_path();
+ create_symlink(f.path, p);
+
+ std::error_code ec = make_error_code(std::errc::no_such_file_or_directory);
+ std::error_code ec2 = make_error_code(std::errc::invalid_argument);
+ permissions(p, perms::owner_all,
+ perm_options::replace|perm_options::nofollow, ec);
+ try
+ {
+ permissions(p, perms::owner_all,
+ perm_options::replace|perm_options::nofollow);
+ }
+ catch (const std::filesystem::filesystem_error& ex)
+ {
+ ec2 = ex.code();
+ VERIFY( ex.path1() == p );
+ }
+ // Both calls should succeed, or both should fail with same error:
+ VERIFY( ec == ec2 );
+
+ remove(p);
+}
+
+void
+test04()
+{
+ using perms = std::filesystem::perms;
+
+ auto p = __gnu_test::nonexistent_path();
+ create_symlink(__gnu_test::nonexistent_path(), p);
+
+ std::error_code ec = make_error_code(std::errc::no_such_file_or_directory);
+ std::error_code ec2 = make_error_code(std::errc::invalid_argument);
+ permissions(p, perms::owner_all, ec);
+ VERIFY( ec );
+ try
+ {
+ permissions(p, perms::owner_all);
+ }
+ catch (const std::filesystem::filesystem_error& ex)
+ {
+ ec2 = ex.code();
+ VERIFY( ex.path1() == p );
+ }
+ VERIFY( ec == ec2 );
+
+ remove(p);
+}
+
+void
+test05()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ using std::filesystem::perms;
+ using std::filesystem::perm_options;
+ std::error_code ec;
+
+ __gnu_test::scoped_file f;
+ auto p = perms::owner_write;
+
+ // symlink_nofollow should not give an error for non-symlinks
+ ec = bad_ec;
+ permissions(f.path, p, perm_options::replace|perm_options::nofollow, ec);
+ VERIFY( !ec );
+ auto st = status(f.path);
+ VERIFY( st.permissions() == p );
+ p |= perms::owner_read;
+ ec = bad_ec;
+ permissions(f.path, p, perm_options::replace|perm_options::nofollow, ec);
+ VERIFY( !ec );
+ st = status(f.path);
+ VERIFY( st.permissions() == p );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+ test05();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc
new file mode 100644
index 0000000..02da250
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/proximate.cc
@@ -0,0 +1,67 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::proximate;
+
+void
+test01()
+{
+ VERIFY( proximate("/a/d", "/a/b/c") == "../../d" );
+ VERIFY( proximate("/a/b/c", "/a/d") == "../b/c" );
+ VERIFY( proximate("a/b/c", "a") == "b/c" );
+ VERIFY( proximate("a/b/c", "a/b/c/x/y") == "../.." );
+ VERIFY( proximate("a/b/c", "a/b/c") == "." );
+ VERIFY( proximate("a/b", "c/d") == "../../a/b" );
+}
+
+void
+test02()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec = bad_ec;
+ VERIFY( proximate("/a/d", "/a/b/c", ec) == "../../d" );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( proximate("/a/b/c", "/a/d", ec) == "../b/c" );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( proximate("a/b/c", "a", ec) == "b/c" );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( proximate("a/b/c", "a/b/c/x/y", ec) == "../.." );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( proximate("a/b/c", "a/b/c", ec) == "." );
+ VERIFY( !ec );
+ ec = bad_ec;
+ VERIFY( proximate("a/b", "c/d", ec) == "../../a/b" );
+ VERIFY( !ec );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc
new file mode 100644
index 0000000..067a609
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/read_symlink.cc
@@ -0,0 +1,51 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ auto p = __gnu_test::nonexistent_path();
+ std::error_code ec;
+
+ read_symlink(p, ec);
+ VERIFY( ec );
+
+ fs::path tgt = ".";
+ create_symlink(tgt, p);
+
+ auto result = read_symlink(p, ec);
+ VERIFY( !ec );
+ VERIFY( result == tgt );
+
+ remove(p);
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc
new file mode 100644
index 0000000..c9765fa
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/relative.cc
@@ -0,0 +1,64 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ auto p = __gnu_test::nonexistent_path();
+ auto q = __gnu_test::nonexistent_path();
+
+ auto r = relative(p, q);
+ VERIFY( r == ".."/p );
+
+ r = relative(p, p/q);
+ VERIFY( r == ".." );
+
+ r = relative(p/q, p);
+ VERIFY( r == q );
+
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+
+ ec = bad_ec;
+ r = relative(p, q, ec);
+ VERIFY( !ec );
+ VERIFY( r == ".."/p );
+
+ ec = bad_ec;
+ r = relative(p, p/q, ec);
+ VERIFY( !ec );
+ VERIFY( r == ".." );
+
+ ec = bad_ec;
+ r = relative(p/q, p, ec);
+ VERIFY( !ec );
+ VERIFY( r == q );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc
new file mode 100644
index 0000000..3f68f17
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/remove_all.cc
@@ -0,0 +1,92 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ std::error_code ec;
+ std::uintmax_t n;
+
+ n = fs::remove_all("", ec);
+ VERIFY( ec );
+ VERIFY( n == std::uintmax_t(-1) );
+
+ auto p = __gnu_test::nonexistent_path();
+ ec.clear();
+ n = remove_all(p, ec);
+ VERIFY( ec );
+ VERIFY( n == std::uintmax_t(-1) );
+
+ const auto bad_ec = ec;
+ auto link = __gnu_test::nonexistent_path();
+ create_symlink(p, link); // dangling symlink
+ ec = bad_ec;
+ n = remove_all(link, ec);
+ VERIFY( !ec );
+ VERIFY( n == 1 );
+ VERIFY( !exists(symlink_status(link)) ); // DR 2721
+
+ __gnu_test::scoped_file f(p);
+ create_symlink(p, link);
+ ec = bad_ec;
+ n = remove_all(link, ec);
+ VERIFY( !ec );
+ VERIFY( n == 1 );
+ VERIFY( !exists(symlink_status(link)) ); // The symlink is removed, but
+ VERIFY( exists(p) ); // its target is not.
+
+ auto dir = __gnu_test::nonexistent_path();
+ create_directories(dir/"a/b/c");
+ ec = bad_ec;
+ n = remove_all(dir/"a", ec);
+ VERIFY( !ec );
+ VERIFY( n == 3 );
+ VERIFY( exists(dir) );
+ VERIFY( !exists(dir/"a") );
+
+ create_directories(dir/"a/b/c");
+ __gnu_test::scoped_file a1(dir/"a/1");
+ __gnu_test::scoped_file a2(dir/"a/2");
+ __gnu_test::scoped_file b1(dir/"a/b/1");
+ __gnu_test::scoped_file b2(dir/"a/b/2");
+ ec = bad_ec;
+ n = remove_all(dir, ec);
+ VERIFY( !ec );
+ VERIFY( n == 8 );
+ VERIFY( !exists(dir) );
+
+ a1.path.clear();
+ a2.path.clear();
+ b1.path.clear();
+ b2.path.clear();
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc
new file mode 100644
index 0000000..7b61135
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/space.cc
@@ -0,0 +1,46 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// 30.10.14.3 Permissions [fs.op.space]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ std::filesystem::space_info s = std::filesystem::space("/");
+ std::error_code ec = make_error_code(std::errc::invalid_argument);
+ s = std::filesystem::space("/", ec);
+ VERIFY( !ec );
+ s = std::filesystem::space(__gnu_test::nonexistent_path(), ec);
+ VERIFY( ec );
+ VERIFY( s.capacity == static_cast<uintmax_t>(-1) );
+ VERIFY( s.free == static_cast<uintmax_t>(-1) );
+ VERIFY( s.available == static_cast<uintmax_t>(-1) );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc
new file mode 100644
index 0000000..efe92b2
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/status.cc
@@ -0,0 +1,97 @@
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ std::error_code ec = make_error_code(std::errc::invalid_argument);
+ fs::path dot = ".";
+
+ fs::file_status st1 = fs::status(dot, ec);
+ VERIFY( !ec );
+ VERIFY( st1.type() == fs::file_type::directory );
+
+ fs::file_status st2 = fs::status(dot);
+ VERIFY( st2.type() == fs::file_type::directory );
+}
+
+void
+test02()
+{
+ fs::path p = __gnu_test::nonexistent_path();
+
+ std::error_code ec;
+ fs::file_status st1 = fs::status(p, ec);
+ VERIFY( ec );
+ VERIFY( st1.type() == fs::file_type::not_found );
+
+ fs::file_status st2 = fs::status(p);
+ VERIFY( st2.type() == fs::file_type::not_found );
+}
+
+void
+test03()
+{
+ fs::path dir = __gnu_test::nonexistent_path();
+ fs::create_directory(dir);
+ __gnu_test::scoped_file d(dir, __gnu_test::scoped_file::adopt_file);
+ __gnu_test::scoped_file f(dir / "file");
+ fs::permissions(dir, fs::perms::none);
+
+ std::error_code ec;
+ fs::file_status st = fs::status(f.path, ec);
+ VERIFY( ec.value() == (int)std::errc::permission_denied );
+ VERIFY( st.type() == fs::file_type::none );
+
+#if __cpp_exceptions
+ bool caught = false;
+ std::error_code ec2;
+ fs::path p, p2;
+ try {
+ fs::symlink_status(f.path);
+ } catch (const fs::filesystem_error& e) {
+ caught = true;
+ p = e.path1();
+ p2 = e.path2();
+ ec2 = e.code();
+ }
+ VERIFY( caught );
+ VERIFY( ec2 == ec );
+ VERIFY( p == f.path );
+ VERIFY( p2.empty() );
+#endif
+
+ fs::permissions(dir, fs::perms::owner_all, ec);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc
new file mode 100644
index 0000000..ae7a76b
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/symlink_status.cc
@@ -0,0 +1,118 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec = bad_ec;
+ fs::path dot = ".";
+
+ fs::file_status st1 = fs::symlink_status(dot, ec);
+ VERIFY( !ec );
+ VERIFY( st1.type() == fs::file_type::directory );
+
+ fs::file_status st2 = fs::symlink_status(dot);
+ VERIFY( st2.type() == fs::file_type::directory );
+
+ fs::path link = __gnu_test::nonexistent_path();
+ create_directory_symlink(dot, link);
+
+ st1 = fs::symlink_status(link);
+ VERIFY( st1.type() == fs::file_type::symlink );
+ ec = bad_ec;
+ st2 = fs::symlink_status(link, ec);
+ VERIFY( !ec );
+ VERIFY( st2.type() == fs::file_type::symlink );
+}
+
+void
+test02()
+{
+ fs::path p = __gnu_test::nonexistent_path();
+
+ std::error_code ec;
+ fs::file_status st1 = fs::symlink_status(p, ec);
+ VERIFY( ec );
+ VERIFY( st1.type() == fs::file_type::not_found );
+
+ fs::file_status st2 = fs::symlink_status(p);
+ VERIFY( st2.type() == fs::file_type::not_found );
+}
+
+void
+test03()
+{
+ fs::path dir = __gnu_test::nonexistent_path();
+ fs::create_directory(dir);
+ __gnu_test::scoped_file d(dir, __gnu_test::scoped_file::adopt_file);
+ __gnu_test::scoped_file f(dir / "file");
+ fs::permissions(dir, fs::perms::none);
+ auto link = __gnu_test::nonexistent_path();
+ fs::create_symlink(f.path, link);
+ __gnu_test::scoped_file l(link, __gnu_test::scoped_file::adopt_file);
+
+ std::error_code ec;
+ fs::file_status st = fs::symlink_status(f.path, ec);
+ VERIFY( ec.value() == (int)std::errc::permission_denied );
+ VERIFY( st.type() == fs::file_type::none );
+
+ st = fs::symlink_status(link, ec);
+ VERIFY( !ec );
+ VERIFY( st.type() == fs::file_type::symlink );
+
+#if __cpp_exceptions
+ bool caught = false;
+ std::error_code ec2;
+ fs::path p, p2;
+ try {
+ fs::symlink_status(f.path);
+ } catch (const fs::filesystem_error& e) {
+ caught = true;
+ p = e.path1();
+ p2 = e.path2();
+ ec2 = e.code();
+ }
+ VERIFY( caught );
+ VERIFY( ec2.value() == (int)std::errc::permission_denied );
+ VERIFY( p == f.path );
+ VERIFY( p2.empty() );
+#endif
+
+ fs::file_status st2 = symlink_status(link);
+ VERIFY( st2.type() == fs::file_type::symlink );
+
+ fs::permissions(dir, fs::perms::owner_all, ec);
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
new file mode 100644
index 0000000..ee065f0
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/temp_directory_path.cc
@@ -0,0 +1,127 @@
+// Copyright (C) 2015-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <stdlib.h>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+void
+clean_env()
+{
+ ::unsetenv("TMPDIR");
+ ::unsetenv("TMP");
+ ::unsetenv("TEMPDIR");
+ ::unsetenv("TEMP");
+}
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ clean_env();
+
+ if (!fs::exists("/tmp"))
+ return; // just give up
+
+ std::error_code ec = make_error_code(std::errc::invalid_argument);
+ fs::path p1 = fs::temp_directory_path(ec);
+ VERIFY( !ec );
+ VERIFY( exists(p1) );
+
+ fs::path p2 = fs::temp_directory_path();
+ VERIFY( p1 == p2 );
+}
+
+void
+test02()
+{
+ clean_env();
+
+ if (::setenv("TMPDIR", __gnu_test::nonexistent_path().string().c_str(), 1))
+ return; // just give up
+
+ std::error_code ec;
+ fs::path p = fs::temp_directory_path(ec);
+ VERIFY( ec );
+ VERIFY( p == fs::path() );
+
+ std::error_code ec2;
+ try {
+ p = fs::temp_directory_path();
+ } catch (const fs::filesystem_error& e) {
+ ec2 = e.code();
+ }
+ VERIFY( ec2 == ec );
+}
+
+void
+test03()
+{
+ auto p = __gnu_test::nonexistent_path();
+ create_directories(p/"tmp");
+ permissions(p, fs::perms::none);
+ setenv("TMPDIR", (p/"tmp").c_str(), 1);
+ std::error_code ec;
+ auto r = fs::temp_directory_path(ec); // libstdc++/PR71337
+ VERIFY( ec == std::make_error_code(std::errc::permission_denied) );
+ VERIFY( r == fs::path() );
+
+ std::error_code ec2;
+ try {
+ fs::temp_directory_path();
+ } catch (const fs::filesystem_error& e) {
+ ec2 = e.code();
+ }
+ VERIFY( ec2 == ec );
+
+ permissions(p, fs::perms::owner_all, ec);
+ remove_all(p, ec);
+}
+
+void
+test04()
+{
+ __gnu_test::scoped_file f;
+ setenv("TMPDIR", f.path.c_str(), 1);
+ std::error_code ec;
+ auto r = fs::temp_directory_path(ec);
+ VERIFY( ec == std::make_error_code(std::errc::not_a_directory) );
+ VERIFY( r == fs::path() );
+
+ std::error_code ec2;
+ try {
+ fs::temp_directory_path();
+ } catch (const fs::filesystem_error& e) {
+ ec2 = e.code();
+ }
+ VERIFY( ec2 == ec );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+ test04();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc b/libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc
new file mode 100644
index 0000000..0f285e2
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/operations/weakly_canonical.cc
@@ -0,0 +1,70 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+namespace fs = std::filesystem;
+
+void
+test01()
+{
+ auto dir = __gnu_test::nonexistent_path();
+ fs::create_directory(dir);
+ const auto dirc = canonical(dir);
+ fs::path foo = dir/"foo", bar = dir/"bar";
+ fs::create_directory(foo);
+ fs::create_directory(bar);
+ fs::create_directory(bar/"baz");
+ fs::create_symlink("../bar", foo/"bar");
+
+ auto p = fs::weakly_canonical(dir/"foo//./bar///../biz/.");
+ VERIFY( p == dirc/"biz/" );
+ p = fs::weakly_canonical(dir/"foo/.//bar/././baz/.");
+ VERIFY( p == dirc/"bar/baz" );
+ p = fs::weakly_canonical(fs::current_path()/dir/"bar//../foo/bar/baz");
+ VERIFY( p == dirc/"bar/baz" );
+
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
+ std::error_code ec;
+
+ ec = bad_ec;
+ p = fs::weakly_canonical(dir/"foo//./bar///../biz/.", ec);
+ VERIFY( !ec );
+ VERIFY( p == dirc/"biz/" );
+ ec = bad_ec;
+ p = fs::weakly_canonical(dir/"foo/.//bar/././baz/.", ec);
+ VERIFY( !ec );
+ VERIFY( p == dirc/"bar/baz" );
+ ec = bad_ec;
+ p = fs::weakly_canonical(fs::current_path()/dir/"bar//../foo/bar/baz", ec);
+ VERIFY( !ec );
+ VERIFY( p == dirc/"bar/baz" );
+
+ fs::remove_all(dir, ec);
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc
new file mode 100644
index 0000000..64c638e
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/append/path.cc
@@ -0,0 +1,87 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.3 path appends [path.append]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ const path p("/foo/bar");
+
+ path pp = p;
+ pp /= p;
+ VERIFY( pp.native() == p.native() );
+
+ path q("baz");
+
+ path qq = q;
+ qq /= q;
+ VERIFY( qq.native() == "baz/baz" );
+
+ q /= p;
+ VERIFY( q.native() == p.native() );
+
+ path r = "";
+ r /= path();
+ VERIFY( r.empty() );
+
+ r /= path("rel");
+ VERIFY( !r.is_absolute() );
+
+ path s = "dir/";
+ s /= path("/file");
+ VERIFY( s.native() == "/file" );
+
+ s = "dir/";
+ s /= path("file");
+ VERIFY( s.native() == "dir/file" );
+}
+
+void
+test02()
+{
+ // C++17 [fs.path.append] p4
+
+ path p = path("//host") / "foo";
+ VERIFY( p == "//host/foo" );
+
+ path pp = path("//host/") / "foo";
+ VERIFY( pp == "//host/foo" );
+
+ path q = path("foo") / "";
+ VERIFY( q == "foo/" );
+
+ path qq = path("foo") / "/bar";
+ VERIFY( qq == "/bar" );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc
new file mode 100644
index 0000000..d8797ca
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/assign.cc
@@ -0,0 +1,94 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+ for (std::string s : __gnu_test::test_paths)
+ {
+ path p0 = s, p1, p2, p3, p4;
+
+ p1 = s;
+ compare_paths(p0, p1);
+
+ p2 = s.c_str();
+ compare_paths(p0, p2);
+
+#if _GLIBCXX_USE_WCHAR_T
+ std::wstring ws(s.begin(), s.end());
+
+ p3 = ws;
+ compare_paths(p0, p3);
+
+ p4 = ws.c_str();
+ compare_paths(p0, p4);
+#endif
+ }
+}
+
+void
+test02()
+{
+ for (std::string s : __gnu_test::test_paths)
+ {
+ path p0 = s, p1, p2, p3, p4, p5, p6, p7, p8;
+
+ p1.assign(s);
+ compare_paths(p0, p1);
+
+ p2.assign( s.begin(), s.end() );
+ compare_paths(p0, p2);
+
+ p3.assign( s.c_str() );
+ compare_paths(p0, p3);
+
+ p4.assign( s.c_str(), s.c_str() + s.size() );
+ compare_paths(p0, p4);
+
+#if _GLIBCXX_USE_WCHAR_T
+ std::wstring ws(s.begin(), s.end());
+
+ p5.assign(ws);
+ compare_paths(p0, p5);
+
+ p6.assign( ws.begin(), ws.end() );
+ compare_paths(p0, p6);
+
+ p7.assign( ws.c_str() );
+ compare_paths(p0, p7);
+
+ p8.assign( ws.c_str(), ws.c_str() + ws.size() );
+ compare_paths(p0, p8);
+#endif
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc
new file mode 100644
index 0000000..27bf00a
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/assign/copy.cc
@@ -0,0 +1,56 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+#include <filesystem>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path copy;
+ copy = p;
+ __gnu_test::compare_paths(p, copy);
+ }
+}
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path copy = p;
+ path move;
+ move = std::move(copy);
+ __gnu_test::compare_paths(p, move);
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc
new file mode 100644
index 0000000..e444220
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/compare.cc
@@ -0,0 +1,51 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.8 path compare [path.compare]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p("/foo/bar");
+ VERIFY( p.compare(p) == 0 );
+ VERIFY( p.compare("/foo//bar") == 0 );
+
+ path q("/foo/baz");
+ VERIFY( p.compare(q) < 0 );
+ VERIFY( q.compare(p) > 0 );
+
+ path r("/foo/bar/.");
+ VERIFY( p.compare(r) < 0 );
+
+ VERIFY( path("a/b/").compare("a/b//") == 0 );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc
new file mode 100644
index 0000000..4bed5a2
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/path.cc
@@ -0,0 +1,51 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.8 path compare [path.compare]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ const path p0 = "/a/a/b/b";
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.compare(p) == 0 );
+ int cmp = p.compare(p0);
+ if (cmp == 0)
+ VERIFY( p0.compare(p) == 0 );
+ else if (cmp < 0)
+ VERIFY( p0.compare(p) > 0 );
+ else if (cmp > 0)
+ VERIFY( p0.compare(p) < 0 );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc
new file mode 100644
index 0000000..be8f8b0
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/compare/strings.cc
@@ -0,0 +1,49 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.8 path compare [path.compare]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ const std::string s0 = "/a/a/b/b";
+ const path p0 = s0;
+ for (const std::string& s : __gnu_test::test_paths)
+ {
+ path p(s);
+ VERIFY( p.compare(s) == 0 );
+ VERIFY( p.compare(s.c_str()) == 0 );
+ VERIFY( p.compare(p0) == p.compare(s0) );
+ VERIFY( p.compare(p0) == p.compare(s0.c_str()) );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc
new file mode 100644
index 0000000..46cf09a
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/path.cc
@@ -0,0 +1,69 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.4 path concatenation [path.concat]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ const path p("/foo/bar");
+
+ path pp = p;
+ pp += p;
+ VERIFY( pp.native() == "/foo/bar/foo/bar" );
+ VERIFY( std::distance(pp.begin(), pp.end()) == 5 );
+
+ path q("foo/bar");
+
+ path qq = q;
+ qq += q;
+ VERIFY( qq.native() == "foo/barfoo/bar" );
+ VERIFY( std::distance(qq.begin(), qq.end()) == 3 );
+
+ q += p;
+ VERIFY( q.native() == "foo/bar/foo/bar" );
+ VERIFY( std::distance(q.begin(), q.end()) == 4 );
+}
+
+void
+test02()
+{
+ for (path p : __gnu_test::test_paths)
+ {
+ auto prior_native = p.native();
+ path x("//blah/di/blah");
+ p += x;
+ VERIFY( p.native() == prior_native + x.native() );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc
new file mode 100644
index 0000000..3eb4d1a
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/concat/strings.cc
@@ -0,0 +1,56 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.4 path concatenation [path.concat]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p("/");
+ p += path::string_type("foo");
+ VERIFY( p.filename() == "foo" );
+ p += "bar";
+ VERIFY( p.filename() == "foobar" );
+ p += '/';
+ VERIFY( p.parent_path() == "/foobar" && p.filename() == "" );
+#if _GLIBCXX_USE_WCHAR_T
+ p += L"baz.txt";
+#else
+ p += "baz.txt";
+#endif
+ VERIFY( p.filename() == "baz.txt" );
+ p.concat("/dir/");
+ VERIFY( p.parent_path() == "/foobar/baz.txt/dir" && p.filename() == "" );
+ std::string file = "file";
+ p.concat(file.begin(), file.end());
+ VERIFY( p.filename() == "file" );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc
new file mode 100644
index 0000000..cb084bd
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/copy.cc
@@ -0,0 +1,55 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path copy = p;
+ __gnu_test::compare_paths(p, copy);
+ }
+}
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path copy = p;
+ path move = std::move(copy);
+ __gnu_test::compare_paths(p, move);
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc
new file mode 100644
index 0000000..85ce129
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/default.cc
@@ -0,0 +1,51 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p;
+ VERIFY( p.empty() );
+ VERIFY( !p.has_root_path() );
+ VERIFY( !p.has_root_name() );
+ VERIFY( !p.has_root_directory() );
+ VERIFY( !p.has_relative_path() );
+ VERIFY( !p.has_parent_path() );
+ VERIFY( !p.has_filename() );
+ VERIFY( !p.has_stem() );
+ VERIFY( !p.has_extension() );
+ VERIFY( !p.is_absolute() );
+ VERIFY( p.is_relative() );
+ VERIFY( std::distance(p.begin(), p.end()) == 0 );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc
new file mode 100644
index 0000000..e313412
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/locale.cc
@@ -0,0 +1,40 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p("/foo/bar", std::locale::classic());
+ VERIFY( p.string() == "/foo/bar" );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc
new file mode 100644
index 0000000..ad2cc18
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/range.cc
@@ -0,0 +1,112 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <string>
+#include <testsuite_fs.h>
+#include <testsuite_iterators.h>
+
+using std::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+ for (std::string s : __gnu_test::test_paths)
+ {
+ path p1 = s;
+ path p2( s.begin(), s.end() );
+ path p3( s.c_str() );
+ path p4( s.c_str(), s.c_str() + s.size() );
+
+ compare_paths(p1, p2);
+ compare_paths(p1, p3);
+ compare_paths(p1, p4);
+
+#if _GLIBCXX_USE_WCHAR_T
+ std::wstring ws(s.begin(), s.end());
+ path p5 = ws;
+ path p6( ws.begin(), ws.end() );
+ path p7( ws.c_str() );
+ path p8( ws.c_str(), ws.c_str() + ws.size() );
+
+ compare_paths(p1, p5);
+ compare_paths(p1, p6);
+ compare_paths(p1, p7);
+ compare_paths(p1, p8);
+#endif
+
+ using __gnu_test::test_container;
+ using __gnu_test::input_iterator_wrapper;
+ // Test with input iterators and const value_types
+
+ test_container<char, input_iterator_wrapper>
+ r1((char*)s.c_str(), (char*)s.c_str() + s.size());
+ path p9(r1.begin(), r1.end());
+ compare_paths(p1, p9);
+
+ test_container<char, input_iterator_wrapper>
+ r2((char*)s.c_str(), (char*)s.c_str() + s.size() + 1); // includes null-terminator
+ path p10(r2.begin());
+ compare_paths(p1, p10);
+
+ test_container<const char, input_iterator_wrapper>
+ r3(s.c_str(), s.c_str() + s.size());
+ path p11(r3.begin(), r3.end());
+ compare_paths(p1, p11);
+
+ test_container<const char, input_iterator_wrapper>
+ r4(s.c_str(), s.c_str() + s.size() + 1); // includes null-terminator
+ path p12(r4.begin());
+ compare_paths(p1, p12);
+
+#if _GLIBCXX_USE_WCHAR_T
+ // Test with input iterators and const value_types
+ test_container<wchar_t, input_iterator_wrapper>
+ r5((wchar_t*)ws.c_str(), (wchar_t*)ws.c_str() + ws.size());
+ path p13(r5.begin(), r5.end());
+ compare_paths(p1, p13);
+
+ test_container<wchar_t, input_iterator_wrapper>
+ r6((wchar_t*)ws.c_str(), (wchar_t*)ws.c_str() + ws.size() + 1); // includes null-terminator
+ path p14(r6.begin());
+ compare_paths(p1, p14);
+
+ test_container<const wchar_t, input_iterator_wrapper>
+ r7(ws.c_str(), ws.c_str() + ws.size());
+ path p15(r7.begin(), r7.end());
+ compare_paths(p1, p15);
+
+ test_container<const wchar_t, input_iterator_wrapper>
+ r8(ws.c_str(), ws.c_str() + ws.size() + 1); // includes null-terminator
+ path p16(r8.begin());
+ compare_paths(p1, p16);
+#endif
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc
new file mode 100644
index 0000000..b9a5205
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/construct/string_view.cc
@@ -0,0 +1,56 @@
+// { dg-options "-lstdc++fs -std=gnu++17" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.1 path constructors [path.construct]
+
+#include <filesystem>
+#include <string_view>
+#include <string>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+using __gnu_test::compare_paths;
+
+void
+test01()
+{
+ for (std::string s : __gnu_test::test_paths)
+ {
+ path p1 = s;
+ std::string_view sv(s);
+ path p2 = sv;
+ compare_paths(p1, p2);
+
+#if _GLIBCXX_USE_WCHAR_T
+ std::wstring ws(s.begin(), s.end());
+ path p3 = ws;
+ std::wstring_view wsv(ws);
+ path p4 = wsv;
+ compare_paths(p1, p4);
+#endif
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc
new file mode 100644
index 0000000..13c9db2
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/extension.cc
@@ -0,0 +1,70 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ VERIFY( path("/foo/bar.txt").extension() == path(".txt") );
+ VERIFY( path("/foo/bar.baz.txt").extension() == path(".txt") );
+ VERIFY( path(".bar.baz.txt").extension() == path(".txt") );
+
+ VERIFY( path(".profile").extension() == path("") );
+ VERIFY( path(".profile.old").extension() == path(".old") );
+ VERIFY( path("..abc").extension() == path(".abc") );
+ VERIFY( path("...abc").extension() == path(".abc") );
+ VERIFY( path("abc..def").extension() == path(".def") );
+ VERIFY( path("abc...def").extension() == path(".def") );
+ VERIFY( path("abc.").extension() == path(".") );
+ VERIFY( path("abc..").extension() == path(".") );
+ VERIFY( path("abc.d.").extension() == path(".") );
+ VERIFY( path("..").extension() == path("") );
+ VERIFY( path(".").extension() == path("") );
+
+ VERIFY( path().extension() == path() );
+}
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ auto stem = p.stem();
+ auto ext = p.extension();
+ auto file = p.filename();
+ VERIFY( stem.native() + ext.native() == file.native() );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc
new file mode 100644
index 0000000..8ba0fcc
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/filename.cc
@@ -0,0 +1,70 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// C++17 30.10.7.4.9 path decomposition [fs.path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ VERIFY( path("/foo/bar.txt").filename() == "bar.txt" );
+ VERIFY( path("/foo/bar").filename() == "bar" );
+ VERIFY( path("/foo/bar/").filename() == "" );
+ VERIFY( path("/").filename() == "" );
+#ifdef __CYGWIN__
+ VERIFY( path("//host").filename() == "" );
+#else
+ VERIFY( path("//host").filename() == "host" );
+#endif
+ VERIFY( path(".").filename() == "." );
+ VERIFY( path("..").filename() == ".." );
+}
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path f = p.filename();
+ if (p.empty())
+ VERIFY( f.empty() );
+ else
+ {
+ const path back = *--p.end();
+ if (back.has_root_path())
+ VERIFY( f.empty() );
+ else
+ VERIFY( f == back );
+ }
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc
new file mode 100644
index 0000000..c46566d
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/parent_path.cc
@@ -0,0 +1,73 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p0;
+ VERIFY( p0.parent_path() == p0 );
+ path p1 = "foo";
+ VERIFY( p1.parent_path() == p0 );
+ path p2 = "foo/bar";
+ VERIFY( p2.parent_path() == p1 );
+ path p3 = "/foo/bar";
+ VERIFY( p3.parent_path() == path("/foo") );
+ VERIFY( p3.parent_path().parent_path() == path("/") );
+ VERIFY( p3.parent_path().parent_path().parent_path() == path("/") );
+ path p4 = "/";
+ VERIFY( p4.parent_path() == p4 );
+}
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ if (p.begin() == p.end())
+ continue;
+ if (p.has_relative_path())
+ {
+ path pp;
+ for (auto i = p.begin(), end = --p.end(); i != end; ++i)
+ {
+ pp /= *i;
+ }
+ VERIFY( p.parent_path() == pp );
+ }
+ else
+ VERIFY( p.parent_path() == p );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc
new file mode 100644
index 0000000..c864972
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/relative_path.cc
@@ -0,0 +1,70 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p1 = "foo";
+ VERIFY( p1.relative_path() == p1 );
+ path p2 = "foo/bar";
+ VERIFY( p2.relative_path() == p2 );
+ path p3 = "/foo/bar";
+ VERIFY( p3.relative_path() == p2 );
+}
+
+#include <iostream> // XXX
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ bool after_root = false;
+ const path prel = p.relative_path();
+ VERIFY( !prel.has_root_name() );
+ path rel;
+ for (const auto& cmpt : p)
+ {
+ if (!cmpt.has_root_path())
+ after_root = true;
+ if (after_root)
+ rel /= cmpt;
+ }
+ if (prel != rel)
+ std::cout << prel << ' ' << rel << '\n';
+ VERIFY( prel == rel );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc
new file mode 100644
index 0000000..8220c58
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_directory.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p1 = "foo/bar";
+ VERIFY( p1.root_directory() == path() );
+ path p2 = "/foo/bar";
+ VERIFY( p2.root_directory() == path("/") );
+ path p3 = "//foo";
+ VERIFY( p3.root_directory() == path("/") );
+ path p4 = "///foo";
+ VERIFY( p4.root_directory() == path("/") );
+}
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path rootdir = p.root_directory();
+ VERIFY( !rootdir.has_relative_path() );
+ VERIFY( rootdir.empty() || rootdir.native() == "/");
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc
new file mode 100644
index 0000000..5bb2ccd
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_name.cc
@@ -0,0 +1,43 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ VERIFY( path("/foo/bar.txt").extension() == ".txt" );
+ VERIFY( path("/foo/bar.baz.txt").extension() == ".txt" );
+ VERIFY( path(".").extension().empty() );
+ VERIFY( path("..").extension().empty() );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc
new file mode 100644
index 0000000..bce0134
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/root_path.cc
@@ -0,0 +1,61 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// C++17 30.10.7.4.9 path decomposition [fs.path.decompose]
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p1 = "foo/bar";
+ VERIFY( p1.root_path() == path() );
+ path p2 = "/foo/bar";
+ VERIFY( p2.root_path() == path("/") );
+}
+
+#undef VERIFY
+#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false)
+#define DUMP(X, Y, Z) do { if (!(Y == Z)) { __builtin_printf("%s %s %s\n", X.c_str(), Y.c_str(), Z.c_str()); } } while(false)
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path rootp = p.root_path();
+ path rootn = p.root_name();
+ path rootd = p.root_directory();
+ VERIFY( rootp == (rootn / rootd) );
+ DUMP(p, rootp , (rootn / rootd) );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc
new file mode 100644
index 0000000..aec64e1
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/decompose/stem.cc
@@ -0,0 +1,62 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ VERIFY( path("/foo/bar.txt").stem() == path("bar") );
+ path p = "foo.bar.baz.tar";
+ std::vector<std::string> v;
+ for (; !p.extension().empty(); p = p.stem())
+ v.push_back(p.extension().native());
+ VERIFY( v.at(0) == ".tar" );
+ VERIFY( v.at(1) == ".baz" );
+ VERIFY( v.at(2) == ".bar" );
+
+ VERIFY( path(".profile").stem() == path(".profile") );
+ VERIFY( path(".profile.old").stem() == path(".profile") );
+ VERIFY( path("..abc").stem() == path(".") );
+ VERIFY( path("...abc").stem() == path("..") );
+ VERIFY( path("abc..def").stem() == path("abc.") );
+ VERIFY( path("abc...def").stem() == path("abc..") );
+ VERIFY( path("abc.").stem() == path("abc") );
+ VERIFY( path("abc..").stem() == path("abc.") );
+ VERIFY( path("abc.d.").stem() == path("abc.d") );
+ VERIFY( path("..").stem() == path("..") );
+ VERIFY( path(".").stem() == path(".") );
+
+ VERIFY( path().stem() == path() );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc
new file mode 100644
index 0000000..2e4ec5b
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/normal.cc
@@ -0,0 +1,52 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ // C++17 [fs.path.gen] p2
+ VERIFY( path("foo/./bar/..").lexically_normal() == "foo/" );
+ VERIFY( path("foo/.///bar/../").lexically_normal() == "foo/" );
+}
+
+void
+test02()
+{
+ VERIFY( path("foo/../bar").lexically_normal() == "bar" );
+ VERIFY( path("../foo/../bar").lexically_normal() == "../bar" );
+ VERIFY( path("foo/../").lexically_normal() == "." );
+ VERIFY( path("../../").lexically_normal() == "../.." );
+ VERIFY( path("../").lexically_normal() == ".." );
+ VERIFY( path("./").lexically_normal() == "." );
+ VERIFY( path().lexically_normal() == "" );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc
new file mode 100644
index 0000000..7a25f7b
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/proximate.cc
@@ -0,0 +1,53 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ // C++17 [fs.path.gen] p5
+ VERIFY( path("/a/d").lexically_proximate("/a/b/c") == "../../d" );
+ VERIFY( path("/a/b/c").lexically_proximate("/a/d") == "../b/c" );
+ VERIFY( path("a/b/c").lexically_proximate("a") == "b/c" );
+ VERIFY( path("a/b/c").lexically_proximate("a/b/c/x/y") == "../.." );
+ VERIFY( path("a/b/c").lexically_proximate("a/b/c") == "." );
+ VERIFY( path("a/b").lexically_proximate("c/d") == "../../a/b" );
+}
+
+void
+test02()
+{
+ path p = "a/b/c";
+ VERIFY( p.lexically_proximate(p) == "." );
+ VERIFY( p.lexically_proximate("a/../a/b/../b/c/../c/.") == "../../b/c" );
+ VERIFY( p.lexically_proximate("../../../") == p );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc
new file mode 100644
index 0000000..64770fb
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generation/relative.cc
@@ -0,0 +1,53 @@
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ // C++17 [fs.path.gen] p5
+ VERIFY( path("/a/d").lexically_relative("/a/b/c") == "../../d" );
+ VERIFY( path("/a/b/c").lexically_relative("/a/d") == "../b/c" );
+ VERIFY( path("a/b/c").lexically_relative("a") == "b/c" );
+ VERIFY( path("a/b/c").lexically_relative("a/b/c/x/y") == "../.." );
+ VERIFY( path("a/b/c").lexically_relative("a/b/c") == "." );
+ VERIFY( path("a/b").lexically_relative("c/d") == "../../a/b" );
+}
+
+void
+test02()
+{
+ path p = "a/b/c";
+ VERIFY( p.lexically_relative(p) == "." );
+ VERIFY( p.lexically_relative("a/../a/b/../b/c/../c/.") == "../../b/c" );
+ VERIFY( p.lexically_relative("../../../") == "" );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc
new file mode 100644
index 0000000..d25d505
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/generic/generic_string.cc
@@ -0,0 +1,55 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// C++17 30.10.7.4.7 path generic format observers [fs.path.generic.obs]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ VERIFY( path().generic_string() == "" );
+ VERIFY( path("/").generic_string() == "/" );
+ VERIFY( path("////").generic_string() == "/" );
+#ifdef __CYGWIN__
+ VERIFY( path("//a").generic_string() == "//a" );
+ VERIFY( path("//a/").generic_string() == "//a/" );
+ VERIFY( path("//a/b").generic_string() == "//a/b" );
+#else
+ VERIFY( path("//a").generic_string() == "/a" );
+ VERIFY( path("//a/").generic_string() == "/a/" );
+ VERIFY( path("//a/b").generic_string() == "/a/b" );
+#endif
+ VERIFY( path("/a//b").generic_string() == "/a/b" );
+ VERIFY( path("/a//b/").generic_string() == "/a/b/" );
+ VERIFY( path("/a//b//").generic_string() == "/a/b/" );
+ VERIFY( path("/a//b//.").generic_string() == "/a/b/." );
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
new file mode 100644
index 0000000..7754140
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/itr/traversal.cc
@@ -0,0 +1,127 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// C++17 30.10.7.5 path iterators [fs.path.itr]
+
+#include <filesystem>
+#include <vector>
+#include <algorithm>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ path p;
+ VERIFY( p.begin() == p.end() );
+
+ std::vector<path> v, v2;
+
+ p = "/";
+ v.assign(p.begin(), p.end());
+ v2 = { "/" };
+ VERIFY( v == v2 );
+
+ p = "filename";
+ v.assign(p.begin(), p.end());
+ v2 = { "filename" };
+ VERIFY( v == v2 );
+
+ p = "dir/.";
+ v.assign(p.begin(), p.end());
+ v2 = { "dir", "." };
+ VERIFY( v == v2 );
+
+ p = "dir/";
+ v.assign(p.begin(), p.end());
+ v2 = { "dir", "" };
+ VERIFY( v == v2 );
+
+ p = "//rootname/dir/.";
+ v.assign(p.begin(), p.end());
+#ifdef __CYGWIN__
+ v2 = { "//rootname", "/", "dir", "." };
+#else
+ v2 = { "/", "rootname", "dir", "." };
+#endif
+ VERIFY( v == v2 );
+
+ p = "//rootname/dir/";
+ v.assign(p.begin(), p.end());
+#ifdef __CYGWIN__
+ v2 = { "//rootname", "/", "dir", "" };
+#else
+ v2 = { "/", "rootname", "dir", "" };
+#endif
+ VERIFY( v == v2 );
+
+ p = "//rootname/dir/filename";
+ v.assign(p.begin(), p.end());
+#ifdef __CYGWIN__
+ v2 = { "//rootname", "/", "dir", "filename" };
+#else
+ v2 = { "/", "rootname", "dir", "filename" };
+#endif
+ VERIFY( v == v2 );
+}
+
+void
+test02()
+{
+ using reverse_iterator = std::reverse_iterator<path::iterator>;
+ std::vector<path> fwd, rev;
+
+ for (const path& p : __gnu_test::test_paths)
+ {
+ const auto begin = p.begin(), end = p.end();
+ fwd.assign(begin, end);
+ rev.assign(reverse_iterator(end), reverse_iterator(begin));
+ VERIFY( fwd.size() == rev.size() );
+ VERIFY( std::equal(fwd.begin(), fwd.end(), rev.rbegin()) );
+ }
+}
+
+void
+test03()
+{
+ path paths[] = { "single", "multiple/elements" };
+ for (const path& p : paths)
+ for (auto iter = p.begin(); iter != p.end(); ++iter)
+ {
+ auto iter2 = iter;
+ ++iter;
+ iter2++;
+ VERIFY( iter2 == iter );
+ --iter;
+ iter2--;
+ VERIFY( iter2 == iter );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+ test03();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc
new file mode 100644
index 0000000..31d984f
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/clear.cc
@@ -0,0 +1,46 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.5 path modifiers [path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (path p : __gnu_test::test_paths)
+ {
+ path empty;
+ p.clear();
+ VERIFY( p.empty() );
+ __gnu_test::compare_paths(p, empty);
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc
new file mode 100644
index 0000000..1df1009
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/make_preferred.cc
@@ -0,0 +1,64 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.5 path modifiers [path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+template<typename T, T sep>
+struct checker
+{
+ static void check(const char* s) { }
+};
+
+template<>
+struct checker<char, '/'>
+{
+ static void check()
+ {
+ VERIFY( path("foo/bar").make_preferred() == "foo/bar" );
+ }
+};
+
+template<>
+struct checker<wchar_t, L'\\'>
+{
+ static void check()
+ {
+ VERIFY( path("foo/bar").make_preferred() == L"foo\\bar" );
+ }
+};
+
+void
+test01()
+{
+ checker<path::value_type, path::preferred_separator>::check();
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc
new file mode 100644
index 0000000..02e1b05
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/remove_filename.cc
@@ -0,0 +1,62 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// C++17 30.10.7.4.5 path modifiers [fs.path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ // C++17 [fs.path.modifiers] p8
+ VERIFY( path("foo/bar").remove_filename() == "foo/" );
+ VERIFY( path("foo/").remove_filename() == "foo/" );
+ VERIFY( path("/foo").remove_filename() == "/" );
+ VERIFY( path("/").remove_filename() == "/" );
+}
+
+#undef VERIFY
+#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false)
+#define DUMP(X, Y) do { if (!(X == Y)) { __builtin_printf("%s %s\n", X.c_str(), Y.c_str()); } } while(false)
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path p2(p);
+ p2.remove_filename();
+ p2 /= p.filename();
+ VERIFY( p2 == p );
+ DUMP( p2 , p );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc
new file mode 100644
index 0000000..cf7ca09
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_extension.cc
@@ -0,0 +1,53 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.5 path modifiers [path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ VERIFY( path("/foo.txt").replace_extension("cpp") == "/foo.cpp" );
+ VERIFY( path("/foo.txt").replace_extension(".cpp") == "/foo.cpp" );
+ VERIFY( path("/").replace_extension("bar") == "/.bar" );
+}
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path p2 = p;
+ VERIFY(p2.replace_extension(p2.extension()) == p);
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc
new file mode 100644
index 0000000..6d3b9b7
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/replace_filename.cc
@@ -0,0 +1,59 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// C++17 30.10.7.4.5 path modifiers [fs.path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ // C++17 [fs.path.modifiers] p11
+ VERIFY( path("/foo").replace_filename("bar") == "/bar" );
+ VERIFY( path("/").replace_filename("bar") == "/bar" );
+}
+
+#undef VERIFY
+#define VERIFY(X) do { if (!(X)) { __builtin_puts("FAIL: " #X); } } while(false)
+#define DUMP(X, Y) do { if (!(X == Y)) { __builtin_printf("%s %s\n", X.c_str(), Y.c_str()); } } while(false)
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path p2(p);
+ p2.replace_filename(p.filename());
+ VERIFY( p2 == p );
+ DUMP( p2 , p );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc
new file mode 100644
index 0000000..f127604
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/modifiers/swap.cc
@@ -0,0 +1,45 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.5 path modifiers [path.modifiers]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ const path p("/foo/bar");
+ path p1;
+ path p2 = p;
+ p1.swap(p2);
+ VERIFY( p2.empty() );
+ __gnu_test::compare_paths(p1, p);
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc
new file mode 100644
index 0000000..23d7970
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/native/string.cc
@@ -0,0 +1,70 @@
+// Copyright (C) 2016-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+#include <filesystem>
+#include <string>
+#include <testsuite_hooks.h>
+
+void
+test01()
+{
+ using namespace std::filesystem;
+ const std::string s = "abc";
+ path p(s);
+
+ VERIFY( p.native() == s );
+ VERIFY( p.c_str() == s );
+ VERIFY( static_cast<std::string>(p) == s );
+
+ std::string s2 = p; // implicit conversion
+ VERIFY( s2 == p.native() );
+}
+
+void
+test02()
+{
+ using namespace std::filesystem;
+ const char* s = "abc";
+ path p(s);
+
+ auto str = p.string<char>();
+ VERIFY( str == u"abc" );
+ VERIFY( str == p.string() );
+
+ auto strw = p.string<wchar_t>();
+ VERIFY( strw == L"abc" );
+ VERIFY( strw == p.wstring() );
+
+ auto str16 = p.string<char16_t>();
+ VERIFY( str16 == u"abc" );
+ VERIFY( str16 == p.u16string() );
+
+ auto str32 = p.string<char32_t>();
+ VERIFY( str32 == U"abc" );
+ VERIFY( str32 == p.u32string() );
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc
new file mode 100644
index 0000000..20f42ac
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/nonmember/hash_value.cc
@@ -0,0 +1,52 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.6 path non-member functions [path.non-member]
+
+#include <filesystem>
+#include <testsuite_fs.h>
+#include <testsuite_hooks.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ VERIFY( hash_value(path("a//b")) == hash_value(path("a/b")) );
+ VERIFY( hash_value(path("a/")) == hash_value(path("a//")) );
+}
+
+void
+test02()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ path pp = p.native();
+ VERIFY( hash_value(p) == hash_value(pp) );
+ }
+}
+
+int
+main()
+{
+ test01();
+ test02();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc
new file mode 100644
index 0000000..76277a0
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/empty.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const std::string& s : __gnu_test::test_paths)
+ {
+ VERIFY( s.empty() == path(s).empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc
new file mode 100644
index 0000000..693bd38
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_extension.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.has_extension() == !p.extension().empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc
new file mode 100644
index 0000000..ce99af3
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_filename.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.has_filename() == !p.filename().empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc
new file mode 100644
index 0000000..4e23b24
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_parent_path.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.has_parent_path() == !p.parent_path().empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc
new file mode 100644
index 0000000..25e2dd5
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_relative_path.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.has_relative_path() == !p.relative_path().empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc
new file mode 100644
index 0000000..66c8df2
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_directory.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.has_root_directory() == !p.root_directory().empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc
new file mode 100644
index 0000000..f9d7157
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_name.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.has_root_name() == !p.root_name().empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc
new file mode 100644
index 0000000..f0bdb81
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_root_path.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.has_root_path() == !p.root_path().empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc
new file mode 100644
index 0000000..18bf015
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/has_stem.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.has_stem() == !p.stem().empty() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc b/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc
new file mode 100644
index 0000000..c6f6c7f
--- /dev/null
+++ b/libstdc++-v3/testsuite/27_io/filesystem/path/query/is_relative.cc
@@ -0,0 +1,44 @@
+// { dg-options "-std=gnu++17 -lstdc++fs" }
+// { dg-do run { target c++17 } }
+// { dg-require-filesystem-ts "" }
+
+// Copyright (C) 2014-2017 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can 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.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// 8.4.9 path decomposition [path.decompose]
+
+#include <filesystem>
+#include <vector>
+#include <testsuite_hooks.h>
+#include <testsuite_fs.h>
+
+using std::filesystem::path;
+
+void
+test01()
+{
+ for (const path& p : __gnu_test::test_paths)
+ {
+ VERIFY( p.is_relative() == !p.is_absolute() );
+ }
+}
+
+int
+main()
+{
+ test01();
+}
diff --git a/libstdc++-v3/testsuite/decimal/conversion-to-integral.cc b/libstdc++-v3/testsuite/decimal/conversion-to-integral.cc
index 6fd59a6..cc48fa8 100644
--- a/libstdc++-v3/testsuite/decimal/conversion-to-integral.cc
+++ b/libstdc++-v3/testsuite/decimal/conversion-to-integral.cc
@@ -64,7 +64,7 @@ void
conversion_to_integral_128 (void)
{
#undef MAXVAL
- #define MAXVAL LONG_LONG_MAX
+ #define MAXVAL __LONG_LONG_MAX__
decimal128 a, b (1), c (-1), d (MAXVAL), e (-MAXVAL);
long long ll;
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc b/libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc
index e7b5e53..50cc7d4 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/iterators/recursive_directory_iterator.cc
@@ -28,6 +28,7 @@ namespace fs = std::experimental::filesystem;
void
test01()
{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
std::error_code ec;
// Test non-existent path.
@@ -37,15 +38,19 @@ test01()
VERIFY( iter == end(iter) );
// Test empty directory.
+ ec = bad_ec;
create_directory(p, fs::current_path(), ec);
VERIFY( !ec );
+ ec = bad_ec;
iter = fs::recursive_directory_iterator(p, ec);
VERIFY( !ec );
VERIFY( iter == end(iter) );
// Test non-empty directory.
- create_directories(p / "d1/d2");
+ ec = bad_ec;
+ create_directories(p / "d1/d2", ec);
VERIFY( !ec );
+ ec = bad_ec;
iter = fs::recursive_directory_iterator(p, ec);
VERIFY( !ec );
VERIFY( iter != end(iter) );
@@ -56,6 +61,7 @@ test01()
VERIFY( iter == end(iter) );
// Test inaccessible directory.
+ ec = bad_ec;
permissions(p, fs::perms::none, ec);
VERIFY( !ec );
iter = fs::recursive_directory_iterator(p, ec);
@@ -64,15 +70,19 @@ test01()
// Test inaccessible directory, skipping permission denied.
const auto opts = fs::directory_options::skip_permission_denied;
+ ec = bad_ec;
iter = fs::recursive_directory_iterator(p, opts, ec);
VERIFY( !ec );
VERIFY( iter == end(iter) );
// Test inaccessible sub-directory.
+ ec = bad_ec;
permissions(p, fs::perms::owner_all, ec);
VERIFY( !ec );
+ ec = bad_ec;
permissions(p/"d1/d2", fs::perms::none, ec);
VERIFY( !ec );
+ ec = bad_ec;
iter = fs::recursive_directory_iterator(p, ec);
VERIFY( !ec );
VERIFY( iter != end(iter) );
@@ -84,12 +94,14 @@ test01()
VERIFY( iter == end(iter) );
// Test inaccessible sub-directory, skipping permission denied.
+ ec = bad_ec;
iter = fs::recursive_directory_iterator(p, opts, ec);
VERIFY( !ec );
VERIFY( iter != end(iter) );
VERIFY( iter->path() == p/"d1" );
++iter; // should recurse into d1
VERIFY( iter->path() == p/"d1/d2" );
+ ec = bad_ec;
iter.increment(ec); // should fail to recurse into p/d1/d2, so skip it
VERIFY( !ec );
VERIFY( iter == end(iter) );
@@ -101,12 +113,15 @@ test01()
void
test02()
{
+ const std::error_code bad_ec = make_error_code(std::errc::invalid_argument);
std::error_code ec;
const auto p = __gnu_test::nonexistent_path();
+ ec = bad_ec;
create_directories(p / "d1/d2", ec);
VERIFY( !ec );
// Test post-increment (libstdc++/71005)
+ ec = bad_ec;
auto iter = fs::recursive_directory_iterator(p, ec);
VERIFY( !ec );
VERIFY( iter != end(iter) );
@@ -126,7 +141,7 @@ test02()
void
test03()
{
- std::error_code ec;
+ std::error_code ec = make_error_code(std::errc::invalid_argument);
const auto p = __gnu_test::nonexistent_path();
create_directories(p / "longer_than_small_string_buffer", ec);
VERIFY( !ec );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directory.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directory.cc
index f1c50a6..85e8281 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directory.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/create_directory.cc
@@ -50,7 +50,6 @@ test01()
VERIFY( !ec );
VERIFY( !b );
b = create_directory(p);
- VERIFY( !ec );
VERIFY( !b );
remove_all(p, ec);
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc b/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc
index e8a6dd3..1689a2a 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/operations/temp_directory_path.cc
@@ -43,7 +43,7 @@ test01()
if (!fs::exists("/tmp"))
return; // just give up
- std::error_code ec;
+ std::error_code ec = make_error_code(std::errc::invalid_argument);
fs::path p1 = fs::temp_directory_path(ec);
VERIFY( !ec );
VERIFY( exists(p1) );
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc
index fbf8bd4..6879909 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/construct/string_view.cc
@@ -24,6 +24,7 @@
#include <experimental/filesystem>
#include <string_view>
#include <string>
+#define USE_FILESYSTEM_TS
#include <testsuite_fs.h>
using std::experimental::filesystem::path;
diff --git a/libstdc++-v3/testsuite/experimental/filesystem/path/itr/traversal.cc b/libstdc++-v3/testsuite/experimental/filesystem/path/itr/traversal.cc
index bc10914..41a292a 100644
--- a/libstdc++-v3/testsuite/experimental/filesystem/path/itr/traversal.cc
+++ b/libstdc++-v3/testsuite/experimental/filesystem/path/itr/traversal.cc
@@ -79,9 +79,27 @@ test02()
}
}
+void
+test03()
+{
+ path paths[] = { "single", "multiple/elements" };
+ for (const path& p : paths)
+ for (auto iter = p.begin(); iter != p.end(); ++iter)
+ {
+ auto iter2 = iter;
+ ++iter;
+ iter2++;
+ VERIFY( iter2 == iter );
+ --iter;
+ iter2--;
+ VERIFY( iter2 == iter );
+ }
+}
+
int
main()
{
test01();
test02();
+ test03();
}
diff --git a/libstdc++-v3/testsuite/util/testsuite_fs.h b/libstdc++-v3/testsuite/util/testsuite_fs.h
index 38ebd4f..e0db46c 100644
--- a/libstdc++-v3/testsuite/util/testsuite_fs.h
+++ b/libstdc++-v3/testsuite/util/testsuite_fs.h
@@ -22,7 +22,14 @@
#ifndef _TESTSUITE_FS_H
#define _TESTSUITE_FS_H 1
+// Assume we want std::filesystem in C++17, unless USE_FILESYSTEM_TS defined:
+#if __cplusplus >= 201703L && ! defined USE_FILESYSTEM_TS
+#include <filesystem>
+namespace test_fs = std::filesystem;
+#else
#include <experimental/filesystem>
+namespace test_fs = std::experimental::filesystem;
+#endif
#include <fstream>
#include <string>
#include <cstdio>
@@ -33,12 +40,12 @@ namespace __gnu_test
{
#define PATH_CHK(p1, p2, fn) \
if ( p1.fn() != p2.fn() ) \
- throw std::experimental::filesystem::filesystem_error( #fn, p1, p2, \
+ throw test_fs::filesystem_error( #fn, p1, p2, \
std::make_error_code(std::errc::invalid_argument) )
void
- compare_paths(const std::experimental::filesystem::path& p1,
- const std::experimental::filesystem::path& p2)
+ compare_paths(const test_fs::path& p1,
+ const test_fs::path& p2)
{
PATH_CHK( p1, p2, string );
PATH_CHK( p1, p2, empty );
@@ -55,7 +62,7 @@ namespace __gnu_test
auto d1 = std::distance(p1.begin(), p1.end());
auto d2 = std::distance(p2.begin(), p2.end());
if( d1 != d2 )
- throw std::experimental::filesystem::filesystem_error(
+ throw test_fs::filesystem_error(
"distance(begin, end)", p1, p2,
std::make_error_code(std::errc::invalid_argument) );
}
@@ -67,15 +74,15 @@ namespace __gnu_test
// This is NOT supposed to be a secure way to get a unique name!
// We just need a path that doesn't exist for testing purposes.
- std::experimental::filesystem::path
+ test_fs::path
nonexistent_path()
{
- std::experimental::filesystem::path p;
+ test_fs::path p;
#if defined(_GNU_SOURCE) || _XOPEN_SOURCE >= 500 || _POSIX_C_SOURCE >= 200112L
- char tmp[] = "filesystem-ts-test.XXXXXX";
+ char tmp[] = "filesystem-test.XXXXXX";
int fd = ::mkstemp(tmp);
if (fd == -1)
- throw std::experimental::filesystem::filesystem_error("mkstemp failed",
+ throw test_fs::filesystem_error("mkstemp failed",
std::error_code(errno, std::generic_category()));
::unlink(tmp);
::close(fd);
@@ -88,7 +95,7 @@ namespace __gnu_test
#else
std::sprintf(buf,
#endif
- "filesystem-ts-test.%d.%lu", counter++, (unsigned long) ::getpid());
+ "filesystem-test.%d.%lu", counter++, (unsigned long) ::getpid());
p = buf;
#endif
return p;
@@ -97,7 +104,7 @@ namespace __gnu_test
// RAII helper to remove a file on scope exit.
struct scoped_file
{
- using path_type = std::experimental::filesystem::path;
+ using path_type = test_fs::path;
enum adopt_file_t { adopt_file };
diff --git a/maintainer-scripts/ChangeLog b/maintainer-scripts/ChangeLog
index 813d920..1ab5363 100644
--- a/maintainer-scripts/ChangeLog
+++ b/maintainer-scripts/ChangeLog
@@ -1,3 +1,8 @@
+2017-10-10 Jakub Jelinek <jakub@redhat.com>
+
+ * update_version_svn: Ignore the GCC 5 branch.
+ * crontab: Remove entry for the GCC 5 branch.
+
2017-05-23 Matthias Klose <doko@ubuntu.com>
* gcc_release (XZ): Default to xz --best.
diff --git a/maintainer-scripts/crontab b/maintainer-scripts/crontab
index bd252e2..7955703 100644
--- a/maintainer-scripts/crontab
+++ b/maintainer-scripts/crontab
@@ -1,7 +1,6 @@
16 0 * * * sh /home/gccadmin/scripts/update_version_svn
50 0 * * * sh /home/gccadmin/scripts/update_web_docs_svn
55 0 * * * sh /home/gccadmin/scripts/update_web_docs_libstdcxx_svn
-32 22 * * 2 sh /home/gccadmin/scripts/gcc_release -s 5:branches/gcc-5-branch -l -d /sourceware/snapshot-tmp/gcc all
32 22 * * 3 sh /home/gccadmin/scripts/gcc_release -s 6:branches/gcc-6-branch -l -d /sourceware/snapshot-tmp/gcc all
32 22 * * 4 sh /home/gccadmin/scripts/gcc_release -s 7:branches/gcc-7-branch -l -d /sourceware/snapshot-tmp/gcc all
32 22 * * 7 sh /home/gccadmin/scripts/gcc_release -s 8:trunk -l -d /sourceware/snapshot-tmp/gcc all
diff --git a/maintainer-scripts/update_version_svn b/maintainer-scripts/update_version_svn
index 7fa2ecb..e83757c 100755
--- a/maintainer-scripts/update_version_svn
+++ b/maintainer-scripts/update_version_svn
@@ -6,7 +6,7 @@
# in the space separated list in $ADD_BRANCHES.
SVNROOT=${SVNROOT:-"file:///svn/gcc"}
-IGNORE_BRANCHES='gcc-(2_95|3_0|3_1|3_2|3_3|3_4|4_0|4_1|4_2|4_3|4_4|4_5|4_6|4_7|4_8|4_9)-branch'
+IGNORE_BRANCHES='gcc-(2_95|3_0|3_1|3_2|3_3|3_4|4_0|4_1|4_2|4_3|4_4|4_5|4_6|4_7|4_8|4_9|5)-branch'
ADD_BRANCHES='HEAD'
# Run this from /tmp.