aboutsummaryrefslogtreecommitdiff
path: root/gcc/ipa-modref.c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-01-14 16:56:44 +0100
committerMartin Liska <mliska@suse.cz>2022-01-17 22:12:04 +0100
commit5c69acb32329d49e58c26fa41ae74229a52b9106 (patch)
treeddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/ipa-modref.c
parent490e23032baaece71f2ec09fa1805064b150fbc2 (diff)
downloadgcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2
Rename .c files to .cc files.
gcc/ada/ChangeLog: * adadecode.c: Moved to... * adadecode.cc: ...here. * affinity.c: Moved to... * affinity.cc: ...here. * argv-lynxos178-raven-cert.c: Moved to... * argv-lynxos178-raven-cert.cc: ...here. * argv.c: Moved to... * argv.cc: ...here. * aux-io.c: Moved to... * aux-io.cc: ...here. * cio.c: Moved to... * cio.cc: ...here. * cstreams.c: Moved to... * cstreams.cc: ...here. * env.c: Moved to... * env.cc: ...here. * exit.c: Moved to... * exit.cc: ...here. * expect.c: Moved to... * expect.cc: ...here. * final.c: Moved to... * final.cc: ...here. * gcc-interface/cuintp.c: Moved to... * gcc-interface/cuintp.cc: ...here. * gcc-interface/decl.c: Moved to... * gcc-interface/decl.cc: ...here. * gcc-interface/misc.c: Moved to... * gcc-interface/misc.cc: ...here. * gcc-interface/targtyps.c: Moved to... * gcc-interface/targtyps.cc: ...here. * gcc-interface/trans.c: Moved to... * gcc-interface/trans.cc: ...here. * gcc-interface/utils.c: Moved to... * gcc-interface/utils.cc: ...here. * gcc-interface/utils2.c: Moved to... * gcc-interface/utils2.cc: ...here. * init.c: Moved to... * init.cc: ...here. * initialize.c: Moved to... * initialize.cc: ...here. * libgnarl/thread.c: Moved to... * libgnarl/thread.cc: ...here. * link.c: Moved to... * link.cc: ...here. * locales.c: Moved to... * locales.cc: ...here. * mkdir.c: Moved to... * mkdir.cc: ...here. * raise.c: Moved to... * raise.cc: ...here. * rtfinal.c: Moved to... * rtfinal.cc: ...here. * rtinit.c: Moved to... * rtinit.cc: ...here. * seh_init.c: Moved to... * seh_init.cc: ...here. * sigtramp-armdroid.c: Moved to... * sigtramp-armdroid.cc: ...here. * sigtramp-ios.c: Moved to... * sigtramp-ios.cc: ...here. * sigtramp-qnx.c: Moved to... * sigtramp-qnx.cc: ...here. * sigtramp-vxworks.c: Moved to... * sigtramp-vxworks.cc: ...here. * socket.c: Moved to... * socket.cc: ...here. * tracebak.c: Moved to... * tracebak.cc: ...here. * version.c: Moved to... * version.cc: ...here. * vx_stack_info.c: Moved to... * vx_stack_info.cc: ...here. gcc/ChangeLog: * adjust-alignment.c: Moved to... * adjust-alignment.cc: ...here. * alias.c: Moved to... * alias.cc: ...here. * alloc-pool.c: Moved to... * alloc-pool.cc: ...here. * asan.c: Moved to... * asan.cc: ...here. * attribs.c: Moved to... * attribs.cc: ...here. * auto-inc-dec.c: Moved to... * auto-inc-dec.cc: ...here. * auto-profile.c: Moved to... * auto-profile.cc: ...here. * bb-reorder.c: Moved to... * bb-reorder.cc: ...here. * bitmap.c: Moved to... * bitmap.cc: ...here. * btfout.c: Moved to... * btfout.cc: ...here. * builtins.c: Moved to... * builtins.cc: ...here. * caller-save.c: Moved to... * caller-save.cc: ...here. * calls.c: Moved to... * calls.cc: ...here. * ccmp.c: Moved to... * ccmp.cc: ...here. * cfg.c: Moved to... * cfg.cc: ...here. * cfganal.c: Moved to... * cfganal.cc: ...here. * cfgbuild.c: Moved to... * cfgbuild.cc: ...here. * cfgcleanup.c: Moved to... * cfgcleanup.cc: ...here. * cfgexpand.c: Moved to... * cfgexpand.cc: ...here. * cfghooks.c: Moved to... * cfghooks.cc: ...here. * cfgloop.c: Moved to... * cfgloop.cc: ...here. * cfgloopanal.c: Moved to... * cfgloopanal.cc: ...here. * cfgloopmanip.c: Moved to... * cfgloopmanip.cc: ...here. * cfgrtl.c: Moved to... * cfgrtl.cc: ...here. * cgraph.c: Moved to... * cgraph.cc: ...here. * cgraphbuild.c: Moved to... * cgraphbuild.cc: ...here. * cgraphclones.c: Moved to... * cgraphclones.cc: ...here. * cgraphunit.c: Moved to... * cgraphunit.cc: ...here. * collect-utils.c: Moved to... * collect-utils.cc: ...here. * collect2-aix.c: Moved to... * collect2-aix.cc: ...here. * collect2.c: Moved to... * collect2.cc: ...here. * combine-stack-adj.c: Moved to... * combine-stack-adj.cc: ...here. * combine.c: Moved to... * combine.cc: ...here. * common/common-targhooks.c: Moved to... * common/common-targhooks.cc: ...here. * common/config/aarch64/aarch64-common.c: Moved to... * common/config/aarch64/aarch64-common.cc: ...here. * common/config/alpha/alpha-common.c: Moved to... * common/config/alpha/alpha-common.cc: ...here. * common/config/arc/arc-common.c: Moved to... * common/config/arc/arc-common.cc: ...here. * common/config/arm/arm-common.c: Moved to... * common/config/arm/arm-common.cc: ...here. * common/config/avr/avr-common.c: Moved to... * common/config/avr/avr-common.cc: ...here. * common/config/bfin/bfin-common.c: Moved to... * common/config/bfin/bfin-common.cc: ...here. * common/config/bpf/bpf-common.c: Moved to... * common/config/bpf/bpf-common.cc: ...here. * common/config/c6x/c6x-common.c: Moved to... * common/config/c6x/c6x-common.cc: ...here. * common/config/cr16/cr16-common.c: Moved to... * common/config/cr16/cr16-common.cc: ...here. * common/config/cris/cris-common.c: Moved to... * common/config/cris/cris-common.cc: ...here. * common/config/csky/csky-common.c: Moved to... * common/config/csky/csky-common.cc: ...here. * common/config/default-common.c: Moved to... * common/config/default-common.cc: ...here. * common/config/epiphany/epiphany-common.c: Moved to... * common/config/epiphany/epiphany-common.cc: ...here. * common/config/fr30/fr30-common.c: Moved to... * common/config/fr30/fr30-common.cc: ...here. * common/config/frv/frv-common.c: Moved to... * common/config/frv/frv-common.cc: ...here. * common/config/gcn/gcn-common.c: Moved to... * common/config/gcn/gcn-common.cc: ...here. * common/config/h8300/h8300-common.c: Moved to... * common/config/h8300/h8300-common.cc: ...here. * common/config/i386/i386-common.c: Moved to... * common/config/i386/i386-common.cc: ...here. * common/config/ia64/ia64-common.c: Moved to... * common/config/ia64/ia64-common.cc: ...here. * common/config/iq2000/iq2000-common.c: Moved to... * common/config/iq2000/iq2000-common.cc: ...here. * common/config/lm32/lm32-common.c: Moved to... * common/config/lm32/lm32-common.cc: ...here. * common/config/m32r/m32r-common.c: Moved to... * common/config/m32r/m32r-common.cc: ...here. * common/config/m68k/m68k-common.c: Moved to... * common/config/m68k/m68k-common.cc: ...here. * common/config/mcore/mcore-common.c: Moved to... * common/config/mcore/mcore-common.cc: ...here. * common/config/microblaze/microblaze-common.c: Moved to... * common/config/microblaze/microblaze-common.cc: ...here. * common/config/mips/mips-common.c: Moved to... * common/config/mips/mips-common.cc: ...here. * common/config/mmix/mmix-common.c: Moved to... * common/config/mmix/mmix-common.cc: ...here. * common/config/mn10300/mn10300-common.c: Moved to... * common/config/mn10300/mn10300-common.cc: ...here. * common/config/msp430/msp430-common.c: Moved to... * common/config/msp430/msp430-common.cc: ...here. * common/config/nds32/nds32-common.c: Moved to... * common/config/nds32/nds32-common.cc: ...here. * common/config/nios2/nios2-common.c: Moved to... * common/config/nios2/nios2-common.cc: ...here. * common/config/nvptx/nvptx-common.c: Moved to... * common/config/nvptx/nvptx-common.cc: ...here. * common/config/or1k/or1k-common.c: Moved to... * common/config/or1k/or1k-common.cc: ...here. * common/config/pa/pa-common.c: Moved to... * common/config/pa/pa-common.cc: ...here. * common/config/pdp11/pdp11-common.c: Moved to... * common/config/pdp11/pdp11-common.cc: ...here. * common/config/pru/pru-common.c: Moved to... * common/config/pru/pru-common.cc: ...here. * common/config/riscv/riscv-common.c: Moved to... * common/config/riscv/riscv-common.cc: ...here. * common/config/rs6000/rs6000-common.c: Moved to... * common/config/rs6000/rs6000-common.cc: ...here. * common/config/rx/rx-common.c: Moved to... * common/config/rx/rx-common.cc: ...here. * common/config/s390/s390-common.c: Moved to... * common/config/s390/s390-common.cc: ...here. * common/config/sh/sh-common.c: Moved to... * common/config/sh/sh-common.cc: ...here. * common/config/sparc/sparc-common.c: Moved to... * common/config/sparc/sparc-common.cc: ...here. * common/config/tilegx/tilegx-common.c: Moved to... * common/config/tilegx/tilegx-common.cc: ...here. * common/config/tilepro/tilepro-common.c: Moved to... * common/config/tilepro/tilepro-common.cc: ...here. * common/config/v850/v850-common.c: Moved to... * common/config/v850/v850-common.cc: ...here. * common/config/vax/vax-common.c: Moved to... * common/config/vax/vax-common.cc: ...here. * common/config/visium/visium-common.c: Moved to... * common/config/visium/visium-common.cc: ...here. * common/config/xstormy16/xstormy16-common.c: Moved to... * common/config/xstormy16/xstormy16-common.cc: ...here. * common/config/xtensa/xtensa-common.c: Moved to... * common/config/xtensa/xtensa-common.cc: ...here. * compare-elim.c: Moved to... * compare-elim.cc: ...here. * config/aarch64/aarch64-bti-insert.c: Moved to... * config/aarch64/aarch64-bti-insert.cc: ...here. * config/aarch64/aarch64-builtins.c: Moved to... * config/aarch64/aarch64-builtins.cc: ...here. * config/aarch64/aarch64-c.c: Moved to... * config/aarch64/aarch64-c.cc: ...here. * config/aarch64/aarch64-d.c: Moved to... * config/aarch64/aarch64-d.cc: ...here. * config/aarch64/aarch64.c: Moved to... * config/aarch64/aarch64.cc: ...here. * config/aarch64/cortex-a57-fma-steering.c: Moved to... * config/aarch64/cortex-a57-fma-steering.cc: ...here. * config/aarch64/driver-aarch64.c: Moved to... * config/aarch64/driver-aarch64.cc: ...here. * config/aarch64/falkor-tag-collision-avoidance.c: Moved to... * config/aarch64/falkor-tag-collision-avoidance.cc: ...here. * config/aarch64/host-aarch64-darwin.c: Moved to... * config/aarch64/host-aarch64-darwin.cc: ...here. * config/alpha/alpha.c: Moved to... * config/alpha/alpha.cc: ...here. * config/alpha/driver-alpha.c: Moved to... * config/alpha/driver-alpha.cc: ...here. * config/arc/arc-c.c: Moved to... * config/arc/arc-c.cc: ...here. * config/arc/arc.c: Moved to... * config/arc/arc.cc: ...here. * config/arc/driver-arc.c: Moved to... * config/arc/driver-arc.cc: ...here. * config/arm/aarch-common.c: Moved to... * config/arm/aarch-common.cc: ...here. * config/arm/arm-builtins.c: Moved to... * config/arm/arm-builtins.cc: ...here. * config/arm/arm-c.c: Moved to... * config/arm/arm-c.cc: ...here. * config/arm/arm-d.c: Moved to... * config/arm/arm-d.cc: ...here. * config/arm/arm.c: Moved to... * config/arm/arm.cc: ...here. * config/arm/driver-arm.c: Moved to... * config/arm/driver-arm.cc: ...here. * config/avr/avr-c.c: Moved to... * config/avr/avr-c.cc: ...here. * config/avr/avr-devices.c: Moved to... * config/avr/avr-devices.cc: ...here. * config/avr/avr-log.c: Moved to... * config/avr/avr-log.cc: ...here. * config/avr/avr.c: Moved to... * config/avr/avr.cc: ...here. * config/avr/driver-avr.c: Moved to... * config/avr/driver-avr.cc: ...here. * config/avr/gen-avr-mmcu-specs.c: Moved to... * config/avr/gen-avr-mmcu-specs.cc: ...here. * config/avr/gen-avr-mmcu-texi.c: Moved to... * config/avr/gen-avr-mmcu-texi.cc: ...here. * config/bfin/bfin.c: Moved to... * config/bfin/bfin.cc: ...here. * config/bpf/bpf.c: Moved to... * config/bpf/bpf.cc: ...here. * config/bpf/coreout.c: Moved to... * config/bpf/coreout.cc: ...here. * config/c6x/c6x.c: Moved to... * config/c6x/c6x.cc: ...here. * config/cr16/cr16.c: Moved to... * config/cr16/cr16.cc: ...here. * config/cris/cris.c: Moved to... * config/cris/cris.cc: ...here. * config/csky/csky.c: Moved to... * config/csky/csky.cc: ...here. * config/darwin-c.c: Moved to... * config/darwin-c.cc: ...here. * config/darwin-d.c: Moved to... * config/darwin-d.cc: ...here. * config/darwin-driver.c: Moved to... * config/darwin-driver.cc: ...here. * config/darwin-f.c: Moved to... * config/darwin-f.cc: ...here. * config/darwin.c: Moved to... * config/darwin.cc: ...here. * config/default-c.c: Moved to... * config/default-c.cc: ...here. * config/default-d.c: Moved to... * config/default-d.cc: ...here. * config/dragonfly-d.c: Moved to... * config/dragonfly-d.cc: ...here. * config/epiphany/epiphany.c: Moved to... * config/epiphany/epiphany.cc: ...here. * config/epiphany/mode-switch-use.c: Moved to... * config/epiphany/mode-switch-use.cc: ...here. * config/epiphany/resolve-sw-modes.c: Moved to... * config/epiphany/resolve-sw-modes.cc: ...here. * config/fr30/fr30.c: Moved to... * config/fr30/fr30.cc: ...here. * config/freebsd-d.c: Moved to... * config/freebsd-d.cc: ...here. * config/frv/frv.c: Moved to... * config/frv/frv.cc: ...here. * config/ft32/ft32.c: Moved to... * config/ft32/ft32.cc: ...here. * config/gcn/driver-gcn.c: Moved to... * config/gcn/driver-gcn.cc: ...here. * config/gcn/gcn-run.c: Moved to... * config/gcn/gcn-run.cc: ...here. * config/gcn/gcn-tree.c: Moved to... * config/gcn/gcn-tree.cc: ...here. * config/gcn/gcn.c: Moved to... * config/gcn/gcn.cc: ...here. * config/gcn/mkoffload.c: Moved to... * config/gcn/mkoffload.cc: ...here. * config/glibc-c.c: Moved to... * config/glibc-c.cc: ...here. * config/glibc-d.c: Moved to... * config/glibc-d.cc: ...here. * config/h8300/h8300.c: Moved to... * config/h8300/h8300.cc: ...here. * config/host-darwin.c: Moved to... * config/host-darwin.cc: ...here. * config/host-hpux.c: Moved to... * config/host-hpux.cc: ...here. * config/host-linux.c: Moved to... * config/host-linux.cc: ...here. * config/host-netbsd.c: Moved to... * config/host-netbsd.cc: ...here. * config/host-openbsd.c: Moved to... * config/host-openbsd.cc: ...here. * config/host-solaris.c: Moved to... * config/host-solaris.cc: ...here. * config/i386/djgpp.c: Moved to... * config/i386/djgpp.cc: ...here. * config/i386/driver-i386.c: Moved to... * config/i386/driver-i386.cc: ...here. * config/i386/driver-mingw32.c: Moved to... * config/i386/driver-mingw32.cc: ...here. * config/i386/gnu-property.c: Moved to... * config/i386/gnu-property.cc: ...here. * config/i386/host-cygwin.c: Moved to... * config/i386/host-cygwin.cc: ...here. * config/i386/host-i386-darwin.c: Moved to... * config/i386/host-i386-darwin.cc: ...here. * config/i386/host-mingw32.c: Moved to... * config/i386/host-mingw32.cc: ...here. * config/i386/i386-builtins.c: Moved to... * config/i386/i386-builtins.cc: ...here. * config/i386/i386-c.c: Moved to... * config/i386/i386-c.cc: ...here. * config/i386/i386-d.c: Moved to... * config/i386/i386-d.cc: ...here. * config/i386/i386-expand.c: Moved to... * config/i386/i386-expand.cc: ...here. * config/i386/i386-features.c: Moved to... * config/i386/i386-features.cc: ...here. * config/i386/i386-options.c: Moved to... * config/i386/i386-options.cc: ...here. * config/i386/i386.c: Moved to... * config/i386/i386.cc: ...here. * config/i386/intelmic-mkoffload.c: Moved to... * config/i386/intelmic-mkoffload.cc: ...here. * config/i386/msformat-c.c: Moved to... * config/i386/msformat-c.cc: ...here. * config/i386/winnt-cxx.c: Moved to... * config/i386/winnt-cxx.cc: ...here. * config/i386/winnt-d.c: Moved to... * config/i386/winnt-d.cc: ...here. * config/i386/winnt-stubs.c: Moved to... * config/i386/winnt-stubs.cc: ...here. * config/i386/winnt.c: Moved to... * config/i386/winnt.cc: ...here. * config/i386/x86-tune-sched-atom.c: Moved to... * config/i386/x86-tune-sched-atom.cc: ...here. * config/i386/x86-tune-sched-bd.c: Moved to... * config/i386/x86-tune-sched-bd.cc: ...here. * config/i386/x86-tune-sched-core.c: Moved to... * config/i386/x86-tune-sched-core.cc: ...here. * config/i386/x86-tune-sched.c: Moved to... * config/i386/x86-tune-sched.cc: ...here. * config/ia64/ia64-c.c: Moved to... * config/ia64/ia64-c.cc: ...here. * config/ia64/ia64.c: Moved to... * config/ia64/ia64.cc: ...here. * config/iq2000/iq2000.c: Moved to... * config/iq2000/iq2000.cc: ...here. * config/linux.c: Moved to... * config/linux.cc: ...here. * config/lm32/lm32.c: Moved to... * config/lm32/lm32.cc: ...here. * config/m32c/m32c-pragma.c: Moved to... * config/m32c/m32c-pragma.cc: ...here. * config/m32c/m32c.c: Moved to... * config/m32c/m32c.cc: ...here. * config/m32r/m32r.c: Moved to... * config/m32r/m32r.cc: ...here. * config/m68k/m68k.c: Moved to... * config/m68k/m68k.cc: ...here. * config/mcore/mcore.c: Moved to... * config/mcore/mcore.cc: ...here. * config/microblaze/microblaze-c.c: Moved to... * config/microblaze/microblaze-c.cc: ...here. * config/microblaze/microblaze.c: Moved to... * config/microblaze/microblaze.cc: ...here. * config/mips/driver-native.c: Moved to... * config/mips/driver-native.cc: ...here. * config/mips/frame-header-opt.c: Moved to... * config/mips/frame-header-opt.cc: ...here. * config/mips/mips-d.c: Moved to... * config/mips/mips-d.cc: ...here. * config/mips/mips.c: Moved to... * config/mips/mips.cc: ...here. * config/mmix/mmix.c: Moved to... * config/mmix/mmix.cc: ...here. * config/mn10300/mn10300.c: Moved to... * config/mn10300/mn10300.cc: ...here. * config/moxie/moxie.c: Moved to... * config/moxie/moxie.cc: ...here. * config/msp430/driver-msp430.c: Moved to... * config/msp430/driver-msp430.cc: ...here. * config/msp430/msp430-c.c: Moved to... * config/msp430/msp430-c.cc: ...here. * config/msp430/msp430-devices.c: Moved to... * config/msp430/msp430-devices.cc: ...here. * config/msp430/msp430.c: Moved to... * config/msp430/msp430.cc: ...here. * config/nds32/nds32-cost.c: Moved to... * config/nds32/nds32-cost.cc: ...here. * config/nds32/nds32-fp-as-gp.c: Moved to... * config/nds32/nds32-fp-as-gp.cc: ...here. * config/nds32/nds32-intrinsic.c: Moved to... * config/nds32/nds32-intrinsic.cc: ...here. * config/nds32/nds32-isr.c: Moved to... * config/nds32/nds32-isr.cc: ...here. * config/nds32/nds32-md-auxiliary.c: Moved to... * config/nds32/nds32-md-auxiliary.cc: ...here. * config/nds32/nds32-memory-manipulation.c: Moved to... * config/nds32/nds32-memory-manipulation.cc: ...here. * config/nds32/nds32-pipelines-auxiliary.c: Moved to... * config/nds32/nds32-pipelines-auxiliary.cc: ...here. * config/nds32/nds32-predicates.c: Moved to... * config/nds32/nds32-predicates.cc: ...here. * config/nds32/nds32-relax-opt.c: Moved to... * config/nds32/nds32-relax-opt.cc: ...here. * config/nds32/nds32-utils.c: Moved to... * config/nds32/nds32-utils.cc: ...here. * config/nds32/nds32.c: Moved to... * config/nds32/nds32.cc: ...here. * config/netbsd-d.c: Moved to... * config/netbsd-d.cc: ...here. * config/netbsd.c: Moved to... * config/netbsd.cc: ...here. * config/nios2/nios2.c: Moved to... * config/nios2/nios2.cc: ...here. * config/nvptx/mkoffload.c: Moved to... * config/nvptx/mkoffload.cc: ...here. * config/nvptx/nvptx-c.c: Moved to... * config/nvptx/nvptx-c.cc: ...here. * config/nvptx/nvptx.c: Moved to... * config/nvptx/nvptx.cc: ...here. * config/openbsd-d.c: Moved to... * config/openbsd-d.cc: ...here. * config/or1k/or1k.c: Moved to... * config/or1k/or1k.cc: ...here. * config/pa/pa-d.c: Moved to... * config/pa/pa-d.cc: ...here. * config/pa/pa.c: Moved to... * config/pa/pa.cc: ...here. * config/pdp11/pdp11.c: Moved to... * config/pdp11/pdp11.cc: ...here. * config/pru/pru-passes.c: Moved to... * config/pru/pru-passes.cc: ...here. * config/pru/pru-pragma.c: Moved to... * config/pru/pru-pragma.cc: ...here. * config/pru/pru.c: Moved to... * config/pru/pru.cc: ...here. * config/riscv/riscv-builtins.c: Moved to... * config/riscv/riscv-builtins.cc: ...here. * config/riscv/riscv-c.c: Moved to... * config/riscv/riscv-c.cc: ...here. * config/riscv/riscv-d.c: Moved to... * config/riscv/riscv-d.cc: ...here. * config/riscv/riscv-shorten-memrefs.c: Moved to... * config/riscv/riscv-shorten-memrefs.cc: ...here. * config/riscv/riscv-sr.c: Moved to... * config/riscv/riscv-sr.cc: ...here. * config/riscv/riscv.c: Moved to... * config/riscv/riscv.cc: ...here. * config/rl78/rl78-c.c: Moved to... * config/rl78/rl78-c.cc: ...here. * config/rl78/rl78.c: Moved to... * config/rl78/rl78.cc: ...here. * config/rs6000/driver-rs6000.c: Moved to... * config/rs6000/driver-rs6000.cc: ...here. * config/rs6000/host-darwin.c: Moved to... * config/rs6000/host-darwin.cc: ...here. * config/rs6000/host-ppc64-darwin.c: Moved to... * config/rs6000/host-ppc64-darwin.cc: ...here. * config/rs6000/rbtree.c: Moved to... * config/rs6000/rbtree.cc: ...here. * config/rs6000/rs6000-c.c: Moved to... * config/rs6000/rs6000-c.cc: ...here. * config/rs6000/rs6000-call.c: Moved to... * config/rs6000/rs6000-call.cc: ...here. * config/rs6000/rs6000-d.c: Moved to... * config/rs6000/rs6000-d.cc: ...here. * config/rs6000/rs6000-gen-builtins.c: Moved to... * config/rs6000/rs6000-gen-builtins.cc: ...here. * config/rs6000/rs6000-linux.c: Moved to... * config/rs6000/rs6000-linux.cc: ...here. * config/rs6000/rs6000-logue.c: Moved to... * config/rs6000/rs6000-logue.cc: ...here. * config/rs6000/rs6000-p8swap.c: Moved to... * config/rs6000/rs6000-p8swap.cc: ...here. * config/rs6000/rs6000-pcrel-opt.c: Moved to... * config/rs6000/rs6000-pcrel-opt.cc: ...here. * config/rs6000/rs6000-string.c: Moved to... * config/rs6000/rs6000-string.cc: ...here. * config/rs6000/rs6000.c: Moved to... * config/rs6000/rs6000.cc: ...here. * config/rx/rx.c: Moved to... * config/rx/rx.cc: ...here. * config/s390/driver-native.c: Moved to... * config/s390/driver-native.cc: ...here. * config/s390/s390-c.c: Moved to... * config/s390/s390-c.cc: ...here. * config/s390/s390-d.c: Moved to... * config/s390/s390-d.cc: ...here. * config/s390/s390.c: Moved to... * config/s390/s390.cc: ...here. * config/sh/divtab-sh4-300.c: Moved to... * config/sh/divtab-sh4-300.cc: ...here. * config/sh/divtab-sh4.c: Moved to... * config/sh/divtab-sh4.cc: ...here. * config/sh/divtab.c: Moved to... * config/sh/divtab.cc: ...here. * config/sh/sh-c.c: Moved to... * config/sh/sh-c.cc: ...here. * config/sh/sh.c: Moved to... * config/sh/sh.cc: ...here. * config/sol2-c.c: Moved to... * config/sol2-c.cc: ...here. * config/sol2-cxx.c: Moved to... * config/sol2-cxx.cc: ...here. * config/sol2-d.c: Moved to... * config/sol2-d.cc: ...here. * config/sol2-stubs.c: Moved to... * config/sol2-stubs.cc: ...here. * config/sol2.c: Moved to... * config/sol2.cc: ...here. * config/sparc/driver-sparc.c: Moved to... * config/sparc/driver-sparc.cc: ...here. * config/sparc/sparc-c.c: Moved to... * config/sparc/sparc-c.cc: ...here. * config/sparc/sparc-d.c: Moved to... * config/sparc/sparc-d.cc: ...here. * config/sparc/sparc.c: Moved to... * config/sparc/sparc.cc: ...here. * config/stormy16/stormy16.c: Moved to... * config/stormy16/stormy16.cc: ...here. * config/tilegx/mul-tables.c: Moved to... * config/tilegx/mul-tables.cc: ...here. * config/tilegx/tilegx-c.c: Moved to... * config/tilegx/tilegx-c.cc: ...here. * config/tilegx/tilegx.c: Moved to... * config/tilegx/tilegx.cc: ...here. * config/tilepro/mul-tables.c: Moved to... * config/tilepro/mul-tables.cc: ...here. * config/tilepro/tilepro-c.c: Moved to... * config/tilepro/tilepro-c.cc: ...here. * config/tilepro/tilepro.c: Moved to... * config/tilepro/tilepro.cc: ...here. * config/v850/v850-c.c: Moved to... * config/v850/v850-c.cc: ...here. * config/v850/v850.c: Moved to... * config/v850/v850.cc: ...here. * config/vax/vax.c: Moved to... * config/vax/vax.cc: ...here. * config/visium/visium.c: Moved to... * config/visium/visium.cc: ...here. * config/vms/vms-c.c: Moved to... * config/vms/vms-c.cc: ...here. * config/vms/vms-f.c: Moved to... * config/vms/vms-f.cc: ...here. * config/vms/vms.c: Moved to... * config/vms/vms.cc: ...here. * config/vxworks-c.c: Moved to... * config/vxworks-c.cc: ...here. * config/vxworks.c: Moved to... * config/vxworks.cc: ...here. * config/winnt-c.c: Moved to... * config/winnt-c.cc: ...here. * config/xtensa/xtensa.c: Moved to... * config/xtensa/xtensa.cc: ...here. * context.c: Moved to... * context.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * coverage.c: Moved to... * coverage.cc: ...here. * cppbuiltin.c: Moved to... * cppbuiltin.cc: ...here. * cppdefault.c: Moved to... * cppdefault.cc: ...here. * cprop.c: Moved to... * cprop.cc: ...here. * cse.c: Moved to... * cse.cc: ...here. * cselib.c: Moved to... * cselib.cc: ...here. * ctfc.c: Moved to... * ctfc.cc: ...here. * ctfout.c: Moved to... * ctfout.cc: ...here. * data-streamer-in.c: Moved to... * data-streamer-in.cc: ...here. * data-streamer-out.c: Moved to... * data-streamer-out.cc: ...here. * data-streamer.c: Moved to... * data-streamer.cc: ...here. * dbgcnt.c: Moved to... * dbgcnt.cc: ...here. * dbxout.c: Moved to... * dbxout.cc: ...here. * dce.c: Moved to... * dce.cc: ...here. * ddg.c: Moved to... * ddg.cc: ...here. * debug.c: Moved to... * debug.cc: ...here. * df-core.c: Moved to... * df-core.cc: ...here. * df-problems.c: Moved to... * df-problems.cc: ...here. * df-scan.c: Moved to... * df-scan.cc: ...here. * dfp.c: Moved to... * dfp.cc: ...here. * diagnostic-color.c: Moved to... * diagnostic-color.cc: ...here. * diagnostic-show-locus.c: Moved to... * diagnostic-show-locus.cc: ...here. * diagnostic-spec.c: Moved to... * diagnostic-spec.cc: ...here. * diagnostic.c: Moved to... * diagnostic.cc: ...here. * dojump.c: Moved to... * dojump.cc: ...here. * dominance.c: Moved to... * dominance.cc: ...here. * domwalk.c: Moved to... * domwalk.cc: ...here. * double-int.c: Moved to... * double-int.cc: ...here. * dse.c: Moved to... * dse.cc: ...here. * dumpfile.c: Moved to... * dumpfile.cc: ...here. * dwarf2asm.c: Moved to... * dwarf2asm.cc: ...here. * dwarf2cfi.c: Moved to... * dwarf2cfi.cc: ...here. * dwarf2ctf.c: Moved to... * dwarf2ctf.cc: ...here. * dwarf2out.c: Moved to... * dwarf2out.cc: ...here. * early-remat.c: Moved to... * early-remat.cc: ...here. * edit-context.c: Moved to... * edit-context.cc: ...here. * emit-rtl.c: Moved to... * emit-rtl.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * et-forest.c: Moved to... * et-forest.cc: ...here. * except.c: Moved to... * except.cc: ...here. * explow.c: Moved to... * explow.cc: ...here. * expmed.c: Moved to... * expmed.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * fibonacci_heap.c: Moved to... * fibonacci_heap.cc: ...here. * file-find.c: Moved to... * file-find.cc: ...here. * file-prefix-map.c: Moved to... * file-prefix-map.cc: ...here. * final.c: Moved to... * final.cc: ...here. * fixed-value.c: Moved to... * fixed-value.cc: ...here. * fold-const-call.c: Moved to... * fold-const-call.cc: ...here. * fold-const.c: Moved to... * fold-const.cc: ...here. * fp-test.c: Moved to... * fp-test.cc: ...here. * function-tests.c: Moved to... * function-tests.cc: ...here. * function.c: Moved to... * function.cc: ...here. * fwprop.c: Moved to... * fwprop.cc: ...here. * gcc-ar.c: Moved to... * gcc-ar.cc: ...here. * gcc-main.c: Moved to... * gcc-main.cc: ...here. * gcc-rich-location.c: Moved to... * gcc-rich-location.cc: ...here. * gcc.c: Moved to... * gcc.cc: ...here. * gcov-dump.c: Moved to... * gcov-dump.cc: ...here. * gcov-io.c: Moved to... * gcov-io.cc: ...here. * gcov-tool.c: Moved to... * gcov-tool.cc: ...here. * gcov.c: Moved to... * gcov.cc: ...here. * gcse-common.c: Moved to... * gcse-common.cc: ...here. * gcse.c: Moved to... * gcse.cc: ...here. * genattr-common.c: Moved to... * genattr-common.cc: ...here. * genattr.c: Moved to... * genattr.cc: ...here. * genattrtab.c: Moved to... * genattrtab.cc: ...here. * genautomata.c: Moved to... * genautomata.cc: ...here. * gencfn-macros.c: Moved to... * gencfn-macros.cc: ...here. * gencheck.c: Moved to... * gencheck.cc: ...here. * genchecksum.c: Moved to... * genchecksum.cc: ...here. * gencodes.c: Moved to... * gencodes.cc: ...here. * genconditions.c: Moved to... * genconditions.cc: ...here. * genconfig.c: Moved to... * genconfig.cc: ...here. * genconstants.c: Moved to... * genconstants.cc: ...here. * genemit.c: Moved to... * genemit.cc: ...here. * genenums.c: Moved to... * genenums.cc: ...here. * generic-match-head.c: Moved to... * generic-match-head.cc: ...here. * genextract.c: Moved to... * genextract.cc: ...here. * genflags.c: Moved to... * genflags.cc: ...here. * gengenrtl.c: Moved to... * gengenrtl.cc: ...here. * gengtype-parse.c: Moved to... * gengtype-parse.cc: ...here. * gengtype-state.c: Moved to... * gengtype-state.cc: ...here. * gengtype.c: Moved to... * gengtype.cc: ...here. * genhooks.c: Moved to... * genhooks.cc: ...here. * genmatch.c: Moved to... * genmatch.cc: ...here. * genmddeps.c: Moved to... * genmddeps.cc: ...here. * genmddump.c: Moved to... * genmddump.cc: ...here. * genmodes.c: Moved to... * genmodes.cc: ...here. * genopinit.c: Moved to... * genopinit.cc: ...here. * genoutput.c: Moved to... * genoutput.cc: ...here. * genpeep.c: Moved to... * genpeep.cc: ...here. * genpreds.c: Moved to... * genpreds.cc: ...here. * genrecog.c: Moved to... * genrecog.cc: ...here. * gensupport.c: Moved to... * gensupport.cc: ...here. * gentarget-def.c: Moved to... * gentarget-def.cc: ...here. * genversion.c: Moved to... * genversion.cc: ...here. * ggc-common.c: Moved to... * ggc-common.cc: ...here. * ggc-none.c: Moved to... * ggc-none.cc: ...here. * ggc-page.c: Moved to... * ggc-page.cc: ...here. * ggc-tests.c: Moved to... * ggc-tests.cc: ...here. * gimple-builder.c: Moved to... * gimple-builder.cc: ...here. * gimple-expr.c: Moved to... * gimple-expr.cc: ...here. * gimple-fold.c: Moved to... * gimple-fold.cc: ...here. * gimple-iterator.c: Moved to... * gimple-iterator.cc: ...here. * gimple-laddress.c: Moved to... * gimple-laddress.cc: ...here. * gimple-loop-jam.c: Moved to... * gimple-loop-jam.cc: ...here. * gimple-low.c: Moved to... * gimple-low.cc: ...here. * gimple-match-head.c: Moved to... * gimple-match-head.cc: ...here. * gimple-pretty-print.c: Moved to... * gimple-pretty-print.cc: ...here. * gimple-ssa-backprop.c: Moved to... * gimple-ssa-backprop.cc: ...here. * gimple-ssa-evrp-analyze.c: Moved to... * gimple-ssa-evrp-analyze.cc: ...here. * gimple-ssa-evrp.c: Moved to... * gimple-ssa-evrp.cc: ...here. * gimple-ssa-isolate-paths.c: Moved to... * gimple-ssa-isolate-paths.cc: ...here. * gimple-ssa-nonnull-compare.c: Moved to... * gimple-ssa-nonnull-compare.cc: ...here. * gimple-ssa-split-paths.c: Moved to... * gimple-ssa-split-paths.cc: ...here. * gimple-ssa-sprintf.c: Moved to... * gimple-ssa-sprintf.cc: ...here. * gimple-ssa-store-merging.c: Moved to... * gimple-ssa-store-merging.cc: ...here. * gimple-ssa-strength-reduction.c: Moved to... * gimple-ssa-strength-reduction.cc: ...here. * gimple-ssa-warn-alloca.c: Moved to... * gimple-ssa-warn-alloca.cc: ...here. * gimple-ssa-warn-restrict.c: Moved to... * gimple-ssa-warn-restrict.cc: ...here. * gimple-streamer-in.c: Moved to... * gimple-streamer-in.cc: ...here. * gimple-streamer-out.c: Moved to... * gimple-streamer-out.cc: ...here. * gimple-walk.c: Moved to... * gimple-walk.cc: ...here. * gimple-warn-recursion.c: Moved to... * gimple-warn-recursion.cc: ...here. * gimple.c: Moved to... * gimple.cc: ...here. * gimplify-me.c: Moved to... * gimplify-me.cc: ...here. * gimplify.c: Moved to... * gimplify.cc: ...here. * godump.c: Moved to... * godump.cc: ...here. * graph.c: Moved to... * graph.cc: ...here. * graphds.c: Moved to... * graphds.cc: ...here. * graphite-dependences.c: Moved to... * graphite-dependences.cc: ...here. * graphite-isl-ast-to-gimple.c: Moved to... * graphite-isl-ast-to-gimple.cc: ...here. * graphite-optimize-isl.c: Moved to... * graphite-optimize-isl.cc: ...here. * graphite-poly.c: Moved to... * graphite-poly.cc: ...here. * graphite-scop-detection.c: Moved to... * graphite-scop-detection.cc: ...here. * graphite-sese-to-poly.c: Moved to... * graphite-sese-to-poly.cc: ...here. * graphite.c: Moved to... * graphite.cc: ...here. * haifa-sched.c: Moved to... * haifa-sched.cc: ...here. * hash-map-tests.c: Moved to... * hash-map-tests.cc: ...here. * hash-set-tests.c: Moved to... * hash-set-tests.cc: ...here. * hash-table.c: Moved to... * hash-table.cc: ...here. * hooks.c: Moved to... * hooks.cc: ...here. * host-default.c: Moved to... * host-default.cc: ...here. * hw-doloop.c: Moved to... * hw-doloop.cc: ...here. * hwint.c: Moved to... * hwint.cc: ...here. * ifcvt.c: Moved to... * ifcvt.cc: ...here. * inchash.c: Moved to... * inchash.cc: ...here. * incpath.c: Moved to... * incpath.cc: ...here. * init-regs.c: Moved to... * init-regs.cc: ...here. * input.c: Moved to... * input.cc: ...here. * internal-fn.c: Moved to... * internal-fn.cc: ...here. * intl.c: Moved to... * intl.cc: ...here. * ipa-comdats.c: Moved to... * ipa-comdats.cc: ...here. * ipa-cp.c: Moved to... * ipa-cp.cc: ...here. * ipa-devirt.c: Moved to... * ipa-devirt.cc: ...here. * ipa-fnsummary.c: Moved to... * ipa-fnsummary.cc: ...here. * ipa-icf-gimple.c: Moved to... * ipa-icf-gimple.cc: ...here. * ipa-icf.c: Moved to... * ipa-icf.cc: ...here. * ipa-inline-analysis.c: Moved to... * ipa-inline-analysis.cc: ...here. * ipa-inline-transform.c: Moved to... * ipa-inline-transform.cc: ...here. * ipa-inline.c: Moved to... * ipa-inline.cc: ...here. * ipa-modref-tree.c: Moved to... * ipa-modref-tree.cc: ...here. * ipa-modref.c: Moved to... * ipa-modref.cc: ...here. * ipa-param-manipulation.c: Moved to... * ipa-param-manipulation.cc: ...here. * ipa-polymorphic-call.c: Moved to... * ipa-polymorphic-call.cc: ...here. * ipa-predicate.c: Moved to... * ipa-predicate.cc: ...here. * ipa-profile.c: Moved to... * ipa-profile.cc: ...here. * ipa-prop.c: Moved to... * ipa-prop.cc: ...here. * ipa-pure-const.c: Moved to... * ipa-pure-const.cc: ...here. * ipa-ref.c: Moved to... * ipa-ref.cc: ...here. * ipa-reference.c: Moved to... * ipa-reference.cc: ...here. * ipa-split.c: Moved to... * ipa-split.cc: ...here. * ipa-sra.c: Moved to... * ipa-sra.cc: ...here. * ipa-utils.c: Moved to... * ipa-utils.cc: ...here. * ipa-visibility.c: Moved to... * ipa-visibility.cc: ...here. * ipa.c: Moved to... * ipa.cc: ...here. * ira-build.c: Moved to... * ira-build.cc: ...here. * ira-color.c: Moved to... * ira-color.cc: ...here. * ira-conflicts.c: Moved to... * ira-conflicts.cc: ...here. * ira-costs.c: Moved to... * ira-costs.cc: ...here. * ira-emit.c: Moved to... * ira-emit.cc: ...here. * ira-lives.c: Moved to... * ira-lives.cc: ...here. * ira.c: Moved to... * ira.cc: ...here. * jump.c: Moved to... * jump.cc: ...here. * langhooks.c: Moved to... * langhooks.cc: ...here. * lcm.c: Moved to... * lcm.cc: ...here. * lists.c: Moved to... * lists.cc: ...here. * loop-doloop.c: Moved to... * loop-doloop.cc: ...here. * loop-init.c: Moved to... * loop-init.cc: ...here. * loop-invariant.c: Moved to... * loop-invariant.cc: ...here. * loop-iv.c: Moved to... * loop-iv.cc: ...here. * loop-unroll.c: Moved to... * loop-unroll.cc: ...here. * lower-subreg.c: Moved to... * lower-subreg.cc: ...here. * lra-assigns.c: Moved to... * lra-assigns.cc: ...here. * lra-coalesce.c: Moved to... * lra-coalesce.cc: ...here. * lra-constraints.c: Moved to... * lra-constraints.cc: ...here. * lra-eliminations.c: Moved to... * lra-eliminations.cc: ...here. * lra-lives.c: Moved to... * lra-lives.cc: ...here. * lra-remat.c: Moved to... * lra-remat.cc: ...here. * lra-spills.c: Moved to... * lra-spills.cc: ...here. * lra.c: Moved to... * lra.cc: ...here. * lto-cgraph.c: Moved to... * lto-cgraph.cc: ...here. * lto-compress.c: Moved to... * lto-compress.cc: ...here. * lto-opts.c: Moved to... * lto-opts.cc: ...here. * lto-section-in.c: Moved to... * lto-section-in.cc: ...here. * lto-section-out.c: Moved to... * lto-section-out.cc: ...here. * lto-streamer-in.c: Moved to... * lto-streamer-in.cc: ...here. * lto-streamer-out.c: Moved to... * lto-streamer-out.cc: ...here. * lto-streamer.c: Moved to... * lto-streamer.cc: ...here. * lto-wrapper.c: Moved to... * lto-wrapper.cc: ...here. * main.c: Moved to... * main.cc: ...here. * mcf.c: Moved to... * mcf.cc: ...here. * mode-switching.c: Moved to... * mode-switching.cc: ...here. * modulo-sched.c: Moved to... * modulo-sched.cc: ...here. * multiple_target.c: Moved to... * multiple_target.cc: ...here. * omp-expand.c: Moved to... * omp-expand.cc: ...here. * omp-general.c: Moved to... * omp-general.cc: ...here. * omp-low.c: Moved to... * omp-low.cc: ...here. * omp-offload.c: Moved to... * omp-offload.cc: ...here. * omp-simd-clone.c: Moved to... * omp-simd-clone.cc: ...here. * opt-suggestions.c: Moved to... * opt-suggestions.cc: ...here. * optabs-libfuncs.c: Moved to... * optabs-libfuncs.cc: ...here. * optabs-query.c: Moved to... * optabs-query.cc: ...here. * optabs-tree.c: Moved to... * optabs-tree.cc: ...here. * optabs.c: Moved to... * optabs.cc: ...here. * opts-common.c: Moved to... * opts-common.cc: ...here. * opts-global.c: Moved to... * opts-global.cc: ...here. * opts.c: Moved to... * opts.cc: ...here. * passes.c: Moved to... * passes.cc: ...here. * plugin.c: Moved to... * plugin.cc: ...here. * postreload-gcse.c: Moved to... * postreload-gcse.cc: ...here. * postreload.c: Moved to... * postreload.cc: ...here. * predict.c: Moved to... * predict.cc: ...here. * prefix.c: Moved to... * prefix.cc: ...here. * pretty-print.c: Moved to... * pretty-print.cc: ...here. * print-rtl-function.c: Moved to... * print-rtl-function.cc: ...here. * print-rtl.c: Moved to... * print-rtl.cc: ...here. * print-tree.c: Moved to... * print-tree.cc: ...here. * profile-count.c: Moved to... * profile-count.cc: ...here. * profile.c: Moved to... * profile.cc: ...here. * read-md.c: Moved to... * read-md.cc: ...here. * read-rtl-function.c: Moved to... * read-rtl-function.cc: ...here. * read-rtl.c: Moved to... * read-rtl.cc: ...here. * real.c: Moved to... * real.cc: ...here. * realmpfr.c: Moved to... * realmpfr.cc: ...here. * recog.c: Moved to... * recog.cc: ...here. * ree.c: Moved to... * ree.cc: ...here. * reg-stack.c: Moved to... * reg-stack.cc: ...here. * regcprop.c: Moved to... * regcprop.cc: ...here. * reginfo.c: Moved to... * reginfo.cc: ...here. * regrename.c: Moved to... * regrename.cc: ...here. * regstat.c: Moved to... * regstat.cc: ...here. * reload.c: Moved to... * reload.cc: ...here. * reload1.c: Moved to... * reload1.cc: ...here. * reorg.c: Moved to... * reorg.cc: ...here. * resource.c: Moved to... * resource.cc: ...here. * rtl-error.c: Moved to... * rtl-error.cc: ...here. * rtl-tests.c: Moved to... * rtl-tests.cc: ...here. * rtl.c: Moved to... * rtl.cc: ...here. * rtlanal.c: Moved to... * rtlanal.cc: ...here. * rtlhash.c: Moved to... * rtlhash.cc: ...here. * rtlhooks.c: Moved to... * rtlhooks.cc: ...here. * rtx-vector-builder.c: Moved to... * rtx-vector-builder.cc: ...here. * run-rtl-passes.c: Moved to... * run-rtl-passes.cc: ...here. * sancov.c: Moved to... * sancov.cc: ...here. * sanopt.c: Moved to... * sanopt.cc: ...here. * sbitmap.c: Moved to... * sbitmap.cc: ...here. * sched-deps.c: Moved to... * sched-deps.cc: ...here. * sched-ebb.c: Moved to... * sched-ebb.cc: ...here. * sched-rgn.c: Moved to... * sched-rgn.cc: ...here. * sel-sched-dump.c: Moved to... * sel-sched-dump.cc: ...here. * sel-sched-ir.c: Moved to... * sel-sched-ir.cc: ...here. * sel-sched.c: Moved to... * sel-sched.cc: ...here. * selftest-diagnostic.c: Moved to... * selftest-diagnostic.cc: ...here. * selftest-rtl.c: Moved to... * selftest-rtl.cc: ...here. * selftest-run-tests.c: Moved to... * selftest-run-tests.cc: ...here. * selftest.c: Moved to... * selftest.cc: ...here. * sese.c: Moved to... * sese.cc: ...here. * shrink-wrap.c: Moved to... * shrink-wrap.cc: ...here. * simplify-rtx.c: Moved to... * simplify-rtx.cc: ...here. * sparseset.c: Moved to... * sparseset.cc: ...here. * spellcheck-tree.c: Moved to... * spellcheck-tree.cc: ...here. * spellcheck.c: Moved to... * spellcheck.cc: ...here. * sreal.c: Moved to... * sreal.cc: ...here. * stack-ptr-mod.c: Moved to... * stack-ptr-mod.cc: ...here. * statistics.c: Moved to... * statistics.cc: ...here. * stmt.c: Moved to... * stmt.cc: ...here. * stor-layout.c: Moved to... * stor-layout.cc: ...here. * store-motion.c: Moved to... * store-motion.cc: ...here. * streamer-hooks.c: Moved to... * streamer-hooks.cc: ...here. * stringpool.c: Moved to... * stringpool.cc: ...here. * substring-locations.c: Moved to... * substring-locations.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * target-globals.c: Moved to... * target-globals.cc: ...here. * targhooks.c: Moved to... * targhooks.cc: ...here. * timevar.c: Moved to... * timevar.cc: ...here. * toplev.c: Moved to... * toplev.cc: ...here. * tracer.c: Moved to... * tracer.cc: ...here. * trans-mem.c: Moved to... * trans-mem.cc: ...here. * tree-affine.c: Moved to... * tree-affine.cc: ...here. * tree-call-cdce.c: Moved to... * tree-call-cdce.cc: ...here. * tree-cfg.c: Moved to... * tree-cfg.cc: ...here. * tree-cfgcleanup.c: Moved to... * tree-cfgcleanup.cc: ...here. * tree-chrec.c: Moved to... * tree-chrec.cc: ...here. * tree-complex.c: Moved to... * tree-complex.cc: ...here. * tree-data-ref.c: Moved to... * tree-data-ref.cc: ...here. * tree-dfa.c: Moved to... * tree-dfa.cc: ...here. * tree-diagnostic.c: Moved to... * tree-diagnostic.cc: ...here. * tree-dump.c: Moved to... * tree-dump.cc: ...here. * tree-eh.c: Moved to... * tree-eh.cc: ...here. * tree-emutls.c: Moved to... * tree-emutls.cc: ...here. * tree-if-conv.c: Moved to... * tree-if-conv.cc: ...here. * tree-inline.c: Moved to... * tree-inline.cc: ...here. * tree-into-ssa.c: Moved to... * tree-into-ssa.cc: ...here. * tree-iterator.c: Moved to... * tree-iterator.cc: ...here. * tree-loop-distribution.c: Moved to... * tree-loop-distribution.cc: ...here. * tree-nested.c: Moved to... * tree-nested.cc: ...here. * tree-nrv.c: Moved to... * tree-nrv.cc: ...here. * tree-object-size.c: Moved to... * tree-object-size.cc: ...here. * tree-outof-ssa.c: Moved to... * tree-outof-ssa.cc: ...here. * tree-parloops.c: Moved to... * tree-parloops.cc: ...here. * tree-phinodes.c: Moved to... * tree-phinodes.cc: ...here. * tree-predcom.c: Moved to... * tree-predcom.cc: ...here. * tree-pretty-print.c: Moved to... * tree-pretty-print.cc: ...here. * tree-profile.c: Moved to... * tree-profile.cc: ...here. * tree-scalar-evolution.c: Moved to... * tree-scalar-evolution.cc: ...here. * tree-sra.c: Moved to... * tree-sra.cc: ...here. * tree-ssa-address.c: Moved to... * tree-ssa-address.cc: ...here. * tree-ssa-alias.c: Moved to... * tree-ssa-alias.cc: ...here. * tree-ssa-ccp.c: Moved to... * tree-ssa-ccp.cc: ...here. * tree-ssa-coalesce.c: Moved to... * tree-ssa-coalesce.cc: ...here. * tree-ssa-copy.c: Moved to... * tree-ssa-copy.cc: ...here. * tree-ssa-dce.c: Moved to... * tree-ssa-dce.cc: ...here. * tree-ssa-dom.c: Moved to... * tree-ssa-dom.cc: ...here. * tree-ssa-dse.c: Moved to... * tree-ssa-dse.cc: ...here. * tree-ssa-forwprop.c: Moved to... * tree-ssa-forwprop.cc: ...here. * tree-ssa-ifcombine.c: Moved to... * tree-ssa-ifcombine.cc: ...here. * tree-ssa-live.c: Moved to... * tree-ssa-live.cc: ...here. * tree-ssa-loop-ch.c: Moved to... * tree-ssa-loop-ch.cc: ...here. * tree-ssa-loop-im.c: Moved to... * tree-ssa-loop-im.cc: ...here. * tree-ssa-loop-ivcanon.c: Moved to... * tree-ssa-loop-ivcanon.cc: ...here. * tree-ssa-loop-ivopts.c: Moved to... * tree-ssa-loop-ivopts.cc: ...here. * tree-ssa-loop-manip.c: Moved to... * tree-ssa-loop-manip.cc: ...here. * tree-ssa-loop-niter.c: Moved to... * tree-ssa-loop-niter.cc: ...here. * tree-ssa-loop-prefetch.c: Moved to... * tree-ssa-loop-prefetch.cc: ...here. * tree-ssa-loop-split.c: Moved to... * tree-ssa-loop-split.cc: ...here. * tree-ssa-loop-unswitch.c: Moved to... * tree-ssa-loop-unswitch.cc: ...here. * tree-ssa-loop.c: Moved to... * tree-ssa-loop.cc: ...here. * tree-ssa-math-opts.c: Moved to... * tree-ssa-math-opts.cc: ...here. * tree-ssa-operands.c: Moved to... * tree-ssa-operands.cc: ...here. * tree-ssa-phiopt.c: Moved to... * tree-ssa-phiopt.cc: ...here. * tree-ssa-phiprop.c: Moved to... * tree-ssa-phiprop.cc: ...here. * tree-ssa-pre.c: Moved to... * tree-ssa-pre.cc: ...here. * tree-ssa-propagate.c: Moved to... * tree-ssa-propagate.cc: ...here. * tree-ssa-reassoc.c: Moved to... * tree-ssa-reassoc.cc: ...here. * tree-ssa-sccvn.c: Moved to... * tree-ssa-sccvn.cc: ...here. * tree-ssa-scopedtables.c: Moved to... * tree-ssa-scopedtables.cc: ...here. * tree-ssa-sink.c: Moved to... * tree-ssa-sink.cc: ...here. * tree-ssa-strlen.c: Moved to... * tree-ssa-strlen.cc: ...here. * tree-ssa-structalias.c: Moved to... * tree-ssa-structalias.cc: ...here. * tree-ssa-tail-merge.c: Moved to... * tree-ssa-tail-merge.cc: ...here. * tree-ssa-ter.c: Moved to... * tree-ssa-ter.cc: ...here. * tree-ssa-threadbackward.c: Moved to... * tree-ssa-threadbackward.cc: ...here. * tree-ssa-threadedge.c: Moved to... * tree-ssa-threadedge.cc: ...here. * tree-ssa-threadupdate.c: Moved to... * tree-ssa-threadupdate.cc: ...here. * tree-ssa-uncprop.c: Moved to... * tree-ssa-uncprop.cc: ...here. * tree-ssa-uninit.c: Moved to... * tree-ssa-uninit.cc: ...here. * tree-ssa.c: Moved to... * tree-ssa.cc: ...here. * tree-ssanames.c: Moved to... * tree-ssanames.cc: ...here. * tree-stdarg.c: Moved to... * tree-stdarg.cc: ...here. * tree-streamer-in.c: Moved to... * tree-streamer-in.cc: ...here. * tree-streamer-out.c: Moved to... * tree-streamer-out.cc: ...here. * tree-streamer.c: Moved to... * tree-streamer.cc: ...here. * tree-switch-conversion.c: Moved to... * tree-switch-conversion.cc: ...here. * tree-tailcall.c: Moved to... * tree-tailcall.cc: ...here. * tree-vect-data-refs.c: Moved to... * tree-vect-data-refs.cc: ...here. * tree-vect-generic.c: Moved to... * tree-vect-generic.cc: ...here. * tree-vect-loop-manip.c: Moved to... * tree-vect-loop-manip.cc: ...here. * tree-vect-loop.c: Moved to... * tree-vect-loop.cc: ...here. * tree-vect-patterns.c: Moved to... * tree-vect-patterns.cc: ...here. * tree-vect-slp-patterns.c: Moved to... * tree-vect-slp-patterns.cc: ...here. * tree-vect-slp.c: Moved to... * tree-vect-slp.cc: ...here. * tree-vect-stmts.c: Moved to... * tree-vect-stmts.cc: ...here. * tree-vector-builder.c: Moved to... * tree-vector-builder.cc: ...here. * tree-vectorizer.c: Moved to... * tree-vectorizer.cc: ...here. * tree-vrp.c: Moved to... * tree-vrp.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * tsan.c: Moved to... * tsan.cc: ...here. * typed-splay-tree.c: Moved to... * typed-splay-tree.cc: ...here. * ubsan.c: Moved to... * ubsan.cc: ...here. * valtrack.c: Moved to... * valtrack.cc: ...here. * value-prof.c: Moved to... * value-prof.cc: ...here. * var-tracking.c: Moved to... * var-tracking.cc: ...here. * varasm.c: Moved to... * varasm.cc: ...here. * varpool.c: Moved to... * varpool.cc: ...here. * vec-perm-indices.c: Moved to... * vec-perm-indices.cc: ...here. * vec.c: Moved to... * vec.cc: ...here. * vmsdbgout.c: Moved to... * vmsdbgout.cc: ...here. * vr-values.c: Moved to... * vr-values.cc: ...here. * vtable-verify.c: Moved to... * vtable-verify.cc: ...here. * web.c: Moved to... * web.cc: ...here. * xcoffout.c: Moved to... * xcoffout.cc: ...here. gcc/c-family/ChangeLog: * c-ada-spec.c: Moved to... * c-ada-spec.cc: ...here. * c-attribs.c: Moved to... * c-attribs.cc: ...here. * c-common.c: Moved to... * c-common.cc: ...here. * c-cppbuiltin.c: Moved to... * c-cppbuiltin.cc: ...here. * c-dump.c: Moved to... * c-dump.cc: ...here. * c-format.c: Moved to... * c-format.cc: ...here. * c-gimplify.c: Moved to... * c-gimplify.cc: ...here. * c-indentation.c: Moved to... * c-indentation.cc: ...here. * c-lex.c: Moved to... * c-lex.cc: ...here. * c-omp.c: Moved to... * c-omp.cc: ...here. * c-opts.c: Moved to... * c-opts.cc: ...here. * c-pch.c: Moved to... * c-pch.cc: ...here. * c-ppoutput.c: Moved to... * c-ppoutput.cc: ...here. * c-pragma.c: Moved to... * c-pragma.cc: ...here. * c-pretty-print.c: Moved to... * c-pretty-print.cc: ...here. * c-semantics.c: Moved to... * c-semantics.cc: ...here. * c-ubsan.c: Moved to... * c-ubsan.cc: ...here. * c-warn.c: Moved to... * c-warn.cc: ...here. * cppspec.c: Moved to... * cppspec.cc: ...here. * stub-objc.c: Moved to... * stub-objc.cc: ...here. gcc/c/ChangeLog: * c-aux-info.c: Moved to... * c-aux-info.cc: ...here. * c-convert.c: Moved to... * c-convert.cc: ...here. * c-decl.c: Moved to... * c-decl.cc: ...here. * c-errors.c: Moved to... * c-errors.cc: ...here. * c-fold.c: Moved to... * c-fold.cc: ...here. * c-lang.c: Moved to... * c-lang.cc: ...here. * c-objc-common.c: Moved to... * c-objc-common.cc: ...here. * c-parser.c: Moved to... * c-parser.cc: ...here. * c-typeck.c: Moved to... * c-typeck.cc: ...here. * gccspec.c: Moved to... * gccspec.cc: ...here. * gimple-parser.c: Moved to... * gimple-parser.cc: ...here. gcc/cp/ChangeLog: * call.c: Moved to... * call.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constexpr.c: Moved to... * constexpr.cc: ...here. * cp-gimplify.c: Moved to... * cp-gimplify.cc: ...here. * cp-lang.c: Moved to... * cp-lang.cc: ...here. * cp-objcp-common.c: Moved to... * cp-objcp-common.cc: ...here. * cp-ubsan.c: Moved to... * cp-ubsan.cc: ...here. * cvt.c: Moved to... * cvt.cc: ...here. * cxx-pretty-print.c: Moved to... * cxx-pretty-print.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * decl2.c: Moved to... * decl2.cc: ...here. * dump.c: Moved to... * dump.cc: ...here. * error.c: Moved to... * error.cc: ...here. * except.c: Moved to... * except.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * friend.c: Moved to... * friend.cc: ...here. * g++spec.c: Moved to... * g++spec.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lambda.c: Moved to... * lambda.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * mangle.c: Moved to... * mangle.cc: ...here. * method.c: Moved to... * method.cc: ...here. * name-lookup.c: Moved to... * name-lookup.cc: ...here. * optimize.c: Moved to... * optimize.cc: ...here. * parser.c: Moved to... * parser.cc: ...here. * pt.c: Moved to... * pt.cc: ...here. * ptree.c: Moved to... * ptree.cc: ...here. * rtti.c: Moved to... * rtti.cc: ...here. * search.c: Moved to... * search.cc: ...here. * semantics.c: Moved to... * semantics.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * typeck.c: Moved to... * typeck.cc: ...here. * typeck2.c: Moved to... * typeck2.cc: ...here. * vtable-class-hierarchy.c: Moved to... * vtable-class-hierarchy.cc: ...here. gcc/fortran/ChangeLog: * arith.c: Moved to... * arith.cc: ...here. * array.c: Moved to... * array.cc: ...here. * bbt.c: Moved to... * bbt.cc: ...here. * check.c: Moved to... * check.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constructor.c: Moved to... * constructor.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * cpp.c: Moved to... * cpp.cc: ...here. * data.c: Moved to... * data.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * dependency.c: Moved to... * dependency.cc: ...here. * dump-parse-tree.c: Moved to... * dump-parse-tree.cc: ...here. * error.c: Moved to... * error.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * f95-lang.c: Moved to... * f95-lang.cc: ...here. * frontend-passes.c: Moved to... * frontend-passes.cc: ...here. * gfortranspec.c: Moved to... * gfortranspec.cc: ...here. * interface.c: Moved to... * interface.cc: ...here. * intrinsic.c: Moved to... * intrinsic.cc: ...here. * io.c: Moved to... * io.cc: ...here. * iresolve.c: Moved to... * iresolve.cc: ...here. * match.c: Moved to... * match.cc: ...here. * matchexp.c: Moved to... * matchexp.cc: ...here. * misc.c: Moved to... * misc.cc: ...here. * module.c: Moved to... * module.cc: ...here. * openmp.c: Moved to... * openmp.cc: ...here. * options.c: Moved to... * options.cc: ...here. * parse.c: Moved to... * parse.cc: ...here. * primary.c: Moved to... * primary.cc: ...here. * resolve.c: Moved to... * resolve.cc: ...here. * scanner.c: Moved to... * scanner.cc: ...here. * simplify.c: Moved to... * simplify.cc: ...here. * st.c: Moved to... * st.cc: ...here. * symbol.c: Moved to... * symbol.cc: ...here. * target-memory.c: Moved to... * target-memory.cc: ...here. * trans-array.c: Moved to... * trans-array.cc: ...here. * trans-common.c: Moved to... * trans-common.cc: ...here. * trans-const.c: Moved to... * trans-const.cc: ...here. * trans-decl.c: Moved to... * trans-decl.cc: ...here. * trans-expr.c: Moved to... * trans-expr.cc: ...here. * trans-intrinsic.c: Moved to... * trans-intrinsic.cc: ...here. * trans-io.c: Moved to... * trans-io.cc: ...here. * trans-openmp.c: Moved to... * trans-openmp.cc: ...here. * trans-stmt.c: Moved to... * trans-stmt.cc: ...here. * trans-types.c: Moved to... * trans-types.cc: ...here. * trans.c: Moved to... * trans.cc: ...here. gcc/go/ChangeLog: * go-backend.c: Moved to... * go-backend.cc: ...here. * go-lang.c: Moved to... * go-lang.cc: ...here. * gospec.c: Moved to... * gospec.cc: ...here. gcc/jit/ChangeLog: * dummy-frontend.c: Moved to... * dummy-frontend.cc: ...here. * jit-builtins.c: Moved to... * jit-builtins.cc: ...here. * jit-logging.c: Moved to... * jit-logging.cc: ...here. * jit-playback.c: Moved to... * jit-playback.cc: ...here. * jit-recording.c: Moved to... * jit-recording.cc: ...here. * jit-result.c: Moved to... * jit-result.cc: ...here. * jit-spec.c: Moved to... * jit-spec.cc: ...here. * jit-tempdir.c: Moved to... * jit-tempdir.cc: ...here. * jit-w32.c: Moved to... * jit-w32.cc: ...here. * libgccjit.c: Moved to... * libgccjit.cc: ...here. gcc/lto/ChangeLog: * common.c: Moved to... * common.cc: ...here. * lto-common.c: Moved to... * lto-common.cc: ...here. * lto-dump.c: Moved to... * lto-dump.cc: ...here. * lto-lang.c: Moved to... * lto-lang.cc: ...here. * lto-object.c: Moved to... * lto-object.cc: ...here. * lto-partition.c: Moved to... * lto-partition.cc: ...here. * lto-symtab.c: Moved to... * lto-symtab.cc: ...here. * lto.c: Moved to... * lto.cc: ...here. gcc/objc/ChangeLog: * objc-act.c: Moved to... * objc-act.cc: ...here. * objc-encoding.c: Moved to... * objc-encoding.cc: ...here. * objc-gnu-runtime-abi-01.c: Moved to... * objc-gnu-runtime-abi-01.cc: ...here. * objc-lang.c: Moved to... * objc-lang.cc: ...here. * objc-map.c: Moved to... * objc-map.cc: ...here. * objc-next-runtime-abi-01.c: Moved to... * objc-next-runtime-abi-01.cc: ...here. * objc-next-runtime-abi-02.c: Moved to... * objc-next-runtime-abi-02.cc: ...here. * objc-runtime-shared-support.c: Moved to... * objc-runtime-shared-support.cc: ...here. gcc/objcp/ChangeLog: * objcp-decl.c: Moved to... * objcp-decl.cc: ...here. * objcp-lang.c: Moved to... * objcp-lang.cc: ...here. libcpp/ChangeLog: * charset.c: Moved to... * charset.cc: ...here. * directives.c: Moved to... * directives.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * files.c: Moved to... * files.cc: ...here. * identifiers.c: Moved to... * identifiers.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * line-map.c: Moved to... * line-map.cc: ...here. * macro.c: Moved to... * macro.cc: ...here. * makeucnid.c: Moved to... * makeucnid.cc: ...here. * mkdeps.c: Moved to... * mkdeps.cc: ...here. * pch.c: Moved to... * pch.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * traditional.c: Moved to... * traditional.cc: ...here.
Diffstat (limited to 'gcc/ipa-modref.c')
-rw-r--r--gcc/ipa-modref.c5509
1 files changed, 0 insertions, 5509 deletions
diff --git a/gcc/ipa-modref.c b/gcc/ipa-modref.c
deleted file mode 100644
index 866cc42..0000000
--- a/gcc/ipa-modref.c
+++ /dev/null
@@ -1,5509 +0,0 @@
-/* Search for references that a functions loads or stores.
- Copyright (C) 2020-2022 Free Software Foundation, Inc.
- Contributed by David Cepelik and Jan Hubicka
-
-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/>. */
-
-/* Mod/ref pass records summary about loads and stores performed by the
- function. This is later used by alias analysis to disambiguate memory
- accesses across function calls.
-
- This file contains a tree pass and an IPA pass. Both performs the same
- analysis however tree pass is executed during early and late optimization
- passes to propagate info downwards in the compilation order. IPA pass
- propagates across the callgraph and is able to handle recursion and works on
- whole program during link-time analysis.
-
- LTO mode differs from the local mode by not recording alias sets but types
- that are translated to alias sets later. This is necessary in order stream
- the information because the alias sets are rebuild at stream-in time and may
- not correspond to ones seen during analysis. For this reason part of
- analysis is duplicated.
-
- The following information is computed
- 1) load/store access tree described in ipa-modref-tree.h
- This is used by tree-ssa-alias to disambiguate load/stores
- 2) EAF flags used by points-to analysis (in tree-ssa-structlias).
- and defined in tree-core.h.
- and stored to optimization_summaries.
-
- There are multiple summaries computed and used during the propagation:
- - summaries holds summaries from analysis to IPA propagation
- time.
- - summaries_lto is same as summaries but holds them in a format
- that can be streamed (as described above).
- - fnspec_summary holds fnspec strings for call. This is
- necessary because gimple_call_fnspec performs additional
- analysis except for looking callee fndecl.
- - escape_summary holds escape points for given call edge.
- That is a vector recording what function parmaeters
- may escape to a function call (and with what parameter index). */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "tree.h"
-#include "gimple.h"
-#include "alloc-pool.h"
-#include "tree-pass.h"
-#include "gimple-iterator.h"
-#include "tree-dfa.h"
-#include "cgraph.h"
-#include "ipa-utils.h"
-#include "symbol-summary.h"
-#include "gimple-pretty-print.h"
-#include "gimple-walk.h"
-#include "print-tree.h"
-#include "tree-streamer.h"
-#include "alias.h"
-#include "calls.h"
-#include "ipa-modref-tree.h"
-#include "ipa-modref.h"
-#include "value-range.h"
-#include "ipa-prop.h"
-#include "ipa-fnsummary.h"
-#include "attr-fnspec.h"
-#include "symtab-clones.h"
-#include "gimple-ssa.h"
-#include "tree-phinodes.h"
-#include "tree-ssa-operands.h"
-#include "ssa-iterators.h"
-#include "stringpool.h"
-#include "tree-ssanames.h"
-#include "attribs.h"
-#include "tree-cfg.h"
-#include "tree-eh.h"
-
-
-namespace {
-
-/* We record fnspec specifiers for call edges since they depends on actual
- gimple statements. */
-
-class fnspec_summary
-{
-public:
- char *fnspec;
-
- fnspec_summary ()
- : fnspec (NULL)
- {
- }
-
- ~fnspec_summary ()
- {
- free (fnspec);
- }
-};
-
-/* Summary holding fnspec string for a given call. */
-
-class fnspec_summaries_t : public call_summary <fnspec_summary *>
-{
-public:
- fnspec_summaries_t (symbol_table *symtab)
- : call_summary <fnspec_summary *> (symtab) {}
- /* Hook that is called by summary when an edge is duplicated. */
- virtual void duplicate (cgraph_edge *,
- cgraph_edge *,
- fnspec_summary *src,
- fnspec_summary *dst)
- {
- dst->fnspec = xstrdup (src->fnspec);
- }
-};
-
-static fnspec_summaries_t *fnspec_summaries = NULL;
-
-/* Escape summary holds a vector of param indexes that escape to
- a given call. */
-struct escape_entry
-{
- /* Parameter that escapes at a given call. */
- int parm_index;
- /* Argument it escapes to. */
- unsigned int arg;
- /* Minimal flags known about the argument. */
- eaf_flags_t min_flags;
- /* Does it escape directly or indirectly? */
- bool direct;
-};
-
-/* Dump EAF flags. */
-
-static void
-dump_eaf_flags (FILE *out, int flags, bool newline = true)
-{
- if (flags & EAF_UNUSED)
- fprintf (out, " unused");
- if (flags & EAF_NO_DIRECT_CLOBBER)
- fprintf (out, " no_direct_clobber");
- if (flags & EAF_NO_INDIRECT_CLOBBER)
- fprintf (out, " no_indirect_clobber");
- if (flags & EAF_NO_DIRECT_ESCAPE)
- fprintf (out, " no_direct_escape");
- if (flags & EAF_NO_INDIRECT_ESCAPE)
- fprintf (out, " no_indirect_escape");
- if (flags & EAF_NOT_RETURNED_DIRECTLY)
- fprintf (out, " not_returned_directly");
- if (flags & EAF_NOT_RETURNED_INDIRECTLY)
- fprintf (out, " not_returned_indirectly");
- if (flags & EAF_NO_DIRECT_READ)
- fprintf (out, " no_direct_read");
- if (flags & EAF_NO_INDIRECT_READ)
- fprintf (out, " no_indirect_read");
- if (newline)
- fprintf (out, "\n");
-}
-
-struct escape_summary
-{
- auto_vec <escape_entry> esc;
- void dump (FILE *out)
- {
- for (unsigned int i = 0; i < esc.length (); i++)
- {
- fprintf (out, " parm %i arg %i %s min:",
- esc[i].parm_index,
- esc[i].arg,
- esc[i].direct ? "(direct)" : "(indirect)");
- dump_eaf_flags (out, esc[i].min_flags, false);
- }
- fprintf (out, "\n");
- }
-};
-
-class escape_summaries_t : public call_summary <escape_summary *>
-{
-public:
- escape_summaries_t (symbol_table *symtab)
- : call_summary <escape_summary *> (symtab) {}
- /* Hook that is called by summary when an edge is duplicated. */
- virtual void duplicate (cgraph_edge *,
- cgraph_edge *,
- escape_summary *src,
- escape_summary *dst)
- {
- dst->esc = src->esc.copy ();
- }
-};
-
-static escape_summaries_t *escape_summaries = NULL;
-
-} /* ANON namespace: GTY annotated summaries can not be anonymous. */
-
-
-/* Class (from which there is one global instance) that holds modref summaries
- for all analyzed functions. */
-
-class GTY((user)) modref_summaries
- : public fast_function_summary <modref_summary *, va_gc>
-{
-public:
- modref_summaries (symbol_table *symtab)
- : fast_function_summary <modref_summary *, va_gc> (symtab) {}
- virtual void insert (cgraph_node *, modref_summary *state);
- virtual void duplicate (cgraph_node *src_node,
- cgraph_node *dst_node,
- modref_summary *src_data,
- modref_summary *dst_data);
- static modref_summaries *create_ggc (symbol_table *symtab)
- {
- return new (ggc_alloc_no_dtor<modref_summaries> ())
- modref_summaries (symtab);
- }
-};
-
-class modref_summary_lto;
-
-/* Class (from which there is one global instance) that holds modref summaries
- for all analyzed functions. */
-
-class GTY((user)) modref_summaries_lto
- : public fast_function_summary <modref_summary_lto *, va_gc>
-{
-public:
- modref_summaries_lto (symbol_table *symtab)
- : fast_function_summary <modref_summary_lto *, va_gc> (symtab),
- propagated (false) {}
- virtual void insert (cgraph_node *, modref_summary_lto *state);
- virtual void duplicate (cgraph_node *src_node,
- cgraph_node *dst_node,
- modref_summary_lto *src_data,
- modref_summary_lto *dst_data);
- static modref_summaries_lto *create_ggc (symbol_table *symtab)
- {
- return new (ggc_alloc_no_dtor<modref_summaries_lto> ())
- modref_summaries_lto (symtab);
- }
- bool propagated;
-};
-
-/* Global variable holding all modref summaries
- (from analysis to IPA propagation time). */
-
-static GTY(()) fast_function_summary <modref_summary *, va_gc>
- *summaries;
-
-/* Global variable holding all modref optimization summaries
- (from IPA propagation time or used by local optimization pass). */
-
-static GTY(()) fast_function_summary <modref_summary *, va_gc>
- *optimization_summaries;
-
-/* LTO summaries hold info from analysis to LTO streaming or from LTO
- stream-in through propagation to LTO stream-out. */
-
-static GTY(()) fast_function_summary <modref_summary_lto *, va_gc>
- *summaries_lto;
-
-/* Summary for a single function which this pass produces. */
-
-modref_summary::modref_summary ()
- : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
- writes_errno (false), side_effects (false), nondeterministic (false),
- calls_interposable (false), global_memory_read (false),
- global_memory_written (false), try_dse (false)
-{
-}
-
-modref_summary::~modref_summary ()
-{
- if (loads)
- ggc_delete (loads);
- if (stores)
- ggc_delete (stores);
-}
-
-/* Remove all flags from EAF_FLAGS that are implied by ECF_FLAGS and not
- useful to track. If returns_void is true moreover clear
- EAF_NOT_RETURNED. */
-static int
-remove_useless_eaf_flags (int eaf_flags, int ecf_flags, bool returns_void)
-{
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
- eaf_flags &= ~implicit_const_eaf_flags;
- else if (ecf_flags & ECF_PURE)
- eaf_flags &= ~implicit_pure_eaf_flags;
- else if ((ecf_flags & ECF_NORETURN) || returns_void)
- eaf_flags &= ~(EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY);
- return eaf_flags;
-}
-
-/* Return true if FLAGS holds some useful information. */
-
-static bool
-eaf_flags_useful_p (vec <eaf_flags_t> &flags, int ecf_flags)
-{
- for (unsigned i = 0; i < flags.length (); i++)
- if (remove_useless_eaf_flags (flags[i], ecf_flags, false))
- return true;
- return false;
-}
-
-/* Return true if summary is potentially useful for optimization.
- If CHECK_FLAGS is false assume that arg_flags are useful. */
-
-bool
-modref_summary::useful_p (int ecf_flags, bool check_flags)
-{
- if (arg_flags.length () && !check_flags)
- return true;
- if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
- return true;
- arg_flags.release ();
- if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
- return true;
- if (check_flags
- && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
- return true;
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
- return ((!side_effects || !nondeterministic)
- && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
- if (loads && !loads->every_base)
- return true;
- else
- kills.release ();
- if (ecf_flags & ECF_PURE)
- return ((!side_effects || !nondeterministic)
- && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
- return stores && !stores->every_base;
-}
-
-/* Single function summary used for LTO. */
-
-typedef modref_tree <tree> modref_records_lto;
-struct GTY(()) modref_summary_lto
-{
- /* Load and stores in functions using types rather then alias sets.
-
- This is necessary to make the information streamable for LTO but is also
- more verbose and thus more likely to hit the limits. */
- modref_records_lto *loads;
- modref_records_lto *stores;
- auto_vec<modref_access_node> GTY((skip)) kills;
- auto_vec<eaf_flags_t> GTY((skip)) arg_flags;
- eaf_flags_t retslot_flags;
- eaf_flags_t static_chain_flags;
- unsigned writes_errno : 1;
- unsigned side_effects : 1;
- unsigned nondeterministic : 1;
- unsigned calls_interposable : 1;
-
- modref_summary_lto ();
- ~modref_summary_lto ();
- void dump (FILE *);
- bool useful_p (int ecf_flags, bool check_flags = true);
-};
-
-/* Summary for a single function which this pass produces. */
-
-modref_summary_lto::modref_summary_lto ()
- : loads (NULL), stores (NULL), retslot_flags (0), static_chain_flags (0),
- writes_errno (false), side_effects (false), nondeterministic (false),
- calls_interposable (false)
-{
-}
-
-modref_summary_lto::~modref_summary_lto ()
-{
- if (loads)
- ggc_delete (loads);
- if (stores)
- ggc_delete (stores);
-}
-
-
-/* Return true if lto summary is potentially useful for optimization.
- If CHECK_FLAGS is false assume that arg_flags are useful. */
-
-bool
-modref_summary_lto::useful_p (int ecf_flags, bool check_flags)
-{
- if (arg_flags.length () && !check_flags)
- return true;
- if (check_flags && eaf_flags_useful_p (arg_flags, ecf_flags))
- return true;
- arg_flags.release ();
- if (check_flags && remove_useless_eaf_flags (retslot_flags, ecf_flags, false))
- return true;
- if (check_flags
- && remove_useless_eaf_flags (static_chain_flags, ecf_flags, false))
- return true;
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
- return ((!side_effects || !nondeterministic)
- && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
- if (loads && !loads->every_base)
- return true;
- else
- kills.release ();
- if (ecf_flags & ECF_PURE)
- return ((!side_effects || !nondeterministic)
- && (ecf_flags & ECF_LOOPING_CONST_OR_PURE));
- return stores && !stores->every_base;
-}
-
-/* Dump records TT to OUT. */
-
-static void
-dump_records (modref_records *tt, FILE *out)
-{
- if (tt->every_base)
- {
- fprintf (out, " Every base\n");
- return;
- }
- size_t i;
- modref_base_node <alias_set_type> *n;
- FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
- {
- fprintf (out, " Base %i: alias set %i\n", (int)i, n->base);
- if (n->every_ref)
- {
- fprintf (out, " Every ref\n");
- continue;
- }
- size_t j;
- modref_ref_node <alias_set_type> *r;
- FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
- {
- fprintf (out, " Ref %i: alias set %i\n", (int)j, r->ref);
- if (r->every_access)
- {
- fprintf (out, " Every access\n");
- continue;
- }
- size_t k;
- modref_access_node *a;
- FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
- {
- fprintf (out, " access:");
- a->dump (out);
- }
- }
- }
-}
-
-/* Dump records TT to OUT. */
-
-static void
-dump_lto_records (modref_records_lto *tt, FILE *out)
-{
- if (tt->every_base)
- {
- fprintf (out, " Every base\n");
- return;
- }
- size_t i;
- modref_base_node <tree> *n;
- FOR_EACH_VEC_SAFE_ELT (tt->bases, i, n)
- {
- fprintf (out, " Base %i:", (int)i);
- print_generic_expr (dump_file, n->base);
- fprintf (out, " (alias set %i)\n",
- n->base ? get_alias_set (n->base) : 0);
- if (n->every_ref)
- {
- fprintf (out, " Every ref\n");
- continue;
- }
- size_t j;
- modref_ref_node <tree> *r;
- FOR_EACH_VEC_SAFE_ELT (n->refs, j, r)
- {
- fprintf (out, " Ref %i:", (int)j);
- print_generic_expr (dump_file, r->ref);
- fprintf (out, " (alias set %i)\n",
- r->ref ? get_alias_set (r->ref) : 0);
- if (r->every_access)
- {
- fprintf (out, " Every access\n");
- continue;
- }
- size_t k;
- modref_access_node *a;
- FOR_EACH_VEC_SAFE_ELT (r->accesses, k, a)
- {
- fprintf (out, " access:");
- a->dump (out);
- }
- }
- }
-}
-
-/* Dump all escape points of NODE to OUT. */
-
-static void
-dump_modref_edge_summaries (FILE *out, cgraph_node *node, int depth)
-{
- int i = 0;
- if (!escape_summaries)
- return;
- for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
- {
- class escape_summary *sum = escape_summaries->get (e);
- if (sum)
- {
- fprintf (out, "%*sIndirect call %i in %s escapes:",
- depth, "", i, node->dump_name ());
- sum->dump (out);
- }
- i++;
- }
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- {
- if (!e->inline_failed)
- dump_modref_edge_summaries (out, e->callee, depth + 1);
- class escape_summary *sum = escape_summaries->get (e);
- if (sum)
- {
- fprintf (out, "%*sCall %s->%s escapes:", depth, "",
- node->dump_name (), e->callee->dump_name ());
- sum->dump (out);
- }
- class fnspec_summary *fsum = fnspec_summaries->get (e);
- if (fsum)
- {
- fprintf (out, "%*sCall %s->%s fnspec: %s\n", depth, "",
- node->dump_name (), e->callee->dump_name (),
- fsum->fnspec);
- }
- }
-}
-
-/* Remove all call edge summaries associated with NODE. */
-
-static void
-remove_modref_edge_summaries (cgraph_node *node)
-{
- if (!escape_summaries)
- return;
- for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
- escape_summaries->remove (e);
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- {
- if (!e->inline_failed)
- remove_modref_edge_summaries (e->callee);
- escape_summaries->remove (e);
- fnspec_summaries->remove (e);
- }
-}
-
-/* Dump summary. */
-
-void
-modref_summary::dump (FILE *out)
-{
- if (loads)
- {
- fprintf (out, " loads:\n");
- dump_records (loads, out);
- }
- if (stores)
- {
- fprintf (out, " stores:\n");
- dump_records (stores, out);
- }
- if (kills.length ())
- {
- fprintf (out, " kills:\n");
- for (auto kill : kills)
- {
- fprintf (out, " ");
- kill.dump (out);
- }
- }
- if (writes_errno)
- fprintf (out, " Writes errno\n");
- if (side_effects)
- fprintf (out, " Side effects\n");
- if (nondeterministic)
- fprintf (out, " Nondeterministic\n");
- if (calls_interposable)
- fprintf (out, " Calls interposable\n");
- if (global_memory_read)
- fprintf (out, " Global memory read\n");
- if (global_memory_written)
- fprintf (out, " Global memory written\n");
- if (try_dse)
- fprintf (out, " Try dse\n");
- if (arg_flags.length ())
- {
- for (unsigned int i = 0; i < arg_flags.length (); i++)
- if (arg_flags[i])
- {
- fprintf (out, " parm %i flags:", i);
- dump_eaf_flags (out, arg_flags[i]);
- }
- }
- if (retslot_flags)
- {
- fprintf (out, " Retslot flags:");
- dump_eaf_flags (out, retslot_flags);
- }
- if (static_chain_flags)
- {
- fprintf (out, " Static chain flags:");
- dump_eaf_flags (out, static_chain_flags);
- }
-}
-
-/* Dump summary. */
-
-void
-modref_summary_lto::dump (FILE *out)
-{
- fprintf (out, " loads:\n");
- dump_lto_records (loads, out);
- fprintf (out, " stores:\n");
- dump_lto_records (stores, out);
- if (kills.length ())
- {
- fprintf (out, " kills:\n");
- for (auto kill : kills)
- {
- fprintf (out, " ");
- kill.dump (out);
- }
- }
- if (writes_errno)
- fprintf (out, " Writes errno\n");
- if (side_effects)
- fprintf (out, " Side effects\n");
- if (nondeterministic)
- fprintf (out, " Nondeterministic\n");
- if (calls_interposable)
- fprintf (out, " Calls interposable\n");
- if (arg_flags.length ())
- {
- for (unsigned int i = 0; i < arg_flags.length (); i++)
- if (arg_flags[i])
- {
- fprintf (out, " parm %i flags:", i);
- dump_eaf_flags (out, arg_flags[i]);
- }
- }
- if (retslot_flags)
- {
- fprintf (out, " Retslot flags:");
- dump_eaf_flags (out, retslot_flags);
- }
- if (static_chain_flags)
- {
- fprintf (out, " Static chain flags:");
- dump_eaf_flags (out, static_chain_flags);
- }
-}
-
-/* Called after summary is produced and before it is used by local analysis.
- Can be called multiple times in case summary needs to update signature.
- FUN is decl of function summary is attached to. */
-void
-modref_summary::finalize (tree fun)
-{
- global_memory_read = !loads || loads->global_access_p ();
- global_memory_written = !stores || stores->global_access_p ();
-
- /* We can do DSE if we know function has no side effects and
- we can analyse all stores. Disable dse if there are too many
- stores to try. */
- if (side_effects || global_memory_written || writes_errno)
- try_dse = false;
- else
- {
- try_dse = true;
- size_t i, j, k;
- int num_tests = 0, max_tests
- = opt_for_fn (fun, param_modref_max_tests);
- modref_base_node <alias_set_type> *base_node;
- modref_ref_node <alias_set_type> *ref_node;
- modref_access_node *access_node;
- FOR_EACH_VEC_SAFE_ELT (stores->bases, i, base_node)
- {
- if (base_node->every_ref)
- {
- try_dse = false;
- break;
- }
- FOR_EACH_VEC_SAFE_ELT (base_node->refs, j, ref_node)
- {
- if (base_node->every_ref)
- {
- try_dse = false;
- break;
- }
- FOR_EACH_VEC_SAFE_ELT (ref_node->accesses, k, access_node)
- if (num_tests++ > max_tests
- || !access_node->parm_offset_known)
- {
- try_dse = false;
- break;
- }
- if (!try_dse)
- break;
- }
- if (!try_dse)
- break;
- }
- }
- if (loads->every_base)
- load_accesses = 1;
- else
- {
- load_accesses = 0;
- for (auto base_node : loads->bases)
- {
- if (base_node->every_ref)
- load_accesses++;
- else
- for (auto ref_node : base_node->refs)
- if (ref_node->every_access)
- load_accesses++;
- else
- load_accesses += ref_node->accesses->length ();
- }
- }
-}
-
-/* Get function summary for FUNC if it exists, return NULL otherwise. */
-
-modref_summary *
-get_modref_function_summary (cgraph_node *func)
-{
- /* Avoid creation of the summary too early (e.g. when front-end calls us). */
- if (!optimization_summaries)
- return NULL;
-
- /* A single function body may be represented by multiple symbols with
- different visibility. For example, if FUNC is an interposable alias,
- we don't want to return anything, even if we have summary for the target
- function. */
- enum availability avail;
- func = func->ultimate_alias_target
- (&avail, current_function_decl ?
- cgraph_node::get (current_function_decl) : NULL);
- if (avail <= AVAIL_INTERPOSABLE)
- return NULL;
-
- modref_summary *r = optimization_summaries->get (func);
- return r;
-}
-
-/* Get function summary for CALL if it exists, return NULL otherwise.
- If non-null set interposed to indicate whether function may not
- bind to current def. In this case sometimes loads from function
- needs to be ignored. */
-
-modref_summary *
-get_modref_function_summary (gcall *call, bool *interposed)
-{
- tree callee = gimple_call_fndecl (call);
- if (!callee)
- return NULL;
- struct cgraph_node *node = cgraph_node::get (callee);
- if (!node)
- return NULL;
- modref_summary *r = get_modref_function_summary (node);
- if (interposed && r)
- *interposed = r->calls_interposable
- || !node->binds_to_current_def_p ();
- return r;
-}
-
-
-namespace {
-
-/* Return true if ECF flags says that nondeterminsm can be ignored. */
-
-static bool
-ignore_nondeterminism_p (tree caller, int flags)
-{
- if (flags & (ECF_CONST | ECF_PURE))
- return true;
- if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
- || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
- return true;
- return false;
-}
-
-/* Return true if ECF flags says that return value can be ignored. */
-
-static bool
-ignore_retval_p (tree caller, int flags)
-{
- if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
- || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
- return true;
- return false;
-}
-
-/* Return true if ECF flags says that stores can be ignored. */
-
-static bool
-ignore_stores_p (tree caller, int flags)
-{
- if (flags & (ECF_PURE | ECF_CONST | ECF_NOVOPS))
- return true;
- if ((flags & (ECF_NORETURN | ECF_NOTHROW)) == (ECF_NORETURN | ECF_NOTHROW)
- || (!opt_for_fn (caller, flag_exceptions) && (flags & ECF_NORETURN)))
- return true;
- return false;
-}
-
-/* Determine parm_map for PTR which is supposed to be a pointer. */
-
-modref_parm_map
-parm_map_for_ptr (tree op)
-{
- bool offset_known;
- poly_int64 offset;
- struct modref_parm_map parm_map;
- gcall *call;
-
- parm_map.parm_offset_known = false;
- parm_map.parm_offset = 0;
-
- offset_known = unadjusted_ptr_and_unit_offset (op, &op, &offset);
- if (TREE_CODE (op) == SSA_NAME
- && SSA_NAME_IS_DEFAULT_DEF (op)
- && TREE_CODE (SSA_NAME_VAR (op)) == PARM_DECL)
- {
- int index = 0;
-
- if (cfun->static_chain_decl
- && op == ssa_default_def (cfun, cfun->static_chain_decl))
- index = MODREF_STATIC_CHAIN_PARM;
- else
- for (tree t = DECL_ARGUMENTS (current_function_decl);
- t != SSA_NAME_VAR (op); t = DECL_CHAIN (t))
- index++;
- parm_map.parm_index = index;
- parm_map.parm_offset_known = offset_known;
- parm_map.parm_offset = offset;
- }
- else if (points_to_local_or_readonly_memory_p (op))
- parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
- /* Memory allocated in the function is not visible to caller before the
- call and thus we do not need to record it as load/stores/kills. */
- else if (TREE_CODE (op) == SSA_NAME
- && (call = dyn_cast<gcall *>(SSA_NAME_DEF_STMT (op))) != NULL
- && gimple_call_flags (call) & ECF_MALLOC)
- parm_map.parm_index = MODREF_LOCAL_MEMORY_PARM;
- else
- parm_map.parm_index = MODREF_UNKNOWN_PARM;
- return parm_map;
-}
-
-/* Return true if ARG with EAF flags FLAGS can not make any caller's parameter
- used (if LOAD is true we check loads, otherwise stores). */
-
-static bool
-verify_arg (tree arg, int flags, bool load)
-{
- if (flags & EAF_UNUSED)
- return true;
- if (load && (flags & EAF_NO_DIRECT_READ))
- return true;
- if (!load
- && (flags & (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
- == (EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER))
- return true;
- if (is_gimple_constant (arg))
- return true;
- if (DECL_P (arg) && TREE_READONLY (arg))
- return true;
- if (TREE_CODE (arg) == ADDR_EXPR)
- {
- tree t = get_base_address (TREE_OPERAND (arg, 0));
- if (is_gimple_constant (t))
- return true;
- if (DECL_P (t)
- && (TREE_READONLY (t) || TREE_CODE (t) == FUNCTION_DECL))
- return true;
- }
- return false;
-}
-
-/* Return true if STMT may access memory that is pointed to by parameters
- of caller and which is not seen as an escape by PTA.
- CALLEE_ECF_FLAGS are ECF flags of callee. If LOAD is true then by access
- we mean load, otherwise we mean store. */
-
-static bool
-may_access_nonescaping_parm_p (gcall *call, int callee_ecf_flags, bool load)
-{
- int implicit_flags = 0;
-
- if (ignore_stores_p (current_function_decl, callee_ecf_flags))
- implicit_flags |= ignore_stores_eaf_flags;
- if (callee_ecf_flags & ECF_PURE)
- implicit_flags |= implicit_pure_eaf_flags;
- if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
- implicit_flags |= implicit_const_eaf_flags;
- if (gimple_call_chain (call)
- && !verify_arg (gimple_call_chain (call),
- gimple_call_static_chain_flags (call) | implicit_flags,
- load))
- return true;
- for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
- if (!verify_arg (gimple_call_arg (call, i),
- gimple_call_arg_flags (call, i) | implicit_flags,
- load))
- return true;
- return false;
-}
-
-
-/* Analyze memory accesses (loads, stores and kills) performed
- by the function. Set also side_effects, calls_interposable
- and nondeterminism flags. */
-
-class modref_access_analysis
-{
-public:
- modref_access_analysis (bool ipa, modref_summary *summary,
- modref_summary_lto *summary_lto)
- : m_summary (summary), m_summary_lto (summary_lto), m_ipa (ipa)
- {
- }
- void analyze ();
-private:
- bool set_side_effects ();
- bool set_nondeterministic ();
- static modref_access_node get_access (ao_ref *ref);
- static void record_access (modref_records *, ao_ref *, modref_access_node &);
- static void record_access_lto (modref_records_lto *, ao_ref *,
- modref_access_node &a);
- bool record_access_p (tree);
- bool record_unknown_load ();
- bool record_unknown_store ();
- bool record_global_memory_load ();
- bool record_global_memory_store ();
- bool merge_call_side_effects (gimple *, modref_summary *,
- cgraph_node *, bool);
- modref_access_node get_access_for_fnspec (gcall *, attr_fnspec &,
- unsigned int, modref_parm_map &);
- void process_fnspec (gcall *);
- void analyze_call (gcall *);
- static bool analyze_load (gimple *, tree, tree, void *);
- static bool analyze_store (gimple *, tree, tree, void *);
- void analyze_stmt (gimple *, bool);
- void propagate ();
-
- /* Summary being computed.
- We work eitehr with m_summary or m_summary_lto. Never on both. */
- modref_summary *m_summary;
- modref_summary_lto *m_summary_lto;
- /* Recursive calls needs simplisitc dataflow after analysis finished.
- Collect all calls into this vector during analysis and later process
- them in propagate. */
- auto_vec <gimple *, 32> m_recursive_calls;
- /* ECF flags of function being analysed. */
- int m_ecf_flags;
- /* True if IPA propagation will be done later. */
- bool m_ipa;
- /* Set true if statement currently analysed is known to be
- executed each time function is called. */
- bool m_always_executed;
-};
-
-/* Set side_effects flag and return if someting changed. */
-
-bool
-modref_access_analysis::set_side_effects ()
-{
- bool changed = false;
-
- if (m_summary && !m_summary->side_effects)
- {
- m_summary->side_effects = true;
- changed = true;
- }
- if (m_summary_lto && !m_summary_lto->side_effects)
- {
- m_summary_lto->side_effects = true;
- changed = true;
- }
- return changed;
-}
-
-/* Set nondeterministic flag and return if someting changed. */
-
-bool
-modref_access_analysis::set_nondeterministic ()
-{
- bool changed = false;
-
- if (m_summary && !m_summary->nondeterministic)
- {
- m_summary->side_effects = m_summary->nondeterministic = true;
- changed = true;
- }
- if (m_summary_lto && !m_summary_lto->nondeterministic)
- {
- m_summary_lto->side_effects = m_summary_lto->nondeterministic = true;
- changed = true;
- }
- return changed;
-}
-
-/* Construct modref_access_node from REF. */
-
-modref_access_node
-modref_access_analysis::get_access (ao_ref *ref)
-{
- tree base;
-
- base = ao_ref_base (ref);
- modref_access_node a = {ref->offset, ref->size, ref->max_size,
- 0, MODREF_UNKNOWN_PARM, false, 0};
- if (TREE_CODE (base) == MEM_REF || TREE_CODE (base) == TARGET_MEM_REF)
- {
- tree memref = base;
- modref_parm_map m = parm_map_for_ptr (TREE_OPERAND (base, 0));
-
- a.parm_index = m.parm_index;
- if (a.parm_index != MODREF_UNKNOWN_PARM && TREE_CODE (memref) == MEM_REF)
- {
- a.parm_offset_known
- = wi::to_poly_wide (TREE_OPERAND
- (memref, 1)).to_shwi (&a.parm_offset);
- if (a.parm_offset_known && m.parm_offset_known)
- a.parm_offset += m.parm_offset;
- else
- a.parm_offset_known = false;
- }
- }
- else
- a.parm_index = MODREF_UNKNOWN_PARM;
- return a;
-}
-
-/* Record access into the modref_records data structure. */
-
-void
-modref_access_analysis::record_access (modref_records *tt,
- ao_ref *ref,
- modref_access_node &a)
-{
- alias_set_type base_set = !flag_strict_aliasing
- || !flag_ipa_strict_aliasing ? 0
- : ao_ref_base_alias_set (ref);
- alias_set_type ref_set = !flag_strict_aliasing
- || !flag_ipa_strict_aliasing ? 0
- : (ao_ref_alias_set (ref));
- if (dump_file)
- {
- fprintf (dump_file, " - Recording base_set=%i ref_set=%i ",
- base_set, ref_set);
- a.dump (dump_file);
- }
- tt->insert (current_function_decl, base_set, ref_set, a, false);
-}
-
-/* IPA version of record_access_tree. */
-
-void
-modref_access_analysis::record_access_lto (modref_records_lto *tt, ao_ref *ref,
- modref_access_node &a)
-{
- /* get_alias_set sometimes use different type to compute the alias set
- than TREE_TYPE (base). Do same adjustments. */
- tree base_type = NULL_TREE, ref_type = NULL_TREE;
- if (flag_strict_aliasing && flag_ipa_strict_aliasing)
- {
- tree base;
-
- base = ref->ref;
- while (handled_component_p (base))
- base = TREE_OPERAND (base, 0);
-
- base_type = reference_alias_ptr_type_1 (&base);
-
- if (!base_type)
- base_type = TREE_TYPE (base);
- else
- base_type = TYPE_REF_CAN_ALIAS_ALL (base_type)
- ? NULL_TREE : TREE_TYPE (base_type);
-
- tree ref_expr = ref->ref;
- ref_type = reference_alias_ptr_type_1 (&ref_expr);
-
- if (!ref_type)
- ref_type = TREE_TYPE (ref_expr);
- else
- ref_type = TYPE_REF_CAN_ALIAS_ALL (ref_type)
- ? NULL_TREE : TREE_TYPE (ref_type);
-
- /* Sanity check that we are in sync with what get_alias_set does. */
- gcc_checking_assert ((!base_type && !ao_ref_base_alias_set (ref))
- || get_alias_set (base_type)
- == ao_ref_base_alias_set (ref));
- gcc_checking_assert ((!ref_type && !ao_ref_alias_set (ref))
- || get_alias_set (ref_type)
- == ao_ref_alias_set (ref));
-
- /* Do not bother to record types that have no meaningful alias set.
- Also skip variably modified types since these go to local streams. */
- if (base_type && (!get_alias_set (base_type)
- || variably_modified_type_p (base_type, NULL_TREE)))
- base_type = NULL_TREE;
- if (ref_type && (!get_alias_set (ref_type)
- || variably_modified_type_p (ref_type, NULL_TREE)))
- ref_type = NULL_TREE;
- }
- if (dump_file)
- {
- fprintf (dump_file, " - Recording base type:");
- print_generic_expr (dump_file, base_type);
- fprintf (dump_file, " (alias set %i) ref type:",
- base_type ? get_alias_set (base_type) : 0);
- print_generic_expr (dump_file, ref_type);
- fprintf (dump_file, " (alias set %i) ",
- ref_type ? get_alias_set (ref_type) : 0);
- a.dump (dump_file);
- }
-
- tt->insert (current_function_decl, base_type, ref_type, a, false);
-}
-
-/* Returns true if and only if we should store the access to EXPR.
- Some accesses, e.g. loads from automatic variables, are not interesting. */
-
-bool
-modref_access_analysis::record_access_p (tree expr)
-{
- if (TREE_THIS_VOLATILE (expr))
- {
- if (dump_file)
- fprintf (dump_file, " (volatile; marking nondeterministic) ");
- set_nondeterministic ();
- }
- if (cfun->can_throw_non_call_exceptions
- && tree_could_throw_p (expr))
- {
- if (dump_file)
- fprintf (dump_file, " (can throw; marking side effects) ");
- set_side_effects ();
- }
-
- if (refs_local_or_readonly_memory_p (expr))
- {
- if (dump_file)
- fprintf (dump_file, " - Read-only or local, ignoring.\n");
- return false;
- }
- return true;
-}
-
-/* Collapse loads and return true if something changed. */
-
-bool
-modref_access_analysis::record_unknown_load ()
-{
- bool changed = false;
-
- if (m_summary && !m_summary->loads->every_base)
- {
- m_summary->loads->collapse ();
- changed = true;
- }
- if (m_summary_lto && !m_summary_lto->loads->every_base)
- {
- m_summary_lto->loads->collapse ();
- changed = true;
- }
- return changed;
-}
-
-/* Collapse loads and return true if something changed. */
-
-bool
-modref_access_analysis::record_unknown_store ()
-{
- bool changed = false;
-
- if (m_summary && !m_summary->stores->every_base)
- {
- m_summary->stores->collapse ();
- changed = true;
- }
- if (m_summary_lto && !m_summary_lto->stores->every_base)
- {
- m_summary_lto->stores->collapse ();
- changed = true;
- }
- return changed;
-}
-
-/* Record unknown load from gloal memory. */
-
-bool
-modref_access_analysis::record_global_memory_load ()
-{
- bool changed = false;
- modref_access_node a = {0, -1, -1,
- 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
-
- if (m_summary && !m_summary->loads->every_base)
- changed |= m_summary->loads->insert (current_function_decl, 0, 0, a, false);
- if (m_summary_lto && !m_summary_lto->loads->every_base)
- changed |= m_summary_lto->loads->insert (current_function_decl,
- 0, 0, a, false);
- return changed;
-}
-
-/* Record unknown store from gloal memory. */
-
-bool
-modref_access_analysis::record_global_memory_store ()
-{
- bool changed = false;
- modref_access_node a = {0, -1, -1,
- 0, MODREF_GLOBAL_MEMORY_PARM, false, 0};
-
- if (m_summary && !m_summary->stores->every_base)
- changed |= m_summary->stores->insert (current_function_decl,
- 0, 0, a, false);
- if (m_summary_lto && !m_summary_lto->stores->every_base)
- changed |= m_summary_lto->stores->insert (current_function_decl,
- 0, 0, a, false);
- return changed;
-}
-
-/* Merge side effects of call STMT to function with CALLEE_SUMMARY.
- Return true if something changed.
- If IGNORE_STORES is true, do not merge stores.
- If RECORD_ADJUSTMENTS is true cap number of adjustments to
- a given access to make dataflow finite. */
-
-bool
-modref_access_analysis::merge_call_side_effects
- (gimple *stmt, modref_summary *callee_summary,
- cgraph_node *callee_node, bool record_adjustments)
-{
- gcall *call = as_a <gcall *> (stmt);
- int flags = gimple_call_flags (call);
-
- /* Nothing to do for non-looping cont functions. */
- if ((flags & (ECF_CONST | ECF_NOVOPS))
- && !(flags & ECF_LOOPING_CONST_OR_PURE))
- return false;
-
- bool changed = false;
-
- if (dump_file)
- fprintf (dump_file, " - Merging side effects of %s\n",
- callee_node->dump_name ());
-
- /* Merge side effects and non-determinism.
- PURE/CONST flags makes functions deterministic and if there is
- no LOOPING_CONST_OR_PURE they also have no side effects. */
- if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
- || (flags & ECF_LOOPING_CONST_OR_PURE))
- {
- if (!m_summary->side_effects && callee_summary->side_effects)
- {
- if (dump_file)
- fprintf (dump_file, " - merging side effects.\n");
- m_summary->side_effects = true;
- changed = true;
- }
- if (!m_summary->nondeterministic && callee_summary->nondeterministic
- && !ignore_nondeterminism_p (current_function_decl, flags))
- {
- if (dump_file)
- fprintf (dump_file, " - merging nondeterministic.\n");
- m_summary->nondeterministic = true;
- changed = true;
- }
- }
-
- /* For const functions we are done. */
- if (flags & (ECF_CONST | ECF_NOVOPS))
- return changed;
-
- /* Merge calls_interposable flags. */
- if (!m_summary->calls_interposable && callee_summary->calls_interposable)
- {
- if (dump_file)
- fprintf (dump_file, " - merging calls interposable.\n");
- m_summary->calls_interposable = true;
- changed = true;
- }
-
- if (!callee_node->binds_to_current_def_p () && !m_summary->calls_interposable)
- {
- if (dump_file)
- fprintf (dump_file, " - May be interposed.\n");
- m_summary->calls_interposable = true;
- changed = true;
- }
-
- /* Now merge the actual load, store and kill vectors. For this we need
- to compute map translating new parameters to old. */
- if (dump_file)
- fprintf (dump_file, " Parm map:");
-
- auto_vec <modref_parm_map, 32> parm_map;
- parm_map.safe_grow_cleared (gimple_call_num_args (call), true);
- for (unsigned i = 0; i < gimple_call_num_args (call); i++)
- {
- parm_map[i] = parm_map_for_ptr (gimple_call_arg (call, i));
- if (dump_file)
- {
- fprintf (dump_file, " %i", parm_map[i].parm_index);
- if (parm_map[i].parm_offset_known)
- {
- fprintf (dump_file, " offset:");
- print_dec ((poly_int64_pod)parm_map[i].parm_offset,
- dump_file, SIGNED);
- }
- }
- }
-
- modref_parm_map chain_map;
- if (gimple_call_chain (call))
- {
- chain_map = parm_map_for_ptr (gimple_call_chain (call));
- if (dump_file)
- {
- fprintf (dump_file, "static chain %i", chain_map.parm_index);
- if (chain_map.parm_offset_known)
- {
- fprintf (dump_file, " offset:");
- print_dec ((poly_int64_pod)chain_map.parm_offset,
- dump_file, SIGNED);
- }
- }
- }
- if (dump_file)
- fprintf (dump_file, "\n");
-
- /* Kills can me merged in only if we know the function is going to be
- always executed. */
- if (m_always_executed
- && callee_summary->kills.length ()
- && (!cfun->can_throw_non_call_exceptions
- || !stmt_could_throw_p (cfun, call)))
- {
- /* Watch for self recursive updates. */
- auto_vec<modref_access_node, 32> saved_kills;
-
- saved_kills.reserve_exact (callee_summary->kills.length ());
- saved_kills.splice (callee_summary->kills);
- for (auto kill : saved_kills)
- {
- if (kill.parm_index >= (int)parm_map.length ())
- continue;
- modref_parm_map &m
- = kill.parm_index == MODREF_STATIC_CHAIN_PARM
- ? chain_map
- : parm_map[kill.parm_index];
- if (m.parm_index == MODREF_LOCAL_MEMORY_PARM
- || m.parm_index == MODREF_UNKNOWN_PARM
- || m.parm_index == MODREF_RETSLOT_PARM
- || !m.parm_offset_known)
- continue;
- modref_access_node n = kill;
- n.parm_index = m.parm_index;
- n.parm_offset += m.parm_offset;
- if (modref_access_node::insert_kill (m_summary->kills, n,
- record_adjustments))
- changed = true;
- }
- }
-
- /* Merge in loads. */
- changed |= m_summary->loads->merge (current_function_decl,
- callee_summary->loads,
- &parm_map, &chain_map,
- record_adjustments,
- !may_access_nonescaping_parm_p
- (call, flags, true));
- /* Merge in stores. */
- if (!ignore_stores_p (current_function_decl, flags))
- {
- changed |= m_summary->stores->merge (current_function_decl,
- callee_summary->stores,
- &parm_map, &chain_map,
- record_adjustments,
- !may_access_nonescaping_parm_p
- (call, flags, false));
- if (!m_summary->writes_errno
- && callee_summary->writes_errno)
- {
- m_summary->writes_errno = true;
- changed = true;
- }
- }
- return changed;
-}
-
-/* Return access mode for argument I of call STMT with FNSPEC. */
-
-modref_access_node
-modref_access_analysis::get_access_for_fnspec (gcall *call, attr_fnspec &fnspec,
- unsigned int i,
- modref_parm_map &map)
-{
- tree size = NULL_TREE;
- unsigned int size_arg;
-
- if (!fnspec.arg_specified_p (i))
- ;
- else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
- size = gimple_call_arg (call, size_arg);
- else if (fnspec.arg_access_size_given_by_type_p (i))
- {
- tree callee = gimple_call_fndecl (call);
- tree t = TYPE_ARG_TYPES (TREE_TYPE (callee));
-
- for (unsigned int p = 0; p < i; p++)
- t = TREE_CHAIN (t);
- size = TYPE_SIZE_UNIT (TREE_TYPE (TREE_VALUE (t)));
- }
- modref_access_node a = {0, -1, -1,
- map.parm_offset, map.parm_index,
- map.parm_offset_known, 0};
- poly_int64 size_hwi;
- if (size
- && poly_int_tree_p (size, &size_hwi)
- && coeffs_in_range_p (size_hwi, 0,
- HOST_WIDE_INT_MAX / BITS_PER_UNIT))
- {
- a.size = -1;
- a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
- }
- return a;
-}
-/* Apply side effects of call STMT to CUR_SUMMARY using FNSPEC.
- If IGNORE_STORES is true ignore them.
- Return false if no useful summary can be produced. */
-
-void
-modref_access_analysis::process_fnspec (gcall *call)
-{
- int flags = gimple_call_flags (call);
-
- /* PURE/CONST flags makes functions deterministic and if there is
- no LOOPING_CONST_OR_PURE they also have no side effects. */
- if (!(flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
- || (flags & ECF_LOOPING_CONST_OR_PURE)
- || (cfun->can_throw_non_call_exceptions
- && stmt_could_throw_p (cfun, call)))
- {
- set_side_effects ();
- if (!ignore_nondeterminism_p (current_function_decl, flags))
- set_nondeterministic ();
- }
-
- /* For const functions we are done. */
- if (flags & (ECF_CONST | ECF_NOVOPS))
- return;
-
- attr_fnspec fnspec = gimple_call_fnspec (call);
- /* If there is no fnpec we know nothing about loads & stores. */
- if (!fnspec.known_p ())
- {
- if (dump_file && gimple_call_builtin_p (call, BUILT_IN_NORMAL))
- fprintf (dump_file, " Builtin with no fnspec: %s\n",
- IDENTIFIER_POINTER (DECL_NAME (gimple_call_fndecl (call))));
- if (!ignore_stores_p (current_function_decl, flags))
- {
- if (!may_access_nonescaping_parm_p (call, flags, false))
- record_global_memory_store ();
- else
- record_unknown_store ();
- if (!may_access_nonescaping_parm_p (call, flags, true))
- record_global_memory_load ();
- else
- record_unknown_load ();
- }
- else
- {
- if (!may_access_nonescaping_parm_p (call, flags, true))
- record_global_memory_load ();
- else
- record_unknown_load ();
- }
- return;
- }
- /* Process fnspec. */
- if (fnspec.global_memory_read_p ())
- {
- if (may_access_nonescaping_parm_p (call, flags, true))
- record_unknown_load ();
- else
- record_global_memory_load ();
- }
- else
- {
- for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
- if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
- ;
- else if (!fnspec.arg_specified_p (i)
- || fnspec.arg_maybe_read_p (i))
- {
- modref_parm_map map = parm_map_for_ptr
- (gimple_call_arg (call, i));
-
- if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
- continue;
- if (map.parm_index == MODREF_UNKNOWN_PARM)
- {
- record_unknown_load ();
- break;
- }
- modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
- if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
- continue;
- if (m_summary)
- m_summary->loads->insert (current_function_decl, 0, 0, a, false);
- if (m_summary_lto)
- m_summary_lto->loads->insert (current_function_decl, 0, 0, a,
- false);
- }
- }
- if (ignore_stores_p (current_function_decl, flags))
- return;
- if (fnspec.global_memory_written_p ())
- {
- if (may_access_nonescaping_parm_p (call, flags, false))
- record_unknown_store ();
- else
- record_global_memory_store ();
- }
- else
- {
- for (unsigned int i = 0; i < gimple_call_num_args (call); i++)
- if (!POINTER_TYPE_P (TREE_TYPE (gimple_call_arg (call, i))))
- ;
- else if (!fnspec.arg_specified_p (i)
- || fnspec.arg_maybe_written_p (i))
- {
- modref_parm_map map = parm_map_for_ptr
- (gimple_call_arg (call, i));
-
- if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
- continue;
- if (map.parm_index == MODREF_UNKNOWN_PARM)
- {
- record_unknown_store ();
- break;
- }
- modref_access_node a = get_access_for_fnspec (call, fnspec, i, map);
- if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
- continue;
- if (m_summary)
- m_summary->stores->insert (current_function_decl, 0, 0, a, false);
- if (m_summary_lto)
- m_summary_lto->stores->insert (current_function_decl,
- 0, 0, a, false);
- }
- if (fnspec.errno_maybe_written_p () && flag_errno_math)
- {
- if (m_summary)
- m_summary->writes_errno = true;
- if (m_summary_lto)
- m_summary_lto->writes_errno = true;
- }
- }
-}
-
-/* Analyze function call STMT in function F.
- Remember recursive calls in RECURSIVE_CALLS. */
-
-void
-modref_access_analysis::analyze_call (gcall *stmt)
-{
- /* Check flags on the function call. In certain cases, analysis can be
- simplified. */
- int flags = gimple_call_flags (stmt);
-
- if (dump_file)
- {
- fprintf (dump_file, " - Analyzing call:");
- print_gimple_stmt (dump_file, stmt, 0);
- }
-
- if ((flags & (ECF_CONST | ECF_NOVOPS))
- && !(flags & ECF_LOOPING_CONST_OR_PURE))
- {
- if (dump_file)
- fprintf (dump_file,
- " - ECF_CONST | ECF_NOVOPS, ignoring all stores and all loads "
- "except for args.\n");
- return;
- }
-
- /* Next, we try to get the callee's function declaration. The goal is to
- merge their summary with ours. */
- tree callee = gimple_call_fndecl (stmt);
-
- /* Check if this is an indirect call. */
- if (!callee)
- {
- if (dump_file)
- fprintf (dump_file, gimple_call_internal_p (stmt)
- ? " - Internal call" : " - Indirect call.\n");
- process_fnspec (stmt);
- return;
- }
- /* We only need to handle internal calls in IPA mode. */
- gcc_checking_assert (!m_summary_lto && !m_ipa);
-
- struct cgraph_node *callee_node = cgraph_node::get_create (callee);
-
- /* If this is a recursive call, the target summary is the same as ours, so
- there's nothing to do. */
- if (recursive_call_p (current_function_decl, callee))
- {
- m_recursive_calls.safe_push (stmt);
- set_side_effects ();
- if (dump_file)
- fprintf (dump_file, " - Skipping recursive call.\n");
- return;
- }
-
- gcc_assert (callee_node != NULL);
-
- /* Get the function symbol and its availability. */
- enum availability avail;
- callee_node = callee_node->function_symbol (&avail);
- bool looping;
- if (builtin_safe_for_const_function_p (&looping, callee))
- {
- if (looping)
- set_side_effects ();
- if (dump_file)
- fprintf (dump_file, " - Builtin is safe for const.\n");
- return;
- }
- if (avail <= AVAIL_INTERPOSABLE)
- {
- if (dump_file)
- fprintf (dump_file,
- " - Function availability <= AVAIL_INTERPOSABLE.\n");
- process_fnspec (stmt);
- return;
- }
-
- /* Get callee's modref summary. As above, if there's no summary, we either
- have to give up or, if stores are ignored, we can just purge loads. */
- modref_summary *callee_summary = optimization_summaries->get (callee_node);
- if (!callee_summary)
- {
- if (dump_file)
- fprintf (dump_file, " - No modref summary available for callee.\n");
- process_fnspec (stmt);
- return;
- }
-
- merge_call_side_effects (stmt, callee_summary, callee_node, false);
-
- return;
-}
-
-/* Helper for analyze_stmt. */
-
-bool
-modref_access_analysis::analyze_load (gimple *, tree, tree op, void *data)
-{
- modref_access_analysis *t = (modref_access_analysis *)data;
-
- if (dump_file)
- {
- fprintf (dump_file, " - Analyzing load: ");
- print_generic_expr (dump_file, op);
- fprintf (dump_file, "\n");
- }
-
- if (!t->record_access_p (op))
- return false;
-
- ao_ref r;
- ao_ref_init (&r, op);
- modref_access_node a = get_access (&r);
- if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
- return false;
-
- if (t->m_summary)
- t->record_access (t->m_summary->loads, &r, a);
- if (t->m_summary_lto)
- t->record_access_lto (t->m_summary_lto->loads, &r, a);
- return false;
-}
-
-/* Helper for analyze_stmt. */
-
-bool
-modref_access_analysis::analyze_store (gimple *stmt, tree, tree op, void *data)
-{
- modref_access_analysis *t = (modref_access_analysis *)data;
-
- if (dump_file)
- {
- fprintf (dump_file, " - Analyzing store: ");
- print_generic_expr (dump_file, op);
- fprintf (dump_file, "\n");
- }
-
- if (!t->record_access_p (op))
- return false;
-
- ao_ref r;
- ao_ref_init (&r, op);
- modref_access_node a = get_access (&r);
- if (a.parm_index == MODREF_LOCAL_MEMORY_PARM)
- return false;
-
- if (t->m_summary)
- t->record_access (t->m_summary->stores, &r, a);
- if (t->m_summary_lto)
- t->record_access_lto (t->m_summary_lto->stores, &r, a);
- if (t->m_always_executed
- && a.useful_for_kill_p ()
- && (!cfun->can_throw_non_call_exceptions
- || !stmt_could_throw_p (cfun, stmt)))
- {
- if (dump_file)
- fprintf (dump_file, " - Recording kill\n");
- if (t->m_summary)
- modref_access_node::insert_kill (t->m_summary->kills, a, false);
- if (t->m_summary_lto)
- modref_access_node::insert_kill (t->m_summary_lto->kills, a, false);
- }
- return false;
-}
-
-/* Analyze statement STMT of function F.
- If IPA is true do not merge in side effects of calls. */
-
-void
-modref_access_analysis::analyze_stmt (gimple *stmt, bool always_executed)
-{
- m_always_executed = always_executed;
- /* In general we can not ignore clobbers because they are barriers for code
- motion, however after inlining it is safe to do because local optimization
- passes do not consider clobbers from other functions.
- Similar logic is in ipa-pure-const.c. */
- if ((m_ipa || cfun->after_inlining) && gimple_clobber_p (stmt))
- {
- if (always_executed && record_access_p (gimple_assign_lhs (stmt)))
- {
- ao_ref r;
- ao_ref_init (&r, gimple_assign_lhs (stmt));
- modref_access_node a = get_access (&r);
- if (a.useful_for_kill_p ())
- {
- if (dump_file)
- fprintf (dump_file, " - Recording kill\n");
- if (m_summary)
- modref_access_node::insert_kill (m_summary->kills, a, false);
- if (m_summary_lto)
- modref_access_node::insert_kill (m_summary_lto->kills,
- a, false);
- }
- }
- return;
- }
-
- /* Analyze all loads and stores in STMT. */
- walk_stmt_load_store_ops (stmt, this,
- analyze_load, analyze_store);
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_ASM:
- if (gimple_asm_volatile_p (as_a <gasm *> (stmt)))
- set_nondeterministic ();
- if (cfun->can_throw_non_call_exceptions
- && stmt_could_throw_p (cfun, stmt))
- set_side_effects ();
- /* If the ASM statement does not read nor write memory, there's nothing
- to do. Otherwise just give up. */
- if (!gimple_asm_clobbers_memory_p (as_a <gasm *> (stmt)))
- return;
- if (dump_file)
- fprintf (dump_file, " - Function contains GIMPLE_ASM statement "
- "which clobbers memory.\n");
- record_unknown_load ();
- record_unknown_store ();
- return;
- case GIMPLE_CALL:
- if (!m_ipa || gimple_call_internal_p (stmt))
- analyze_call (as_a <gcall *> (stmt));
- else
- {
- attr_fnspec fnspec = gimple_call_fnspec (as_a <gcall *>(stmt));
-
- if (fnspec.known_p ()
- && (!fnspec.global_memory_read_p ()
- || !fnspec.global_memory_written_p ()))
- {
- cgraph_edge *e = cgraph_node::get
- (current_function_decl)->get_edge (stmt);
- if (e->callee)
- {
- fnspec_summaries->get_create (e)->fnspec
- = xstrdup (fnspec.get_str ());
- if (dump_file)
- fprintf (dump_file, " Recorded fnspec %s\n",
- fnspec.get_str ());
- }
- }
- }
- return;
- default:
- if (cfun->can_throw_non_call_exceptions
- && stmt_could_throw_p (cfun, stmt))
- set_side_effects ();
- return;
- }
-}
-
-/* Propagate load/stres acress recursive calls. */
-
-void
-modref_access_analysis::propagate ()
-{
- if (m_ipa && m_summary)
- return;
-
- bool changed = true;
- bool first = true;
- cgraph_node *fnode = cgraph_node::get (current_function_decl);
-
- m_always_executed = false;
- while (changed && m_summary->useful_p (m_ecf_flags, false))
- {
- changed = false;
- for (unsigned i = 0; i < m_recursive_calls.length (); i++)
- {
- changed |= merge_call_side_effects (m_recursive_calls[i], m_summary,
- fnode, !first);
- }
- first = false;
- }
-}
-
-/* Analyze function. */
-
-void
-modref_access_analysis::analyze ()
-{
- m_ecf_flags = flags_from_decl_or_type (current_function_decl);
- bool summary_useful = true;
-
- /* Analyze each statement in each basic block of the function. If the
- statement cannot be analyzed (for any reason), the entire function cannot
- be analyzed by modref. */
- basic_block bb;
- FOR_EACH_BB_FN (bb, cfun)
- {
- gimple_stmt_iterator si;
- bool always_executed
- = bb == single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))->dest;
-
- for (si = gsi_start_nondebug_after_labels_bb (bb);
- !gsi_end_p (si); gsi_next_nondebug (&si))
- {
- /* NULL memory accesses terminates BB. These accesses are known
- to trip undefined behaviour. gimple-ssa-isolate-paths turns them
- to volatile accesses and adds builtin_trap call which would
- confuse us otherwise. */
- if (infer_nonnull_range_by_dereference (gsi_stmt (si),
- null_pointer_node))
- {
- if (dump_file)
- fprintf (dump_file, " - NULL memory access; terminating BB\n");
- if (flag_non_call_exceptions)
- set_side_effects ();
- break;
- }
- analyze_stmt (gsi_stmt (si), always_executed);
-
- /* Avoid doing useles work. */
- if ((!m_summary || !m_summary->useful_p (m_ecf_flags, false))
- && (!m_summary_lto
- || !m_summary_lto->useful_p (m_ecf_flags, false)))
- {
- summary_useful = false;
- break;
- }
- if (always_executed
- && stmt_can_throw_external (cfun, gsi_stmt (si)))
- always_executed = false;
- }
- if (!summary_useful)
- break;
- }
- /* In non-IPA mode we need to perform iterative datafow on recursive calls.
- This needs to be done after all other side effects are computed. */
- if (summary_useful)
- {
- if (!m_ipa)
- propagate ();
- if (m_summary && !m_summary->side_effects && !finite_function_p ())
- m_summary->side_effects = true;
- if (m_summary_lto && !m_summary_lto->side_effects
- && !finite_function_p ())
- m_summary_lto->side_effects = true;
- }
-}
-
-/* Return true if OP accesses memory pointed to by SSA_NAME. */
-
-bool
-memory_access_to (tree op, tree ssa_name)
-{
- tree base = get_base_address (op);
- if (!base)
- return false;
- if (TREE_CODE (base) != MEM_REF && TREE_CODE (base) != TARGET_MEM_REF)
- return false;
- return TREE_OPERAND (base, 0) == ssa_name;
-}
-
-/* Consider statement val = *arg.
- return EAF flags of ARG that can be determined from EAF flags of VAL
- (which are known to be FLAGS). If IGNORE_STORES is true we can ignore
- all stores to VAL, i.e. when handling noreturn function. */
-
-static int
-deref_flags (int flags, bool ignore_stores)
-{
- /* Dereference is also a direct read but dereferenced value does not
- yield any other direct use. */
- int ret = EAF_NO_DIRECT_CLOBBER | EAF_NO_DIRECT_ESCAPE
- | EAF_NOT_RETURNED_DIRECTLY;
- /* If argument is unused just account for
- the read involved in dereference. */
- if (flags & EAF_UNUSED)
- ret |= EAF_NO_INDIRECT_READ | EAF_NO_INDIRECT_CLOBBER
- | EAF_NO_INDIRECT_ESCAPE;
- else
- {
- /* Direct or indirect accesses leads to indirect accesses. */
- if (((flags & EAF_NO_DIRECT_CLOBBER)
- && (flags & EAF_NO_INDIRECT_CLOBBER))
- || ignore_stores)
- ret |= EAF_NO_INDIRECT_CLOBBER;
- if (((flags & EAF_NO_DIRECT_ESCAPE)
- && (flags & EAF_NO_INDIRECT_ESCAPE))
- || ignore_stores)
- ret |= EAF_NO_INDIRECT_ESCAPE;
- if ((flags & EAF_NO_DIRECT_READ)
- && (flags & EAF_NO_INDIRECT_READ))
- ret |= EAF_NO_INDIRECT_READ;
- if ((flags & EAF_NOT_RETURNED_DIRECTLY)
- && (flags & EAF_NOT_RETURNED_INDIRECTLY))
- ret |= EAF_NOT_RETURNED_INDIRECTLY;
- }
- return ret;
-}
-
-
-/* Description of an escape point: a call which affects flags of a given
- SSA name. */
-
-struct escape_point
-{
- /* Value escapes to this call. */
- gcall *call;
- /* Argument it escapes to. */
- int arg;
- /* Flags already known about the argument (this can save us from recording
- esape points if local analysis did good job already). */
- eaf_flags_t min_flags;
- /* Does value escape directly or indiretly? */
- bool direct;
-};
-
-/* Lattice used during the eaf flags analsysis dataflow. For a given SSA name
- we aim to compute its flags and escape points. We also use the lattice
- to dynamically build dataflow graph to propagate on. */
-
-class modref_lattice
-{
-public:
- /* EAF flags of the SSA name. */
- eaf_flags_t flags;
- /* Used during DFS walk to mark names where final value was determined
- without need for dataflow. */
- bool known;
- /* Used during DFS walk to mark open vertices (for cycle detection). */
- bool open;
- /* Set during DFS walk for names that needs dataflow propagation. */
- bool do_dataflow;
- /* Used during the iterative dataflow. */
- bool changed;
-
- /* When doing IPA analysis we can not merge in callee escape points;
- Only remember them and do the merging at IPA propagation time. */
- vec <escape_point, va_heap, vl_ptr> escape_points;
-
- /* Representation of a graph for dataaflow. This graph is built on-demand
- using modref_eaf_analysis::analyze_ssa and later solved by
- modref_eaf_analysis::propagate.
- Each edge represents the fact that flags of current lattice should be
- propagated to lattice of SSA_NAME. */
- struct propagate_edge
- {
- int ssa_name;
- bool deref;
- };
- vec <propagate_edge, va_heap, vl_ptr> propagate_to;
-
- void init ();
- void release ();
- bool merge (const modref_lattice &with);
- bool merge (int flags);
- bool merge_deref (const modref_lattice &with, bool ignore_stores);
- bool merge_direct_load ();
- bool merge_direct_store ();
- bool add_escape_point (gcall *call, int arg, int min_flags, bool diret);
- void dump (FILE *out, int indent = 0) const;
-};
-
-/* Lattices are saved to vectors, so keep them PODs. */
-void
-modref_lattice::init ()
-{
- /* All flags we track. */
- int f = EAF_NO_DIRECT_CLOBBER | EAF_NO_INDIRECT_CLOBBER
- | EAF_NO_DIRECT_ESCAPE | EAF_NO_INDIRECT_ESCAPE
- | EAF_NO_DIRECT_READ | EAF_NO_INDIRECT_READ
- | EAF_NOT_RETURNED_DIRECTLY | EAF_NOT_RETURNED_INDIRECTLY
- | EAF_UNUSED;
- flags = f;
- /* Check that eaf_flags_t is wide enough to hold all flags. */
- gcc_checking_assert (f == flags);
- open = true;
- known = false;
-}
-
-/* Release memory. */
-void
-modref_lattice::release ()
-{
- escape_points.release ();
- propagate_to.release ();
-}
-
-/* Dump lattice to OUT; indent with INDENT spaces. */
-
-void
-modref_lattice::dump (FILE *out, int indent) const
-{
- dump_eaf_flags (out, flags);
- if (escape_points.length ())
- {
- fprintf (out, "%*sEscapes:\n", indent, "");
- for (unsigned int i = 0; i < escape_points.length (); i++)
- {
- fprintf (out, "%*s Arg %i (%s) min flags", indent, "",
- escape_points[i].arg,
- escape_points[i].direct ? "direct" : "indirect");
- dump_eaf_flags (out, escape_points[i].min_flags, false);
- fprintf (out, " in call ");
- print_gimple_stmt (out, escape_points[i].call, 0);
- }
- }
-}
-
-/* Add escape point CALL, ARG, MIN_FLAGS, DIRECT. Return false if such escape
- point exists. */
-
-bool
-modref_lattice::add_escape_point (gcall *call, int arg, int min_flags,
- bool direct)
-{
- escape_point *ep;
- unsigned int i;
-
- /* If we already determined flags to be bad enough,
- we do not need to record. */
- if ((flags & min_flags) == flags || (min_flags & EAF_UNUSED))
- return false;
-
- FOR_EACH_VEC_ELT (escape_points, i, ep)
- if (ep->call == call && ep->arg == arg && ep->direct == direct)
- {
- if ((ep->min_flags & min_flags) == min_flags)
- return false;
- ep->min_flags &= min_flags;
- return true;
- }
- /* Give up if max escape points is met. */
- if ((int)escape_points.length () > param_modref_max_escape_points)
- {
- if (dump_file)
- fprintf (dump_file, "--param modref-max-escape-points limit reached\n");
- merge (0);
- return true;
- }
- escape_point new_ep = {call, arg, min_flags, direct};
- escape_points.safe_push (new_ep);
- return true;
-}
-
-/* Merge in flags from F. */
-bool
-modref_lattice::merge (int f)
-{
- if (f & EAF_UNUSED)
- return false;
- /* Check that flags seems sane: if function does not read the parameter
- it can not access it indirectly. */
- gcc_checking_assert (!(f & EAF_NO_DIRECT_READ)
- || ((f & EAF_NO_INDIRECT_READ)
- && (f & EAF_NO_INDIRECT_CLOBBER)
- && (f & EAF_NO_INDIRECT_ESCAPE)
- && (f & EAF_NOT_RETURNED_INDIRECTLY)));
- if ((flags & f) != flags)
- {
- flags &= f;
- /* Prune obvoiusly useless flags;
- We do not have ECF_FLAGS handy which is not big problem since
- we will do final flags cleanup before producing summary.
- Merging should be fast so it can work well with dataflow. */
- flags = remove_useless_eaf_flags (flags, 0, false);
- if (!flags)
- escape_points.release ();
- return true;
- }
- return false;
-}
-
-/* Merge in WITH. Return true if anyting changed. */
-
-bool
-modref_lattice::merge (const modref_lattice &with)
-{
- if (!with.known)
- do_dataflow = true;
-
- bool changed = merge (with.flags);
-
- if (!flags)
- return changed;
- for (unsigned int i = 0; i < with.escape_points.length (); i++)
- changed |= add_escape_point (with.escape_points[i].call,
- with.escape_points[i].arg,
- with.escape_points[i].min_flags,
- with.escape_points[i].direct);
- return changed;
-}
-
-/* Merge in deref of WITH. If IGNORE_STORES is true do not consider
- stores. Return true if anyting changed. */
-
-bool
-modref_lattice::merge_deref (const modref_lattice &with, bool ignore_stores)
-{
- if (!with.known)
- do_dataflow = true;
-
- bool changed = merge (deref_flags (with.flags, ignore_stores));
-
- if (!flags)
- return changed;
- for (unsigned int i = 0; i < with.escape_points.length (); i++)
- {
- int min_flags = with.escape_points[i].min_flags;
-
- if (with.escape_points[i].direct)
- min_flags = deref_flags (min_flags, ignore_stores);
- else if (ignore_stores)
- min_flags |= ignore_stores_eaf_flags;
- changed |= add_escape_point (with.escape_points[i].call,
- with.escape_points[i].arg,
- min_flags,
- false);
- }
- return changed;
-}
-
-/* Merge in flags for direct load. */
-
-bool
-modref_lattice::merge_direct_load ()
-{
- return merge (~(EAF_UNUSED | EAF_NO_DIRECT_READ));
-}
-
-/* Merge in flags for direct store. */
-
-bool
-modref_lattice::merge_direct_store ()
-{
- return merge (~(EAF_UNUSED | EAF_NO_DIRECT_CLOBBER));
-}
-
-/* Analyzer of EAF flags.
- This is genrally dataflow problem over the SSA graph, however we only
- care about flags of few selected ssa names (arguments, return slot and
- static chain). So we first call analyze_ssa_name on all relevant names
- and perform a DFS walk to discover SSA names where flags needs to be
- determined. For acyclic graphs we try to determine final flags during
- this walk. Once cycles or recursin depth is met we enlist SSA names
- for dataflow which is done by propagate call.
-
- After propagation the flags can be obtained using get_ssa_name_flags. */
-
-class modref_eaf_analysis
-{
-public:
- /* Mark NAME as relevant for analysis. */
- void analyze_ssa_name (tree name, bool deferred = false);
- /* Dataflow slover. */
- void propagate ();
- /* Return flags computed earlier for NAME. */
- int get_ssa_name_flags (tree name)
- {
- int version = SSA_NAME_VERSION (name);
- gcc_checking_assert (m_lattice[version].known);
- return m_lattice[version].flags;
- }
- /* In IPA mode this will record all escape points
- determined for NAME to PARM_IDNEX. Flags are minimal
- flags known. */
- void record_escape_points (tree name, int parm_index, int flags);
- modref_eaf_analysis (bool ipa)
- {
- m_ipa = ipa;
- m_depth = 0;
- m_lattice.safe_grow_cleared (num_ssa_names, true);
- }
- ~modref_eaf_analysis ()
- {
- gcc_checking_assert (!m_depth);
- if (m_ipa || m_names_to_propagate.length ())
- for (unsigned int i = 0; i < num_ssa_names; i++)
- m_lattice[i].release ();
- }
-private:
- /* If true, we produce analysis for IPA mode. In this case escape points ar
- collected. */
- bool m_ipa;
- /* Depth of recursion of analyze_ssa_name. */
- int m_depth;
- /* Propagation lattice for individual ssa names. */
- auto_vec<modref_lattice> m_lattice;
- auto_vec<tree> m_deferred_names;
- auto_vec<int> m_names_to_propagate;
-
- void merge_with_ssa_name (tree dest, tree src, bool deref);
- void merge_call_lhs_flags (gcall *call, int arg, tree name, bool direct,
- bool deref);
-};
-
-
-/* Call statements may return tgeir parameters. Consider argument number
- ARG of USE_STMT and determine flags that can needs to be cleared
- in case pointer possibly indirectly references from ARG I is returned.
- If DIRECT is true consider direct returns and if INDIRECT consider
- indirect returns.
- LATTICE, DEPTH and ipa are same as in analyze_ssa_name.
- ARG is set to -1 for static chain. */
-
-void
-modref_eaf_analysis::merge_call_lhs_flags (gcall *call, int arg,
- tree name, bool direct,
- bool indirect)
-{
- int index = SSA_NAME_VERSION (name);
- bool returned_directly = false;
-
- /* If there is no return value, no flags are affected. */
- if (!gimple_call_lhs (call))
- return;
-
- /* If we know that function returns given argument and it is not ARG
- we can still be happy. */
- if (arg >= 0)
- {
- int flags = gimple_call_return_flags (call);
- if (flags & ERF_RETURNS_ARG)
- {
- if ((flags & ERF_RETURN_ARG_MASK) == arg)
- returned_directly = true;
- else
- return;
- }
- }
- /* Make ERF_RETURNS_ARG overwrite EAF_UNUSED. */
- if (returned_directly)
- {
- direct = true;
- indirect = false;
- }
- /* If value is not returned at all, do nothing. */
- else if (!direct && !indirect)
- return;
-
- /* If return value is SSA name determine its flags. */
- if (TREE_CODE (gimple_call_lhs (call)) == SSA_NAME)
- {
- tree lhs = gimple_call_lhs (call);
- if (direct)
- merge_with_ssa_name (name, lhs, false);
- if (indirect)
- merge_with_ssa_name (name, lhs, true);
- }
- /* In the case of memory store we can do nothing. */
- else if (!direct)
- m_lattice[index].merge (deref_flags (0, false));
- else
- m_lattice[index].merge (0);
-}
-
-/* CALL_FLAGS are EAF_FLAGS of the argument. Turn them
- into flags for caller, update LATTICE of corresponding
- argument if needed. */
-
-static int
-callee_to_caller_flags (int call_flags, bool ignore_stores,
- modref_lattice &lattice)
-{
- /* call_flags is about callee returning a value
- that is not the same as caller returning it. */
- call_flags |= EAF_NOT_RETURNED_DIRECTLY
- | EAF_NOT_RETURNED_INDIRECTLY;
- if (!ignore_stores && !(call_flags & EAF_UNUSED))
- {
- /* If value escapes we are no longer able to track what happens
- with it because we can read it from the escaped location
- anytime. */
- if (!(call_flags & EAF_NO_DIRECT_ESCAPE))
- lattice.merge (0);
- else if (!(call_flags & EAF_NO_INDIRECT_ESCAPE))
- lattice.merge (~(EAF_NOT_RETURNED_INDIRECTLY
- | EAF_NO_DIRECT_READ
- | EAF_NO_INDIRECT_READ
- | EAF_NO_INDIRECT_CLOBBER
- | EAF_UNUSED));
- }
- else
- call_flags |= ignore_stores_eaf_flags;
- return call_flags;
-}
-
-/* Analyze EAF flags for SSA name NAME and store result to LATTICE.
- LATTICE is an array of modref_lattices.
- DEPTH is a recursion depth used to make debug output prettier.
- If IPA is true we analyze for IPA propagation (and thus call escape points
- are processed later) */
-
-void
-modref_eaf_analysis::analyze_ssa_name (tree name, bool deferred)
-{
- imm_use_iterator ui;
- gimple *use_stmt;
- int index = SSA_NAME_VERSION (name);
-
- if (!deferred)
- {
- /* See if value is already computed. */
- if (m_lattice[index].known || m_lattice[index].do_dataflow)
- return;
- if (m_lattice[index].open)
- {
- if (dump_file)
- fprintf (dump_file,
- "%*sCycle in SSA graph\n",
- m_depth * 4, "");
- return;
- }
- /* Recursion guard. */
- m_lattice[index].init ();
- if (m_depth == param_modref_max_depth)
- {
- if (dump_file)
- fprintf (dump_file,
- "%*sMax recursion depth reached; postponing\n",
- m_depth * 4, "");
- m_deferred_names.safe_push (name);
- return;
- }
- }
-
- if (dump_file)
- {
- fprintf (dump_file,
- "%*sAnalyzing flags of ssa name: ", m_depth * 4, "");
- print_generic_expr (dump_file, name);
- fprintf (dump_file, "\n");
- }
-
- FOR_EACH_IMM_USE_STMT (use_stmt, ui, name)
- {
- if (m_lattice[index].flags == 0)
- break;
- if (is_gimple_debug (use_stmt))
- continue;
- if (dump_file)
- {
- fprintf (dump_file, "%*s Analyzing stmt: ", m_depth * 4, "");
- print_gimple_stmt (dump_file, use_stmt, 0);
- }
- /* If we see a direct non-debug use, clear unused bit.
- All dereferneces should be accounted below using deref_flags. */
- m_lattice[index].merge (~EAF_UNUSED);
-
- /* Gimple return may load the return value.
- Returning name counts as an use by tree-ssa-structalias.c */
- if (greturn *ret = dyn_cast <greturn *> (use_stmt))
- {
- /* Returning through return slot is seen as memory write earlier. */
- if (DECL_RESULT (current_function_decl)
- && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
- ;
- else if (gimple_return_retval (ret) == name)
- m_lattice[index].merge (~(EAF_UNUSED | EAF_NOT_RETURNED_DIRECTLY
- | EAF_NOT_RETURNED_DIRECTLY));
- else if (memory_access_to (gimple_return_retval (ret), name))
- {
- m_lattice[index].merge_direct_load ();
- m_lattice[index].merge (~(EAF_UNUSED
- | EAF_NOT_RETURNED_INDIRECTLY));
- }
- }
- /* Account for LHS store, arg loads and flags from callee function. */
- else if (gcall *call = dyn_cast <gcall *> (use_stmt))
- {
- tree callee = gimple_call_fndecl (call);
-
- /* IPA PTA internally it treats calling a function as "writing" to
- the argument space of all functions the function pointer points to
- (PR101949). We can not drop EAF_NOCLOBBER only when ipa-pta
- is on since that would allow propagation of this from -fno-ipa-pta
- to -fipa-pta functions. */
- if (gimple_call_fn (use_stmt) == name)
- m_lattice[index].merge (~(EAF_NO_DIRECT_CLOBBER | EAF_UNUSED));
-
- /* Recursion would require bit of propagation; give up for now. */
- if (callee && !m_ipa && recursive_call_p (current_function_decl,
- callee))
- m_lattice[index].merge (0);
- else
- {
- int ecf_flags = gimple_call_flags (call);
- bool ignore_stores = ignore_stores_p (current_function_decl,
- ecf_flags);
- bool ignore_retval = ignore_retval_p (current_function_decl,
- ecf_flags);
-
- /* Handle *name = func (...). */
- if (gimple_call_lhs (call)
- && memory_access_to (gimple_call_lhs (call), name))
- {
- m_lattice[index].merge_direct_store ();
- /* Return slot optimization passes address of
- LHS to callee via hidden parameter and this
- may make LHS to escape. See PR 98499. */
- if (gimple_call_return_slot_opt_p (call)
- && TREE_ADDRESSABLE (TREE_TYPE (gimple_call_lhs (call))))
- {
- int call_flags = gimple_call_retslot_flags (call);
- bool isretslot = false;
-
- if (DECL_RESULT (current_function_decl)
- && DECL_BY_REFERENCE
- (DECL_RESULT (current_function_decl)))
- isretslot = ssa_default_def
- (cfun,
- DECL_RESULT (current_function_decl))
- == name;
-
- /* Passing returnslot to return slot is special because
- not_returned and escape has same meaning.
- However passing arg to return slot is different. If
- the callee's return slot is returned it means that
- arg is written to itself which is an escape.
- Since we do not track the memory it is written to we
- need to give up on analysisng it. */
- if (!isretslot)
- {
- if (!(call_flags & (EAF_NOT_RETURNED_DIRECTLY
- | EAF_UNUSED)))
- m_lattice[index].merge (0);
- else gcc_checking_assert
- (call_flags & (EAF_NOT_RETURNED_INDIRECTLY
- | EAF_UNUSED));
- call_flags = callee_to_caller_flags
- (call_flags, false,
- m_lattice[index]);
- }
- m_lattice[index].merge (call_flags);
- }
- }
-
- if (gimple_call_chain (call)
- && (gimple_call_chain (call) == name))
- {
- int call_flags = gimple_call_static_chain_flags (call);
- if (!ignore_retval && !(call_flags & EAF_UNUSED))
- merge_call_lhs_flags
- (call, -1, name,
- !(call_flags & EAF_NOT_RETURNED_DIRECTLY),
- !(call_flags & EAF_NOT_RETURNED_INDIRECTLY));
- call_flags = callee_to_caller_flags
- (call_flags, ignore_stores,
- m_lattice[index]);
- if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
- m_lattice[index].merge (call_flags);
- }
-
- /* Process internal functions and right away. */
- bool record_ipa = m_ipa && !gimple_call_internal_p (call);
-
- /* Handle all function parameters. */
- for (unsigned i = 0;
- i < gimple_call_num_args (call)
- && m_lattice[index].flags; i++)
- /* Name is directly passed to the callee. */
- if (gimple_call_arg (call, i) == name)
- {
- int call_flags = gimple_call_arg_flags (call, i);
- if (!ignore_retval)
- merge_call_lhs_flags
- (call, i, name,
- !(call_flags & (EAF_NOT_RETURNED_DIRECTLY
- | EAF_UNUSED)),
- !(call_flags & (EAF_NOT_RETURNED_INDIRECTLY
- | EAF_UNUSED)));
- if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS)))
- {
- call_flags = callee_to_caller_flags
- (call_flags, ignore_stores,
- m_lattice[index]);
- if (!record_ipa)
- m_lattice[index].merge (call_flags);
- else
- m_lattice[index].add_escape_point (call, i,
- call_flags, true);
- }
- }
- /* Name is dereferenced and passed to a callee. */
- else if (memory_access_to (gimple_call_arg (call, i), name))
- {
- int call_flags = deref_flags
- (gimple_call_arg_flags (call, i), ignore_stores);
- if (!ignore_retval && !(call_flags & EAF_UNUSED)
- && !(call_flags & EAF_NOT_RETURNED_DIRECTLY)
- && !(call_flags & EAF_NOT_RETURNED_INDIRECTLY))
- merge_call_lhs_flags (call, i, name, false, true);
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
- m_lattice[index].merge_direct_load ();
- else
- {
- call_flags = callee_to_caller_flags
- (call_flags, ignore_stores,
- m_lattice[index]);
- if (!record_ipa)
- m_lattice[index].merge (call_flags);
- else
- m_lattice[index].add_escape_point (call, i,
- call_flags, false);
- }
- }
- }
- }
- else if (gimple_assign_load_p (use_stmt))
- {
- gassign *assign = as_a <gassign *> (use_stmt);
- /* Memory to memory copy. */
- if (gimple_store_p (assign))
- {
- /* Handle *lhs = *name.
-
- We do not track memory locations, so assume that value
- is used arbitrarily. */
- if (memory_access_to (gimple_assign_rhs1 (assign), name))
- m_lattice[index].merge (deref_flags (0, false));
- /* Handle *name = *exp. */
- else if (memory_access_to (gimple_assign_lhs (assign), name))
- m_lattice[index].merge_direct_store ();
- }
- /* Handle lhs = *name. */
- else if (memory_access_to (gimple_assign_rhs1 (assign), name))
- {
- tree lhs = gimple_assign_lhs (assign);
- merge_with_ssa_name (name, lhs, true);
- }
- }
- else if (gimple_store_p (use_stmt))
- {
- gassign *assign = dyn_cast <gassign *> (use_stmt);
-
- /* Handle *lhs = name. */
- if (assign && gimple_assign_rhs1 (assign) == name)
- {
- if (dump_file)
- fprintf (dump_file, "%*s ssa name saved to memory\n",
- m_depth * 4, "");
- m_lattice[index].merge (0);
- }
- /* Handle *name = exp. */
- else if (assign
- && memory_access_to (gimple_assign_lhs (assign), name))
- {
- /* In general we can not ignore clobbers because they are
- barriers for code motion, however after inlining it is safe to
- do because local optimization passes do not consider clobbers
- from other functions.
- Similar logic is in ipa-pure-const.c. */
- if (!cfun->after_inlining || !gimple_clobber_p (assign))
- m_lattice[index].merge_direct_store ();
- }
- /* ASM statements etc. */
- else if (!assign)
- {
- if (dump_file)
- fprintf (dump_file, "%*s Unhandled store\n", m_depth * 4, "");
- m_lattice[index].merge (0);
- }
- }
- else if (gassign *assign = dyn_cast <gassign *> (use_stmt))
- {
- enum tree_code code = gimple_assign_rhs_code (assign);
-
- /* See if operation is a merge as considered by
- tree-ssa-structalias.c:find_func_aliases. */
- if (!truth_value_p (code)
- && code != POINTER_DIFF_EXPR
- && (code != POINTER_PLUS_EXPR
- || gimple_assign_rhs1 (assign) == name))
- {
- tree lhs = gimple_assign_lhs (assign);
- merge_with_ssa_name (name, lhs, false);
- }
- }
- else if (gphi *phi = dyn_cast <gphi *> (use_stmt))
- {
- tree result = gimple_phi_result (phi);
- merge_with_ssa_name (name, result, false);
- }
- /* Conditions are not considered escape points
- by tree-ssa-structalias. */
- else if (gimple_code (use_stmt) == GIMPLE_COND)
- ;
- else
- {
- if (dump_file)
- fprintf (dump_file, "%*s Unhandled stmt\n", m_depth * 4, "");
- m_lattice[index].merge (0);
- }
-
- if (dump_file)
- {
- fprintf (dump_file, "%*s current flags of ", m_depth * 4, "");
- print_generic_expr (dump_file, name);
- m_lattice[index].dump (dump_file, m_depth * 4 + 4);
- }
- }
- if (dump_file)
- {
- fprintf (dump_file, "%*sflags of ssa name ", m_depth * 4, "");
- print_generic_expr (dump_file, name);
- m_lattice[index].dump (dump_file, m_depth * 4 + 2);
- }
- m_lattice[index].open = false;
- if (!m_lattice[index].do_dataflow)
- m_lattice[index].known = true;
-}
-
-/* Propagate info from SRC to DEST. If DEREF it true, assume that SRC
- is dereferenced. */
-
-void
-modref_eaf_analysis::merge_with_ssa_name (tree dest, tree src, bool deref)
-{
- int index = SSA_NAME_VERSION (dest);
- int src_index = SSA_NAME_VERSION (src);
-
- /* Merging lattice with itself is a no-op. */
- if (!deref && src == dest)
- return;
-
- m_depth++;
- analyze_ssa_name (src);
- m_depth--;
- if (deref)
- m_lattice[index].merge_deref (m_lattice[src_index], false);
- else
- m_lattice[index].merge (m_lattice[src_index]);
-
- /* If we failed to produce final solution add an edge to the dataflow
- graph. */
- if (!m_lattice[src_index].known)
- {
- modref_lattice::propagate_edge e = {index, deref};
-
- if (!m_lattice[src_index].propagate_to.length ())
- m_names_to_propagate.safe_push (src_index);
- m_lattice[src_index].propagate_to.safe_push (e);
- m_lattice[src_index].changed = true;
- m_lattice[src_index].do_dataflow = true;
- if (dump_file)
- fprintf (dump_file,
- "%*sWill propgate from ssa_name %i to %i%s\n",
- m_depth * 4 + 4,
- "", src_index, index, deref ? " (deref)" : "");
- }
-}
-
-/* In the case we deferred some SSA names, reprocess them. In the case some
- dataflow edges were introduced, do the actual iterative dataflow. */
-
-void
-modref_eaf_analysis::propagate ()
-{
- int iterations = 0;
- size_t i;
- int index;
- bool changed = true;
-
- while (m_deferred_names.length ())
- {
- tree name = m_deferred_names.pop ();
- if (dump_file)
- fprintf (dump_file, "Analyzing deferred SSA name\n");
- analyze_ssa_name (name, true);
- }
-
- if (!m_names_to_propagate.length ())
- return;
- if (dump_file)
- fprintf (dump_file, "Propagating EAF flags\n");
-
- /* Compute reverse postorder. */
- auto_vec <int> rpo;
- struct stack_entry
- {
- int name;
- unsigned pos;
- };
- auto_vec <struct stack_entry> stack;
- int pos = m_names_to_propagate.length () - 1;
-
- rpo.safe_grow (m_names_to_propagate.length (), true);
- stack.reserve_exact (m_names_to_propagate.length ());
-
- /* We reuse known flag for RPO DFS walk bookeeping. */
- if (flag_checking)
- FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
- gcc_assert (!m_lattice[index].known && m_lattice[index].changed);
-
- FOR_EACH_VEC_ELT (m_names_to_propagate, i, index)
- {
- if (!m_lattice[index].known)
- {
- stack_entry e = {index, 0};
-
- stack.quick_push (e);
- m_lattice[index].known = true;
- }
- while (stack.length ())
- {
- bool found = false;
- int index1 = stack.last ().name;
-
- while (stack.last ().pos < m_lattice[index1].propagate_to.length ())
- {
- int index2 = m_lattice[index1]
- .propagate_to[stack.last ().pos].ssa_name;
-
- stack.last ().pos++;
- if (!m_lattice[index2].known
- && m_lattice[index2].propagate_to.length ())
- {
- stack_entry e = {index2, 0};
-
- stack.quick_push (e);
- m_lattice[index2].known = true;
- found = true;
- break;
- }
- }
- if (!found
- && stack.last ().pos == m_lattice[index1].propagate_to.length ())
- {
- rpo[pos--] = index1;
- stack.pop ();
- }
- }
- }
-
- /* Perform itrative dataflow. */
- while (changed)
- {
- changed = false;
- iterations++;
- if (dump_file)
- fprintf (dump_file, " iteration %i\n", iterations);
- FOR_EACH_VEC_ELT (rpo, i, index)
- {
- if (m_lattice[index].changed)
- {
- size_t j;
-
- m_lattice[index].changed = false;
- if (dump_file)
- fprintf (dump_file, " Visiting ssa name %i\n", index);
- for (j = 0; j < m_lattice[index].propagate_to.length (); j++)
- {
- bool ch;
- int target = m_lattice[index].propagate_to[j].ssa_name;
- bool deref = m_lattice[index].propagate_to[j].deref;
-
- if (dump_file)
- fprintf (dump_file, " Propagating flags of ssa name"
- " %i to %i%s\n",
- index, target, deref ? " (deref)" : "");
- m_lattice[target].known = true;
- if (!m_lattice[index].propagate_to[j].deref)
- ch = m_lattice[target].merge (m_lattice[index]);
- else
- ch = m_lattice[target].merge_deref (m_lattice[index],
- false);
- if (!ch)
- continue;
- if (dump_file)
- {
- fprintf (dump_file, " New lattice: ");
- m_lattice[target].dump (dump_file);
- }
- changed = true;
- m_lattice[target].changed = true;
- }
- }
- }
- }
- if (dump_file)
- fprintf (dump_file, "EAF flags propagated in %i iterations\n", iterations);
-}
-
-/* Record escape points of PARM_INDEX according to LATTICE. */
-
-void
-modref_eaf_analysis::record_escape_points (tree name, int parm_index, int flags)
-{
- modref_lattice &lattice = m_lattice[SSA_NAME_VERSION (name)];
-
- if (lattice.escape_points.length ())
- {
- escape_point *ep;
- unsigned int ip;
- cgraph_node *node = cgraph_node::get (current_function_decl);
-
- gcc_assert (m_ipa);
- FOR_EACH_VEC_ELT (lattice.escape_points, ip, ep)
- if ((ep->min_flags & flags) != flags)
- {
- cgraph_edge *e = node->get_edge (ep->call);
- struct escape_entry ee = {parm_index, ep->arg,
- ep->min_flags, ep->direct};
-
- escape_summaries->get_create (e)->esc.safe_push (ee);
- }
- }
-}
-
-/* Determine EAF flags for function parameters
- and fill in SUMMARY/SUMMARY_LTO. If IPA is true work in IPA mode
- where we also collect scape points.
- PAST_FLAGS, PAST_RETSLOT_FLAGS, PAST_STATIC_CHAIN_FLAGS can be
- used to preserve flags from prevoius (IPA) run for cases where
- late optimizations changed code in a way we can no longer analyze
- it easily. */
-
-static void
-analyze_parms (modref_summary *summary, modref_summary_lto *summary_lto,
- bool ipa, vec<eaf_flags_t> &past_flags,
- int past_retslot_flags, int past_static_chain_flags)
-{
- unsigned int parm_index = 0;
- unsigned int count = 0;
- int ecf_flags = flags_from_decl_or_type (current_function_decl);
- tree retslot = NULL;
- tree static_chain = NULL;
-
- /* If there is return slot, look up its SSA name. */
- if (DECL_RESULT (current_function_decl)
- && DECL_BY_REFERENCE (DECL_RESULT (current_function_decl)))
- retslot = ssa_default_def (cfun, DECL_RESULT (current_function_decl));
- if (cfun->static_chain_decl)
- static_chain = ssa_default_def (cfun, cfun->static_chain_decl);
-
- for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
- parm = TREE_CHAIN (parm))
- count++;
-
- if (!count && !retslot && !static_chain)
- return;
-
- modref_eaf_analysis eaf_analysis (ipa);
-
- /* Determine all SSA names we need to know flags for. */
- for (tree parm = DECL_ARGUMENTS (current_function_decl); parm;
- parm = TREE_CHAIN (parm))
- {
- tree name = ssa_default_def (cfun, parm);
- if (name)
- eaf_analysis.analyze_ssa_name (name);
- }
- if (retslot)
- eaf_analysis.analyze_ssa_name (retslot);
- if (static_chain)
- eaf_analysis.analyze_ssa_name (static_chain);
-
- /* Do the dataflow. */
- eaf_analysis.propagate ();
-
- tree attr = lookup_attribute ("fn spec",
- TYPE_ATTRIBUTES
- (TREE_TYPE (current_function_decl)));
- attr_fnspec fnspec (attr
- ? TREE_STRING_POINTER (TREE_VALUE (TREE_VALUE (attr)))
- : "");
-
-
- /* Store results to summaries. */
- for (tree parm = DECL_ARGUMENTS (current_function_decl); parm; parm_index++,
- parm = TREE_CHAIN (parm))
- {
- tree name = ssa_default_def (cfun, parm);
- if (!name || has_zero_uses (name))
- {
- /* We do not track non-SSA parameters,
- but we want to track unused gimple_regs. */
- if (!is_gimple_reg (parm))
- continue;
- if (summary)
- {
- if (parm_index >= summary->arg_flags.length ())
- summary->arg_flags.safe_grow_cleared (count, true);
- summary->arg_flags[parm_index] = EAF_UNUSED;
- }
- else if (summary_lto)
- {
- if (parm_index >= summary_lto->arg_flags.length ())
- summary_lto->arg_flags.safe_grow_cleared (count, true);
- summary_lto->arg_flags[parm_index] = EAF_UNUSED;
- }
- continue;
- }
- int flags = eaf_analysis.get_ssa_name_flags (name);
- int attr_flags = fnspec.arg_eaf_flags (parm_index);
-
- if (dump_file && (flags | attr_flags) != flags && !(flags & EAF_UNUSED))
- {
- fprintf (dump_file,
- " Flags for param %i combined with fnspec flags:",
- (int)parm_index);
- dump_eaf_flags (dump_file, attr_flags, false);
- fprintf (dump_file, " determined: ");
- dump_eaf_flags (dump_file, flags, true);
- }
- flags |= attr_flags;
-
- /* Eliminate useless flags so we do not end up storing unnecessary
- summaries. */
-
- flags = remove_useless_eaf_flags
- (flags, ecf_flags,
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
- if (past_flags.length () > parm_index)
- {
- int past = past_flags[parm_index];
- past = remove_useless_eaf_flags
- (past, ecf_flags,
- VOID_TYPE_P (TREE_TYPE
- (TREE_TYPE (current_function_decl))));
- if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
- {
- fprintf (dump_file,
- " Flags for param %i combined with IPA pass:",
- (int)parm_index);
- dump_eaf_flags (dump_file, past, false);
- fprintf (dump_file, " determined: ");
- dump_eaf_flags (dump_file, flags, true);
- }
- if (!(flags & EAF_UNUSED))
- flags |= past;
- }
-
- if (flags)
- {
- if (summary)
- {
- if (parm_index >= summary->arg_flags.length ())
- summary->arg_flags.safe_grow_cleared (count, true);
- summary->arg_flags[parm_index] = flags;
- }
- else if (summary_lto)
- {
- if (parm_index >= summary_lto->arg_flags.length ())
- summary_lto->arg_flags.safe_grow_cleared (count, true);
- summary_lto->arg_flags[parm_index] = flags;
- }
- eaf_analysis.record_escape_points (name, parm_index, flags);
- }
- }
- if (retslot)
- {
- int flags = eaf_analysis.get_ssa_name_flags (retslot);
- int past = past_retslot_flags;
-
- flags = remove_useless_eaf_flags (flags, ecf_flags, false);
- past = remove_useless_eaf_flags
- (past, ecf_flags,
- VOID_TYPE_P (TREE_TYPE
- (TREE_TYPE (current_function_decl))));
- if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
- {
- fprintf (dump_file,
- " Retslot flags combined with IPA pass:");
- dump_eaf_flags (dump_file, past, false);
- fprintf (dump_file, " determined: ");
- dump_eaf_flags (dump_file, flags, true);
- }
- if (!(flags & EAF_UNUSED))
- flags |= past;
- if (flags)
- {
- if (summary)
- summary->retslot_flags = flags;
- if (summary_lto)
- summary_lto->retslot_flags = flags;
- eaf_analysis.record_escape_points (retslot,
- MODREF_RETSLOT_PARM, flags);
- }
- }
- if (static_chain)
- {
- int flags = eaf_analysis.get_ssa_name_flags (static_chain);
- int past = past_static_chain_flags;
-
- flags = remove_useless_eaf_flags (flags, ecf_flags, false);
- past = remove_useless_eaf_flags
- (past, ecf_flags,
- VOID_TYPE_P (TREE_TYPE
- (TREE_TYPE (current_function_decl))));
- if (dump_file && (flags | past) != flags && !(flags & EAF_UNUSED))
- {
- fprintf (dump_file,
- " Static chain flags combined with IPA pass:");
- dump_eaf_flags (dump_file, past, false);
- fprintf (dump_file, " determined: ");
- dump_eaf_flags (dump_file, flags, true);
- }
- if (!(flags & EAF_UNUSED))
- flags |= past;
- if (flags)
- {
- if (summary)
- summary->static_chain_flags = flags;
- if (summary_lto)
- summary_lto->static_chain_flags = flags;
- eaf_analysis.record_escape_points (static_chain,
- MODREF_STATIC_CHAIN_PARM,
- flags);
- }
- }
-}
-
-/* Analyze function. IPA indicates whether we're running in local mode
- (false) or the IPA mode (true).
- Return true if fixup cfg is needed after the pass. */
-
-static bool
-analyze_function (bool ipa)
-{
- bool fixup_cfg = false;
- if (dump_file)
- fprintf (dump_file, "\n\nmodref analyzing '%s' (ipa=%i)%s%s\n",
- cgraph_node::get (current_function_decl)->dump_name (), ipa,
- TREE_READONLY (current_function_decl) ? " (const)" : "",
- DECL_PURE_P (current_function_decl) ? " (pure)" : "");
-
- /* Don't analyze this function if it's compiled with -fno-strict-aliasing. */
- if (!flag_ipa_modref
- || lookup_attribute ("noipa", DECL_ATTRIBUTES (current_function_decl)))
- return false;
-
- /* Compute no-LTO summaries when local optimization is going to happen. */
- bool nolto = (!ipa || ((!flag_lto || flag_fat_lto_objects) && !in_lto_p)
- || (in_lto_p && !flag_wpa
- && flag_incremental_link != INCREMENTAL_LINK_LTO));
- /* Compute LTO when LTO streaming is going to happen. */
- bool lto = ipa && ((flag_lto && !in_lto_p)
- || flag_wpa
- || flag_incremental_link == INCREMENTAL_LINK_LTO);
- cgraph_node *fnode = cgraph_node::get (current_function_decl);
-
- modref_summary *summary = NULL;
- modref_summary_lto *summary_lto = NULL;
-
- bool past_flags_known = false;
- auto_vec <eaf_flags_t> past_flags;
- int past_retslot_flags = 0;
- int past_static_chain_flags = 0;
-
- /* Initialize the summary.
- If we run in local mode there is possibly pre-existing summary from
- IPA pass. Dump it so it is easy to compare if mod-ref info has
- improved. */
- if (!ipa)
- {
- if (!optimization_summaries)
- optimization_summaries = modref_summaries::create_ggc (symtab);
- else /* Remove existing summary if we are re-running the pass. */
- {
- summary = optimization_summaries->get (fnode);
- if (summary != NULL
- && summary->loads)
- {
- if (dump_file)
- {
- fprintf (dump_file, "Past summary:\n");
- optimization_summaries->get (fnode)->dump (dump_file);
- }
- past_flags.reserve_exact (summary->arg_flags.length ());
- past_flags.splice (summary->arg_flags);
- past_retslot_flags = summary->retslot_flags;
- past_static_chain_flags = summary->static_chain_flags;
- past_flags_known = true;
- }
- optimization_summaries->remove (fnode);
- }
- summary = optimization_summaries->get_create (fnode);
- gcc_checking_assert (nolto && !lto);
- }
- /* In IPA mode we analyze every function precisely once. Assert that. */
- else
- {
- if (nolto)
- {
- if (!summaries)
- summaries = modref_summaries::create_ggc (symtab);
- else
- summaries->remove (fnode);
- summary = summaries->get_create (fnode);
- }
- if (lto)
- {
- if (!summaries_lto)
- summaries_lto = modref_summaries_lto::create_ggc (symtab);
- else
- summaries_lto->remove (fnode);
- summary_lto = summaries_lto->get_create (fnode);
- }
- if (!fnspec_summaries)
- fnspec_summaries = new fnspec_summaries_t (symtab);
- if (!escape_summaries)
- escape_summaries = new escape_summaries_t (symtab);
- }
-
-
- /* Create and initialize summary for F.
- Note that summaries may be already allocated from previous
- run of the pass. */
- if (nolto)
- {
- gcc_assert (!summary->loads);
- summary->loads = modref_records::create_ggc ();
- gcc_assert (!summary->stores);
- summary->stores = modref_records::create_ggc ();
- summary->writes_errno = false;
- summary->side_effects = false;
- summary->nondeterministic = false;
- summary->calls_interposable = false;
- }
- if (lto)
- {
- gcc_assert (!summary_lto->loads);
- summary_lto->loads = modref_records_lto::create_ggc ();
- gcc_assert (!summary_lto->stores);
- summary_lto->stores = modref_records_lto::create_ggc ();
- summary_lto->writes_errno = false;
- summary_lto->side_effects = false;
- summary_lto->nondeterministic = false;
- summary_lto->calls_interposable = false;
- }
-
- analyze_parms (summary, summary_lto, ipa,
- past_flags, past_retslot_flags, past_static_chain_flags);
-
- {
- modref_access_analysis analyzer (ipa, summary, summary_lto);
- analyzer.analyze ();
- }
-
- if (!ipa && flag_ipa_pure_const)
- {
- if (!summary->stores->every_base && !summary->stores->bases
- && !summary->nondeterministic)
- {
- if (!summary->loads->every_base && !summary->loads->bases
- && !summary->calls_interposable)
- fixup_cfg = ipa_make_function_const (fnode,
- summary->side_effects, true);
- else
- fixup_cfg = ipa_make_function_pure (fnode,
- summary->side_effects, true);
- }
- }
- int ecf_flags = flags_from_decl_or_type (current_function_decl);
- if (summary && !summary->useful_p (ecf_flags))
- {
- if (!ipa)
- optimization_summaries->remove (fnode);
- else
- summaries->remove (fnode);
- summary = NULL;
- }
- if (summary)
- summary->finalize (current_function_decl);
- if (summary_lto && !summary_lto->useful_p (ecf_flags))
- {
- summaries_lto->remove (fnode);
- summary_lto = NULL;
- }
-
- if (ipa && !summary && !summary_lto)
- remove_modref_edge_summaries (fnode);
-
- if (dump_file)
- {
- fprintf (dump_file, " - modref done with result: tracked.\n");
- if (summary)
- summary->dump (dump_file);
- if (summary_lto)
- summary_lto->dump (dump_file);
- dump_modref_edge_summaries (dump_file, fnode, 2);
- /* To simplify debugging, compare IPA and local solutions. */
- if (past_flags_known && summary)
- {
- size_t len = summary->arg_flags.length ();
-
- if (past_flags.length () > len)
- len = past_flags.length ();
- for (size_t i = 0; i < len; i++)
- {
- int old_flags = i < past_flags.length () ? past_flags[i] : 0;
- int new_flags = i < summary->arg_flags.length ()
- ? summary->arg_flags[i] : 0;
- old_flags = remove_useless_eaf_flags
- (old_flags, flags_from_decl_or_type (current_function_decl),
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
- if (old_flags != new_flags)
- {
- if ((old_flags & ~new_flags) == 0
- || (new_flags & EAF_UNUSED))
- fprintf (dump_file, " Flags for param %i improved:",
- (int)i);
- else
- gcc_unreachable ();
- dump_eaf_flags (dump_file, old_flags, false);
- fprintf (dump_file, " -> ");
- dump_eaf_flags (dump_file, new_flags, true);
- }
- }
- past_retslot_flags = remove_useless_eaf_flags
- (past_retslot_flags,
- flags_from_decl_or_type (current_function_decl),
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
- if (past_retslot_flags != summary->retslot_flags)
- {
- if ((past_retslot_flags & ~summary->retslot_flags) == 0
- || (summary->retslot_flags & EAF_UNUSED))
- fprintf (dump_file, " Flags for retslot improved:");
- else
- gcc_unreachable ();
- dump_eaf_flags (dump_file, past_retslot_flags, false);
- fprintf (dump_file, " -> ");
- dump_eaf_flags (dump_file, summary->retslot_flags, true);
- }
- past_static_chain_flags = remove_useless_eaf_flags
- (past_static_chain_flags,
- flags_from_decl_or_type (current_function_decl),
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
- if (past_static_chain_flags != summary->static_chain_flags)
- {
- if ((past_static_chain_flags & ~summary->static_chain_flags) == 0
- || (summary->static_chain_flags & EAF_UNUSED))
- fprintf (dump_file, " Flags for static chain improved:");
- else
- gcc_unreachable ();
- dump_eaf_flags (dump_file, past_static_chain_flags, false);
- fprintf (dump_file, " -> ");
- dump_eaf_flags (dump_file, summary->static_chain_flags, true);
- }
- }
- else if (past_flags_known && !summary)
- {
- for (size_t i = 0; i < past_flags.length (); i++)
- {
- int old_flags = past_flags[i];
- old_flags = remove_useless_eaf_flags
- (old_flags, flags_from_decl_or_type (current_function_decl),
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
- if (old_flags)
- {
- fprintf (dump_file, " Flags for param %i worsened:",
- (int)i);
- dump_eaf_flags (dump_file, old_flags, false);
- fprintf (dump_file, " -> \n");
- }
- }
- past_retslot_flags = remove_useless_eaf_flags
- (past_retslot_flags,
- flags_from_decl_or_type (current_function_decl),
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
- if (past_retslot_flags)
- {
- fprintf (dump_file, " Flags for retslot worsened:");
- dump_eaf_flags (dump_file, past_retslot_flags, false);
- fprintf (dump_file, " ->\n");
- }
- past_static_chain_flags = remove_useless_eaf_flags
- (past_static_chain_flags,
- flags_from_decl_or_type (current_function_decl),
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (current_function_decl))));
- if (past_static_chain_flags)
- {
- fprintf (dump_file, " Flags for static chain worsened:");
- dump_eaf_flags (dump_file, past_static_chain_flags, false);
- fprintf (dump_file, " ->\n");
- }
- }
- }
- return fixup_cfg;
-}
-
-/* Callback for generate_summary. */
-
-static void
-modref_generate (void)
-{
- struct cgraph_node *node;
- FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
- {
- function *f = DECL_STRUCT_FUNCTION (node->decl);
- if (!f)
- continue;
- push_cfun (f);
- analyze_function (true);
- pop_cfun ();
- }
-}
-
-} /* ANON namespace. */
-
-/* Debugging helper. */
-
-void
-debug_eaf_flags (int flags)
-{
- dump_eaf_flags (stderr, flags, true);
-}
-
-/* Called when a new function is inserted to callgraph late. */
-
-void
-modref_summaries::insert (struct cgraph_node *node, modref_summary *)
-{
- /* Local passes ought to be executed by the pass manager. */
- if (this == optimization_summaries)
- {
- optimization_summaries->remove (node);
- return;
- }
- if (!DECL_STRUCT_FUNCTION (node->decl)
- || !opt_for_fn (node->decl, flag_ipa_modref))
- {
- summaries->remove (node);
- return;
- }
- push_cfun (DECL_STRUCT_FUNCTION (node->decl));
- analyze_function (true);
- pop_cfun ();
-}
-
-/* Called when a new function is inserted to callgraph late. */
-
-void
-modref_summaries_lto::insert (struct cgraph_node *node, modref_summary_lto *)
-{
- /* We do not support adding new function when IPA information is already
- propagated. This is done only by SIMD cloning that is not very
- critical. */
- if (!DECL_STRUCT_FUNCTION (node->decl)
- || !opt_for_fn (node->decl, flag_ipa_modref)
- || propagated)
- {
- summaries_lto->remove (node);
- return;
- }
- push_cfun (DECL_STRUCT_FUNCTION (node->decl));
- analyze_function (true);
- pop_cfun ();
-}
-
-/* Called when new clone is inserted to callgraph late. */
-
-void
-modref_summaries::duplicate (cgraph_node *, cgraph_node *dst,
- modref_summary *src_data,
- modref_summary *dst_data)
-{
- /* Do not duplicate optimization summaries; we do not handle parameter
- transforms on them. */
- if (this == optimization_summaries)
- {
- optimization_summaries->remove (dst);
- return;
- }
- dst_data->stores = modref_records::create_ggc ();
- dst_data->stores->copy_from (src_data->stores);
- dst_data->loads = modref_records::create_ggc ();
- dst_data->loads->copy_from (src_data->loads);
- dst_data->kills.reserve_exact (src_data->kills.length ());
- dst_data->kills.splice (src_data->kills);
- dst_data->writes_errno = src_data->writes_errno;
- dst_data->side_effects = src_data->side_effects;
- dst_data->nondeterministic = src_data->nondeterministic;
- dst_data->calls_interposable = src_data->calls_interposable;
- if (src_data->arg_flags.length ())
- dst_data->arg_flags = src_data->arg_flags.copy ();
- dst_data->retslot_flags = src_data->retslot_flags;
- dst_data->static_chain_flags = src_data->static_chain_flags;
-}
-
-/* Called when new clone is inserted to callgraph late. */
-
-void
-modref_summaries_lto::duplicate (cgraph_node *, cgraph_node *,
- modref_summary_lto *src_data,
- modref_summary_lto *dst_data)
-{
- /* Be sure that no further cloning happens after ipa-modref. If it does
- we will need to update signatures for possible param changes. */
- gcc_checking_assert (!((modref_summaries_lto *)summaries_lto)->propagated);
- dst_data->stores = modref_records_lto::create_ggc ();
- dst_data->stores->copy_from (src_data->stores);
- dst_data->loads = modref_records_lto::create_ggc ();
- dst_data->loads->copy_from (src_data->loads);
- dst_data->kills.reserve_exact (src_data->kills.length ());
- dst_data->kills.splice (src_data->kills);
- dst_data->writes_errno = src_data->writes_errno;
- dst_data->side_effects = src_data->side_effects;
- dst_data->nondeterministic = src_data->nondeterministic;
- dst_data->calls_interposable = src_data->calls_interposable;
- if (src_data->arg_flags.length ())
- dst_data->arg_flags = src_data->arg_flags.copy ();
- dst_data->retslot_flags = src_data->retslot_flags;
- dst_data->static_chain_flags = src_data->static_chain_flags;
-}
-
-namespace
-{
-/* Definition of the modref pass on GIMPLE. */
-const pass_data pass_data_modref = {
- GIMPLE_PASS,
- "modref",
- OPTGROUP_IPA,
- TV_TREE_MODREF,
- (PROP_cfg | PROP_ssa),
- 0,
- 0,
- 0,
- 0,
-};
-
-class pass_modref : public gimple_opt_pass
-{
- public:
- pass_modref (gcc::context *ctxt)
- : gimple_opt_pass (pass_data_modref, ctxt) {}
-
- /* opt_pass methods: */
- opt_pass *clone ()
- {
- return new pass_modref (m_ctxt);
- }
- virtual bool gate (function *)
- {
- return flag_ipa_modref;
- }
- virtual unsigned int execute (function *);
-};
-
-/* Encode TT to the output block OB using the summary streaming API. */
-
-static void
-write_modref_records (modref_records_lto *tt, struct output_block *ob)
-{
- streamer_write_uhwi (ob, tt->every_base);
- streamer_write_uhwi (ob, vec_safe_length (tt->bases));
- for (auto base_node : tt->bases)
- {
- stream_write_tree (ob, base_node->base, true);
-
- streamer_write_uhwi (ob, base_node->every_ref);
- streamer_write_uhwi (ob, vec_safe_length (base_node->refs));
-
- for (auto ref_node : base_node->refs)
- {
- stream_write_tree (ob, ref_node->ref, true);
- streamer_write_uhwi (ob, ref_node->every_access);
- streamer_write_uhwi (ob, vec_safe_length (ref_node->accesses));
-
- for (auto access_node : ref_node->accesses)
- access_node.stream_out (ob);
- }
- }
-}
-
-/* Read a modref_tree from the input block IB using the data from DATA_IN.
- This assumes that the tree was encoded using write_modref_tree.
- Either nolto_ret or lto_ret is initialized by the tree depending whether
- LTO streaming is expected or not. */
-
-static void
-read_modref_records (tree decl,
- lto_input_block *ib, struct data_in *data_in,
- modref_records **nolto_ret,
- modref_records_lto **lto_ret)
-{
- size_t max_bases = opt_for_fn (decl, param_modref_max_bases);
- size_t max_refs = opt_for_fn (decl, param_modref_max_refs);
- size_t max_accesses = opt_for_fn (decl, param_modref_max_accesses);
-
- if (lto_ret)
- *lto_ret = modref_records_lto::create_ggc ();
- if (nolto_ret)
- *nolto_ret = modref_records::create_ggc ();
- gcc_checking_assert (lto_ret || nolto_ret);
-
- size_t every_base = streamer_read_uhwi (ib);
- size_t nbase = streamer_read_uhwi (ib);
-
- gcc_assert (!every_base || nbase == 0);
- if (every_base)
- {
- if (nolto_ret)
- (*nolto_ret)->collapse ();
- if (lto_ret)
- (*lto_ret)->collapse ();
- }
- for (size_t i = 0; i < nbase; i++)
- {
- tree base_tree = stream_read_tree (ib, data_in);
- modref_base_node <alias_set_type> *nolto_base_node = NULL;
- modref_base_node <tree> *lto_base_node = NULL;
-
- /* At stream in time we have LTO alias info. Check if we streamed in
- something obviously unnecessary. Do not glob types by alias sets;
- it is not 100% clear that ltrans types will get merged same way.
- Types may get refined based on ODR type conflicts. */
- if (base_tree && !get_alias_set (base_tree))
- {
- if (dump_file)
- {
- fprintf (dump_file, "Streamed in alias set 0 type ");
- print_generic_expr (dump_file, base_tree);
- fprintf (dump_file, "\n");
- }
- base_tree = NULL;
- }
-
- if (nolto_ret)
- nolto_base_node = (*nolto_ret)->insert_base (base_tree
- ? get_alias_set (base_tree)
- : 0, 0, INT_MAX);
- if (lto_ret)
- lto_base_node = (*lto_ret)->insert_base (base_tree, 0, max_bases);
- size_t every_ref = streamer_read_uhwi (ib);
- size_t nref = streamer_read_uhwi (ib);
-
- gcc_assert (!every_ref || nref == 0);
- if (every_ref)
- {
- if (nolto_base_node)
- nolto_base_node->collapse ();
- if (lto_base_node)
- lto_base_node->collapse ();
- }
- for (size_t j = 0; j < nref; j++)
- {
- tree ref_tree = stream_read_tree (ib, data_in);
-
- if (ref_tree && !get_alias_set (ref_tree))
- {
- if (dump_file)
- {
- fprintf (dump_file, "Streamed in alias set 0 type ");
- print_generic_expr (dump_file, ref_tree);
- fprintf (dump_file, "\n");
- }
- ref_tree = NULL;
- }
-
- modref_ref_node <alias_set_type> *nolto_ref_node = NULL;
- modref_ref_node <tree> *lto_ref_node = NULL;
-
- if (nolto_base_node)
- nolto_ref_node
- = nolto_base_node->insert_ref (ref_tree
- ? get_alias_set (ref_tree) : 0,
- max_refs);
- if (lto_base_node)
- lto_ref_node = lto_base_node->insert_ref (ref_tree, max_refs);
-
- size_t every_access = streamer_read_uhwi (ib);
- size_t naccesses = streamer_read_uhwi (ib);
-
- if (nolto_ref_node && every_access)
- nolto_ref_node->collapse ();
- if (lto_ref_node && every_access)
- lto_ref_node->collapse ();
-
- for (size_t k = 0; k < naccesses; k++)
- {
- modref_access_node a = modref_access_node::stream_in (ib);
- if (nolto_ref_node)
- nolto_ref_node->insert_access (a, max_accesses, false);
- if (lto_ref_node)
- lto_ref_node->insert_access (a, max_accesses, false);
- }
- }
- }
- if (lto_ret)
- (*lto_ret)->cleanup ();
- if (nolto_ret)
- (*nolto_ret)->cleanup ();
-}
-
-/* Write ESUM to BP. */
-
-static void
-modref_write_escape_summary (struct bitpack_d *bp, escape_summary *esum)
-{
- if (!esum)
- {
- bp_pack_var_len_unsigned (bp, 0);
- return;
- }
- bp_pack_var_len_unsigned (bp, esum->esc.length ());
- unsigned int i;
- escape_entry *ee;
- FOR_EACH_VEC_ELT (esum->esc, i, ee)
- {
- bp_pack_var_len_int (bp, ee->parm_index);
- bp_pack_var_len_unsigned (bp, ee->arg);
- bp_pack_var_len_unsigned (bp, ee->min_flags);
- bp_pack_value (bp, ee->direct, 1);
- }
-}
-
-/* Read escape summary for E from BP. */
-
-static void
-modref_read_escape_summary (struct bitpack_d *bp, cgraph_edge *e)
-{
- unsigned int n = bp_unpack_var_len_unsigned (bp);
- if (!n)
- return;
- escape_summary *esum = escape_summaries->get_create (e);
- esum->esc.reserve_exact (n);
- for (unsigned int i = 0; i < n; i++)
- {
- escape_entry ee;
- ee.parm_index = bp_unpack_var_len_int (bp);
- ee.arg = bp_unpack_var_len_unsigned (bp);
- ee.min_flags = bp_unpack_var_len_unsigned (bp);
- ee.direct = bp_unpack_value (bp, 1);
- esum->esc.quick_push (ee);
- }
-}
-
-/* Callback for write_summary. */
-
-static void
-modref_write ()
-{
- struct output_block *ob = create_output_block (LTO_section_ipa_modref);
- lto_symtab_encoder_t encoder = ob->decl_state->symtab_node_encoder;
- unsigned int count = 0;
- int i;
-
- if (!summaries_lto)
- {
- streamer_write_uhwi (ob, 0);
- streamer_write_char_stream (ob->main_stream, 0);
- produce_asm (ob, NULL);
- destroy_output_block (ob);
- return;
- }
-
- for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
- {
- symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
- cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
- modref_summary_lto *r;
-
- if (cnode && cnode->definition && !cnode->alias
- && (r = summaries_lto->get (cnode))
- && r->useful_p (flags_from_decl_or_type (cnode->decl)))
- count++;
- }
- streamer_write_uhwi (ob, count);
-
- for (i = 0; i < lto_symtab_encoder_size (encoder); i++)
- {
- symtab_node *snode = lto_symtab_encoder_deref (encoder, i);
- cgraph_node *cnode = dyn_cast <cgraph_node *> (snode);
-
- if (cnode && cnode->definition && !cnode->alias)
- {
- modref_summary_lto *r = summaries_lto->get (cnode);
-
- if (!r || !r->useful_p (flags_from_decl_or_type (cnode->decl)))
- continue;
-
- streamer_write_uhwi (ob, lto_symtab_encoder_encode (encoder, cnode));
-
- streamer_write_uhwi (ob, r->arg_flags.length ());
- for (unsigned int i = 0; i < r->arg_flags.length (); i++)
- streamer_write_uhwi (ob, r->arg_flags[i]);
- streamer_write_uhwi (ob, r->retslot_flags);
- streamer_write_uhwi (ob, r->static_chain_flags);
-
- write_modref_records (r->loads, ob);
- write_modref_records (r->stores, ob);
- streamer_write_uhwi (ob, r->kills.length ());
- for (auto kill : r->kills)
- kill.stream_out (ob);
-
- struct bitpack_d bp = bitpack_create (ob->main_stream);
- bp_pack_value (&bp, r->writes_errno, 1);
- bp_pack_value (&bp, r->side_effects, 1);
- bp_pack_value (&bp, r->nondeterministic, 1);
- bp_pack_value (&bp, r->calls_interposable, 1);
- if (!flag_wpa)
- {
- for (cgraph_edge *e = cnode->indirect_calls;
- e; e = e->next_callee)
- {
- class fnspec_summary *sum = fnspec_summaries->get (e);
- bp_pack_value (&bp, sum != NULL, 1);
- if (sum)
- bp_pack_string (ob, &bp, sum->fnspec, true);
- class escape_summary *esum = escape_summaries->get (e);
- modref_write_escape_summary (&bp,esum);
- }
- for (cgraph_edge *e = cnode->callees; e; e = e->next_callee)
- {
- class fnspec_summary *sum = fnspec_summaries->get (e);
- bp_pack_value (&bp, sum != NULL, 1);
- if (sum)
- bp_pack_string (ob, &bp, sum->fnspec, true);
- class escape_summary *esum = escape_summaries->get (e);
- modref_write_escape_summary (&bp,esum);
- }
- }
- streamer_write_bitpack (&bp);
- }
- }
- streamer_write_char_stream (ob->main_stream, 0);
- produce_asm (ob, NULL);
- destroy_output_block (ob);
-}
-
-static void
-read_section (struct lto_file_decl_data *file_data, const char *data,
- size_t len)
-{
- const struct lto_function_header *header
- = (const struct lto_function_header *) data;
- const int cfg_offset = sizeof (struct lto_function_header);
- const int main_offset = cfg_offset + header->cfg_size;
- const int string_offset = main_offset + header->main_size;
- struct data_in *data_in;
- unsigned int i;
- unsigned int f_count;
-
- lto_input_block ib ((const char *) data + main_offset, header->main_size,
- file_data->mode_table);
-
- data_in
- = lto_data_in_create (file_data, (const char *) data + string_offset,
- header->string_size, vNULL);
- f_count = streamer_read_uhwi (&ib);
- for (i = 0; i < f_count; i++)
- {
- struct cgraph_node *node;
- lto_symtab_encoder_t encoder;
-
- unsigned int index = streamer_read_uhwi (&ib);
- encoder = file_data->symtab_node_encoder;
- node = dyn_cast <cgraph_node *> (lto_symtab_encoder_deref (encoder,
- index));
-
- modref_summary *modref_sum = summaries
- ? summaries->get_create (node) : NULL;
- modref_summary_lto *modref_sum_lto = summaries_lto
- ? summaries_lto->get_create (node)
- : NULL;
- if (optimization_summaries)
- modref_sum = optimization_summaries->get_create (node);
-
- if (modref_sum)
- {
- modref_sum->writes_errno = false;
- modref_sum->side_effects = false;
- modref_sum->nondeterministic = false;
- modref_sum->calls_interposable = false;
- }
- if (modref_sum_lto)
- {
- modref_sum_lto->writes_errno = false;
- modref_sum_lto->side_effects = false;
- modref_sum_lto->nondeterministic = false;
- modref_sum_lto->calls_interposable = false;
- }
-
- gcc_assert (!modref_sum || (!modref_sum->loads
- && !modref_sum->stores));
- gcc_assert (!modref_sum_lto || (!modref_sum_lto->loads
- && !modref_sum_lto->stores));
- unsigned int args = streamer_read_uhwi (&ib);
- if (args && modref_sum)
- modref_sum->arg_flags.reserve_exact (args);
- if (args && modref_sum_lto)
- modref_sum_lto->arg_flags.reserve_exact (args);
- for (unsigned int i = 0; i < args; i++)
- {
- eaf_flags_t flags = streamer_read_uhwi (&ib);
- if (modref_sum)
- modref_sum->arg_flags.quick_push (flags);
- if (modref_sum_lto)
- modref_sum_lto->arg_flags.quick_push (flags);
- }
- eaf_flags_t flags = streamer_read_uhwi (&ib);
- if (modref_sum)
- modref_sum->retslot_flags = flags;
- if (modref_sum_lto)
- modref_sum_lto->retslot_flags = flags;
-
- flags = streamer_read_uhwi (&ib);
- if (modref_sum)
- modref_sum->static_chain_flags = flags;
- if (modref_sum_lto)
- modref_sum_lto->static_chain_flags = flags;
-
- read_modref_records (node->decl, &ib, data_in,
- modref_sum ? &modref_sum->loads : NULL,
- modref_sum_lto ? &modref_sum_lto->loads : NULL);
- read_modref_records (node->decl, &ib, data_in,
- modref_sum ? &modref_sum->stores : NULL,
- modref_sum_lto ? &modref_sum_lto->stores : NULL);
- int j = streamer_read_uhwi (&ib);
- if (j && modref_sum)
- modref_sum->kills.reserve_exact (j);
- if (j && modref_sum_lto)
- modref_sum_lto->kills.reserve_exact (j);
- for (int k = 0; k < j; k++)
- {
- modref_access_node a = modref_access_node::stream_in (&ib);
-
- if (modref_sum)
- modref_sum->kills.quick_push (a);
- if (modref_sum_lto)
- modref_sum_lto->kills.quick_push (a);
- }
- struct bitpack_d bp = streamer_read_bitpack (&ib);
- if (bp_unpack_value (&bp, 1))
- {
- if (modref_sum)
- modref_sum->writes_errno = true;
- if (modref_sum_lto)
- modref_sum_lto->writes_errno = true;
- }
- if (bp_unpack_value (&bp, 1))
- {
- if (modref_sum)
- modref_sum->side_effects = true;
- if (modref_sum_lto)
- modref_sum_lto->side_effects = true;
- }
- if (bp_unpack_value (&bp, 1))
- {
- if (modref_sum)
- modref_sum->nondeterministic = true;
- if (modref_sum_lto)
- modref_sum_lto->nondeterministic = true;
- }
- if (bp_unpack_value (&bp, 1))
- {
- if (modref_sum)
- modref_sum->calls_interposable = true;
- if (modref_sum_lto)
- modref_sum_lto->calls_interposable = true;
- }
- if (!flag_ltrans)
- {
- for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
- {
- if (bp_unpack_value (&bp, 1))
- {
- class fnspec_summary *sum = fnspec_summaries->get_create (e);
- sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
- }
- modref_read_escape_summary (&bp, e);
- }
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- {
- if (bp_unpack_value (&bp, 1))
- {
- class fnspec_summary *sum = fnspec_summaries->get_create (e);
- sum->fnspec = xstrdup (bp_unpack_string (data_in, &bp));
- }
- modref_read_escape_summary (&bp, e);
- }
- }
- if (flag_ltrans)
- modref_sum->finalize (node->decl);
- if (dump_file)
- {
- fprintf (dump_file, "Read modref for %s\n",
- node->dump_name ());
- if (modref_sum)
- modref_sum->dump (dump_file);
- if (modref_sum_lto)
- modref_sum_lto->dump (dump_file);
- dump_modref_edge_summaries (dump_file, node, 4);
- }
- }
-
- lto_free_section_data (file_data, LTO_section_ipa_modref, NULL, data,
- len);
- lto_data_in_delete (data_in);
-}
-
-/* Callback for read_summary. */
-
-static void
-modref_read (void)
-{
- struct lto_file_decl_data **file_data_vec = lto_get_file_decl_data ();
- struct lto_file_decl_data *file_data;
- unsigned int j = 0;
-
- gcc_checking_assert (!optimization_summaries && !summaries && !summaries_lto);
- if (flag_ltrans)
- optimization_summaries = modref_summaries::create_ggc (symtab);
- else
- {
- if (flag_wpa || flag_incremental_link == INCREMENTAL_LINK_LTO)
- summaries_lto = modref_summaries_lto::create_ggc (symtab);
- if (!flag_wpa
- || (flag_incremental_link == INCREMENTAL_LINK_LTO
- && flag_fat_lto_objects))
- summaries = modref_summaries::create_ggc (symtab);
- if (!fnspec_summaries)
- fnspec_summaries = new fnspec_summaries_t (symtab);
- if (!escape_summaries)
- escape_summaries = new escape_summaries_t (symtab);
- }
-
- while ((file_data = file_data_vec[j++]))
- {
- size_t len;
- const char *data = lto_get_summary_section_data (file_data,
- LTO_section_ipa_modref,
- &len);
- if (data)
- read_section (file_data, data, len);
- else
- /* Fatal error here. We do not want to support compiling ltrans units
- with different version of compiler or different flags than the WPA
- unit, so this should never happen. */
- fatal_error (input_location,
- "IPA modref summary is missing in input file");
- }
-}
-
-/* Recompute arg_flags for param adjustments in INFO. */
-
-static void
-remap_arg_flags (auto_vec <eaf_flags_t> &arg_flags, clone_info *info)
-{
- auto_vec<eaf_flags_t> old = arg_flags.copy ();
- int max = -1;
- size_t i;
- ipa_adjusted_param *p;
-
- arg_flags.release ();
-
- FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
- {
- int o = info->param_adjustments->get_original_index (i);
- if (o >= 0 && (int)old.length () > o && old[o])
- max = i;
- }
- if (max >= 0)
- arg_flags.safe_grow_cleared (max + 1, true);
- FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
- {
- int o = info->param_adjustments->get_original_index (i);
- if (o >= 0 && (int)old.length () > o && old[o])
- arg_flags[i] = old[o];
- }
-}
-
-/* Update kills accrdoing to the parm map MAP. */
-
-static void
-remap_kills (vec <modref_access_node> &kills, const vec <int> &map)
-{
- for (size_t i = 0; i < kills.length ();)
- if (kills[i].parm_index >= 0)
- {
- if (kills[i].parm_index < (int)map.length ()
- && map[kills[i].parm_index] != MODREF_UNKNOWN_PARM)
- {
- kills[i].parm_index = map[kills[i].parm_index];
- i++;
- }
- else
- kills.unordered_remove (i);
- }
- else
- i++;
-}
-
-/* If signature changed, update the summary. */
-
-static void
-update_signature (struct cgraph_node *node)
-{
- clone_info *info = clone_info::get (node);
- if (!info || !info->param_adjustments)
- return;
-
- modref_summary *r = optimization_summaries
- ? optimization_summaries->get (node) : NULL;
- modref_summary_lto *r_lto = summaries_lto
- ? summaries_lto->get (node) : NULL;
- if (!r && !r_lto)
- return;
- if (dump_file)
- {
- fprintf (dump_file, "Updating summary for %s from:\n",
- node->dump_name ());
- if (r)
- r->dump (dump_file);
- if (r_lto)
- r_lto->dump (dump_file);
- }
-
- size_t i, max = 0;
- ipa_adjusted_param *p;
-
- FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
- {
- int idx = info->param_adjustments->get_original_index (i);
- if (idx > (int)max)
- max = idx;
- }
-
- auto_vec <int, 32> map;
-
- map.reserve (max + 1);
- for (i = 0; i <= max; i++)
- map.quick_push (MODREF_UNKNOWN_PARM);
- FOR_EACH_VEC_SAFE_ELT (info->param_adjustments->m_adj_params, i, p)
- {
- int idx = info->param_adjustments->get_original_index (i);
- if (idx >= 0)
- map[idx] = i;
- }
- if (r)
- {
- r->loads->remap_params (&map);
- r->stores->remap_params (&map);
- remap_kills (r->kills, map);
- if (r->arg_flags.length ())
- remap_arg_flags (r->arg_flags, info);
- }
- if (r_lto)
- {
- r_lto->loads->remap_params (&map);
- r_lto->stores->remap_params (&map);
- remap_kills (r_lto->kills, map);
- if (r_lto->arg_flags.length ())
- remap_arg_flags (r_lto->arg_flags, info);
- }
- if (dump_file)
- {
- fprintf (dump_file, "to:\n");
- if (r)
- r->dump (dump_file);
- if (r_lto)
- r_lto->dump (dump_file);
- }
- if (r)
- r->finalize (node->decl);
- return;
-}
-
-/* Definition of the modref IPA pass. */
-const pass_data pass_data_ipa_modref =
-{
- IPA_PASS, /* type */
- "modref", /* name */
- OPTGROUP_IPA, /* optinfo_flags */
- TV_IPA_MODREF, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- ( TODO_dump_symtab ), /* todo_flags_finish */
-};
-
-class pass_ipa_modref : public ipa_opt_pass_d
-{
-public:
- pass_ipa_modref (gcc::context *ctxt)
- : ipa_opt_pass_d (pass_data_ipa_modref, ctxt,
- modref_generate, /* generate_summary */
- modref_write, /* write_summary */
- modref_read, /* read_summary */
- modref_write, /* write_optimization_summary */
- modref_read, /* read_optimization_summary */
- NULL, /* stmt_fixup */
- 0, /* function_transform_todo_flags_start */
- NULL, /* function_transform */
- NULL) /* variable_transform */
- {}
-
- /* opt_pass methods: */
- opt_pass *clone () { return new pass_ipa_modref (m_ctxt); }
- virtual bool gate (function *)
- {
- return true;
- }
- virtual unsigned int execute (function *);
-
-};
-
-}
-
-unsigned int pass_modref::execute (function *)
-{
- if (analyze_function (false))
- return execute_fixup_cfg ();
- return 0;
-}
-
-gimple_opt_pass *
-make_pass_modref (gcc::context *ctxt)
-{
- return new pass_modref (ctxt);
-}
-
-ipa_opt_pass_d *
-make_pass_ipa_modref (gcc::context *ctxt)
-{
- return new pass_ipa_modref (ctxt);
-}
-
-namespace {
-
-/* Skip edges from and to nodes without ipa_pure_const enabled.
- Ignore not available symbols. */
-
-static bool
-ignore_edge (struct cgraph_edge *e)
-{
- /* We merge summaries of inline clones into summaries of functions they
- are inlined to. For that reason the complete function bodies must
- act as unit. */
- if (!e->inline_failed)
- return false;
- enum availability avail;
- cgraph_node *callee = e->callee->ultimate_alias_target
- (&avail, e->caller);
-
- return (avail <= AVAIL_INTERPOSABLE
- || ((!optimization_summaries || !optimization_summaries->get (callee))
- && (!summaries_lto || !summaries_lto->get (callee))));
-}
-
-/* Compute parm_map for CALLEE_EDGE. */
-
-static bool
-compute_parm_map (cgraph_edge *callee_edge, vec<modref_parm_map> *parm_map)
-{
- class ipa_edge_args *args;
- if (ipa_node_params_sum
- && !callee_edge->call_stmt_cannot_inline_p
- && (args = ipa_edge_args_sum->get (callee_edge)) != NULL)
- {
- int i, count = ipa_get_cs_argument_count (args);
- class ipa_node_params *caller_parms_info, *callee_pi;
- class ipa_call_summary *es
- = ipa_call_summaries->get (callee_edge);
- cgraph_node *callee
- = callee_edge->callee->ultimate_alias_target
- (NULL, callee_edge->caller);
-
- caller_parms_info
- = ipa_node_params_sum->get (callee_edge->caller->inlined_to
- ? callee_edge->caller->inlined_to
- : callee_edge->caller);
- callee_pi = ipa_node_params_sum->get (callee);
-
- (*parm_map).safe_grow_cleared (count, true);
-
- for (i = 0; i < count; i++)
- {
- if (es && es->param[i].points_to_local_or_readonly_memory)
- {
- (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
- continue;
- }
-
- struct ipa_jump_func *jf
- = ipa_get_ith_jump_func (args, i);
- if (jf && callee_pi)
- {
- tree cst = ipa_value_from_jfunc (caller_parms_info,
- jf,
- ipa_get_type
- (callee_pi, i));
- if (cst && points_to_local_or_readonly_memory_p (cst))
- {
- (*parm_map)[i].parm_index = MODREF_LOCAL_MEMORY_PARM;
- continue;
- }
- }
- if (jf && jf->type == IPA_JF_PASS_THROUGH)
- {
- (*parm_map)[i].parm_index
- = ipa_get_jf_pass_through_formal_id (jf);
- if (ipa_get_jf_pass_through_operation (jf) == NOP_EXPR)
- {
- (*parm_map)[i].parm_offset_known = true;
- (*parm_map)[i].parm_offset = 0;
- }
- else if (ipa_get_jf_pass_through_operation (jf)
- == POINTER_PLUS_EXPR
- && ptrdiff_tree_p (ipa_get_jf_pass_through_operand (jf),
- &(*parm_map)[i].parm_offset))
- (*parm_map)[i].parm_offset_known = true;
- else
- (*parm_map)[i].parm_offset_known = false;
- continue;
- }
- if (jf && jf->type == IPA_JF_ANCESTOR)
- {
- (*parm_map)[i].parm_index = ipa_get_jf_ancestor_formal_id (jf);
- (*parm_map)[i].parm_offset_known = true;
- gcc_checking_assert
- (!(ipa_get_jf_ancestor_offset (jf) & (BITS_PER_UNIT - 1)));
- (*parm_map)[i].parm_offset
- = ipa_get_jf_ancestor_offset (jf) >> LOG2_BITS_PER_UNIT;
- }
- else
- (*parm_map)[i].parm_index = -1;
- }
- if (dump_file)
- {
- fprintf (dump_file, " Parm map: ");
- for (i = 0; i < count; i++)
- fprintf (dump_file, " %i", (*parm_map)[i].parm_index);
- fprintf (dump_file, "\n");
- }
- return true;
- }
- return false;
-}
-
-/* Map used to translate escape infos. */
-
-struct escape_map
-{
- int parm_index;
- bool direct;
-};
-
-/* Update escape map for E. */
-
-static void
-update_escape_summary_1 (cgraph_edge *e,
- vec <vec <escape_map>> &map,
- bool ignore_stores)
-{
- escape_summary *sum = escape_summaries->get (e);
- if (!sum)
- return;
- auto_vec <escape_entry> old = sum->esc.copy ();
- sum->esc.release ();
-
- unsigned int i;
- escape_entry *ee;
- FOR_EACH_VEC_ELT (old, i, ee)
- {
- unsigned int j;
- struct escape_map *em;
- /* TODO: We do not have jump functions for return slots, so we
- never propagate them to outer function. */
- if (ee->parm_index >= (int)map.length ()
- || ee->parm_index < 0)
- continue;
- FOR_EACH_VEC_ELT (map[ee->parm_index], j, em)
- {
- int min_flags = ee->min_flags;
- if (ee->direct && !em->direct)
- min_flags = deref_flags (min_flags, ignore_stores);
- struct escape_entry entry = {em->parm_index, ee->arg,
- min_flags,
- ee->direct & em->direct};
- sum->esc.safe_push (entry);
- }
- }
- if (!sum->esc.length ())
- escape_summaries->remove (e);
-}
-
-/* Update escape map fo NODE. */
-
-static void
-update_escape_summary (cgraph_node *node,
- vec <vec <escape_map>> &map,
- bool ignore_stores)
-{
- if (!escape_summaries)
- return;
- for (cgraph_edge *e = node->indirect_calls; e; e = e->next_callee)
- update_escape_summary_1 (e, map, ignore_stores);
- for (cgraph_edge *e = node->callees; e; e = e->next_callee)
- {
- if (!e->inline_failed)
- update_escape_summary (e->callee, map, ignore_stores);
- else
- update_escape_summary_1 (e, map, ignore_stores);
- }
-}
-
-/* Get parameter type from DECL. This is only safe for special cases
- like builtins we create fnspec for because the type match is checked
- at fnspec creation time. */
-
-static tree
-get_parm_type (tree decl, unsigned int i)
-{
- tree t = TYPE_ARG_TYPES (TREE_TYPE (decl));
-
- for (unsigned int p = 0; p < i; p++)
- t = TREE_CHAIN (t);
- return TREE_VALUE (t);
-}
-
-/* Return access mode for argument I of call E with FNSPEC. */
-
-static modref_access_node
-get_access_for_fnspec (cgraph_edge *e, attr_fnspec &fnspec,
- unsigned int i, modref_parm_map &map)
-{
- tree size = NULL_TREE;
- unsigned int size_arg;
-
- if (!fnspec.arg_specified_p (i))
- ;
- else if (fnspec.arg_max_access_size_given_by_arg_p (i, &size_arg))
- {
- cgraph_node *node = e->caller->inlined_to
- ? e->caller->inlined_to : e->caller;
- ipa_node_params *caller_parms_info = ipa_node_params_sum->get (node);
- ipa_edge_args *args = ipa_edge_args_sum->get (e);
- struct ipa_jump_func *jf = ipa_get_ith_jump_func (args, size_arg);
-
- if (jf)
- size = ipa_value_from_jfunc (caller_parms_info, jf,
- get_parm_type (e->callee->decl, size_arg));
- }
- else if (fnspec.arg_access_size_given_by_type_p (i))
- size = TYPE_SIZE_UNIT (get_parm_type (e->callee->decl, i));
- modref_access_node a = {0, -1, -1,
- map.parm_offset, map.parm_index,
- map.parm_offset_known, 0};
- poly_int64 size_hwi;
- if (size
- && poly_int_tree_p (size, &size_hwi)
- && coeffs_in_range_p (size_hwi, 0,
- HOST_WIDE_INT_MAX / BITS_PER_UNIT))
- {
- a.size = -1;
- a.max_size = size_hwi << LOG2_BITS_PER_UNIT;
- }
- return a;
-}
-
- /* Collapse loads and return true if something changed. */
-static bool
-collapse_loads (modref_summary *cur_summary,
- modref_summary_lto *cur_summary_lto)
-{
- bool changed = false;
-
- if (cur_summary && !cur_summary->loads->every_base)
- {
- cur_summary->loads->collapse ();
- changed = true;
- }
- if (cur_summary_lto
- && !cur_summary_lto->loads->every_base)
- {
- cur_summary_lto->loads->collapse ();
- changed = true;
- }
- return changed;
-}
-
-/* Collapse loads and return true if something changed. */
-
-static bool
-collapse_stores (modref_summary *cur_summary,
- modref_summary_lto *cur_summary_lto)
-{
- bool changed = false;
-
- if (cur_summary && !cur_summary->stores->every_base)
- {
- cur_summary->stores->collapse ();
- changed = true;
- }
- if (cur_summary_lto
- && !cur_summary_lto->stores->every_base)
- {
- cur_summary_lto->stores->collapse ();
- changed = true;
- }
- return changed;
-}
-
-/* Call E in NODE with ECF_FLAGS has no summary; update MODREF_SUMMARY and
- CUR_SUMMARY_LTO accordingly. Return true if something changed. */
-
-static bool
-propagate_unknown_call (cgraph_node *node,
- cgraph_edge *e, int ecf_flags,
- modref_summary *cur_summary,
- modref_summary_lto *cur_summary_lto,
- bool nontrivial_scc)
-{
- bool changed = false;
- class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
- auto_vec <modref_parm_map, 32> parm_map;
- bool looping;
-
- if (e->callee
- && builtin_safe_for_const_function_p (&looping, e->callee->decl))
- {
- if (looping && cur_summary && !cur_summary->side_effects)
- {
- cur_summary->side_effects = true;
- changed = true;
- }
- if (looping && cur_summary_lto && !cur_summary_lto->side_effects)
- {
- cur_summary_lto->side_effects = true;
- changed = true;
- }
- return changed;
- }
-
- if (!(ecf_flags & (ECF_CONST | ECF_NOVOPS | ECF_PURE))
- || (ecf_flags & ECF_LOOPING_CONST_OR_PURE)
- || nontrivial_scc)
- {
- if (cur_summary && !cur_summary->side_effects)
- {
- cur_summary->side_effects = true;
- changed = true;
- }
- if (cur_summary_lto && !cur_summary_lto->side_effects)
- {
- cur_summary_lto->side_effects = true;
- changed = true;
- }
- if (cur_summary && !cur_summary->nondeterministic
- && !ignore_nondeterminism_p (node->decl, ecf_flags))
- {
- cur_summary->nondeterministic = true;
- changed = true;
- }
- if (cur_summary_lto && !cur_summary_lto->nondeterministic
- && !ignore_nondeterminism_p (node->decl, ecf_flags))
- {
- cur_summary_lto->nondeterministic = true;
- changed = true;
- }
- }
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS))
- return changed;
-
- if (fnspec_sum
- && compute_parm_map (e, &parm_map))
- {
- attr_fnspec fnspec (fnspec_sum->fnspec);
-
- gcc_checking_assert (fnspec.known_p ());
- if (fnspec.global_memory_read_p ())
- collapse_loads (cur_summary, cur_summary_lto);
- else
- {
- tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
- for (unsigned i = 0; i < parm_map.length () && t;
- i++, t = TREE_CHAIN (t))
- if (!POINTER_TYPE_P (TREE_VALUE (t)))
- ;
- else if (!fnspec.arg_specified_p (i)
- || fnspec.arg_maybe_read_p (i))
- {
- modref_parm_map map = parm_map[i];
- if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
- continue;
- if (map.parm_index == MODREF_UNKNOWN_PARM)
- {
- collapse_loads (cur_summary, cur_summary_lto);
- break;
- }
- if (cur_summary)
- changed |= cur_summary->loads->insert
- (node->decl, 0, 0,
- get_access_for_fnspec (e, fnspec, i, map), false);
- if (cur_summary_lto)
- changed |= cur_summary_lto->loads->insert
- (node->decl, 0, 0,
- get_access_for_fnspec (e, fnspec, i, map), false);
- }
- }
- if (ignore_stores_p (node->decl, ecf_flags))
- ;
- else if (fnspec.global_memory_written_p ())
- collapse_stores (cur_summary, cur_summary_lto);
- else
- {
- tree t = TYPE_ARG_TYPES (TREE_TYPE (e->callee->decl));
- for (unsigned i = 0; i < parm_map.length () && t;
- i++, t = TREE_CHAIN (t))
- if (!POINTER_TYPE_P (TREE_VALUE (t)))
- ;
- else if (!fnspec.arg_specified_p (i)
- || fnspec.arg_maybe_written_p (i))
- {
- modref_parm_map map = parm_map[i];
- if (map.parm_index == MODREF_LOCAL_MEMORY_PARM)
- continue;
- if (map.parm_index == MODREF_UNKNOWN_PARM)
- {
- collapse_stores (cur_summary, cur_summary_lto);
- break;
- }
- if (cur_summary)
- changed |= cur_summary->stores->insert
- (node->decl, 0, 0,
- get_access_for_fnspec (e, fnspec, i, map), false);
- if (cur_summary_lto)
- changed |= cur_summary_lto->stores->insert
- (node->decl, 0, 0,
- get_access_for_fnspec (e, fnspec, i, map), false);
- }
- }
- if (fnspec.errno_maybe_written_p () && flag_errno_math)
- {
- if (cur_summary && !cur_summary->writes_errno)
- {
- cur_summary->writes_errno = true;
- changed = true;
- }
- if (cur_summary_lto && !cur_summary_lto->writes_errno)
- {
- cur_summary_lto->writes_errno = true;
- changed = true;
- }
- }
- return changed;
- }
- if (dump_file)
- fprintf (dump_file, " collapsing loads\n");
- changed |= collapse_loads (cur_summary, cur_summary_lto);
- if (!ignore_stores_p (node->decl, ecf_flags))
- {
- if (dump_file)
- fprintf (dump_file, " collapsing stores\n");
- changed |= collapse_stores (cur_summary, cur_summary_lto);
- }
- return changed;
-}
-
-/* Maybe remove summaies of NODE pointed to by CUR_SUMMARY_PTR
- and CUR_SUMMARY_LTO_PTR if they are useless according to ECF_FLAGS. */
-
-static void
-remove_useless_summaries (cgraph_node *node,
- modref_summary **cur_summary_ptr,
- modref_summary_lto **cur_summary_lto_ptr,
- int ecf_flags)
-{
- if (*cur_summary_ptr && !(*cur_summary_ptr)->useful_p (ecf_flags, false))
- {
- optimization_summaries->remove (node);
- *cur_summary_ptr = NULL;
- }
- if (*cur_summary_lto_ptr
- && !(*cur_summary_lto_ptr)->useful_p (ecf_flags, false))
- {
- summaries_lto->remove (node);
- *cur_summary_lto_ptr = NULL;
- }
-}
-
-/* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
- and propagate loads/stores. */
-
-static bool
-modref_propagate_in_scc (cgraph_node *component_node)
-{
- bool changed = true;
- bool first = true;
- int iteration = 0;
-
- while (changed)
- {
- bool nontrivial_scc
- = ((struct ipa_dfs_info *) component_node->aux)->next_cycle;
- changed = false;
- for (struct cgraph_node *cur = component_node; cur;
- cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
- {
- cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
- modref_summary *cur_summary = optimization_summaries
- ? optimization_summaries->get (node)
- : NULL;
- modref_summary_lto *cur_summary_lto = summaries_lto
- ? summaries_lto->get (node)
- : NULL;
-
- if (!cur_summary && !cur_summary_lto)
- continue;
-
- int cur_ecf_flags = flags_from_decl_or_type (node->decl);
-
- if (dump_file)
- fprintf (dump_file, " Processing %s%s%s\n",
- cur->dump_name (),
- TREE_READONLY (cur->decl) ? " (const)" : "",
- DECL_PURE_P (cur->decl) ? " (pure)" : "");
-
- for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
- {
- if (dump_file)
- fprintf (dump_file, " Indirect call\n");
- if (propagate_unknown_call
- (node, e, e->indirect_info->ecf_flags,
- cur_summary, cur_summary_lto,
- nontrivial_scc))
- {
- changed = true;
- remove_useless_summaries (node, &cur_summary,
- &cur_summary_lto,
- cur_ecf_flags);
- if (!cur_summary && !cur_summary_lto)
- break;
- }
- }
-
- if (!cur_summary && !cur_summary_lto)
- continue;
-
- for (cgraph_edge *callee_edge = cur->callees; callee_edge;
- callee_edge = callee_edge->next_callee)
- {
- int flags = flags_from_decl_or_type (callee_edge->callee->decl);
- modref_summary *callee_summary = NULL;
- modref_summary_lto *callee_summary_lto = NULL;
- struct cgraph_node *callee;
-
- if (!callee_edge->inline_failed
- || ((flags & (ECF_CONST | ECF_NOVOPS))
- && !(flags & ECF_LOOPING_CONST_OR_PURE)))
- continue;
-
- /* Get the callee and its summary. */
- enum availability avail;
- callee = callee_edge->callee->ultimate_alias_target
- (&avail, cur);
-
- /* It is not necessary to re-process calls outside of the
- SCC component. */
- if (iteration > 0
- && (!callee->aux
- || ((struct ipa_dfs_info *)cur->aux)->scc_no
- != ((struct ipa_dfs_info *)callee->aux)->scc_no))
- continue;
-
- if (dump_file)
- fprintf (dump_file, " Call to %s\n",
- callee_edge->callee->dump_name ());
-
- bool ignore_stores = ignore_stores_p (cur->decl, flags);
-
- if (avail <= AVAIL_INTERPOSABLE)
- {
- if (dump_file)
- fprintf (dump_file, " Call target interposable"
- " or not available\n");
- changed |= propagate_unknown_call
- (node, callee_edge, flags,
- cur_summary, cur_summary_lto,
- nontrivial_scc);
- if (!cur_summary && !cur_summary_lto)
- break;
- continue;
- }
-
- /* We don't know anything about CALLEE, hence we cannot tell
- anything about the entire component. */
-
- if (cur_summary
- && !(callee_summary = optimization_summaries->get (callee)))
- {
- if (dump_file)
- fprintf (dump_file, " No call target summary\n");
- changed |= propagate_unknown_call
- (node, callee_edge, flags,
- cur_summary, NULL,
- nontrivial_scc);
- }
- if (cur_summary_lto
- && !(callee_summary_lto = summaries_lto->get (callee)))
- {
- if (dump_file)
- fprintf (dump_file, " No call target summary\n");
- changed |= propagate_unknown_call
- (node, callee_edge, flags,
- NULL, cur_summary_lto,
- nontrivial_scc);
- }
-
- if (callee_summary && !cur_summary->side_effects
- && (callee_summary->side_effects
- || callee_edge->recursive_p ()))
- {
- cur_summary->side_effects = true;
- changed = true;
- }
- if (callee_summary_lto && !cur_summary_lto->side_effects
- && (callee_summary_lto->side_effects
- || callee_edge->recursive_p ()))
- {
- cur_summary_lto->side_effects = true;
- changed = true;
- }
- if (callee_summary && !cur_summary->nondeterministic
- && callee_summary->nondeterministic
- && !ignore_nondeterminism_p (cur->decl, flags))
- {
- cur_summary->nondeterministic = true;
- changed = true;
- }
- if (callee_summary_lto && !cur_summary_lto->nondeterministic
- && callee_summary_lto->nondeterministic
- && !ignore_nondeterminism_p (cur->decl, flags))
- {
- cur_summary_lto->nondeterministic = true;
- changed = true;
- }
- if (flags & (ECF_CONST | ECF_NOVOPS))
- continue;
-
- /* We can not safely optimize based on summary of callee if it
- does not always bind to current def: it is possible that
- memory load was optimized out earlier which may not happen in
- the interposed variant. */
- if (!callee_edge->binds_to_current_def_p ())
- {
- if (cur_summary && !cur_summary->calls_interposable)
- {
- cur_summary->calls_interposable = true;
- changed = true;
- }
- if (cur_summary_lto && !cur_summary_lto->calls_interposable)
- {
- cur_summary_lto->calls_interposable = true;
- changed = true;
- }
- if (dump_file)
- fprintf (dump_file, " May not bind local;"
- " collapsing loads\n");
- }
-
-
- auto_vec <modref_parm_map, 32> parm_map;
- modref_parm_map chain_map;
- /* TODO: Once we get jump functions for static chains we could
- compute this. */
- chain_map.parm_index = MODREF_UNKNOWN_PARM;
-
- compute_parm_map (callee_edge, &parm_map);
-
- /* Merge in callee's information. */
- if (callee_summary)
- {
- changed |= cur_summary->loads->merge
- (node->decl, callee_summary->loads,
- &parm_map, &chain_map, !first);
- if (!ignore_stores)
- {
- changed |= cur_summary->stores->merge
- (node->decl, callee_summary->stores,
- &parm_map, &chain_map, !first);
- if (!cur_summary->writes_errno
- && callee_summary->writes_errno)
- {
- cur_summary->writes_errno = true;
- changed = true;
- }
- }
- }
- if (callee_summary_lto)
- {
- changed |= cur_summary_lto->loads->merge
- (node->decl, callee_summary_lto->loads,
- &parm_map, &chain_map, !first);
- if (!ignore_stores)
- {
- changed |= cur_summary_lto->stores->merge
- (node->decl, callee_summary_lto->stores,
- &parm_map, &chain_map, !first);
- if (!cur_summary_lto->writes_errno
- && callee_summary_lto->writes_errno)
- {
- cur_summary_lto->writes_errno = true;
- changed = true;
- }
- }
- }
- if (changed)
- remove_useless_summaries (node, &cur_summary,
- &cur_summary_lto,
- cur_ecf_flags);
- if (!cur_summary && !cur_summary_lto)
- break;
- if (dump_file && changed)
- {
- if (cur_summary)
- cur_summary->dump (dump_file);
- if (cur_summary_lto)
- cur_summary_lto->dump (dump_file);
- dump_modref_edge_summaries (dump_file, node, 4);
- }
- }
- }
- iteration++;
- first = false;
- }
- if (dump_file)
- fprintf (dump_file,
- "Propagation finished in %i iterations\n", iteration);
- bool pureconst = false;
- for (struct cgraph_node *cur = component_node; cur;
- cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
- if (!cur->inlined_to && opt_for_fn (cur->decl, flag_ipa_pure_const))
- {
- modref_summary *summary = optimization_summaries
- ? optimization_summaries->get (cur)
- : NULL;
- modref_summary_lto *summary_lto = summaries_lto
- ? summaries_lto->get (cur)
- : NULL;
- if (summary && !summary->stores->every_base && !summary->stores->bases
- && !summary->nondeterministic)
- {
- if (!summary->loads->every_base && !summary->loads->bases
- && !summary->calls_interposable)
- pureconst |= ipa_make_function_const
- (cur, summary->side_effects, false);
- else
- pureconst |= ipa_make_function_pure
- (cur, summary->side_effects, false);
- }
- if (summary_lto && !summary_lto->stores->every_base
- && !summary_lto->stores->bases && !summary_lto->nondeterministic)
- {
- if (!summary_lto->loads->every_base && !summary_lto->loads->bases
- && !summary_lto->calls_interposable)
- pureconst |= ipa_make_function_const
- (cur, summary_lto->side_effects, false);
- else
- pureconst |= ipa_make_function_pure
- (cur, summary_lto->side_effects, false);
- }
- }
- return pureconst;
-}
-
-/* Dump results of propagation in SCC rooted in COMPONENT_NODE. */
-
-static void
-modref_propagate_dump_scc (cgraph_node *component_node)
-{
- for (struct cgraph_node *cur = component_node; cur;
- cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
- if (!cur->inlined_to)
- {
- modref_summary *cur_summary = optimization_summaries
- ? optimization_summaries->get (cur)
- : NULL;
- modref_summary_lto *cur_summary_lto = summaries_lto
- ? summaries_lto->get (cur)
- : NULL;
-
- fprintf (dump_file, "Propagated modref for %s%s%s\n",
- cur->dump_name (),
- TREE_READONLY (cur->decl) ? " (const)" : "",
- DECL_PURE_P (cur->decl) ? " (pure)" : "");
- if (optimization_summaries)
- {
- if (cur_summary)
- cur_summary->dump (dump_file);
- else
- fprintf (dump_file, " Not tracked\n");
- }
- if (summaries_lto)
- {
- if (cur_summary_lto)
- cur_summary_lto->dump (dump_file);
- else
- fprintf (dump_file, " Not tracked (lto)\n");
- }
- }
-}
-
-/* Determine EAF flags know for call E with CALLEE_ECF_FLAGS and ARG. */
-
-int
-implicit_eaf_flags_for_edge_and_arg (cgraph_edge *e, int callee_ecf_flags,
- bool ignore_stores, int arg)
-{
- /* Returning the value is already accounted to at local propagation. */
- int implicit_flags = EAF_NOT_RETURNED_DIRECTLY
- | EAF_NOT_RETURNED_INDIRECTLY;
- if (ignore_stores)
- implicit_flags |= ignore_stores_eaf_flags;
- if (callee_ecf_flags & ECF_PURE)
- implicit_flags |= implicit_pure_eaf_flags;
- if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
- implicit_flags |= implicit_const_eaf_flags;
- class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
- if (fnspec_sum)
- {
- attr_fnspec fnspec (fnspec_sum->fnspec);
- implicit_flags |= fnspec.arg_eaf_flags (arg);
- }
- return implicit_flags;
-}
-
-/* Process escapes in SUM and merge SUMMARY to CUR_SUMMARY
- and SUMMARY_LTO to CUR_SUMMARY_LTO.
- Return true if something changed. */
-
-static bool
-modref_merge_call_site_flags (escape_summary *sum,
- modref_summary *cur_summary,
- modref_summary_lto *cur_summary_lto,
- modref_summary *summary,
- modref_summary_lto *summary_lto,
- tree caller,
- cgraph_edge *e,
- int caller_ecf_flags,
- int callee_ecf_flags,
- bool binds_to_current_def)
-{
- escape_entry *ee;
- unsigned int i;
- bool changed = false;
- bool ignore_stores = ignore_stores_p (caller, callee_ecf_flags);
-
- /* Return early if we have no useful info to propagate. */
- if ((!cur_summary
- || (!cur_summary->arg_flags.length ()
- && !cur_summary->static_chain_flags
- && !cur_summary->retslot_flags))
- && (!cur_summary_lto
- || (!cur_summary_lto->arg_flags.length ()
- && !cur_summary_lto->static_chain_flags
- && !cur_summary_lto->retslot_flags)))
- return false;
-
- FOR_EACH_VEC_ELT (sum->esc, i, ee)
- {
- int flags = 0;
- int flags_lto = 0;
- int implicit_flags = implicit_eaf_flags_for_edge_and_arg
- (e, callee_ecf_flags, ignore_stores, ee->arg);
-
- if (summary && ee->arg < summary->arg_flags.length ())
- flags = summary->arg_flags[ee->arg];
- if (summary_lto
- && ee->arg < summary_lto->arg_flags.length ())
- flags_lto = summary_lto->arg_flags[ee->arg];
- if (!ee->direct)
- {
- flags = deref_flags (flags, ignore_stores);
- flags_lto = deref_flags (flags_lto, ignore_stores);
- }
- if (ignore_stores)
- implicit_flags |= ignore_stores_eaf_flags;
- if (callee_ecf_flags & ECF_PURE)
- implicit_flags |= implicit_pure_eaf_flags;
- if (callee_ecf_flags & (ECF_CONST | ECF_NOVOPS))
- implicit_flags |= implicit_const_eaf_flags;
- class fnspec_summary *fnspec_sum = fnspec_summaries->get (e);
- if (fnspec_sum)
- {
- attr_fnspec fnspec (fnspec_sum->fnspec);
- implicit_flags |= fnspec.arg_eaf_flags (ee->arg);
- }
- if (!ee->direct)
- implicit_flags = deref_flags (implicit_flags, ignore_stores);
- flags |= implicit_flags;
- flags_lto |= implicit_flags;
- if (!binds_to_current_def && (flags || flags_lto))
- {
- flags = interposable_eaf_flags (flags, implicit_flags);
- flags_lto = interposable_eaf_flags (flags_lto, implicit_flags);
- }
- if (!(flags & EAF_UNUSED)
- && cur_summary && ee->parm_index < (int)cur_summary->arg_flags.length ())
- {
- eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
- ? cur_summary->retslot_flags
- : ee->parm_index == MODREF_STATIC_CHAIN_PARM
- ? cur_summary->static_chain_flags
- : cur_summary->arg_flags[ee->parm_index];
- if ((f & flags) != f)
- {
- f = remove_useless_eaf_flags
- (f & flags, caller_ecf_flags,
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
- changed = true;
- }
- }
- if (!(flags_lto & EAF_UNUSED)
- && cur_summary_lto
- && ee->parm_index < (int)cur_summary_lto->arg_flags.length ())
- {
- eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
- ? cur_summary_lto->retslot_flags
- : ee->parm_index == MODREF_STATIC_CHAIN_PARM
- ? cur_summary_lto->static_chain_flags
- : cur_summary_lto->arg_flags[ee->parm_index];
- if ((f & flags_lto) != f)
- {
- f = remove_useless_eaf_flags
- (f & flags_lto, caller_ecf_flags,
- VOID_TYPE_P (TREE_TYPE (TREE_TYPE (caller))));
- changed = true;
- }
- }
- }
- return changed;
-}
-
-/* Perform iterative dataflow on SCC component starting in COMPONENT_NODE
- and propagate arg flags. */
-
-static void
-modref_propagate_flags_in_scc (cgraph_node *component_node)
-{
- bool changed = true;
- int iteration = 0;
-
- while (changed)
- {
- changed = false;
- for (struct cgraph_node *cur = component_node; cur;
- cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
- {
- cgraph_node *node = cur->inlined_to ? cur->inlined_to : cur;
- modref_summary *cur_summary = optimization_summaries
- ? optimization_summaries->get (node)
- : NULL;
- modref_summary_lto *cur_summary_lto = summaries_lto
- ? summaries_lto->get (node)
- : NULL;
-
- if (!cur_summary && !cur_summary_lto)
- continue;
- int caller_ecf_flags = flags_from_decl_or_type (cur->decl);
-
- if (dump_file)
- fprintf (dump_file, " Processing %s%s%s\n",
- cur->dump_name (),
- TREE_READONLY (cur->decl) ? " (const)" : "",
- DECL_PURE_P (cur->decl) ? " (pure)" : "");
-
- for (cgraph_edge *e = cur->indirect_calls; e; e = e->next_callee)
- {
- escape_summary *sum = escape_summaries->get (e);
-
- if (!sum || (e->indirect_info->ecf_flags
- & (ECF_CONST | ECF_NOVOPS)))
- continue;
-
- changed |= modref_merge_call_site_flags
- (sum, cur_summary, cur_summary_lto,
- NULL, NULL,
- node->decl,
- e,
- caller_ecf_flags,
- e->indirect_info->ecf_flags,
- false);
- }
-
- if (!cur_summary && !cur_summary_lto)
- continue;
-
- for (cgraph_edge *callee_edge = cur->callees; callee_edge;
- callee_edge = callee_edge->next_callee)
- {
- int ecf_flags = flags_from_decl_or_type
- (callee_edge->callee->decl);
- modref_summary *callee_summary = NULL;
- modref_summary_lto *callee_summary_lto = NULL;
- struct cgraph_node *callee;
-
- if (ecf_flags & (ECF_CONST | ECF_NOVOPS)
- || !callee_edge->inline_failed)
- continue;
-
- /* Get the callee and its summary. */
- enum availability avail;
- callee = callee_edge->callee->ultimate_alias_target
- (&avail, cur);
-
- /* It is not necessary to re-process calls outside of the
- SCC component. */
- if (iteration > 0
- && (!callee->aux
- || ((struct ipa_dfs_info *)cur->aux)->scc_no
- != ((struct ipa_dfs_info *)callee->aux)->scc_no))
- continue;
-
- escape_summary *sum = escape_summaries->get (callee_edge);
- if (!sum)
- continue;
-
- if (dump_file)
- fprintf (dump_file, " Call to %s\n",
- callee_edge->callee->dump_name ());
-
- if (avail <= AVAIL_INTERPOSABLE
- || callee_edge->call_stmt_cannot_inline_p)
- ;
- else
- {
- if (cur_summary)
- callee_summary = optimization_summaries->get (callee);
- if (cur_summary_lto)
- callee_summary_lto = summaries_lto->get (callee);
- }
- changed |= modref_merge_call_site_flags
- (sum, cur_summary, cur_summary_lto,
- callee_summary, callee_summary_lto,
- node->decl,
- callee_edge,
- caller_ecf_flags,
- ecf_flags,
- callee->binds_to_current_def_p ());
- if (dump_file && changed)
- {
- if (cur_summary)
- cur_summary->dump (dump_file);
- if (cur_summary_lto)
- cur_summary_lto->dump (dump_file);
- }
- }
- }
- iteration++;
- }
- if (dump_file)
- fprintf (dump_file,
- "Propagation of flags finished in %i iterations\n", iteration);
-}
-
-} /* ANON namespace. */
-
-/* Call EDGE was inlined; merge summary from callee to the caller. */
-
-void
-ipa_merge_modref_summary_after_inlining (cgraph_edge *edge)
-{
- if (!summaries && !summaries_lto)
- return;
-
- struct cgraph_node *to = (edge->caller->inlined_to
- ? edge->caller->inlined_to : edge->caller);
- class modref_summary *to_info = summaries ? summaries->get (to) : NULL;
- class modref_summary_lto *to_info_lto = summaries_lto
- ? summaries_lto->get (to) : NULL;
-
- if (!to_info && !to_info_lto)
- {
- if (summaries)
- summaries->remove (edge->callee);
- if (summaries_lto)
- summaries_lto->remove (edge->callee);
- remove_modref_edge_summaries (edge->callee);
- return;
- }
-
- class modref_summary *callee_info = summaries ? summaries->get (edge->callee)
- : NULL;
- class modref_summary_lto *callee_info_lto
- = summaries_lto ? summaries_lto->get (edge->callee) : NULL;
- int flags = flags_from_decl_or_type (edge->callee->decl);
- /* Combine in outer flags. */
- cgraph_node *n;
- for (n = edge->caller; n->inlined_to; n = n->callers->caller)
- flags |= flags_from_decl_or_type (n->decl);
- flags |= flags_from_decl_or_type (n->decl);
- bool ignore_stores = ignore_stores_p (edge->caller->decl, flags);
-
- if (!callee_info && to_info)
- {
- if (!(flags & (ECF_CONST | ECF_NOVOPS)))
- to_info->loads->collapse ();
- if (!ignore_stores)
- to_info->stores->collapse ();
- }
- if (!callee_info_lto && to_info_lto)
- {
- if (!(flags & (ECF_CONST | ECF_NOVOPS)))
- to_info_lto->loads->collapse ();
- if (!ignore_stores)
- to_info_lto->stores->collapse ();
- }
- if (callee_info || callee_info_lto)
- {
- auto_vec <modref_parm_map, 32> parm_map;
- modref_parm_map chain_map;
- /* TODO: Once we get jump functions for static chains we could
- compute parm_index. */
-
- compute_parm_map (edge, &parm_map);
-
- if (!ignore_stores)
- {
- if (to_info && callee_info)
- to_info->stores->merge (to->decl, callee_info->stores, &parm_map,
- &chain_map, false);
- if (to_info_lto && callee_info_lto)
- to_info_lto->stores->merge (to->decl, callee_info_lto->stores,
- &parm_map, &chain_map, false);
- }
- if (!(flags & (ECF_CONST | ECF_NOVOPS)))
- {
- if (to_info && callee_info)
- to_info->loads->merge (to->decl, callee_info->loads, &parm_map,
- &chain_map, false);
- if (to_info_lto && callee_info_lto)
- to_info_lto->loads->merge (to->decl, callee_info_lto->loads,
- &parm_map, &chain_map, false);
- }
- }
-
- /* Now merge escape summaries.
- For every escape to the callee we need to merge calle flags
- and remap calees escapes. */
- class escape_summary *sum = escape_summaries->get (edge);
- int max_escape = -1;
- escape_entry *ee;
- unsigned int i;
-
- if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
- FOR_EACH_VEC_ELT (sum->esc, i, ee)
- if ((int)ee->arg > max_escape)
- max_escape = ee->arg;
-
- auto_vec <vec <struct escape_map>, 32> emap (max_escape + 1);
- emap.safe_grow (max_escape + 1, true);
- for (i = 0; (int)i < max_escape + 1; i++)
- emap[i] = vNULL;
-
- if (sum && !(flags & (ECF_CONST | ECF_NOVOPS)))
- FOR_EACH_VEC_ELT (sum->esc, i, ee)
- {
- bool needed = false;
- int implicit_flags = implicit_eaf_flags_for_edge_and_arg
- (edge, flags, ignore_stores,
- ee->arg);
- if (!ee->direct)
- implicit_flags = deref_flags (implicit_flags, ignore_stores);
- if (to_info && (int)to_info->arg_flags.length () > ee->parm_index)
- {
- int flags = callee_info
- && callee_info->arg_flags.length () > ee->arg
- ? callee_info->arg_flags[ee->arg] : 0;
- if (!ee->direct)
- flags = deref_flags (flags, ignore_stores);
- flags |= ee->min_flags | implicit_flags;
- eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
- ? to_info->retslot_flags
- : ee->parm_index == MODREF_STATIC_CHAIN_PARM
- ? to_info->static_chain_flags
- : to_info->arg_flags[ee->parm_index];
- f &= flags;
- if (f)
- needed = true;
- }
- if (to_info_lto
- && (int)to_info_lto->arg_flags.length () > ee->parm_index)
- {
- int flags = callee_info_lto
- && callee_info_lto->arg_flags.length () > ee->arg
- ? callee_info_lto->arg_flags[ee->arg] : 0;
- if (!ee->direct)
- flags = deref_flags (flags, ignore_stores);
- flags |= ee->min_flags | implicit_flags;
- eaf_flags_t &f = ee->parm_index == MODREF_RETSLOT_PARM
- ? to_info_lto->retslot_flags
- : ee->parm_index == MODREF_STATIC_CHAIN_PARM
- ? to_info_lto->static_chain_flags
- : to_info_lto->arg_flags[ee->parm_index];
- f &= flags;
- if (f)
- needed = true;
- }
- struct escape_map entry = {ee->parm_index, ee->direct};
- if (needed)
- emap[ee->arg].safe_push (entry);
- }
- update_escape_summary (edge->callee, emap, ignore_stores);
- for (i = 0; (int)i < max_escape + 1; i++)
- emap[i].release ();
- if (sum)
- escape_summaries->remove (edge);
-
- if (summaries)
- {
- if (to_info && !to_info->useful_p (flags))
- {
- if (dump_file)
- fprintf (dump_file, "Removed mod-ref summary for %s\n",
- to->dump_name ());
- summaries->remove (to);
- to_info = NULL;
- }
- else if (to_info && dump_file)
- {
- if (dump_file)
- fprintf (dump_file, "Updated mod-ref summary for %s\n",
- to->dump_name ());
- to_info->dump (dump_file);
- }
- if (callee_info)
- summaries->remove (edge->callee);
- }
- if (summaries_lto)
- {
- if (to_info_lto && !to_info_lto->useful_p (flags))
- {
- if (dump_file)
- fprintf (dump_file, "Removed mod-ref summary for %s\n",
- to->dump_name ());
- summaries_lto->remove (to);
- to_info_lto = NULL;
- }
- else if (to_info_lto && dump_file)
- {
- if (dump_file)
- fprintf (dump_file, "Updated mod-ref summary for %s\n",
- to->dump_name ());
- to_info_lto->dump (dump_file);
- }
- if (callee_info_lto)
- summaries_lto->remove (edge->callee);
- }
- if (!to_info && !to_info_lto)
- remove_modref_edge_summaries (to);
- return;
-}
-
-/* Run the IPA pass. This will take a function's summaries and calls and
- construct new summaries which represent a transitive closure. So that
- summary of an analyzed function contains information about the loads and
- stores that the function or any function that it calls does. */
-
-unsigned int
-pass_ipa_modref::execute (function *)
-{
- if (!summaries && !summaries_lto)
- return 0;
- bool pureconst = false;
-
- if (optimization_summaries)
- ggc_delete (optimization_summaries);
- optimization_summaries = summaries;
- summaries = NULL;
-
- struct cgraph_node **order = XCNEWVEC (struct cgraph_node *,
- symtab->cgraph_count);
- int order_pos;
- order_pos = ipa_reduced_postorder (order, true, ignore_edge);
- int i;
-
- /* Iterate over all strongly connected components in post-order. */
- for (i = 0; i < order_pos; i++)
- {
- /* Get the component's representative. That's just any node in the
- component from which we can traverse the entire component. */
- struct cgraph_node *component_node = order[i];
-
- if (dump_file)
- fprintf (dump_file, "\n\nStart of SCC component\n");
-
- pureconst |= modref_propagate_in_scc (component_node);
- modref_propagate_flags_in_scc (component_node);
- if (optimization_summaries)
- for (struct cgraph_node *cur = component_node; cur;
- cur = ((struct ipa_dfs_info *) cur->aux)->next_cycle)
- if (modref_summary *sum = optimization_summaries->get (cur))
- sum->finalize (cur->decl);
- if (dump_file)
- modref_propagate_dump_scc (component_node);
- }
- cgraph_node *node;
- FOR_EACH_FUNCTION (node)
- update_signature (node);
- if (summaries_lto)
- ((modref_summaries_lto *)summaries_lto)->propagated = true;
- ipa_free_postorder_info ();
- free (order);
- delete fnspec_summaries;
- fnspec_summaries = NULL;
- delete escape_summaries;
- escape_summaries = NULL;
-
- /* If we posibly made constructors const/pure we may need to remove
- them. */
- return pureconst ? TODO_remove_functions : 0;
-}
-
-/* Summaries must stay alive until end of compilation. */
-
-void
-ipa_modref_c_finalize ()
-{
- if (optimization_summaries)
- ggc_delete (optimization_summaries);
- optimization_summaries = NULL;
- if (summaries_lto)
- ggc_delete (summaries_lto);
- summaries_lto = NULL;
- if (fnspec_summaries)
- delete fnspec_summaries;
- fnspec_summaries = NULL;
- if (escape_summaries)
- delete escape_summaries;
- escape_summaries = NULL;
-}
-
-#include "gt-ipa-modref.h"