diff options
author | Martin Liska <mliska@suse.cz> | 2022-01-14 16:56:44 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-01-17 22:12:04 +0100 |
commit | 5c69acb32329d49e58c26fa41ae74229a52b9106 (patch) | |
tree | ddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/tree-inline.c | |
parent | 490e23032baaece71f2ec09fa1805064b150fbc2 (diff) | |
download | gcc-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/tree-inline.c')
-rw-r--r-- | gcc/tree-inline.c | 6634 |
1 files changed, 0 insertions, 6634 deletions
diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c deleted file mode 100644 index 8ea8de7..0000000 --- a/gcc/tree-inline.c +++ /dev/null @@ -1,6634 +0,0 @@ -/* Tree inlining. - Copyright (C) 2001-2022 Free Software Foundation, Inc. - Contributed by Alexandre Oliva <aoliva@redhat.com> - -This file is part of GCC. - -GCC is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 3, or (at your option) -any later version. - -GCC is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with GCC; see the file COPYING3. If not see -<http://www.gnu.org/licenses/>. */ - -#include "config.h" -#include "system.h" -#include "coretypes.h" -#include "backend.h" -#include "target.h" -#include "rtl.h" -#include "tree.h" -#include "gimple.h" -#include "cfghooks.h" -#include "tree-pass.h" -#include "ssa.h" -#include "cgraph.h" -#include "tree-pretty-print.h" -#include "diagnostic-core.h" -#include "gimple-predict.h" -#include "fold-const.h" -#include "stor-layout.h" -#include "calls.h" -#include "tree-inline.h" -#include "langhooks.h" -#include "cfganal.h" -#include "tree-iterator.h" -#include "intl.h" -#include "gimple-fold.h" -#include "tree-eh.h" -#include "gimplify.h" -#include "gimple-iterator.h" -#include "gimplify-me.h" -#include "gimple-walk.h" -#include "tree-cfg.h" -#include "tree-into-ssa.h" -#include "tree-dfa.h" -#include "tree-ssa.h" -#include "except.h" -#include "debug.h" -#include "value-prof.h" -#include "cfgloop.h" -#include "builtins.h" -#include "stringpool.h" -#include "attribs.h" -#include "sreal.h" -#include "tree-cfgcleanup.h" -#include "tree-ssa-live.h" -#include "alloc-pool.h" -#include "symbol-summary.h" -#include "symtab-thunks.h" -#include "symtab-clones.h" - -/* I'm not real happy about this, but we need to handle gimple and - non-gimple trees. */ - -/* Inlining, Cloning, Versioning, Parallelization - - Inlining: a function body is duplicated, but the PARM_DECLs are - remapped into VAR_DECLs, and non-void RETURN_EXPRs become - MODIFY_EXPRs that store to a dedicated returned-value variable. - The duplicated eh_region info of the copy will later be appended - to the info for the caller; the eh_region info in copied throwing - statements and RESX statements are adjusted accordingly. - - Cloning: (only in C++) We have one body for a con/de/structor, and - multiple function decls, each with a unique parameter list. - Duplicate the body, using the given splay tree; some parameters - will become constants (like 0 or 1). - - Versioning: a function body is duplicated and the result is a new - function rather than into blocks of an existing function as with - inlining. Some parameters will become constants. - - Parallelization: a region of a function is duplicated resulting in - a new function. Variables may be replaced with complex expressions - to enable shared variable semantics. - - All of these will simultaneously lookup any callgraph edges. If - we're going to inline the duplicated function body, and the given - function has some cloned callgraph nodes (one for each place this - function will be inlined) those callgraph edges will be duplicated. - If we're cloning the body, those callgraph edges will be - updated to point into the new body. (Note that the original - callgraph node and edge list will not be altered.) - - See the CALL_EXPR handling case in copy_tree_body_r (). */ - -/* To Do: - - o In order to make inlining-on-trees work, we pessimized - function-local static constants. In particular, they are now - always output, even when not addressed. Fix this by treating - function-local static constants just like global static - constants; the back-end already knows not to output them if they - are not needed. - - o Provide heuristics to clamp inlining of recursive template - calls? */ - - -/* Weights that estimate_num_insns uses to estimate the size of the - produced code. */ - -eni_weights eni_size_weights; - -/* Weights that estimate_num_insns uses to estimate the time necessary - to execute the produced code. */ - -eni_weights eni_time_weights; - -/* Prototypes. */ - -static tree declare_return_variable (copy_body_data *, tree, tree, - basic_block); -static void remap_block (tree *, copy_body_data *); -static void copy_bind_expr (tree *, int *, copy_body_data *); -static void declare_inline_vars (tree, tree); -static void remap_save_expr (tree *, hash_map<tree, tree> *, int *); -static void prepend_lexical_block (tree current_block, tree new_block); -static tree copy_result_decl_to_var (tree, copy_body_data *); -static tree copy_decl_maybe_to_var (tree, copy_body_data *); -static gimple_seq remap_gimple_stmt (gimple *, copy_body_data *); -static void insert_init_stmt (copy_body_data *, basic_block, gimple *); - -/* Insert a tree->tree mapping for ID. Despite the name suggests - that the trees should be variables, it is used for more than that. */ - -void -insert_decl_map (copy_body_data *id, tree key, tree value) -{ - id->decl_map->put (key, value); - - /* Always insert an identity map as well. If we see this same new - node again, we won't want to duplicate it a second time. */ - if (key != value) - id->decl_map->put (value, value); -} - -/* If nonzero, we're remapping the contents of inlined debug - statements. If negative, an error has occurred, such as a - reference to a variable that isn't available in the inlined - context. */ -static int processing_debug_stmt = 0; - -/* Construct new SSA name for old NAME. ID is the inline context. */ - -static tree -remap_ssa_name (tree name, copy_body_data *id) -{ - tree new_tree, var; - tree *n; - - gcc_assert (TREE_CODE (name) == SSA_NAME); - - n = id->decl_map->get (name); - if (n) - { - /* WHen we perform edge redirection as part of CFG copy, IPA-SRA can - remove an unused LHS from a call statement. Such LHS can however - still appear in debug statements, but their value is lost in this - function and we do not want to map them. */ - if (id->killed_new_ssa_names - && id->killed_new_ssa_names->contains (*n)) - { - gcc_assert (processing_debug_stmt); - processing_debug_stmt = -1; - return name; - } - - return unshare_expr (*n); - } - - if (processing_debug_stmt) - { - if (SSA_NAME_IS_DEFAULT_DEF (name) - && TREE_CODE (SSA_NAME_VAR (name)) == PARM_DECL - && id->entry_bb == NULL - && single_succ_p (ENTRY_BLOCK_PTR_FOR_FN (cfun))) - { - gimple *def_temp; - gimple_stmt_iterator gsi; - tree val = SSA_NAME_VAR (name); - - n = id->decl_map->get (val); - if (n != NULL) - val = *n; - if (TREE_CODE (val) != PARM_DECL - && !(VAR_P (val) && DECL_ABSTRACT_ORIGIN (val))) - { - processing_debug_stmt = -1; - return name; - } - n = id->decl_map->get (val); - if (n && TREE_CODE (*n) == DEBUG_EXPR_DECL) - return *n; - tree vexpr = build_debug_expr_decl (TREE_TYPE (name)); - /* FIXME: Is setting the mode really necessary? */ - SET_DECL_MODE (vexpr, DECL_MODE (SSA_NAME_VAR (name))); - def_temp = gimple_build_debug_source_bind (vexpr, val, NULL); - gsi = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); - gsi_insert_before (&gsi, def_temp, GSI_SAME_STMT); - insert_decl_map (id, val, vexpr); - return vexpr; - } - - processing_debug_stmt = -1; - return name; - } - - /* Remap anonymous SSA names or SSA names of anonymous decls. */ - var = SSA_NAME_VAR (name); - if (!var - || (!SSA_NAME_IS_DEFAULT_DEF (name) - && VAR_P (var) - && !VAR_DECL_IS_VIRTUAL_OPERAND (var) - && DECL_ARTIFICIAL (var) - && DECL_IGNORED_P (var) - && !DECL_NAME (var))) - { - struct ptr_info_def *pi; - new_tree = make_ssa_name (remap_type (TREE_TYPE (name), id)); - if (!var && SSA_NAME_IDENTIFIER (name)) - SET_SSA_NAME_VAR_OR_IDENTIFIER (new_tree, SSA_NAME_IDENTIFIER (name)); - insert_decl_map (id, name, new_tree); - SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_tree) - = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name); - /* At least IPA points-to info can be directly transferred. */ - if (id->src_cfun->gimple_df - && id->src_cfun->gimple_df->ipa_pta - && POINTER_TYPE_P (TREE_TYPE (name)) - && (pi = SSA_NAME_PTR_INFO (name)) - && !pi->pt.anything) - { - struct ptr_info_def *new_pi = get_ptr_info (new_tree); - new_pi->pt = pi->pt; - } - /* So can range-info. */ - if (!POINTER_TYPE_P (TREE_TYPE (name)) - && SSA_NAME_RANGE_INFO (name)) - duplicate_ssa_name_range_info (new_tree, SSA_NAME_RANGE_TYPE (name), - SSA_NAME_RANGE_INFO (name)); - return new_tree; - } - - /* Do not set DEF_STMT yet as statement is not copied yet. We do that - in copy_bb. */ - new_tree = remap_decl (var, id); - - /* We might've substituted constant or another SSA_NAME for - the variable. - - Replace the SSA name representing RESULT_DECL by variable during - inlining: this saves us from need to introduce PHI node in a case - return value is just partly initialized. */ - if ((VAR_P (new_tree) || TREE_CODE (new_tree) == PARM_DECL) - && (!SSA_NAME_VAR (name) - || TREE_CODE (SSA_NAME_VAR (name)) != RESULT_DECL - || !id->transform_return_to_modify)) - { - struct ptr_info_def *pi; - new_tree = make_ssa_name (new_tree); - insert_decl_map (id, name, new_tree); - SSA_NAME_OCCURS_IN_ABNORMAL_PHI (new_tree) - = SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name); - /* At least IPA points-to info can be directly transferred. */ - if (id->src_cfun->gimple_df - && id->src_cfun->gimple_df->ipa_pta - && POINTER_TYPE_P (TREE_TYPE (name)) - && (pi = SSA_NAME_PTR_INFO (name)) - && !pi->pt.anything) - { - struct ptr_info_def *new_pi = get_ptr_info (new_tree); - new_pi->pt = pi->pt; - } - /* So can range-info. */ - if (!POINTER_TYPE_P (TREE_TYPE (name)) - && SSA_NAME_RANGE_INFO (name)) - duplicate_ssa_name_range_info (new_tree, SSA_NAME_RANGE_TYPE (name), - SSA_NAME_RANGE_INFO (name)); - if (SSA_NAME_IS_DEFAULT_DEF (name)) - { - /* By inlining function having uninitialized variable, we might - extend the lifetime (variable might get reused). This cause - ICE in the case we end up extending lifetime of SSA name across - abnormal edge, but also increase register pressure. - - We simply initialize all uninitialized vars by 0 except - for case we are inlining to very first BB. We can avoid - this for all BBs that are not inside strongly connected - regions of the CFG, but this is expensive to test. */ - if (id->entry_bb - && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (name) - && (!SSA_NAME_VAR (name) - || TREE_CODE (SSA_NAME_VAR (name)) != PARM_DECL) - && (id->entry_bb != EDGE_SUCC (ENTRY_BLOCK_PTR_FOR_FN (cfun), - 0)->dest - || EDGE_COUNT (id->entry_bb->preds) != 1)) - { - gimple_stmt_iterator gsi = gsi_last_bb (id->entry_bb); - gimple *init_stmt; - tree zero = build_zero_cst (TREE_TYPE (new_tree)); - - init_stmt = gimple_build_assign (new_tree, zero); - gsi_insert_after (&gsi, init_stmt, GSI_NEW_STMT); - SSA_NAME_IS_DEFAULT_DEF (new_tree) = 0; - } - else - { - SSA_NAME_DEF_STMT (new_tree) = gimple_build_nop (); - set_ssa_default_def (cfun, SSA_NAME_VAR (new_tree), new_tree); - } - } - } - else - insert_decl_map (id, name, new_tree); - return new_tree; -} - -/* Remap DECL during the copying of the BLOCK tree for the function. */ - -tree -remap_decl (tree decl, copy_body_data *id) -{ - tree *n; - - /* We only remap local variables in the current function. */ - - /* See if we have remapped this declaration. */ - - n = id->decl_map->get (decl); - - if (!n && processing_debug_stmt) - { - processing_debug_stmt = -1; - return decl; - } - - /* When remapping a type within copy_gimple_seq_and_replace_locals, all - necessary DECLs have already been remapped and we do not want to duplicate - a decl coming from outside of the sequence we are copying. */ - if (!n - && id->prevent_decl_creation_for_types - && id->remapping_type_depth > 0 - && (VAR_P (decl) || TREE_CODE (decl) == PARM_DECL)) - return decl; - - /* If we didn't already have an equivalent for this declaration, create one - now. */ - if (!n) - { - /* Make a copy of the variable or label. */ - tree t = id->copy_decl (decl, id); - - /* Remember it, so that if we encounter this local entity again - we can reuse this copy. Do this early because remap_type may - need this decl for TYPE_STUB_DECL. */ - insert_decl_map (id, decl, t); - - if (!DECL_P (t)) - return t; - - /* Remap types, if necessary. */ - TREE_TYPE (t) = remap_type (TREE_TYPE (t), id); - if (TREE_CODE (t) == TYPE_DECL) - { - DECL_ORIGINAL_TYPE (t) = remap_type (DECL_ORIGINAL_TYPE (t), id); - - /* Preserve the invariant that DECL_ORIGINAL_TYPE != TREE_TYPE, - which is enforced in gen_typedef_die when DECL_ABSTRACT_ORIGIN - is not set on the TYPE_DECL, for example in LTO mode. */ - if (DECL_ORIGINAL_TYPE (t) == TREE_TYPE (t)) - { - tree x = build_variant_type_copy (TREE_TYPE (t)); - TYPE_STUB_DECL (x) = TYPE_STUB_DECL (TREE_TYPE (t)); - TYPE_NAME (x) = TYPE_NAME (TREE_TYPE (t)); - DECL_ORIGINAL_TYPE (t) = x; - } - } - - /* Remap sizes as necessary. */ - walk_tree (&DECL_SIZE (t), copy_tree_body_r, id, NULL); - walk_tree (&DECL_SIZE_UNIT (t), copy_tree_body_r, id, NULL); - - /* If fields, do likewise for offset and qualifier. */ - if (TREE_CODE (t) == FIELD_DECL) - { - walk_tree (&DECL_FIELD_OFFSET (t), copy_tree_body_r, id, NULL); - if (TREE_CODE (DECL_CONTEXT (t)) == QUAL_UNION_TYPE) - walk_tree (&DECL_QUALIFIER (t), copy_tree_body_r, id, NULL); - } - - return t; - } - - if (id->do_not_unshare) - return *n; - else - return unshare_expr (*n); -} - -static tree -remap_type_1 (tree type, copy_body_data *id) -{ - tree new_tree, t; - - /* We do need a copy. build and register it now. If this is a pointer or - reference type, remap the designated type and make a new pointer or - reference type. */ - if (TREE_CODE (type) == POINTER_TYPE) - { - new_tree = build_pointer_type_for_mode (remap_type (TREE_TYPE (type), id), - TYPE_MODE (type), - TYPE_REF_CAN_ALIAS_ALL (type)); - if (TYPE_ATTRIBUTES (type) || TYPE_QUALS (type)) - new_tree = build_type_attribute_qual_variant (new_tree, - TYPE_ATTRIBUTES (type), - TYPE_QUALS (type)); - insert_decl_map (id, type, new_tree); - return new_tree; - } - else if (TREE_CODE (type) == REFERENCE_TYPE) - { - new_tree = build_reference_type_for_mode (remap_type (TREE_TYPE (type), id), - TYPE_MODE (type), - TYPE_REF_CAN_ALIAS_ALL (type)); - if (TYPE_ATTRIBUTES (type) || TYPE_QUALS (type)) - new_tree = build_type_attribute_qual_variant (new_tree, - TYPE_ATTRIBUTES (type), - TYPE_QUALS (type)); - insert_decl_map (id, type, new_tree); - return new_tree; - } - else - new_tree = copy_node (type); - - insert_decl_map (id, type, new_tree); - - /* This is a new type, not a copy of an old type. Need to reassociate - variants. We can handle everything except the main variant lazily. */ - t = TYPE_MAIN_VARIANT (type); - if (type != t) - { - t = remap_type (t, id); - TYPE_MAIN_VARIANT (new_tree) = t; - TYPE_NEXT_VARIANT (new_tree) = TYPE_NEXT_VARIANT (t); - TYPE_NEXT_VARIANT (t) = new_tree; - } - else - { - TYPE_MAIN_VARIANT (new_tree) = new_tree; - TYPE_NEXT_VARIANT (new_tree) = NULL; - } - - if (TYPE_STUB_DECL (type)) - TYPE_STUB_DECL (new_tree) = remap_decl (TYPE_STUB_DECL (type), id); - - /* Lazily create pointer and reference types. */ - TYPE_POINTER_TO (new_tree) = NULL; - TYPE_REFERENCE_TO (new_tree) = NULL; - - /* Copy all types that may contain references to local variables; be sure to - preserve sharing in between type and its main variant when possible. */ - switch (TREE_CODE (new_tree)) - { - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case ENUMERAL_TYPE: - case BOOLEAN_TYPE: - if (TYPE_MAIN_VARIANT (new_tree) != new_tree) - { - gcc_checking_assert (TYPE_MIN_VALUE (type) == TYPE_MIN_VALUE (TYPE_MAIN_VARIANT (type))); - gcc_checking_assert (TYPE_MAX_VALUE (type) == TYPE_MAX_VALUE (TYPE_MAIN_VARIANT (type))); - - TYPE_MIN_VALUE (new_tree) = TYPE_MIN_VALUE (TYPE_MAIN_VARIANT (new_tree)); - TYPE_MAX_VALUE (new_tree) = TYPE_MAX_VALUE (TYPE_MAIN_VARIANT (new_tree)); - } - else - { - t = TYPE_MIN_VALUE (new_tree); - if (t && TREE_CODE (t) != INTEGER_CST) - walk_tree (&TYPE_MIN_VALUE (new_tree), copy_tree_body_r, id, NULL); - - t = TYPE_MAX_VALUE (new_tree); - if (t && TREE_CODE (t) != INTEGER_CST) - walk_tree (&TYPE_MAX_VALUE (new_tree), copy_tree_body_r, id, NULL); - } - return new_tree; - - case FUNCTION_TYPE: - if (TYPE_MAIN_VARIANT (new_tree) != new_tree - && TREE_TYPE (type) == TREE_TYPE (TYPE_MAIN_VARIANT (type))) - TREE_TYPE (new_tree) = TREE_TYPE (TYPE_MAIN_VARIANT (new_tree)); - else - TREE_TYPE (new_tree) = remap_type (TREE_TYPE (new_tree), id); - if (TYPE_MAIN_VARIANT (new_tree) != new_tree - && TYPE_ARG_TYPES (type) == TYPE_ARG_TYPES (TYPE_MAIN_VARIANT (type))) - TYPE_ARG_TYPES (new_tree) = TYPE_ARG_TYPES (TYPE_MAIN_VARIANT (new_tree)); - else - walk_tree (&TYPE_ARG_TYPES (new_tree), copy_tree_body_r, id, NULL); - return new_tree; - - case ARRAY_TYPE: - if (TYPE_MAIN_VARIANT (new_tree) != new_tree - && TREE_TYPE (type) == TREE_TYPE (TYPE_MAIN_VARIANT (type))) - TREE_TYPE (new_tree) = TREE_TYPE (TYPE_MAIN_VARIANT (new_tree)); - else - TREE_TYPE (new_tree) = remap_type (TREE_TYPE (new_tree), id); - - if (TYPE_MAIN_VARIANT (new_tree) != new_tree) - { - gcc_checking_assert (TYPE_DOMAIN (type) - == TYPE_DOMAIN (TYPE_MAIN_VARIANT (type))); - TYPE_DOMAIN (new_tree) = TYPE_DOMAIN (TYPE_MAIN_VARIANT (new_tree)); - } - else - { - TYPE_DOMAIN (new_tree) = remap_type (TYPE_DOMAIN (new_tree), id); - /* For array bounds where we have decided not to copy over the bounds - variable which isn't used in OpenMP/OpenACC region, change them to - an uninitialized VAR_DECL temporary. */ - if (id->adjust_array_error_bounds - && TYPE_DOMAIN (new_tree) - && TYPE_MAX_VALUE (TYPE_DOMAIN (new_tree)) == error_mark_node - && TYPE_MAX_VALUE (TYPE_DOMAIN (type)) != error_mark_node) - { - tree v = create_tmp_var (TREE_TYPE (TYPE_DOMAIN (new_tree))); - DECL_ATTRIBUTES (v) - = tree_cons (get_identifier ("omp dummy var"), NULL_TREE, - DECL_ATTRIBUTES (v)); - TYPE_MAX_VALUE (TYPE_DOMAIN (new_tree)) = v; - } - } - break; - - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - if (TYPE_MAIN_VARIANT (type) != type - && TYPE_FIELDS (type) == TYPE_FIELDS (TYPE_MAIN_VARIANT (type))) - TYPE_FIELDS (new_tree) = TYPE_FIELDS (TYPE_MAIN_VARIANT (new_tree)); - else - { - tree f, nf = NULL; - - for (f = TYPE_FIELDS (new_tree); f ; f = DECL_CHAIN (f)) - { - t = remap_decl (f, id); - DECL_CONTEXT (t) = new_tree; - DECL_CHAIN (t) = nf; - nf = t; - } - TYPE_FIELDS (new_tree) = nreverse (nf); - } - break; - - case OFFSET_TYPE: - default: - /* Shouldn't have been thought variable sized. */ - gcc_unreachable (); - } - - /* All variants of type share the same size, so use the already remaped data. */ - if (TYPE_MAIN_VARIANT (new_tree) != new_tree) - { - tree s = TYPE_SIZE (type); - tree mvs = TYPE_SIZE (TYPE_MAIN_VARIANT (type)); - tree su = TYPE_SIZE_UNIT (type); - tree mvsu = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (type)); - gcc_checking_assert ((TREE_CODE (s) == PLACEHOLDER_EXPR - && (TREE_CODE (mvs) == PLACEHOLDER_EXPR)) - || s == mvs); - gcc_checking_assert ((TREE_CODE (su) == PLACEHOLDER_EXPR - && (TREE_CODE (mvsu) == PLACEHOLDER_EXPR)) - || su == mvsu); - TYPE_SIZE (new_tree) = TYPE_SIZE (TYPE_MAIN_VARIANT (new_tree)); - TYPE_SIZE_UNIT (new_tree) = TYPE_SIZE_UNIT (TYPE_MAIN_VARIANT (new_tree)); - } - else - { - walk_tree (&TYPE_SIZE (new_tree), copy_tree_body_r, id, NULL); - walk_tree (&TYPE_SIZE_UNIT (new_tree), copy_tree_body_r, id, NULL); - } - - return new_tree; -} - -/* Helper function for remap_type_2, called through walk_tree. */ - -static tree -remap_type_3 (tree *tp, int *walk_subtrees, void *data) -{ - copy_body_data *id = (copy_body_data *) data; - - if (TYPE_P (*tp)) - *walk_subtrees = 0; - - else if (DECL_P (*tp) && remap_decl (*tp, id) != *tp) - return *tp; - - return NULL_TREE; -} - -/* Return true if TYPE needs to be remapped because remap_decl on any - needed embedded decl returns something other than that decl. */ - -static bool -remap_type_2 (tree type, copy_body_data *id) -{ - tree t; - -#define RETURN_TRUE_IF_VAR(T) \ - do \ - { \ - tree _t = (T); \ - if (_t) \ - { \ - if (DECL_P (_t) && remap_decl (_t, id) != _t) \ - return true; \ - if (!TYPE_SIZES_GIMPLIFIED (type) \ - && walk_tree (&_t, remap_type_3, id, NULL)) \ - return true; \ - } \ - } \ - while (0) - - switch (TREE_CODE (type)) - { - case POINTER_TYPE: - case REFERENCE_TYPE: - case FUNCTION_TYPE: - case METHOD_TYPE: - return remap_type_2 (TREE_TYPE (type), id); - - case INTEGER_TYPE: - case REAL_TYPE: - case FIXED_POINT_TYPE: - case ENUMERAL_TYPE: - case BOOLEAN_TYPE: - RETURN_TRUE_IF_VAR (TYPE_MIN_VALUE (type)); - RETURN_TRUE_IF_VAR (TYPE_MAX_VALUE (type)); - return false; - - case ARRAY_TYPE: - if (remap_type_2 (TREE_TYPE (type), id) - || (TYPE_DOMAIN (type) && remap_type_2 (TYPE_DOMAIN (type), id))) - return true; - break; - - case RECORD_TYPE: - case UNION_TYPE: - case QUAL_UNION_TYPE: - for (t = TYPE_FIELDS (type); t; t = DECL_CHAIN (t)) - if (TREE_CODE (t) == FIELD_DECL) - { - RETURN_TRUE_IF_VAR (DECL_FIELD_OFFSET (t)); - RETURN_TRUE_IF_VAR (DECL_SIZE (t)); - RETURN_TRUE_IF_VAR (DECL_SIZE_UNIT (t)); - if (TREE_CODE (type) == QUAL_UNION_TYPE) - RETURN_TRUE_IF_VAR (DECL_QUALIFIER (t)); - } - break; - - default: - return false; - } - - RETURN_TRUE_IF_VAR (TYPE_SIZE (type)); - RETURN_TRUE_IF_VAR (TYPE_SIZE_UNIT (type)); - return false; -#undef RETURN_TRUE_IF_VAR -} - -tree -remap_type (tree type, copy_body_data *id) -{ - tree *node; - tree tmp; - - if (type == NULL) - return type; - - /* See if we have remapped this type. */ - node = id->decl_map->get (type); - if (node) - return *node; - - /* The type only needs remapping if it's variably modified. */ - if (! variably_modified_type_p (type, id->src_fn) - /* Don't remap if copy_decl method doesn't always return a new - decl and for all embedded decls returns the passed in decl. */ - || (id->dont_remap_vla_if_no_change && !remap_type_2 (type, id))) - { - insert_decl_map (id, type, type); - return type; - } - - id->remapping_type_depth++; - tmp = remap_type_1 (type, id); - id->remapping_type_depth--; - - return tmp; -} - -/* Decide if DECL can be put into BLOCK_NONLOCAL_VARs. */ - -static bool -can_be_nonlocal (tree decl, copy_body_data *id) -{ - /* We cannot duplicate function decls. */ - if (TREE_CODE (decl) == FUNCTION_DECL) - return true; - - /* Local static vars must be non-local or we get multiple declaration - problems. */ - if (VAR_P (decl) && !auto_var_in_fn_p (decl, id->src_fn)) - return true; - - return false; -} - -static tree -remap_decls (tree decls, vec<tree, va_gc> **nonlocalized_list, - copy_body_data *id) -{ - tree old_var; - tree new_decls = NULL_TREE; - - /* Remap its variables. */ - for (old_var = decls; old_var; old_var = DECL_CHAIN (old_var)) - { - tree new_var; - - if (can_be_nonlocal (old_var, id)) - { - /* We need to add this variable to the local decls as otherwise - nothing else will do so. */ - if (VAR_P (old_var) && ! DECL_EXTERNAL (old_var) && cfun) - add_local_decl (cfun, old_var); - if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE) - && !DECL_IGNORED_P (old_var) - && nonlocalized_list) - vec_safe_push (*nonlocalized_list, old_var); - continue; - } - - /* Remap the variable. */ - new_var = remap_decl (old_var, id); - - /* If we didn't remap this variable, we can't mess with its - TREE_CHAIN. If we remapped this variable to the return slot, it's - already declared somewhere else, so don't declare it here. */ - - if (new_var == id->retvar) - ; - else if (!new_var) - { - if ((!optimize || debug_info_level > DINFO_LEVEL_TERSE) - && !DECL_IGNORED_P (old_var) - && nonlocalized_list) - vec_safe_push (*nonlocalized_list, old_var); - } - else - { - gcc_assert (DECL_P (new_var)); - DECL_CHAIN (new_var) = new_decls; - new_decls = new_var; - - /* Also copy value-expressions. */ - if (VAR_P (new_var) && DECL_HAS_VALUE_EXPR_P (new_var)) - { - tree tem = DECL_VALUE_EXPR (new_var); - bool old_regimplify = id->regimplify; - id->remapping_type_depth++; - walk_tree (&tem, copy_tree_body_r, id, NULL); - id->remapping_type_depth--; - id->regimplify = old_regimplify; - SET_DECL_VALUE_EXPR (new_var, tem); - } - } - } - - return nreverse (new_decls); -} - -/* Copy the BLOCK to contain remapped versions of the variables - therein. And hook the new block into the block-tree. */ - -static void -remap_block (tree *block, copy_body_data *id) -{ - tree old_block; - tree new_block; - - /* Make the new block. */ - old_block = *block; - new_block = make_node (BLOCK); - TREE_USED (new_block) = TREE_USED (old_block); - BLOCK_ABSTRACT_ORIGIN (new_block) = BLOCK_ORIGIN (old_block); - BLOCK_SOURCE_LOCATION (new_block) = BLOCK_SOURCE_LOCATION (old_block); - BLOCK_NONLOCALIZED_VARS (new_block) - = vec_safe_copy (BLOCK_NONLOCALIZED_VARS (old_block)); - *block = new_block; - - /* Remap its variables. */ - BLOCK_VARS (new_block) = remap_decls (BLOCK_VARS (old_block), - &BLOCK_NONLOCALIZED_VARS (new_block), - id); - - /* Remember the remapped block. */ - insert_decl_map (id, old_block, new_block); -} - -/* Copy the whole block tree and root it in id->block. */ - -static tree -remap_blocks (tree block, copy_body_data *id) -{ - tree t; - tree new_tree = block; - - if (!block) - return NULL; - - remap_block (&new_tree, id); - gcc_assert (new_tree != block); - for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t)) - prepend_lexical_block (new_tree, remap_blocks (t, id)); - /* Blocks are in arbitrary order, but make things slightly prettier and do - not swap order when producing a copy. */ - BLOCK_SUBBLOCKS (new_tree) = blocks_nreverse (BLOCK_SUBBLOCKS (new_tree)); - return new_tree; -} - -/* Remap the block tree rooted at BLOCK to nothing. */ - -static void -remap_blocks_to_null (tree block, copy_body_data *id) -{ - tree t; - insert_decl_map (id, block, NULL_TREE); - for (t = BLOCK_SUBBLOCKS (block); t ; t = BLOCK_CHAIN (t)) - remap_blocks_to_null (t, id); -} - -/* Remap the location info pointed to by LOCUS. */ - -static location_t -remap_location (location_t locus, copy_body_data *id) -{ - if (LOCATION_BLOCK (locus)) - { - tree *n = id->decl_map->get (LOCATION_BLOCK (locus)); - gcc_assert (n); - if (*n) - return set_block (locus, *n); - } - - locus = LOCATION_LOCUS (locus); - - if (locus != UNKNOWN_LOCATION && id->block) - return set_block (locus, id->block); - - return locus; -} - -static void -copy_statement_list (tree *tp) -{ - tree_stmt_iterator oi, ni; - tree new_tree; - - new_tree = alloc_stmt_list (); - ni = tsi_start (new_tree); - oi = tsi_start (*tp); - TREE_TYPE (new_tree) = TREE_TYPE (*tp); - *tp = new_tree; - - for (; !tsi_end_p (oi); tsi_next (&oi)) - { - tree stmt = tsi_stmt (oi); - if (TREE_CODE (stmt) == STATEMENT_LIST) - /* This copy is not redundant; tsi_link_after will smash this - STATEMENT_LIST into the end of the one we're building, and we - don't want to do that with the original. */ - copy_statement_list (&stmt); - tsi_link_after (&ni, stmt, TSI_CONTINUE_LINKING); - } -} - -static void -copy_bind_expr (tree *tp, int *walk_subtrees, copy_body_data *id) -{ - tree block = BIND_EXPR_BLOCK (*tp); - /* Copy (and replace) the statement. */ - copy_tree_r (tp, walk_subtrees, NULL); - if (block) - { - remap_block (&block, id); - BIND_EXPR_BLOCK (*tp) = block; - } - - if (BIND_EXPR_VARS (*tp)) - /* This will remap a lot of the same decls again, but this should be - harmless. */ - BIND_EXPR_VARS (*tp) = remap_decls (BIND_EXPR_VARS (*tp), NULL, id); -} - - -/* Create a new gimple_seq by remapping all the statements in BODY - using the inlining information in ID. */ - -static gimple_seq -remap_gimple_seq (gimple_seq body, copy_body_data *id) -{ - gimple_stmt_iterator si; - gimple_seq new_body = NULL; - - for (si = gsi_start (body); !gsi_end_p (si); gsi_next (&si)) - { - gimple_seq new_stmts = remap_gimple_stmt (gsi_stmt (si), id); - gimple_seq_add_seq (&new_body, new_stmts); - } - - return new_body; -} - - -/* Copy a GIMPLE_BIND statement STMT, remapping all the symbols in its - block using the mapping information in ID. */ - -static gimple * -copy_gimple_bind (gbind *stmt, copy_body_data *id) -{ - gimple *new_bind; - tree new_block, new_vars; - gimple_seq body, new_body; - - /* Copy the statement. Note that we purposely don't use copy_stmt - here because we need to remap statements as we copy. */ - body = gimple_bind_body (stmt); - new_body = remap_gimple_seq (body, id); - - new_block = gimple_bind_block (stmt); - if (new_block) - remap_block (&new_block, id); - - /* This will remap a lot of the same decls again, but this should be - harmless. */ - new_vars = gimple_bind_vars (stmt); - if (new_vars) - new_vars = remap_decls (new_vars, NULL, id); - - new_bind = gimple_build_bind (new_vars, new_body, new_block); - - return new_bind; -} - -/* Return true if DECL is a parameter or a SSA_NAME for a parameter. */ - -static bool -is_parm (tree decl) -{ - if (TREE_CODE (decl) == SSA_NAME) - { - decl = SSA_NAME_VAR (decl); - if (!decl) - return false; - } - - return (TREE_CODE (decl) == PARM_DECL); -} - -/* Remap the dependence CLIQUE from the source to the destination function - as specified in ID. */ - -static unsigned short -remap_dependence_clique (copy_body_data *id, unsigned short clique) -{ - if (clique == 0 || processing_debug_stmt) - return 0; - if (!id->dependence_map) - id->dependence_map = new hash_map<dependence_hash, unsigned short>; - bool existed; - unsigned short &newc = id->dependence_map->get_or_insert (clique, &existed); - if (!existed) - { - /* Clique 1 is reserved for local ones set by PTA. */ - if (cfun->last_clique == 0) - cfun->last_clique = 1; - newc = ++cfun->last_clique; - } - return newc; -} - -/* Remap the GIMPLE operand pointed to by *TP. DATA is really a - 'struct walk_stmt_info *'. DATA->INFO is a 'copy_body_data *'. - WALK_SUBTREES is used to indicate walk_gimple_op whether to keep - recursing into the children nodes of *TP. */ - -static tree -remap_gimple_op_r (tree *tp, int *walk_subtrees, void *data) -{ - struct walk_stmt_info *wi_p = (struct walk_stmt_info *) data; - copy_body_data *id = (copy_body_data *) wi_p->info; - tree fn = id->src_fn; - - /* For recursive invocations this is no longer the LHS itself. */ - bool is_lhs = wi_p->is_lhs; - wi_p->is_lhs = false; - - if (TREE_CODE (*tp) == SSA_NAME) - { - *tp = remap_ssa_name (*tp, id); - *walk_subtrees = 0; - if (is_lhs) - SSA_NAME_DEF_STMT (*tp) = wi_p->stmt; - return NULL; - } - else if (auto_var_in_fn_p (*tp, fn)) - { - /* Local variables and labels need to be replaced by equivalent - variables. We don't want to copy static variables; there's - only one of those, no matter how many times we inline the - containing function. Similarly for globals from an outer - function. */ - tree new_decl; - - /* Remap the declaration. */ - new_decl = remap_decl (*tp, id); - gcc_assert (new_decl); - /* Replace this variable with the copy. */ - STRIP_TYPE_NOPS (new_decl); - /* ??? The C++ frontend uses void * pointer zero to initialize - any other type. This confuses the middle-end type verification. - As cloned bodies do not go through gimplification again the fixup - there doesn't trigger. */ - if (TREE_CODE (new_decl) == INTEGER_CST - && !useless_type_conversion_p (TREE_TYPE (*tp), TREE_TYPE (new_decl))) - new_decl = fold_convert (TREE_TYPE (*tp), new_decl); - *tp = new_decl; - *walk_subtrees = 0; - } - else if (TREE_CODE (*tp) == STATEMENT_LIST) - gcc_unreachable (); - else if (TREE_CODE (*tp) == SAVE_EXPR) - gcc_unreachable (); - else if (TREE_CODE (*tp) == LABEL_DECL - && (!DECL_CONTEXT (*tp) - || decl_function_context (*tp) == id->src_fn)) - /* These may need to be remapped for EH handling. */ - *tp = remap_decl (*tp, id); - else if (TREE_CODE (*tp) == FIELD_DECL) - { - /* If the enclosing record type is variably_modified_type_p, the field - has already been remapped. Otherwise, it need not be. */ - tree *n = id->decl_map->get (*tp); - if (n) - *tp = *n; - *walk_subtrees = 0; - } - else if (TYPE_P (*tp)) - /* Types may need remapping as well. */ - *tp = remap_type (*tp, id); - else if (CONSTANT_CLASS_P (*tp)) - { - /* If this is a constant, we have to copy the node iff the type - will be remapped. copy_tree_r will not copy a constant. */ - tree new_type = remap_type (TREE_TYPE (*tp), id); - - if (new_type == TREE_TYPE (*tp)) - *walk_subtrees = 0; - - else if (TREE_CODE (*tp) == INTEGER_CST) - *tp = wide_int_to_tree (new_type, wi::to_wide (*tp)); - else - { - *tp = copy_node (*tp); - TREE_TYPE (*tp) = new_type; - } - } - else - { - /* Otherwise, just copy the node. Note that copy_tree_r already - knows not to copy VAR_DECLs, etc., so this is safe. */ - - if (TREE_CODE (*tp) == MEM_REF && !id->do_not_fold) - { - /* We need to re-canonicalize MEM_REFs from inline substitutions - that can happen when a pointer argument is an ADDR_EXPR. - Recurse here manually to allow that. */ - tree ptr = TREE_OPERAND (*tp, 0); - tree type = remap_type (TREE_TYPE (*tp), id); - tree old = *tp; - walk_tree (&ptr, remap_gimple_op_r, data, NULL); - *tp = fold_build2 (MEM_REF, type, ptr, TREE_OPERAND (*tp, 1)); - TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old); - TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old); - copy_warning (*tp, old); - if (MR_DEPENDENCE_CLIQUE (old) != 0) - { - MR_DEPENDENCE_CLIQUE (*tp) - = remap_dependence_clique (id, MR_DEPENDENCE_CLIQUE (old)); - MR_DEPENDENCE_BASE (*tp) = MR_DEPENDENCE_BASE (old); - } - /* We cannot propagate the TREE_THIS_NOTRAP flag if we have - remapped a parameter as the property might be valid only - for the parameter itself. */ - if (TREE_THIS_NOTRAP (old) - && (!is_parm (TREE_OPERAND (old, 0)) - || (!id->transform_parameter && is_parm (ptr)))) - TREE_THIS_NOTRAP (*tp) = 1; - REF_REVERSE_STORAGE_ORDER (*tp) = REF_REVERSE_STORAGE_ORDER (old); - *walk_subtrees = 0; - return NULL; - } - - /* Here is the "usual case". Copy this tree node, and then - tweak some special cases. */ - copy_tree_r (tp, walk_subtrees, NULL); - - if (TREE_CODE (*tp) != OMP_CLAUSE) - TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id); - - if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3)) - { - /* The copied TARGET_EXPR has never been expanded, even if the - original node was expanded already. */ - TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3); - TREE_OPERAND (*tp, 3) = NULL_TREE; - } - else if (TREE_CODE (*tp) == ADDR_EXPR) - { - /* Variable substitution need not be simple. In particular, - the MEM_REF substitution above. Make sure that - TREE_CONSTANT and friends are up-to-date. */ - int invariant = is_gimple_min_invariant (*tp); - walk_tree (&TREE_OPERAND (*tp, 0), remap_gimple_op_r, data, NULL); - recompute_tree_invariant_for_addr_expr (*tp); - - /* If this used to be invariant, but is not any longer, - then regimplification is probably needed. */ - if (invariant && !is_gimple_min_invariant (*tp)) - id->regimplify = true; - - *walk_subtrees = 0; - } - } - - /* Update the TREE_BLOCK for the cloned expr. */ - if (EXPR_P (*tp)) - { - tree new_block = id->remapping_type_depth == 0 ? id->block : NULL; - tree old_block = TREE_BLOCK (*tp); - if (old_block) - { - tree *n; - n = id->decl_map->get (TREE_BLOCK (*tp)); - if (n) - new_block = *n; - } - TREE_SET_BLOCK (*tp, new_block); - } - - /* Keep iterating. */ - return NULL_TREE; -} - - -/* Called from copy_body_id via walk_tree. DATA is really a - `copy_body_data *'. */ - -tree -copy_tree_body_r (tree *tp, int *walk_subtrees, void *data) -{ - copy_body_data *id = (copy_body_data *) data; - tree fn = id->src_fn; - tree new_block; - - /* Begin by recognizing trees that we'll completely rewrite for the - inlining context. Our output for these trees is completely - different from out input (e.g. RETURN_EXPR is deleted, and morphs - into an edge). Further down, we'll handle trees that get - duplicated and/or tweaked. */ - - /* When requested, RETURN_EXPRs should be transformed to just the - contained MODIFY_EXPR. The branch semantics of the return will - be handled elsewhere by manipulating the CFG rather than a statement. */ - if (TREE_CODE (*tp) == RETURN_EXPR && id->transform_return_to_modify) - { - tree assignment = TREE_OPERAND (*tp, 0); - - /* If we're returning something, just turn that into an - assignment into the equivalent of the original RESULT_DECL. - If the "assignment" is just the result decl, the result - decl has already been set (e.g. a recent "foo (&result_decl, - ...)"); just toss the entire RETURN_EXPR. */ - if (assignment && TREE_CODE (assignment) == MODIFY_EXPR) - { - /* Replace the RETURN_EXPR with (a copy of) the - MODIFY_EXPR hanging underneath. */ - *tp = copy_node (assignment); - } - else /* Else the RETURN_EXPR returns no value. */ - { - *tp = NULL; - return (tree) (void *)1; - } - } - else if (TREE_CODE (*tp) == SSA_NAME) - { - *tp = remap_ssa_name (*tp, id); - *walk_subtrees = 0; - return NULL; - } - - /* Local variables and labels need to be replaced by equivalent - variables. We don't want to copy static variables; there's only - one of those, no matter how many times we inline the containing - function. Similarly for globals from an outer function. */ - else if (auto_var_in_fn_p (*tp, fn)) - { - tree new_decl; - - /* Remap the declaration. */ - new_decl = remap_decl (*tp, id); - gcc_assert (new_decl); - /* Replace this variable with the copy. */ - STRIP_TYPE_NOPS (new_decl); - *tp = new_decl; - *walk_subtrees = 0; - } - else if (TREE_CODE (*tp) == STATEMENT_LIST) - copy_statement_list (tp); - else if (TREE_CODE (*tp) == SAVE_EXPR - || TREE_CODE (*tp) == TARGET_EXPR) - remap_save_expr (tp, id->decl_map, walk_subtrees); - else if (TREE_CODE (*tp) == LABEL_DECL - && (! DECL_CONTEXT (*tp) - || decl_function_context (*tp) == id->src_fn)) - /* These may need to be remapped for EH handling. */ - *tp = remap_decl (*tp, id); - else if (TREE_CODE (*tp) == BIND_EXPR) - copy_bind_expr (tp, walk_subtrees, id); - /* Types may need remapping as well. */ - else if (TYPE_P (*tp)) - *tp = remap_type (*tp, id); - - /* If this is a constant, we have to copy the node iff the type will be - remapped. copy_tree_r will not copy a constant. */ - else if (CONSTANT_CLASS_P (*tp)) - { - tree new_type = remap_type (TREE_TYPE (*tp), id); - - if (new_type == TREE_TYPE (*tp)) - *walk_subtrees = 0; - - else if (TREE_CODE (*tp) == INTEGER_CST) - *tp = wide_int_to_tree (new_type, wi::to_wide (*tp)); - else - { - *tp = copy_node (*tp); - TREE_TYPE (*tp) = new_type; - } - } - - /* Otherwise, just copy the node. Note that copy_tree_r already - knows not to copy VAR_DECLs, etc., so this is safe. */ - else - { - /* Here we handle trees that are not completely rewritten. - First we detect some inlining-induced bogosities for - discarding. */ - if (TREE_CODE (*tp) == MODIFY_EXPR - && TREE_OPERAND (*tp, 0) == TREE_OPERAND (*tp, 1) - && (auto_var_in_fn_p (TREE_OPERAND (*tp, 0), fn))) - { - /* Some assignments VAR = VAR; don't generate any rtl code - and thus don't count as variable modification. Avoid - keeping bogosities like 0 = 0. */ - tree decl = TREE_OPERAND (*tp, 0), value; - tree *n; - - n = id->decl_map->get (decl); - if (n) - { - value = *n; - STRIP_TYPE_NOPS (value); - if (TREE_CONSTANT (value) || TREE_READONLY (value)) - { - *tp = build_empty_stmt (EXPR_LOCATION (*tp)); - return copy_tree_body_r (tp, walk_subtrees, data); - } - } - } - else if (TREE_CODE (*tp) == INDIRECT_REF) - { - /* Get rid of *& from inline substitutions that can happen when a - pointer argument is an ADDR_EXPR. */ - tree decl = TREE_OPERAND (*tp, 0); - tree *n = id->decl_map->get (decl); - if (n) - { - /* If we happen to get an ADDR_EXPR in n->value, strip - it manually here as we'll eventually get ADDR_EXPRs - which lie about their types pointed to. In this case - build_fold_indirect_ref wouldn't strip the INDIRECT_REF, - but we absolutely rely on that. As fold_indirect_ref - does other useful transformations, try that first, though. */ - tree type = TREE_TYPE (*tp); - tree ptr = id->do_not_unshare ? *n : unshare_expr (*n); - tree old = *tp; - *tp = id->do_not_fold ? NULL : gimple_fold_indirect_ref (ptr); - if (! *tp) - { - type = remap_type (type, id); - if (TREE_CODE (ptr) == ADDR_EXPR && !id->do_not_fold) - { - *tp - = fold_indirect_ref_1 (EXPR_LOCATION (ptr), type, ptr); - /* ??? We should either assert here or build - a VIEW_CONVERT_EXPR instead of blindly leaking - incompatible types to our IL. */ - if (! *tp) - *tp = TREE_OPERAND (ptr, 0); - } - else - { - *tp = build1 (INDIRECT_REF, type, ptr); - TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old); - TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old); - TREE_READONLY (*tp) = TREE_READONLY (old); - /* We cannot propagate the TREE_THIS_NOTRAP flag if we - have remapped a parameter as the property might be - valid only for the parameter itself. */ - if (TREE_THIS_NOTRAP (old) - && (!is_parm (TREE_OPERAND (old, 0)) - || (!id->transform_parameter && is_parm (ptr)))) - TREE_THIS_NOTRAP (*tp) = 1; - } - } - *walk_subtrees = 0; - return NULL; - } - } - else if (TREE_CODE (*tp) == MEM_REF && !id->do_not_fold) - { - /* We need to re-canonicalize MEM_REFs from inline substitutions - that can happen when a pointer argument is an ADDR_EXPR. - Recurse here manually to allow that. */ - tree ptr = TREE_OPERAND (*tp, 0); - tree type = remap_type (TREE_TYPE (*tp), id); - tree old = *tp; - walk_tree (&ptr, copy_tree_body_r, data, NULL); - *tp = fold_build2 (MEM_REF, type, ptr, TREE_OPERAND (*tp, 1)); - TREE_THIS_VOLATILE (*tp) = TREE_THIS_VOLATILE (old); - TREE_SIDE_EFFECTS (*tp) = TREE_SIDE_EFFECTS (old); - copy_warning (*tp, old); - if (MR_DEPENDENCE_CLIQUE (old) != 0) - { - MR_DEPENDENCE_CLIQUE (*tp) - = remap_dependence_clique (id, MR_DEPENDENCE_CLIQUE (old)); - MR_DEPENDENCE_BASE (*tp) = MR_DEPENDENCE_BASE (old); - } - /* We cannot propagate the TREE_THIS_NOTRAP flag if we have - remapped a parameter as the property might be valid only - for the parameter itself. */ - if (TREE_THIS_NOTRAP (old) - && (!is_parm (TREE_OPERAND (old, 0)) - || (!id->transform_parameter && is_parm (ptr)))) - TREE_THIS_NOTRAP (*tp) = 1; - REF_REVERSE_STORAGE_ORDER (*tp) = REF_REVERSE_STORAGE_ORDER (old); - *walk_subtrees = 0; - return NULL; - } - - /* Here is the "usual case". Copy this tree node, and then - tweak some special cases. */ - copy_tree_r (tp, walk_subtrees, NULL); - - /* If EXPR has block defined, map it to newly constructed block. - When inlining we want EXPRs without block appear in the block - of function call if we are not remapping a type. */ - if (EXPR_P (*tp)) - { - new_block = id->remapping_type_depth == 0 ? id->block : NULL; - if (TREE_BLOCK (*tp)) - { - tree *n; - n = id->decl_map->get (TREE_BLOCK (*tp)); - if (n) - new_block = *n; - } - TREE_SET_BLOCK (*tp, new_block); - } - - if (TREE_CODE (*tp) != OMP_CLAUSE) - TREE_TYPE (*tp) = remap_type (TREE_TYPE (*tp), id); - - /* The copied TARGET_EXPR has never been expanded, even if the - original node was expanded already. */ - if (TREE_CODE (*tp) == TARGET_EXPR && TREE_OPERAND (*tp, 3)) - { - TREE_OPERAND (*tp, 1) = TREE_OPERAND (*tp, 3); - TREE_OPERAND (*tp, 3) = NULL_TREE; - } - - /* Variable substitution need not be simple. In particular, the - INDIRECT_REF substitution above. Make sure that TREE_CONSTANT - and friends are up-to-date. */ - else if (TREE_CODE (*tp) == ADDR_EXPR) - { - int invariant = is_gimple_min_invariant (*tp); - walk_tree (&TREE_OPERAND (*tp, 0), copy_tree_body_r, id, NULL); - - /* Handle the case where we substituted an INDIRECT_REF - into the operand of the ADDR_EXPR. */ - if (TREE_CODE (TREE_OPERAND (*tp, 0)) == INDIRECT_REF - && !id->do_not_fold) - { - tree t = TREE_OPERAND (TREE_OPERAND (*tp, 0), 0); - if (TREE_TYPE (t) != TREE_TYPE (*tp)) - t = fold_convert (remap_type (TREE_TYPE (*tp), id), t); - *tp = t; - } - else - recompute_tree_invariant_for_addr_expr (*tp); - - /* If this used to be invariant, but is not any longer, - then regimplification is probably needed. */ - if (invariant && !is_gimple_min_invariant (*tp)) - id->regimplify = true; - - *walk_subtrees = 0; - } - else if (TREE_CODE (*tp) == OMP_CLAUSE - && (OMP_CLAUSE_CODE (*tp) == OMP_CLAUSE_AFFINITY - || OMP_CLAUSE_CODE (*tp) == OMP_CLAUSE_DEPEND)) - { - tree t = OMP_CLAUSE_DECL (*tp); - if (t - && TREE_CODE (t) == TREE_LIST - && TREE_PURPOSE (t) - && TREE_CODE (TREE_PURPOSE (t)) == TREE_VEC) - { - *walk_subtrees = 0; - OMP_CLAUSE_DECL (*tp) = copy_node (t); - t = OMP_CLAUSE_DECL (*tp); - TREE_PURPOSE (t) = copy_node (TREE_PURPOSE (t)); - for (int i = 0; i <= 4; i++) - walk_tree (&TREE_VEC_ELT (TREE_PURPOSE (t), i), - copy_tree_body_r, id, NULL); - if (TREE_VEC_ELT (TREE_PURPOSE (t), 5)) - remap_block (&TREE_VEC_ELT (TREE_PURPOSE (t), 5), id); - walk_tree (&TREE_VALUE (t), copy_tree_body_r, id, NULL); - } - } - } - - /* Keep iterating. */ - return NULL_TREE; -} - -/* Helper for remap_gimple_stmt. Given an EH region number for the - source function, map that to the duplicate EH region number in - the destination function. */ - -static int -remap_eh_region_nr (int old_nr, copy_body_data *id) -{ - eh_region old_r, new_r; - - old_r = get_eh_region_from_number_fn (id->src_cfun, old_nr); - new_r = static_cast<eh_region> (*id->eh_map->get (old_r)); - - return new_r->index; -} - -/* Similar, but operate on INTEGER_CSTs. */ - -static tree -remap_eh_region_tree_nr (tree old_t_nr, copy_body_data *id) -{ - int old_nr, new_nr; - - old_nr = tree_to_shwi (old_t_nr); - new_nr = remap_eh_region_nr (old_nr, id); - - return build_int_cst (integer_type_node, new_nr); -} - -/* Helper for copy_bb. Remap statement STMT using the inlining - information in ID. Return the new statement copy. */ - -static gimple_seq -remap_gimple_stmt (gimple *stmt, copy_body_data *id) -{ - gimple *copy = NULL; - struct walk_stmt_info wi; - bool skip_first = false; - gimple_seq stmts = NULL; - - if (is_gimple_debug (stmt) - && (gimple_debug_nonbind_marker_p (stmt) - ? !DECL_STRUCT_FUNCTION (id->dst_fn)->debug_nonbind_markers - : !opt_for_fn (id->dst_fn, flag_var_tracking_assignments))) - return NULL; - - if (!is_gimple_debug (stmt) - && id->param_body_adjs - && id->param_body_adjs->m_dead_stmts.contains (stmt)) - { - tree *dval = id->param_body_adjs->m_dead_stmt_debug_equiv.get (stmt); - if (!dval) - return NULL; - - gcc_assert (is_gimple_assign (stmt)); - tree lhs = gimple_assign_lhs (stmt); - tree *dvar = id->param_body_adjs->m_dead_ssa_debug_equiv.get (lhs); - gdebug *bind = gimple_build_debug_bind (*dvar, *dval, stmt); - if (id->reset_location) - gimple_set_location (bind, input_location); - id->debug_stmts.safe_push (bind); - gimple_seq_add_stmt (&stmts, bind); - return stmts; - } - - /* Begin by recognizing trees that we'll completely rewrite for the - inlining context. Our output for these trees is completely - different from our input (e.g. RETURN_EXPR is deleted and morphs - into an edge). Further down, we'll handle trees that get - duplicated and/or tweaked. */ - - /* When requested, GIMPLE_RETURN should be transformed to just the - contained GIMPLE_ASSIGN. The branch semantics of the return will - be handled elsewhere by manipulating the CFG rather than the - statement. */ - if (gimple_code (stmt) == GIMPLE_RETURN && id->transform_return_to_modify) - { - tree retval = gimple_return_retval (as_a <greturn *> (stmt)); - - /* If we're returning something, just turn that into an - assignment to the equivalent of the original RESULT_DECL. - If RETVAL is just the result decl, the result decl has - already been set (e.g. a recent "foo (&result_decl, ...)"); - just toss the entire GIMPLE_RETURN. Likewise for when the - call doesn't want the return value. */ - if (retval - && (TREE_CODE (retval) != RESULT_DECL - && (!id->call_stmt - || gimple_call_lhs (id->call_stmt) != NULL_TREE) - && (TREE_CODE (retval) != SSA_NAME - || ! SSA_NAME_VAR (retval) - || TREE_CODE (SSA_NAME_VAR (retval)) != RESULT_DECL))) - { - copy = gimple_build_assign (id->do_not_unshare - ? id->retvar : unshare_expr (id->retvar), - retval); - /* id->retvar is already substituted. Skip it on later remapping. */ - skip_first = true; - } - else - return NULL; - } - else if (gimple_has_substatements (stmt)) - { - gimple_seq s1, s2; - - /* When cloning bodies from the C++ front end, we will be handed bodies - in High GIMPLE form. Handle here all the High GIMPLE statements that - have embedded statements. */ - switch (gimple_code (stmt)) - { - case GIMPLE_BIND: - copy = copy_gimple_bind (as_a <gbind *> (stmt), id); - break; - - case GIMPLE_CATCH: - { - gcatch *catch_stmt = as_a <gcatch *> (stmt); - s1 = remap_gimple_seq (gimple_catch_handler (catch_stmt), id); - copy = gimple_build_catch (gimple_catch_types (catch_stmt), s1); - } - break; - - case GIMPLE_EH_FILTER: - s1 = remap_gimple_seq (gimple_eh_filter_failure (stmt), id); - copy = gimple_build_eh_filter (gimple_eh_filter_types (stmt), s1); - break; - - case GIMPLE_TRY: - s1 = remap_gimple_seq (gimple_try_eval (stmt), id); - s2 = remap_gimple_seq (gimple_try_cleanup (stmt), id); - copy = gimple_build_try (s1, s2, gimple_try_kind (stmt)); - break; - - case GIMPLE_WITH_CLEANUP_EXPR: - s1 = remap_gimple_seq (gimple_wce_cleanup (stmt), id); - copy = gimple_build_wce (s1); - break; - - case GIMPLE_OMP_PARALLEL: - { - gomp_parallel *omp_par_stmt = as_a <gomp_parallel *> (stmt); - s1 = remap_gimple_seq (gimple_omp_body (omp_par_stmt), id); - copy = gimple_build_omp_parallel - (s1, - gimple_omp_parallel_clauses (omp_par_stmt), - gimple_omp_parallel_child_fn (omp_par_stmt), - gimple_omp_parallel_data_arg (omp_par_stmt)); - } - break; - - case GIMPLE_OMP_TASK: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_task - (s1, - gimple_omp_task_clauses (stmt), - gimple_omp_task_child_fn (stmt), - gimple_omp_task_data_arg (stmt), - gimple_omp_task_copy_fn (stmt), - gimple_omp_task_arg_size (stmt), - gimple_omp_task_arg_align (stmt)); - break; - - case GIMPLE_OMP_FOR: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - s2 = remap_gimple_seq (gimple_omp_for_pre_body (stmt), id); - copy = gimple_build_omp_for (s1, gimple_omp_for_kind (stmt), - gimple_omp_for_clauses (stmt), - gimple_omp_for_collapse (stmt), s2); - { - size_t i; - for (i = 0; i < gimple_omp_for_collapse (stmt); i++) - { - gimple_omp_for_set_index (copy, i, - gimple_omp_for_index (stmt, i)); - gimple_omp_for_set_initial (copy, i, - gimple_omp_for_initial (stmt, i)); - gimple_omp_for_set_final (copy, i, - gimple_omp_for_final (stmt, i)); - gimple_omp_for_set_incr (copy, i, - gimple_omp_for_incr (stmt, i)); - gimple_omp_for_set_cond (copy, i, - gimple_omp_for_cond (stmt, i)); - } - } - break; - - case GIMPLE_OMP_MASTER: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_master (s1); - break; - - case GIMPLE_OMP_MASKED: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_masked - (s1, gimple_omp_masked_clauses (stmt)); - break; - - case GIMPLE_OMP_SCOPE: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_scope - (s1, gimple_omp_scope_clauses (stmt)); - break; - - case GIMPLE_OMP_TASKGROUP: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_taskgroup - (s1, gimple_omp_taskgroup_clauses (stmt)); - break; - - case GIMPLE_OMP_ORDERED: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_ordered - (s1, - gimple_omp_ordered_clauses (as_a <gomp_ordered *> (stmt))); - break; - - case GIMPLE_OMP_SCAN: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_scan - (s1, gimple_omp_scan_clauses (as_a <gomp_scan *> (stmt))); - break; - - case GIMPLE_OMP_SECTION: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_section (s1); - break; - - case GIMPLE_OMP_SECTIONS: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_sections - (s1, gimple_omp_sections_clauses (stmt)); - break; - - case GIMPLE_OMP_SINGLE: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_single - (s1, gimple_omp_single_clauses (stmt)); - break; - - case GIMPLE_OMP_TARGET: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_target - (s1, gimple_omp_target_kind (stmt), - gimple_omp_target_clauses (stmt)); - break; - - case GIMPLE_OMP_TEAMS: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_teams - (s1, gimple_omp_teams_clauses (stmt)); - break; - - case GIMPLE_OMP_CRITICAL: - s1 = remap_gimple_seq (gimple_omp_body (stmt), id); - copy = gimple_build_omp_critical (s1, - gimple_omp_critical_name - (as_a <gomp_critical *> (stmt)), - gimple_omp_critical_clauses - (as_a <gomp_critical *> (stmt))); - break; - - case GIMPLE_TRANSACTION: - { - gtransaction *old_trans_stmt = as_a <gtransaction *> (stmt); - gtransaction *new_trans_stmt; - s1 = remap_gimple_seq (gimple_transaction_body (old_trans_stmt), - id); - copy = new_trans_stmt = gimple_build_transaction (s1); - gimple_transaction_set_subcode (new_trans_stmt, - gimple_transaction_subcode (old_trans_stmt)); - gimple_transaction_set_label_norm (new_trans_stmt, - gimple_transaction_label_norm (old_trans_stmt)); - gimple_transaction_set_label_uninst (new_trans_stmt, - gimple_transaction_label_uninst (old_trans_stmt)); - gimple_transaction_set_label_over (new_trans_stmt, - gimple_transaction_label_over (old_trans_stmt)); - } - break; - - default: - gcc_unreachable (); - } - } - else - { - if (gimple_assign_copy_p (stmt) - && gimple_assign_lhs (stmt) == gimple_assign_rhs1 (stmt) - && auto_var_in_fn_p (gimple_assign_lhs (stmt), id->src_fn)) - { - /* Here we handle statements that are not completely rewritten. - First we detect some inlining-induced bogosities for - discarding. */ - - /* Some assignments VAR = VAR; don't generate any rtl code - and thus don't count as variable modification. Avoid - keeping bogosities like 0 = 0. */ - tree decl = gimple_assign_lhs (stmt), value; - tree *n; - - n = id->decl_map->get (decl); - if (n) - { - value = *n; - STRIP_TYPE_NOPS (value); - if (TREE_CONSTANT (value) || TREE_READONLY (value)) - return NULL; - } - } - - /* For *ptr_N ={v} {CLOBBER}, if ptr_N is SSA_NAME defined - in a block that we aren't copying during tree_function_versioning, - just drop the clobber stmt. */ - if (id->blocks_to_copy && gimple_clobber_p (stmt)) - { - tree lhs = gimple_assign_lhs (stmt); - if (TREE_CODE (lhs) == MEM_REF - && TREE_CODE (TREE_OPERAND (lhs, 0)) == SSA_NAME) - { - gimple *def_stmt = SSA_NAME_DEF_STMT (TREE_OPERAND (lhs, 0)); - if (gimple_bb (def_stmt) - && !bitmap_bit_p (id->blocks_to_copy, - gimple_bb (def_stmt)->index)) - return NULL; - } - } - - /* We do not allow CLOBBERs of handled components. In case - returned value is stored via such handled component, remove - the clobber so stmt verifier is happy. */ - if (gimple_clobber_p (stmt) - && TREE_CODE (gimple_assign_lhs (stmt)) == RESULT_DECL) - { - tree remapped = remap_decl (gimple_assign_lhs (stmt), id); - if (!DECL_P (remapped) - && TREE_CODE (remapped) != MEM_REF) - return NULL; - } - - if (gimple_debug_bind_p (stmt)) - { - tree var = gimple_debug_bind_get_var (stmt); - tree value = gimple_debug_bind_get_value (stmt); - if (id->param_body_adjs - && id->param_body_adjs->m_dead_stmts.contains (stmt)) - { - value = unshare_expr_without_location (value); - id->param_body_adjs->remap_with_debug_expressions (&value); - } - - gdebug *copy = gimple_build_debug_bind (var, value, stmt); - if (id->reset_location) - gimple_set_location (copy, input_location); - id->debug_stmts.safe_push (copy); - gimple_seq_add_stmt (&stmts, copy); - return stmts; - } - if (gimple_debug_source_bind_p (stmt)) - { - gdebug *copy = gimple_build_debug_source_bind - (gimple_debug_source_bind_get_var (stmt), - gimple_debug_source_bind_get_value (stmt), - stmt); - if (id->reset_location) - gimple_set_location (copy, input_location); - id->debug_stmts.safe_push (copy); - gimple_seq_add_stmt (&stmts, copy); - return stmts; - } - if (gimple_debug_nonbind_marker_p (stmt)) - { - /* If the inlined function has too many debug markers, - don't copy them. */ - if (id->src_cfun->debug_marker_count - > param_max_debug_marker_count - || id->reset_location) - return stmts; - - gdebug *copy = as_a <gdebug *> (gimple_copy (stmt)); - id->debug_stmts.safe_push (copy); - gimple_seq_add_stmt (&stmts, copy); - return stmts; - } - - /* Create a new deep copy of the statement. */ - copy = gimple_copy (stmt); - - /* Clear flags that need revisiting. */ - if (gcall *call_stmt = dyn_cast <gcall *> (copy)) - { - if (gimple_call_tail_p (call_stmt)) - gimple_call_set_tail (call_stmt, false); - if (gimple_call_from_thunk_p (call_stmt)) - gimple_call_set_from_thunk (call_stmt, false); - if (gimple_call_internal_p (call_stmt)) - switch (gimple_call_internal_fn (call_stmt)) - { - case IFN_GOMP_SIMD_LANE: - case IFN_GOMP_SIMD_VF: - case IFN_GOMP_SIMD_LAST_LANE: - case IFN_GOMP_SIMD_ORDERED_START: - case IFN_GOMP_SIMD_ORDERED_END: - DECL_STRUCT_FUNCTION (id->dst_fn)->has_simduid_loops = true; - break; - default: - break; - } - } - - /* Remap the region numbers for __builtin_eh_{pointer,filter}, - RESX and EH_DISPATCH. */ - if (id->eh_map) - switch (gimple_code (copy)) - { - case GIMPLE_CALL: - { - tree r, fndecl = gimple_call_fndecl (copy); - if (fndecl && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL)) - switch (DECL_FUNCTION_CODE (fndecl)) - { - case BUILT_IN_EH_COPY_VALUES: - r = gimple_call_arg (copy, 1); - r = remap_eh_region_tree_nr (r, id); - gimple_call_set_arg (copy, 1, r); - /* FALLTHRU */ - - case BUILT_IN_EH_POINTER: - case BUILT_IN_EH_FILTER: - r = gimple_call_arg (copy, 0); - r = remap_eh_region_tree_nr (r, id); - gimple_call_set_arg (copy, 0, r); - break; - - default: - break; - } - - /* Reset alias info if we didn't apply measures to - keep it valid over inlining by setting DECL_PT_UID. */ - if (!id->src_cfun->gimple_df - || !id->src_cfun->gimple_df->ipa_pta) - gimple_call_reset_alias_info (as_a <gcall *> (copy)); - } - break; - - case GIMPLE_RESX: - { - gresx *resx_stmt = as_a <gresx *> (copy); - int r = gimple_resx_region (resx_stmt); - r = remap_eh_region_nr (r, id); - gimple_resx_set_region (resx_stmt, r); - } - break; - - case GIMPLE_EH_DISPATCH: - { - geh_dispatch *eh_dispatch = as_a <geh_dispatch *> (copy); - int r = gimple_eh_dispatch_region (eh_dispatch); - r = remap_eh_region_nr (r, id); - gimple_eh_dispatch_set_region (eh_dispatch, r); - } - break; - - default: - break; - } - } - - /* If STMT has a block defined, map it to the newly constructed block. */ - if (tree block = gimple_block (copy)) - { - tree *n; - n = id->decl_map->get (block); - gcc_assert (n); - gimple_set_block (copy, *n); - } - if (id->param_body_adjs) - { - gimple_seq extra_stmts = NULL; - id->param_body_adjs->modify_gimple_stmt (©, &extra_stmts, stmt); - if (!gimple_seq_empty_p (extra_stmts)) - { - memset (&wi, 0, sizeof (wi)); - wi.info = id; - for (gimple_stmt_iterator egsi = gsi_start (extra_stmts); - !gsi_end_p (egsi); - gsi_next (&egsi)) - walk_gimple_op (gsi_stmt (egsi), remap_gimple_op_r, &wi); - gimple_seq_add_seq (&stmts, extra_stmts); - } - } - - if (id->reset_location) - gimple_set_location (copy, input_location); - - /* Debug statements ought to be rebuilt and not copied. */ - gcc_checking_assert (!is_gimple_debug (copy)); - - /* Remap all the operands in COPY. */ - memset (&wi, 0, sizeof (wi)); - wi.info = id; - if (skip_first) - walk_tree (gimple_op_ptr (copy, 1), remap_gimple_op_r, &wi, NULL); - else - walk_gimple_op (copy, remap_gimple_op_r, &wi); - - /* Clear the copied virtual operands. We are not remapping them here - but are going to recreate them from scratch. */ - if (gimple_has_mem_ops (copy)) - { - gimple_set_vdef (copy, NULL_TREE); - gimple_set_vuse (copy, NULL_TREE); - } - - if (cfun->can_throw_non_call_exceptions) - { - /* When inlining a function which does not have non-call exceptions - enabled into a function that has (which only happens with - always-inline) we have to fixup stmts that cannot throw. */ - if (gcond *cond = dyn_cast <gcond *> (copy)) - if (gimple_could_trap_p (cond)) - { - gassign *cmp - = gimple_build_assign (make_ssa_name (boolean_type_node), - gimple_cond_code (cond), - gimple_cond_lhs (cond), - gimple_cond_rhs (cond)); - gimple_seq_add_stmt (&stmts, cmp); - gimple_cond_set_code (cond, NE_EXPR); - gimple_cond_set_lhs (cond, gimple_assign_lhs (cmp)); - gimple_cond_set_rhs (cond, boolean_false_node); - } - } - - gimple_seq_add_stmt (&stmts, copy); - return stmts; -} - - -/* Copy basic block, scale profile accordingly. Edges will be taken care of - later */ - -static basic_block -copy_bb (copy_body_data *id, basic_block bb, - profile_count num, profile_count den) -{ - gimple_stmt_iterator gsi, copy_gsi, seq_gsi; - basic_block copy_basic_block; - tree decl; - basic_block prev; - - profile_count::adjust_for_ipa_scaling (&num, &den); - - /* Search for previous copied basic block. */ - prev = bb->prev_bb; - while (!prev->aux) - prev = prev->prev_bb; - - /* create_basic_block() will append every new block to - basic_block_info automatically. */ - copy_basic_block = create_basic_block (NULL, (basic_block) prev->aux); - copy_basic_block->count = bb->count.apply_scale (num, den); - - copy_gsi = gsi_start_bb (copy_basic_block); - - for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple_seq stmts; - gimple *stmt = gsi_stmt (gsi); - gimple *orig_stmt = stmt; - gimple_stmt_iterator stmts_gsi; - bool stmt_added = false; - - id->regimplify = false; - stmts = remap_gimple_stmt (stmt, id); - - if (gimple_seq_empty_p (stmts)) - continue; - - seq_gsi = copy_gsi; - - for (stmts_gsi = gsi_start (stmts); - !gsi_end_p (stmts_gsi); ) - { - stmt = gsi_stmt (stmts_gsi); - - /* Advance iterator now before stmt is moved to seq_gsi. */ - gsi_next (&stmts_gsi); - - if (gimple_nop_p (stmt)) - continue; - - gimple_duplicate_stmt_histograms (cfun, stmt, id->src_cfun, - orig_stmt); - - /* With return slot optimization we can end up with - non-gimple (foo *)&this->m, fix that here. */ - if (is_gimple_assign (stmt) - && CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt)) - && !is_gimple_val (gimple_assign_rhs1 (stmt))) - { - tree new_rhs; - new_rhs = force_gimple_operand_gsi (&seq_gsi, - gimple_assign_rhs1 (stmt), - true, NULL, false, - GSI_CONTINUE_LINKING); - gimple_assign_set_rhs1 (stmt, new_rhs); - id->regimplify = false; - } - - gsi_insert_after (&seq_gsi, stmt, GSI_NEW_STMT); - - if (id->regimplify) - gimple_regimplify_operands (stmt, &seq_gsi); - - stmt_added = true; - } - - if (!stmt_added) - continue; - - /* If copy_basic_block has been empty at the start of this iteration, - call gsi_start_bb again to get at the newly added statements. */ - if (gsi_end_p (copy_gsi)) - copy_gsi = gsi_start_bb (copy_basic_block); - else - gsi_next (©_gsi); - - /* Process the new statement. The call to gimple_regimplify_operands - possibly turned the statement into multiple statements, we - need to process all of them. */ - do - { - tree fn; - gcall *call_stmt; - - stmt = gsi_stmt (copy_gsi); - call_stmt = dyn_cast <gcall *> (stmt); - if (call_stmt - && gimple_call_va_arg_pack_p (call_stmt) - && id->call_stmt - && ! gimple_call_va_arg_pack_p (id->call_stmt)) - { - /* __builtin_va_arg_pack () should be replaced by - all arguments corresponding to ... in the caller. */ - tree p; - gcall *new_call; - vec<tree> argarray; - size_t nargs_caller = gimple_call_num_args (id->call_stmt); - size_t nargs = nargs_caller; - - for (p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p)) - { - /* Avoid crashing on invalid IL that doesn't have a - varargs function or that passes not enough arguments. */ - if (nargs == 0) - break; - nargs--; - } - - /* Create the new array of arguments. */ - size_t nargs_callee = gimple_call_num_args (call_stmt); - size_t n = nargs + nargs_callee; - argarray.create (n); - argarray.safe_grow_cleared (n, true); - - /* Copy all the arguments before '...' */ - if (nargs_callee) - memcpy (argarray.address (), - gimple_call_arg_ptr (call_stmt, 0), - nargs_callee * sizeof (tree)); - - /* Append the arguments passed in '...' */ - if (nargs) - memcpy (argarray.address () + nargs_callee, - gimple_call_arg_ptr (id->call_stmt, 0) - + (nargs_caller - nargs), nargs * sizeof (tree)); - - new_call = gimple_build_call_vec (gimple_call_fn (call_stmt), - argarray); - - argarray.release (); - - /* Copy all GIMPLE_CALL flags, location and block, except - GF_CALL_VA_ARG_PACK. */ - gimple_call_copy_flags (new_call, call_stmt); - gimple_call_set_va_arg_pack (new_call, false); - gimple_call_set_fntype (new_call, gimple_call_fntype (call_stmt)); - /* location includes block. */ - gimple_set_location (new_call, gimple_location (stmt)); - gimple_call_set_lhs (new_call, gimple_call_lhs (call_stmt)); - - gsi_replace (©_gsi, new_call, false); - stmt = new_call; - } - else if (call_stmt - && id->call_stmt - && (decl = gimple_call_fndecl (stmt)) - && fndecl_built_in_p (decl, BUILT_IN_VA_ARG_PACK_LEN)) - { - /* __builtin_va_arg_pack_len () should be replaced by - the number of anonymous arguments. */ - size_t nargs = gimple_call_num_args (id->call_stmt); - tree count, p; - gimple *new_stmt; - - for (p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p)) - nargs--; - - if (!gimple_call_lhs (stmt)) - { - /* Drop unused calls. */ - gsi_remove (©_gsi, false); - continue; - } - else if (!gimple_call_va_arg_pack_p (id->call_stmt)) - { - count = build_int_cst (integer_type_node, nargs); - new_stmt = gimple_build_assign (gimple_call_lhs (stmt), count); - gsi_replace (©_gsi, new_stmt, false); - stmt = new_stmt; - } - else if (nargs != 0) - { - tree newlhs = create_tmp_reg_or_ssa_name (integer_type_node); - count = build_int_cst (integer_type_node, nargs); - new_stmt = gimple_build_assign (gimple_call_lhs (stmt), - PLUS_EXPR, newlhs, count); - gimple_call_set_lhs (stmt, newlhs); - gsi_insert_after (©_gsi, new_stmt, GSI_NEW_STMT); - } - } - else if (call_stmt - && id->call_stmt - && gimple_call_internal_p (stmt) - && gimple_call_internal_fn (stmt) == IFN_TSAN_FUNC_EXIT) - { - /* Drop TSAN_FUNC_EXIT () internal calls during inlining. */ - gsi_remove (©_gsi, false); - continue; - } - - /* Statements produced by inlining can be unfolded, especially - when we constant propagated some operands. We can't fold - them right now for two reasons: - 1) folding require SSA_NAME_DEF_STMTs to be correct - 2) we can't change function calls to builtins. - So we just mark statement for later folding. We mark - all new statements, instead just statements that has changed - by some nontrivial substitution so even statements made - foldable indirectly are updated. If this turns out to be - expensive, copy_body can be told to watch for nontrivial - changes. */ - if (id->statements_to_fold) - id->statements_to_fold->add (stmt); - - /* We're duplicating a CALL_EXPR. Find any corresponding - callgraph edges and update or duplicate them. */ - if (gcall *call_stmt = dyn_cast <gcall *> (stmt)) - { - struct cgraph_edge *edge; - - switch (id->transform_call_graph_edges) - { - case CB_CGE_DUPLICATE: - edge = id->src_node->get_edge (orig_stmt); - if (edge) - { - struct cgraph_edge *old_edge = edge; - - /* A speculative call is consist of multiple - edges - indirect edge and one or more direct edges - Duplicate the whole thing and distribute frequencies - accordingly. */ - if (edge->speculative) - { - int n = 0; - profile_count direct_cnt - = profile_count::zero (); - - /* First figure out the distribution of counts - so we can re-scale BB profile accordingly. */ - for (cgraph_edge *e = old_edge; e; - e = e->next_speculative_call_target ()) - direct_cnt = direct_cnt + e->count; - - cgraph_edge *indirect - = old_edge->speculative_call_indirect_edge (); - profile_count indir_cnt = indirect->count; - - /* Next iterate all direct edges, clone it and its - corresponding reference and update profile. */ - for (cgraph_edge *e = old_edge; - e; - e = e->next_speculative_call_target ()) - { - profile_count cnt = e->count; - - id->dst_node->clone_reference - (e->speculative_call_target_ref (), stmt); - edge = e->clone (id->dst_node, call_stmt, - gimple_uid (stmt), num, den, - true); - profile_probability prob - = cnt.probability_in (direct_cnt - + indir_cnt); - edge->count - = copy_basic_block->count.apply_probability - (prob); - n++; - } - gcc_checking_assert - (indirect->num_speculative_call_targets_p () - == n); - - /* Duplicate the indirect edge after all direct edges - cloned. */ - indirect = indirect->clone (id->dst_node, call_stmt, - gimple_uid (stmt), - num, den, - true); - - profile_probability prob - = indir_cnt.probability_in (direct_cnt - + indir_cnt); - indirect->count - = copy_basic_block->count.apply_probability (prob); - } - else - { - edge = edge->clone (id->dst_node, call_stmt, - gimple_uid (stmt), - num, den, - true); - edge->count = copy_basic_block->count; - } - } - break; - - case CB_CGE_MOVE_CLONES: - id->dst_node->set_call_stmt_including_clones (orig_stmt, - call_stmt); - edge = id->dst_node->get_edge (stmt); - break; - - case CB_CGE_MOVE: - edge = id->dst_node->get_edge (orig_stmt); - if (edge) - edge = cgraph_edge::set_call_stmt (edge, call_stmt); - break; - - default: - gcc_unreachable (); - } - - /* Constant propagation on argument done during inlining - may create new direct call. Produce an edge for it. */ - if ((!edge - || (edge->indirect_inlining_edge - && id->transform_call_graph_edges == CB_CGE_MOVE_CLONES)) - && id->dst_node->definition - && (fn = gimple_call_fndecl (stmt)) != NULL) - { - struct cgraph_node *dest = cgraph_node::get_create (fn); - - /* We have missing edge in the callgraph. This can happen - when previous inlining turned an indirect call into a - direct call by constant propagating arguments or we are - producing dead clone (for further cloning). In all - other cases we hit a bug (incorrect node sharing is the - most common reason for missing edges). */ - gcc_assert (!dest->definition - || dest->address_taken - || !id->src_node->definition - || !id->dst_node->definition); - if (id->transform_call_graph_edges == CB_CGE_MOVE_CLONES) - id->dst_node->create_edge_including_clones - (dest, orig_stmt, call_stmt, bb->count, - CIF_ORIGINALLY_INDIRECT_CALL); - else - id->dst_node->create_edge (dest, call_stmt, - bb->count)->inline_failed - = CIF_ORIGINALLY_INDIRECT_CALL; - if (dump_file) - { - fprintf (dump_file, "Created new direct edge to %s\n", - dest->dump_name ()); - } - } - - notice_special_calls (as_a <gcall *> (stmt)); - } - - maybe_duplicate_eh_stmt_fn (cfun, stmt, id->src_cfun, orig_stmt, - id->eh_map, id->eh_lp_nr); - - gsi_next (©_gsi); - } - while (!gsi_end_p (copy_gsi)); - - copy_gsi = gsi_last_bb (copy_basic_block); - } - - return copy_basic_block; -} - -/* Inserting Single Entry Multiple Exit region in SSA form into code in SSA - form is quite easy, since dominator relationship for old basic blocks does - not change. - - There is however exception where inlining might change dominator relation - across EH edges from basic block within inlined functions destinating - to landing pads in function we inline into. - - The function fills in PHI_RESULTs of such PHI nodes if they refer - to gimple regs. Otherwise, the function mark PHI_RESULT of such - PHI nodes for renaming. For non-gimple regs, renaming is safe: the - EH edges are abnormal and SSA_NAME_OCCURS_IN_ABNORMAL_PHI must be - set, and this means that there will be no overlapping live ranges - for the underlying symbol. - - This might change in future if we allow redirecting of EH edges and - we might want to change way build CFG pre-inlining to include - all the possible edges then. */ -static void -update_ssa_across_abnormal_edges (basic_block bb, basic_block ret_bb, - bool can_throw, bool nonlocal_goto) -{ - edge e; - edge_iterator ei; - - FOR_EACH_EDGE (e, ei, bb->succs) - if (!e->dest->aux - || ((basic_block)e->dest->aux)->index == ENTRY_BLOCK) - { - gphi *phi; - gphi_iterator si; - - if (!nonlocal_goto) - gcc_assert (e->flags & EDGE_EH); - - if (!can_throw) - gcc_assert (!(e->flags & EDGE_EH)); - - for (si = gsi_start_phis (e->dest); !gsi_end_p (si); gsi_next (&si)) - { - edge re; - - phi = si.phi (); - - /* For abnormal goto/call edges the receiver can be the - ENTRY_BLOCK. Do not assert this cannot happen. */ - - gcc_assert ((e->flags & EDGE_EH) - || SSA_NAME_OCCURS_IN_ABNORMAL_PHI (PHI_RESULT (phi))); - - re = find_edge (ret_bb, e->dest); - gcc_checking_assert (re); - gcc_assert ((re->flags & (EDGE_EH | EDGE_ABNORMAL)) - == (e->flags & (EDGE_EH | EDGE_ABNORMAL))); - - SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), - USE_FROM_PTR (PHI_ARG_DEF_PTR_FROM_EDGE (phi, re))); - } - } -} - -/* Insert clobbers for automatic variables of inlined ID->src_fn - function at the start of basic block ID->eh_landing_pad_dest. */ - -static void -add_clobbers_to_eh_landing_pad (copy_body_data *id) -{ - tree var; - basic_block bb = id->eh_landing_pad_dest; - live_vars_map *vars = NULL; - unsigned int cnt = 0; - unsigned int i; - FOR_EACH_VEC_SAFE_ELT (id->src_cfun->local_decls, i, var) - if (VAR_P (var) - && !DECL_HARD_REGISTER (var) - && !TREE_THIS_VOLATILE (var) - && !DECL_HAS_VALUE_EXPR_P (var) - && !is_gimple_reg (var) - && auto_var_in_fn_p (var, id->src_fn) - && !lookup_attribute ("omp simd array", DECL_ATTRIBUTES (var))) - { - tree *t = id->decl_map->get (var); - if (!t) - continue; - tree new_var = *t; - if (VAR_P (new_var) - && !DECL_HARD_REGISTER (new_var) - && !TREE_THIS_VOLATILE (new_var) - && !DECL_HAS_VALUE_EXPR_P (new_var) - && !is_gimple_reg (new_var) - && auto_var_in_fn_p (new_var, id->dst_fn)) - { - if (vars == NULL) - vars = new live_vars_map; - vars->put (DECL_UID (var), cnt++); - } - } - if (vars == NULL) - return; - - vec<bitmap_head> live = compute_live_vars (id->src_cfun, vars); - FOR_EACH_VEC_SAFE_ELT (id->src_cfun->local_decls, i, var) - if (VAR_P (var)) - { - edge e; - edge_iterator ei; - bool needed = false; - unsigned int *v = vars->get (DECL_UID (var)); - if (v == NULL) - continue; - FOR_EACH_EDGE (e, ei, bb->preds) - if ((e->flags & EDGE_EH) != 0 - && e->src->index >= id->add_clobbers_to_eh_landing_pads) - { - basic_block src_bb = (basic_block) e->src->aux; - - if (bitmap_bit_p (&live[src_bb->index], *v)) - { - needed = true; - break; - } - } - if (needed) - { - tree new_var = *id->decl_map->get (var); - gimple_stmt_iterator gsi = gsi_after_labels (bb); - tree clobber = build_clobber (TREE_TYPE (new_var)); - gimple *clobber_stmt = gimple_build_assign (new_var, clobber); - gsi_insert_before (&gsi, clobber_stmt, GSI_NEW_STMT); - } - } - destroy_live_vars (live); - delete vars; -} - -/* Copy edges from BB into its copy constructed earlier, scale profile - accordingly. Edges will be taken care of later. Assume aux - pointers to point to the copies of each BB. Return true if any - debug stmts are left after a statement that must end the basic block. */ - -static bool -copy_edges_for_bb (basic_block bb, profile_count num, profile_count den, - basic_block ret_bb, basic_block abnormal_goto_dest, - copy_body_data *id) -{ - basic_block new_bb = (basic_block) bb->aux; - edge_iterator ei; - edge old_edge; - gimple_stmt_iterator si; - bool need_debug_cleanup = false; - - /* Use the indices from the original blocks to create edges for the - new ones. */ - FOR_EACH_EDGE (old_edge, ei, bb->succs) - if (!(old_edge->flags & EDGE_EH)) - { - edge new_edge; - int flags = old_edge->flags; - location_t locus = old_edge->goto_locus; - - /* Return edges do get a FALLTHRU flag when they get inlined. */ - if (old_edge->dest->index == EXIT_BLOCK - && !(flags & (EDGE_TRUE_VALUE|EDGE_FALSE_VALUE|EDGE_FAKE)) - && old_edge->dest->aux != EXIT_BLOCK_PTR_FOR_FN (cfun)) - flags |= EDGE_FALLTHRU; - - new_edge - = make_edge (new_bb, (basic_block) old_edge->dest->aux, flags); - new_edge->probability = old_edge->probability; - if (!id->reset_location) - new_edge->goto_locus = remap_location (locus, id); - } - - if (bb->index == ENTRY_BLOCK || bb->index == EXIT_BLOCK) - return false; - - /* When doing function splitting, we must decrease count of the return block - which was previously reachable by block we did not copy. */ - if (single_succ_p (bb) && single_succ_edge (bb)->dest->index == EXIT_BLOCK) - FOR_EACH_EDGE (old_edge, ei, bb->preds) - if (old_edge->src->index != ENTRY_BLOCK - && !old_edge->src->aux) - new_bb->count -= old_edge->count ().apply_scale (num, den); - - for (si = gsi_start_bb (new_bb); !gsi_end_p (si);) - { - gimple *copy_stmt; - bool can_throw, nonlocal_goto; - - copy_stmt = gsi_stmt (si); - if (!is_gimple_debug (copy_stmt)) - update_stmt (copy_stmt); - - /* Do this before the possible split_block. */ - gsi_next (&si); - - /* If this tree could throw an exception, there are two - cases where we need to add abnormal edge(s): the - tree wasn't in a region and there is a "current - region" in the caller; or the original tree had - EH edges. In both cases split the block after the tree, - and add abnormal edge(s) as needed; we need both - those from the callee and the caller. - We check whether the copy can throw, because the const - propagation can change an INDIRECT_REF which throws - into a COMPONENT_REF which doesn't. If the copy - can throw, the original could also throw. */ - can_throw = stmt_can_throw_internal (cfun, copy_stmt); - nonlocal_goto - = (stmt_can_make_abnormal_goto (copy_stmt) - && !computed_goto_p (copy_stmt)); - - if (can_throw || nonlocal_goto) - { - if (!gsi_end_p (si)) - { - while (!gsi_end_p (si) && is_gimple_debug (gsi_stmt (si))) - gsi_next (&si); - if (gsi_end_p (si)) - need_debug_cleanup = true; - } - if (!gsi_end_p (si)) - /* Note that bb's predecessor edges aren't necessarily - right at this point; split_block doesn't care. */ - { - edge e = split_block (new_bb, copy_stmt); - - new_bb = e->dest; - new_bb->aux = e->src->aux; - si = gsi_start_bb (new_bb); - } - } - - bool update_probs = false; - - if (gimple_code (copy_stmt) == GIMPLE_EH_DISPATCH) - { - make_eh_dispatch_edges (as_a <geh_dispatch *> (copy_stmt)); - update_probs = true; - } - else if (can_throw) - { - make_eh_edges (copy_stmt); - update_probs = true; - } - - /* EH edges may not match old edges. Copy as much as possible. */ - if (update_probs) - { - edge e; - edge_iterator ei; - basic_block copy_stmt_bb = gimple_bb (copy_stmt); - - FOR_EACH_EDGE (old_edge, ei, bb->succs) - if ((old_edge->flags & EDGE_EH) - && (e = find_edge (copy_stmt_bb, - (basic_block) old_edge->dest->aux)) - && (e->flags & EDGE_EH)) - e->probability = old_edge->probability; - - FOR_EACH_EDGE (e, ei, copy_stmt_bb->succs) - if (e->flags & EDGE_EH) - { - if (!e->probability.initialized_p ()) - e->probability = profile_probability::never (); - if (e->dest->index < id->add_clobbers_to_eh_landing_pads) - { - if (id->eh_landing_pad_dest == NULL) - id->eh_landing_pad_dest = e->dest; - else - gcc_assert (id->eh_landing_pad_dest == e->dest); - } - } - } - - - /* If the call we inline cannot make abnormal goto do not add - additional abnormal edges but only retain those already present - in the original function body. */ - if (abnormal_goto_dest == NULL) - nonlocal_goto = false; - if (nonlocal_goto) - { - basic_block copy_stmt_bb = gimple_bb (copy_stmt); - - if (get_abnormal_succ_dispatcher (copy_stmt_bb)) - nonlocal_goto = false; - /* ABNORMAL_DISPATCHER (1) is for longjmp/setjmp or nonlocal gotos - in OpenMP regions which aren't allowed to be left abnormally. - So, no need to add abnormal edge in that case. */ - else if (is_gimple_call (copy_stmt) - && gimple_call_internal_p (copy_stmt) - && (gimple_call_internal_fn (copy_stmt) - == IFN_ABNORMAL_DISPATCHER) - && gimple_call_arg (copy_stmt, 0) == boolean_true_node) - nonlocal_goto = false; - else - make_single_succ_edge (copy_stmt_bb, abnormal_goto_dest, - EDGE_ABNORMAL); - } - - if ((can_throw || nonlocal_goto) - && gimple_in_ssa_p (cfun)) - update_ssa_across_abnormal_edges (gimple_bb (copy_stmt), ret_bb, - can_throw, nonlocal_goto); - } - return need_debug_cleanup; -} - -/* Copy the PHIs. All blocks and edges are copied, some blocks - was possibly split and new outgoing EH edges inserted. - BB points to the block of original function and AUX pointers links - the original and newly copied blocks. */ - -static void -copy_phis_for_bb (basic_block bb, copy_body_data *id) -{ - basic_block const new_bb = (basic_block) bb->aux; - edge_iterator ei; - gphi *phi; - gphi_iterator si; - edge new_edge; - bool inserted = false; - - for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si)) - { - tree res, new_res; - gphi *new_phi; - - phi = si.phi (); - res = PHI_RESULT (phi); - new_res = res; - if (!virtual_operand_p (res) - && (!id->param_body_adjs - || !id->param_body_adjs->m_dead_stmts.contains (phi))) - { - walk_tree (&new_res, copy_tree_body_r, id, NULL); - if (EDGE_COUNT (new_bb->preds) == 0) - { - /* Technically we'd want a SSA_DEFAULT_DEF here... */ - SSA_NAME_DEF_STMT (new_res) = gimple_build_nop (); - } - else - { - new_phi = create_phi_node (new_res, new_bb); - FOR_EACH_EDGE (new_edge, ei, new_bb->preds) - { - edge old_edge = find_edge ((basic_block) new_edge->src->aux, - bb); - tree arg; - tree new_arg; - edge_iterator ei2; - location_t locus; - - /* When doing partial cloning, we allow PHIs on the entry - block as long as all the arguments are the same. - Find any input edge to see argument to copy. */ - if (!old_edge) - FOR_EACH_EDGE (old_edge, ei2, bb->preds) - if (!old_edge->src->aux) - break; - - arg = PHI_ARG_DEF_FROM_EDGE (phi, old_edge); - new_arg = arg; - walk_tree (&new_arg, copy_tree_body_r, id, NULL); - gcc_assert (new_arg); - /* With return slot optimization we can end up with - non-gimple (foo *)&this->m, fix that here. */ - if (TREE_CODE (new_arg) != SSA_NAME - && TREE_CODE (new_arg) != FUNCTION_DECL - && !is_gimple_val (new_arg)) - { - gimple_seq stmts = NULL; - new_arg = force_gimple_operand (new_arg, &stmts, true, - NULL); - gsi_insert_seq_on_edge (new_edge, stmts); - inserted = true; - } - locus = gimple_phi_arg_location_from_edge (phi, old_edge); - if (id->reset_location) - locus = input_location; - else - locus = remap_location (locus, id); - add_phi_arg (new_phi, new_arg, new_edge, locus); - } - } - } - } - - /* Commit the delayed edge insertions. */ - if (inserted) - FOR_EACH_EDGE (new_edge, ei, new_bb->preds) - gsi_commit_one_edge_insert (new_edge, NULL); -} - - -/* Wrapper for remap_decl so it can be used as a callback. */ - -static tree -remap_decl_1 (tree decl, void *data) -{ - return remap_decl (decl, (copy_body_data *) data); -} - -/* Build struct function and associated datastructures for the new clone - NEW_FNDECL to be build. CALLEE_FNDECL is the original. Function changes - the cfun to the function of new_fndecl (and current_function_decl too). */ - -static void -initialize_cfun (tree new_fndecl, tree callee_fndecl, profile_count count) -{ - struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl); - - if (!DECL_ARGUMENTS (new_fndecl)) - DECL_ARGUMENTS (new_fndecl) = DECL_ARGUMENTS (callee_fndecl); - if (!DECL_RESULT (new_fndecl)) - DECL_RESULT (new_fndecl) = DECL_RESULT (callee_fndecl); - - /* Register specific tree functions. */ - gimple_register_cfg_hooks (); - - /* Get clean struct function. */ - push_struct_function (new_fndecl); - - /* We will rebuild these, so just sanity check that they are empty. */ - gcc_assert (VALUE_HISTOGRAMS (cfun) == NULL); - gcc_assert (cfun->local_decls == NULL); - gcc_assert (cfun->cfg == NULL); - gcc_assert (cfun->decl == new_fndecl); - - /* Copy items we preserve during cloning. */ - cfun->static_chain_decl = src_cfun->static_chain_decl; - cfun->nonlocal_goto_save_area = src_cfun->nonlocal_goto_save_area; - cfun->function_end_locus = src_cfun->function_end_locus; - cfun->curr_properties = src_cfun->curr_properties; - cfun->last_verified = src_cfun->last_verified; - cfun->va_list_gpr_size = src_cfun->va_list_gpr_size; - cfun->va_list_fpr_size = src_cfun->va_list_fpr_size; - cfun->has_nonlocal_label = src_cfun->has_nonlocal_label; - cfun->calls_eh_return = src_cfun->calls_eh_return; - cfun->stdarg = src_cfun->stdarg; - cfun->after_inlining = src_cfun->after_inlining; - cfun->can_throw_non_call_exceptions - = src_cfun->can_throw_non_call_exceptions; - cfun->can_delete_dead_exceptions = src_cfun->can_delete_dead_exceptions; - cfun->returns_struct = src_cfun->returns_struct; - cfun->returns_pcc_struct = src_cfun->returns_pcc_struct; - - init_empty_tree_cfg (); - - profile_status_for_fn (cfun) = profile_status_for_fn (src_cfun); - - profile_count num = count; - profile_count den = ENTRY_BLOCK_PTR_FOR_FN (src_cfun)->count; - profile_count::adjust_for_ipa_scaling (&num, &den); - - ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = - ENTRY_BLOCK_PTR_FOR_FN (src_cfun)->count.apply_scale (count, - ENTRY_BLOCK_PTR_FOR_FN (src_cfun)->count); - EXIT_BLOCK_PTR_FOR_FN (cfun)->count = - EXIT_BLOCK_PTR_FOR_FN (src_cfun)->count.apply_scale (count, - ENTRY_BLOCK_PTR_FOR_FN (src_cfun)->count); - if (src_cfun->eh) - init_eh_for_function (); - - if (src_cfun->gimple_df) - { - init_tree_ssa (cfun); - cfun->gimple_df->in_ssa_p = src_cfun->gimple_df->in_ssa_p; - if (cfun->gimple_df->in_ssa_p) - init_ssa_operands (cfun); - } -} - -/* Helper function for copy_cfg_body. Move debug stmts from the end - of NEW_BB to the beginning of successor basic blocks when needed. If the - successor has multiple predecessors, reset them, otherwise keep - their value. */ - -static void -maybe_move_debug_stmts_to_successors (copy_body_data *id, basic_block new_bb) -{ - edge e; - edge_iterator ei; - gimple_stmt_iterator si = gsi_last_nondebug_bb (new_bb); - - if (gsi_end_p (si) - || gsi_one_before_end_p (si) - || !(stmt_can_throw_internal (cfun, gsi_stmt (si)) - || stmt_can_make_abnormal_goto (gsi_stmt (si)))) - return; - - FOR_EACH_EDGE (e, ei, new_bb->succs) - { - gimple_stmt_iterator ssi = gsi_last_bb (new_bb); - gimple_stmt_iterator dsi = gsi_after_labels (e->dest); - while (is_gimple_debug (gsi_stmt (ssi))) - { - gimple *stmt = gsi_stmt (ssi); - gdebug *new_stmt; - tree var; - tree value; - - /* For the last edge move the debug stmts instead of copying - them. */ - if (ei_one_before_end_p (ei)) - { - si = ssi; - gsi_prev (&ssi); - if (!single_pred_p (e->dest) && gimple_debug_bind_p (stmt)) - { - gimple_debug_bind_reset_value (stmt); - gimple_set_location (stmt, UNKNOWN_LOCATION); - } - gsi_remove (&si, false); - gsi_insert_before (&dsi, stmt, GSI_NEW_STMT); - continue; - } - - if (gimple_debug_bind_p (stmt)) - { - var = gimple_debug_bind_get_var (stmt); - if (single_pred_p (e->dest)) - { - value = gimple_debug_bind_get_value (stmt); - value = unshare_expr (value); - new_stmt = gimple_build_debug_bind (var, value, stmt); - } - else - new_stmt = gimple_build_debug_bind (var, NULL_TREE, NULL); - } - else if (gimple_debug_source_bind_p (stmt)) - { - var = gimple_debug_source_bind_get_var (stmt); - value = gimple_debug_source_bind_get_value (stmt); - new_stmt = gimple_build_debug_source_bind (var, value, stmt); - } - else if (gimple_debug_nonbind_marker_p (stmt)) - new_stmt = as_a <gdebug *> (gimple_copy (stmt)); - else - gcc_unreachable (); - gsi_insert_before (&dsi, new_stmt, GSI_NEW_STMT); - id->debug_stmts.safe_push (new_stmt); - gsi_prev (&ssi); - } - } -} - -/* Make a copy of the sub-loops of SRC_PARENT and place them - as siblings of DEST_PARENT. */ - -static void -copy_loops (copy_body_data *id, - class loop *dest_parent, class loop *src_parent) -{ - class loop *src_loop = src_parent->inner; - while (src_loop) - { - if (!id->blocks_to_copy - || bitmap_bit_p (id->blocks_to_copy, src_loop->header->index)) - { - class loop *dest_loop = alloc_loop (); - - /* Assign the new loop its header and latch and associate - those with the new loop. */ - dest_loop->header = (basic_block)src_loop->header->aux; - dest_loop->header->loop_father = dest_loop; - if (src_loop->latch != NULL) - { - dest_loop->latch = (basic_block)src_loop->latch->aux; - dest_loop->latch->loop_father = dest_loop; - } - - /* Copy loop meta-data. */ - copy_loop_info (src_loop, dest_loop); - if (dest_loop->unroll) - cfun->has_unroll = true; - if (dest_loop->force_vectorize) - cfun->has_force_vectorize_loops = true; - if (id->src_cfun->last_clique != 0) - dest_loop->owned_clique - = remap_dependence_clique (id, - src_loop->owned_clique - ? src_loop->owned_clique : 1); - - /* Finally place it into the loop array and the loop tree. */ - place_new_loop (cfun, dest_loop); - flow_loop_tree_node_add (dest_parent, dest_loop); - - if (src_loop->simduid) - { - dest_loop->simduid = remap_decl (src_loop->simduid, id); - cfun->has_simduid_loops = true; - } - - /* Recurse. */ - copy_loops (id, dest_loop, src_loop); - } - src_loop = src_loop->next; - } -} - -/* Call redirect_call_stmt_to_callee on all calls in BB. */ - -void -redirect_all_calls (copy_body_data * id, basic_block bb) -{ - gimple_stmt_iterator si; - gimple *last = last_stmt (bb); - for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si)) - { - gimple *stmt = gsi_stmt (si); - if (is_gimple_call (stmt)) - { - tree old_lhs = gimple_call_lhs (stmt); - struct cgraph_edge *edge = id->dst_node->get_edge (stmt); - if (edge) - { - gimple *new_stmt - = cgraph_edge::redirect_call_stmt_to_callee (edge); - /* If IPA-SRA transformation, run as part of edge redirection, - removed the LHS because it is unused, save it to - killed_new_ssa_names so that we can prune it from debug - statements. */ - if (old_lhs - && TREE_CODE (old_lhs) == SSA_NAME - && !gimple_call_lhs (new_stmt)) - { - if (!id->killed_new_ssa_names) - id->killed_new_ssa_names = new hash_set<tree> (16); - id->killed_new_ssa_names->add (old_lhs); - } - - if (stmt == last && id->call_stmt && maybe_clean_eh_stmt (stmt)) - gimple_purge_dead_eh_edges (bb); - } - } - } -} - -/* Make a copy of the body of FN so that it can be inserted inline in - another function. Walks FN via CFG, returns new fndecl. */ - -static tree -copy_cfg_body (copy_body_data * id, - basic_block entry_block_map, basic_block exit_block_map, - basic_block new_entry) -{ - tree callee_fndecl = id->src_fn; - /* Original cfun for the callee, doesn't change. */ - struct function *src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl); - struct function *cfun_to_copy; - basic_block bb; - tree new_fndecl = NULL; - bool need_debug_cleanup = false; - int last; - profile_count den = ENTRY_BLOCK_PTR_FOR_FN (src_cfun)->count; - profile_count num = entry_block_map->count; - - cfun_to_copy = id->src_cfun = DECL_STRUCT_FUNCTION (callee_fndecl); - - /* Register specific tree functions. */ - gimple_register_cfg_hooks (); - - /* If we are inlining just region of the function, make sure to connect - new entry to ENTRY_BLOCK_PTR_FOR_FN (cfun). Since new entry can be - part of loop, we must compute frequency and probability of - ENTRY_BLOCK_PTR_FOR_FN (cfun) based on the frequencies and - probabilities of edges incoming from nonduplicated region. */ - if (new_entry) - { - edge e; - edge_iterator ei; - den = profile_count::zero (); - - FOR_EACH_EDGE (e, ei, new_entry->preds) - if (!e->src->aux) - den += e->count (); - ENTRY_BLOCK_PTR_FOR_FN (cfun)->count = den; - } - - profile_count::adjust_for_ipa_scaling (&num, &den); - - /* Must have a CFG here at this point. */ - gcc_assert (ENTRY_BLOCK_PTR_FOR_FN - (DECL_STRUCT_FUNCTION (callee_fndecl))); - - - ENTRY_BLOCK_PTR_FOR_FN (cfun_to_copy)->aux = entry_block_map; - EXIT_BLOCK_PTR_FOR_FN (cfun_to_copy)->aux = exit_block_map; - entry_block_map->aux = ENTRY_BLOCK_PTR_FOR_FN (cfun_to_copy); - exit_block_map->aux = EXIT_BLOCK_PTR_FOR_FN (cfun_to_copy); - - /* Duplicate any exception-handling regions. */ - if (cfun->eh) - id->eh_map = duplicate_eh_regions (cfun_to_copy, NULL, id->eh_lp_nr, - remap_decl_1, id); - - /* Use aux pointers to map the original blocks to copy. */ - FOR_EACH_BB_FN (bb, cfun_to_copy) - if (!id->blocks_to_copy || bitmap_bit_p (id->blocks_to_copy, bb->index)) - { - basic_block new_bb = copy_bb (id, bb, num, den); - bb->aux = new_bb; - new_bb->aux = bb; - new_bb->loop_father = entry_block_map->loop_father; - } - - last = last_basic_block_for_fn (cfun); - - /* Now that we've duplicated the blocks, duplicate their edges. */ - basic_block abnormal_goto_dest = NULL; - if (id->call_stmt - && stmt_can_make_abnormal_goto (id->call_stmt)) - { - gimple_stmt_iterator gsi = gsi_for_stmt (id->call_stmt); - - bb = gimple_bb (id->call_stmt); - gsi_next (&gsi); - if (gsi_end_p (gsi)) - abnormal_goto_dest = get_abnormal_succ_dispatcher (bb); - } - FOR_ALL_BB_FN (bb, cfun_to_copy) - if (!id->blocks_to_copy - || (bb->index > 0 && bitmap_bit_p (id->blocks_to_copy, bb->index))) - need_debug_cleanup |= copy_edges_for_bb (bb, num, den, exit_block_map, - abnormal_goto_dest, id); - - if (id->eh_landing_pad_dest) - { - add_clobbers_to_eh_landing_pad (id); - id->eh_landing_pad_dest = NULL; - } - - if (new_entry) - { - edge e = make_edge (entry_block_map, (basic_block)new_entry->aux, - EDGE_FALLTHRU); - e->probability = profile_probability::always (); - } - - /* Duplicate the loop tree, if available and wanted. */ - if (loops_for_fn (src_cfun) != NULL - && current_loops != NULL) - { - copy_loops (id, entry_block_map->loop_father, - get_loop (src_cfun, 0)); - /* Defer to cfgcleanup to update loop-father fields of basic-blocks. */ - loops_state_set (LOOPS_NEED_FIXUP); - } - - /* If the loop tree in the source function needed fixup, mark the - destination loop tree for fixup, too. */ - if (loops_for_fn (src_cfun)->state & LOOPS_NEED_FIXUP) - loops_state_set (LOOPS_NEED_FIXUP); - - if (gimple_in_ssa_p (cfun)) - FOR_ALL_BB_FN (bb, cfun_to_copy) - if (!id->blocks_to_copy - || (bb->index > 0 && bitmap_bit_p (id->blocks_to_copy, bb->index))) - copy_phis_for_bb (bb, id); - - FOR_ALL_BB_FN (bb, cfun_to_copy) - if (bb->aux) - { - if (need_debug_cleanup - && bb->index != ENTRY_BLOCK - && bb->index != EXIT_BLOCK) - maybe_move_debug_stmts_to_successors (id, (basic_block) bb->aux); - /* Update call edge destinations. This cannot be done before loop - info is updated, because we may split basic blocks. */ - if (id->transform_call_graph_edges == CB_CGE_DUPLICATE - && bb->index != ENTRY_BLOCK - && bb->index != EXIT_BLOCK) - redirect_all_calls (id, (basic_block)bb->aux); - ((basic_block)bb->aux)->aux = NULL; - bb->aux = NULL; - } - - /* Zero out AUX fields of newly created block during EH edge - insertion. */ - for (; last < last_basic_block_for_fn (cfun); last++) - { - if (need_debug_cleanup) - maybe_move_debug_stmts_to_successors (id, - BASIC_BLOCK_FOR_FN (cfun, last)); - BASIC_BLOCK_FOR_FN (cfun, last)->aux = NULL; - /* Update call edge destinations. This cannot be done before loop - info is updated, because we may split basic blocks. */ - if (id->transform_call_graph_edges == CB_CGE_DUPLICATE) - redirect_all_calls (id, BASIC_BLOCK_FOR_FN (cfun, last)); - } - entry_block_map->aux = NULL; - exit_block_map->aux = NULL; - - if (id->eh_map) - { - delete id->eh_map; - id->eh_map = NULL; - } - if (id->dependence_map) - { - delete id->dependence_map; - id->dependence_map = NULL; - } - - return new_fndecl; -} - -/* Copy the debug STMT using ID. We deal with these statements in a - special way: if any variable in their VALUE expression wasn't - remapped yet, we won't remap it, because that would get decl uids - out of sync, causing codegen differences between -g and -g0. If - this arises, we drop the VALUE expression altogether. */ - -static void -copy_debug_stmt (gdebug *stmt, copy_body_data *id) -{ - tree t, *n; - struct walk_stmt_info wi; - - if (tree block = gimple_block (stmt)) - { - n = id->decl_map->get (block); - gimple_set_block (stmt, n ? *n : id->block); - } - - if (gimple_debug_nonbind_marker_p (stmt)) - { - if (id->call_stmt && !gimple_block (stmt)) - { - gimple_stmt_iterator gsi = gsi_for_stmt (stmt); - gsi_remove (&gsi, true); - } - return; - } - - /* Remap all the operands in COPY. */ - memset (&wi, 0, sizeof (wi)); - wi.info = id; - - processing_debug_stmt = 1; - - if (gimple_debug_source_bind_p (stmt)) - t = gimple_debug_source_bind_get_var (stmt); - else if (gimple_debug_bind_p (stmt)) - t = gimple_debug_bind_get_var (stmt); - else - gcc_unreachable (); - - if (TREE_CODE (t) == PARM_DECL - && id->debug_map - && (n = id->debug_map->get (t))) - { - gcc_assert (VAR_P (*n)); - t = *n; - } - else if (VAR_P (t) && !is_global_var (t) && !id->decl_map->get (t)) - /* T is a non-localized variable. */; - else - walk_tree (&t, remap_gimple_op_r, &wi, NULL); - - if (gimple_debug_bind_p (stmt)) - { - gimple_debug_bind_set_var (stmt, t); - - if (gimple_debug_bind_has_value_p (stmt)) - walk_tree (gimple_debug_bind_get_value_ptr (stmt), - remap_gimple_op_r, &wi, NULL); - - /* Punt if any decl couldn't be remapped. */ - if (processing_debug_stmt < 0) - gimple_debug_bind_reset_value (stmt); - } - else if (gimple_debug_source_bind_p (stmt)) - { - gimple_debug_source_bind_set_var (stmt, t); - /* When inlining and source bind refers to one of the optimized - away parameters, change the source bind into normal debug bind - referring to the corresponding DEBUG_EXPR_DECL that should have - been bound before the call stmt. */ - t = gimple_debug_source_bind_get_value (stmt); - if (t != NULL_TREE - && TREE_CODE (t) == PARM_DECL - && id->call_stmt) - { - vec<tree, va_gc> **debug_args = decl_debug_args_lookup (id->src_fn); - unsigned int i; - if (debug_args != NULL) - { - for (i = 0; i < vec_safe_length (*debug_args); i += 2) - if ((**debug_args)[i] == DECL_ORIGIN (t) - && TREE_CODE ((**debug_args)[i + 1]) == DEBUG_EXPR_DECL) - { - t = (**debug_args)[i + 1]; - stmt->subcode = GIMPLE_DEBUG_BIND; - gimple_debug_bind_set_value (stmt, t); - break; - } - } - } - if (gimple_debug_source_bind_p (stmt)) - walk_tree (gimple_debug_source_bind_get_value_ptr (stmt), - remap_gimple_op_r, &wi, NULL); - } - - processing_debug_stmt = 0; - - update_stmt (stmt); -} - -/* Process deferred debug stmts. In order to give values better odds - of being successfully remapped, we delay the processing of debug - stmts until all other stmts that might require remapping are - processed. */ - -static void -copy_debug_stmts (copy_body_data *id) -{ - if (!id->debug_stmts.exists ()) - return; - - for (gdebug *stmt : id->debug_stmts) - copy_debug_stmt (stmt, id); - - id->debug_stmts.release (); -} - -/* Make a copy of the body of SRC_FN so that it can be inserted inline in - another function. */ - -static tree -copy_tree_body (copy_body_data *id) -{ - tree fndecl = id->src_fn; - tree body = DECL_SAVED_TREE (fndecl); - - walk_tree (&body, copy_tree_body_r, id, NULL); - - return body; -} - -/* Make a copy of the body of FN so that it can be inserted inline in - another function. */ - -static tree -copy_body (copy_body_data *id, - basic_block entry_block_map, basic_block exit_block_map, - basic_block new_entry) -{ - tree fndecl = id->src_fn; - tree body; - - /* If this body has a CFG, walk CFG and copy. */ - gcc_assert (ENTRY_BLOCK_PTR_FOR_FN (DECL_STRUCT_FUNCTION (fndecl))); - body = copy_cfg_body (id, entry_block_map, exit_block_map, - new_entry); - copy_debug_stmts (id); - delete id->killed_new_ssa_names; - id->killed_new_ssa_names = NULL; - - return body; -} - -/* Return true if VALUE is an ADDR_EXPR of an automatic variable - defined in function FN, or of a data member thereof. */ - -static bool -self_inlining_addr_expr (tree value, tree fn) -{ - tree var; - - if (TREE_CODE (value) != ADDR_EXPR) - return false; - - var = get_base_address (TREE_OPERAND (value, 0)); - - return var && auto_var_in_fn_p (var, fn); -} - -/* Append to BB a debug annotation that binds VAR to VALUE, inheriting - lexical block and line number information from base_stmt, if given, - or from the last stmt of the block otherwise. */ - -static gimple * -insert_init_debug_bind (copy_body_data *id, - basic_block bb, tree var, tree value, - gimple *base_stmt) -{ - gimple *note; - gimple_stmt_iterator gsi; - tree tracked_var; - - if (!gimple_in_ssa_p (id->src_cfun)) - return NULL; - - if (!opt_for_fn (id->dst_fn, flag_var_tracking_assignments)) - return NULL; - - tracked_var = target_for_debug_bind (var); - if (!tracked_var) - return NULL; - - if (bb) - { - gsi = gsi_last_bb (bb); - if (!base_stmt && !gsi_end_p (gsi)) - base_stmt = gsi_stmt (gsi); - } - - note = gimple_build_debug_bind (tracked_var, - value == error_mark_node - ? NULL_TREE : unshare_expr (value), - base_stmt); - - if (bb) - { - if (!gsi_end_p (gsi)) - gsi_insert_after (&gsi, note, GSI_SAME_STMT); - else - gsi_insert_before (&gsi, note, GSI_SAME_STMT); - } - - return note; -} - -static void -insert_init_stmt (copy_body_data *id, basic_block bb, gimple *init_stmt) -{ - /* If VAR represents a zero-sized variable, it's possible that the - assignment statement may result in no gimple statements. */ - if (init_stmt) - { - gimple_stmt_iterator si = gsi_last_bb (bb); - - /* We can end up with init statements that store to a non-register - from a rhs with a conversion. Handle that here by forcing the - rhs into a temporary. gimple_regimplify_operands is not - prepared to do this for us. */ - if (!is_gimple_debug (init_stmt) - && !is_gimple_reg (gimple_assign_lhs (init_stmt)) - && is_gimple_reg_type (TREE_TYPE (gimple_assign_lhs (init_stmt))) - && gimple_assign_rhs_class (init_stmt) == GIMPLE_UNARY_RHS) - { - tree rhs = build1 (gimple_assign_rhs_code (init_stmt), - TREE_TYPE (gimple_assign_lhs (init_stmt)), - gimple_assign_rhs1 (init_stmt)); - rhs = force_gimple_operand_gsi (&si, rhs, true, NULL_TREE, false, - GSI_NEW_STMT); - gimple_assign_set_rhs_code (init_stmt, TREE_CODE (rhs)); - gimple_assign_set_rhs1 (init_stmt, rhs); - } - gsi_insert_after (&si, init_stmt, GSI_NEW_STMT); - if (!is_gimple_debug (init_stmt)) - { - gimple_regimplify_operands (init_stmt, &si); - - tree def = gimple_assign_lhs (init_stmt); - insert_init_debug_bind (id, bb, def, def, init_stmt); - } - } -} - -/* Deal with mismatched formal/actual parameters, in a rather brute-force way - if need be (which should only be necessary for invalid programs). Attempt - to convert VAL to TYPE and return the result if it is possible, just return - a zero constant of the given type if it fails. */ - -tree -force_value_to_type (tree type, tree value) -{ - /* If we can match up types by promotion/demotion do so. */ - if (fold_convertible_p (type, value)) - return fold_convert (type, value); - - /* ??? For valid programs we should not end up here. - Still if we end up with truly mismatched types here, fall back - to using a VIEW_CONVERT_EXPR or a literal zero to not leak invalid - GIMPLE to the following passes. */ - if (TREE_CODE (value) == WITH_SIZE_EXPR) - return error_mark_node; - else if (!is_gimple_reg_type (TREE_TYPE (value)) - || TYPE_SIZE (type) == TYPE_SIZE (TREE_TYPE (value))) - return fold_build1 (VIEW_CONVERT_EXPR, type, value); - else - return build_zero_cst (type); -} - -/* Initialize parameter P with VALUE. If needed, produce init statement - at the end of BB. When BB is NULL, we return init statement to be - output later. */ -static gimple * -setup_one_parameter (copy_body_data *id, tree p, tree value, tree fn, - basic_block bb, tree *vars) -{ - gimple *init_stmt = NULL; - tree var; - tree def = (gimple_in_ssa_p (cfun) - ? ssa_default_def (id->src_cfun, p) : NULL); - - /* Make an equivalent VAR_DECL. Note that we must NOT remap the type - here since the type of this decl must be visible to the calling - function. */ - var = copy_decl_to_var (p, id); - - /* Declare this new variable. */ - DECL_CHAIN (var) = *vars; - *vars = var; - - /* Make gimplifier happy about this variable. */ - DECL_SEEN_IN_BIND_EXPR_P (var) = 1; - - /* If the parameter is never assigned to, has no SSA_NAMEs created, - we would not need to create a new variable here at all, if it - weren't for debug info. Still, we can just use the argument - value. */ - if (TREE_READONLY (p) - && !TREE_ADDRESSABLE (p) - && value - && !TREE_SIDE_EFFECTS (value) - && !def) - { - /* We may produce non-gimple trees by adding NOPs or introduce invalid - sharing when the value is not constant or DECL. And we need to make - sure that it cannot be modified from another path in the callee. */ - if (((is_gimple_min_invariant (value) - /* When the parameter is used in a context that forces it to - not be a GIMPLE register avoid substituting something that - is not a decl there. */ - && ! DECL_NOT_GIMPLE_REG_P (p)) - || (DECL_P (value) && TREE_READONLY (value)) - || (auto_var_in_fn_p (value, id->dst_fn) - && !TREE_ADDRESSABLE (value))) - && useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value)) - /* We have to be very careful about ADDR_EXPR. Make sure - the base variable isn't a local variable of the inlined - function, e.g., when doing recursive inlining, direct or - mutually-recursive or whatever, which is why we don't - just test whether fn == current_function_decl. */ - && ! self_inlining_addr_expr (value, fn)) - { - insert_decl_map (id, p, value); - if (!id->debug_map) - id->debug_map = new hash_map<tree, tree>; - id->debug_map->put (p, var); - return insert_init_debug_bind (id, bb, var, value, NULL); - } - } - - /* Register the VAR_DECL as the equivalent for the PARM_DECL; - that way, when the PARM_DECL is encountered, it will be - automatically replaced by the VAR_DECL. */ - insert_decl_map (id, p, var); - - /* Even if P was TREE_READONLY, the new VAR should not be. In the original - code, we would have constructed a temporary, and then the function body - would have never changed the value of P. However, now, we will be - constructing VAR directly. Therefore, it must not be TREE_READONLY. */ - TREE_READONLY (var) = 0; - - tree rhs = value; - if (value - && value != error_mark_node - && !useless_type_conversion_p (TREE_TYPE (p), TREE_TYPE (value))) - rhs = force_value_to_type (TREE_TYPE (p), value); - - /* If there is no setup required and we are in SSA, take the easy route - replacing all SSA names representing the function parameter by the - SSA name passed to function. - - We need to construct map for the variable anyway as it might be used - in different SSA names when parameter is set in function. - - Do replacement at -O0 for const arguments replaced by constant. - This is important for builtin_constant_p and other construct requiring - constant argument to be visible in inlined function body. */ - if (gimple_in_ssa_p (cfun) && rhs && def && is_gimple_reg (p) - && (optimize - || (TREE_READONLY (p) - && is_gimple_min_invariant (rhs))) - && (TREE_CODE (rhs) == SSA_NAME - || is_gimple_min_invariant (rhs)) - && !SSA_NAME_OCCURS_IN_ABNORMAL_PHI (def)) - { - insert_decl_map (id, def, rhs); - return insert_init_debug_bind (id, bb, var, rhs, NULL); - } - - /* If the value of argument is never used, don't care about initializing - it. */ - if (optimize && gimple_in_ssa_p (cfun) && !def && is_gimple_reg (p)) - { - gcc_assert (!value || !TREE_SIDE_EFFECTS (value)); - return insert_init_debug_bind (id, bb, var, rhs, NULL); - } - - /* Initialize this VAR_DECL from the equivalent argument. Convert - the argument to the proper type in case it was promoted. */ - if (value) - { - if (rhs == error_mark_node) - { - insert_decl_map (id, p, var); - return insert_init_debug_bind (id, bb, var, rhs, NULL); - } - - STRIP_USELESS_TYPE_CONVERSION (rhs); - - /* If we are in SSA form properly remap the default definition - or assign to a dummy SSA name if the parameter is unused and - we are not optimizing. */ - if (gimple_in_ssa_p (cfun) && is_gimple_reg (p)) - { - if (def) - { - def = remap_ssa_name (def, id); - init_stmt = gimple_build_assign (def, rhs); - SSA_NAME_IS_DEFAULT_DEF (def) = 0; - set_ssa_default_def (cfun, var, NULL); - } - else if (!optimize) - { - def = make_ssa_name (var); - init_stmt = gimple_build_assign (def, rhs); - } - } - else if (!is_empty_type (TREE_TYPE (var))) - init_stmt = gimple_build_assign (var, rhs); - - if (bb && init_stmt) - insert_init_stmt (id, bb, init_stmt); - } - return init_stmt; -} - -/* Generate code to initialize the parameters of the function at the - top of the stack in ID from the GIMPLE_CALL STMT. */ - -static void -initialize_inlined_parameters (copy_body_data *id, gimple *stmt, - tree fn, basic_block bb) -{ - tree parms; - size_t i; - tree p; - tree vars = NULL_TREE; - tree static_chain = gimple_call_chain (stmt); - - /* Figure out what the parameters are. */ - parms = DECL_ARGUMENTS (fn); - - /* Loop through the parameter declarations, replacing each with an - equivalent VAR_DECL, appropriately initialized. */ - for (p = parms, i = 0; p; p = DECL_CHAIN (p), i++) - { - tree val; - val = i < gimple_call_num_args (stmt) ? gimple_call_arg (stmt, i) : NULL; - setup_one_parameter (id, p, val, fn, bb, &vars); - } - /* After remapping parameters remap their types. This has to be done - in a second loop over all parameters to appropriately remap - variable sized arrays when the size is specified in a - parameter following the array. */ - for (p = parms, i = 0; p; p = DECL_CHAIN (p), i++) - { - tree *varp = id->decl_map->get (p); - if (varp && VAR_P (*varp)) - { - tree def = (gimple_in_ssa_p (cfun) && is_gimple_reg (p) - ? ssa_default_def (id->src_cfun, p) : NULL); - tree var = *varp; - TREE_TYPE (var) = remap_type (TREE_TYPE (var), id); - /* Also remap the default definition if it was remapped - to the default definition of the parameter replacement - by the parameter setup. */ - if (def) - { - tree *defp = id->decl_map->get (def); - if (defp - && TREE_CODE (*defp) == SSA_NAME - && SSA_NAME_VAR (*defp) == var) - TREE_TYPE (*defp) = TREE_TYPE (var); - } - } - } - - /* Initialize the static chain. */ - p = DECL_STRUCT_FUNCTION (fn)->static_chain_decl; - gcc_assert (fn != current_function_decl); - if (p) - { - /* No static chain? Seems like a bug in tree-nested.c. */ - gcc_assert (static_chain); - - setup_one_parameter (id, p, static_chain, fn, bb, &vars); - } - - declare_inline_vars (id->block, vars); -} - - -/* Declare a return variable to replace the RESULT_DECL for the - function we are calling. An appropriate DECL_STMT is returned. - The USE_STMT is filled to contain a use of the declaration to - indicate the return value of the function. - - RETURN_SLOT, if non-null is place where to store the result. It - is set only for CALL_EXPR_RETURN_SLOT_OPT. MODIFY_DEST, if non-null, - was the LHS of the MODIFY_EXPR to which this call is the RHS. - - The return value is a (possibly null) value that holds the result - as seen by the caller. */ - -static tree -declare_return_variable (copy_body_data *id, tree return_slot, tree modify_dest, - basic_block entry_bb) -{ - tree callee = id->src_fn; - tree result = DECL_RESULT (callee); - tree callee_type = TREE_TYPE (result); - tree caller_type; - tree var, use; - - /* Handle type-mismatches in the function declaration return type - vs. the call expression. */ - if (modify_dest) - caller_type = TREE_TYPE (modify_dest); - else if (return_slot) - caller_type = TREE_TYPE (return_slot); - else /* No LHS on the call. */ - caller_type = TREE_TYPE (TREE_TYPE (callee)); - - /* We don't need to do anything for functions that don't return anything. */ - if (VOID_TYPE_P (callee_type)) - return NULL_TREE; - - /* If there was a return slot, then the return value is the - dereferenced address of that object. */ - if (return_slot) - { - /* The front end shouldn't have used both return_slot and - a modify expression. */ - gcc_assert (!modify_dest); - if (DECL_BY_REFERENCE (result)) - { - tree return_slot_addr = build_fold_addr_expr (return_slot); - STRIP_USELESS_TYPE_CONVERSION (return_slot_addr); - - /* We are going to construct *&return_slot and we can't do that - for variables believed to be not addressable. - - FIXME: This check possibly can match, because values returned - via return slot optimization are not believed to have address - taken by alias analysis. */ - gcc_assert (TREE_CODE (return_slot) != SSA_NAME); - var = return_slot_addr; - mark_addressable (return_slot); - } - else - { - var = return_slot; - gcc_assert (TREE_CODE (var) != SSA_NAME); - if (TREE_ADDRESSABLE (result)) - mark_addressable (var); - } - if (DECL_NOT_GIMPLE_REG_P (result) - && DECL_P (var)) - DECL_NOT_GIMPLE_REG_P (var) = 1; - - if (!useless_type_conversion_p (callee_type, caller_type)) - var = build1 (VIEW_CONVERT_EXPR, callee_type, var); - - use = NULL; - goto done; - } - - /* All types requiring non-trivial constructors should have been handled. */ - gcc_assert (!TREE_ADDRESSABLE (callee_type)); - - /* Attempt to avoid creating a new temporary variable. */ - if (modify_dest - && TREE_CODE (modify_dest) != SSA_NAME) - { - bool use_it = false; - - /* We can't use MODIFY_DEST if there's type promotion involved. */ - if (!useless_type_conversion_p (callee_type, caller_type)) - use_it = false; - - /* ??? If we're assigning to a variable sized type, then we must - reuse the destination variable, because we've no good way to - create variable sized temporaries at this point. */ - else if (!poly_int_tree_p (TYPE_SIZE_UNIT (caller_type))) - use_it = true; - - /* If the callee cannot possibly modify MODIFY_DEST, then we can - reuse it as the result of the call directly. Don't do this if - it would promote MODIFY_DEST to addressable. */ - else if (TREE_ADDRESSABLE (result)) - use_it = false; - else - { - tree base_m = get_base_address (modify_dest); - - /* If the base isn't a decl, then it's a pointer, and we don't - know where that's going to go. */ - if (!DECL_P (base_m)) - use_it = false; - else if (is_global_var (base_m)) - use_it = false; - else if (DECL_NOT_GIMPLE_REG_P (result) - && !DECL_NOT_GIMPLE_REG_P (base_m)) - use_it = false; - else if (!TREE_ADDRESSABLE (base_m)) - use_it = true; - } - - if (use_it) - { - var = modify_dest; - use = NULL; - goto done; - } - } - - gcc_assert (poly_int_tree_p (TYPE_SIZE_UNIT (callee_type))); - - var = copy_result_decl_to_var (result, id); - DECL_SEEN_IN_BIND_EXPR_P (var) = 1; - - /* Do not have the rest of GCC warn about this variable as it should - not be visible to the user. */ - suppress_warning (var /* OPT_Wuninitialized? */); - - declare_inline_vars (id->block, var); - - /* Build the use expr. If the return type of the function was - promoted, convert it back to the expected type. */ - use = var; - if (!useless_type_conversion_p (caller_type, TREE_TYPE (var))) - { - /* If we can match up types by promotion/demotion do so. */ - if (fold_convertible_p (caller_type, var)) - use = fold_convert (caller_type, var); - else - { - /* ??? For valid programs we should not end up here. - Still if we end up with truly mismatched types here, fall back - to using a MEM_REF to not leak invalid GIMPLE to the following - passes. */ - /* Prevent var from being written into SSA form. */ - if (is_gimple_reg_type (TREE_TYPE (var))) - DECL_NOT_GIMPLE_REG_P (var) = true; - use = fold_build2 (MEM_REF, caller_type, - build_fold_addr_expr (var), - build_int_cst (ptr_type_node, 0)); - } - } - - STRIP_USELESS_TYPE_CONVERSION (use); - - if (DECL_BY_REFERENCE (result)) - { - TREE_ADDRESSABLE (var) = 1; - var = build_fold_addr_expr (var); - } - - done: - /* Register the VAR_DECL as the equivalent for the RESULT_DECL; that - way, when the RESULT_DECL is encountered, it will be - automatically replaced by the VAR_DECL. - - When returning by reference, ensure that RESULT_DECL remaps to - gimple_val. */ - if (DECL_BY_REFERENCE (result) - && !is_gimple_val (var)) - { - tree temp = create_tmp_var (TREE_TYPE (result), "retvalptr"); - insert_decl_map (id, result, temp); - /* When RESULT_DECL is in SSA form, we need to remap and initialize - it's default_def SSA_NAME. */ - if (gimple_in_ssa_p (id->src_cfun) - && is_gimple_reg (result)) - { - temp = make_ssa_name (temp); - insert_decl_map (id, ssa_default_def (id->src_cfun, result), temp); - } - insert_init_stmt (id, entry_bb, gimple_build_assign (temp, var)); - } - else - insert_decl_map (id, result, var); - - /* Remember this so we can ignore it in remap_decls. */ - id->retvar = var; - return use; -} - -/* Determine if the function can be copied. If so return NULL. If - not return a string describng the reason for failure. */ - -const char * -copy_forbidden (struct function *fun) -{ - const char *reason = fun->cannot_be_copied_reason; - - /* Only examine the function once. */ - if (fun->cannot_be_copied_set) - return reason; - - /* We cannot copy a function that receives a non-local goto - because we cannot remap the destination label used in the - function that is performing the non-local goto. */ - /* ??? Actually, this should be possible, if we work at it. - No doubt there's just a handful of places that simply - assume it doesn't happen and don't substitute properly. */ - if (fun->has_nonlocal_label) - { - reason = G_("function %q+F can never be copied " - "because it receives a non-local goto"); - goto fail; - } - - if (fun->has_forced_label_in_static) - { - reason = G_("function %q+F can never be copied because it saves " - "address of local label in a static variable"); - goto fail; - } - - fail: - fun->cannot_be_copied_reason = reason; - fun->cannot_be_copied_set = true; - return reason; -} - - -static const char *inline_forbidden_reason; - -/* A callback for walk_gimple_seq to handle statements. Returns non-null - iff a function cannot be inlined. Also sets the reason why. */ - -static tree -inline_forbidden_p_stmt (gimple_stmt_iterator *gsi, bool *handled_ops_p, - struct walk_stmt_info *wip) -{ - tree fn = (tree) wip->info; - tree t; - gimple *stmt = gsi_stmt (*gsi); - - switch (gimple_code (stmt)) - { - case GIMPLE_CALL: - /* Refuse to inline alloca call unless user explicitly forced so as - this may change program's memory overhead drastically when the - function using alloca is called in loop. In GCC present in - SPEC2000 inlining into schedule_block cause it to require 2GB of - RAM instead of 256MB. Don't do so for alloca calls emitted for - VLA objects as those can't cause unbounded growth (they're always - wrapped inside stack_save/stack_restore regions. */ - if (gimple_maybe_alloca_call_p (stmt) - && !gimple_call_alloca_for_var_p (as_a <gcall *> (stmt)) - && !lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn))) - { - inline_forbidden_reason - = G_("function %q+F can never be inlined because it uses " - "alloca (override using the always_inline attribute)"); - *handled_ops_p = true; - return fn; - } - - t = gimple_call_fndecl (stmt); - if (t == NULL_TREE) - break; - - /* We cannot inline functions that call setjmp. */ - if (setjmp_call_p (t)) - { - inline_forbidden_reason - = G_("function %q+F can never be inlined because it uses setjmp"); - *handled_ops_p = true; - return t; - } - - if (DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL) - switch (DECL_FUNCTION_CODE (t)) - { - /* We cannot inline functions that take a variable number of - arguments. */ - case BUILT_IN_VA_START: - case BUILT_IN_NEXT_ARG: - case BUILT_IN_VA_END: - inline_forbidden_reason - = G_("function %q+F can never be inlined because it " - "uses variable argument lists"); - *handled_ops_p = true; - return t; - - case BUILT_IN_LONGJMP: - /* We can't inline functions that call __builtin_longjmp at - all. The non-local goto machinery really requires the - destination be in a different function. If we allow the - function calling __builtin_longjmp to be inlined into the - function calling __builtin_setjmp, Things will Go Awry. */ - inline_forbidden_reason - = G_("function %q+F can never be inlined because " - "it uses setjmp-longjmp exception handling"); - *handled_ops_p = true; - return t; - - case BUILT_IN_NONLOCAL_GOTO: - /* Similarly. */ - inline_forbidden_reason - = G_("function %q+F can never be inlined because " - "it uses non-local goto"); - *handled_ops_p = true; - return t; - - case BUILT_IN_RETURN: - case BUILT_IN_APPLY_ARGS: - /* If a __builtin_apply_args caller would be inlined, - it would be saving arguments of the function it has - been inlined into. Similarly __builtin_return would - return from the function the inline has been inlined into. */ - inline_forbidden_reason - = G_("function %q+F can never be inlined because " - "it uses %<__builtin_return%> or %<__builtin_apply_args%>"); - *handled_ops_p = true; - return t; - - default: - break; - } - break; - - case GIMPLE_GOTO: - t = gimple_goto_dest (stmt); - - /* We will not inline a function which uses computed goto. The - addresses of its local labels, which may be tucked into - global storage, are of course not constant across - instantiations, which causes unexpected behavior. */ - if (TREE_CODE (t) != LABEL_DECL) - { - inline_forbidden_reason - = G_("function %q+F can never be inlined " - "because it contains a computed goto"); - *handled_ops_p = true; - return t; - } - break; - - default: - break; - } - - *handled_ops_p = false; - return NULL_TREE; -} - -/* Return true if FNDECL is a function that cannot be inlined into - another one. */ - -static bool -inline_forbidden_p (tree fndecl) -{ - struct function *fun = DECL_STRUCT_FUNCTION (fndecl); - struct walk_stmt_info wi; - basic_block bb; - bool forbidden_p = false; - - /* First check for shared reasons not to copy the code. */ - inline_forbidden_reason = copy_forbidden (fun); - if (inline_forbidden_reason != NULL) - return true; - - /* Next, walk the statements of the function looking for - constraucts we can't handle, or are non-optimal for inlining. */ - hash_set<tree> visited_nodes; - memset (&wi, 0, sizeof (wi)); - wi.info = (void *) fndecl; - wi.pset = &visited_nodes; - - /* We cannot inline a function with a variable-sized parameter because we - cannot materialize a temporary of such a type in the caller if need be. - Note that the return case is not symmetrical because we can guarantee - that a temporary is not needed by means of CALL_EXPR_RETURN_SLOT_OPT. */ - for (tree parm = DECL_ARGUMENTS (fndecl); parm; parm = DECL_CHAIN (parm)) - if (!poly_int_tree_p (DECL_SIZE (parm))) - { - inline_forbidden_reason - = G_("function %q+F can never be inlined because " - "it has a VLA argument"); - return true; - } - - FOR_EACH_BB_FN (bb, fun) - { - gimple *ret; - gimple_seq seq = bb_seq (bb); - ret = walk_gimple_seq (seq, inline_forbidden_p_stmt, NULL, &wi); - forbidden_p = (ret != NULL); - if (forbidden_p) - break; - } - - return forbidden_p; -} - -/* Return false if the function FNDECL cannot be inlined on account of its - attributes, true otherwise. */ -static bool -function_attribute_inlinable_p (const_tree fndecl) -{ - if (targetm.attribute_table) - { - const_tree a; - - for (a = DECL_ATTRIBUTES (fndecl); a; a = TREE_CHAIN (a)) - { - const_tree name = get_attribute_name (a); - int i; - - for (i = 0; targetm.attribute_table[i].name != NULL; i++) - if (is_attribute_p (targetm.attribute_table[i].name, name)) - return targetm.function_attribute_inlinable_p (fndecl); - } - } - - return true; -} - -/* Returns nonzero if FN is a function that does not have any - fundamental inline blocking properties. */ - -bool -tree_inlinable_function_p (tree fn) -{ - bool inlinable = true; - bool do_warning; - tree always_inline; - - /* If we've already decided this function shouldn't be inlined, - there's no need to check again. */ - if (DECL_UNINLINABLE (fn)) - return false; - - /* We only warn for functions declared `inline' by the user. */ - do_warning = (opt_for_fn (fn, warn_inline) - && DECL_DECLARED_INLINE_P (fn) - && !DECL_NO_INLINE_WARNING_P (fn) - && !DECL_IN_SYSTEM_HEADER (fn)); - - always_inline = lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)); - - if (flag_no_inline - && always_inline == NULL) - { - if (do_warning) - warning (OPT_Winline, "function %q+F can never be inlined because it " - "is suppressed using %<-fno-inline%>", fn); - inlinable = false; - } - - else if (!function_attribute_inlinable_p (fn)) - { - if (do_warning) - warning (OPT_Winline, "function %q+F can never be inlined because it " - "uses attributes conflicting with inlining", fn); - inlinable = false; - } - - else if (inline_forbidden_p (fn)) - { - /* See if we should warn about uninlinable functions. Previously, - some of these warnings would be issued while trying to expand - the function inline, but that would cause multiple warnings - about functions that would for example call alloca. But since - this a property of the function, just one warning is enough. - As a bonus we can now give more details about the reason why a - function is not inlinable. */ - if (always_inline) - error (inline_forbidden_reason, fn); - else if (do_warning) - warning (OPT_Winline, inline_forbidden_reason, fn); - - inlinable = false; - } - - /* Squirrel away the result so that we don't have to check again. */ - DECL_UNINLINABLE (fn) = !inlinable; - - return inlinable; -} - -/* Estimate the cost of a memory move of type TYPE. Use machine dependent - word size and take possible memcpy call into account and return - cost based on whether optimizing for size or speed according to SPEED_P. */ - -int -estimate_move_cost (tree type, bool ARG_UNUSED (speed_p)) -{ - HOST_WIDE_INT size; - - gcc_assert (!VOID_TYPE_P (type)); - - if (TREE_CODE (type) == VECTOR_TYPE) - { - scalar_mode inner = SCALAR_TYPE_MODE (TREE_TYPE (type)); - machine_mode simd = targetm.vectorize.preferred_simd_mode (inner); - int orig_mode_size - = estimated_poly_value (GET_MODE_SIZE (TYPE_MODE (type))); - int simd_mode_size = estimated_poly_value (GET_MODE_SIZE (simd)); - return ((orig_mode_size + simd_mode_size - 1) - / simd_mode_size); - } - - size = int_size_in_bytes (type); - - if (size < 0 || size > MOVE_MAX_PIECES * MOVE_RATIO (speed_p)) - /* Cost of a memcpy call, 3 arguments and the call. */ - return 4; - else - return ((size + MOVE_MAX_PIECES - 1) / MOVE_MAX_PIECES); -} - -/* Returns cost of operation CODE, according to WEIGHTS */ - -static int -estimate_operator_cost (enum tree_code code, eni_weights *weights, - tree op1 ATTRIBUTE_UNUSED, tree op2) -{ - switch (code) - { - /* These are "free" conversions, or their presumed cost - is folded into other operations. */ - case RANGE_EXPR: - CASE_CONVERT: - case COMPLEX_EXPR: - case PAREN_EXPR: - case VIEW_CONVERT_EXPR: - return 0; - - /* Assign cost of 1 to usual operations. - ??? We may consider mapping RTL costs to this. */ - case COND_EXPR: - case VEC_COND_EXPR: - case VEC_PERM_EXPR: - - case PLUS_EXPR: - case POINTER_PLUS_EXPR: - case POINTER_DIFF_EXPR: - case MINUS_EXPR: - case MULT_EXPR: - case MULT_HIGHPART_EXPR: - - case ADDR_SPACE_CONVERT_EXPR: - case FIXED_CONVERT_EXPR: - case FIX_TRUNC_EXPR: - - case NEGATE_EXPR: - case FLOAT_EXPR: - case MIN_EXPR: - case MAX_EXPR: - case ABS_EXPR: - case ABSU_EXPR: - - case LSHIFT_EXPR: - case RSHIFT_EXPR: - case LROTATE_EXPR: - case RROTATE_EXPR: - - case BIT_IOR_EXPR: - case BIT_XOR_EXPR: - case BIT_AND_EXPR: - case BIT_NOT_EXPR: - - case TRUTH_ANDIF_EXPR: - case TRUTH_ORIF_EXPR: - case TRUTH_AND_EXPR: - case TRUTH_OR_EXPR: - case TRUTH_XOR_EXPR: - case TRUTH_NOT_EXPR: - - case LT_EXPR: - case LE_EXPR: - case GT_EXPR: - case GE_EXPR: - case EQ_EXPR: - case NE_EXPR: - case ORDERED_EXPR: - case UNORDERED_EXPR: - - case UNLT_EXPR: - case UNLE_EXPR: - case UNGT_EXPR: - case UNGE_EXPR: - case UNEQ_EXPR: - case LTGT_EXPR: - - case CONJ_EXPR: - - case PREDECREMENT_EXPR: - case PREINCREMENT_EXPR: - case POSTDECREMENT_EXPR: - case POSTINCREMENT_EXPR: - - case REALIGN_LOAD_EXPR: - - case WIDEN_PLUS_EXPR: - case WIDEN_MINUS_EXPR: - case WIDEN_SUM_EXPR: - case WIDEN_MULT_EXPR: - case DOT_PROD_EXPR: - case SAD_EXPR: - case WIDEN_MULT_PLUS_EXPR: - case WIDEN_MULT_MINUS_EXPR: - case WIDEN_LSHIFT_EXPR: - - case VEC_WIDEN_PLUS_HI_EXPR: - case VEC_WIDEN_PLUS_LO_EXPR: - case VEC_WIDEN_MINUS_HI_EXPR: - case VEC_WIDEN_MINUS_LO_EXPR: - case VEC_WIDEN_MULT_HI_EXPR: - case VEC_WIDEN_MULT_LO_EXPR: - case VEC_WIDEN_MULT_EVEN_EXPR: - case VEC_WIDEN_MULT_ODD_EXPR: - case VEC_UNPACK_HI_EXPR: - case VEC_UNPACK_LO_EXPR: - case VEC_UNPACK_FLOAT_HI_EXPR: - case VEC_UNPACK_FLOAT_LO_EXPR: - case VEC_UNPACK_FIX_TRUNC_HI_EXPR: - case VEC_UNPACK_FIX_TRUNC_LO_EXPR: - case VEC_PACK_TRUNC_EXPR: - case VEC_PACK_SAT_EXPR: - case VEC_PACK_FIX_TRUNC_EXPR: - case VEC_PACK_FLOAT_EXPR: - case VEC_WIDEN_LSHIFT_HI_EXPR: - case VEC_WIDEN_LSHIFT_LO_EXPR: - case VEC_DUPLICATE_EXPR: - case VEC_SERIES_EXPR: - - return 1; - - /* Few special cases of expensive operations. This is useful - to avoid inlining on functions having too many of these. */ - case TRUNC_DIV_EXPR: - case CEIL_DIV_EXPR: - case FLOOR_DIV_EXPR: - case ROUND_DIV_EXPR: - case EXACT_DIV_EXPR: - case TRUNC_MOD_EXPR: - case CEIL_MOD_EXPR: - case FLOOR_MOD_EXPR: - case ROUND_MOD_EXPR: - case RDIV_EXPR: - if (TREE_CODE (op2) != INTEGER_CST) - return weights->div_mod_cost; - return 1; - - /* Bit-field insertion needs several shift and mask operations. */ - case BIT_INSERT_EXPR: - return 3; - - default: - /* We expect a copy assignment with no operator. */ - gcc_assert (get_gimple_rhs_class (code) == GIMPLE_SINGLE_RHS); - return 0; - } -} - - -/* Estimate number of instructions that will be created by expanding - the statements in the statement sequence STMTS. - WEIGHTS contains weights attributed to various constructs. */ - -int -estimate_num_insns_seq (gimple_seq stmts, eni_weights *weights) -{ - int cost; - gimple_stmt_iterator gsi; - - cost = 0; - for (gsi = gsi_start (stmts); !gsi_end_p (gsi); gsi_next (&gsi)) - cost += estimate_num_insns (gsi_stmt (gsi), weights); - - return cost; -} - - -/* Estimate number of instructions that will be created by expanding STMT. - WEIGHTS contains weights attributed to various constructs. */ - -int -estimate_num_insns (gimple *stmt, eni_weights *weights) -{ - unsigned cost, i; - enum gimple_code code = gimple_code (stmt); - tree lhs; - tree rhs; - - switch (code) - { - case GIMPLE_ASSIGN: - /* Try to estimate the cost of assignments. We have three cases to - deal with: - 1) Simple assignments to registers; - 2) Stores to things that must live in memory. This includes - "normal" stores to scalars, but also assignments of large - structures, or constructors of big arrays; - - Let us look at the first two cases, assuming we have "a = b + C": - <GIMPLE_ASSIGN <var_decl "a"> - <plus_expr <var_decl "b"> <constant C>> - If "a" is a GIMPLE register, the assignment to it is free on almost - any target, because "a" usually ends up in a real register. Hence - the only cost of this expression comes from the PLUS_EXPR, and we - can ignore the GIMPLE_ASSIGN. - If "a" is not a GIMPLE register, the assignment to "a" will most - likely be a real store, so the cost of the GIMPLE_ASSIGN is the cost - of moving something into "a", which we compute using the function - estimate_move_cost. */ - if (gimple_clobber_p (stmt)) - return 0; /* ={v} {CLOBBER} stmt expands to nothing. */ - - lhs = gimple_assign_lhs (stmt); - rhs = gimple_assign_rhs1 (stmt); - - cost = 0; - - /* Account for the cost of moving to / from memory. */ - if (gimple_store_p (stmt)) - cost += estimate_move_cost (TREE_TYPE (lhs), weights->time_based); - if (gimple_assign_load_p (stmt)) - cost += estimate_move_cost (TREE_TYPE (rhs), weights->time_based); - - cost += estimate_operator_cost (gimple_assign_rhs_code (stmt), weights, - gimple_assign_rhs1 (stmt), - get_gimple_rhs_class (gimple_assign_rhs_code (stmt)) - == GIMPLE_BINARY_RHS - ? gimple_assign_rhs2 (stmt) : NULL); - break; - - case GIMPLE_COND: - cost = 1 + estimate_operator_cost (gimple_cond_code (stmt), weights, - gimple_op (stmt, 0), - gimple_op (stmt, 1)); - break; - - case GIMPLE_SWITCH: - { - gswitch *switch_stmt = as_a <gswitch *> (stmt); - /* Take into account cost of the switch + guess 2 conditional jumps for - each case label. - - TODO: once the switch expansion logic is sufficiently separated, we can - do better job on estimating cost of the switch. */ - if (weights->time_based) - cost = floor_log2 (gimple_switch_num_labels (switch_stmt)) * 2; - else - cost = gimple_switch_num_labels (switch_stmt) * 2; - } - break; - - case GIMPLE_CALL: - { - tree decl; - - if (gimple_call_internal_p (stmt)) - return 0; - else if ((decl = gimple_call_fndecl (stmt)) - && fndecl_built_in_p (decl)) - { - /* Do not special case builtins where we see the body. - This just confuse inliner. */ - struct cgraph_node *node; - if ((node = cgraph_node::get (decl)) - && node->definition) - ; - /* For buitins that are likely expanded to nothing or - inlined do not account operand costs. */ - else if (is_simple_builtin (decl)) - return 0; - else if (is_inexpensive_builtin (decl)) - return weights->target_builtin_call_cost; - else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL)) - { - /* We canonicalize x * x to pow (x, 2.0) with -ffast-math, so - specialize the cheap expansion we do here. - ??? This asks for a more general solution. */ - switch (DECL_FUNCTION_CODE (decl)) - { - case BUILT_IN_POW: - case BUILT_IN_POWF: - case BUILT_IN_POWL: - if (TREE_CODE (gimple_call_arg (stmt, 1)) == REAL_CST - && (real_equal - (&TREE_REAL_CST (gimple_call_arg (stmt, 1)), - &dconst2))) - return estimate_operator_cost - (MULT_EXPR, weights, gimple_call_arg (stmt, 0), - gimple_call_arg (stmt, 0)); - break; - - default: - break; - } - } - } - - cost = decl ? weights->call_cost : weights->indirect_call_cost; - if (gimple_call_lhs (stmt)) - cost += estimate_move_cost (TREE_TYPE (gimple_call_lhs (stmt)), - weights->time_based); - for (i = 0; i < gimple_call_num_args (stmt); i++) - { - tree arg = gimple_call_arg (stmt, i); - cost += estimate_move_cost (TREE_TYPE (arg), - weights->time_based); - } - break; - } - - case GIMPLE_RETURN: - return weights->return_cost; - - case GIMPLE_GOTO: - case GIMPLE_LABEL: - case GIMPLE_NOP: - case GIMPLE_PHI: - case GIMPLE_PREDICT: - case GIMPLE_DEBUG: - return 0; - - case GIMPLE_ASM: - { - int count = asm_str_count (gimple_asm_string (as_a <gasm *> (stmt))); - /* 1000 means infinity. This avoids overflows later - with very long asm statements. */ - if (count > 1000) - count = 1000; - /* If this asm is asm inline, count anything as minimum size. */ - if (gimple_asm_inline_p (as_a <gasm *> (stmt))) - count = MIN (1, count); - return MAX (1, count); - } - - case GIMPLE_RESX: - /* This is either going to be an external function call with one - argument, or two register copy statements plus a goto. */ - return 2; - - case GIMPLE_EH_DISPATCH: - /* ??? This is going to turn into a switch statement. Ideally - we'd have a look at the eh region and estimate the number of - edges involved. */ - return 10; - - case GIMPLE_BIND: - return estimate_num_insns_seq ( - gimple_bind_body (as_a <gbind *> (stmt)), - weights); - - case GIMPLE_EH_FILTER: - return estimate_num_insns_seq (gimple_eh_filter_failure (stmt), weights); - - case GIMPLE_CATCH: - return estimate_num_insns_seq (gimple_catch_handler ( - as_a <gcatch *> (stmt)), - weights); - - case GIMPLE_TRY: - return (estimate_num_insns_seq (gimple_try_eval (stmt), weights) - + estimate_num_insns_seq (gimple_try_cleanup (stmt), weights)); - - /* OMP directives are generally very expensive. */ - - case GIMPLE_OMP_RETURN: - case GIMPLE_OMP_SECTIONS_SWITCH: - case GIMPLE_OMP_ATOMIC_STORE: - case GIMPLE_OMP_CONTINUE: - /* ...except these, which are cheap. */ - return 0; - - case GIMPLE_OMP_ATOMIC_LOAD: - return weights->omp_cost; - - case GIMPLE_OMP_FOR: - return (weights->omp_cost - + estimate_num_insns_seq (gimple_omp_body (stmt), weights) - + estimate_num_insns_seq (gimple_omp_for_pre_body (stmt), weights)); - - case GIMPLE_OMP_PARALLEL: - case GIMPLE_OMP_TASK: - case GIMPLE_OMP_CRITICAL: - case GIMPLE_OMP_MASTER: - case GIMPLE_OMP_MASKED: - case GIMPLE_OMP_SCOPE: - case GIMPLE_OMP_TASKGROUP: - case GIMPLE_OMP_ORDERED: - case GIMPLE_OMP_SCAN: - case GIMPLE_OMP_SECTION: - case GIMPLE_OMP_SECTIONS: - case GIMPLE_OMP_SINGLE: - case GIMPLE_OMP_TARGET: - case GIMPLE_OMP_TEAMS: - return (weights->omp_cost - + estimate_num_insns_seq (gimple_omp_body (stmt), weights)); - - case GIMPLE_TRANSACTION: - return (weights->tm_cost - + estimate_num_insns_seq (gimple_transaction_body ( - as_a <gtransaction *> (stmt)), - weights)); - - default: - gcc_unreachable (); - } - - return cost; -} - -/* Estimate number of instructions that will be created by expanding - function FNDECL. WEIGHTS contains weights attributed to various - constructs. */ - -int -estimate_num_insns_fn (tree fndecl, eni_weights *weights) -{ - struct function *my_function = DECL_STRUCT_FUNCTION (fndecl); - gimple_stmt_iterator bsi; - basic_block bb; - int n = 0; - - gcc_assert (my_function && my_function->cfg); - FOR_EACH_BB_FN (bb, my_function) - { - for (bsi = gsi_start_bb (bb); !gsi_end_p (bsi); gsi_next (&bsi)) - n += estimate_num_insns (gsi_stmt (bsi), weights); - } - - return n; -} - - -/* Initializes weights used by estimate_num_insns. */ - -void -init_inline_once (void) -{ - eni_size_weights.call_cost = 1; - eni_size_weights.indirect_call_cost = 3; - eni_size_weights.target_builtin_call_cost = 1; - eni_size_weights.div_mod_cost = 1; - eni_size_weights.omp_cost = 40; - eni_size_weights.tm_cost = 10; - eni_size_weights.time_based = false; - eni_size_weights.return_cost = 1; - - /* Estimating time for call is difficult, since we have no idea what the - called function does. In the current uses of eni_time_weights, - underestimating the cost does less harm than overestimating it, so - we choose a rather small value here. */ - eni_time_weights.call_cost = 10; - eni_time_weights.indirect_call_cost = 15; - eni_time_weights.target_builtin_call_cost = 1; - eni_time_weights.div_mod_cost = 10; - eni_time_weights.omp_cost = 40; - eni_time_weights.tm_cost = 40; - eni_time_weights.time_based = true; - eni_time_weights.return_cost = 2; -} - - -/* Install new lexical TREE_BLOCK underneath 'current_block'. */ - -static void -prepend_lexical_block (tree current_block, tree new_block) -{ - BLOCK_CHAIN (new_block) = BLOCK_SUBBLOCKS (current_block); - BLOCK_SUBBLOCKS (current_block) = new_block; - BLOCK_SUPERCONTEXT (new_block) = current_block; -} - -/* Add local variables from CALLEE to CALLER. */ - -static inline void -add_local_variables (struct function *callee, struct function *caller, - copy_body_data *id) -{ - tree var; - unsigned ix; - - FOR_EACH_LOCAL_DECL (callee, ix, var) - if (!can_be_nonlocal (var, id)) - { - tree new_var = remap_decl (var, id); - - /* Remap debug-expressions. */ - if (VAR_P (new_var) - && DECL_HAS_DEBUG_EXPR_P (var) - && new_var != var) - { - tree tem = DECL_DEBUG_EXPR (var); - bool old_regimplify = id->regimplify; - id->remapping_type_depth++; - walk_tree (&tem, copy_tree_body_r, id, NULL); - id->remapping_type_depth--; - id->regimplify = old_regimplify; - SET_DECL_DEBUG_EXPR (new_var, tem); - DECL_HAS_DEBUG_EXPR_P (new_var) = 1; - } - add_local_decl (caller, new_var); - } -} - -/* Add to BINDINGS a debug stmt resetting SRCVAR if inlining might - have brought in or introduced any debug stmts for SRCVAR. */ - -static inline void -reset_debug_binding (copy_body_data *id, tree srcvar, gimple_seq *bindings) -{ - tree *remappedvarp = id->decl_map->get (srcvar); - - if (!remappedvarp) - return; - - if (!VAR_P (*remappedvarp)) - return; - - if (*remappedvarp == id->retvar) - return; - - tree tvar = target_for_debug_bind (*remappedvarp); - if (!tvar) - return; - - gdebug *stmt = gimple_build_debug_bind (tvar, NULL_TREE, - id->call_stmt); - gimple_seq_add_stmt (bindings, stmt); -} - -/* For each inlined variable for which we may have debug bind stmts, - add before GSI a final debug stmt resetting it, marking the end of - its life, so that var-tracking knows it doesn't have to compute - further locations for it. */ - -static inline void -reset_debug_bindings (copy_body_data *id, gimple_stmt_iterator gsi) -{ - tree var; - unsigned ix; - gimple_seq bindings = NULL; - - if (!gimple_in_ssa_p (id->src_cfun)) - return; - - if (!opt_for_fn (id->dst_fn, flag_var_tracking_assignments)) - return; - - for (var = DECL_ARGUMENTS (id->src_fn); - var; var = DECL_CHAIN (var)) - reset_debug_binding (id, var, &bindings); - - FOR_EACH_LOCAL_DECL (id->src_cfun, ix, var) - reset_debug_binding (id, var, &bindings); - - gsi_insert_seq_before_without_update (&gsi, bindings, GSI_SAME_STMT); -} - -/* If STMT is a GIMPLE_CALL, replace it with its inline expansion. */ - -static bool -expand_call_inline (basic_block bb, gimple *stmt, copy_body_data *id, - bitmap to_purge) -{ - tree use_retvar; - tree fn; - hash_map<tree, tree> *dst; - hash_map<tree, tree> *st = NULL; - tree return_slot; - tree modify_dest; - struct cgraph_edge *cg_edge; - cgraph_inline_failed_t reason; - basic_block return_block; - edge e; - gimple_stmt_iterator gsi, stmt_gsi; - bool successfully_inlined = false; - bool purge_dead_abnormal_edges; - gcall *call_stmt; - unsigned int prop_mask, src_properties; - struct function *dst_cfun; - tree simduid; - use_operand_p use; - gimple *simtenter_stmt = NULL; - vec<tree> *simtvars_save; - - /* The gimplifier uses input_location in too many places, such as - internal_get_tmp_var (). */ - location_t saved_location = input_location; - input_location = gimple_location (stmt); - - /* From here on, we're only interested in CALL_EXPRs. */ - call_stmt = dyn_cast <gcall *> (stmt); - if (!call_stmt) - goto egress; - - cg_edge = id->dst_node->get_edge (stmt); - gcc_checking_assert (cg_edge); - /* First, see if we can figure out what function is being called. - If we cannot, then there is no hope of inlining the function. */ - if (cg_edge->indirect_unknown_callee) - goto egress; - fn = cg_edge->callee->decl; - gcc_checking_assert (fn); - - /* If FN is a declaration of a function in a nested scope that was - globally declared inline, we don't set its DECL_INITIAL. - However, we can't blindly follow DECL_ABSTRACT_ORIGIN because the - C++ front-end uses it for cdtors to refer to their internal - declarations, that are not real functions. Fortunately those - don't have trees to be saved, so we can tell by checking their - gimple_body. */ - if (!DECL_INITIAL (fn) - && DECL_ABSTRACT_ORIGIN (fn) - && gimple_has_body_p (DECL_ABSTRACT_ORIGIN (fn))) - fn = DECL_ABSTRACT_ORIGIN (fn); - - /* Don't try to inline functions that are not well-suited to inlining. */ - if (cg_edge->inline_failed) - { - reason = cg_edge->inline_failed; - /* If this call was originally indirect, we do not want to emit any - inlining related warnings or sorry messages because there are no - guarantees regarding those. */ - if (cg_edge->indirect_inlining_edge) - goto egress; - - if (lookup_attribute ("always_inline", DECL_ATTRIBUTES (fn)) - /* For extern inline functions that get redefined we always - silently ignored always_inline flag. Better behavior would - be to be able to keep both bodies and use extern inline body - for inlining, but we can't do that because frontends overwrite - the body. */ - && !cg_edge->callee->redefined_extern_inline - /* During early inline pass, report only when optimization is - not turned on. */ - && (symtab->global_info_ready - || !optimize - || cgraph_inline_failed_type (reason) == CIF_FINAL_ERROR) - /* PR 20090218-1_0.c. Body can be provided by another module. */ - && (reason != CIF_BODY_NOT_AVAILABLE || !flag_generate_lto)) - { - error ("inlining failed in call to %<always_inline%> %q+F: %s", fn, - cgraph_inline_failed_string (reason)); - if (gimple_location (stmt) != UNKNOWN_LOCATION) - inform (gimple_location (stmt), "called from here"); - else if (DECL_SOURCE_LOCATION (cfun->decl) != UNKNOWN_LOCATION) - inform (DECL_SOURCE_LOCATION (cfun->decl), - "called from this function"); - } - else if (opt_for_fn (fn, warn_inline) - && DECL_DECLARED_INLINE_P (fn) - && !DECL_NO_INLINE_WARNING_P (fn) - && !DECL_IN_SYSTEM_HEADER (fn) - && reason != CIF_UNSPECIFIED - && !lookup_attribute ("noinline", DECL_ATTRIBUTES (fn)) - /* Do not warn about not inlined recursive calls. */ - && !cg_edge->recursive_p () - /* Avoid warnings during early inline pass. */ - && symtab->global_info_ready) - { - auto_diagnostic_group d; - if (warning (OPT_Winline, "inlining failed in call to %q+F: %s", - fn, _(cgraph_inline_failed_string (reason)))) - { - if (gimple_location (stmt) != UNKNOWN_LOCATION) - inform (gimple_location (stmt), "called from here"); - else if (DECL_SOURCE_LOCATION (cfun->decl) != UNKNOWN_LOCATION) - inform (DECL_SOURCE_LOCATION (cfun->decl), - "called from this function"); - } - } - goto egress; - } - id->src_node = cg_edge->callee; - - /* If callee is thunk, all we need is to adjust the THIS pointer - and redirect to function being thunked. */ - if (id->src_node->thunk) - { - cgraph_edge *edge; - tree virtual_offset = NULL; - profile_count count = cg_edge->count; - tree op; - gimple_stmt_iterator iter = gsi_for_stmt (stmt); - thunk_info *info = thunk_info::get (id->src_node); - - cgraph_edge::remove (cg_edge); - edge = id->src_node->callees->clone (id->dst_node, call_stmt, - gimple_uid (stmt), - profile_count::one (), - profile_count::one (), - true); - edge->count = count; - if (info->virtual_offset_p) - virtual_offset = size_int (info->virtual_value); - op = create_tmp_reg_fn (cfun, TREE_TYPE (gimple_call_arg (stmt, 0)), - NULL); - gsi_insert_before (&iter, gimple_build_assign (op, - gimple_call_arg (stmt, 0)), - GSI_NEW_STMT); - gcc_assert (info->this_adjusting); - op = thunk_adjust (&iter, op, 1, info->fixed_offset, - virtual_offset, info->indirect_offset); - - gimple_call_set_arg (stmt, 0, op); - gimple_call_set_fndecl (stmt, edge->callee->decl); - update_stmt (stmt); - id->src_node->remove (); - successfully_inlined = expand_call_inline (bb, stmt, id, to_purge); - maybe_remove_unused_call_args (cfun, stmt); - /* This used to return true even though we do fail to inline in - some cases. See PR98525. */ - goto egress; - } - fn = cg_edge->callee->decl; - cg_edge->callee->get_untransformed_body (); - - if (flag_checking && cg_edge->callee->decl != id->dst_node->decl) - cg_edge->callee->verify (); - - /* We will be inlining this callee. */ - id->eh_lp_nr = lookup_stmt_eh_lp (stmt); - - /* Update the callers EH personality. */ - if (DECL_FUNCTION_PERSONALITY (fn)) - DECL_FUNCTION_PERSONALITY (cg_edge->caller->decl) - = DECL_FUNCTION_PERSONALITY (fn); - - /* Split the block before the GIMPLE_CALL. */ - stmt_gsi = gsi_for_stmt (stmt); - gsi_prev (&stmt_gsi); - e = split_block (bb, gsi_end_p (stmt_gsi) ? NULL : gsi_stmt (stmt_gsi)); - bb = e->src; - return_block = e->dest; - remove_edge (e); - - /* If the GIMPLE_CALL was in the last statement of BB, it may have - been the source of abnormal edges. In this case, schedule - the removal of dead abnormal edges. */ - gsi = gsi_start_bb (return_block); - gsi_next (&gsi); - purge_dead_abnormal_edges = gsi_end_p (gsi); - - stmt_gsi = gsi_start_bb (return_block); - - /* Build a block containing code to initialize the arguments, the - actual inline expansion of the body, and a label for the return - statements within the function to jump to. The type of the - statement expression is the return type of the function call. - ??? If the call does not have an associated block then we will - remap all callee blocks to NULL, effectively dropping most of - its debug information. This should only happen for calls to - artificial decls inserted by the compiler itself. We need to - either link the inlined blocks into the caller block tree or - not refer to them in any way to not break GC for locations. */ - if (tree block = gimple_block (stmt)) - { - /* We do want to assign a not UNKNOWN_LOCATION BLOCK_SOURCE_LOCATION - to make inlined_function_outer_scope_p return true on this BLOCK. */ - location_t loc = LOCATION_LOCUS (gimple_location (stmt)); - if (loc == UNKNOWN_LOCATION) - loc = LOCATION_LOCUS (DECL_SOURCE_LOCATION (fn)); - if (loc == UNKNOWN_LOCATION) - loc = BUILTINS_LOCATION; - id->block = make_node (BLOCK); - BLOCK_ABSTRACT_ORIGIN (id->block) = DECL_ORIGIN (fn); - BLOCK_SOURCE_LOCATION (id->block) = loc; - prepend_lexical_block (block, id->block); - } - - /* Local declarations will be replaced by their equivalents in this map. */ - st = id->decl_map; - id->decl_map = new hash_map<tree, tree>; - dst = id->debug_map; - id->debug_map = NULL; - if (flag_stack_reuse != SR_NONE) - id->add_clobbers_to_eh_landing_pads = last_basic_block_for_fn (cfun); - - /* Record the function we are about to inline. */ - id->src_fn = fn; - id->src_cfun = DECL_STRUCT_FUNCTION (fn); - id->reset_location = DECL_IGNORED_P (fn); - id->call_stmt = call_stmt; - - /* When inlining into an OpenMP SIMD-on-SIMT loop, arrange for new automatic - variables to be added to IFN_GOMP_SIMT_ENTER argument list. */ - dst_cfun = DECL_STRUCT_FUNCTION (id->dst_fn); - simtvars_save = id->dst_simt_vars; - if (!(dst_cfun->curr_properties & PROP_gimple_lomp_dev) - && (simduid = bb->loop_father->simduid) != NULL_TREE - && (simduid = ssa_default_def (dst_cfun, simduid)) != NULL_TREE - && single_imm_use (simduid, &use, &simtenter_stmt) - && is_gimple_call (simtenter_stmt) - && gimple_call_internal_p (simtenter_stmt, IFN_GOMP_SIMT_ENTER)) - vec_alloc (id->dst_simt_vars, 0); - else - id->dst_simt_vars = NULL; - - if (profile_status_for_fn (id->src_cfun) == PROFILE_ABSENT) - profile_status_for_fn (dst_cfun) = PROFILE_ABSENT; - - /* If the src function contains an IFN_VA_ARG, then so will the dst - function after inlining. Likewise for IFN_GOMP_USE_SIMT. */ - prop_mask = PROP_gimple_lva | PROP_gimple_lomp_dev; - src_properties = id->src_cfun->curr_properties & prop_mask; - if (src_properties != prop_mask) - dst_cfun->curr_properties &= src_properties | ~prop_mask; - dst_cfun->calls_eh_return |= id->src_cfun->calls_eh_return; - id->dst_node->calls_declare_variant_alt - |= id->src_node->calls_declare_variant_alt; - - gcc_assert (!id->src_cfun->after_inlining); - - id->entry_bb = bb; - if (lookup_attribute ("cold", DECL_ATTRIBUTES (fn))) - { - gimple_stmt_iterator si = gsi_last_bb (bb); - gsi_insert_after (&si, gimple_build_predict (PRED_COLD_FUNCTION, - NOT_TAKEN), - GSI_NEW_STMT); - } - initialize_inlined_parameters (id, stmt, fn, bb); - if (debug_nonbind_markers_p && debug_inline_points && id->block - && inlined_function_outer_scope_p (id->block)) - { - gimple_stmt_iterator si = gsi_last_bb (bb); - gsi_insert_after (&si, gimple_build_debug_inline_entry - (id->block, DECL_SOURCE_LOCATION (id->src_fn)), - GSI_NEW_STMT); - } - - if (DECL_INITIAL (fn)) - { - if (gimple_block (stmt)) - { - tree *var; - - prepend_lexical_block (id->block, - remap_blocks (DECL_INITIAL (fn), id)); - gcc_checking_assert (BLOCK_SUBBLOCKS (id->block) - && (BLOCK_CHAIN (BLOCK_SUBBLOCKS (id->block)) - == NULL_TREE)); - /* Move vars for PARM_DECLs from DECL_INITIAL block to id->block, - otherwise for DWARF DW_TAG_formal_parameter will not be children of - DW_TAG_inlined_subroutine, but of a DW_TAG_lexical_block - under it. The parameters can be then evaluated in the debugger, - but don't show in backtraces. */ - for (var = &BLOCK_VARS (BLOCK_SUBBLOCKS (id->block)); *var; ) - if (TREE_CODE (DECL_ORIGIN (*var)) == PARM_DECL) - { - tree v = *var; - *var = TREE_CHAIN (v); - TREE_CHAIN (v) = BLOCK_VARS (id->block); - BLOCK_VARS (id->block) = v; - } - else - var = &TREE_CHAIN (*var); - } - else - remap_blocks_to_null (DECL_INITIAL (fn), id); - } - - /* Return statements in the function body will be replaced by jumps - to the RET_LABEL. */ - gcc_assert (DECL_INITIAL (fn)); - gcc_assert (TREE_CODE (DECL_INITIAL (fn)) == BLOCK); - - /* Find the LHS to which the result of this call is assigned. */ - return_slot = NULL; - if (gimple_call_lhs (stmt)) - { - modify_dest = gimple_call_lhs (stmt); - - /* The function which we are inlining might not return a value, - in which case we should issue a warning that the function - does not return a value. In that case the optimizers will - see that the variable to which the value is assigned was not - initialized. We do not want to issue a warning about that - uninitialized variable. */ - if (DECL_P (modify_dest)) - suppress_warning (modify_dest, OPT_Wuninitialized); - - if (gimple_call_return_slot_opt_p (call_stmt)) - { - return_slot = modify_dest; - modify_dest = NULL; - } - } - else - modify_dest = NULL; - - /* If we are inlining a call to the C++ operator new, we don't want - to use type based alias analysis on the return value. Otherwise - we may get confused if the compiler sees that the inlined new - function returns a pointer which was just deleted. See bug - 33407. */ - if (DECL_IS_OPERATOR_NEW_P (fn)) - { - return_slot = NULL; - modify_dest = NULL; - } - - /* Declare the return variable for the function. */ - use_retvar = declare_return_variable (id, return_slot, modify_dest, bb); - - /* Add local vars in this inlined callee to caller. */ - add_local_variables (id->src_cfun, cfun, id); - - if (dump_enabled_p ()) - { - char buf[128]; - snprintf (buf, sizeof(buf), "%4.2f", - cg_edge->sreal_frequency ().to_double ()); - dump_printf_loc (MSG_NOTE | MSG_PRIORITY_INTERNALS, - call_stmt, - "Inlining %C to %C with frequency %s\n", - id->src_node, id->dst_node, buf); - if (dump_file && (dump_flags & TDF_DETAILS)) - { - id->src_node->dump (dump_file); - id->dst_node->dump (dump_file); - } - } - - /* This is it. Duplicate the callee body. Assume callee is - pre-gimplified. Note that we must not alter the caller - function in any way before this point, as this CALL_EXPR may be - a self-referential call; if we're calling ourselves, we need to - duplicate our body before altering anything. */ - copy_body (id, bb, return_block, NULL); - - reset_debug_bindings (id, stmt_gsi); - - if (flag_stack_reuse != SR_NONE) - for (tree p = DECL_ARGUMENTS (id->src_fn); p; p = DECL_CHAIN (p)) - if (!TREE_THIS_VOLATILE (p)) - { - /* The value associated with P is a local temporary only if - there is no value associated with P in the debug map. */ - tree *varp = id->decl_map->get (p); - if (varp - && VAR_P (*varp) - && !is_gimple_reg (*varp) - && !(id->debug_map && id->debug_map->get (p))) - { - tree clobber = build_clobber (TREE_TYPE (*varp)); - gimple *clobber_stmt; - clobber_stmt = gimple_build_assign (*varp, clobber); - gimple_set_location (clobber_stmt, gimple_location (stmt)); - gsi_insert_before (&stmt_gsi, clobber_stmt, GSI_SAME_STMT); - } - } - - /* Reset the escaped solution. */ - if (cfun->gimple_df) - pt_solution_reset (&cfun->gimple_df->escaped); - - /* Add new automatic variables to IFN_GOMP_SIMT_ENTER arguments. */ - if (id->dst_simt_vars && id->dst_simt_vars->length () > 0) - { - size_t nargs = gimple_call_num_args (simtenter_stmt); - vec<tree> *vars = id->dst_simt_vars; - auto_vec<tree> newargs (nargs + vars->length ()); - for (size_t i = 0; i < nargs; i++) - newargs.quick_push (gimple_call_arg (simtenter_stmt, i)); - for (tree *pvar = vars->begin (); pvar != vars->end (); pvar++) - { - tree ptrtype = build_pointer_type (TREE_TYPE (*pvar)); - newargs.quick_push (build1 (ADDR_EXPR, ptrtype, *pvar)); - } - gcall *g = gimple_build_call_internal_vec (IFN_GOMP_SIMT_ENTER, newargs); - gimple_call_set_lhs (g, gimple_call_lhs (simtenter_stmt)); - gimple_stmt_iterator gsi = gsi_for_stmt (simtenter_stmt); - gsi_replace (&gsi, g, false); - } - vec_free (id->dst_simt_vars); - id->dst_simt_vars = simtvars_save; - - /* Clean up. */ - if (id->debug_map) - { - delete id->debug_map; - id->debug_map = dst; - } - delete id->decl_map; - id->decl_map = st; - - /* Unlink the calls virtual operands before replacing it. */ - unlink_stmt_vdef (stmt); - if (gimple_vdef (stmt) - && TREE_CODE (gimple_vdef (stmt)) == SSA_NAME) - release_ssa_name (gimple_vdef (stmt)); - - /* If the inlined function returns a result that we care about, - substitute the GIMPLE_CALL with an assignment of the return - variable to the LHS of the call. That is, if STMT was - 'a = foo (...)', substitute the call with 'a = USE_RETVAR'. */ - if (use_retvar && gimple_call_lhs (stmt)) - { - gimple *old_stmt = stmt; - stmt = gimple_build_assign (gimple_call_lhs (stmt), use_retvar); - gimple_set_location (stmt, gimple_location (old_stmt)); - gsi_replace (&stmt_gsi, stmt, false); - maybe_clean_or_replace_eh_stmt (old_stmt, stmt); - /* Append a clobber for id->retvar if easily possible. */ - if (flag_stack_reuse != SR_NONE - && id->retvar - && VAR_P (id->retvar) - && id->retvar != return_slot - && id->retvar != modify_dest - && !TREE_THIS_VOLATILE (id->retvar) - && !is_gimple_reg (id->retvar) - && !stmt_ends_bb_p (stmt)) - { - tree clobber = build_clobber (TREE_TYPE (id->retvar)); - gimple *clobber_stmt; - clobber_stmt = gimple_build_assign (id->retvar, clobber); - gimple_set_location (clobber_stmt, gimple_location (old_stmt)); - gsi_insert_after (&stmt_gsi, clobber_stmt, GSI_SAME_STMT); - } - } - else - { - /* Handle the case of inlining a function with no return - statement, which causes the return value to become undefined. */ - if (gimple_call_lhs (stmt) - && TREE_CODE (gimple_call_lhs (stmt)) == SSA_NAME) - { - tree name = gimple_call_lhs (stmt); - tree var = SSA_NAME_VAR (name); - tree def = var ? ssa_default_def (cfun, var) : NULL; - - if (def) - { - /* If the variable is used undefined, make this name - undefined via a move. */ - stmt = gimple_build_assign (gimple_call_lhs (stmt), def); - gsi_replace (&stmt_gsi, stmt, true); - } - else - { - if (!var) - { - var = create_tmp_reg_fn (cfun, TREE_TYPE (name), NULL); - SET_SSA_NAME_VAR_OR_IDENTIFIER (name, var); - } - /* Otherwise make this variable undefined. */ - gsi_remove (&stmt_gsi, true); - set_ssa_default_def (cfun, var, name); - SSA_NAME_DEF_STMT (name) = gimple_build_nop (); - } - } - /* Replace with a clobber for id->retvar. */ - else if (flag_stack_reuse != SR_NONE - && id->retvar - && VAR_P (id->retvar) - && id->retvar != return_slot - && id->retvar != modify_dest - && !TREE_THIS_VOLATILE (id->retvar) - && !is_gimple_reg (id->retvar)) - { - tree clobber = build_clobber (TREE_TYPE (id->retvar)); - gimple *clobber_stmt; - clobber_stmt = gimple_build_assign (id->retvar, clobber); - gimple_set_location (clobber_stmt, gimple_location (stmt)); - gsi_replace (&stmt_gsi, clobber_stmt, false); - maybe_clean_or_replace_eh_stmt (stmt, clobber_stmt); - } - else - gsi_remove (&stmt_gsi, true); - } - - if (purge_dead_abnormal_edges) - bitmap_set_bit (to_purge, return_block->index); - - /* If the value of the new expression is ignored, that's OK. We - don't warn about this for CALL_EXPRs, so we shouldn't warn about - the equivalent inlined version either. */ - if (is_gimple_assign (stmt)) - { - gcc_assert (gimple_assign_single_p (stmt) - || CONVERT_EXPR_CODE_P (gimple_assign_rhs_code (stmt))); - TREE_USED (gimple_assign_rhs1 (stmt)) = 1; - } - - id->add_clobbers_to_eh_landing_pads = 0; - - /* Output the inlining info for this abstract function, since it has been - inlined. If we don't do this now, we can lose the information about the - variables in the function when the blocks get blown away as soon as we - remove the cgraph node. */ - if (gimple_block (stmt)) - (*debug_hooks->outlining_inline_function) (fn); - - /* Update callgraph if needed. */ - cg_edge->callee->remove (); - - id->block = NULL_TREE; - id->retvar = NULL_TREE; - successfully_inlined = true; - - egress: - input_location = saved_location; - return successfully_inlined; -} - -/* Expand call statements reachable from STMT_P. - We can only have CALL_EXPRs as the "toplevel" tree code or nested - in a MODIFY_EXPR. */ - -static bool -gimple_expand_calls_inline (basic_block bb, copy_body_data *id, - bitmap to_purge) -{ - gimple_stmt_iterator gsi; - bool inlined = false; - - for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);) - { - gimple *stmt = gsi_stmt (gsi); - gsi_prev (&gsi); - - if (is_gimple_call (stmt) - && !gimple_call_internal_p (stmt)) - inlined |= expand_call_inline (bb, stmt, id, to_purge); - } - - return inlined; -} - - -/* Walk all basic blocks created after FIRST and try to fold every statement - in the STATEMENTS pointer set. */ - -static void -fold_marked_statements (int first, hash_set<gimple *> *statements) -{ - auto_bitmap to_purge; - - auto_vec<edge, 20> stack (n_basic_blocks_for_fn (cfun) + 2); - auto_sbitmap visited (last_basic_block_for_fn (cfun)); - bitmap_clear (visited); - - stack.quick_push (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))); - while (!stack.is_empty ()) - { - /* Look at the edge on the top of the stack. */ - edge e = stack.pop (); - basic_block dest = e->dest; - - if (dest == EXIT_BLOCK_PTR_FOR_FN (cfun) - || bitmap_bit_p (visited, dest->index)) - continue; - - bitmap_set_bit (visited, dest->index); - - if (dest->index >= first) - for (gimple_stmt_iterator gsi = gsi_start_bb (dest); - !gsi_end_p (gsi); gsi_next (&gsi)) - { - if (!statements->contains (gsi_stmt (gsi))) - continue; - - gimple *old_stmt = gsi_stmt (gsi); - tree old_decl = (is_gimple_call (old_stmt) - ? gimple_call_fndecl (old_stmt) : 0); - if (old_decl && fndecl_built_in_p (old_decl)) - { - /* Folding builtins can create multiple instructions, - we need to look at all of them. */ - gimple_stmt_iterator i2 = gsi; - gsi_prev (&i2); - if (fold_stmt (&gsi)) - { - gimple *new_stmt; - /* If a builtin at the end of a bb folded into nothing, - the following loop won't work. */ - if (gsi_end_p (gsi)) - { - cgraph_update_edges_for_call_stmt (old_stmt, - old_decl, NULL); - break; - } - if (gsi_end_p (i2)) - i2 = gsi_start_bb (dest); - else - gsi_next (&i2); - while (1) - { - new_stmt = gsi_stmt (i2); - update_stmt (new_stmt); - cgraph_update_edges_for_call_stmt (old_stmt, old_decl, - new_stmt); - - if (new_stmt == gsi_stmt (gsi)) - { - /* It is okay to check only for the very last - of these statements. If it is a throwing - statement nothing will change. If it isn't - this can remove EH edges. If that weren't - correct then because some intermediate stmts - throw, but not the last one. That would mean - we'd have to split the block, which we can't - here and we'd loose anyway. And as builtins - probably never throw, this all - is mood anyway. */ - if (maybe_clean_or_replace_eh_stmt (old_stmt, - new_stmt)) - bitmap_set_bit (to_purge, dest->index); - break; - } - gsi_next (&i2); - } - } - } - else if (fold_stmt (&gsi)) - { - /* Re-read the statement from GSI as fold_stmt() may - have changed it. */ - gimple *new_stmt = gsi_stmt (gsi); - update_stmt (new_stmt); - - if (is_gimple_call (old_stmt) - || is_gimple_call (new_stmt)) - cgraph_update_edges_for_call_stmt (old_stmt, old_decl, - new_stmt); - - if (maybe_clean_or_replace_eh_stmt (old_stmt, new_stmt)) - bitmap_set_bit (to_purge, dest->index); - } - } - - if (EDGE_COUNT (dest->succs) > 0) - { - /* Avoid warnings emitted from folding statements that - became unreachable because of inlined function parameter - propagation. */ - e = find_taken_edge (dest, NULL_TREE); - if (e) - stack.quick_push (e); - else - { - edge_iterator ei; - FOR_EACH_EDGE (e, ei, dest->succs) - stack.safe_push (e); - } - } - } - - gimple_purge_all_dead_eh_edges (to_purge); -} - -/* Expand calls to inline functions in the body of FN. */ - -unsigned int -optimize_inline_calls (tree fn) -{ - copy_body_data id; - basic_block bb; - int last = n_basic_blocks_for_fn (cfun); - bool inlined_p = false; - - /* Clear out ID. */ - memset (&id, 0, sizeof (id)); - - id.src_node = id.dst_node = cgraph_node::get (fn); - gcc_assert (id.dst_node->definition); - id.dst_fn = fn; - /* Or any functions that aren't finished yet. */ - if (current_function_decl) - id.dst_fn = current_function_decl; - - id.copy_decl = copy_decl_maybe_to_var; - id.transform_call_graph_edges = CB_CGE_DUPLICATE; - id.transform_new_cfg = false; - id.transform_return_to_modify = true; - id.transform_parameter = true; - id.statements_to_fold = new hash_set<gimple *>; - - push_gimplify_context (); - - /* We make no attempts to keep dominance info up-to-date. */ - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - - /* Register specific gimple functions. */ - gimple_register_cfg_hooks (); - - /* Reach the trees by walking over the CFG, and note the - enclosing basic-blocks in the call edges. */ - /* We walk the blocks going forward, because inlined function bodies - will split id->current_basic_block, and the new blocks will - follow it; we'll trudge through them, processing their CALL_EXPRs - along the way. */ - auto_bitmap to_purge; - FOR_EACH_BB_FN (bb, cfun) - inlined_p |= gimple_expand_calls_inline (bb, &id, to_purge); - - pop_gimplify_context (NULL); - - if (flag_checking) - { - struct cgraph_edge *e; - - id.dst_node->verify (); - - /* Double check that we inlined everything we are supposed to inline. */ - for (e = id.dst_node->callees; e; e = e->next_callee) - gcc_assert (e->inline_failed); - } - - /* If we didn't inline into the function there is nothing to do. */ - if (!inlined_p) - { - delete id.statements_to_fold; - return 0; - } - - /* Fold queued statements. */ - update_max_bb_count (); - fold_marked_statements (last, id.statements_to_fold); - delete id.statements_to_fold; - - /* Finally purge EH and abnormal edges from the call stmts we inlined. - We need to do this after fold_marked_statements since that may walk - the SSA use-def chain. */ - unsigned i; - bitmap_iterator bi; - EXECUTE_IF_SET_IN_BITMAP (to_purge, 0, i, bi) - { - basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i); - if (bb) - { - gimple_purge_dead_eh_edges (bb); - gimple_purge_dead_abnormal_call_edges (bb); - } - } - - gcc_assert (!id.debug_stmts.exists ()); - - /* Renumber the lexical scoping (non-code) blocks consecutively. */ - number_blocks (fn); - - delete_unreachable_blocks_update_callgraph (id.dst_node, false); - id.dst_node->calls_comdat_local = id.dst_node->check_calls_comdat_local_p (); - - if (flag_checking) - id.dst_node->verify (); - - /* It would be nice to check SSA/CFG/statement consistency here, but it is - not possible yet - the IPA passes might make various functions to not - throw and they don't care to proactively update local EH info. This is - done later in fixup_cfg pass that also execute the verification. */ - return (TODO_update_ssa - | TODO_cleanup_cfg - | (gimple_in_ssa_p (cfun) ? TODO_remove_unused_locals : 0) - | (gimple_in_ssa_p (cfun) ? TODO_update_address_taken : 0) - | (profile_status_for_fn (cfun) != PROFILE_ABSENT - ? TODO_rebuild_frequencies : 0)); -} - -/* Passed to walk_tree. Copies the node pointed to, if appropriate. */ - -tree -copy_tree_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED) -{ - enum tree_code code = TREE_CODE (*tp); - enum tree_code_class cl = TREE_CODE_CLASS (code); - - /* We make copies of most nodes. */ - if (IS_EXPR_CODE_CLASS (cl) - || code == TREE_LIST - || code == TREE_VEC - || code == TYPE_DECL - || code == OMP_CLAUSE) - { - /* Because the chain gets clobbered when we make a copy, we save it - here. */ - tree chain = NULL_TREE, new_tree; - - if (CODE_CONTAINS_STRUCT (code, TS_COMMON)) - chain = TREE_CHAIN (*tp); - - /* Copy the node. */ - new_tree = copy_node (*tp); - - *tp = new_tree; - - /* Now, restore the chain, if appropriate. That will cause - walk_tree to walk into the chain as well. */ - if (code == PARM_DECL - || code == TREE_LIST - || code == OMP_CLAUSE) - TREE_CHAIN (*tp) = chain; - - /* For now, we don't update BLOCKs when we make copies. So, we - have to nullify all BIND_EXPRs. */ - if (TREE_CODE (*tp) == BIND_EXPR) - BIND_EXPR_BLOCK (*tp) = NULL_TREE; - } - else if (code == CONSTRUCTOR) - { - /* CONSTRUCTOR nodes need special handling because - we need to duplicate the vector of elements. */ - tree new_tree; - - new_tree = copy_node (*tp); - CONSTRUCTOR_ELTS (new_tree) = vec_safe_copy (CONSTRUCTOR_ELTS (*tp)); - *tp = new_tree; - } - else if (code == STATEMENT_LIST) - /* We used to just abort on STATEMENT_LIST, but we can run into them - with statement-expressions (c++/40975). */ - copy_statement_list (tp); - else if (TREE_CODE_CLASS (code) == tcc_type) - *walk_subtrees = 0; - else if (TREE_CODE_CLASS (code) == tcc_declaration) - *walk_subtrees = 0; - else if (TREE_CODE_CLASS (code) == tcc_constant) - *walk_subtrees = 0; - return NULL_TREE; -} - -/* The SAVE_EXPR pointed to by TP is being copied. If ST contains - information indicating to what new SAVE_EXPR this one should be mapped, - use that one. Otherwise, create a new node and enter it in ST. FN is - the function into which the copy will be placed. */ - -static void -remap_save_expr (tree *tp, hash_map<tree, tree> *st, int *walk_subtrees) -{ - tree *n; - tree t; - - /* See if we already encountered this SAVE_EXPR. */ - n = st->get (*tp); - - /* If we didn't already remap this SAVE_EXPR, do so now. */ - if (!n) - { - t = copy_node (*tp); - - /* Remember this SAVE_EXPR. */ - st->put (*tp, t); - /* Make sure we don't remap an already-remapped SAVE_EXPR. */ - st->put (t, t); - } - else - { - /* We've already walked into this SAVE_EXPR; don't do it again. */ - *walk_subtrees = 0; - t = *n; - } - - /* Replace this SAVE_EXPR with the copy. */ - *tp = t; -} - -/* Called via walk_gimple_seq. If *GSIP points to a GIMPLE_LABEL for a local - label, copies the declaration and enters it in the splay_tree in DATA (which - is really a 'copy_body_data *'. */ - -static tree -mark_local_labels_stmt (gimple_stmt_iterator *gsip, - bool *handled_ops_p ATTRIBUTE_UNUSED, - struct walk_stmt_info *wi) -{ - copy_body_data *id = (copy_body_data *) wi->info; - glabel *stmt = dyn_cast <glabel *> (gsi_stmt (*gsip)); - - if (stmt) - { - tree decl = gimple_label_label (stmt); - - /* Copy the decl and remember the copy. */ - insert_decl_map (id, decl, id->copy_decl (decl, id)); - } - - return NULL_TREE; -} - -static gimple_seq duplicate_remap_omp_clause_seq (gimple_seq seq, - struct walk_stmt_info *wi); - -/* Called via walk_gimple_seq by copy_gimple_seq_and_replace_local. - Using the splay_tree pointed to by ST (which is really a `splay_tree'), - remaps all local declarations to appropriate replacements in gimple - operands. */ - -static tree -replace_locals_op (tree *tp, int *walk_subtrees, void *data) -{ - struct walk_stmt_info *wi = (struct walk_stmt_info*) data; - copy_body_data *id = (copy_body_data *) wi->info; - hash_map<tree, tree> *st = id->decl_map; - tree *n; - tree expr = *tp; - - /* For recursive invocations this is no longer the LHS itself. */ - bool is_lhs = wi->is_lhs; - wi->is_lhs = false; - - if (TREE_CODE (expr) == SSA_NAME) - { - *tp = remap_ssa_name (*tp, id); - *walk_subtrees = 0; - if (is_lhs) - SSA_NAME_DEF_STMT (*tp) = gsi_stmt (wi->gsi); - } - /* Only a local declaration (variable or label). */ - else if ((VAR_P (expr) && !TREE_STATIC (expr)) - || TREE_CODE (expr) == LABEL_DECL) - { - /* Lookup the declaration. */ - n = st->get (expr); - - /* If it's there, remap it. */ - if (n) - *tp = *n; - *walk_subtrees = 0; - } - else if (TREE_CODE (expr) == STATEMENT_LIST - || TREE_CODE (expr) == BIND_EXPR - || TREE_CODE (expr) == SAVE_EXPR) - gcc_unreachable (); - else if (TREE_CODE (expr) == TARGET_EXPR) - { - /* Don't mess with a TARGET_EXPR that hasn't been expanded. - It's OK for this to happen if it was part of a subtree that - isn't immediately expanded, such as operand 2 of another - TARGET_EXPR. */ - if (!TREE_OPERAND (expr, 1)) - { - TREE_OPERAND (expr, 1) = TREE_OPERAND (expr, 3); - TREE_OPERAND (expr, 3) = NULL_TREE; - } - } - else if (TREE_CODE (expr) == OMP_CLAUSE) - { - /* Before the omplower pass completes, some OMP clauses can contain - sequences that are neither copied by gimple_seq_copy nor walked by - walk_gimple_seq. To make copy_gimple_seq_and_replace_locals work even - in those situations, we have to copy and process them explicitely. */ - - if (OMP_CLAUSE_CODE (expr) == OMP_CLAUSE_LASTPRIVATE) - { - gimple_seq seq = OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (expr); - seq = duplicate_remap_omp_clause_seq (seq, wi); - OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (expr) = seq; - } - else if (OMP_CLAUSE_CODE (expr) == OMP_CLAUSE_LINEAR) - { - gimple_seq seq = OMP_CLAUSE_LINEAR_GIMPLE_SEQ (expr); - seq = duplicate_remap_omp_clause_seq (seq, wi); - OMP_CLAUSE_LINEAR_GIMPLE_SEQ (expr) = seq; - } - else if (OMP_CLAUSE_CODE (expr) == OMP_CLAUSE_REDUCTION) - { - gimple_seq seq = OMP_CLAUSE_REDUCTION_GIMPLE_INIT (expr); - seq = duplicate_remap_omp_clause_seq (seq, wi); - OMP_CLAUSE_REDUCTION_GIMPLE_INIT (expr) = seq; - seq = OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (expr); - seq = duplicate_remap_omp_clause_seq (seq, wi); - OMP_CLAUSE_REDUCTION_GIMPLE_MERGE (expr) = seq; - } - } - - /* Keep iterating. */ - return NULL_TREE; -} - - -/* Called via walk_gimple_seq by copy_gimple_seq_and_replace_local. - Using the splay_tree pointed to by ST (which is really a `splay_tree'), - remaps all local declarations to appropriate replacements in gimple - statements. */ - -static tree -replace_locals_stmt (gimple_stmt_iterator *gsip, - bool *handled_ops_p ATTRIBUTE_UNUSED, - struct walk_stmt_info *wi) -{ - copy_body_data *id = (copy_body_data *) wi->info; - gimple *gs = gsi_stmt (*gsip); - - if (gbind *stmt = dyn_cast <gbind *> (gs)) - { - tree block = gimple_bind_block (stmt); - - if (block) - { - remap_block (&block, id); - gimple_bind_set_block (stmt, block); - } - - /* This will remap a lot of the same decls again, but this should be - harmless. */ - if (gimple_bind_vars (stmt)) - { - tree old_var, decls = gimple_bind_vars (stmt); - - for (old_var = decls; old_var; old_var = DECL_CHAIN (old_var)) - if (!can_be_nonlocal (old_var, id) - && ! variably_modified_type_p (TREE_TYPE (old_var), id->src_fn)) - remap_decl (old_var, id); - - gcc_checking_assert (!id->prevent_decl_creation_for_types); - id->prevent_decl_creation_for_types = true; - gimple_bind_set_vars (stmt, remap_decls (decls, NULL, id)); - id->prevent_decl_creation_for_types = false; - } - } - - /* Keep iterating. */ - return NULL_TREE; -} - -/* Create a copy of SEQ and remap all decls in it. */ - -static gimple_seq -duplicate_remap_omp_clause_seq (gimple_seq seq, struct walk_stmt_info *wi) -{ - if (!seq) - return NULL; - - /* If there are any labels in OMP sequences, they can be only referred to in - the sequence itself and therefore we can do both here. */ - walk_gimple_seq (seq, mark_local_labels_stmt, NULL, wi); - gimple_seq copy = gimple_seq_copy (seq); - walk_gimple_seq (copy, replace_locals_stmt, replace_locals_op, wi); - return copy; -} - -/* Copies everything in SEQ and replaces variables and labels local to - current_function_decl. */ - -gimple_seq -copy_gimple_seq_and_replace_locals (gimple_seq seq) -{ - copy_body_data id; - struct walk_stmt_info wi; - gimple_seq copy; - - /* There's nothing to do for NULL_TREE. */ - if (seq == NULL) - return seq; - - /* Set up ID. */ - memset (&id, 0, sizeof (id)); - id.src_fn = current_function_decl; - id.dst_fn = current_function_decl; - id.src_cfun = cfun; - id.decl_map = new hash_map<tree, tree>; - id.debug_map = NULL; - - id.copy_decl = copy_decl_no_change; - id.transform_call_graph_edges = CB_CGE_DUPLICATE; - id.transform_new_cfg = false; - id.transform_return_to_modify = false; - id.transform_parameter = false; - - /* Walk the tree once to find local labels. */ - memset (&wi, 0, sizeof (wi)); - hash_set<tree> visited; - wi.info = &id; - wi.pset = &visited; - walk_gimple_seq (seq, mark_local_labels_stmt, NULL, &wi); - - copy = gimple_seq_copy (seq); - - /* Walk the copy, remapping decls. */ - memset (&wi, 0, sizeof (wi)); - wi.info = &id; - walk_gimple_seq (copy, replace_locals_stmt, replace_locals_op, &wi); - - /* Clean up. */ - delete id.decl_map; - if (id.debug_map) - delete id.debug_map; - if (id.dependence_map) - { - delete id.dependence_map; - id.dependence_map = NULL; - } - - return copy; -} - - -/* Allow someone to determine if SEARCH is a child of TOP from gdb. */ - -static tree -debug_find_tree_1 (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data) -{ - if (*tp == data) - return (tree) data; - else - return NULL; -} - -DEBUG_FUNCTION bool -debug_find_tree (tree top, tree search) -{ - return walk_tree_without_duplicates (&top, debug_find_tree_1, search) != 0; -} - - -/* Declare the variables created by the inliner. Add all the variables in - VARS to BIND_EXPR. */ - -static void -declare_inline_vars (tree block, tree vars) -{ - tree t; - for (t = vars; t; t = DECL_CHAIN (t)) - { - DECL_SEEN_IN_BIND_EXPR_P (t) = 1; - gcc_assert (!TREE_STATIC (t) && !TREE_ASM_WRITTEN (t)); - add_local_decl (cfun, t); - } - - if (block) - BLOCK_VARS (block) = chainon (BLOCK_VARS (block), vars); -} - -/* Copy NODE (which must be a DECL). The DECL originally was in the FROM_FN, - but now it will be in the TO_FN. PARM_TO_VAR means enable PARM_DECL to - VAR_DECL translation. */ - -tree -copy_decl_for_dup_finish (copy_body_data *id, tree decl, tree copy) -{ - /* Don't generate debug information for the copy if we wouldn't have - generated it for the copy either. */ - DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (decl); - DECL_IGNORED_P (copy) = DECL_IGNORED_P (decl); - - /* Set the DECL_ABSTRACT_ORIGIN so the debugging routines know what - declaration inspired this copy. */ - DECL_ABSTRACT_ORIGIN (copy) = DECL_ORIGIN (decl); - - /* The new variable/label has no RTL, yet. */ - if (CODE_CONTAINS_STRUCT (TREE_CODE (copy), TS_DECL_WRTL) - && !TREE_STATIC (copy) && !DECL_EXTERNAL (copy)) - SET_DECL_RTL (copy, 0); - /* For vector typed decls make sure to update DECL_MODE according - to the new function context. */ - if (VECTOR_TYPE_P (TREE_TYPE (copy))) - SET_DECL_MODE (copy, TYPE_MODE (TREE_TYPE (copy))); - - /* These args would always appear unused, if not for this. */ - TREE_USED (copy) = 1; - - /* Set the context for the new declaration. */ - if (!DECL_CONTEXT (decl)) - /* Globals stay global. */ - ; - else if (DECL_CONTEXT (decl) != id->src_fn) - /* Things that weren't in the scope of the function we're inlining - from aren't in the scope we're inlining to, either. */ - ; - else if (TREE_STATIC (decl)) - /* Function-scoped static variables should stay in the original - function. */ - ; - else - { - /* Ordinary automatic local variables are now in the scope of the - new function. */ - DECL_CONTEXT (copy) = id->dst_fn; - if (VAR_P (copy) && id->dst_simt_vars && !is_gimple_reg (copy)) - { - if (!lookup_attribute ("omp simt private", DECL_ATTRIBUTES (copy))) - DECL_ATTRIBUTES (copy) - = tree_cons (get_identifier ("omp simt private"), NULL, - DECL_ATTRIBUTES (copy)); - id->dst_simt_vars->safe_push (copy); - } - } - - return copy; -} - -/* Create a new VAR_DECL that is indentical in all respect to DECL except that - DECL can be either a VAR_DECL, a PARM_DECL or RESULT_DECL. The original - DECL must come from ID->src_fn and the copy will be part of ID->dst_fn. */ - -tree -copy_decl_to_var (tree decl, copy_body_data *id) -{ - tree copy, type; - - gcc_assert (TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == RESULT_DECL); - - type = TREE_TYPE (decl); - - copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn), - VAR_DECL, DECL_NAME (decl), type); - if (DECL_PT_UID_SET_P (decl)) - SET_DECL_PT_UID (copy, DECL_PT_UID (decl)); - TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl); - TREE_READONLY (copy) = TREE_READONLY (decl); - TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl); - DECL_NOT_GIMPLE_REG_P (copy) = DECL_NOT_GIMPLE_REG_P (decl); - DECL_BY_REFERENCE (copy) = DECL_BY_REFERENCE (decl); - - return copy_decl_for_dup_finish (id, decl, copy); -} - -/* Like copy_decl_to_var, but create a return slot object instead of a - pointer variable for return by invisible reference. */ - -static tree -copy_result_decl_to_var (tree decl, copy_body_data *id) -{ - tree copy, type; - - gcc_assert (TREE_CODE (decl) == PARM_DECL - || TREE_CODE (decl) == RESULT_DECL); - - type = TREE_TYPE (decl); - if (DECL_BY_REFERENCE (decl)) - type = TREE_TYPE (type); - - copy = build_decl (DECL_SOURCE_LOCATION (id->dst_fn), - VAR_DECL, DECL_NAME (decl), type); - if (DECL_PT_UID_SET_P (decl)) - SET_DECL_PT_UID (copy, DECL_PT_UID (decl)); - TREE_READONLY (copy) = TREE_READONLY (decl); - TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl); - if (!DECL_BY_REFERENCE (decl)) - { - TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl); - DECL_NOT_GIMPLE_REG_P (copy) - = (DECL_NOT_GIMPLE_REG_P (decl) - /* RESULT_DECLs are treated special by needs_to_live_in_memory, - mirror that to the created VAR_DECL. */ - || (TREE_CODE (decl) == RESULT_DECL - && aggregate_value_p (decl, id->src_fn))); - } - - return copy_decl_for_dup_finish (id, decl, copy); -} - -tree -copy_decl_no_change (tree decl, copy_body_data *id) -{ - tree copy; - - copy = copy_node (decl); - - /* The COPY is not abstract; it will be generated in DST_FN. */ - DECL_ABSTRACT_P (copy) = false; - lang_hooks.dup_lang_specific_decl (copy); - - /* TREE_ADDRESSABLE isn't used to indicate that a label's address has - been taken; it's for internal bookkeeping in expand_goto_internal. */ - if (TREE_CODE (copy) == LABEL_DECL) - { - TREE_ADDRESSABLE (copy) = 0; - LABEL_DECL_UID (copy) = -1; - } - - return copy_decl_for_dup_finish (id, decl, copy); -} - -static tree -copy_decl_maybe_to_var (tree decl, copy_body_data *id) -{ - if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL) - return copy_decl_to_var (decl, id); - else - return copy_decl_no_change (decl, id); -} - -/* Return a copy of the function's argument tree without any modifications. */ - -static tree -copy_arguments_nochange (tree orig_parm, copy_body_data * id) -{ - tree arg, *parg; - tree new_parm = NULL; - - parg = &new_parm; - for (arg = orig_parm; arg; arg = DECL_CHAIN (arg)) - { - tree new_tree = remap_decl (arg, id); - if (TREE_CODE (new_tree) != PARM_DECL) - new_tree = id->copy_decl (arg, id); - lang_hooks.dup_lang_specific_decl (new_tree); - *parg = new_tree; - parg = &DECL_CHAIN (new_tree); - } - return new_parm; -} - -/* Return a copy of the function's static chain. */ -static tree -copy_static_chain (tree static_chain, copy_body_data * id) -{ - tree *chain_copy, *pvar; - - chain_copy = &static_chain; - for (pvar = chain_copy; *pvar; pvar = &DECL_CHAIN (*pvar)) - { - tree new_tree = remap_decl (*pvar, id); - lang_hooks.dup_lang_specific_decl (new_tree); - DECL_CHAIN (new_tree) = DECL_CHAIN (*pvar); - *pvar = new_tree; - } - return static_chain; -} - -/* Return true if the function is allowed to be versioned. - This is a guard for the versioning functionality. */ - -bool -tree_versionable_function_p (tree fndecl) -{ - return (!lookup_attribute ("noclone", DECL_ATTRIBUTES (fndecl)) - && copy_forbidden (DECL_STRUCT_FUNCTION (fndecl)) == NULL); -} - -/* Update clone info after duplication. */ - -static void -update_clone_info (copy_body_data * id) -{ - struct cgraph_node *this_node = id->dst_node; - if (!this_node->clones) - return; - for (cgraph_node *node = this_node->clones; node != this_node;) - { - /* First update replace maps to match the new body. */ - clone_info *info = clone_info::get (node); - if (info && info->tree_map) - { - unsigned int i; - for (i = 0; i < vec_safe_length (info->tree_map); i++) - { - struct ipa_replace_map *replace_info; - replace_info = (*info->tree_map)[i]; - walk_tree (&replace_info->new_tree, copy_tree_body_r, id, NULL); - } - } - - if (node->clones) - node = node->clones; - else if (node->next_sibling_clone) - node = node->next_sibling_clone; - else - { - while (node != id->dst_node && !node->next_sibling_clone) - node = node->clone_of; - if (node != id->dst_node) - node = node->next_sibling_clone; - } - } -} - -/* Create a copy of a function's tree. - OLD_DECL and NEW_DECL are FUNCTION_DECL tree nodes - of the original function and the new copied function - respectively. In case we want to replace a DECL - tree with another tree while duplicating the function's - body, TREE_MAP represents the mapping between these - trees. If UPDATE_CLONES is set, the call_stmt fields - of edges of clones of the function will be updated. - - If non-NULL PARAM_ADJUSTMENTS determines how function prototype (i.e. the - function parameters and return value) should be modified). - If non-NULL BLOCKS_TO_COPY determine what basic blocks to copy. - If non_NULL NEW_ENTRY determine new entry BB of the clone. -*/ -void -tree_function_versioning (tree old_decl, tree new_decl, - vec<ipa_replace_map *, va_gc> *tree_map, - ipa_param_adjustments *param_adjustments, - bool update_clones, bitmap blocks_to_copy, - basic_block new_entry) -{ - struct cgraph_node *old_version_node; - struct cgraph_node *new_version_node; - copy_body_data id; - tree p; - unsigned i; - struct ipa_replace_map *replace_info; - basic_block old_entry_block, bb; - auto_vec<gimple *, 10> init_stmts; - tree vars = NULL_TREE; - - /* We can get called recursively from expand_call_inline via clone - materialization. While expand_call_inline maintains input_location - we cannot tolerate it to leak into the materialized clone. */ - location_t saved_location = input_location; - input_location = UNKNOWN_LOCATION; - - gcc_assert (TREE_CODE (old_decl) == FUNCTION_DECL - && TREE_CODE (new_decl) == FUNCTION_DECL); - DECL_POSSIBLY_INLINED (old_decl) = 1; - - old_version_node = cgraph_node::get (old_decl); - gcc_checking_assert (old_version_node); - new_version_node = cgraph_node::get (new_decl); - gcc_checking_assert (new_version_node); - - /* Copy over debug args. */ - if (DECL_HAS_DEBUG_ARGS_P (old_decl)) - { - vec<tree, va_gc> **new_debug_args, **old_debug_args; - gcc_checking_assert (decl_debug_args_lookup (new_decl) == NULL); - DECL_HAS_DEBUG_ARGS_P (new_decl) = 0; - old_debug_args = decl_debug_args_lookup (old_decl); - if (old_debug_args) - { - new_debug_args = decl_debug_args_insert (new_decl); - *new_debug_args = vec_safe_copy (*old_debug_args); - } - } - - /* Output the inlining info for this abstract function, since it has been - inlined. If we don't do this now, we can lose the information about the - variables in the function when the blocks get blown away as soon as we - remove the cgraph node. */ - (*debug_hooks->outlining_inline_function) (old_decl); - - DECL_ARTIFICIAL (new_decl) = 1; - DECL_ABSTRACT_ORIGIN (new_decl) = DECL_ORIGIN (old_decl); - if (DECL_ORIGIN (old_decl) == old_decl) - old_version_node->used_as_abstract_origin = true; - DECL_FUNCTION_PERSONALITY (new_decl) = DECL_FUNCTION_PERSONALITY (old_decl); - - /* Prepare the data structures for the tree copy. */ - memset (&id, 0, sizeof (id)); - - /* Generate a new name for the new version. */ - id.statements_to_fold = new hash_set<gimple *>; - - id.decl_map = new hash_map<tree, tree>; - id.debug_map = NULL; - id.src_fn = old_decl; - id.dst_fn = new_decl; - id.src_node = old_version_node; - id.dst_node = new_version_node; - id.src_cfun = DECL_STRUCT_FUNCTION (old_decl); - id.blocks_to_copy = blocks_to_copy; - - id.copy_decl = copy_decl_no_change; - id.transform_call_graph_edges - = update_clones ? CB_CGE_MOVE_CLONES : CB_CGE_MOVE; - id.transform_new_cfg = true; - id.transform_return_to_modify = false; - id.transform_parameter = false; - - old_entry_block = ENTRY_BLOCK_PTR_FOR_FN - (DECL_STRUCT_FUNCTION (old_decl)); - DECL_RESULT (new_decl) = DECL_RESULT (old_decl); - DECL_ARGUMENTS (new_decl) = DECL_ARGUMENTS (old_decl); - initialize_cfun (new_decl, old_decl, - new_entry ? new_entry->count : old_entry_block->count); - new_version_node->calls_declare_variant_alt - = old_version_node->calls_declare_variant_alt; - if (DECL_STRUCT_FUNCTION (new_decl)->gimple_df) - DECL_STRUCT_FUNCTION (new_decl)->gimple_df->ipa_pta - = id.src_cfun->gimple_df->ipa_pta; - - /* Copy the function's static chain. */ - p = DECL_STRUCT_FUNCTION (old_decl)->static_chain_decl; - if (p) - DECL_STRUCT_FUNCTION (new_decl)->static_chain_decl - = copy_static_chain (p, &id); - - auto_vec<int, 16> new_param_indices; - clone_info *info = clone_info::get (old_version_node); - ipa_param_adjustments *old_param_adjustments - = info ? info->param_adjustments : NULL; - if (old_param_adjustments) - old_param_adjustments->get_updated_indices (&new_param_indices); - - /* If there's a tree_map, prepare for substitution. */ - if (tree_map) - for (i = 0; i < tree_map->length (); i++) - { - gimple *init; - replace_info = (*tree_map)[i]; - - int p = replace_info->parm_num; - if (old_param_adjustments) - p = new_param_indices[p]; - - tree parm; - for (parm = DECL_ARGUMENTS (old_decl); p; - parm = DECL_CHAIN (parm)) - p--; - gcc_assert (parm); - init = setup_one_parameter (&id, parm, replace_info->new_tree, - id.src_fn, NULL, &vars); - if (init) - init_stmts.safe_push (init); - } - - ipa_param_body_adjustments *param_body_adjs = NULL; - if (param_adjustments) - { - param_body_adjs = new ipa_param_body_adjustments (param_adjustments, - new_decl, old_decl, - &id, &vars, tree_map); - id.param_body_adjs = param_body_adjs; - DECL_ARGUMENTS (new_decl) = param_body_adjs->get_new_param_chain (); - } - else if (DECL_ARGUMENTS (old_decl) != NULL_TREE) - DECL_ARGUMENTS (new_decl) - = copy_arguments_nochange (DECL_ARGUMENTS (old_decl), &id); - - DECL_INITIAL (new_decl) = remap_blocks (DECL_INITIAL (id.src_fn), &id); - BLOCK_SUPERCONTEXT (DECL_INITIAL (new_decl)) = new_decl; - - declare_inline_vars (DECL_INITIAL (new_decl), vars); - - if (!vec_safe_is_empty (DECL_STRUCT_FUNCTION (old_decl)->local_decls)) - /* Add local vars. */ - add_local_variables (DECL_STRUCT_FUNCTION (old_decl), cfun, &id); - - if (DECL_RESULT (old_decl) == NULL_TREE) - ; - else if (param_adjustments && param_adjustments->m_skip_return - && !VOID_TYPE_P (TREE_TYPE (DECL_RESULT (old_decl)))) - { - tree resdecl_repl = copy_result_decl_to_var (DECL_RESULT (old_decl), - &id); - declare_inline_vars (NULL, resdecl_repl); - if (DECL_BY_REFERENCE (DECL_RESULT (old_decl))) - resdecl_repl = build_fold_addr_expr (resdecl_repl); - insert_decl_map (&id, DECL_RESULT (old_decl), resdecl_repl); - - DECL_RESULT (new_decl) - = build_decl (DECL_SOURCE_LOCATION (DECL_RESULT (old_decl)), - RESULT_DECL, NULL_TREE, void_type_node); - DECL_CONTEXT (DECL_RESULT (new_decl)) = new_decl; - DECL_IS_MALLOC (new_decl) = false; - cfun->returns_struct = 0; - cfun->returns_pcc_struct = 0; - } - else - { - tree old_name; - DECL_RESULT (new_decl) = remap_decl (DECL_RESULT (old_decl), &id); - lang_hooks.dup_lang_specific_decl (DECL_RESULT (new_decl)); - if (gimple_in_ssa_p (id.src_cfun) - && DECL_BY_REFERENCE (DECL_RESULT (old_decl)) - && (old_name = ssa_default_def (id.src_cfun, DECL_RESULT (old_decl)))) - { - tree new_name = make_ssa_name (DECL_RESULT (new_decl)); - insert_decl_map (&id, old_name, new_name); - SSA_NAME_DEF_STMT (new_name) = gimple_build_nop (); - set_ssa_default_def (cfun, DECL_RESULT (new_decl), new_name); - } - } - - /* Set up the destination functions loop tree. */ - if (loops_for_fn (DECL_STRUCT_FUNCTION (old_decl)) != NULL) - { - cfun->curr_properties &= ~PROP_loops; - loop_optimizer_init (AVOID_CFG_MODIFICATIONS); - cfun->curr_properties |= PROP_loops; - } - - /* Copy the Function's body. */ - copy_body (&id, ENTRY_BLOCK_PTR_FOR_FN (cfun), EXIT_BLOCK_PTR_FOR_FN (cfun), - new_entry); - - /* Renumber the lexical scoping (non-code) blocks consecutively. */ - number_blocks (new_decl); - - /* We want to create the BB unconditionally, so that the addition of - debug stmts doesn't affect BB count, which may in the end cause - codegen differences. */ - bb = split_edge (single_succ_edge (ENTRY_BLOCK_PTR_FOR_FN (cfun))); - while (init_stmts.length ()) - insert_init_stmt (&id, bb, init_stmts.pop ()); - update_clone_info (&id); - - /* Remap the nonlocal_goto_save_area, if any. */ - if (cfun->nonlocal_goto_save_area) - { - struct walk_stmt_info wi; - - memset (&wi, 0, sizeof (wi)); - wi.info = &id; - walk_tree (&cfun->nonlocal_goto_save_area, remap_gimple_op_r, &wi, NULL); - } - - /* Clean up. */ - delete id.decl_map; - if (id.debug_map) - delete id.debug_map; - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - - update_max_bb_count (); - fold_marked_statements (0, id.statements_to_fold); - delete id.statements_to_fold; - delete_unreachable_blocks_update_callgraph (id.dst_node, update_clones); - if (id.dst_node->definition) - cgraph_edge::rebuild_references (); - if (loops_state_satisfies_p (LOOPS_NEED_FIXUP)) - { - calculate_dominance_info (CDI_DOMINATORS); - fix_loop_structure (NULL); - } - update_ssa (TODO_update_ssa); - - /* After partial cloning we need to rescale frequencies, so they are - within proper range in the cloned function. */ - if (new_entry) - { - struct cgraph_edge *e; - rebuild_frequencies (); - - new_version_node->count = ENTRY_BLOCK_PTR_FOR_FN (cfun)->count; - for (e = new_version_node->callees; e; e = e->next_callee) - { - basic_block bb = gimple_bb (e->call_stmt); - e->count = bb->count; - } - for (e = new_version_node->indirect_calls; e; e = e->next_callee) - { - basic_block bb = gimple_bb (e->call_stmt); - e->count = bb->count; - } - } - - if (param_body_adjs && MAY_HAVE_DEBUG_BIND_STMTS) - { - vec<tree, va_gc> **debug_args = NULL; - unsigned int len = 0; - unsigned reset_len = param_body_adjs->m_reset_debug_decls.length (); - - for (i = 0; i < reset_len; i++) - { - tree parm = param_body_adjs->m_reset_debug_decls[i]; - gcc_assert (is_gimple_reg (parm)); - tree ddecl; - - if (debug_args == NULL) - { - debug_args = decl_debug_args_insert (new_decl); - len = vec_safe_length (*debug_args); - } - ddecl = build_debug_expr_decl (TREE_TYPE (parm)); - /* FIXME: Is setting the mode really necessary? */ - SET_DECL_MODE (ddecl, DECL_MODE (parm)); - vec_safe_push (*debug_args, DECL_ORIGIN (parm)); - vec_safe_push (*debug_args, ddecl); - } - if (debug_args != NULL) - { - /* On the callee side, add - DEBUG D#Y s=> parm - DEBUG var => D#Y - stmts to the first bb where var is a VAR_DECL created for the - optimized away parameter in DECL_INITIAL block. This hints - in the debug info that var (whole DECL_ORIGIN is the parm - PARM_DECL) is optimized away, but could be looked up at the - call site as value of D#X there. */ - gimple_stmt_iterator cgsi - = gsi_after_labels (single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun))); - gimple *def_temp; - tree var = vars; - i = vec_safe_length (*debug_args); - do - { - tree vexpr = NULL_TREE; - i -= 2; - while (var != NULL_TREE - && DECL_ABSTRACT_ORIGIN (var) != (**debug_args)[i]) - var = TREE_CHAIN (var); - if (var == NULL_TREE) - break; - tree parm = (**debug_args)[i]; - if (tree parm_ddef = ssa_default_def (id.src_cfun, parm)) - if (tree *d - = param_body_adjs->m_dead_ssa_debug_equiv.get (parm_ddef)) - vexpr = *d; - if (!vexpr) - { - vexpr = build_debug_expr_decl (TREE_TYPE (parm)); - /* FIXME: Is setting the mode really necessary? */ - SET_DECL_MODE (vexpr, DECL_MODE (parm)); - } - def_temp = gimple_build_debug_bind (var, vexpr, NULL); - gsi_insert_before (&cgsi, def_temp, GSI_NEW_STMT); - def_temp = gimple_build_debug_source_bind (vexpr, parm, NULL); - gsi_insert_before (&cgsi, def_temp, GSI_NEW_STMT); - } - while (i > len); - } - } - delete param_body_adjs; - free_dominance_info (CDI_DOMINATORS); - free_dominance_info (CDI_POST_DOMINATORS); - - gcc_assert (!id.debug_stmts.exists ()); - pop_cfun (); - input_location = saved_location; - return; -} - -/* EXP is CALL_EXPR present in a GENERIC expression tree. Try to integrate - the callee and return the inlined body on success. */ - -tree -maybe_inline_call_in_expr (tree exp) -{ - tree fn = get_callee_fndecl (exp); - - /* We can only try to inline "const" functions. */ - if (fn && TREE_READONLY (fn) && DECL_SAVED_TREE (fn)) - { - call_expr_arg_iterator iter; - copy_body_data id; - tree param, arg, t; - hash_map<tree, tree> decl_map; - - /* Remap the parameters. */ - for (param = DECL_ARGUMENTS (fn), arg = first_call_expr_arg (exp, &iter); - param; - param = DECL_CHAIN (param), arg = next_call_expr_arg (&iter)) - decl_map.put (param, arg); - - memset (&id, 0, sizeof (id)); - id.src_fn = fn; - id.dst_fn = current_function_decl; - id.src_cfun = DECL_STRUCT_FUNCTION (fn); - id.decl_map = &decl_map; - - id.copy_decl = copy_decl_no_change; - id.transform_call_graph_edges = CB_CGE_DUPLICATE; - id.transform_new_cfg = false; - id.transform_return_to_modify = true; - id.transform_parameter = true; - - /* Make sure not to unshare trees behind the front-end's back - since front-end specific mechanisms may rely on sharing. */ - id.regimplify = false; - id.do_not_unshare = true; - - /* We're not inside any EH region. */ - id.eh_lp_nr = 0; - - t = copy_tree_body (&id); - - /* We can only return something suitable for use in a GENERIC - expression tree. */ - if (TREE_CODE (t) == MODIFY_EXPR) - return TREE_OPERAND (t, 1); - } - - return NULL_TREE; -} - -/* Duplicate a type, fields and all. */ - -tree -build_duplicate_type (tree type) -{ - struct copy_body_data id; - - memset (&id, 0, sizeof (id)); - id.src_fn = current_function_decl; - id.dst_fn = current_function_decl; - id.src_cfun = cfun; - id.decl_map = new hash_map<tree, tree>; - id.debug_map = NULL; - id.copy_decl = copy_decl_no_change; - - type = remap_type_1 (type, &id); - - delete id.decl_map; - if (id.debug_map) - delete id.debug_map; - - TYPE_CANONICAL (type) = type; - - return type; -} - -/* Unshare the entire DECL_SAVED_TREE of FN and return the remapped - parameters and RESULT_DECL in PARMS and RESULT. Used by C++ constexpr - evaluation. */ - -tree -copy_fn (tree fn, tree& parms, tree& result) -{ - copy_body_data id; - tree param; - hash_map<tree, tree> decl_map; - - tree *p = &parms; - *p = NULL_TREE; - - memset (&id, 0, sizeof (id)); - id.src_fn = fn; - id.dst_fn = current_function_decl; - id.src_cfun = DECL_STRUCT_FUNCTION (fn); - id.decl_map = &decl_map; - - id.copy_decl = copy_decl_no_change; - id.transform_call_graph_edges = CB_CGE_DUPLICATE; - id.transform_new_cfg = false; - id.transform_return_to_modify = false; - id.transform_parameter = true; - - /* Make sure not to unshare trees behind the front-end's back - since front-end specific mechanisms may rely on sharing. */ - id.regimplify = false; - id.do_not_unshare = true; - id.do_not_fold = true; - - /* We're not inside any EH region. */ - id.eh_lp_nr = 0; - - /* Remap the parameters and result and return them to the caller. */ - for (param = DECL_ARGUMENTS (fn); - param; - param = DECL_CHAIN (param)) - { - *p = remap_decl (param, &id); - p = &DECL_CHAIN (*p); - } - - if (DECL_RESULT (fn)) - result = remap_decl (DECL_RESULT (fn), &id); - else - result = NULL_TREE; - - return copy_tree_body (&id); -} |