aboutsummaryrefslogtreecommitdiff
path: root/gcc/cse.c
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-01-14 16:56:44 +0100
committerMartin Liska <mliska@suse.cz>2022-01-17 22:12:04 +0100
commit5c69acb32329d49e58c26fa41ae74229a52b9106 (patch)
treeddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/cse.c
parent490e23032baaece71f2ec09fa1805064b150fbc2 (diff)
downloadgcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz
gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2
Rename .c files to .cc files.
gcc/ada/ChangeLog: * adadecode.c: Moved to... * adadecode.cc: ...here. * affinity.c: Moved to... * affinity.cc: ...here. * argv-lynxos178-raven-cert.c: Moved to... * argv-lynxos178-raven-cert.cc: ...here. * argv.c: Moved to... * argv.cc: ...here. * aux-io.c: Moved to... * aux-io.cc: ...here. * cio.c: Moved to... * cio.cc: ...here. * cstreams.c: Moved to... * cstreams.cc: ...here. * env.c: Moved to... * env.cc: ...here. * exit.c: Moved to... * exit.cc: ...here. * expect.c: Moved to... * expect.cc: ...here. * final.c: Moved to... * final.cc: ...here. * gcc-interface/cuintp.c: Moved to... * gcc-interface/cuintp.cc: ...here. * gcc-interface/decl.c: Moved to... * gcc-interface/decl.cc: ...here. * gcc-interface/misc.c: Moved to... * gcc-interface/misc.cc: ...here. * gcc-interface/targtyps.c: Moved to... * gcc-interface/targtyps.cc: ...here. * gcc-interface/trans.c: Moved to... * gcc-interface/trans.cc: ...here. * gcc-interface/utils.c: Moved to... * gcc-interface/utils.cc: ...here. * gcc-interface/utils2.c: Moved to... * gcc-interface/utils2.cc: ...here. * init.c: Moved to... * init.cc: ...here. * initialize.c: Moved to... * initialize.cc: ...here. * libgnarl/thread.c: Moved to... * libgnarl/thread.cc: ...here. * link.c: Moved to... * link.cc: ...here. * locales.c: Moved to... * locales.cc: ...here. * mkdir.c: Moved to... * mkdir.cc: ...here. * raise.c: Moved to... * raise.cc: ...here. * rtfinal.c: Moved to... * rtfinal.cc: ...here. * rtinit.c: Moved to... * rtinit.cc: ...here. * seh_init.c: Moved to... * seh_init.cc: ...here. * sigtramp-armdroid.c: Moved to... * sigtramp-armdroid.cc: ...here. * sigtramp-ios.c: Moved to... * sigtramp-ios.cc: ...here. * sigtramp-qnx.c: Moved to... * sigtramp-qnx.cc: ...here. * sigtramp-vxworks.c: Moved to... * sigtramp-vxworks.cc: ...here. * socket.c: Moved to... * socket.cc: ...here. * tracebak.c: Moved to... * tracebak.cc: ...here. * version.c: Moved to... * version.cc: ...here. * vx_stack_info.c: Moved to... * vx_stack_info.cc: ...here. gcc/ChangeLog: * adjust-alignment.c: Moved to... * adjust-alignment.cc: ...here. * alias.c: Moved to... * alias.cc: ...here. * alloc-pool.c: Moved to... * alloc-pool.cc: ...here. * asan.c: Moved to... * asan.cc: ...here. * attribs.c: Moved to... * attribs.cc: ...here. * auto-inc-dec.c: Moved to... * auto-inc-dec.cc: ...here. * auto-profile.c: Moved to... * auto-profile.cc: ...here. * bb-reorder.c: Moved to... * bb-reorder.cc: ...here. * bitmap.c: Moved to... * bitmap.cc: ...here. * btfout.c: Moved to... * btfout.cc: ...here. * builtins.c: Moved to... * builtins.cc: ...here. * caller-save.c: Moved to... * caller-save.cc: ...here. * calls.c: Moved to... * calls.cc: ...here. * ccmp.c: Moved to... * ccmp.cc: ...here. * cfg.c: Moved to... * cfg.cc: ...here. * cfganal.c: Moved to... * cfganal.cc: ...here. * cfgbuild.c: Moved to... * cfgbuild.cc: ...here. * cfgcleanup.c: Moved to... * cfgcleanup.cc: ...here. * cfgexpand.c: Moved to... * cfgexpand.cc: ...here. * cfghooks.c: Moved to... * cfghooks.cc: ...here. * cfgloop.c: Moved to... * cfgloop.cc: ...here. * cfgloopanal.c: Moved to... * cfgloopanal.cc: ...here. * cfgloopmanip.c: Moved to... * cfgloopmanip.cc: ...here. * cfgrtl.c: Moved to... * cfgrtl.cc: ...here. * cgraph.c: Moved to... * cgraph.cc: ...here. * cgraphbuild.c: Moved to... * cgraphbuild.cc: ...here. * cgraphclones.c: Moved to... * cgraphclones.cc: ...here. * cgraphunit.c: Moved to... * cgraphunit.cc: ...here. * collect-utils.c: Moved to... * collect-utils.cc: ...here. * collect2-aix.c: Moved to... * collect2-aix.cc: ...here. * collect2.c: Moved to... * collect2.cc: ...here. * combine-stack-adj.c: Moved to... * combine-stack-adj.cc: ...here. * combine.c: Moved to... * combine.cc: ...here. * common/common-targhooks.c: Moved to... * common/common-targhooks.cc: ...here. * common/config/aarch64/aarch64-common.c: Moved to... * common/config/aarch64/aarch64-common.cc: ...here. * common/config/alpha/alpha-common.c: Moved to... * common/config/alpha/alpha-common.cc: ...here. * common/config/arc/arc-common.c: Moved to... * common/config/arc/arc-common.cc: ...here. * common/config/arm/arm-common.c: Moved to... * common/config/arm/arm-common.cc: ...here. * common/config/avr/avr-common.c: Moved to... * common/config/avr/avr-common.cc: ...here. * common/config/bfin/bfin-common.c: Moved to... * common/config/bfin/bfin-common.cc: ...here. * common/config/bpf/bpf-common.c: Moved to... * common/config/bpf/bpf-common.cc: ...here. * common/config/c6x/c6x-common.c: Moved to... * common/config/c6x/c6x-common.cc: ...here. * common/config/cr16/cr16-common.c: Moved to... * common/config/cr16/cr16-common.cc: ...here. * common/config/cris/cris-common.c: Moved to... * common/config/cris/cris-common.cc: ...here. * common/config/csky/csky-common.c: Moved to... * common/config/csky/csky-common.cc: ...here. * common/config/default-common.c: Moved to... * common/config/default-common.cc: ...here. * common/config/epiphany/epiphany-common.c: Moved to... * common/config/epiphany/epiphany-common.cc: ...here. * common/config/fr30/fr30-common.c: Moved to... * common/config/fr30/fr30-common.cc: ...here. * common/config/frv/frv-common.c: Moved to... * common/config/frv/frv-common.cc: ...here. * common/config/gcn/gcn-common.c: Moved to... * common/config/gcn/gcn-common.cc: ...here. * common/config/h8300/h8300-common.c: Moved to... * common/config/h8300/h8300-common.cc: ...here. * common/config/i386/i386-common.c: Moved to... * common/config/i386/i386-common.cc: ...here. * common/config/ia64/ia64-common.c: Moved to... * common/config/ia64/ia64-common.cc: ...here. * common/config/iq2000/iq2000-common.c: Moved to... * common/config/iq2000/iq2000-common.cc: ...here. * common/config/lm32/lm32-common.c: Moved to... * common/config/lm32/lm32-common.cc: ...here. * common/config/m32r/m32r-common.c: Moved to... * common/config/m32r/m32r-common.cc: ...here. * common/config/m68k/m68k-common.c: Moved to... * common/config/m68k/m68k-common.cc: ...here. * common/config/mcore/mcore-common.c: Moved to... * common/config/mcore/mcore-common.cc: ...here. * common/config/microblaze/microblaze-common.c: Moved to... * common/config/microblaze/microblaze-common.cc: ...here. * common/config/mips/mips-common.c: Moved to... * common/config/mips/mips-common.cc: ...here. * common/config/mmix/mmix-common.c: Moved to... * common/config/mmix/mmix-common.cc: ...here. * common/config/mn10300/mn10300-common.c: Moved to... * common/config/mn10300/mn10300-common.cc: ...here. * common/config/msp430/msp430-common.c: Moved to... * common/config/msp430/msp430-common.cc: ...here. * common/config/nds32/nds32-common.c: Moved to... * common/config/nds32/nds32-common.cc: ...here. * common/config/nios2/nios2-common.c: Moved to... * common/config/nios2/nios2-common.cc: ...here. * common/config/nvptx/nvptx-common.c: Moved to... * common/config/nvptx/nvptx-common.cc: ...here. * common/config/or1k/or1k-common.c: Moved to... * common/config/or1k/or1k-common.cc: ...here. * common/config/pa/pa-common.c: Moved to... * common/config/pa/pa-common.cc: ...here. * common/config/pdp11/pdp11-common.c: Moved to... * common/config/pdp11/pdp11-common.cc: ...here. * common/config/pru/pru-common.c: Moved to... * common/config/pru/pru-common.cc: ...here. * common/config/riscv/riscv-common.c: Moved to... * common/config/riscv/riscv-common.cc: ...here. * common/config/rs6000/rs6000-common.c: Moved to... * common/config/rs6000/rs6000-common.cc: ...here. * common/config/rx/rx-common.c: Moved to... * common/config/rx/rx-common.cc: ...here. * common/config/s390/s390-common.c: Moved to... * common/config/s390/s390-common.cc: ...here. * common/config/sh/sh-common.c: Moved to... * common/config/sh/sh-common.cc: ...here. * common/config/sparc/sparc-common.c: Moved to... * common/config/sparc/sparc-common.cc: ...here. * common/config/tilegx/tilegx-common.c: Moved to... * common/config/tilegx/tilegx-common.cc: ...here. * common/config/tilepro/tilepro-common.c: Moved to... * common/config/tilepro/tilepro-common.cc: ...here. * common/config/v850/v850-common.c: Moved to... * common/config/v850/v850-common.cc: ...here. * common/config/vax/vax-common.c: Moved to... * common/config/vax/vax-common.cc: ...here. * common/config/visium/visium-common.c: Moved to... * common/config/visium/visium-common.cc: ...here. * common/config/xstormy16/xstormy16-common.c: Moved to... * common/config/xstormy16/xstormy16-common.cc: ...here. * common/config/xtensa/xtensa-common.c: Moved to... * common/config/xtensa/xtensa-common.cc: ...here. * compare-elim.c: Moved to... * compare-elim.cc: ...here. * config/aarch64/aarch64-bti-insert.c: Moved to... * config/aarch64/aarch64-bti-insert.cc: ...here. * config/aarch64/aarch64-builtins.c: Moved to... * config/aarch64/aarch64-builtins.cc: ...here. * config/aarch64/aarch64-c.c: Moved to... * config/aarch64/aarch64-c.cc: ...here. * config/aarch64/aarch64-d.c: Moved to... * config/aarch64/aarch64-d.cc: ...here. * config/aarch64/aarch64.c: Moved to... * config/aarch64/aarch64.cc: ...here. * config/aarch64/cortex-a57-fma-steering.c: Moved to... * config/aarch64/cortex-a57-fma-steering.cc: ...here. * config/aarch64/driver-aarch64.c: Moved to... * config/aarch64/driver-aarch64.cc: ...here. * config/aarch64/falkor-tag-collision-avoidance.c: Moved to... * config/aarch64/falkor-tag-collision-avoidance.cc: ...here. * config/aarch64/host-aarch64-darwin.c: Moved to... * config/aarch64/host-aarch64-darwin.cc: ...here. * config/alpha/alpha.c: Moved to... * config/alpha/alpha.cc: ...here. * config/alpha/driver-alpha.c: Moved to... * config/alpha/driver-alpha.cc: ...here. * config/arc/arc-c.c: Moved to... * config/arc/arc-c.cc: ...here. * config/arc/arc.c: Moved to... * config/arc/arc.cc: ...here. * config/arc/driver-arc.c: Moved to... * config/arc/driver-arc.cc: ...here. * config/arm/aarch-common.c: Moved to... * config/arm/aarch-common.cc: ...here. * config/arm/arm-builtins.c: Moved to... * config/arm/arm-builtins.cc: ...here. * config/arm/arm-c.c: Moved to... * config/arm/arm-c.cc: ...here. * config/arm/arm-d.c: Moved to... * config/arm/arm-d.cc: ...here. * config/arm/arm.c: Moved to... * config/arm/arm.cc: ...here. * config/arm/driver-arm.c: Moved to... * config/arm/driver-arm.cc: ...here. * config/avr/avr-c.c: Moved to... * config/avr/avr-c.cc: ...here. * config/avr/avr-devices.c: Moved to... * config/avr/avr-devices.cc: ...here. * config/avr/avr-log.c: Moved to... * config/avr/avr-log.cc: ...here. * config/avr/avr.c: Moved to... * config/avr/avr.cc: ...here. * config/avr/driver-avr.c: Moved to... * config/avr/driver-avr.cc: ...here. * config/avr/gen-avr-mmcu-specs.c: Moved to... * config/avr/gen-avr-mmcu-specs.cc: ...here. * config/avr/gen-avr-mmcu-texi.c: Moved to... * config/avr/gen-avr-mmcu-texi.cc: ...here. * config/bfin/bfin.c: Moved to... * config/bfin/bfin.cc: ...here. * config/bpf/bpf.c: Moved to... * config/bpf/bpf.cc: ...here. * config/bpf/coreout.c: Moved to... * config/bpf/coreout.cc: ...here. * config/c6x/c6x.c: Moved to... * config/c6x/c6x.cc: ...here. * config/cr16/cr16.c: Moved to... * config/cr16/cr16.cc: ...here. * config/cris/cris.c: Moved to... * config/cris/cris.cc: ...here. * config/csky/csky.c: Moved to... * config/csky/csky.cc: ...here. * config/darwin-c.c: Moved to... * config/darwin-c.cc: ...here. * config/darwin-d.c: Moved to... * config/darwin-d.cc: ...here. * config/darwin-driver.c: Moved to... * config/darwin-driver.cc: ...here. * config/darwin-f.c: Moved to... * config/darwin-f.cc: ...here. * config/darwin.c: Moved to... * config/darwin.cc: ...here. * config/default-c.c: Moved to... * config/default-c.cc: ...here. * config/default-d.c: Moved to... * config/default-d.cc: ...here. * config/dragonfly-d.c: Moved to... * config/dragonfly-d.cc: ...here. * config/epiphany/epiphany.c: Moved to... * config/epiphany/epiphany.cc: ...here. * config/epiphany/mode-switch-use.c: Moved to... * config/epiphany/mode-switch-use.cc: ...here. * config/epiphany/resolve-sw-modes.c: Moved to... * config/epiphany/resolve-sw-modes.cc: ...here. * config/fr30/fr30.c: Moved to... * config/fr30/fr30.cc: ...here. * config/freebsd-d.c: Moved to... * config/freebsd-d.cc: ...here. * config/frv/frv.c: Moved to... * config/frv/frv.cc: ...here. * config/ft32/ft32.c: Moved to... * config/ft32/ft32.cc: ...here. * config/gcn/driver-gcn.c: Moved to... * config/gcn/driver-gcn.cc: ...here. * config/gcn/gcn-run.c: Moved to... * config/gcn/gcn-run.cc: ...here. * config/gcn/gcn-tree.c: Moved to... * config/gcn/gcn-tree.cc: ...here. * config/gcn/gcn.c: Moved to... * config/gcn/gcn.cc: ...here. * config/gcn/mkoffload.c: Moved to... * config/gcn/mkoffload.cc: ...here. * config/glibc-c.c: Moved to... * config/glibc-c.cc: ...here. * config/glibc-d.c: Moved to... * config/glibc-d.cc: ...here. * config/h8300/h8300.c: Moved to... * config/h8300/h8300.cc: ...here. * config/host-darwin.c: Moved to... * config/host-darwin.cc: ...here. * config/host-hpux.c: Moved to... * config/host-hpux.cc: ...here. * config/host-linux.c: Moved to... * config/host-linux.cc: ...here. * config/host-netbsd.c: Moved to... * config/host-netbsd.cc: ...here. * config/host-openbsd.c: Moved to... * config/host-openbsd.cc: ...here. * config/host-solaris.c: Moved to... * config/host-solaris.cc: ...here. * config/i386/djgpp.c: Moved to... * config/i386/djgpp.cc: ...here. * config/i386/driver-i386.c: Moved to... * config/i386/driver-i386.cc: ...here. * config/i386/driver-mingw32.c: Moved to... * config/i386/driver-mingw32.cc: ...here. * config/i386/gnu-property.c: Moved to... * config/i386/gnu-property.cc: ...here. * config/i386/host-cygwin.c: Moved to... * config/i386/host-cygwin.cc: ...here. * config/i386/host-i386-darwin.c: Moved to... * config/i386/host-i386-darwin.cc: ...here. * config/i386/host-mingw32.c: Moved to... * config/i386/host-mingw32.cc: ...here. * config/i386/i386-builtins.c: Moved to... * config/i386/i386-builtins.cc: ...here. * config/i386/i386-c.c: Moved to... * config/i386/i386-c.cc: ...here. * config/i386/i386-d.c: Moved to... * config/i386/i386-d.cc: ...here. * config/i386/i386-expand.c: Moved to... * config/i386/i386-expand.cc: ...here. * config/i386/i386-features.c: Moved to... * config/i386/i386-features.cc: ...here. * config/i386/i386-options.c: Moved to... * config/i386/i386-options.cc: ...here. * config/i386/i386.c: Moved to... * config/i386/i386.cc: ...here. * config/i386/intelmic-mkoffload.c: Moved to... * config/i386/intelmic-mkoffload.cc: ...here. * config/i386/msformat-c.c: Moved to... * config/i386/msformat-c.cc: ...here. * config/i386/winnt-cxx.c: Moved to... * config/i386/winnt-cxx.cc: ...here. * config/i386/winnt-d.c: Moved to... * config/i386/winnt-d.cc: ...here. * config/i386/winnt-stubs.c: Moved to... * config/i386/winnt-stubs.cc: ...here. * config/i386/winnt.c: Moved to... * config/i386/winnt.cc: ...here. * config/i386/x86-tune-sched-atom.c: Moved to... * config/i386/x86-tune-sched-atom.cc: ...here. * config/i386/x86-tune-sched-bd.c: Moved to... * config/i386/x86-tune-sched-bd.cc: ...here. * config/i386/x86-tune-sched-core.c: Moved to... * config/i386/x86-tune-sched-core.cc: ...here. * config/i386/x86-tune-sched.c: Moved to... * config/i386/x86-tune-sched.cc: ...here. * config/ia64/ia64-c.c: Moved to... * config/ia64/ia64-c.cc: ...here. * config/ia64/ia64.c: Moved to... * config/ia64/ia64.cc: ...here. * config/iq2000/iq2000.c: Moved to... * config/iq2000/iq2000.cc: ...here. * config/linux.c: Moved to... * config/linux.cc: ...here. * config/lm32/lm32.c: Moved to... * config/lm32/lm32.cc: ...here. * config/m32c/m32c-pragma.c: Moved to... * config/m32c/m32c-pragma.cc: ...here. * config/m32c/m32c.c: Moved to... * config/m32c/m32c.cc: ...here. * config/m32r/m32r.c: Moved to... * config/m32r/m32r.cc: ...here. * config/m68k/m68k.c: Moved to... * config/m68k/m68k.cc: ...here. * config/mcore/mcore.c: Moved to... * config/mcore/mcore.cc: ...here. * config/microblaze/microblaze-c.c: Moved to... * config/microblaze/microblaze-c.cc: ...here. * config/microblaze/microblaze.c: Moved to... * config/microblaze/microblaze.cc: ...here. * config/mips/driver-native.c: Moved to... * config/mips/driver-native.cc: ...here. * config/mips/frame-header-opt.c: Moved to... * config/mips/frame-header-opt.cc: ...here. * config/mips/mips-d.c: Moved to... * config/mips/mips-d.cc: ...here. * config/mips/mips.c: Moved to... * config/mips/mips.cc: ...here. * config/mmix/mmix.c: Moved to... * config/mmix/mmix.cc: ...here. * config/mn10300/mn10300.c: Moved to... * config/mn10300/mn10300.cc: ...here. * config/moxie/moxie.c: Moved to... * config/moxie/moxie.cc: ...here. * config/msp430/driver-msp430.c: Moved to... * config/msp430/driver-msp430.cc: ...here. * config/msp430/msp430-c.c: Moved to... * config/msp430/msp430-c.cc: ...here. * config/msp430/msp430-devices.c: Moved to... * config/msp430/msp430-devices.cc: ...here. * config/msp430/msp430.c: Moved to... * config/msp430/msp430.cc: ...here. * config/nds32/nds32-cost.c: Moved to... * config/nds32/nds32-cost.cc: ...here. * config/nds32/nds32-fp-as-gp.c: Moved to... * config/nds32/nds32-fp-as-gp.cc: ...here. * config/nds32/nds32-intrinsic.c: Moved to... * config/nds32/nds32-intrinsic.cc: ...here. * config/nds32/nds32-isr.c: Moved to... * config/nds32/nds32-isr.cc: ...here. * config/nds32/nds32-md-auxiliary.c: Moved to... * config/nds32/nds32-md-auxiliary.cc: ...here. * config/nds32/nds32-memory-manipulation.c: Moved to... * config/nds32/nds32-memory-manipulation.cc: ...here. * config/nds32/nds32-pipelines-auxiliary.c: Moved to... * config/nds32/nds32-pipelines-auxiliary.cc: ...here. * config/nds32/nds32-predicates.c: Moved to... * config/nds32/nds32-predicates.cc: ...here. * config/nds32/nds32-relax-opt.c: Moved to... * config/nds32/nds32-relax-opt.cc: ...here. * config/nds32/nds32-utils.c: Moved to... * config/nds32/nds32-utils.cc: ...here. * config/nds32/nds32.c: Moved to... * config/nds32/nds32.cc: ...here. * config/netbsd-d.c: Moved to... * config/netbsd-d.cc: ...here. * config/netbsd.c: Moved to... * config/netbsd.cc: ...here. * config/nios2/nios2.c: Moved to... * config/nios2/nios2.cc: ...here. * config/nvptx/mkoffload.c: Moved to... * config/nvptx/mkoffload.cc: ...here. * config/nvptx/nvptx-c.c: Moved to... * config/nvptx/nvptx-c.cc: ...here. * config/nvptx/nvptx.c: Moved to... * config/nvptx/nvptx.cc: ...here. * config/openbsd-d.c: Moved to... * config/openbsd-d.cc: ...here. * config/or1k/or1k.c: Moved to... * config/or1k/or1k.cc: ...here. * config/pa/pa-d.c: Moved to... * config/pa/pa-d.cc: ...here. * config/pa/pa.c: Moved to... * config/pa/pa.cc: ...here. * config/pdp11/pdp11.c: Moved to... * config/pdp11/pdp11.cc: ...here. * config/pru/pru-passes.c: Moved to... * config/pru/pru-passes.cc: ...here. * config/pru/pru-pragma.c: Moved to... * config/pru/pru-pragma.cc: ...here. * config/pru/pru.c: Moved to... * config/pru/pru.cc: ...here. * config/riscv/riscv-builtins.c: Moved to... * config/riscv/riscv-builtins.cc: ...here. * config/riscv/riscv-c.c: Moved to... * config/riscv/riscv-c.cc: ...here. * config/riscv/riscv-d.c: Moved to... * config/riscv/riscv-d.cc: ...here. * config/riscv/riscv-shorten-memrefs.c: Moved to... * config/riscv/riscv-shorten-memrefs.cc: ...here. * config/riscv/riscv-sr.c: Moved to... * config/riscv/riscv-sr.cc: ...here. * config/riscv/riscv.c: Moved to... * config/riscv/riscv.cc: ...here. * config/rl78/rl78-c.c: Moved to... * config/rl78/rl78-c.cc: ...here. * config/rl78/rl78.c: Moved to... * config/rl78/rl78.cc: ...here. * config/rs6000/driver-rs6000.c: Moved to... * config/rs6000/driver-rs6000.cc: ...here. * config/rs6000/host-darwin.c: Moved to... * config/rs6000/host-darwin.cc: ...here. * config/rs6000/host-ppc64-darwin.c: Moved to... * config/rs6000/host-ppc64-darwin.cc: ...here. * config/rs6000/rbtree.c: Moved to... * config/rs6000/rbtree.cc: ...here. * config/rs6000/rs6000-c.c: Moved to... * config/rs6000/rs6000-c.cc: ...here. * config/rs6000/rs6000-call.c: Moved to... * config/rs6000/rs6000-call.cc: ...here. * config/rs6000/rs6000-d.c: Moved to... * config/rs6000/rs6000-d.cc: ...here. * config/rs6000/rs6000-gen-builtins.c: Moved to... * config/rs6000/rs6000-gen-builtins.cc: ...here. * config/rs6000/rs6000-linux.c: Moved to... * config/rs6000/rs6000-linux.cc: ...here. * config/rs6000/rs6000-logue.c: Moved to... * config/rs6000/rs6000-logue.cc: ...here. * config/rs6000/rs6000-p8swap.c: Moved to... * config/rs6000/rs6000-p8swap.cc: ...here. * config/rs6000/rs6000-pcrel-opt.c: Moved to... * config/rs6000/rs6000-pcrel-opt.cc: ...here. * config/rs6000/rs6000-string.c: Moved to... * config/rs6000/rs6000-string.cc: ...here. * config/rs6000/rs6000.c: Moved to... * config/rs6000/rs6000.cc: ...here. * config/rx/rx.c: Moved to... * config/rx/rx.cc: ...here. * config/s390/driver-native.c: Moved to... * config/s390/driver-native.cc: ...here. * config/s390/s390-c.c: Moved to... * config/s390/s390-c.cc: ...here. * config/s390/s390-d.c: Moved to... * config/s390/s390-d.cc: ...here. * config/s390/s390.c: Moved to... * config/s390/s390.cc: ...here. * config/sh/divtab-sh4-300.c: Moved to... * config/sh/divtab-sh4-300.cc: ...here. * config/sh/divtab-sh4.c: Moved to... * config/sh/divtab-sh4.cc: ...here. * config/sh/divtab.c: Moved to... * config/sh/divtab.cc: ...here. * config/sh/sh-c.c: Moved to... * config/sh/sh-c.cc: ...here. * config/sh/sh.c: Moved to... * config/sh/sh.cc: ...here. * config/sol2-c.c: Moved to... * config/sol2-c.cc: ...here. * config/sol2-cxx.c: Moved to... * config/sol2-cxx.cc: ...here. * config/sol2-d.c: Moved to... * config/sol2-d.cc: ...here. * config/sol2-stubs.c: Moved to... * config/sol2-stubs.cc: ...here. * config/sol2.c: Moved to... * config/sol2.cc: ...here. * config/sparc/driver-sparc.c: Moved to... * config/sparc/driver-sparc.cc: ...here. * config/sparc/sparc-c.c: Moved to... * config/sparc/sparc-c.cc: ...here. * config/sparc/sparc-d.c: Moved to... * config/sparc/sparc-d.cc: ...here. * config/sparc/sparc.c: Moved to... * config/sparc/sparc.cc: ...here. * config/stormy16/stormy16.c: Moved to... * config/stormy16/stormy16.cc: ...here. * config/tilegx/mul-tables.c: Moved to... * config/tilegx/mul-tables.cc: ...here. * config/tilegx/tilegx-c.c: Moved to... * config/tilegx/tilegx-c.cc: ...here. * config/tilegx/tilegx.c: Moved to... * config/tilegx/tilegx.cc: ...here. * config/tilepro/mul-tables.c: Moved to... * config/tilepro/mul-tables.cc: ...here. * config/tilepro/tilepro-c.c: Moved to... * config/tilepro/tilepro-c.cc: ...here. * config/tilepro/tilepro.c: Moved to... * config/tilepro/tilepro.cc: ...here. * config/v850/v850-c.c: Moved to... * config/v850/v850-c.cc: ...here. * config/v850/v850.c: Moved to... * config/v850/v850.cc: ...here. * config/vax/vax.c: Moved to... * config/vax/vax.cc: ...here. * config/visium/visium.c: Moved to... * config/visium/visium.cc: ...here. * config/vms/vms-c.c: Moved to... * config/vms/vms-c.cc: ...here. * config/vms/vms-f.c: Moved to... * config/vms/vms-f.cc: ...here. * config/vms/vms.c: Moved to... * config/vms/vms.cc: ...here. * config/vxworks-c.c: Moved to... * config/vxworks-c.cc: ...here. * config/vxworks.c: Moved to... * config/vxworks.cc: ...here. * config/winnt-c.c: Moved to... * config/winnt-c.cc: ...here. * config/xtensa/xtensa.c: Moved to... * config/xtensa/xtensa.cc: ...here. * context.c: Moved to... * context.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * coverage.c: Moved to... * coverage.cc: ...here. * cppbuiltin.c: Moved to... * cppbuiltin.cc: ...here. * cppdefault.c: Moved to... * cppdefault.cc: ...here. * cprop.c: Moved to... * cprop.cc: ...here. * cse.c: Moved to... * cse.cc: ...here. * cselib.c: Moved to... * cselib.cc: ...here. * ctfc.c: Moved to... * ctfc.cc: ...here. * ctfout.c: Moved to... * ctfout.cc: ...here. * data-streamer-in.c: Moved to... * data-streamer-in.cc: ...here. * data-streamer-out.c: Moved to... * data-streamer-out.cc: ...here. * data-streamer.c: Moved to... * data-streamer.cc: ...here. * dbgcnt.c: Moved to... * dbgcnt.cc: ...here. * dbxout.c: Moved to... * dbxout.cc: ...here. * dce.c: Moved to... * dce.cc: ...here. * ddg.c: Moved to... * ddg.cc: ...here. * debug.c: Moved to... * debug.cc: ...here. * df-core.c: Moved to... * df-core.cc: ...here. * df-problems.c: Moved to... * df-problems.cc: ...here. * df-scan.c: Moved to... * df-scan.cc: ...here. * dfp.c: Moved to... * dfp.cc: ...here. * diagnostic-color.c: Moved to... * diagnostic-color.cc: ...here. * diagnostic-show-locus.c: Moved to... * diagnostic-show-locus.cc: ...here. * diagnostic-spec.c: Moved to... * diagnostic-spec.cc: ...here. * diagnostic.c: Moved to... * diagnostic.cc: ...here. * dojump.c: Moved to... * dojump.cc: ...here. * dominance.c: Moved to... * dominance.cc: ...here. * domwalk.c: Moved to... * domwalk.cc: ...here. * double-int.c: Moved to... * double-int.cc: ...here. * dse.c: Moved to... * dse.cc: ...here. * dumpfile.c: Moved to... * dumpfile.cc: ...here. * dwarf2asm.c: Moved to... * dwarf2asm.cc: ...here. * dwarf2cfi.c: Moved to... * dwarf2cfi.cc: ...here. * dwarf2ctf.c: Moved to... * dwarf2ctf.cc: ...here. * dwarf2out.c: Moved to... * dwarf2out.cc: ...here. * early-remat.c: Moved to... * early-remat.cc: ...here. * edit-context.c: Moved to... * edit-context.cc: ...here. * emit-rtl.c: Moved to... * emit-rtl.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * et-forest.c: Moved to... * et-forest.cc: ...here. * except.c: Moved to... * except.cc: ...here. * explow.c: Moved to... * explow.cc: ...here. * expmed.c: Moved to... * expmed.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * fibonacci_heap.c: Moved to... * fibonacci_heap.cc: ...here. * file-find.c: Moved to... * file-find.cc: ...here. * file-prefix-map.c: Moved to... * file-prefix-map.cc: ...here. * final.c: Moved to... * final.cc: ...here. * fixed-value.c: Moved to... * fixed-value.cc: ...here. * fold-const-call.c: Moved to... * fold-const-call.cc: ...here. * fold-const.c: Moved to... * fold-const.cc: ...here. * fp-test.c: Moved to... * fp-test.cc: ...here. * function-tests.c: Moved to... * function-tests.cc: ...here. * function.c: Moved to... * function.cc: ...here. * fwprop.c: Moved to... * fwprop.cc: ...here. * gcc-ar.c: Moved to... * gcc-ar.cc: ...here. * gcc-main.c: Moved to... * gcc-main.cc: ...here. * gcc-rich-location.c: Moved to... * gcc-rich-location.cc: ...here. * gcc.c: Moved to... * gcc.cc: ...here. * gcov-dump.c: Moved to... * gcov-dump.cc: ...here. * gcov-io.c: Moved to... * gcov-io.cc: ...here. * gcov-tool.c: Moved to... * gcov-tool.cc: ...here. * gcov.c: Moved to... * gcov.cc: ...here. * gcse-common.c: Moved to... * gcse-common.cc: ...here. * gcse.c: Moved to... * gcse.cc: ...here. * genattr-common.c: Moved to... * genattr-common.cc: ...here. * genattr.c: Moved to... * genattr.cc: ...here. * genattrtab.c: Moved to... * genattrtab.cc: ...here. * genautomata.c: Moved to... * genautomata.cc: ...here. * gencfn-macros.c: Moved to... * gencfn-macros.cc: ...here. * gencheck.c: Moved to... * gencheck.cc: ...here. * genchecksum.c: Moved to... * genchecksum.cc: ...here. * gencodes.c: Moved to... * gencodes.cc: ...here. * genconditions.c: Moved to... * genconditions.cc: ...here. * genconfig.c: Moved to... * genconfig.cc: ...here. * genconstants.c: Moved to... * genconstants.cc: ...here. * genemit.c: Moved to... * genemit.cc: ...here. * genenums.c: Moved to... * genenums.cc: ...here. * generic-match-head.c: Moved to... * generic-match-head.cc: ...here. * genextract.c: Moved to... * genextract.cc: ...here. * genflags.c: Moved to... * genflags.cc: ...here. * gengenrtl.c: Moved to... * gengenrtl.cc: ...here. * gengtype-parse.c: Moved to... * gengtype-parse.cc: ...here. * gengtype-state.c: Moved to... * gengtype-state.cc: ...here. * gengtype.c: Moved to... * gengtype.cc: ...here. * genhooks.c: Moved to... * genhooks.cc: ...here. * genmatch.c: Moved to... * genmatch.cc: ...here. * genmddeps.c: Moved to... * genmddeps.cc: ...here. * genmddump.c: Moved to... * genmddump.cc: ...here. * genmodes.c: Moved to... * genmodes.cc: ...here. * genopinit.c: Moved to... * genopinit.cc: ...here. * genoutput.c: Moved to... * genoutput.cc: ...here. * genpeep.c: Moved to... * genpeep.cc: ...here. * genpreds.c: Moved to... * genpreds.cc: ...here. * genrecog.c: Moved to... * genrecog.cc: ...here. * gensupport.c: Moved to... * gensupport.cc: ...here. * gentarget-def.c: Moved to... * gentarget-def.cc: ...here. * genversion.c: Moved to... * genversion.cc: ...here. * ggc-common.c: Moved to... * ggc-common.cc: ...here. * ggc-none.c: Moved to... * ggc-none.cc: ...here. * ggc-page.c: Moved to... * ggc-page.cc: ...here. * ggc-tests.c: Moved to... * ggc-tests.cc: ...here. * gimple-builder.c: Moved to... * gimple-builder.cc: ...here. * gimple-expr.c: Moved to... * gimple-expr.cc: ...here. * gimple-fold.c: Moved to... * gimple-fold.cc: ...here. * gimple-iterator.c: Moved to... * gimple-iterator.cc: ...here. * gimple-laddress.c: Moved to... * gimple-laddress.cc: ...here. * gimple-loop-jam.c: Moved to... * gimple-loop-jam.cc: ...here. * gimple-low.c: Moved to... * gimple-low.cc: ...here. * gimple-match-head.c: Moved to... * gimple-match-head.cc: ...here. * gimple-pretty-print.c: Moved to... * gimple-pretty-print.cc: ...here. * gimple-ssa-backprop.c: Moved to... * gimple-ssa-backprop.cc: ...here. * gimple-ssa-evrp-analyze.c: Moved to... * gimple-ssa-evrp-analyze.cc: ...here. * gimple-ssa-evrp.c: Moved to... * gimple-ssa-evrp.cc: ...here. * gimple-ssa-isolate-paths.c: Moved to... * gimple-ssa-isolate-paths.cc: ...here. * gimple-ssa-nonnull-compare.c: Moved to... * gimple-ssa-nonnull-compare.cc: ...here. * gimple-ssa-split-paths.c: Moved to... * gimple-ssa-split-paths.cc: ...here. * gimple-ssa-sprintf.c: Moved to... * gimple-ssa-sprintf.cc: ...here. * gimple-ssa-store-merging.c: Moved to... * gimple-ssa-store-merging.cc: ...here. * gimple-ssa-strength-reduction.c: Moved to... * gimple-ssa-strength-reduction.cc: ...here. * gimple-ssa-warn-alloca.c: Moved to... * gimple-ssa-warn-alloca.cc: ...here. * gimple-ssa-warn-restrict.c: Moved to... * gimple-ssa-warn-restrict.cc: ...here. * gimple-streamer-in.c: Moved to... * gimple-streamer-in.cc: ...here. * gimple-streamer-out.c: Moved to... * gimple-streamer-out.cc: ...here. * gimple-walk.c: Moved to... * gimple-walk.cc: ...here. * gimple-warn-recursion.c: Moved to... * gimple-warn-recursion.cc: ...here. * gimple.c: Moved to... * gimple.cc: ...here. * gimplify-me.c: Moved to... * gimplify-me.cc: ...here. * gimplify.c: Moved to... * gimplify.cc: ...here. * godump.c: Moved to... * godump.cc: ...here. * graph.c: Moved to... * graph.cc: ...here. * graphds.c: Moved to... * graphds.cc: ...here. * graphite-dependences.c: Moved to... * graphite-dependences.cc: ...here. * graphite-isl-ast-to-gimple.c: Moved to... * graphite-isl-ast-to-gimple.cc: ...here. * graphite-optimize-isl.c: Moved to... * graphite-optimize-isl.cc: ...here. * graphite-poly.c: Moved to... * graphite-poly.cc: ...here. * graphite-scop-detection.c: Moved to... * graphite-scop-detection.cc: ...here. * graphite-sese-to-poly.c: Moved to... * graphite-sese-to-poly.cc: ...here. * graphite.c: Moved to... * graphite.cc: ...here. * haifa-sched.c: Moved to... * haifa-sched.cc: ...here. * hash-map-tests.c: Moved to... * hash-map-tests.cc: ...here. * hash-set-tests.c: Moved to... * hash-set-tests.cc: ...here. * hash-table.c: Moved to... * hash-table.cc: ...here. * hooks.c: Moved to... * hooks.cc: ...here. * host-default.c: Moved to... * host-default.cc: ...here. * hw-doloop.c: Moved to... * hw-doloop.cc: ...here. * hwint.c: Moved to... * hwint.cc: ...here. * ifcvt.c: Moved to... * ifcvt.cc: ...here. * inchash.c: Moved to... * inchash.cc: ...here. * incpath.c: Moved to... * incpath.cc: ...here. * init-regs.c: Moved to... * init-regs.cc: ...here. * input.c: Moved to... * input.cc: ...here. * internal-fn.c: Moved to... * internal-fn.cc: ...here. * intl.c: Moved to... * intl.cc: ...here. * ipa-comdats.c: Moved to... * ipa-comdats.cc: ...here. * ipa-cp.c: Moved to... * ipa-cp.cc: ...here. * ipa-devirt.c: Moved to... * ipa-devirt.cc: ...here. * ipa-fnsummary.c: Moved to... * ipa-fnsummary.cc: ...here. * ipa-icf-gimple.c: Moved to... * ipa-icf-gimple.cc: ...here. * ipa-icf.c: Moved to... * ipa-icf.cc: ...here. * ipa-inline-analysis.c: Moved to... * ipa-inline-analysis.cc: ...here. * ipa-inline-transform.c: Moved to... * ipa-inline-transform.cc: ...here. * ipa-inline.c: Moved to... * ipa-inline.cc: ...here. * ipa-modref-tree.c: Moved to... * ipa-modref-tree.cc: ...here. * ipa-modref.c: Moved to... * ipa-modref.cc: ...here. * ipa-param-manipulation.c: Moved to... * ipa-param-manipulation.cc: ...here. * ipa-polymorphic-call.c: Moved to... * ipa-polymorphic-call.cc: ...here. * ipa-predicate.c: Moved to... * ipa-predicate.cc: ...here. * ipa-profile.c: Moved to... * ipa-profile.cc: ...here. * ipa-prop.c: Moved to... * ipa-prop.cc: ...here. * ipa-pure-const.c: Moved to... * ipa-pure-const.cc: ...here. * ipa-ref.c: Moved to... * ipa-ref.cc: ...here. * ipa-reference.c: Moved to... * ipa-reference.cc: ...here. * ipa-split.c: Moved to... * ipa-split.cc: ...here. * ipa-sra.c: Moved to... * ipa-sra.cc: ...here. * ipa-utils.c: Moved to... * ipa-utils.cc: ...here. * ipa-visibility.c: Moved to... * ipa-visibility.cc: ...here. * ipa.c: Moved to... * ipa.cc: ...here. * ira-build.c: Moved to... * ira-build.cc: ...here. * ira-color.c: Moved to... * ira-color.cc: ...here. * ira-conflicts.c: Moved to... * ira-conflicts.cc: ...here. * ira-costs.c: Moved to... * ira-costs.cc: ...here. * ira-emit.c: Moved to... * ira-emit.cc: ...here. * ira-lives.c: Moved to... * ira-lives.cc: ...here. * ira.c: Moved to... * ira.cc: ...here. * jump.c: Moved to... * jump.cc: ...here. * langhooks.c: Moved to... * langhooks.cc: ...here. * lcm.c: Moved to... * lcm.cc: ...here. * lists.c: Moved to... * lists.cc: ...here. * loop-doloop.c: Moved to... * loop-doloop.cc: ...here. * loop-init.c: Moved to... * loop-init.cc: ...here. * loop-invariant.c: Moved to... * loop-invariant.cc: ...here. * loop-iv.c: Moved to... * loop-iv.cc: ...here. * loop-unroll.c: Moved to... * loop-unroll.cc: ...here. * lower-subreg.c: Moved to... * lower-subreg.cc: ...here. * lra-assigns.c: Moved to... * lra-assigns.cc: ...here. * lra-coalesce.c: Moved to... * lra-coalesce.cc: ...here. * lra-constraints.c: Moved to... * lra-constraints.cc: ...here. * lra-eliminations.c: Moved to... * lra-eliminations.cc: ...here. * lra-lives.c: Moved to... * lra-lives.cc: ...here. * lra-remat.c: Moved to... * lra-remat.cc: ...here. * lra-spills.c: Moved to... * lra-spills.cc: ...here. * lra.c: Moved to... * lra.cc: ...here. * lto-cgraph.c: Moved to... * lto-cgraph.cc: ...here. * lto-compress.c: Moved to... * lto-compress.cc: ...here. * lto-opts.c: Moved to... * lto-opts.cc: ...here. * lto-section-in.c: Moved to... * lto-section-in.cc: ...here. * lto-section-out.c: Moved to... * lto-section-out.cc: ...here. * lto-streamer-in.c: Moved to... * lto-streamer-in.cc: ...here. * lto-streamer-out.c: Moved to... * lto-streamer-out.cc: ...here. * lto-streamer.c: Moved to... * lto-streamer.cc: ...here. * lto-wrapper.c: Moved to... * lto-wrapper.cc: ...here. * main.c: Moved to... * main.cc: ...here. * mcf.c: Moved to... * mcf.cc: ...here. * mode-switching.c: Moved to... * mode-switching.cc: ...here. * modulo-sched.c: Moved to... * modulo-sched.cc: ...here. * multiple_target.c: Moved to... * multiple_target.cc: ...here. * omp-expand.c: Moved to... * omp-expand.cc: ...here. * omp-general.c: Moved to... * omp-general.cc: ...here. * omp-low.c: Moved to... * omp-low.cc: ...here. * omp-offload.c: Moved to... * omp-offload.cc: ...here. * omp-simd-clone.c: Moved to... * omp-simd-clone.cc: ...here. * opt-suggestions.c: Moved to... * opt-suggestions.cc: ...here. * optabs-libfuncs.c: Moved to... * optabs-libfuncs.cc: ...here. * optabs-query.c: Moved to... * optabs-query.cc: ...here. * optabs-tree.c: Moved to... * optabs-tree.cc: ...here. * optabs.c: Moved to... * optabs.cc: ...here. * opts-common.c: Moved to... * opts-common.cc: ...here. * opts-global.c: Moved to... * opts-global.cc: ...here. * opts.c: Moved to... * opts.cc: ...here. * passes.c: Moved to... * passes.cc: ...here. * plugin.c: Moved to... * plugin.cc: ...here. * postreload-gcse.c: Moved to... * postreload-gcse.cc: ...here. * postreload.c: Moved to... * postreload.cc: ...here. * predict.c: Moved to... * predict.cc: ...here. * prefix.c: Moved to... * prefix.cc: ...here. * pretty-print.c: Moved to... * pretty-print.cc: ...here. * print-rtl-function.c: Moved to... * print-rtl-function.cc: ...here. * print-rtl.c: Moved to... * print-rtl.cc: ...here. * print-tree.c: Moved to... * print-tree.cc: ...here. * profile-count.c: Moved to... * profile-count.cc: ...here. * profile.c: Moved to... * profile.cc: ...here. * read-md.c: Moved to... * read-md.cc: ...here. * read-rtl-function.c: Moved to... * read-rtl-function.cc: ...here. * read-rtl.c: Moved to... * read-rtl.cc: ...here. * real.c: Moved to... * real.cc: ...here. * realmpfr.c: Moved to... * realmpfr.cc: ...here. * recog.c: Moved to... * recog.cc: ...here. * ree.c: Moved to... * ree.cc: ...here. * reg-stack.c: Moved to... * reg-stack.cc: ...here. * regcprop.c: Moved to... * regcprop.cc: ...here. * reginfo.c: Moved to... * reginfo.cc: ...here. * regrename.c: Moved to... * regrename.cc: ...here. * regstat.c: Moved to... * regstat.cc: ...here. * reload.c: Moved to... * reload.cc: ...here. * reload1.c: Moved to... * reload1.cc: ...here. * reorg.c: Moved to... * reorg.cc: ...here. * resource.c: Moved to... * resource.cc: ...here. * rtl-error.c: Moved to... * rtl-error.cc: ...here. * rtl-tests.c: Moved to... * rtl-tests.cc: ...here. * rtl.c: Moved to... * rtl.cc: ...here. * rtlanal.c: Moved to... * rtlanal.cc: ...here. * rtlhash.c: Moved to... * rtlhash.cc: ...here. * rtlhooks.c: Moved to... * rtlhooks.cc: ...here. * rtx-vector-builder.c: Moved to... * rtx-vector-builder.cc: ...here. * run-rtl-passes.c: Moved to... * run-rtl-passes.cc: ...here. * sancov.c: Moved to... * sancov.cc: ...here. * sanopt.c: Moved to... * sanopt.cc: ...here. * sbitmap.c: Moved to... * sbitmap.cc: ...here. * sched-deps.c: Moved to... * sched-deps.cc: ...here. * sched-ebb.c: Moved to... * sched-ebb.cc: ...here. * sched-rgn.c: Moved to... * sched-rgn.cc: ...here. * sel-sched-dump.c: Moved to... * sel-sched-dump.cc: ...here. * sel-sched-ir.c: Moved to... * sel-sched-ir.cc: ...here. * sel-sched.c: Moved to... * sel-sched.cc: ...here. * selftest-diagnostic.c: Moved to... * selftest-diagnostic.cc: ...here. * selftest-rtl.c: Moved to... * selftest-rtl.cc: ...here. * selftest-run-tests.c: Moved to... * selftest-run-tests.cc: ...here. * selftest.c: Moved to... * selftest.cc: ...here. * sese.c: Moved to... * sese.cc: ...here. * shrink-wrap.c: Moved to... * shrink-wrap.cc: ...here. * simplify-rtx.c: Moved to... * simplify-rtx.cc: ...here. * sparseset.c: Moved to... * sparseset.cc: ...here. * spellcheck-tree.c: Moved to... * spellcheck-tree.cc: ...here. * spellcheck.c: Moved to... * spellcheck.cc: ...here. * sreal.c: Moved to... * sreal.cc: ...here. * stack-ptr-mod.c: Moved to... * stack-ptr-mod.cc: ...here. * statistics.c: Moved to... * statistics.cc: ...here. * stmt.c: Moved to... * stmt.cc: ...here. * stor-layout.c: Moved to... * stor-layout.cc: ...here. * store-motion.c: Moved to... * store-motion.cc: ...here. * streamer-hooks.c: Moved to... * streamer-hooks.cc: ...here. * stringpool.c: Moved to... * stringpool.cc: ...here. * substring-locations.c: Moved to... * substring-locations.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * target-globals.c: Moved to... * target-globals.cc: ...here. * targhooks.c: Moved to... * targhooks.cc: ...here. * timevar.c: Moved to... * timevar.cc: ...here. * toplev.c: Moved to... * toplev.cc: ...here. * tracer.c: Moved to... * tracer.cc: ...here. * trans-mem.c: Moved to... * trans-mem.cc: ...here. * tree-affine.c: Moved to... * tree-affine.cc: ...here. * tree-call-cdce.c: Moved to... * tree-call-cdce.cc: ...here. * tree-cfg.c: Moved to... * tree-cfg.cc: ...here. * tree-cfgcleanup.c: Moved to... * tree-cfgcleanup.cc: ...here. * tree-chrec.c: Moved to... * tree-chrec.cc: ...here. * tree-complex.c: Moved to... * tree-complex.cc: ...here. * tree-data-ref.c: Moved to... * tree-data-ref.cc: ...here. * tree-dfa.c: Moved to... * tree-dfa.cc: ...here. * tree-diagnostic.c: Moved to... * tree-diagnostic.cc: ...here. * tree-dump.c: Moved to... * tree-dump.cc: ...here. * tree-eh.c: Moved to... * tree-eh.cc: ...here. * tree-emutls.c: Moved to... * tree-emutls.cc: ...here. * tree-if-conv.c: Moved to... * tree-if-conv.cc: ...here. * tree-inline.c: Moved to... * tree-inline.cc: ...here. * tree-into-ssa.c: Moved to... * tree-into-ssa.cc: ...here. * tree-iterator.c: Moved to... * tree-iterator.cc: ...here. * tree-loop-distribution.c: Moved to... * tree-loop-distribution.cc: ...here. * tree-nested.c: Moved to... * tree-nested.cc: ...here. * tree-nrv.c: Moved to... * tree-nrv.cc: ...here. * tree-object-size.c: Moved to... * tree-object-size.cc: ...here. * tree-outof-ssa.c: Moved to... * tree-outof-ssa.cc: ...here. * tree-parloops.c: Moved to... * tree-parloops.cc: ...here. * tree-phinodes.c: Moved to... * tree-phinodes.cc: ...here. * tree-predcom.c: Moved to... * tree-predcom.cc: ...here. * tree-pretty-print.c: Moved to... * tree-pretty-print.cc: ...here. * tree-profile.c: Moved to... * tree-profile.cc: ...here. * tree-scalar-evolution.c: Moved to... * tree-scalar-evolution.cc: ...here. * tree-sra.c: Moved to... * tree-sra.cc: ...here. * tree-ssa-address.c: Moved to... * tree-ssa-address.cc: ...here. * tree-ssa-alias.c: Moved to... * tree-ssa-alias.cc: ...here. * tree-ssa-ccp.c: Moved to... * tree-ssa-ccp.cc: ...here. * tree-ssa-coalesce.c: Moved to... * tree-ssa-coalesce.cc: ...here. * tree-ssa-copy.c: Moved to... * tree-ssa-copy.cc: ...here. * tree-ssa-dce.c: Moved to... * tree-ssa-dce.cc: ...here. * tree-ssa-dom.c: Moved to... * tree-ssa-dom.cc: ...here. * tree-ssa-dse.c: Moved to... * tree-ssa-dse.cc: ...here. * tree-ssa-forwprop.c: Moved to... * tree-ssa-forwprop.cc: ...here. * tree-ssa-ifcombine.c: Moved to... * tree-ssa-ifcombine.cc: ...here. * tree-ssa-live.c: Moved to... * tree-ssa-live.cc: ...here. * tree-ssa-loop-ch.c: Moved to... * tree-ssa-loop-ch.cc: ...here. * tree-ssa-loop-im.c: Moved to... * tree-ssa-loop-im.cc: ...here. * tree-ssa-loop-ivcanon.c: Moved to... * tree-ssa-loop-ivcanon.cc: ...here. * tree-ssa-loop-ivopts.c: Moved to... * tree-ssa-loop-ivopts.cc: ...here. * tree-ssa-loop-manip.c: Moved to... * tree-ssa-loop-manip.cc: ...here. * tree-ssa-loop-niter.c: Moved to... * tree-ssa-loop-niter.cc: ...here. * tree-ssa-loop-prefetch.c: Moved to... * tree-ssa-loop-prefetch.cc: ...here. * tree-ssa-loop-split.c: Moved to... * tree-ssa-loop-split.cc: ...here. * tree-ssa-loop-unswitch.c: Moved to... * tree-ssa-loop-unswitch.cc: ...here. * tree-ssa-loop.c: Moved to... * tree-ssa-loop.cc: ...here. * tree-ssa-math-opts.c: Moved to... * tree-ssa-math-opts.cc: ...here. * tree-ssa-operands.c: Moved to... * tree-ssa-operands.cc: ...here. * tree-ssa-phiopt.c: Moved to... * tree-ssa-phiopt.cc: ...here. * tree-ssa-phiprop.c: Moved to... * tree-ssa-phiprop.cc: ...here. * tree-ssa-pre.c: Moved to... * tree-ssa-pre.cc: ...here. * tree-ssa-propagate.c: Moved to... * tree-ssa-propagate.cc: ...here. * tree-ssa-reassoc.c: Moved to... * tree-ssa-reassoc.cc: ...here. * tree-ssa-sccvn.c: Moved to... * tree-ssa-sccvn.cc: ...here. * tree-ssa-scopedtables.c: Moved to... * tree-ssa-scopedtables.cc: ...here. * tree-ssa-sink.c: Moved to... * tree-ssa-sink.cc: ...here. * tree-ssa-strlen.c: Moved to... * tree-ssa-strlen.cc: ...here. * tree-ssa-structalias.c: Moved to... * tree-ssa-structalias.cc: ...here. * tree-ssa-tail-merge.c: Moved to... * tree-ssa-tail-merge.cc: ...here. * tree-ssa-ter.c: Moved to... * tree-ssa-ter.cc: ...here. * tree-ssa-threadbackward.c: Moved to... * tree-ssa-threadbackward.cc: ...here. * tree-ssa-threadedge.c: Moved to... * tree-ssa-threadedge.cc: ...here. * tree-ssa-threadupdate.c: Moved to... * tree-ssa-threadupdate.cc: ...here. * tree-ssa-uncprop.c: Moved to... * tree-ssa-uncprop.cc: ...here. * tree-ssa-uninit.c: Moved to... * tree-ssa-uninit.cc: ...here. * tree-ssa.c: Moved to... * tree-ssa.cc: ...here. * tree-ssanames.c: Moved to... * tree-ssanames.cc: ...here. * tree-stdarg.c: Moved to... * tree-stdarg.cc: ...here. * tree-streamer-in.c: Moved to... * tree-streamer-in.cc: ...here. * tree-streamer-out.c: Moved to... * tree-streamer-out.cc: ...here. * tree-streamer.c: Moved to... * tree-streamer.cc: ...here. * tree-switch-conversion.c: Moved to... * tree-switch-conversion.cc: ...here. * tree-tailcall.c: Moved to... * tree-tailcall.cc: ...here. * tree-vect-data-refs.c: Moved to... * tree-vect-data-refs.cc: ...here. * tree-vect-generic.c: Moved to... * tree-vect-generic.cc: ...here. * tree-vect-loop-manip.c: Moved to... * tree-vect-loop-manip.cc: ...here. * tree-vect-loop.c: Moved to... * tree-vect-loop.cc: ...here. * tree-vect-patterns.c: Moved to... * tree-vect-patterns.cc: ...here. * tree-vect-slp-patterns.c: Moved to... * tree-vect-slp-patterns.cc: ...here. * tree-vect-slp.c: Moved to... * tree-vect-slp.cc: ...here. * tree-vect-stmts.c: Moved to... * tree-vect-stmts.cc: ...here. * tree-vector-builder.c: Moved to... * tree-vector-builder.cc: ...here. * tree-vectorizer.c: Moved to... * tree-vectorizer.cc: ...here. * tree-vrp.c: Moved to... * tree-vrp.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * tsan.c: Moved to... * tsan.cc: ...here. * typed-splay-tree.c: Moved to... * typed-splay-tree.cc: ...here. * ubsan.c: Moved to... * ubsan.cc: ...here. * valtrack.c: Moved to... * valtrack.cc: ...here. * value-prof.c: Moved to... * value-prof.cc: ...here. * var-tracking.c: Moved to... * var-tracking.cc: ...here. * varasm.c: Moved to... * varasm.cc: ...here. * varpool.c: Moved to... * varpool.cc: ...here. * vec-perm-indices.c: Moved to... * vec-perm-indices.cc: ...here. * vec.c: Moved to... * vec.cc: ...here. * vmsdbgout.c: Moved to... * vmsdbgout.cc: ...here. * vr-values.c: Moved to... * vr-values.cc: ...here. * vtable-verify.c: Moved to... * vtable-verify.cc: ...here. * web.c: Moved to... * web.cc: ...here. * xcoffout.c: Moved to... * xcoffout.cc: ...here. gcc/c-family/ChangeLog: * c-ada-spec.c: Moved to... * c-ada-spec.cc: ...here. * c-attribs.c: Moved to... * c-attribs.cc: ...here. * c-common.c: Moved to... * c-common.cc: ...here. * c-cppbuiltin.c: Moved to... * c-cppbuiltin.cc: ...here. * c-dump.c: Moved to... * c-dump.cc: ...here. * c-format.c: Moved to... * c-format.cc: ...here. * c-gimplify.c: Moved to... * c-gimplify.cc: ...here. * c-indentation.c: Moved to... * c-indentation.cc: ...here. * c-lex.c: Moved to... * c-lex.cc: ...here. * c-omp.c: Moved to... * c-omp.cc: ...here. * c-opts.c: Moved to... * c-opts.cc: ...here. * c-pch.c: Moved to... * c-pch.cc: ...here. * c-ppoutput.c: Moved to... * c-ppoutput.cc: ...here. * c-pragma.c: Moved to... * c-pragma.cc: ...here. * c-pretty-print.c: Moved to... * c-pretty-print.cc: ...here. * c-semantics.c: Moved to... * c-semantics.cc: ...here. * c-ubsan.c: Moved to... * c-ubsan.cc: ...here. * c-warn.c: Moved to... * c-warn.cc: ...here. * cppspec.c: Moved to... * cppspec.cc: ...here. * stub-objc.c: Moved to... * stub-objc.cc: ...here. gcc/c/ChangeLog: * c-aux-info.c: Moved to... * c-aux-info.cc: ...here. * c-convert.c: Moved to... * c-convert.cc: ...here. * c-decl.c: Moved to... * c-decl.cc: ...here. * c-errors.c: Moved to... * c-errors.cc: ...here. * c-fold.c: Moved to... * c-fold.cc: ...here. * c-lang.c: Moved to... * c-lang.cc: ...here. * c-objc-common.c: Moved to... * c-objc-common.cc: ...here. * c-parser.c: Moved to... * c-parser.cc: ...here. * c-typeck.c: Moved to... * c-typeck.cc: ...here. * gccspec.c: Moved to... * gccspec.cc: ...here. * gimple-parser.c: Moved to... * gimple-parser.cc: ...here. gcc/cp/ChangeLog: * call.c: Moved to... * call.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constexpr.c: Moved to... * constexpr.cc: ...here. * cp-gimplify.c: Moved to... * cp-gimplify.cc: ...here. * cp-lang.c: Moved to... * cp-lang.cc: ...here. * cp-objcp-common.c: Moved to... * cp-objcp-common.cc: ...here. * cp-ubsan.c: Moved to... * cp-ubsan.cc: ...here. * cvt.c: Moved to... * cvt.cc: ...here. * cxx-pretty-print.c: Moved to... * cxx-pretty-print.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * decl2.c: Moved to... * decl2.cc: ...here. * dump.c: Moved to... * dump.cc: ...here. * error.c: Moved to... * error.cc: ...here. * except.c: Moved to... * except.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * friend.c: Moved to... * friend.cc: ...here. * g++spec.c: Moved to... * g++spec.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lambda.c: Moved to... * lambda.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * mangle.c: Moved to... * mangle.cc: ...here. * method.c: Moved to... * method.cc: ...here. * name-lookup.c: Moved to... * name-lookup.cc: ...here. * optimize.c: Moved to... * optimize.cc: ...here. * parser.c: Moved to... * parser.cc: ...here. * pt.c: Moved to... * pt.cc: ...here. * ptree.c: Moved to... * ptree.cc: ...here. * rtti.c: Moved to... * rtti.cc: ...here. * search.c: Moved to... * search.cc: ...here. * semantics.c: Moved to... * semantics.cc: ...here. * tree.c: Moved to... * tree.cc: ...here. * typeck.c: Moved to... * typeck.cc: ...here. * typeck2.c: Moved to... * typeck2.cc: ...here. * vtable-class-hierarchy.c: Moved to... * vtable-class-hierarchy.cc: ...here. gcc/fortran/ChangeLog: * arith.c: Moved to... * arith.cc: ...here. * array.c: Moved to... * array.cc: ...here. * bbt.c: Moved to... * bbt.cc: ...here. * check.c: Moved to... * check.cc: ...here. * class.c: Moved to... * class.cc: ...here. * constructor.c: Moved to... * constructor.cc: ...here. * convert.c: Moved to... * convert.cc: ...here. * cpp.c: Moved to... * cpp.cc: ...here. * data.c: Moved to... * data.cc: ...here. * decl.c: Moved to... * decl.cc: ...here. * dependency.c: Moved to... * dependency.cc: ...here. * dump-parse-tree.c: Moved to... * dump-parse-tree.cc: ...here. * error.c: Moved to... * error.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * f95-lang.c: Moved to... * f95-lang.cc: ...here. * frontend-passes.c: Moved to... * frontend-passes.cc: ...here. * gfortranspec.c: Moved to... * gfortranspec.cc: ...here. * interface.c: Moved to... * interface.cc: ...here. * intrinsic.c: Moved to... * intrinsic.cc: ...here. * io.c: Moved to... * io.cc: ...here. * iresolve.c: Moved to... * iresolve.cc: ...here. * match.c: Moved to... * match.cc: ...here. * matchexp.c: Moved to... * matchexp.cc: ...here. * misc.c: Moved to... * misc.cc: ...here. * module.c: Moved to... * module.cc: ...here. * openmp.c: Moved to... * openmp.cc: ...here. * options.c: Moved to... * options.cc: ...here. * parse.c: Moved to... * parse.cc: ...here. * primary.c: Moved to... * primary.cc: ...here. * resolve.c: Moved to... * resolve.cc: ...here. * scanner.c: Moved to... * scanner.cc: ...here. * simplify.c: Moved to... * simplify.cc: ...here. * st.c: Moved to... * st.cc: ...here. * symbol.c: Moved to... * symbol.cc: ...here. * target-memory.c: Moved to... * target-memory.cc: ...here. * trans-array.c: Moved to... * trans-array.cc: ...here. * trans-common.c: Moved to... * trans-common.cc: ...here. * trans-const.c: Moved to... * trans-const.cc: ...here. * trans-decl.c: Moved to... * trans-decl.cc: ...here. * trans-expr.c: Moved to... * trans-expr.cc: ...here. * trans-intrinsic.c: Moved to... * trans-intrinsic.cc: ...here. * trans-io.c: Moved to... * trans-io.cc: ...here. * trans-openmp.c: Moved to... * trans-openmp.cc: ...here. * trans-stmt.c: Moved to... * trans-stmt.cc: ...here. * trans-types.c: Moved to... * trans-types.cc: ...here. * trans.c: Moved to... * trans.cc: ...here. gcc/go/ChangeLog: * go-backend.c: Moved to... * go-backend.cc: ...here. * go-lang.c: Moved to... * go-lang.cc: ...here. * gospec.c: Moved to... * gospec.cc: ...here. gcc/jit/ChangeLog: * dummy-frontend.c: Moved to... * dummy-frontend.cc: ...here. * jit-builtins.c: Moved to... * jit-builtins.cc: ...here. * jit-logging.c: Moved to... * jit-logging.cc: ...here. * jit-playback.c: Moved to... * jit-playback.cc: ...here. * jit-recording.c: Moved to... * jit-recording.cc: ...here. * jit-result.c: Moved to... * jit-result.cc: ...here. * jit-spec.c: Moved to... * jit-spec.cc: ...here. * jit-tempdir.c: Moved to... * jit-tempdir.cc: ...here. * jit-w32.c: Moved to... * jit-w32.cc: ...here. * libgccjit.c: Moved to... * libgccjit.cc: ...here. gcc/lto/ChangeLog: * common.c: Moved to... * common.cc: ...here. * lto-common.c: Moved to... * lto-common.cc: ...here. * lto-dump.c: Moved to... * lto-dump.cc: ...here. * lto-lang.c: Moved to... * lto-lang.cc: ...here. * lto-object.c: Moved to... * lto-object.cc: ...here. * lto-partition.c: Moved to... * lto-partition.cc: ...here. * lto-symtab.c: Moved to... * lto-symtab.cc: ...here. * lto.c: Moved to... * lto.cc: ...here. gcc/objc/ChangeLog: * objc-act.c: Moved to... * objc-act.cc: ...here. * objc-encoding.c: Moved to... * objc-encoding.cc: ...here. * objc-gnu-runtime-abi-01.c: Moved to... * objc-gnu-runtime-abi-01.cc: ...here. * objc-lang.c: Moved to... * objc-lang.cc: ...here. * objc-map.c: Moved to... * objc-map.cc: ...here. * objc-next-runtime-abi-01.c: Moved to... * objc-next-runtime-abi-01.cc: ...here. * objc-next-runtime-abi-02.c: Moved to... * objc-next-runtime-abi-02.cc: ...here. * objc-runtime-shared-support.c: Moved to... * objc-runtime-shared-support.cc: ...here. gcc/objcp/ChangeLog: * objcp-decl.c: Moved to... * objcp-decl.cc: ...here. * objcp-lang.c: Moved to... * objcp-lang.cc: ...here. libcpp/ChangeLog: * charset.c: Moved to... * charset.cc: ...here. * directives.c: Moved to... * directives.cc: ...here. * errors.c: Moved to... * errors.cc: ...here. * expr.c: Moved to... * expr.cc: ...here. * files.c: Moved to... * files.cc: ...here. * identifiers.c: Moved to... * identifiers.cc: ...here. * init.c: Moved to... * init.cc: ...here. * lex.c: Moved to... * lex.cc: ...here. * line-map.c: Moved to... * line-map.cc: ...here. * macro.c: Moved to... * macro.cc: ...here. * makeucnid.c: Moved to... * makeucnid.cc: ...here. * mkdeps.c: Moved to... * mkdeps.cc: ...here. * pch.c: Moved to... * pch.cc: ...here. * symtab.c: Moved to... * symtab.cc: ...here. * traditional.c: Moved to... * traditional.cc: ...here.
Diffstat (limited to 'gcc/cse.c')
-rw-r--r--gcc/cse.c7736
1 files changed, 0 insertions, 7736 deletions
diff --git a/gcc/cse.c b/gcc/cse.c
deleted file mode 100644
index 94acdb9..0000000
--- a/gcc/cse.c
+++ /dev/null
@@ -1,7736 +0,0 @@
-/* Common subexpression elimination for GNU compiler.
- Copyright (C) 1987-2022 Free Software Foundation, Inc.
-
-This file is part of GCC.
-
-GCC is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free
-Software Foundation; either version 3, or (at your option) any later
-version.
-
-GCC is distributed in the hope that it will be useful, but WITHOUT ANY
-WARRANTY; without even the implied warranty of MERCHANTABILITY or
-FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
-for more details.
-
-You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING3. If not see
-<http://www.gnu.org/licenses/>. */
-
-#include "config.h"
-#include "system.h"
-#include "coretypes.h"
-#include "backend.h"
-#include "target.h"
-#include "rtl.h"
-#include "tree.h"
-#include "cfghooks.h"
-#include "df.h"
-#include "memmodel.h"
-#include "tm_p.h"
-#include "insn-config.h"
-#include "regs.h"
-#include "emit-rtl.h"
-#include "recog.h"
-#include "cfgrtl.h"
-#include "cfganal.h"
-#include "cfgcleanup.h"
-#include "alias.h"
-#include "toplev.h"
-#include "rtlhooks-def.h"
-#include "tree-pass.h"
-#include "dbgcnt.h"
-#include "rtl-iter.h"
-#include "regs.h"
-#include "function-abi.h"
-#include "rtlanal.h"
-#include "expr.h"
-
-/* The basic idea of common subexpression elimination is to go
- through the code, keeping a record of expressions that would
- have the same value at the current scan point, and replacing
- expressions encountered with the cheapest equivalent expression.
-
- It is too complicated to keep track of the different possibilities
- when control paths merge in this code; so, at each label, we forget all
- that is known and start fresh. This can be described as processing each
- extended basic block separately. We have a separate pass to perform
- global CSE.
-
- Note CSE can turn a conditional or computed jump into a nop or
- an unconditional jump. When this occurs we arrange to run the jump
- optimizer after CSE to delete the unreachable code.
-
- We use two data structures to record the equivalent expressions:
- a hash table for most expressions, and a vector of "quantity
- numbers" to record equivalent (pseudo) registers.
-
- The use of the special data structure for registers is desirable
- because it is faster. It is possible because registers references
- contain a fairly small number, the register number, taken from
- a contiguously allocated series, and two register references are
- identical if they have the same number. General expressions
- do not have any such thing, so the only way to retrieve the
- information recorded on an expression other than a register
- is to keep it in a hash table.
-
-Registers and "quantity numbers":
-
- At the start of each basic block, all of the (hardware and pseudo)
- registers used in the function are given distinct quantity
- numbers to indicate their contents. During scan, when the code
- copies one register into another, we copy the quantity number.
- When a register is loaded in any other way, we allocate a new
- quantity number to describe the value generated by this operation.
- `REG_QTY (N)' records what quantity register N is currently thought
- of as containing.
-
- All real quantity numbers are greater than or equal to zero.
- If register N has not been assigned a quantity, `REG_QTY (N)' will
- equal -N - 1, which is always negative.
-
- Quantity numbers below zero do not exist and none of the `qty_table'
- entries should be referenced with a negative index.
-
- We also maintain a bidirectional chain of registers for each
- quantity number. The `qty_table` members `first_reg' and `last_reg',
- and `reg_eqv_table' members `next' and `prev' hold these chains.
-
- The first register in a chain is the one whose lifespan is least local.
- Among equals, it is the one that was seen first.
- We replace any equivalent register with that one.
-
- If two registers have the same quantity number, it must be true that
- REG expressions with qty_table `mode' must be in the hash table for both
- registers and must be in the same class.
-
- The converse is not true. Since hard registers may be referenced in
- any mode, two REG expressions might be equivalent in the hash table
- but not have the same quantity number if the quantity number of one
- of the registers is not the same mode as those expressions.
-
-Constants and quantity numbers
-
- When a quantity has a known constant value, that value is stored
- in the appropriate qty_table `const_rtx'. This is in addition to
- putting the constant in the hash table as is usual for non-regs.
-
- Whether a reg or a constant is preferred is determined by the configuration
- macro CONST_COSTS and will often depend on the constant value. In any
- event, expressions containing constants can be simplified, by fold_rtx.
-
- When a quantity has a known nearly constant value (such as an address
- of a stack slot), that value is stored in the appropriate qty_table
- `const_rtx'.
-
- Integer constants don't have a machine mode. However, cse
- determines the intended machine mode from the destination
- of the instruction that moves the constant. The machine mode
- is recorded in the hash table along with the actual RTL
- constant expression so that different modes are kept separate.
-
-Other expressions:
-
- To record known equivalences among expressions in general
- we use a hash table called `table'. It has a fixed number of buckets
- that contain chains of `struct table_elt' elements for expressions.
- These chains connect the elements whose expressions have the same
- hash codes.
-
- Other chains through the same elements connect the elements which
- currently have equivalent values.
-
- Register references in an expression are canonicalized before hashing
- the expression. This is done using `reg_qty' and qty_table `first_reg'.
- The hash code of a register reference is computed using the quantity
- number, not the register number.
-
- When the value of an expression changes, it is necessary to remove from the
- hash table not just that expression but all expressions whose values
- could be different as a result.
-
- 1. If the value changing is in memory, except in special cases
- ANYTHING referring to memory could be changed. That is because
- nobody knows where a pointer does not point.
- The function `invalidate_memory' removes what is necessary.
-
- The special cases are when the address is constant or is
- a constant plus a fixed register such as the frame pointer
- or a static chain pointer. When such addresses are stored in,
- we can tell exactly which other such addresses must be invalidated
- due to overlap. `invalidate' does this.
- All expressions that refer to non-constant
- memory addresses are also invalidated. `invalidate_memory' does this.
-
- 2. If the value changing is a register, all expressions
- containing references to that register, and only those,
- must be removed.
-
- Because searching the entire hash table for expressions that contain
- a register is very slow, we try to figure out when it isn't necessary.
- Precisely, this is necessary only when expressions have been
- entered in the hash table using this register, and then the value has
- changed, and then another expression wants to be added to refer to
- the register's new value. This sequence of circumstances is rare
- within any one basic block.
-
- `REG_TICK' and `REG_IN_TABLE', accessors for members of
- cse_reg_info, are used to detect this case. REG_TICK (i) is
- incremented whenever a value is stored in register i.
- REG_IN_TABLE (i) holds -1 if no references to register i have been
- entered in the table; otherwise, it contains the value REG_TICK (i)
- had when the references were entered. If we want to enter a
- reference and REG_IN_TABLE (i) != REG_TICK (i), we must scan and
- remove old references. Until we want to enter a new entry, the
- mere fact that the two vectors don't match makes the entries be
- ignored if anyone tries to match them.
-
- Registers themselves are entered in the hash table as well as in
- the equivalent-register chains. However, `REG_TICK' and
- `REG_IN_TABLE' do not apply to expressions which are simple
- register references. These expressions are removed from the table
- immediately when they become invalid, and this can be done even if
- we do not immediately search for all the expressions that refer to
- the register.
-
- A CLOBBER rtx in an instruction invalidates its operand for further
- reuse. A CLOBBER or SET rtx whose operand is a MEM:BLK
- invalidates everything that resides in memory.
-
-Related expressions:
-
- Constant expressions that differ only by an additive integer
- are called related. When a constant expression is put in
- the table, the related expression with no constant term
- is also entered. These are made to point at each other
- so that it is possible to find out if there exists any
- register equivalent to an expression related to a given expression. */
-
-/* Length of qty_table vector. We know in advance we will not need
- a quantity number this big. */
-
-static int max_qty;
-
-/* Next quantity number to be allocated.
- This is 1 + the largest number needed so far. */
-
-static int next_qty;
-
-/* Per-qty information tracking.
-
- `first_reg' and `last_reg' track the head and tail of the
- chain of registers which currently contain this quantity.
-
- `mode' contains the machine mode of this quantity.
-
- `const_rtx' holds the rtx of the constant value of this
- quantity, if known. A summations of the frame/arg pointer
- and a constant can also be entered here. When this holds
- a known value, `const_insn' is the insn which stored the
- constant value.
-
- `comparison_{code,const,qty}' are used to track when a
- comparison between a quantity and some constant or register has
- been passed. In such a case, we know the results of the comparison
- in case we see it again. These members record a comparison that
- is known to be true. `comparison_code' holds the rtx code of such
- a comparison, else it is set to UNKNOWN and the other two
- comparison members are undefined. `comparison_const' holds
- the constant being compared against, or zero if the comparison
- is not against a constant. `comparison_qty' holds the quantity
- being compared against when the result is known. If the comparison
- is not with a register, `comparison_qty' is -1. */
-
-struct qty_table_elem
-{
- rtx const_rtx;
- rtx_insn *const_insn;
- rtx comparison_const;
- int comparison_qty;
- unsigned int first_reg, last_reg;
- /* The sizes of these fields should match the sizes of the
- code and mode fields of struct rtx_def (see rtl.h). */
- ENUM_BITFIELD(rtx_code) comparison_code : 16;
- ENUM_BITFIELD(machine_mode) mode : 8;
-};
-
-/* The table of all qtys, indexed by qty number. */
-static struct qty_table_elem *qty_table;
-
-/* Insn being scanned. */
-
-static rtx_insn *this_insn;
-static bool optimize_this_for_speed_p;
-
-/* Index by register number, gives the number of the next (or
- previous) register in the chain of registers sharing the same
- value.
-
- Or -1 if this register is at the end of the chain.
-
- If REG_QTY (N) == -N - 1, reg_eqv_table[N].next is undefined. */
-
-/* Per-register equivalence chain. */
-struct reg_eqv_elem
-{
- int next, prev;
-};
-
-/* The table of all register equivalence chains. */
-static struct reg_eqv_elem *reg_eqv_table;
-
-struct cse_reg_info
-{
- /* The timestamp at which this register is initialized. */
- unsigned int timestamp;
-
- /* The quantity number of the register's current contents. */
- int reg_qty;
-
- /* The number of times the register has been altered in the current
- basic block. */
- int reg_tick;
-
- /* The REG_TICK value at which rtx's containing this register are
- valid in the hash table. If this does not equal the current
- reg_tick value, such expressions existing in the hash table are
- invalid. */
- int reg_in_table;
-
- /* The SUBREG that was set when REG_TICK was last incremented. Set
- to -1 if the last store was to the whole register, not a subreg. */
- unsigned int subreg_ticked;
-};
-
-/* A table of cse_reg_info indexed by register numbers. */
-static struct cse_reg_info *cse_reg_info_table;
-
-/* The size of the above table. */
-static unsigned int cse_reg_info_table_size;
-
-/* The index of the first entry that has not been initialized. */
-static unsigned int cse_reg_info_table_first_uninitialized;
-
-/* The timestamp at the beginning of the current run of
- cse_extended_basic_block. We increment this variable at the beginning of
- the current run of cse_extended_basic_block. The timestamp field of a
- cse_reg_info entry matches the value of this variable if and only
- if the entry has been initialized during the current run of
- cse_extended_basic_block. */
-static unsigned int cse_reg_info_timestamp;
-
-/* A HARD_REG_SET containing all the hard registers for which there is
- currently a REG expression in the hash table. Note the difference
- from the above variables, which indicate if the REG is mentioned in some
- expression in the table. */
-
-static HARD_REG_SET hard_regs_in_table;
-
-/* True if CSE has altered the CFG. */
-static bool cse_cfg_altered;
-
-/* True if CSE has altered conditional jump insns in such a way
- that jump optimization should be redone. */
-static bool cse_jumps_altered;
-
-/* True if we put a LABEL_REF into the hash table for an INSN
- without a REG_LABEL_OPERAND, we have to rerun jump after CSE
- to put in the note. */
-static bool recorded_label_ref;
-
-/* canon_hash stores 1 in do_not_record if it notices a reference to PC or
- some other volatile subexpression. */
-
-static int do_not_record;
-
-/* canon_hash stores 1 in hash_arg_in_memory
- if it notices a reference to memory within the expression being hashed. */
-
-static int hash_arg_in_memory;
-
-/* The hash table contains buckets which are chains of `struct table_elt's,
- each recording one expression's information.
- That expression is in the `exp' field.
-
- The canon_exp field contains a canonical (from the point of view of
- alias analysis) version of the `exp' field.
-
- Those elements with the same hash code are chained in both directions
- through the `next_same_hash' and `prev_same_hash' fields.
-
- Each set of expressions with equivalent values
- are on a two-way chain through the `next_same_value'
- and `prev_same_value' fields, and all point with
- the `first_same_value' field at the first element in
- that chain. The chain is in order of increasing cost.
- Each element's cost value is in its `cost' field.
-
- The `in_memory' field is nonzero for elements that
- involve any reference to memory. These elements are removed
- whenever a write is done to an unidentified location in memory.
- To be safe, we assume that a memory address is unidentified unless
- the address is either a symbol constant or a constant plus
- the frame pointer or argument pointer.
-
- The `related_value' field is used to connect related expressions
- (that differ by adding an integer).
- The related expressions are chained in a circular fashion.
- `related_value' is zero for expressions for which this
- chain is not useful.
-
- The `cost' field stores the cost of this element's expression.
- The `regcost' field stores the value returned by approx_reg_cost for
- this element's expression.
-
- The `is_const' flag is set if the element is a constant (including
- a fixed address).
-
- The `flag' field is used as a temporary during some search routines.
-
- The `mode' field is usually the same as GET_MODE (`exp'), but
- if `exp' is a CONST_INT and has no machine mode then the `mode'
- field is the mode it was being used as. Each constant is
- recorded separately for each mode it is used with. */
-
-struct table_elt
-{
- rtx exp;
- rtx canon_exp;
- struct table_elt *next_same_hash;
- struct table_elt *prev_same_hash;
- struct table_elt *next_same_value;
- struct table_elt *prev_same_value;
- struct table_elt *first_same_value;
- struct table_elt *related_value;
- int cost;
- int regcost;
- /* The size of this field should match the size
- of the mode field of struct rtx_def (see rtl.h). */
- ENUM_BITFIELD(machine_mode) mode : 8;
- char in_memory;
- char is_const;
- char flag;
-};
-
-/* We don't want a lot of buckets, because we rarely have very many
- things stored in the hash table, and a lot of buckets slows
- down a lot of loops that happen frequently. */
-#define HASH_SHIFT 5
-#define HASH_SIZE (1 << HASH_SHIFT)
-#define HASH_MASK (HASH_SIZE - 1)
-
-/* Compute hash code of X in mode M. Special-case case where X is a pseudo
- register (hard registers may require `do_not_record' to be set). */
-
-#define HASH(X, M) \
- ((REG_P (X) && REGNO (X) >= FIRST_PSEUDO_REGISTER \
- ? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X))) \
- : canon_hash (X, M)) & HASH_MASK)
-
-/* Like HASH, but without side-effects. */
-#define SAFE_HASH(X, M) \
- ((REG_P (X) && REGNO (X) >= FIRST_PSEUDO_REGISTER \
- ? (((unsigned) REG << 7) + (unsigned) REG_QTY (REGNO (X))) \
- : safe_hash (X, M)) & HASH_MASK)
-
-/* Determine whether register number N is considered a fixed register for the
- purpose of approximating register costs.
- It is desirable to replace other regs with fixed regs, to reduce need for
- non-fixed hard regs.
- A reg wins if it is either the frame pointer or designated as fixed. */
-#define FIXED_REGNO_P(N) \
- ((N) == FRAME_POINTER_REGNUM || (N) == HARD_FRAME_POINTER_REGNUM \
- || fixed_regs[N] || global_regs[N])
-
-/* Compute cost of X, as stored in the `cost' field of a table_elt. Fixed
- hard registers and pointers into the frame are the cheapest with a cost
- of 0. Next come pseudos with a cost of one and other hard registers with
- a cost of 2. Aside from these special cases, call `rtx_cost'. */
-
-#define CHEAP_REGNO(N) \
- (REGNO_PTR_FRAME_P (N) \
- || (HARD_REGISTER_NUM_P (N) \
- && FIXED_REGNO_P (N) && REGNO_REG_CLASS (N) != NO_REGS))
-
-#define COST(X, MODE) \
- (REG_P (X) ? 0 : notreg_cost (X, MODE, SET, 1))
-#define COST_IN(X, MODE, OUTER, OPNO) \
- (REG_P (X) ? 0 : notreg_cost (X, MODE, OUTER, OPNO))
-
-/* Get the number of times this register has been updated in this
- basic block. */
-
-#define REG_TICK(N) (get_cse_reg_info (N)->reg_tick)
-
-/* Get the point at which REG was recorded in the table. */
-
-#define REG_IN_TABLE(N) (get_cse_reg_info (N)->reg_in_table)
-
-/* Get the SUBREG set at the last increment to REG_TICK (-1 if not a
- SUBREG). */
-
-#define SUBREG_TICKED(N) (get_cse_reg_info (N)->subreg_ticked)
-
-/* Get the quantity number for REG. */
-
-#define REG_QTY(N) (get_cse_reg_info (N)->reg_qty)
-
-/* Determine if the quantity number for register X represents a valid index
- into the qty_table. */
-
-#define REGNO_QTY_VALID_P(N) (REG_QTY (N) >= 0)
-
-/* Compare table_elt X and Y and return true iff X is cheaper than Y. */
-
-#define CHEAPER(X, Y) \
- (preferable ((X)->cost, (X)->regcost, (Y)->cost, (Y)->regcost) < 0)
-
-static struct table_elt *table[HASH_SIZE];
-
-/* Chain of `struct table_elt's made so far for this function
- but currently removed from the table. */
-
-static struct table_elt *free_element_chain;
-
-/* Trace a patch through the CFG. */
-
-struct branch_path
-{
- /* The basic block for this path entry. */
- basic_block bb;
-};
-
-/* This data describes a block that will be processed by
- cse_extended_basic_block. */
-
-struct cse_basic_block_data
-{
- /* Total number of SETs in block. */
- int nsets;
- /* Size of current branch path, if any. */
- int path_size;
- /* Current path, indicating which basic_blocks will be processed. */
- struct branch_path *path;
-};
-
-
-/* Pointers to the live in/live out bitmaps for the boundaries of the
- current EBB. */
-static bitmap cse_ebb_live_in, cse_ebb_live_out;
-
-/* A simple bitmap to track which basic blocks have been visited
- already as part of an already processed extended basic block. */
-static sbitmap cse_visited_basic_blocks;
-
-static bool fixed_base_plus_p (rtx x);
-static int notreg_cost (rtx, machine_mode, enum rtx_code, int);
-static int preferable (int, int, int, int);
-static void new_basic_block (void);
-static void make_new_qty (unsigned int, machine_mode);
-static void make_regs_eqv (unsigned int, unsigned int);
-static void delete_reg_equiv (unsigned int);
-static int mention_regs (rtx);
-static int insert_regs (rtx, struct table_elt *, int);
-static void remove_from_table (struct table_elt *, unsigned);
-static void remove_pseudo_from_table (rtx, unsigned);
-static struct table_elt *lookup (rtx, unsigned, machine_mode);
-static struct table_elt *lookup_for_remove (rtx, unsigned, machine_mode);
-static rtx lookup_as_function (rtx, enum rtx_code);
-static struct table_elt *insert_with_costs (rtx, struct table_elt *, unsigned,
- machine_mode, int, int);
-static struct table_elt *insert (rtx, struct table_elt *, unsigned,
- machine_mode);
-static void merge_equiv_classes (struct table_elt *, struct table_elt *);
-static void invalidate (rtx, machine_mode);
-static void remove_invalid_refs (unsigned int);
-static void remove_invalid_subreg_refs (unsigned int, poly_uint64,
- machine_mode);
-static void rehash_using_reg (rtx);
-static void invalidate_memory (void);
-static rtx use_related_value (rtx, struct table_elt *);
-
-static inline unsigned canon_hash (rtx, machine_mode);
-static inline unsigned safe_hash (rtx, machine_mode);
-static inline unsigned hash_rtx_string (const char *);
-
-static rtx canon_reg (rtx, rtx_insn *);
-static enum rtx_code find_comparison_args (enum rtx_code, rtx *, rtx *,
- machine_mode *,
- machine_mode *);
-static rtx fold_rtx (rtx, rtx_insn *);
-static rtx equiv_constant (rtx);
-static void record_jump_equiv (rtx_insn *, bool);
-static void record_jump_cond (enum rtx_code, machine_mode, rtx, rtx,
- int);
-static void cse_insn (rtx_insn *);
-static void cse_prescan_path (struct cse_basic_block_data *);
-static void invalidate_from_clobbers (rtx_insn *);
-static void invalidate_from_sets_and_clobbers (rtx_insn *);
-static void cse_extended_basic_block (struct cse_basic_block_data *);
-extern void dump_class (struct table_elt*);
-static void get_cse_reg_info_1 (unsigned int regno);
-static struct cse_reg_info * get_cse_reg_info (unsigned int regno);
-
-static void flush_hash_table (void);
-static bool insn_live_p (rtx_insn *, int *);
-static bool set_live_p (rtx, int *);
-static void cse_change_cc_mode_insn (rtx_insn *, rtx);
-static void cse_change_cc_mode_insns (rtx_insn *, rtx_insn *, rtx);
-static machine_mode cse_cc_succs (basic_block, basic_block, rtx, rtx,
- bool);
-
-
-#undef RTL_HOOKS_GEN_LOWPART
-#define RTL_HOOKS_GEN_LOWPART gen_lowpart_if_possible
-
-static const struct rtl_hooks cse_rtl_hooks = RTL_HOOKS_INITIALIZER;
-
-/* Nonzero if X has the form (PLUS frame-pointer integer). */
-
-static bool
-fixed_base_plus_p (rtx x)
-{
- switch (GET_CODE (x))
- {
- case REG:
- if (x == frame_pointer_rtx || x == hard_frame_pointer_rtx)
- return true;
- if (x == arg_pointer_rtx && fixed_regs[ARG_POINTER_REGNUM])
- return true;
- return false;
-
- case PLUS:
- if (!CONST_INT_P (XEXP (x, 1)))
- return false;
- return fixed_base_plus_p (XEXP (x, 0));
-
- default:
- return false;
- }
-}
-
-/* Dump the expressions in the equivalence class indicated by CLASSP.
- This function is used only for debugging. */
-DEBUG_FUNCTION void
-dump_class (struct table_elt *classp)
-{
- struct table_elt *elt;
-
- fprintf (stderr, "Equivalence chain for ");
- print_rtl (stderr, classp->exp);
- fprintf (stderr, ": \n");
-
- for (elt = classp->first_same_value; elt; elt = elt->next_same_value)
- {
- print_rtl (stderr, elt->exp);
- fprintf (stderr, "\n");
- }
-}
-
-/* Return an estimate of the cost of the registers used in an rtx.
- This is mostly the number of different REG expressions in the rtx;
- however for some exceptions like fixed registers we use a cost of
- 0. If any other hard register reference occurs, return MAX_COST. */
-
-static int
-approx_reg_cost (const_rtx x)
-{
- int cost = 0;
- subrtx_iterator::array_type array;
- FOR_EACH_SUBRTX (iter, array, x, NONCONST)
- {
- const_rtx x = *iter;
- if (REG_P (x))
- {
- unsigned int regno = REGNO (x);
- if (!CHEAP_REGNO (regno))
- {
- if (regno < FIRST_PSEUDO_REGISTER)
- {
- if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
- return MAX_COST;
- cost += 2;
- }
- else
- cost += 1;
- }
- }
- }
- return cost;
-}
-
-/* Return a negative value if an rtx A, whose costs are given by COST_A
- and REGCOST_A, is more desirable than an rtx B.
- Return a positive value if A is less desirable, or 0 if the two are
- equally good. */
-static int
-preferable (int cost_a, int regcost_a, int cost_b, int regcost_b)
-{
- /* First, get rid of cases involving expressions that are entirely
- unwanted. */
- if (cost_a != cost_b)
- {
- if (cost_a == MAX_COST)
- return 1;
- if (cost_b == MAX_COST)
- return -1;
- }
-
- /* Avoid extending lifetimes of hardregs. */
- if (regcost_a != regcost_b)
- {
- if (regcost_a == MAX_COST)
- return 1;
- if (regcost_b == MAX_COST)
- return -1;
- }
-
- /* Normal operation costs take precedence. */
- if (cost_a != cost_b)
- return cost_a - cost_b;
- /* Only if these are identical consider effects on register pressure. */
- if (regcost_a != regcost_b)
- return regcost_a - regcost_b;
- return 0;
-}
-
-/* Internal function, to compute cost when X is not a register; called
- from COST macro to keep it simple. */
-
-static int
-notreg_cost (rtx x, machine_mode mode, enum rtx_code outer, int opno)
-{
- scalar_int_mode int_mode, inner_mode;
- return ((GET_CODE (x) == SUBREG
- && REG_P (SUBREG_REG (x))
- && is_int_mode (mode, &int_mode)
- && is_int_mode (GET_MODE (SUBREG_REG (x)), &inner_mode)
- && GET_MODE_SIZE (int_mode) < GET_MODE_SIZE (inner_mode)
- && subreg_lowpart_p (x)
- && TRULY_NOOP_TRUNCATION_MODES_P (int_mode, inner_mode))
- ? 0
- : rtx_cost (x, mode, outer, opno, optimize_this_for_speed_p) * 2);
-}
-
-
-/* Initialize CSE_REG_INFO_TABLE. */
-
-static void
-init_cse_reg_info (unsigned int nregs)
-{
- /* Do we need to grow the table? */
- if (nregs > cse_reg_info_table_size)
- {
- unsigned int new_size;
-
- if (cse_reg_info_table_size < 2048)
- {
- /* Compute a new size that is a power of 2 and no smaller
- than the large of NREGS and 64. */
- new_size = (cse_reg_info_table_size
- ? cse_reg_info_table_size : 64);
-
- while (new_size < nregs)
- new_size *= 2;
- }
- else
- {
- /* If we need a big table, allocate just enough to hold
- NREGS registers. */
- new_size = nregs;
- }
-
- /* Reallocate the table with NEW_SIZE entries. */
- free (cse_reg_info_table);
- cse_reg_info_table = XNEWVEC (struct cse_reg_info, new_size);
- cse_reg_info_table_size = new_size;
- cse_reg_info_table_first_uninitialized = 0;
- }
-
- /* Do we have all of the first NREGS entries initialized? */
- if (cse_reg_info_table_first_uninitialized < nregs)
- {
- unsigned int old_timestamp = cse_reg_info_timestamp - 1;
- unsigned int i;
-
- /* Put the old timestamp on newly allocated entries so that they
- will all be considered out of date. We do not touch those
- entries beyond the first NREGS entries to be nice to the
- virtual memory. */
- for (i = cse_reg_info_table_first_uninitialized; i < nregs; i++)
- cse_reg_info_table[i].timestamp = old_timestamp;
-
- cse_reg_info_table_first_uninitialized = nregs;
- }
-}
-
-/* Given REGNO, initialize the cse_reg_info entry for REGNO. */
-
-static void
-get_cse_reg_info_1 (unsigned int regno)
-{
- /* Set TIMESTAMP field to CSE_REG_INFO_TIMESTAMP so that this
- entry will be considered to have been initialized. */
- cse_reg_info_table[regno].timestamp = cse_reg_info_timestamp;
-
- /* Initialize the rest of the entry. */
- cse_reg_info_table[regno].reg_tick = 1;
- cse_reg_info_table[regno].reg_in_table = -1;
- cse_reg_info_table[regno].subreg_ticked = -1;
- cse_reg_info_table[regno].reg_qty = -regno - 1;
-}
-
-/* Find a cse_reg_info entry for REGNO. */
-
-static inline struct cse_reg_info *
-get_cse_reg_info (unsigned int regno)
-{
- struct cse_reg_info *p = &cse_reg_info_table[regno];
-
- /* If this entry has not been initialized, go ahead and initialize
- it. */
- if (p->timestamp != cse_reg_info_timestamp)
- get_cse_reg_info_1 (regno);
-
- return p;
-}
-
-/* Clear the hash table and initialize each register with its own quantity,
- for a new basic block. */
-
-static void
-new_basic_block (void)
-{
- int i;
-
- next_qty = 0;
-
- /* Invalidate cse_reg_info_table. */
- cse_reg_info_timestamp++;
-
- /* Clear out hash table state for this pass. */
- CLEAR_HARD_REG_SET (hard_regs_in_table);
-
- /* The per-quantity values used to be initialized here, but it is
- much faster to initialize each as it is made in `make_new_qty'. */
-
- for (i = 0; i < HASH_SIZE; i++)
- {
- struct table_elt *first;
-
- first = table[i];
- if (first != NULL)
- {
- struct table_elt *last = first;
-
- table[i] = NULL;
-
- while (last->next_same_hash != NULL)
- last = last->next_same_hash;
-
- /* Now relink this hash entire chain into
- the free element list. */
-
- last->next_same_hash = free_element_chain;
- free_element_chain = first;
- }
- }
-}
-
-/* Say that register REG contains a quantity in mode MODE not in any
- register before and initialize that quantity. */
-
-static void
-make_new_qty (unsigned int reg, machine_mode mode)
-{
- int q;
- struct qty_table_elem *ent;
- struct reg_eqv_elem *eqv;
-
- gcc_assert (next_qty < max_qty);
-
- q = REG_QTY (reg) = next_qty++;
- ent = &qty_table[q];
- ent->first_reg = reg;
- ent->last_reg = reg;
- ent->mode = mode;
- ent->const_rtx = ent->const_insn = NULL;
- ent->comparison_code = UNKNOWN;
-
- eqv = &reg_eqv_table[reg];
- eqv->next = eqv->prev = -1;
-}
-
-/* Make reg NEW equivalent to reg OLD.
- OLD is not changing; NEW is. */
-
-static void
-make_regs_eqv (unsigned int new_reg, unsigned int old_reg)
-{
- unsigned int lastr, firstr;
- int q = REG_QTY (old_reg);
- struct qty_table_elem *ent;
-
- ent = &qty_table[q];
-
- /* Nothing should become eqv until it has a "non-invalid" qty number. */
- gcc_assert (REGNO_QTY_VALID_P (old_reg));
-
- REG_QTY (new_reg) = q;
- firstr = ent->first_reg;
- lastr = ent->last_reg;
-
- /* Prefer fixed hard registers to anything. Prefer pseudo regs to other
- hard regs. Among pseudos, if NEW will live longer than any other reg
- of the same qty, and that is beyond the current basic block,
- make it the new canonical replacement for this qty. */
- if (! (firstr < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (firstr))
- /* Certain fixed registers might be of the class NO_REGS. This means
- that not only can they not be allocated by the compiler, but
- they cannot be used in substitutions or canonicalizations
- either. */
- && (new_reg >= FIRST_PSEUDO_REGISTER || REGNO_REG_CLASS (new_reg) != NO_REGS)
- && ((new_reg < FIRST_PSEUDO_REGISTER && FIXED_REGNO_P (new_reg))
- || (new_reg >= FIRST_PSEUDO_REGISTER
- && (firstr < FIRST_PSEUDO_REGISTER
- || (bitmap_bit_p (cse_ebb_live_out, new_reg)
- && !bitmap_bit_p (cse_ebb_live_out, firstr))
- || (bitmap_bit_p (cse_ebb_live_in, new_reg)
- && !bitmap_bit_p (cse_ebb_live_in, firstr))))))
- {
- reg_eqv_table[firstr].prev = new_reg;
- reg_eqv_table[new_reg].next = firstr;
- reg_eqv_table[new_reg].prev = -1;
- ent->first_reg = new_reg;
- }
- else
- {
- /* If NEW is a hard reg (known to be non-fixed), insert at end.
- Otherwise, insert before any non-fixed hard regs that are at the
- end. Registers of class NO_REGS cannot be used as an
- equivalent for anything. */
- while (lastr < FIRST_PSEUDO_REGISTER && reg_eqv_table[lastr].prev >= 0
- && (REGNO_REG_CLASS (lastr) == NO_REGS || ! FIXED_REGNO_P (lastr))
- && new_reg >= FIRST_PSEUDO_REGISTER)
- lastr = reg_eqv_table[lastr].prev;
- reg_eqv_table[new_reg].next = reg_eqv_table[lastr].next;
- if (reg_eqv_table[lastr].next >= 0)
- reg_eqv_table[reg_eqv_table[lastr].next].prev = new_reg;
- else
- qty_table[q].last_reg = new_reg;
- reg_eqv_table[lastr].next = new_reg;
- reg_eqv_table[new_reg].prev = lastr;
- }
-}
-
-/* Remove REG from its equivalence class. */
-
-static void
-delete_reg_equiv (unsigned int reg)
-{
- struct qty_table_elem *ent;
- int q = REG_QTY (reg);
- int p, n;
-
- /* If invalid, do nothing. */
- if (! REGNO_QTY_VALID_P (reg))
- return;
-
- ent = &qty_table[q];
-
- p = reg_eqv_table[reg].prev;
- n = reg_eqv_table[reg].next;
-
- if (n != -1)
- reg_eqv_table[n].prev = p;
- else
- ent->last_reg = p;
- if (p != -1)
- reg_eqv_table[p].next = n;
- else
- ent->first_reg = n;
-
- REG_QTY (reg) = -reg - 1;
-}
-
-/* Remove any invalid expressions from the hash table
- that refer to any of the registers contained in expression X.
-
- Make sure that newly inserted references to those registers
- as subexpressions will be considered valid.
-
- mention_regs is not called when a register itself
- is being stored in the table.
-
- Return 1 if we have done something that may have changed the hash code
- of X. */
-
-static int
-mention_regs (rtx x)
-{
- enum rtx_code code;
- int i, j;
- const char *fmt;
- int changed = 0;
-
- if (x == 0)
- return 0;
-
- code = GET_CODE (x);
- if (code == REG)
- {
- unsigned int regno = REGNO (x);
- unsigned int endregno = END_REGNO (x);
- unsigned int i;
-
- for (i = regno; i < endregno; i++)
- {
- if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
- remove_invalid_refs (i);
-
- REG_IN_TABLE (i) = REG_TICK (i);
- SUBREG_TICKED (i) = -1;
- }
-
- return 0;
- }
-
- /* If this is a SUBREG, we don't want to discard other SUBREGs of the same
- pseudo if they don't use overlapping words. We handle only pseudos
- here for simplicity. */
- if (code == SUBREG && REG_P (SUBREG_REG (x))
- && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER)
- {
- unsigned int i = REGNO (SUBREG_REG (x));
-
- if (REG_IN_TABLE (i) >= 0 && REG_IN_TABLE (i) != REG_TICK (i))
- {
- /* If REG_IN_TABLE (i) differs from REG_TICK (i) by one, and
- the last store to this register really stored into this
- subreg, then remove the memory of this subreg.
- Otherwise, remove any memory of the entire register and
- all its subregs from the table. */
- if (REG_TICK (i) - REG_IN_TABLE (i) > 1
- || SUBREG_TICKED (i) != REGNO (SUBREG_REG (x)))
- remove_invalid_refs (i);
- else
- remove_invalid_subreg_refs (i, SUBREG_BYTE (x), GET_MODE (x));
- }
-
- REG_IN_TABLE (i) = REG_TICK (i);
- SUBREG_TICKED (i) = REGNO (SUBREG_REG (x));
- return 0;
- }
-
- /* If X is a comparison or a COMPARE and either operand is a register
- that does not have a quantity, give it one. This is so that a later
- call to record_jump_equiv won't cause X to be assigned a different
- hash code and not found in the table after that call.
-
- It is not necessary to do this here, since rehash_using_reg can
- fix up the table later, but doing this here eliminates the need to
- call that expensive function in the most common case where the only
- use of the register is in the comparison. */
-
- if (code == COMPARE || COMPARISON_P (x))
- {
- if (REG_P (XEXP (x, 0))
- && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 0))))
- if (insert_regs (XEXP (x, 0), NULL, 0))
- {
- rehash_using_reg (XEXP (x, 0));
- changed = 1;
- }
-
- if (REG_P (XEXP (x, 1))
- && ! REGNO_QTY_VALID_P (REGNO (XEXP (x, 1))))
- if (insert_regs (XEXP (x, 1), NULL, 0))
- {
- rehash_using_reg (XEXP (x, 1));
- changed = 1;
- }
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- changed |= mention_regs (XEXP (x, i));
- else if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- changed |= mention_regs (XVECEXP (x, i, j));
-
- return changed;
-}
-
-/* Update the register quantities for inserting X into the hash table
- with a value equivalent to CLASSP.
- (If the class does not contain a REG, it is irrelevant.)
- If MODIFIED is nonzero, X is a destination; it is being modified.
- Note that delete_reg_equiv should be called on a register
- before insert_regs is done on that register with MODIFIED != 0.
-
- Nonzero value means that elements of reg_qty have changed
- so X's hash code may be different. */
-
-static int
-insert_regs (rtx x, struct table_elt *classp, int modified)
-{
- if (REG_P (x))
- {
- unsigned int regno = REGNO (x);
- int qty_valid;
-
- /* If REGNO is in the equivalence table already but is of the
- wrong mode for that equivalence, don't do anything here. */
-
- qty_valid = REGNO_QTY_VALID_P (regno);
- if (qty_valid)
- {
- struct qty_table_elem *ent = &qty_table[REG_QTY (regno)];
-
- if (ent->mode != GET_MODE (x))
- return 0;
- }
-
- if (modified || ! qty_valid)
- {
- if (classp)
- for (classp = classp->first_same_value;
- classp != 0;
- classp = classp->next_same_value)
- if (REG_P (classp->exp)
- && GET_MODE (classp->exp) == GET_MODE (x))
- {
- unsigned c_regno = REGNO (classp->exp);
-
- gcc_assert (REGNO_QTY_VALID_P (c_regno));
-
- /* Suppose that 5 is hard reg and 100 and 101 are
- pseudos. Consider
-
- (set (reg:si 100) (reg:si 5))
- (set (reg:si 5) (reg:si 100))
- (set (reg:di 101) (reg:di 5))
-
- We would now set REG_QTY (101) = REG_QTY (5), but the
- entry for 5 is in SImode. When we use this later in
- copy propagation, we get the register in wrong mode. */
- if (qty_table[REG_QTY (c_regno)].mode != GET_MODE (x))
- continue;
-
- make_regs_eqv (regno, c_regno);
- return 1;
- }
-
- /* Mention_regs for a SUBREG checks if REG_TICK is exactly one larger
- than REG_IN_TABLE to find out if there was only a single preceding
- invalidation - for the SUBREG - or another one, which would be
- for the full register. However, if we find here that REG_TICK
- indicates that the register is invalid, it means that it has
- been invalidated in a separate operation. The SUBREG might be used
- now (then this is a recursive call), or we might use the full REG
- now and a SUBREG of it later. So bump up REG_TICK so that
- mention_regs will do the right thing. */
- if (! modified
- && REG_IN_TABLE (regno) >= 0
- && REG_TICK (regno) == REG_IN_TABLE (regno) + 1)
- REG_TICK (regno)++;
- make_new_qty (regno, GET_MODE (x));
- return 1;
- }
-
- return 0;
- }
-
- /* If X is a SUBREG, we will likely be inserting the inner register in the
- table. If that register doesn't have an assigned quantity number at
- this point but does later, the insertion that we will be doing now will
- not be accessible because its hash code will have changed. So assign
- a quantity number now. */
-
- else if (GET_CODE (x) == SUBREG && REG_P (SUBREG_REG (x))
- && ! REGNO_QTY_VALID_P (REGNO (SUBREG_REG (x))))
- {
- insert_regs (SUBREG_REG (x), NULL, 0);
- mention_regs (x);
- return 1;
- }
- else
- return mention_regs (x);
-}
-
-
-/* Compute upper and lower anchors for CST. Also compute the offset of CST
- from these anchors/bases such that *_BASE + *_OFFS = CST. Return false iff
- CST is equal to an anchor. */
-
-static bool
-compute_const_anchors (rtx cst,
- HOST_WIDE_INT *lower_base, HOST_WIDE_INT *lower_offs,
- HOST_WIDE_INT *upper_base, HOST_WIDE_INT *upper_offs)
-{
- HOST_WIDE_INT n = INTVAL (cst);
-
- *lower_base = n & ~(targetm.const_anchor - 1);
- if (*lower_base == n)
- return false;
-
- *upper_base =
- (n + (targetm.const_anchor - 1)) & ~(targetm.const_anchor - 1);
- *upper_offs = n - *upper_base;
- *lower_offs = n - *lower_base;
- return true;
-}
-
-/* Insert the equivalence between ANCHOR and (REG + OFF) in mode MODE. */
-
-static void
-insert_const_anchor (HOST_WIDE_INT anchor, rtx reg, HOST_WIDE_INT offs,
- machine_mode mode)
-{
- struct table_elt *elt;
- unsigned hash;
- rtx anchor_exp;
- rtx exp;
-
- anchor_exp = GEN_INT (anchor);
- hash = HASH (anchor_exp, mode);
- elt = lookup (anchor_exp, hash, mode);
- if (!elt)
- elt = insert (anchor_exp, NULL, hash, mode);
-
- exp = plus_constant (mode, reg, offs);
- /* REG has just been inserted and the hash codes recomputed. */
- mention_regs (exp);
- hash = HASH (exp, mode);
-
- /* Use the cost of the register rather than the whole expression. When
- looking up constant anchors we will further offset the corresponding
- expression therefore it does not make sense to prefer REGs over
- reg-immediate additions. Prefer instead the oldest expression. Also
- don't prefer pseudos over hard regs so that we derive constants in
- argument registers from other argument registers rather than from the
- original pseudo that was used to synthesize the constant. */
- insert_with_costs (exp, elt, hash, mode, COST (reg, mode), 1);
-}
-
-/* The constant CST is equivalent to the register REG. Create
- equivalences between the two anchors of CST and the corresponding
- register-offset expressions using REG. */
-
-static void
-insert_const_anchors (rtx reg, rtx cst, machine_mode mode)
-{
- HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
-
- if (!compute_const_anchors (cst, &lower_base, &lower_offs,
- &upper_base, &upper_offs))
- return;
-
- /* Ignore anchors of value 0. Constants accessible from zero are
- simple. */
- if (lower_base != 0)
- insert_const_anchor (lower_base, reg, -lower_offs, mode);
-
- if (upper_base != 0)
- insert_const_anchor (upper_base, reg, -upper_offs, mode);
-}
-
-/* We need to express ANCHOR_ELT->exp + OFFS. Walk the equivalence list of
- ANCHOR_ELT and see if offsetting any of the entries by OFFS would create a
- valid expression. Return the cheapest and oldest of such expressions. In
- *OLD, return how old the resulting expression is compared to the other
- equivalent expressions. */
-
-static rtx
-find_reg_offset_for_const (struct table_elt *anchor_elt, HOST_WIDE_INT offs,
- unsigned *old)
-{
- struct table_elt *elt;
- unsigned idx;
- struct table_elt *match_elt;
- rtx match;
-
- /* Find the cheapest and *oldest* expression to maximize the chance of
- reusing the same pseudo. */
-
- match_elt = NULL;
- match = NULL_RTX;
- for (elt = anchor_elt->first_same_value, idx = 0;
- elt;
- elt = elt->next_same_value, idx++)
- {
- if (match_elt && CHEAPER (match_elt, elt))
- return match;
-
- if (REG_P (elt->exp)
- || (GET_CODE (elt->exp) == PLUS
- && REG_P (XEXP (elt->exp, 0))
- && GET_CODE (XEXP (elt->exp, 1)) == CONST_INT))
- {
- rtx x;
-
- /* Ignore expressions that are no longer valid. */
- if (!REG_P (elt->exp) && !exp_equiv_p (elt->exp, elt->exp, 1, false))
- continue;
-
- x = plus_constant (GET_MODE (elt->exp), elt->exp, offs);
- if (REG_P (x)
- || (GET_CODE (x) == PLUS
- && IN_RANGE (INTVAL (XEXP (x, 1)),
- -targetm.const_anchor,
- targetm.const_anchor - 1)))
- {
- match = x;
- match_elt = elt;
- *old = idx;
- }
- }
- }
-
- return match;
-}
-
-/* Try to express the constant SRC_CONST using a register+offset expression
- derived from a constant anchor. Return it if successful or NULL_RTX,
- otherwise. */
-
-static rtx
-try_const_anchors (rtx src_const, machine_mode mode)
-{
- struct table_elt *lower_elt, *upper_elt;
- HOST_WIDE_INT lower_base, lower_offs, upper_base, upper_offs;
- rtx lower_anchor_rtx, upper_anchor_rtx;
- rtx lower_exp = NULL_RTX, upper_exp = NULL_RTX;
- unsigned lower_old, upper_old;
-
- /* CONST_INT is used for CC modes, but we should leave those alone. */
- if (GET_MODE_CLASS (mode) == MODE_CC)
- return NULL_RTX;
-
- gcc_assert (SCALAR_INT_MODE_P (mode));
- if (!compute_const_anchors (src_const, &lower_base, &lower_offs,
- &upper_base, &upper_offs))
- return NULL_RTX;
-
- lower_anchor_rtx = GEN_INT (lower_base);
- upper_anchor_rtx = GEN_INT (upper_base);
- lower_elt = lookup (lower_anchor_rtx, HASH (lower_anchor_rtx, mode), mode);
- upper_elt = lookup (upper_anchor_rtx, HASH (upper_anchor_rtx, mode), mode);
-
- if (lower_elt)
- lower_exp = find_reg_offset_for_const (lower_elt, lower_offs, &lower_old);
- if (upper_elt)
- upper_exp = find_reg_offset_for_const (upper_elt, upper_offs, &upper_old);
-
- if (!lower_exp)
- return upper_exp;
- if (!upper_exp)
- return lower_exp;
-
- /* Return the older expression. */
- return (upper_old > lower_old ? upper_exp : lower_exp);
-}
-
-/* Look in or update the hash table. */
-
-/* Remove table element ELT from use in the table.
- HASH is its hash code, made using the HASH macro.
- It's an argument because often that is known in advance
- and we save much time not recomputing it. */
-
-static void
-remove_from_table (struct table_elt *elt, unsigned int hash)
-{
- if (elt == 0)
- return;
-
- /* Mark this element as removed. See cse_insn. */
- elt->first_same_value = 0;
-
- /* Remove the table element from its equivalence class. */
-
- {
- struct table_elt *prev = elt->prev_same_value;
- struct table_elt *next = elt->next_same_value;
-
- if (next)
- next->prev_same_value = prev;
-
- if (prev)
- prev->next_same_value = next;
- else
- {
- struct table_elt *newfirst = next;
- while (next)
- {
- next->first_same_value = newfirst;
- next = next->next_same_value;
- }
- }
- }
-
- /* Remove the table element from its hash bucket. */
-
- {
- struct table_elt *prev = elt->prev_same_hash;
- struct table_elt *next = elt->next_same_hash;
-
- if (next)
- next->prev_same_hash = prev;
-
- if (prev)
- prev->next_same_hash = next;
- else if (table[hash] == elt)
- table[hash] = next;
- else
- {
- /* This entry is not in the proper hash bucket. This can happen
- when two classes were merged by `merge_equiv_classes'. Search
- for the hash bucket that it heads. This happens only very
- rarely, so the cost is acceptable. */
- for (hash = 0; hash < HASH_SIZE; hash++)
- if (table[hash] == elt)
- table[hash] = next;
- }
- }
-
- /* Remove the table element from its related-value circular chain. */
-
- if (elt->related_value != 0 && elt->related_value != elt)
- {
- struct table_elt *p = elt->related_value;
-
- while (p->related_value != elt)
- p = p->related_value;
- p->related_value = elt->related_value;
- if (p->related_value == p)
- p->related_value = 0;
- }
-
- /* Now add it to the free element chain. */
- elt->next_same_hash = free_element_chain;
- free_element_chain = elt;
-}
-
-/* Same as above, but X is a pseudo-register. */
-
-static void
-remove_pseudo_from_table (rtx x, unsigned int hash)
-{
- struct table_elt *elt;
-
- /* Because a pseudo-register can be referenced in more than one
- mode, we might have to remove more than one table entry. */
- while ((elt = lookup_for_remove (x, hash, VOIDmode)))
- remove_from_table (elt, hash);
-}
-
-/* Look up X in the hash table and return its table element,
- or 0 if X is not in the table.
-
- MODE is the machine-mode of X, or if X is an integer constant
- with VOIDmode then MODE is the mode with which X will be used.
-
- Here we are satisfied to find an expression whose tree structure
- looks like X. */
-
-static struct table_elt *
-lookup (rtx x, unsigned int hash, machine_mode mode)
-{
- struct table_elt *p;
-
- for (p = table[hash]; p; p = p->next_same_hash)
- if (mode == p->mode && ((x == p->exp && REG_P (x))
- || exp_equiv_p (x, p->exp, !REG_P (x), false)))
- return p;
-
- return 0;
-}
-
-/* Like `lookup' but don't care whether the table element uses invalid regs.
- Also ignore discrepancies in the machine mode of a register. */
-
-static struct table_elt *
-lookup_for_remove (rtx x, unsigned int hash, machine_mode mode)
-{
- struct table_elt *p;
-
- if (REG_P (x))
- {
- unsigned int regno = REGNO (x);
-
- /* Don't check the machine mode when comparing registers;
- invalidating (REG:SI 0) also invalidates (REG:DF 0). */
- for (p = table[hash]; p; p = p->next_same_hash)
- if (REG_P (p->exp)
- && REGNO (p->exp) == regno)
- return p;
- }
- else
- {
- for (p = table[hash]; p; p = p->next_same_hash)
- if (mode == p->mode
- && (x == p->exp || exp_equiv_p (x, p->exp, 0, false)))
- return p;
- }
-
- return 0;
-}
-
-/* Look for an expression equivalent to X and with code CODE.
- If one is found, return that expression. */
-
-static rtx
-lookup_as_function (rtx x, enum rtx_code code)
-{
- struct table_elt *p
- = lookup (x, SAFE_HASH (x, VOIDmode), GET_MODE (x));
-
- if (p == 0)
- return 0;
-
- for (p = p->first_same_value; p; p = p->next_same_value)
- if (GET_CODE (p->exp) == code
- /* Make sure this is a valid entry in the table. */
- && exp_equiv_p (p->exp, p->exp, 1, false))
- return p->exp;
-
- return 0;
-}
-
-/* Insert X in the hash table, assuming HASH is its hash code and
- CLASSP is an element of the class it should go in (or 0 if a new
- class should be made). COST is the code of X and reg_cost is the
- cost of registers in X. It is inserted at the proper position to
- keep the class in the order cheapest first.
-
- MODE is the machine-mode of X, or if X is an integer constant
- with VOIDmode then MODE is the mode with which X will be used.
-
- For elements of equal cheapness, the most recent one
- goes in front, except that the first element in the list
- remains first unless a cheaper element is added. The order of
- pseudo-registers does not matter, as canon_reg will be called to
- find the cheapest when a register is retrieved from the table.
-
- The in_memory field in the hash table element is set to 0.
- The caller must set it nonzero if appropriate.
-
- You should call insert_regs (X, CLASSP, MODIFY) before calling here,
- and if insert_regs returns a nonzero value
- you must then recompute its hash code before calling here.
-
- If necessary, update table showing constant values of quantities. */
-
-static struct table_elt *
-insert_with_costs (rtx x, struct table_elt *classp, unsigned int hash,
- machine_mode mode, int cost, int reg_cost)
-{
- struct table_elt *elt;
-
- /* If X is a register and we haven't made a quantity for it,
- something is wrong. */
- gcc_assert (!REG_P (x) || REGNO_QTY_VALID_P (REGNO (x)));
-
- /* If X is a hard register, show it is being put in the table. */
- if (REG_P (x) && REGNO (x) < FIRST_PSEUDO_REGISTER)
- add_to_hard_reg_set (&hard_regs_in_table, GET_MODE (x), REGNO (x));
-
- /* Put an element for X into the right hash bucket. */
-
- elt = free_element_chain;
- if (elt)
- free_element_chain = elt->next_same_hash;
- else
- elt = XNEW (struct table_elt);
-
- elt->exp = x;
- elt->canon_exp = NULL_RTX;
- elt->cost = cost;
- elt->regcost = reg_cost;
- elt->next_same_value = 0;
- elt->prev_same_value = 0;
- elt->next_same_hash = table[hash];
- elt->prev_same_hash = 0;
- elt->related_value = 0;
- elt->in_memory = 0;
- elt->mode = mode;
- elt->is_const = (CONSTANT_P (x) || fixed_base_plus_p (x));
-
- if (table[hash])
- table[hash]->prev_same_hash = elt;
- table[hash] = elt;
-
- /* Put it into the proper value-class. */
- if (classp)
- {
- classp = classp->first_same_value;
- if (CHEAPER (elt, classp))
- /* Insert at the head of the class. */
- {
- struct table_elt *p;
- elt->next_same_value = classp;
- classp->prev_same_value = elt;
- elt->first_same_value = elt;
-
- for (p = classp; p; p = p->next_same_value)
- p->first_same_value = elt;
- }
- else
- {
- /* Insert not at head of the class. */
- /* Put it after the last element cheaper than X. */
- struct table_elt *p, *next;
-
- for (p = classp;
- (next = p->next_same_value) && CHEAPER (next, elt);
- p = next)
- ;
-
- /* Put it after P and before NEXT. */
- elt->next_same_value = next;
- if (next)
- next->prev_same_value = elt;
-
- elt->prev_same_value = p;
- p->next_same_value = elt;
- elt->first_same_value = classp;
- }
- }
- else
- elt->first_same_value = elt;
-
- /* If this is a constant being set equivalent to a register or a register
- being set equivalent to a constant, note the constant equivalence.
-
- If this is a constant, it cannot be equivalent to a different constant,
- and a constant is the only thing that can be cheaper than a register. So
- we know the register is the head of the class (before the constant was
- inserted).
-
- If this is a register that is not already known equivalent to a
- constant, we must check the entire class.
-
- If this is a register that is already known equivalent to an insn,
- update the qtys `const_insn' to show that `this_insn' is the latest
- insn making that quantity equivalent to the constant. */
-
- if (elt->is_const && classp && REG_P (classp->exp)
- && !REG_P (x))
- {
- int exp_q = REG_QTY (REGNO (classp->exp));
- struct qty_table_elem *exp_ent = &qty_table[exp_q];
-
- exp_ent->const_rtx = gen_lowpart (exp_ent->mode, x);
- exp_ent->const_insn = this_insn;
- }
-
- else if (REG_P (x)
- && classp
- && ! qty_table[REG_QTY (REGNO (x))].const_rtx
- && ! elt->is_const)
- {
- struct table_elt *p;
-
- for (p = classp; p != 0; p = p->next_same_value)
- {
- if (p->is_const && !REG_P (p->exp))
- {
- int x_q = REG_QTY (REGNO (x));
- struct qty_table_elem *x_ent = &qty_table[x_q];
-
- x_ent->const_rtx
- = gen_lowpart (GET_MODE (x), p->exp);
- x_ent->const_insn = this_insn;
- break;
- }
- }
- }
-
- else if (REG_P (x)
- && qty_table[REG_QTY (REGNO (x))].const_rtx
- && GET_MODE (x) == qty_table[REG_QTY (REGNO (x))].mode)
- qty_table[REG_QTY (REGNO (x))].const_insn = this_insn;
-
- /* If this is a constant with symbolic value,
- and it has a term with an explicit integer value,
- link it up with related expressions. */
- if (GET_CODE (x) == CONST)
- {
- rtx subexp = get_related_value (x);
- unsigned subhash;
- struct table_elt *subelt, *subelt_prev;
-
- if (subexp != 0)
- {
- /* Get the integer-free subexpression in the hash table. */
- subhash = SAFE_HASH (subexp, mode);
- subelt = lookup (subexp, subhash, mode);
- if (subelt == 0)
- subelt = insert (subexp, NULL, subhash, mode);
- /* Initialize SUBELT's circular chain if it has none. */
- if (subelt->related_value == 0)
- subelt->related_value = subelt;
- /* Find the element in the circular chain that precedes SUBELT. */
- subelt_prev = subelt;
- while (subelt_prev->related_value != subelt)
- subelt_prev = subelt_prev->related_value;
- /* Put new ELT into SUBELT's circular chain just before SUBELT.
- This way the element that follows SUBELT is the oldest one. */
- elt->related_value = subelt_prev->related_value;
- subelt_prev->related_value = elt;
- }
- }
-
- return elt;
-}
-
-/* Wrap insert_with_costs by passing the default costs. */
-
-static struct table_elt *
-insert (rtx x, struct table_elt *classp, unsigned int hash,
- machine_mode mode)
-{
- return insert_with_costs (x, classp, hash, mode,
- COST (x, mode), approx_reg_cost (x));
-}
-
-
-/* Given two equivalence classes, CLASS1 and CLASS2, put all the entries from
- CLASS2 into CLASS1. This is done when we have reached an insn which makes
- the two classes equivalent.
-
- CLASS1 will be the surviving class; CLASS2 should not be used after this
- call.
-
- Any invalid entries in CLASS2 will not be copied. */
-
-static void
-merge_equiv_classes (struct table_elt *class1, struct table_elt *class2)
-{
- struct table_elt *elt, *next, *new_elt;
-
- /* Ensure we start with the head of the classes. */
- class1 = class1->first_same_value;
- class2 = class2->first_same_value;
-
- /* If they were already equal, forget it. */
- if (class1 == class2)
- return;
-
- for (elt = class2; elt; elt = next)
- {
- unsigned int hash;
- rtx exp = elt->exp;
- machine_mode mode = elt->mode;
-
- next = elt->next_same_value;
-
- /* Remove old entry, make a new one in CLASS1's class.
- Don't do this for invalid entries as we cannot find their
- hash code (it also isn't necessary). */
- if (REG_P (exp) || exp_equiv_p (exp, exp, 1, false))
- {
- bool need_rehash = false;
-
- hash_arg_in_memory = 0;
- hash = HASH (exp, mode);
-
- if (REG_P (exp))
- {
- need_rehash = REGNO_QTY_VALID_P (REGNO (exp));
- delete_reg_equiv (REGNO (exp));
- }
-
- if (REG_P (exp) && REGNO (exp) >= FIRST_PSEUDO_REGISTER)
- remove_pseudo_from_table (exp, hash);
- else
- remove_from_table (elt, hash);
-
- if (insert_regs (exp, class1, 0) || need_rehash)
- {
- rehash_using_reg (exp);
- hash = HASH (exp, mode);
- }
- new_elt = insert (exp, class1, hash, mode);
- new_elt->in_memory = hash_arg_in_memory;
- if (GET_CODE (exp) == ASM_OPERANDS && elt->cost == MAX_COST)
- new_elt->cost = MAX_COST;
- }
- }
-}
-
-/* Flush the entire hash table. */
-
-static void
-flush_hash_table (void)
-{
- int i;
- struct table_elt *p;
-
- for (i = 0; i < HASH_SIZE; i++)
- for (p = table[i]; p; p = table[i])
- {
- /* Note that invalidate can remove elements
- after P in the current hash chain. */
- if (REG_P (p->exp))
- invalidate (p->exp, VOIDmode);
- else
- remove_from_table (p, i);
- }
-}
-
-/* Check whether an anti dependence exists between X and EXP. MODE and
- ADDR are as for canon_anti_dependence. */
-
-static bool
-check_dependence (const_rtx x, rtx exp, machine_mode mode, rtx addr)
-{
- subrtx_iterator::array_type array;
- FOR_EACH_SUBRTX (iter, array, x, NONCONST)
- {
- const_rtx x = *iter;
- if (MEM_P (x) && canon_anti_dependence (x, true, exp, mode, addr))
- return true;
- }
- return false;
-}
-
-/* Remove from the hash table, or mark as invalid, all expressions whose
- values could be altered by storing in register X. */
-
-static void
-invalidate_reg (rtx x)
-{
- gcc_assert (GET_CODE (x) == REG);
-
- /* If X is a register, dependencies on its contents are recorded
- through the qty number mechanism. Just change the qty number of
- the register, mark it as invalid for expressions that refer to it,
- and remove it itself. */
- unsigned int regno = REGNO (x);
- unsigned int hash = HASH (x, GET_MODE (x));
-
- /* Remove REGNO from any quantity list it might be on and indicate
- that its value might have changed. If it is a pseudo, remove its
- entry from the hash table.
-
- For a hard register, we do the first two actions above for any
- additional hard registers corresponding to X. Then, if any of these
- registers are in the table, we must remove any REG entries that
- overlap these registers. */
-
- delete_reg_equiv (regno);
- REG_TICK (regno)++;
- SUBREG_TICKED (regno) = -1;
-
- if (regno >= FIRST_PSEUDO_REGISTER)
- remove_pseudo_from_table (x, hash);
- else
- {
- HOST_WIDE_INT in_table = TEST_HARD_REG_BIT (hard_regs_in_table, regno);
- unsigned int endregno = END_REGNO (x);
- unsigned int rn;
- struct table_elt *p, *next;
-
- CLEAR_HARD_REG_BIT (hard_regs_in_table, regno);
-
- for (rn = regno + 1; rn < endregno; rn++)
- {
- in_table |= TEST_HARD_REG_BIT (hard_regs_in_table, rn);
- CLEAR_HARD_REG_BIT (hard_regs_in_table, rn);
- delete_reg_equiv (rn);
- REG_TICK (rn)++;
- SUBREG_TICKED (rn) = -1;
- }
-
- if (in_table)
- for (hash = 0; hash < HASH_SIZE; hash++)
- for (p = table[hash]; p; p = next)
- {
- next = p->next_same_hash;
-
- if (!REG_P (p->exp) || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
- continue;
-
- unsigned int tregno = REGNO (p->exp);
- unsigned int tendregno = END_REGNO (p->exp);
- if (tendregno > regno && tregno < endregno)
- remove_from_table (p, hash);
- }
- }
-}
-
-/* Remove from the hash table, or mark as invalid, all expressions whose
- values could be altered by storing in X. X is a register, a subreg, or
- a memory reference with nonvarying address (because, when a memory
- reference with a varying address is stored in, all memory references are
- removed by invalidate_memory so specific invalidation is superfluous).
- FULL_MODE, if not VOIDmode, indicates that this much should be
- invalidated instead of just the amount indicated by the mode of X. This
- is only used for bitfield stores into memory.
-
- A nonvarying address may be just a register or just a symbol reference,
- or it may be either of those plus a numeric offset. */
-
-static void
-invalidate (rtx x, machine_mode full_mode)
-{
- int i;
- struct table_elt *p;
- rtx addr;
-
- switch (GET_CODE (x))
- {
- case REG:
- invalidate_reg (x);
- return;
-
- case SUBREG:
- invalidate (SUBREG_REG (x), VOIDmode);
- return;
-
- case PARALLEL:
- for (i = XVECLEN (x, 0) - 1; i >= 0; --i)
- invalidate (XVECEXP (x, 0, i), VOIDmode);
- return;
-
- case EXPR_LIST:
- /* This is part of a disjoint return value; extract the location in
- question ignoring the offset. */
- invalidate (XEXP (x, 0), VOIDmode);
- return;
-
- case MEM:
- addr = canon_rtx (get_addr (XEXP (x, 0)));
- /* Calculate the canonical version of X here so that
- true_dependence doesn't generate new RTL for X on each call. */
- x = canon_rtx (x);
-
- /* Remove all hash table elements that refer to overlapping pieces of
- memory. */
- if (full_mode == VOIDmode)
- full_mode = GET_MODE (x);
-
- for (i = 0; i < HASH_SIZE; i++)
- {
- struct table_elt *next;
-
- for (p = table[i]; p; p = next)
- {
- next = p->next_same_hash;
- if (p->in_memory)
- {
- /* Just canonicalize the expression once;
- otherwise each time we call invalidate
- true_dependence will canonicalize the
- expression again. */
- if (!p->canon_exp)
- p->canon_exp = canon_rtx (p->exp);
- if (check_dependence (p->canon_exp, x, full_mode, addr))
- remove_from_table (p, i);
- }
- }
- }
- return;
-
- default:
- gcc_unreachable ();
- }
-}
-
-/* Invalidate DEST. Used when DEST is not going to be added
- into the hash table for some reason, e.g. do_not_record
- flagged on it. */
-
-static void
-invalidate_dest (rtx dest)
-{
- if (REG_P (dest)
- || GET_CODE (dest) == SUBREG
- || MEM_P (dest))
- invalidate (dest, VOIDmode);
- else if (GET_CODE (dest) == STRICT_LOW_PART
- || GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0), GET_MODE (dest));
-}
-
-/* Remove all expressions that refer to register REGNO,
- since they are already invalid, and we are about to
- mark that register valid again and don't want the old
- expressions to reappear as valid. */
-
-static void
-remove_invalid_refs (unsigned int regno)
-{
- unsigned int i;
- struct table_elt *p, *next;
-
- for (i = 0; i < HASH_SIZE; i++)
- for (p = table[i]; p; p = next)
- {
- next = p->next_same_hash;
- if (!REG_P (p->exp) && refers_to_regno_p (regno, p->exp))
- remove_from_table (p, i);
- }
-}
-
-/* Likewise for a subreg with subreg_reg REGNO, subreg_byte OFFSET,
- and mode MODE. */
-static void
-remove_invalid_subreg_refs (unsigned int regno, poly_uint64 offset,
- machine_mode mode)
-{
- unsigned int i;
- struct table_elt *p, *next;
-
- for (i = 0; i < HASH_SIZE; i++)
- for (p = table[i]; p; p = next)
- {
- rtx exp = p->exp;
- next = p->next_same_hash;
-
- if (!REG_P (exp)
- && (GET_CODE (exp) != SUBREG
- || !REG_P (SUBREG_REG (exp))
- || REGNO (SUBREG_REG (exp)) != regno
- || ranges_maybe_overlap_p (SUBREG_BYTE (exp),
- GET_MODE_SIZE (GET_MODE (exp)),
- offset, GET_MODE_SIZE (mode)))
- && refers_to_regno_p (regno, p->exp))
- remove_from_table (p, i);
- }
-}
-
-/* Recompute the hash codes of any valid entries in the hash table that
- reference X, if X is a register, or SUBREG_REG (X) if X is a SUBREG.
-
- This is called when we make a jump equivalence. */
-
-static void
-rehash_using_reg (rtx x)
-{
- unsigned int i;
- struct table_elt *p, *next;
- unsigned hash;
-
- if (GET_CODE (x) == SUBREG)
- x = SUBREG_REG (x);
-
- /* If X is not a register or if the register is known not to be in any
- valid entries in the table, we have no work to do. */
-
- if (!REG_P (x)
- || REG_IN_TABLE (REGNO (x)) < 0
- || REG_IN_TABLE (REGNO (x)) != REG_TICK (REGNO (x)))
- return;
-
- /* Scan all hash chains looking for valid entries that mention X.
- If we find one and it is in the wrong hash chain, move it. */
-
- for (i = 0; i < HASH_SIZE; i++)
- for (p = table[i]; p; p = next)
- {
- next = p->next_same_hash;
- if (reg_mentioned_p (x, p->exp)
- && exp_equiv_p (p->exp, p->exp, 1, false)
- && i != (hash = SAFE_HASH (p->exp, p->mode)))
- {
- if (p->next_same_hash)
- p->next_same_hash->prev_same_hash = p->prev_same_hash;
-
- if (p->prev_same_hash)
- p->prev_same_hash->next_same_hash = p->next_same_hash;
- else
- table[i] = p->next_same_hash;
-
- p->next_same_hash = table[hash];
- p->prev_same_hash = 0;
- if (table[hash])
- table[hash]->prev_same_hash = p;
- table[hash] = p;
- }
- }
-}
-
-/* Remove from the hash table any expression that is a call-clobbered
- register in INSN. Also update their TICK values. */
-
-static void
-invalidate_for_call (rtx_insn *insn)
-{
- unsigned int regno;
- unsigned hash;
- struct table_elt *p, *next;
- int in_table = 0;
- hard_reg_set_iterator hrsi;
-
- /* Go through all the hard registers. For each that might be clobbered
- in call insn INSN, remove the register from quantity chains and update
- reg_tick if defined. Also see if any of these registers is currently
- in the table.
-
- ??? We could be more precise for partially-clobbered registers,
- and only invalidate values that actually occupy the clobbered part
- of the registers. It doesn't seem worth the effort though, since
- we shouldn't see this situation much before RA. Whatever choice
- we make here has to be consistent with the table walk below,
- so any change to this test will require a change there too. */
- HARD_REG_SET callee_clobbers
- = insn_callee_abi (insn).full_and_partial_reg_clobbers ();
- EXECUTE_IF_SET_IN_HARD_REG_SET (callee_clobbers, 0, regno, hrsi)
- {
- delete_reg_equiv (regno);
- if (REG_TICK (regno) >= 0)
- {
- REG_TICK (regno)++;
- SUBREG_TICKED (regno) = -1;
- }
- in_table |= (TEST_HARD_REG_BIT (hard_regs_in_table, regno) != 0);
- }
-
- /* In the case where we have no call-clobbered hard registers in the
- table, we are done. Otherwise, scan the table and remove any
- entry that overlaps a call-clobbered register. */
-
- if (in_table)
- for (hash = 0; hash < HASH_SIZE; hash++)
- for (p = table[hash]; p; p = next)
- {
- next = p->next_same_hash;
-
- if (!REG_P (p->exp)
- || REGNO (p->exp) >= FIRST_PSEUDO_REGISTER)
- continue;
-
- /* This must use the same test as above rather than the
- more accurate clobbers_reg_p. */
- if (overlaps_hard_reg_set_p (callee_clobbers, GET_MODE (p->exp),
- REGNO (p->exp)))
- remove_from_table (p, hash);
- }
-}
-
-/* Given an expression X of type CONST,
- and ELT which is its table entry (or 0 if it
- is not in the hash table),
- return an alternate expression for X as a register plus integer.
- If none can be found, return 0. */
-
-static rtx
-use_related_value (rtx x, struct table_elt *elt)
-{
- struct table_elt *relt = 0;
- struct table_elt *p, *q;
- HOST_WIDE_INT offset;
-
- /* First, is there anything related known?
- If we have a table element, we can tell from that.
- Otherwise, must look it up. */
-
- if (elt != 0 && elt->related_value != 0)
- relt = elt;
- else if (elt == 0 && GET_CODE (x) == CONST)
- {
- rtx subexp = get_related_value (x);
- if (subexp != 0)
- relt = lookup (subexp,
- SAFE_HASH (subexp, GET_MODE (subexp)),
- GET_MODE (subexp));
- }
-
- if (relt == 0)
- return 0;
-
- /* Search all related table entries for one that has an
- equivalent register. */
-
- p = relt;
- while (1)
- {
- /* This loop is strange in that it is executed in two different cases.
- The first is when X is already in the table. Then it is searching
- the RELATED_VALUE list of X's class (RELT). The second case is when
- X is not in the table. Then RELT points to a class for the related
- value.
-
- Ensure that, whatever case we are in, that we ignore classes that have
- the same value as X. */
-
- if (rtx_equal_p (x, p->exp))
- q = 0;
- else
- for (q = p->first_same_value; q; q = q->next_same_value)
- if (REG_P (q->exp))
- break;
-
- if (q)
- break;
-
- p = p->related_value;
-
- /* We went all the way around, so there is nothing to be found.
- Alternatively, perhaps RELT was in the table for some other reason
- and it has no related values recorded. */
- if (p == relt || p == 0)
- break;
- }
-
- if (q == 0)
- return 0;
-
- offset = (get_integer_term (x) - get_integer_term (p->exp));
- /* Note: OFFSET may be 0 if P->xexp and X are related by commutativity. */
- return plus_constant (q->mode, q->exp, offset);
-}
-
-
-/* Hash a string. Just add its bytes up. */
-static inline unsigned
-hash_rtx_string (const char *ps)
-{
- unsigned hash = 0;
- const unsigned char *p = (const unsigned char *) ps;
-
- if (p)
- while (*p)
- hash += *p++;
-
- return hash;
-}
-
-/* Same as hash_rtx, but call CB on each rtx if it is not NULL.
- When the callback returns true, we continue with the new rtx. */
-
-unsigned
-hash_rtx_cb (const_rtx x, machine_mode mode,
- int *do_not_record_p, int *hash_arg_in_memory_p,
- bool have_reg_qty, hash_rtx_callback_function cb)
-{
- int i, j;
- unsigned hash = 0;
- enum rtx_code code;
- const char *fmt;
- machine_mode newmode;
- rtx newx;
-
- /* Used to turn recursion into iteration. We can't rely on GCC's
- tail-recursion elimination since we need to keep accumulating values
- in HASH. */
- repeat:
- if (x == 0)
- return hash;
-
- /* Invoke the callback first. */
- if (cb != NULL
- && ((*cb) (x, mode, &newx, &newmode)))
- {
- hash += hash_rtx_cb (newx, newmode, do_not_record_p,
- hash_arg_in_memory_p, have_reg_qty, cb);
- return hash;
- }
-
- code = GET_CODE (x);
- switch (code)
- {
- case REG:
- {
- unsigned int regno = REGNO (x);
-
- if (do_not_record_p && !reload_completed)
- {
- /* On some machines, we can't record any non-fixed hard register,
- because extending its life will cause reload problems. We
- consider ap, fp, sp, gp to be fixed for this purpose.
-
- We also consider CCmode registers to be fixed for this purpose;
- failure to do so leads to failure to simplify 0<100 type of
- conditionals.
-
- On all machines, we can't record any global registers.
- Nor should we record any register that is in a small
- class, as defined by TARGET_CLASS_LIKELY_SPILLED_P. */
- bool record;
-
- if (regno >= FIRST_PSEUDO_REGISTER)
- record = true;
- else if (x == frame_pointer_rtx
- || x == hard_frame_pointer_rtx
- || x == arg_pointer_rtx
- || x == stack_pointer_rtx
- || x == pic_offset_table_rtx)
- record = true;
- else if (global_regs[regno])
- record = false;
- else if (fixed_regs[regno])
- record = true;
- else if (GET_MODE_CLASS (GET_MODE (x)) == MODE_CC)
- record = true;
- else if (targetm.small_register_classes_for_mode_p (GET_MODE (x)))
- record = false;
- else if (targetm.class_likely_spilled_p (REGNO_REG_CLASS (regno)))
- record = false;
- else
- record = true;
-
- if (!record)
- {
- *do_not_record_p = 1;
- return 0;
- }
- }
-
- hash += ((unsigned int) REG << 7);
- hash += (have_reg_qty ? (unsigned) REG_QTY (regno) : regno);
- return hash;
- }
-
- /* We handle SUBREG of a REG specially because the underlying
- reg changes its hash value with every value change; we don't
- want to have to forget unrelated subregs when one subreg changes. */
- case SUBREG:
- {
- if (REG_P (SUBREG_REG (x)))
- {
- hash += (((unsigned int) SUBREG << 7)
- + REGNO (SUBREG_REG (x))
- + (constant_lower_bound (SUBREG_BYTE (x))
- / UNITS_PER_WORD));
- return hash;
- }
- break;
- }
-
- case CONST_INT:
- hash += (((unsigned int) CONST_INT << 7) + (unsigned int) mode
- + (unsigned int) INTVAL (x));
- return hash;
-
- case CONST_WIDE_INT:
- for (i = 0; i < CONST_WIDE_INT_NUNITS (x); i++)
- hash += CONST_WIDE_INT_ELT (x, i);
- return hash;
-
- case CONST_POLY_INT:
- {
- inchash::hash h;
- h.add_int (hash);
- for (unsigned int i = 0; i < NUM_POLY_INT_COEFFS; ++i)
- h.add_wide_int (CONST_POLY_INT_COEFFS (x)[i]);
- return h.end ();
- }
-
- case CONST_DOUBLE:
- /* This is like the general case, except that it only counts
- the integers representing the constant. */
- hash += (unsigned int) code + (unsigned int) GET_MODE (x);
- if (TARGET_SUPPORTS_WIDE_INT == 0 && GET_MODE (x) == VOIDmode)
- hash += ((unsigned int) CONST_DOUBLE_LOW (x)
- + (unsigned int) CONST_DOUBLE_HIGH (x));
- else
- hash += real_hash (CONST_DOUBLE_REAL_VALUE (x));
- return hash;
-
- case CONST_FIXED:
- hash += (unsigned int) code + (unsigned int) GET_MODE (x);
- hash += fixed_hash (CONST_FIXED_VALUE (x));
- return hash;
-
- case CONST_VECTOR:
- {
- int units;
- rtx elt;
-
- units = const_vector_encoded_nelts (x);
-
- for (i = 0; i < units; ++i)
- {
- elt = CONST_VECTOR_ENCODED_ELT (x, i);
- hash += hash_rtx_cb (elt, GET_MODE (elt),
- do_not_record_p, hash_arg_in_memory_p,
- have_reg_qty, cb);
- }
-
- return hash;
- }
-
- /* Assume there is only one rtx object for any given label. */
- case LABEL_REF:
- /* We don't hash on the address of the CODE_LABEL to avoid bootstrap
- differences and differences between each stage's debugging dumps. */
- hash += (((unsigned int) LABEL_REF << 7)
- + CODE_LABEL_NUMBER (label_ref_label (x)));
- return hash;
-
- case SYMBOL_REF:
- {
- /* Don't hash on the symbol's address to avoid bootstrap differences.
- Different hash values may cause expressions to be recorded in
- different orders and thus different registers to be used in the
- final assembler. This also avoids differences in the dump files
- between various stages. */
- unsigned int h = 0;
- const unsigned char *p = (const unsigned char *) XSTR (x, 0);
-
- while (*p)
- h += (h << 7) + *p++; /* ??? revisit */
-
- hash += ((unsigned int) SYMBOL_REF << 7) + h;
- return hash;
- }
-
- case MEM:
- /* We don't record if marked volatile or if BLKmode since we don't
- know the size of the move. */
- if (do_not_record_p && (MEM_VOLATILE_P (x) || GET_MODE (x) == BLKmode))
- {
- *do_not_record_p = 1;
- return 0;
- }
- if (hash_arg_in_memory_p && !MEM_READONLY_P (x))
- *hash_arg_in_memory_p = 1;
-
- /* Now that we have already found this special case,
- might as well speed it up as much as possible. */
- hash += (unsigned) MEM;
- x = XEXP (x, 0);
- goto repeat;
-
- case USE:
- /* A USE that mentions non-volatile memory needs special
- handling since the MEM may be BLKmode which normally
- prevents an entry from being made. Pure calls are
- marked by a USE which mentions BLKmode memory.
- See calls.c:emit_call_1. */
- if (MEM_P (XEXP (x, 0))
- && ! MEM_VOLATILE_P (XEXP (x, 0)))
- {
- hash += (unsigned) USE;
- x = XEXP (x, 0);
-
- if (hash_arg_in_memory_p && !MEM_READONLY_P (x))
- *hash_arg_in_memory_p = 1;
-
- /* Now that we have already found this special case,
- might as well speed it up as much as possible. */
- hash += (unsigned) MEM;
- x = XEXP (x, 0);
- goto repeat;
- }
- break;
-
- case PRE_DEC:
- case PRE_INC:
- case POST_DEC:
- case POST_INC:
- case PRE_MODIFY:
- case POST_MODIFY:
- case PC:
- case CALL:
- case UNSPEC_VOLATILE:
- if (do_not_record_p) {
- *do_not_record_p = 1;
- return 0;
- }
- else
- return hash;
- break;
-
- case ASM_OPERANDS:
- if (do_not_record_p && MEM_VOLATILE_P (x))
- {
- *do_not_record_p = 1;
- return 0;
- }
- else
- {
- /* We don't want to take the filename and line into account. */
- hash += (unsigned) code + (unsigned) GET_MODE (x)
- + hash_rtx_string (ASM_OPERANDS_TEMPLATE (x))
- + hash_rtx_string (ASM_OPERANDS_OUTPUT_CONSTRAINT (x))
- + (unsigned) ASM_OPERANDS_OUTPUT_IDX (x);
-
- if (ASM_OPERANDS_INPUT_LENGTH (x))
- {
- for (i = 1; i < ASM_OPERANDS_INPUT_LENGTH (x); i++)
- {
- hash += (hash_rtx_cb (ASM_OPERANDS_INPUT (x, i),
- GET_MODE (ASM_OPERANDS_INPUT (x, i)),
- do_not_record_p, hash_arg_in_memory_p,
- have_reg_qty, cb)
- + hash_rtx_string
- (ASM_OPERANDS_INPUT_CONSTRAINT (x, i)));
- }
-
- hash += hash_rtx_string (ASM_OPERANDS_INPUT_CONSTRAINT (x, 0));
- x = ASM_OPERANDS_INPUT (x, 0);
- mode = GET_MODE (x);
- goto repeat;
- }
-
- return hash;
- }
- break;
-
- default:
- break;
- }
-
- i = GET_RTX_LENGTH (code) - 1;
- hash += (unsigned) code + (unsigned) GET_MODE (x);
- fmt = GET_RTX_FORMAT (code);
- for (; i >= 0; i--)
- {
- switch (fmt[i])
- {
- case 'e':
- /* If we are about to do the last recursive call
- needed at this level, change it into iteration.
- This function is called enough to be worth it. */
- if (i == 0)
- {
- x = XEXP (x, i);
- goto repeat;
- }
-
- hash += hash_rtx_cb (XEXP (x, i), VOIDmode, do_not_record_p,
- hash_arg_in_memory_p,
- have_reg_qty, cb);
- break;
-
- case 'E':
- for (j = 0; j < XVECLEN (x, i); j++)
- hash += hash_rtx_cb (XVECEXP (x, i, j), VOIDmode, do_not_record_p,
- hash_arg_in_memory_p,
- have_reg_qty, cb);
- break;
-
- case 's':
- hash += hash_rtx_string (XSTR (x, i));
- break;
-
- case 'i':
- hash += (unsigned int) XINT (x, i);
- break;
-
- case 'p':
- hash += constant_lower_bound (SUBREG_BYTE (x));
- break;
-
- case '0': case 't':
- /* Unused. */
- break;
-
- default:
- gcc_unreachable ();
- }
- }
-
- return hash;
-}
-
-/* Hash an rtx. We are careful to make sure the value is never negative.
- Equivalent registers hash identically.
- MODE is used in hashing for CONST_INTs only;
- otherwise the mode of X is used.
-
- Store 1 in DO_NOT_RECORD_P if any subexpression is volatile.
-
- If HASH_ARG_IN_MEMORY_P is not NULL, store 1 in it if X contains
- a MEM rtx which does not have the MEM_READONLY_P flag set.
-
- Note that cse_insn knows that the hash code of a MEM expression
- is just (int) MEM plus the hash code of the address. */
-
-unsigned
-hash_rtx (const_rtx x, machine_mode mode, int *do_not_record_p,
- int *hash_arg_in_memory_p, bool have_reg_qty)
-{
- return hash_rtx_cb (x, mode, do_not_record_p,
- hash_arg_in_memory_p, have_reg_qty, NULL);
-}
-
-/* Hash an rtx X for cse via hash_rtx.
- Stores 1 in do_not_record if any subexpression is volatile.
- Stores 1 in hash_arg_in_memory if X contains a mem rtx which
- does not have the MEM_READONLY_P flag set. */
-
-static inline unsigned
-canon_hash (rtx x, machine_mode mode)
-{
- return hash_rtx (x, mode, &do_not_record, &hash_arg_in_memory, true);
-}
-
-/* Like canon_hash but with no side effects, i.e. do_not_record
- and hash_arg_in_memory are not changed. */
-
-static inline unsigned
-safe_hash (rtx x, machine_mode mode)
-{
- int dummy_do_not_record;
- return hash_rtx (x, mode, &dummy_do_not_record, NULL, true);
-}
-
-/* Return 1 iff X and Y would canonicalize into the same thing,
- without actually constructing the canonicalization of either one.
- If VALIDATE is nonzero,
- we assume X is an expression being processed from the rtl
- and Y was found in the hash table. We check register refs
- in Y for being marked as valid.
-
- If FOR_GCSE is true, we compare X and Y for equivalence for GCSE. */
-
-int
-exp_equiv_p (const_rtx x, const_rtx y, int validate, bool for_gcse)
-{
- int i, j;
- enum rtx_code code;
- const char *fmt;
-
- /* Note: it is incorrect to assume an expression is equivalent to itself
- if VALIDATE is nonzero. */
- if (x == y && !validate)
- return 1;
-
- if (x == 0 || y == 0)
- return x == y;
-
- code = GET_CODE (x);
- if (code != GET_CODE (y))
- return 0;
-
- /* (MULT:SI x y) and (MULT:HI x y) are NOT equivalent. */
- if (GET_MODE (x) != GET_MODE (y))
- return 0;
-
- /* MEMs referring to different address space are not equivalent. */
- if (code == MEM && MEM_ADDR_SPACE (x) != MEM_ADDR_SPACE (y))
- return 0;
-
- switch (code)
- {
- case PC:
- CASE_CONST_UNIQUE:
- return x == y;
-
- case CONST_VECTOR:
- if (!same_vector_encodings_p (x, y))
- return false;
- break;
-
- case LABEL_REF:
- return label_ref_label (x) == label_ref_label (y);
-
- case SYMBOL_REF:
- return XSTR (x, 0) == XSTR (y, 0);
-
- case REG:
- if (for_gcse)
- return REGNO (x) == REGNO (y);
- else
- {
- unsigned int regno = REGNO (y);
- unsigned int i;
- unsigned int endregno = END_REGNO (y);
-
- /* If the quantities are not the same, the expressions are not
- equivalent. If there are and we are not to validate, they
- are equivalent. Otherwise, ensure all regs are up-to-date. */
-
- if (REG_QTY (REGNO (x)) != REG_QTY (regno))
- return 0;
-
- if (! validate)
- return 1;
-
- for (i = regno; i < endregno; i++)
- if (REG_IN_TABLE (i) != REG_TICK (i))
- return 0;
-
- return 1;
- }
-
- case MEM:
- if (for_gcse)
- {
- /* A volatile mem should not be considered equivalent to any
- other. */
- if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
- return 0;
-
- /* Can't merge two expressions in different alias sets, since we
- can decide that the expression is transparent in a block when
- it isn't, due to it being set with the different alias set.
-
- Also, can't merge two expressions with different MEM_ATTRS.
- They could e.g. be two different entities allocated into the
- same space on the stack (see e.g. PR25130). In that case, the
- MEM addresses can be the same, even though the two MEMs are
- absolutely not equivalent.
-
- But because really all MEM attributes should be the same for
- equivalent MEMs, we just use the invariant that MEMs that have
- the same attributes share the same mem_attrs data structure. */
- if (!mem_attrs_eq_p (MEM_ATTRS (x), MEM_ATTRS (y)))
- return 0;
-
- /* If we are handling exceptions, we cannot consider two expressions
- with different trapping status as equivalent, because simple_mem
- might accept one and reject the other. */
- if (cfun->can_throw_non_call_exceptions
- && (MEM_NOTRAP_P (x) != MEM_NOTRAP_P (y)))
- return 0;
- }
- break;
-
- /* For commutative operations, check both orders. */
- case PLUS:
- case MULT:
- case AND:
- case IOR:
- case XOR:
- case NE:
- case EQ:
- return ((exp_equiv_p (XEXP (x, 0), XEXP (y, 0),
- validate, for_gcse)
- && exp_equiv_p (XEXP (x, 1), XEXP (y, 1),
- validate, for_gcse))
- || (exp_equiv_p (XEXP (x, 0), XEXP (y, 1),
- validate, for_gcse)
- && exp_equiv_p (XEXP (x, 1), XEXP (y, 0),
- validate, for_gcse)));
-
- case ASM_OPERANDS:
- /* We don't use the generic code below because we want to
- disregard filename and line numbers. */
-
- /* A volatile asm isn't equivalent to any other. */
- if (MEM_VOLATILE_P (x) || MEM_VOLATILE_P (y))
- return 0;
-
- if (GET_MODE (x) != GET_MODE (y)
- || strcmp (ASM_OPERANDS_TEMPLATE (x), ASM_OPERANDS_TEMPLATE (y))
- || strcmp (ASM_OPERANDS_OUTPUT_CONSTRAINT (x),
- ASM_OPERANDS_OUTPUT_CONSTRAINT (y))
- || ASM_OPERANDS_OUTPUT_IDX (x) != ASM_OPERANDS_OUTPUT_IDX (y)
- || ASM_OPERANDS_INPUT_LENGTH (x) != ASM_OPERANDS_INPUT_LENGTH (y))
- return 0;
-
- if (ASM_OPERANDS_INPUT_LENGTH (x))
- {
- for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
- if (! exp_equiv_p (ASM_OPERANDS_INPUT (x, i),
- ASM_OPERANDS_INPUT (y, i),
- validate, for_gcse)
- || strcmp (ASM_OPERANDS_INPUT_CONSTRAINT (x, i),
- ASM_OPERANDS_INPUT_CONSTRAINT (y, i)))
- return 0;
- }
-
- return 1;
-
- default:
- break;
- }
-
- /* Compare the elements. If any pair of corresponding elements
- fail to match, return 0 for the whole thing. */
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- switch (fmt[i])
- {
- case 'e':
- if (! exp_equiv_p (XEXP (x, i), XEXP (y, i),
- validate, for_gcse))
- return 0;
- break;
-
- case 'E':
- if (XVECLEN (x, i) != XVECLEN (y, i))
- return 0;
- for (j = 0; j < XVECLEN (x, i); j++)
- if (! exp_equiv_p (XVECEXP (x, i, j), XVECEXP (y, i, j),
- validate, for_gcse))
- return 0;
- break;
-
- case 's':
- if (strcmp (XSTR (x, i), XSTR (y, i)))
- return 0;
- break;
-
- case 'i':
- if (XINT (x, i) != XINT (y, i))
- return 0;
- break;
-
- case 'w':
- if (XWINT (x, i) != XWINT (y, i))
- return 0;
- break;
-
- case 'p':
- if (maybe_ne (SUBREG_BYTE (x), SUBREG_BYTE (y)))
- return 0;
- break;
-
- case '0':
- case 't':
- break;
-
- default:
- gcc_unreachable ();
- }
- }
-
- return 1;
-}
-
-/* Subroutine of canon_reg. Pass *XLOC through canon_reg, and validate
- the result if necessary. INSN is as for canon_reg. */
-
-static void
-validate_canon_reg (rtx *xloc, rtx_insn *insn)
-{
- if (*xloc)
- {
- rtx new_rtx = canon_reg (*xloc, insn);
-
- /* If replacing pseudo with hard reg or vice versa, ensure the
- insn remains valid. Likewise if the insn has MATCH_DUPs. */
- gcc_assert (insn && new_rtx);
- validate_change (insn, xloc, new_rtx, 1);
- }
-}
-
-/* Canonicalize an expression:
- replace each register reference inside it
- with the "oldest" equivalent register.
-
- If INSN is nonzero validate_change is used to ensure that INSN remains valid
- after we make our substitution. The calls are made with IN_GROUP nonzero
- so apply_change_group must be called upon the outermost return from this
- function (unless INSN is zero). The result of apply_change_group can
- generally be discarded since the changes we are making are optional. */
-
-static rtx
-canon_reg (rtx x, rtx_insn *insn)
-{
- int i;
- enum rtx_code code;
- const char *fmt;
-
- if (x == 0)
- return x;
-
- code = GET_CODE (x);
- switch (code)
- {
- case PC:
- case CONST:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case LABEL_REF:
- case ADDR_VEC:
- case ADDR_DIFF_VEC:
- return x;
-
- case REG:
- {
- int first;
- int q;
- struct qty_table_elem *ent;
-
- /* Never replace a hard reg, because hard regs can appear
- in more than one machine mode, and we must preserve the mode
- of each occurrence. Also, some hard regs appear in
- MEMs that are shared and mustn't be altered. Don't try to
- replace any reg that maps to a reg of class NO_REGS. */
- if (REGNO (x) < FIRST_PSEUDO_REGISTER
- || ! REGNO_QTY_VALID_P (REGNO (x)))
- return x;
-
- q = REG_QTY (REGNO (x));
- ent = &qty_table[q];
- first = ent->first_reg;
- return (first >= FIRST_PSEUDO_REGISTER ? regno_reg_rtx[first]
- : REGNO_REG_CLASS (first) == NO_REGS ? x
- : gen_rtx_REG (ent->mode, first));
- }
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- int j;
-
- if (fmt[i] == 'e')
- validate_canon_reg (&XEXP (x, i), insn);
- else if (fmt[i] == 'E')
- for (j = 0; j < XVECLEN (x, i); j++)
- validate_canon_reg (&XVECEXP (x, i, j), insn);
- }
-
- return x;
-}
-
-/* Given an operation (CODE, *PARG1, *PARG2), where code is a comparison
- operation (EQ, NE, GT, etc.), follow it back through the hash table and
- what values are being compared.
-
- *PARG1 and *PARG2 are updated to contain the rtx representing the values
- actually being compared. For example, if *PARG1 was (reg:CC CC_REG) and
- *PARG2 was (const_int 0), *PARG1 and *PARG2 will be set to the objects that
- were compared to produce (reg:CC CC_REG).
-
- The return value is the comparison operator and is either the code of
- A or the code corresponding to the inverse of the comparison. */
-
-static enum rtx_code
-find_comparison_args (enum rtx_code code, rtx *parg1, rtx *parg2,
- machine_mode *pmode1, machine_mode *pmode2)
-{
- rtx arg1, arg2;
- hash_set<rtx> *visited = NULL;
- /* Set nonzero when we find something of interest. */
- rtx x = NULL;
-
- arg1 = *parg1, arg2 = *parg2;
-
- /* If ARG2 is const0_rtx, see what ARG1 is equivalent to. */
-
- while (arg2 == CONST0_RTX (GET_MODE (arg1)))
- {
- int reverse_code = 0;
- struct table_elt *p = 0;
-
- /* Remember state from previous iteration. */
- if (x)
- {
- if (!visited)
- visited = new hash_set<rtx>;
- visited->add (x);
- x = 0;
- }
-
- /* If arg1 is a COMPARE, extract the comparison arguments from it. */
-
- if (GET_CODE (arg1) == COMPARE && arg2 == const0_rtx)
- x = arg1;
-
- /* If ARG1 is a comparison operator and CODE is testing for
- STORE_FLAG_VALUE, get the inner arguments. */
-
- else if (COMPARISON_P (arg1))
- {
-#ifdef FLOAT_STORE_FLAG_VALUE
- REAL_VALUE_TYPE fsfv;
-#endif
-
- if (code == NE
- || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
- && code == LT && STORE_FLAG_VALUE == -1)
-#ifdef FLOAT_STORE_FLAG_VALUE
- || (SCALAR_FLOAT_MODE_P (GET_MODE (arg1))
- && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
- REAL_VALUE_NEGATIVE (fsfv)))
-#endif
- )
- x = arg1;
- else if (code == EQ
- || (GET_MODE_CLASS (GET_MODE (arg1)) == MODE_INT
- && code == GE && STORE_FLAG_VALUE == -1)
-#ifdef FLOAT_STORE_FLAG_VALUE
- || (SCALAR_FLOAT_MODE_P (GET_MODE (arg1))
- && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
- REAL_VALUE_NEGATIVE (fsfv)))
-#endif
- )
- x = arg1, reverse_code = 1;
- }
-
- /* ??? We could also check for
-
- (ne (and (eq (...) (const_int 1))) (const_int 0))
-
- and related forms, but let's wait until we see them occurring. */
-
- if (x == 0)
- /* Look up ARG1 in the hash table and see if it has an equivalence
- that lets us see what is being compared. */
- p = lookup (arg1, SAFE_HASH (arg1, GET_MODE (arg1)), GET_MODE (arg1));
- if (p)
- {
- p = p->first_same_value;
-
- /* If what we compare is already known to be constant, that is as
- good as it gets.
- We need to break the loop in this case, because otherwise we
- can have an infinite loop when looking at a reg that is known
- to be a constant which is the same as a comparison of a reg
- against zero which appears later in the insn stream, which in
- turn is constant and the same as the comparison of the first reg
- against zero... */
- if (p->is_const)
- break;
- }
-
- for (; p; p = p->next_same_value)
- {
- machine_mode inner_mode = GET_MODE (p->exp);
-#ifdef FLOAT_STORE_FLAG_VALUE
- REAL_VALUE_TYPE fsfv;
-#endif
-
- /* If the entry isn't valid, skip it. */
- if (! exp_equiv_p (p->exp, p->exp, 1, false))
- continue;
-
- /* If it's a comparison we've used before, skip it. */
- if (visited && visited->contains (p->exp))
- continue;
-
- if (GET_CODE (p->exp) == COMPARE
- /* Another possibility is that this machine has a compare insn
- that includes the comparison code. In that case, ARG1 would
- be equivalent to a comparison operation that would set ARG1 to
- either STORE_FLAG_VALUE or zero. If this is an NE operation,
- ORIG_CODE is the actual comparison being done; if it is an EQ,
- we must reverse ORIG_CODE. On machine with a negative value
- for STORE_FLAG_VALUE, also look at LT and GE operations. */
- || ((code == NE
- || (code == LT
- && val_signbit_known_set_p (inner_mode,
- STORE_FLAG_VALUE))
-#ifdef FLOAT_STORE_FLAG_VALUE
- || (code == LT
- && SCALAR_FLOAT_MODE_P (inner_mode)
- && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
- REAL_VALUE_NEGATIVE (fsfv)))
-#endif
- )
- && COMPARISON_P (p->exp)))
- {
- x = p->exp;
- break;
- }
- else if ((code == EQ
- || (code == GE
- && val_signbit_known_set_p (inner_mode,
- STORE_FLAG_VALUE))
-#ifdef FLOAT_STORE_FLAG_VALUE
- || (code == GE
- && SCALAR_FLOAT_MODE_P (inner_mode)
- && (fsfv = FLOAT_STORE_FLAG_VALUE (GET_MODE (arg1)),
- REAL_VALUE_NEGATIVE (fsfv)))
-#endif
- )
- && COMPARISON_P (p->exp))
- {
- reverse_code = 1;
- x = p->exp;
- break;
- }
-
- /* If this non-trapping address, e.g. fp + constant, the
- equivalent is a better operand since it may let us predict
- the value of the comparison. */
- else if (!rtx_addr_can_trap_p (p->exp))
- {
- arg1 = p->exp;
- continue;
- }
- }
-
- /* If we didn't find a useful equivalence for ARG1, we are done.
- Otherwise, set up for the next iteration. */
- if (x == 0)
- break;
-
- /* If we need to reverse the comparison, make sure that is
- possible -- we can't necessarily infer the value of GE from LT
- with floating-point operands. */
- if (reverse_code)
- {
- enum rtx_code reversed = reversed_comparison_code (x, NULL);
- if (reversed == UNKNOWN)
- break;
- else
- code = reversed;
- }
- else if (COMPARISON_P (x))
- code = GET_CODE (x);
- arg1 = XEXP (x, 0), arg2 = XEXP (x, 1);
- }
-
- /* Return our results. Return the modes from before fold_rtx
- because fold_rtx might produce const_int, and then it's too late. */
- *pmode1 = GET_MODE (arg1), *pmode2 = GET_MODE (arg2);
- *parg1 = fold_rtx (arg1, 0), *parg2 = fold_rtx (arg2, 0);
-
- if (visited)
- delete visited;
- return code;
-}
-
-/* If X is a nontrivial arithmetic operation on an argument for which
- a constant value can be determined, return the result of operating
- on that value, as a constant. Otherwise, return X, possibly with
- one or more operands changed to a forward-propagated constant.
-
- If X is a register whose contents are known, we do NOT return
- those contents here; equiv_constant is called to perform that task.
- For SUBREGs and MEMs, we do that both here and in equiv_constant.
-
- INSN is the insn that we may be modifying. If it is 0, make a copy
- of X before modifying it. */
-
-static rtx
-fold_rtx (rtx x, rtx_insn *insn)
-{
- enum rtx_code code;
- machine_mode mode;
- const char *fmt;
- int i;
- rtx new_rtx = 0;
- int changed = 0;
- poly_int64 xval;
-
- /* Operands of X. */
- /* Workaround -Wmaybe-uninitialized false positive during
- profiledbootstrap by initializing them. */
- rtx folded_arg0 = NULL_RTX;
- rtx folded_arg1 = NULL_RTX;
-
- /* Constant equivalents of first three operands of X;
- 0 when no such equivalent is known. */
- rtx const_arg0;
- rtx const_arg1;
- rtx const_arg2;
-
- /* The mode of the first operand of X. We need this for sign and zero
- extends. */
- machine_mode mode_arg0;
-
- if (x == 0)
- return x;
-
- /* Try to perform some initial simplifications on X. */
- code = GET_CODE (x);
- switch (code)
- {
- case MEM:
- case SUBREG:
- /* The first operand of a SIGN/ZERO_EXTRACT has a different meaning
- than it would in other contexts. Basically its mode does not
- signify the size of the object read. That information is carried
- by size operand. If we happen to have a MEM of the appropriate
- mode in our tables with a constant value we could simplify the
- extraction incorrectly if we allowed substitution of that value
- for the MEM. */
- case ZERO_EXTRACT:
- case SIGN_EXTRACT:
- if ((new_rtx = equiv_constant (x)) != NULL_RTX)
- return new_rtx;
- return x;
-
- case CONST:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case LABEL_REF:
- case REG:
- case PC:
- /* No use simplifying an EXPR_LIST
- since they are used only for lists of args
- in a function call's REG_EQUAL note. */
- case EXPR_LIST:
- return x;
-
- case ASM_OPERANDS:
- if (insn)
- {
- for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
- validate_change (insn, &ASM_OPERANDS_INPUT (x, i),
- fold_rtx (ASM_OPERANDS_INPUT (x, i), insn), 0);
- }
- return x;
-
- case CALL:
- if (NO_FUNCTION_CSE && CONSTANT_P (XEXP (XEXP (x, 0), 0)))
- return x;
- break;
- case VEC_SELECT:
- {
- rtx trueop0 = XEXP (x, 0);
- mode = GET_MODE (trueop0);
- rtx trueop1 = XEXP (x, 1);
- /* If we select a low-part subreg, return that. */
- if (vec_series_lowpart_p (GET_MODE (x), mode, trueop1))
- {
- rtx new_rtx = lowpart_subreg (GET_MODE (x), trueop0, mode);
- if (new_rtx != NULL_RTX)
- return new_rtx;
- }
- }
-
- /* Anything else goes through the loop below. */
- default:
- break;
- }
-
- mode = GET_MODE (x);
- const_arg0 = 0;
- const_arg1 = 0;
- const_arg2 = 0;
- mode_arg0 = VOIDmode;
-
- /* Try folding our operands.
- Then see which ones have constant values known. */
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- if (fmt[i] == 'e')
- {
- rtx folded_arg = XEXP (x, i), const_arg;
- machine_mode mode_arg = GET_MODE (folded_arg);
-
- switch (GET_CODE (folded_arg))
- {
- case MEM:
- case REG:
- case SUBREG:
- const_arg = equiv_constant (folded_arg);
- break;
-
- case CONST:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case LABEL_REF:
- const_arg = folded_arg;
- break;
-
- default:
- folded_arg = fold_rtx (folded_arg, insn);
- const_arg = equiv_constant (folded_arg);
- break;
- }
-
- /* For the first three operands, see if the operand
- is constant or equivalent to a constant. */
- switch (i)
- {
- case 0:
- folded_arg0 = folded_arg;
- const_arg0 = const_arg;
- mode_arg0 = mode_arg;
- break;
- case 1:
- folded_arg1 = folded_arg;
- const_arg1 = const_arg;
- break;
- case 2:
- const_arg2 = const_arg;
- break;
- }
-
- /* Pick the least expensive of the argument and an equivalent constant
- argument. */
- if (const_arg != 0
- && const_arg != folded_arg
- && (COST_IN (const_arg, mode_arg, code, i)
- <= COST_IN (folded_arg, mode_arg, code, i))
-
- /* It's not safe to substitute the operand of a conversion
- operator with a constant, as the conversion's identity
- depends upon the mode of its operand. This optimization
- is handled by the call to simplify_unary_operation. */
- && (GET_RTX_CLASS (code) != RTX_UNARY
- || GET_MODE (const_arg) == mode_arg0
- || (code != ZERO_EXTEND
- && code != SIGN_EXTEND
- && code != TRUNCATE
- && code != FLOAT_TRUNCATE
- && code != FLOAT_EXTEND
- && code != FLOAT
- && code != FIX
- && code != UNSIGNED_FLOAT
- && code != UNSIGNED_FIX)))
- folded_arg = const_arg;
-
- if (folded_arg == XEXP (x, i))
- continue;
-
- if (insn == NULL_RTX && !changed)
- x = copy_rtx (x);
- changed = 1;
- validate_unshare_change (insn, &XEXP (x, i), folded_arg, 1);
- }
-
- if (changed)
- {
- /* Canonicalize X if necessary, and keep const_argN and folded_argN
- consistent with the order in X. */
- if (canonicalize_change_group (insn, x))
- {
- std::swap (const_arg0, const_arg1);
- std::swap (folded_arg0, folded_arg1);
- }
-
- apply_change_group ();
- }
-
- /* If X is an arithmetic operation, see if we can simplify it. */
-
- switch (GET_RTX_CLASS (code))
- {
- case RTX_UNARY:
- {
- /* We can't simplify extension ops unless we know the
- original mode. */
- if ((code == ZERO_EXTEND || code == SIGN_EXTEND)
- && mode_arg0 == VOIDmode)
- break;
-
- new_rtx = simplify_unary_operation (code, mode,
- const_arg0 ? const_arg0 : folded_arg0,
- mode_arg0);
- }
- break;
-
- case RTX_COMPARE:
- case RTX_COMM_COMPARE:
- /* See what items are actually being compared and set FOLDED_ARG[01]
- to those values and CODE to the actual comparison code. If any are
- constant, set CONST_ARG0 and CONST_ARG1 appropriately. We needn't
- do anything if both operands are already known to be constant. */
-
- /* ??? Vector mode comparisons are not supported yet. */
- if (VECTOR_MODE_P (mode))
- break;
-
- if (const_arg0 == 0 || const_arg1 == 0)
- {
- struct table_elt *p0, *p1;
- rtx true_rtx, false_rtx;
- machine_mode mode_arg1;
-
- if (SCALAR_FLOAT_MODE_P (mode))
- {
-#ifdef FLOAT_STORE_FLAG_VALUE
- true_rtx = (const_double_from_real_value
- (FLOAT_STORE_FLAG_VALUE (mode), mode));
-#else
- true_rtx = NULL_RTX;
-#endif
- false_rtx = CONST0_RTX (mode);
- }
- else
- {
- true_rtx = const_true_rtx;
- false_rtx = const0_rtx;
- }
-
- code = find_comparison_args (code, &folded_arg0, &folded_arg1,
- &mode_arg0, &mode_arg1);
-
- /* If the mode is VOIDmode or a MODE_CC mode, we don't know
- what kinds of things are being compared, so we can't do
- anything with this comparison. */
-
- if (mode_arg0 == VOIDmode || GET_MODE_CLASS (mode_arg0) == MODE_CC)
- break;
-
- const_arg0 = equiv_constant (folded_arg0);
- const_arg1 = equiv_constant (folded_arg1);
-
- /* If we do not now have two constants being compared, see
- if we can nevertheless deduce some things about the
- comparison. */
- if (const_arg0 == 0 || const_arg1 == 0)
- {
- if (const_arg1 != NULL)
- {
- rtx cheapest_simplification;
- int cheapest_cost;
- rtx simp_result;
- struct table_elt *p;
-
- /* See if we can find an equivalent of folded_arg0
- that gets us a cheaper expression, possibly a
- constant through simplifications. */
- p = lookup (folded_arg0, SAFE_HASH (folded_arg0, mode_arg0),
- mode_arg0);
-
- if (p != NULL)
- {
- cheapest_simplification = x;
- cheapest_cost = COST (x, mode);
-
- for (p = p->first_same_value; p != NULL; p = p->next_same_value)
- {
- int cost;
-
- /* If the entry isn't valid, skip it. */
- if (! exp_equiv_p (p->exp, p->exp, 1, false))
- continue;
-
- /* Try to simplify using this equivalence. */
- simp_result
- = simplify_relational_operation (code, mode,
- mode_arg0,
- p->exp,
- const_arg1);
-
- if (simp_result == NULL)
- continue;
-
- cost = COST (simp_result, mode);
- if (cost < cheapest_cost)
- {
- cheapest_cost = cost;
- cheapest_simplification = simp_result;
- }
- }
-
- /* If we have a cheaper expression now, use that
- and try folding it further, from the top. */
- if (cheapest_simplification != x)
- return fold_rtx (copy_rtx (cheapest_simplification),
- insn);
- }
- }
-
- /* See if the two operands are the same. */
-
- if ((REG_P (folded_arg0)
- && REG_P (folded_arg1)
- && (REG_QTY (REGNO (folded_arg0))
- == REG_QTY (REGNO (folded_arg1))))
- || ((p0 = lookup (folded_arg0,
- SAFE_HASH (folded_arg0, mode_arg0),
- mode_arg0))
- && (p1 = lookup (folded_arg1,
- SAFE_HASH (folded_arg1, mode_arg0),
- mode_arg0))
- && p0->first_same_value == p1->first_same_value))
- folded_arg1 = folded_arg0;
-
- /* If FOLDED_ARG0 is a register, see if the comparison we are
- doing now is either the same as we did before or the reverse
- (we only check the reverse if not floating-point). */
- else if (REG_P (folded_arg0))
- {
- int qty = REG_QTY (REGNO (folded_arg0));
-
- if (REGNO_QTY_VALID_P (REGNO (folded_arg0)))
- {
- struct qty_table_elem *ent = &qty_table[qty];
-
- if ((comparison_dominates_p (ent->comparison_code, code)
- || (! FLOAT_MODE_P (mode_arg0)
- && comparison_dominates_p (ent->comparison_code,
- reverse_condition (code))))
- && (rtx_equal_p (ent->comparison_const, folded_arg1)
- || (const_arg1
- && rtx_equal_p (ent->comparison_const,
- const_arg1))
- || (REG_P (folded_arg1)
- && (REG_QTY (REGNO (folded_arg1)) == ent->comparison_qty))))
- {
- if (comparison_dominates_p (ent->comparison_code, code))
- {
- if (true_rtx)
- return true_rtx;
- else
- break;
- }
- else
- return false_rtx;
- }
- }
- }
- }
- }
-
- /* If we are comparing against zero, see if the first operand is
- equivalent to an IOR with a constant. If so, we may be able to
- determine the result of this comparison. */
- if (const_arg1 == const0_rtx && !const_arg0)
- {
- rtx y = lookup_as_function (folded_arg0, IOR);
- rtx inner_const;
-
- if (y != 0
- && (inner_const = equiv_constant (XEXP (y, 1))) != 0
- && CONST_INT_P (inner_const)
- && INTVAL (inner_const) != 0)
- folded_arg0 = gen_rtx_IOR (mode_arg0, XEXP (y, 0), inner_const);
- }
-
- {
- rtx op0 = const_arg0 ? const_arg0 : copy_rtx (folded_arg0);
- rtx op1 = const_arg1 ? const_arg1 : copy_rtx (folded_arg1);
- new_rtx = simplify_relational_operation (code, mode, mode_arg0,
- op0, op1);
- }
- break;
-
- case RTX_BIN_ARITH:
- case RTX_COMM_ARITH:
- switch (code)
- {
- case PLUS:
- /* If the second operand is a LABEL_REF, see if the first is a MINUS
- with that LABEL_REF as its second operand. If so, the result is
- the first operand of that MINUS. This handles switches with an
- ADDR_DIFF_VEC table. */
- if (const_arg1 && GET_CODE (const_arg1) == LABEL_REF)
- {
- rtx y
- = GET_CODE (folded_arg0) == MINUS ? folded_arg0
- : lookup_as_function (folded_arg0, MINUS);
-
- if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
- && label_ref_label (XEXP (y, 1)) == label_ref_label (const_arg1))
- return XEXP (y, 0);
-
- /* Now try for a CONST of a MINUS like the above. */
- if ((y = (GET_CODE (folded_arg0) == CONST ? folded_arg0
- : lookup_as_function (folded_arg0, CONST))) != 0
- && GET_CODE (XEXP (y, 0)) == MINUS
- && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
- && label_ref_label (XEXP (XEXP (y, 0), 1)) == label_ref_label (const_arg1))
- return XEXP (XEXP (y, 0), 0);
- }
-
- /* Likewise if the operands are in the other order. */
- if (const_arg0 && GET_CODE (const_arg0) == LABEL_REF)
- {
- rtx y
- = GET_CODE (folded_arg1) == MINUS ? folded_arg1
- : lookup_as_function (folded_arg1, MINUS);
-
- if (y != 0 && GET_CODE (XEXP (y, 1)) == LABEL_REF
- && label_ref_label (XEXP (y, 1)) == label_ref_label (const_arg0))
- return XEXP (y, 0);
-
- /* Now try for a CONST of a MINUS like the above. */
- if ((y = (GET_CODE (folded_arg1) == CONST ? folded_arg1
- : lookup_as_function (folded_arg1, CONST))) != 0
- && GET_CODE (XEXP (y, 0)) == MINUS
- && GET_CODE (XEXP (XEXP (y, 0), 1)) == LABEL_REF
- && label_ref_label (XEXP (XEXP (y, 0), 1)) == label_ref_label (const_arg0))
- return XEXP (XEXP (y, 0), 0);
- }
-
- /* If second operand is a register equivalent to a negative
- CONST_INT, see if we can find a register equivalent to the
- positive constant. Make a MINUS if so. Don't do this for
- a non-negative constant since we might then alternate between
- choosing positive and negative constants. Having the positive
- constant previously-used is the more common case. Be sure
- the resulting constant is non-negative; if const_arg1 were
- the smallest negative number this would overflow: depending
- on the mode, this would either just be the same value (and
- hence not save anything) or be incorrect. */
- if (const_arg1 != 0 && CONST_INT_P (const_arg1)
- && INTVAL (const_arg1) < 0
- /* This used to test
-
- -INTVAL (const_arg1) >= 0
-
- But The Sun V5.0 compilers mis-compiled that test. So
- instead we test for the problematic value in a more direct
- manner and hope the Sun compilers get it correct. */
- && INTVAL (const_arg1) !=
- (HOST_WIDE_INT_1 << (HOST_BITS_PER_WIDE_INT - 1))
- && REG_P (folded_arg1))
- {
- rtx new_const = GEN_INT (-INTVAL (const_arg1));
- struct table_elt *p
- = lookup (new_const, SAFE_HASH (new_const, mode), mode);
-
- if (p)
- for (p = p->first_same_value; p; p = p->next_same_value)
- if (REG_P (p->exp))
- return simplify_gen_binary (MINUS, mode, folded_arg0,
- canon_reg (p->exp, NULL));
- }
- goto from_plus;
-
- case MINUS:
- /* If we have (MINUS Y C), see if Y is known to be (PLUS Z C2).
- If so, produce (PLUS Z C2-C). */
- if (const_arg1 != 0 && poly_int_rtx_p (const_arg1, &xval))
- {
- rtx y = lookup_as_function (XEXP (x, 0), PLUS);
- if (y && poly_int_rtx_p (XEXP (y, 1)))
- return fold_rtx (plus_constant (mode, copy_rtx (y), -xval),
- NULL);
- }
-
- /* Fall through. */
-
- from_plus:
- case SMIN: case SMAX: case UMIN: case UMAX:
- case IOR: case AND: case XOR:
- case MULT:
- case ASHIFT: case LSHIFTRT: case ASHIFTRT:
- /* If we have (<op> <reg> <const_int>) for an associative OP and REG
- is known to be of similar form, we may be able to replace the
- operation with a combined operation. This may eliminate the
- intermediate operation if every use is simplified in this way.
- Note that the similar optimization done by combine.c only works
- if the intermediate operation's result has only one reference. */
-
- if (REG_P (folded_arg0)
- && const_arg1 && CONST_INT_P (const_arg1))
- {
- int is_shift
- = (code == ASHIFT || code == ASHIFTRT || code == LSHIFTRT);
- rtx y, inner_const, new_const;
- rtx canon_const_arg1 = const_arg1;
- enum rtx_code associate_code;
-
- if (is_shift
- && (INTVAL (const_arg1) >= GET_MODE_UNIT_PRECISION (mode)
- || INTVAL (const_arg1) < 0))
- {
- if (SHIFT_COUNT_TRUNCATED)
- canon_const_arg1 = gen_int_shift_amount
- (mode, (INTVAL (const_arg1)
- & (GET_MODE_UNIT_BITSIZE (mode) - 1)));
- else
- break;
- }
-
- y = lookup_as_function (folded_arg0, code);
- if (y == 0)
- break;
-
- /* If we have compiled a statement like
- "if (x == (x & mask1))", and now are looking at
- "x & mask2", we will have a case where the first operand
- of Y is the same as our first operand. Unless we detect
- this case, an infinite loop will result. */
- if (XEXP (y, 0) == folded_arg0)
- break;
-
- inner_const = equiv_constant (fold_rtx (XEXP (y, 1), 0));
- if (!inner_const || !CONST_INT_P (inner_const))
- break;
-
- /* Don't associate these operations if they are a PLUS with the
- same constant and it is a power of two. These might be doable
- with a pre- or post-increment. Similarly for two subtracts of
- identical powers of two with post decrement. */
-
- if (code == PLUS && const_arg1 == inner_const
- && ((HAVE_PRE_INCREMENT
- && pow2p_hwi (INTVAL (const_arg1)))
- || (HAVE_POST_INCREMENT
- && pow2p_hwi (INTVAL (const_arg1)))
- || (HAVE_PRE_DECREMENT
- && pow2p_hwi (- INTVAL (const_arg1)))
- || (HAVE_POST_DECREMENT
- && pow2p_hwi (- INTVAL (const_arg1)))))
- break;
-
- /* ??? Vector mode shifts by scalar
- shift operand are not supported yet. */
- if (is_shift && VECTOR_MODE_P (mode))
- break;
-
- if (is_shift
- && (INTVAL (inner_const) >= GET_MODE_UNIT_PRECISION (mode)
- || INTVAL (inner_const) < 0))
- {
- if (SHIFT_COUNT_TRUNCATED)
- inner_const = gen_int_shift_amount
- (mode, (INTVAL (inner_const)
- & (GET_MODE_UNIT_BITSIZE (mode) - 1)));
- else
- break;
- }
-
- /* Compute the code used to compose the constants. For example,
- A-C1-C2 is A-(C1 + C2), so if CODE == MINUS, we want PLUS. */
-
- associate_code = (is_shift || code == MINUS ? PLUS : code);
-
- new_const = simplify_binary_operation (associate_code, mode,
- canon_const_arg1,
- inner_const);
-
- if (new_const == 0)
- break;
-
- /* If we are associating shift operations, don't let this
- produce a shift of the size of the object or larger.
- This could occur when we follow a sign-extend by a right
- shift on a machine that does a sign-extend as a pair
- of shifts. */
-
- if (is_shift
- && CONST_INT_P (new_const)
- && INTVAL (new_const) >= GET_MODE_UNIT_PRECISION (mode))
- {
- /* As an exception, we can turn an ASHIFTRT of this
- form into a shift of the number of bits - 1. */
- if (code == ASHIFTRT)
- new_const = gen_int_shift_amount
- (mode, GET_MODE_UNIT_BITSIZE (mode) - 1);
- else if (!side_effects_p (XEXP (y, 0)))
- return CONST0_RTX (mode);
- else
- break;
- }
-
- y = copy_rtx (XEXP (y, 0));
-
- /* If Y contains our first operand (the most common way this
- can happen is if Y is a MEM), we would do into an infinite
- loop if we tried to fold it. So don't in that case. */
-
- if (! reg_mentioned_p (folded_arg0, y))
- y = fold_rtx (y, insn);
-
- return simplify_gen_binary (code, mode, y, new_const);
- }
- break;
-
- case DIV: case UDIV:
- /* ??? The associative optimization performed immediately above is
- also possible for DIV and UDIV using associate_code of MULT.
- However, we would need extra code to verify that the
- multiplication does not overflow, that is, there is no overflow
- in the calculation of new_const. */
- break;
-
- default:
- break;
- }
-
- new_rtx = simplify_binary_operation (code, mode,
- const_arg0 ? const_arg0 : folded_arg0,
- const_arg1 ? const_arg1 : folded_arg1);
- break;
-
- case RTX_OBJ:
- /* (lo_sum (high X) X) is simply X. */
- if (code == LO_SUM && const_arg0 != 0
- && GET_CODE (const_arg0) == HIGH
- && rtx_equal_p (XEXP (const_arg0, 0), const_arg1))
- return const_arg1;
- break;
-
- case RTX_TERNARY:
- case RTX_BITFIELD_OPS:
- new_rtx = simplify_ternary_operation (code, mode, mode_arg0,
- const_arg0 ? const_arg0 : folded_arg0,
- const_arg1 ? const_arg1 : folded_arg1,
- const_arg2 ? const_arg2 : XEXP (x, 2));
- break;
-
- default:
- break;
- }
-
- return new_rtx ? new_rtx : x;
-}
-
-/* Return a constant value currently equivalent to X.
- Return 0 if we don't know one. */
-
-static rtx
-equiv_constant (rtx x)
-{
- if (REG_P (x)
- && REGNO_QTY_VALID_P (REGNO (x)))
- {
- int x_q = REG_QTY (REGNO (x));
- struct qty_table_elem *x_ent = &qty_table[x_q];
-
- if (x_ent->const_rtx)
- x = gen_lowpart (GET_MODE (x), x_ent->const_rtx);
- }
-
- if (x == 0 || CONSTANT_P (x))
- return x;
-
- if (GET_CODE (x) == SUBREG)
- {
- machine_mode mode = GET_MODE (x);
- machine_mode imode = GET_MODE (SUBREG_REG (x));
- rtx new_rtx;
-
- /* See if we previously assigned a constant value to this SUBREG. */
- if ((new_rtx = lookup_as_function (x, CONST_INT)) != 0
- || (new_rtx = lookup_as_function (x, CONST_WIDE_INT)) != 0
- || (NUM_POLY_INT_COEFFS > 1
- && (new_rtx = lookup_as_function (x, CONST_POLY_INT)) != 0)
- || (new_rtx = lookup_as_function (x, CONST_DOUBLE)) != 0
- || (new_rtx = lookup_as_function (x, CONST_FIXED)) != 0)
- return new_rtx;
-
- /* If we didn't and if doing so makes sense, see if we previously
- assigned a constant value to the enclosing word mode SUBREG. */
- if (known_lt (GET_MODE_SIZE (mode), UNITS_PER_WORD)
- && known_lt (UNITS_PER_WORD, GET_MODE_SIZE (imode)))
- {
- poly_int64 byte = (SUBREG_BYTE (x)
- - subreg_lowpart_offset (mode, word_mode));
- if (known_ge (byte, 0) && multiple_p (byte, UNITS_PER_WORD))
- {
- rtx y = gen_rtx_SUBREG (word_mode, SUBREG_REG (x), byte);
- new_rtx = lookup_as_function (y, CONST_INT);
- if (new_rtx)
- return gen_lowpart (mode, new_rtx);
- }
- }
-
- /* Otherwise see if we already have a constant for the inner REG,
- and if that is enough to calculate an equivalent constant for
- the subreg. Note that the upper bits of paradoxical subregs
- are undefined, so they cannot be said to equal anything. */
- if (REG_P (SUBREG_REG (x))
- && !paradoxical_subreg_p (x)
- && (new_rtx = equiv_constant (SUBREG_REG (x))) != 0)
- return simplify_subreg (mode, new_rtx, imode, SUBREG_BYTE (x));
-
- return 0;
- }
-
- /* If X is a MEM, see if it is a constant-pool reference, or look it up in
- the hash table in case its value was seen before. */
-
- if (MEM_P (x))
- {
- struct table_elt *elt;
-
- x = avoid_constant_pool_reference (x);
- if (CONSTANT_P (x))
- return x;
-
- elt = lookup (x, SAFE_HASH (x, GET_MODE (x)), GET_MODE (x));
- if (elt == 0)
- return 0;
-
- for (elt = elt->first_same_value; elt; elt = elt->next_same_value)
- if (elt->is_const && CONSTANT_P (elt->exp))
- return elt->exp;
- }
-
- return 0;
-}
-
-/* Given INSN, a jump insn, TAKEN indicates if we are following the
- "taken" branch.
-
- In certain cases, this can cause us to add an equivalence. For example,
- if we are following the taken case of
- if (i == 2)
- we can add the fact that `i' and '2' are now equivalent.
-
- In any case, we can record that this comparison was passed. If the same
- comparison is seen later, we will know its value. */
-
-static void
-record_jump_equiv (rtx_insn *insn, bool taken)
-{
- int cond_known_true;
- rtx op0, op1;
- rtx set;
- machine_mode mode, mode0, mode1;
- int reversed_nonequality = 0;
- enum rtx_code code;
-
- /* Ensure this is the right kind of insn. */
- gcc_assert (any_condjump_p (insn));
-
- set = pc_set (insn);
-
- /* See if this jump condition is known true or false. */
- if (taken)
- cond_known_true = (XEXP (SET_SRC (set), 2) == pc_rtx);
- else
- cond_known_true = (XEXP (SET_SRC (set), 1) == pc_rtx);
-
- /* Get the type of comparison being done and the operands being compared.
- If we had to reverse a non-equality condition, record that fact so we
- know that it isn't valid for floating-point. */
- code = GET_CODE (XEXP (SET_SRC (set), 0));
- op0 = fold_rtx (XEXP (XEXP (SET_SRC (set), 0), 0), insn);
- op1 = fold_rtx (XEXP (XEXP (SET_SRC (set), 0), 1), insn);
-
- /* If fold_rtx returns NULL_RTX, there's nothing to record. */
- if (op0 == NULL_RTX || op1 == NULL_RTX)
- return;
-
- code = find_comparison_args (code, &op0, &op1, &mode0, &mode1);
- if (! cond_known_true)
- {
- code = reversed_comparison_code_parts (code, op0, op1, insn);
-
- /* Don't remember if we can't find the inverse. */
- if (code == UNKNOWN)
- return;
- }
-
- /* The mode is the mode of the non-constant. */
- mode = mode0;
- if (mode1 != VOIDmode)
- mode = mode1;
-
- record_jump_cond (code, mode, op0, op1, reversed_nonequality);
-}
-
-/* Yet another form of subreg creation. In this case, we want something in
- MODE, and we should assume OP has MODE iff it is naturally modeless. */
-
-static rtx
-record_jump_cond_subreg (machine_mode mode, rtx op)
-{
- machine_mode op_mode = GET_MODE (op);
- if (op_mode == mode || op_mode == VOIDmode)
- return op;
- return lowpart_subreg (mode, op, op_mode);
-}
-
-/* We know that comparison CODE applied to OP0 and OP1 in MODE is true.
- REVERSED_NONEQUALITY is nonzero if CODE had to be swapped.
- Make any useful entries we can with that information. Called from
- above function and called recursively. */
-
-static void
-record_jump_cond (enum rtx_code code, machine_mode mode, rtx op0,
- rtx op1, int reversed_nonequality)
-{
- unsigned op0_hash, op1_hash;
- int op0_in_memory, op1_in_memory;
- struct table_elt *op0_elt, *op1_elt;
-
- /* If OP0 and OP1 are known equal, and either is a paradoxical SUBREG,
- we know that they are also equal in the smaller mode (this is also
- true for all smaller modes whether or not there is a SUBREG, but
- is not worth testing for with no SUBREG). */
-
- /* Note that GET_MODE (op0) may not equal MODE. */
- if (code == EQ && paradoxical_subreg_p (op0))
- {
- machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
- rtx tem = record_jump_cond_subreg (inner_mode, op1);
- if (tem)
- record_jump_cond (code, mode, SUBREG_REG (op0), tem,
- reversed_nonequality);
- }
-
- if (code == EQ && paradoxical_subreg_p (op1))
- {
- machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
- rtx tem = record_jump_cond_subreg (inner_mode, op0);
- if (tem)
- record_jump_cond (code, mode, SUBREG_REG (op1), tem,
- reversed_nonequality);
- }
-
- /* Similarly, if this is an NE comparison, and either is a SUBREG
- making a smaller mode, we know the whole thing is also NE. */
-
- /* Note that GET_MODE (op0) may not equal MODE;
- if we test MODE instead, we can get an infinite recursion
- alternating between two modes each wider than MODE. */
-
- if (code == NE
- && partial_subreg_p (op0)
- && subreg_lowpart_p (op0))
- {
- machine_mode inner_mode = GET_MODE (SUBREG_REG (op0));
- rtx tem = record_jump_cond_subreg (inner_mode, op1);
- if (tem)
- record_jump_cond (code, mode, SUBREG_REG (op0), tem,
- reversed_nonequality);
- }
-
- if (code == NE
- && partial_subreg_p (op1)
- && subreg_lowpart_p (op1))
- {
- machine_mode inner_mode = GET_MODE (SUBREG_REG (op1));
- rtx tem = record_jump_cond_subreg (inner_mode, op0);
- if (tem)
- record_jump_cond (code, mode, SUBREG_REG (op1), tem,
- reversed_nonequality);
- }
-
- /* Hash both operands. */
-
- do_not_record = 0;
- hash_arg_in_memory = 0;
- op0_hash = HASH (op0, mode);
- op0_in_memory = hash_arg_in_memory;
-
- if (do_not_record)
- return;
-
- do_not_record = 0;
- hash_arg_in_memory = 0;
- op1_hash = HASH (op1, mode);
- op1_in_memory = hash_arg_in_memory;
-
- if (do_not_record)
- return;
-
- /* Look up both operands. */
- op0_elt = lookup (op0, op0_hash, mode);
- op1_elt = lookup (op1, op1_hash, mode);
-
- /* If both operands are already equivalent or if they are not in the
- table but are identical, do nothing. */
- if ((op0_elt != 0 && op1_elt != 0
- && op0_elt->first_same_value == op1_elt->first_same_value)
- || op0 == op1 || rtx_equal_p (op0, op1))
- return;
-
- /* If we aren't setting two things equal all we can do is save this
- comparison. Similarly if this is floating-point. In the latter
- case, OP1 might be zero and both -0.0 and 0.0 are equal to it.
- If we record the equality, we might inadvertently delete code
- whose intent was to change -0 to +0. */
-
- if (code != EQ || FLOAT_MODE_P (GET_MODE (op0)))
- {
- struct qty_table_elem *ent;
- int qty;
-
- /* If we reversed a floating-point comparison, if OP0 is not a
- register, or if OP1 is neither a register or constant, we can't
- do anything. */
-
- if (!REG_P (op1))
- op1 = equiv_constant (op1);
-
- if ((reversed_nonequality && FLOAT_MODE_P (mode))
- || !REG_P (op0) || op1 == 0)
- return;
-
- /* Put OP0 in the hash table if it isn't already. This gives it a
- new quantity number. */
- if (op0_elt == 0)
- {
- if (insert_regs (op0, NULL, 0))
- {
- rehash_using_reg (op0);
- op0_hash = HASH (op0, mode);
-
- /* If OP0 is contained in OP1, this changes its hash code
- as well. Faster to rehash than to check, except
- for the simple case of a constant. */
- if (! CONSTANT_P (op1))
- op1_hash = HASH (op1,mode);
- }
-
- op0_elt = insert (op0, NULL, op0_hash, mode);
- op0_elt->in_memory = op0_in_memory;
- }
-
- qty = REG_QTY (REGNO (op0));
- ent = &qty_table[qty];
-
- ent->comparison_code = code;
- if (REG_P (op1))
- {
- /* Look it up again--in case op0 and op1 are the same. */
- op1_elt = lookup (op1, op1_hash, mode);
-
- /* Put OP1 in the hash table so it gets a new quantity number. */
- if (op1_elt == 0)
- {
- if (insert_regs (op1, NULL, 0))
- {
- rehash_using_reg (op1);
- op1_hash = HASH (op1, mode);
- }
-
- op1_elt = insert (op1, NULL, op1_hash, mode);
- op1_elt->in_memory = op1_in_memory;
- }
-
- ent->comparison_const = NULL_RTX;
- ent->comparison_qty = REG_QTY (REGNO (op1));
- }
- else
- {
- ent->comparison_const = op1;
- ent->comparison_qty = -1;
- }
-
- return;
- }
-
- /* If either side is still missing an equivalence, make it now,
- then merge the equivalences. */
-
- if (op0_elt == 0)
- {
- if (insert_regs (op0, NULL, 0))
- {
- rehash_using_reg (op0);
- op0_hash = HASH (op0, mode);
- }
-
- op0_elt = insert (op0, NULL, op0_hash, mode);
- op0_elt->in_memory = op0_in_memory;
- }
-
- if (op1_elt == 0)
- {
- if (insert_regs (op1, NULL, 0))
- {
- rehash_using_reg (op1);
- op1_hash = HASH (op1, mode);
- }
-
- op1_elt = insert (op1, NULL, op1_hash, mode);
- op1_elt->in_memory = op1_in_memory;
- }
-
- merge_equiv_classes (op0_elt, op1_elt);
-}
-
-/* CSE processing for one instruction.
-
- Most "true" common subexpressions are mostly optimized away in GIMPLE,
- but the few that "leak through" are cleaned up by cse_insn, and complex
- addressing modes are often formed here.
-
- The main function is cse_insn, and between here and that function
- a couple of helper functions is defined to keep the size of cse_insn
- within reasonable proportions.
-
- Data is shared between the main and helper functions via STRUCT SET,
- that contains all data related for every set in the instruction that
- is being processed.
-
- Note that cse_main processes all sets in the instruction. Most
- passes in GCC only process simple SET insns or single_set insns, but
- CSE processes insns with multiple sets as well. */
-
-/* Data on one SET contained in the instruction. */
-
-struct set
-{
- /* The SET rtx itself. */
- rtx rtl;
- /* The SET_SRC of the rtx (the original value, if it is changing). */
- rtx src;
- /* The hash-table element for the SET_SRC of the SET. */
- struct table_elt *src_elt;
- /* Hash value for the SET_SRC. */
- unsigned src_hash;
- /* Hash value for the SET_DEST. */
- unsigned dest_hash;
- /* The SET_DEST, with SUBREG, etc., stripped. */
- rtx inner_dest;
- /* Nonzero if the SET_SRC is in memory. */
- char src_in_memory;
- /* Nonzero if the SET_SRC contains something
- whose value cannot be predicted and understood. */
- char src_volatile;
- /* Original machine mode, in case it becomes a CONST_INT.
- The size of this field should match the size of the mode
- field of struct rtx_def (see rtl.h). */
- ENUM_BITFIELD(machine_mode) mode : 8;
- /* Hash value of constant equivalent for SET_SRC. */
- unsigned src_const_hash;
- /* A constant equivalent for SET_SRC, if any. */
- rtx src_const;
- /* Table entry for constant equivalent for SET_SRC, if any. */
- struct table_elt *src_const_elt;
- /* Table entry for the destination address. */
- struct table_elt *dest_addr_elt;
-};
-
-/* Special handling for (set REG0 REG1) where REG0 is the
- "cheapest", cheaper than REG1. After cse, REG1 will probably not
- be used in the sequel, so (if easily done) change this insn to
- (set REG1 REG0) and replace REG1 with REG0 in the previous insn
- that computed their value. Then REG1 will become a dead store
- and won't cloud the situation for later optimizations.
-
- Do not make this change if REG1 is a hard register, because it will
- then be used in the sequel and we may be changing a two-operand insn
- into a three-operand insn.
-
- This is the last transformation that cse_insn will try to do. */
-
-static void
-try_back_substitute_reg (rtx set, rtx_insn *insn)
-{
- rtx dest = SET_DEST (set);
- rtx src = SET_SRC (set);
-
- if (REG_P (dest)
- && REG_P (src) && ! HARD_REGISTER_P (src)
- && REGNO_QTY_VALID_P (REGNO (src)))
- {
- int src_q = REG_QTY (REGNO (src));
- struct qty_table_elem *src_ent = &qty_table[src_q];
-
- if (src_ent->first_reg == REGNO (dest))
- {
- /* Scan for the previous nonnote insn, but stop at a basic
- block boundary. */
- rtx_insn *prev = insn;
- rtx_insn *bb_head = BB_HEAD (BLOCK_FOR_INSN (insn));
- do
- {
- prev = PREV_INSN (prev);
- }
- while (prev != bb_head && (NOTE_P (prev) || DEBUG_INSN_P (prev)));
-
- /* Do not swap the registers around if the previous instruction
- attaches a REG_EQUIV note to REG1.
-
- ??? It's not entirely clear whether we can transfer a REG_EQUIV
- from the pseudo that originally shadowed an incoming argument
- to another register. Some uses of REG_EQUIV might rely on it
- being attached to REG1 rather than REG2.
-
- This section previously turned the REG_EQUIV into a REG_EQUAL
- note. We cannot do that because REG_EQUIV may provide an
- uninitialized stack slot when REG_PARM_STACK_SPACE is used. */
- if (NONJUMP_INSN_P (prev)
- && GET_CODE (PATTERN (prev)) == SET
- && SET_DEST (PATTERN (prev)) == src
- && ! find_reg_note (prev, REG_EQUIV, NULL_RTX))
- {
- rtx note;
-
- validate_change (prev, &SET_DEST (PATTERN (prev)), dest, 1);
- validate_change (insn, &SET_DEST (set), src, 1);
- validate_change (insn, &SET_SRC (set), dest, 1);
- apply_change_group ();
-
- /* If INSN has a REG_EQUAL note, and this note mentions
- REG0, then we must delete it, because the value in
- REG0 has changed. If the note's value is REG1, we must
- also delete it because that is now this insn's dest. */
- note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- if (note != 0
- && (reg_mentioned_p (dest, XEXP (note, 0))
- || rtx_equal_p (src, XEXP (note, 0))))
- remove_note (insn, note);
-
- /* If INSN has a REG_ARGS_SIZE note, move it to PREV. */
- note = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX);
- if (note != 0)
- {
- remove_note (insn, note);
- gcc_assert (!find_reg_note (prev, REG_ARGS_SIZE, NULL_RTX));
- set_unique_reg_note (prev, REG_ARGS_SIZE, XEXP (note, 0));
- }
- }
- }
- }
-}
-
-/* Add an entry containing RTL X into SETS. */
-static inline void
-add_to_set (vec<struct set> *sets, rtx x)
-{
- struct set entry = {};
- entry.rtl = x;
- sets->safe_push (entry);
-}
-
-/* Record all the SETs in this instruction into SETS_PTR,
- and return the number of recorded sets. */
-static int
-find_sets_in_insn (rtx_insn *insn, vec<struct set> *psets)
-{
- rtx x = PATTERN (insn);
-
- if (GET_CODE (x) == SET)
- {
- /* Ignore SETs that are unconditional jumps.
- They never need cse processing, so this does not hurt.
- The reason is not efficiency but rather
- so that we can test at the end for instructions
- that have been simplified to unconditional jumps
- and not be misled by unchanged instructions
- that were unconditional jumps to begin with. */
- if (SET_DEST (x) == pc_rtx
- && GET_CODE (SET_SRC (x)) == LABEL_REF)
- ;
- /* Don't count call-insns, (set (reg 0) (call ...)), as a set.
- The hard function value register is used only once, to copy to
- someplace else, so it isn't worth cse'ing. */
- else if (GET_CODE (SET_SRC (x)) == CALL)
- ;
- else if (GET_CODE (SET_SRC (x)) == CONST_VECTOR
- && GET_MODE_CLASS (GET_MODE (SET_SRC (x))) != MODE_VECTOR_BOOL
- /* Prevent duplicates from being generated if the type is a V1
- type and a subreg. Folding this will result in the same
- element as folding x itself. */
- && !(SUBREG_P (SET_DEST (x))
- && known_eq (GET_MODE_NUNITS (GET_MODE (SET_SRC (x))), 1)))
- {
- /* First register the vector itself. */
- add_to_set (psets, x);
- rtx src = SET_SRC (x);
- /* Go over the constants of the CONST_VECTOR in forward order, to
- put them in the same order in the SETS array. */
- for (unsigned i = 0; i < const_vector_encoded_nelts (src) ; i++)
- {
- /* These are templates and don't actually get emitted but are
- used to tell CSE how to get to a particular constant. */
- rtx y = simplify_gen_vec_select (SET_DEST (x), i);
- gcc_assert (y);
- add_to_set (psets, gen_rtx_SET (y, CONST_VECTOR_ELT (src, i)));
- }
- }
- else
- add_to_set (psets, x);
- }
- else if (GET_CODE (x) == PARALLEL)
- {
- int i, lim = XVECLEN (x, 0);
-
- /* Go over the expressions of the PARALLEL in forward order, to
- put them in the same order in the SETS array. */
- for (i = 0; i < lim; i++)
- {
- rtx y = XVECEXP (x, 0, i);
- if (GET_CODE (y) == SET)
- {
- /* As above, we ignore unconditional jumps and call-insns and
- ignore the result of apply_change_group. */
- if (SET_DEST (y) == pc_rtx
- && GET_CODE (SET_SRC (y)) == LABEL_REF)
- ;
- else if (GET_CODE (SET_SRC (y)) == CALL)
- ;
- else
- add_to_set (psets, y);
- }
- }
- }
-
- return psets->length ();
-}
-
-/* Subroutine of canonicalize_insn. X is an ASM_OPERANDS in INSN. */
-
-static void
-canon_asm_operands (rtx x, rtx_insn *insn)
-{
- for (int i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
- {
- rtx input = ASM_OPERANDS_INPUT (x, i);
- if (!(REG_P (input) && HARD_REGISTER_P (input)))
- {
- input = canon_reg (input, insn);
- validate_change (insn, &ASM_OPERANDS_INPUT (x, i), input, 1);
- }
- }
-}
-
-/* Where possible, substitute every register reference in the N_SETS
- number of SETS in INSN with the canonical register.
-
- Register canonicalization propagatest the earliest register (i.e.
- one that is set before INSN) with the same value. This is a very
- useful, simple form of CSE, to clean up warts from expanding GIMPLE
- to RTL. For instance, a CONST for an address is usually expanded
- multiple times to loads into different registers, thus creating many
- subexpressions of the form:
-
- (set (reg1) (some_const))
- (set (mem (... reg1 ...) (thing)))
- (set (reg2) (some_const))
- (set (mem (... reg2 ...) (thing)))
-
- After canonicalizing, the code takes the following form:
-
- (set (reg1) (some_const))
- (set (mem (... reg1 ...) (thing)))
- (set (reg2) (some_const))
- (set (mem (... reg1 ...) (thing)))
-
- The set to reg2 is now trivially dead, and the memory reference (or
- address, or whatever) may be a candidate for further CSEing.
-
- In this function, the result of apply_change_group can be ignored;
- see canon_reg. */
-
-static void
-canonicalize_insn (rtx_insn *insn, vec<struct set> *psets)
-{
- vec<struct set> sets = *psets;
- int n_sets = sets.length ();
- rtx tem;
- rtx x = PATTERN (insn);
- int i;
-
- if (CALL_P (insn))
- {
- for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
- if (GET_CODE (XEXP (tem, 0)) != SET)
- XEXP (tem, 0) = canon_reg (XEXP (tem, 0), insn);
- }
-
- if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
- {
- canon_reg (SET_SRC (x), insn);
- apply_change_group ();
- fold_rtx (SET_SRC (x), insn);
- }
- else if (GET_CODE (x) == CLOBBER)
- {
- /* If we clobber memory, canon the address.
- This does nothing when a register is clobbered
- because we have already invalidated the reg. */
- if (MEM_P (XEXP (x, 0)))
- canon_reg (XEXP (x, 0), insn);
- }
- else if (GET_CODE (x) == USE
- && ! (REG_P (XEXP (x, 0))
- && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER))
- /* Canonicalize a USE of a pseudo register or memory location. */
- canon_reg (x, insn);
- else if (GET_CODE (x) == ASM_OPERANDS)
- canon_asm_operands (x, insn);
- else if (GET_CODE (x) == CALL)
- {
- canon_reg (x, insn);
- apply_change_group ();
- fold_rtx (x, insn);
- }
- else if (DEBUG_INSN_P (insn))
- canon_reg (PATTERN (insn), insn);
- else if (GET_CODE (x) == PARALLEL)
- {
- for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- {
- rtx y = XVECEXP (x, 0, i);
- if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
- {
- canon_reg (SET_SRC (y), insn);
- apply_change_group ();
- fold_rtx (SET_SRC (y), insn);
- }
- else if (GET_CODE (y) == CLOBBER)
- {
- if (MEM_P (XEXP (y, 0)))
- canon_reg (XEXP (y, 0), insn);
- }
- else if (GET_CODE (y) == USE
- && ! (REG_P (XEXP (y, 0))
- && REGNO (XEXP (y, 0)) < FIRST_PSEUDO_REGISTER))
- canon_reg (y, insn);
- else if (GET_CODE (y) == ASM_OPERANDS)
- canon_asm_operands (y, insn);
- else if (GET_CODE (y) == CALL)
- {
- canon_reg (y, insn);
- apply_change_group ();
- fold_rtx (y, insn);
- }
- }
- }
-
- if (n_sets == 1 && REG_NOTES (insn) != 0
- && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
- {
- /* We potentially will process this insn many times. Therefore,
- drop the REG_EQUAL note if it is equal to the SET_SRC of the
- unique set in INSN.
-
- Do not do so if the REG_EQUAL note is for a STRICT_LOW_PART,
- because cse_insn handles those specially. */
- if (GET_CODE (SET_DEST (sets[0].rtl)) != STRICT_LOW_PART
- && rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl)))
- remove_note (insn, tem);
- else
- {
- canon_reg (XEXP (tem, 0), insn);
- apply_change_group ();
- XEXP (tem, 0) = fold_rtx (XEXP (tem, 0), insn);
- df_notes_rescan (insn);
- }
- }
-
- /* Canonicalize sources and addresses of destinations.
- We do this in a separate pass to avoid problems when a MATCH_DUP is
- present in the insn pattern. In that case, we want to ensure that
- we don't break the duplicate nature of the pattern. So we will replace
- both operands at the same time. Otherwise, we would fail to find an
- equivalent substitution in the loop calling validate_change below.
-
- We used to suppress canonicalization of DEST if it appears in SRC,
- but we don't do this any more. */
-
- for (i = 0; i < n_sets; i++)
- {
- rtx dest = SET_DEST (sets[i].rtl);
- rtx src = SET_SRC (sets[i].rtl);
- rtx new_rtx = canon_reg (src, insn);
-
- validate_change (insn, &SET_SRC (sets[i].rtl), new_rtx, 1);
-
- if (GET_CODE (dest) == ZERO_EXTRACT)
- {
- validate_change (insn, &XEXP (dest, 1),
- canon_reg (XEXP (dest, 1), insn), 1);
- validate_change (insn, &XEXP (dest, 2),
- canon_reg (XEXP (dest, 2), insn), 1);
- }
-
- while (GET_CODE (dest) == SUBREG
- || GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == STRICT_LOW_PART)
- dest = XEXP (dest, 0);
-
- if (MEM_P (dest))
- canon_reg (dest, insn);
- }
-
- /* Now that we have done all the replacements, we can apply the change
- group and see if they all work. Note that this will cause some
- canonicalizations that would have worked individually not to be applied
- because some other canonicalization didn't work, but this should not
- occur often.
-
- The result of apply_change_group can be ignored; see canon_reg. */
-
- apply_change_group ();
-}
-
-/* Main function of CSE.
- First simplify sources and addresses of all assignments
- in the instruction, using previously-computed equivalents values.
- Then install the new sources and destinations in the table
- of available values. */
-
-static void
-cse_insn (rtx_insn *insn)
-{
- rtx x = PATTERN (insn);
- int i;
- rtx tem;
- int n_sets = 0;
-
- rtx src_eqv = 0;
- struct table_elt *src_eqv_elt = 0;
- int src_eqv_volatile = 0;
- int src_eqv_in_memory = 0;
- unsigned src_eqv_hash = 0;
-
- this_insn = insn;
-
- /* Find all regs explicitly clobbered in this insn,
- to ensure they are not replaced with any other regs
- elsewhere in this insn. */
- invalidate_from_sets_and_clobbers (insn);
-
- /* Record all the SETs in this instruction. */
- auto_vec<struct set, 8> sets;
- n_sets = find_sets_in_insn (insn, (vec<struct set>*)&sets);
-
- /* Substitute the canonical register where possible. */
- canonicalize_insn (insn, (vec<struct set>*)&sets);
-
- /* If this insn has a REG_EQUAL note, store the equivalent value in SRC_EQV,
- if different, or if the DEST is a STRICT_LOW_PART/ZERO_EXTRACT. The
- latter condition is necessary because SRC_EQV is handled specially for
- this case, and if it isn't set, then there will be no equivalence
- for the destination. */
- if (n_sets == 1 && REG_NOTES (insn) != 0
- && (tem = find_reg_note (insn, REG_EQUAL, NULL_RTX)) != 0)
- {
-
- if (GET_CODE (SET_DEST (sets[0].rtl)) != ZERO_EXTRACT
- && (! rtx_equal_p (XEXP (tem, 0), SET_SRC (sets[0].rtl))
- || GET_CODE (SET_DEST (sets[0].rtl)) == STRICT_LOW_PART))
- src_eqv = copy_rtx (XEXP (tem, 0));
- /* If DEST is of the form ZERO_EXTACT, as in:
- (set (zero_extract:SI (reg:SI 119)
- (const_int 16 [0x10])
- (const_int 16 [0x10]))
- (const_int 51154 [0xc7d2]))
- REG_EQUAL note will specify the value of register (reg:SI 119) at this
- point. Note that this is different from SRC_EQV. We can however
- calculate SRC_EQV with the position and width of ZERO_EXTRACT. */
- else if (GET_CODE (SET_DEST (sets[0].rtl)) == ZERO_EXTRACT
- && CONST_INT_P (XEXP (tem, 0))
- && CONST_INT_P (XEXP (SET_DEST (sets[0].rtl), 1))
- && CONST_INT_P (XEXP (SET_DEST (sets[0].rtl), 2)))
- {
- rtx dest_reg = XEXP (SET_DEST (sets[0].rtl), 0);
- /* This is the mode of XEXP (tem, 0) as well. */
- scalar_int_mode dest_mode
- = as_a <scalar_int_mode> (GET_MODE (dest_reg));
- rtx width = XEXP (SET_DEST (sets[0].rtl), 1);
- rtx pos = XEXP (SET_DEST (sets[0].rtl), 2);
- HOST_WIDE_INT val = INTVAL (XEXP (tem, 0));
- HOST_WIDE_INT mask;
- unsigned int shift;
- if (BITS_BIG_ENDIAN)
- shift = (GET_MODE_PRECISION (dest_mode)
- - INTVAL (pos) - INTVAL (width));
- else
- shift = INTVAL (pos);
- if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
- mask = HOST_WIDE_INT_M1;
- else
- mask = (HOST_WIDE_INT_1 << INTVAL (width)) - 1;
- val = (val >> shift) & mask;
- src_eqv = GEN_INT (val);
- }
- }
-
- /* Set sets[i].src_elt to the class each source belongs to.
- Detect assignments from or to volatile things
- and set set[i] to zero so they will be ignored
- in the rest of this function.
-
- Nothing in this loop changes the hash table or the register chains. */
-
- for (i = 0; i < n_sets; i++)
- {
- bool repeat = false;
- bool noop_insn = false;
- rtx src, dest;
- rtx src_folded;
- struct table_elt *elt = 0, *p;
- machine_mode mode;
- rtx src_eqv_here;
- rtx src_const = 0;
- rtx src_related = 0;
- bool src_related_is_const_anchor = false;
- struct table_elt *src_const_elt = 0;
- int src_cost = MAX_COST;
- int src_eqv_cost = MAX_COST;
- int src_folded_cost = MAX_COST;
- int src_related_cost = MAX_COST;
- int src_elt_cost = MAX_COST;
- int src_regcost = MAX_COST;
- int src_eqv_regcost = MAX_COST;
- int src_folded_regcost = MAX_COST;
- int src_related_regcost = MAX_COST;
- int src_elt_regcost = MAX_COST;
- scalar_int_mode int_mode;
-
- dest = SET_DEST (sets[i].rtl);
- src = SET_SRC (sets[i].rtl);
-
- /* If SRC is a constant that has no machine mode,
- hash it with the destination's machine mode.
- This way we can keep different modes separate. */
-
- mode = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
- sets[i].mode = mode;
-
- if (src_eqv)
- {
- machine_mode eqvmode = mode;
- if (GET_CODE (dest) == STRICT_LOW_PART)
- eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
- do_not_record = 0;
- hash_arg_in_memory = 0;
- src_eqv_hash = HASH (src_eqv, eqvmode);
-
- /* Find the equivalence class for the equivalent expression. */
-
- if (!do_not_record)
- src_eqv_elt = lookup (src_eqv, src_eqv_hash, eqvmode);
-
- src_eqv_volatile = do_not_record;
- src_eqv_in_memory = hash_arg_in_memory;
- }
-
- /* If this is a STRICT_LOW_PART assignment, src_eqv corresponds to the
- value of the INNER register, not the destination. So it is not
- a valid substitution for the source. But save it for later. */
- if (GET_CODE (dest) == STRICT_LOW_PART)
- src_eqv_here = 0;
- else
- src_eqv_here = src_eqv;
-
- /* Simplify and foldable subexpressions in SRC. Then get the fully-
- simplified result, which may not necessarily be valid. */
- src_folded = fold_rtx (src, NULL);
-
-#if 0
- /* ??? This caused bad code to be generated for the m68k port with -O2.
- Suppose src is (CONST_INT -1), and that after truncation src_folded
- is (CONST_INT 3). Suppose src_folded is then used for src_const.
- At the end we will add src and src_const to the same equivalence
- class. We now have 3 and -1 on the same equivalence class. This
- causes later instructions to be mis-optimized. */
- /* If storing a constant in a bitfield, pre-truncate the constant
- so we will be able to record it later. */
- if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT)
- {
- rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
-
- if (CONST_INT_P (src)
- && CONST_INT_P (width)
- && INTVAL (width) < HOST_BITS_PER_WIDE_INT
- && (INTVAL (src) & ((HOST_WIDE_INT) (-1) << INTVAL (width))))
- src_folded
- = GEN_INT (INTVAL (src) & ((HOST_WIDE_INT_1
- << INTVAL (width)) - 1));
- }
-#endif
-
- /* Compute SRC's hash code, and also notice if it
- should not be recorded at all. In that case,
- prevent any further processing of this assignment.
-
- We set DO_NOT_RECORD if the destination has a REG_UNUSED note.
- This avoids getting the source register into the tables, where it
- may be invalidated later (via REG_QTY), then trigger an ICE upon
- re-insertion.
-
- This is only a problem in multi-set insns. If it were a single
- set the dead copy would have been removed. If the RHS were anything
- but a simple REG, then we won't call insert_regs and thus there's
- no potential for triggering the ICE. */
- do_not_record = (REG_P (dest)
- && REG_P (src)
- && find_reg_note (insn, REG_UNUSED, dest));
- hash_arg_in_memory = 0;
-
- sets[i].src = src;
- sets[i].src_hash = HASH (src, mode);
- sets[i].src_volatile = do_not_record;
- sets[i].src_in_memory = hash_arg_in_memory;
-
- /* If SRC is a MEM, there is a REG_EQUIV note for SRC, and DEST is
- a pseudo, do not record SRC. Using SRC as a replacement for
- anything else will be incorrect in that situation. Note that
- this usually occurs only for stack slots, in which case all the
- RTL would be referring to SRC, so we don't lose any optimization
- opportunities by not having SRC in the hash table. */
-
- if (MEM_P (src)
- && find_reg_note (insn, REG_EQUIV, NULL_RTX) != 0
- && REG_P (dest)
- && REGNO (dest) >= FIRST_PSEUDO_REGISTER)
- sets[i].src_volatile = 1;
-
- else if (GET_CODE (src) == ASM_OPERANDS
- && GET_CODE (x) == PARALLEL)
- {
- /* Do not record result of a non-volatile inline asm with
- more than one result. */
- if (n_sets > 1)
- sets[i].src_volatile = 1;
-
- int j, lim = XVECLEN (x, 0);
- for (j = 0; j < lim; j++)
- {
- rtx y = XVECEXP (x, 0, j);
- /* And do not record result of a non-volatile inline asm
- with "memory" clobber. */
- if (GET_CODE (y) == CLOBBER && MEM_P (XEXP (y, 0)))
- {
- sets[i].src_volatile = 1;
- break;
- }
- }
- }
-
-#if 0
- /* It is no longer clear why we used to do this, but it doesn't
- appear to still be needed. So let's try without it since this
- code hurts cse'ing widened ops. */
- /* If source is a paradoxical subreg (such as QI treated as an SI),
- treat it as volatile. It may do the work of an SI in one context
- where the extra bits are not being used, but cannot replace an SI
- in general. */
- if (paradoxical_subreg_p (src))
- sets[i].src_volatile = 1;
-#endif
-
- /* Locate all possible equivalent forms for SRC. Try to replace
- SRC in the insn with each cheaper equivalent.
-
- We have the following types of equivalents: SRC itself, a folded
- version, a value given in a REG_EQUAL note, or a value related
- to a constant.
-
- Each of these equivalents may be part of an additional class
- of equivalents (if more than one is in the table, they must be in
- the same class; we check for this).
-
- If the source is volatile, we don't do any table lookups.
-
- We note any constant equivalent for possible later use in a
- REG_NOTE. */
-
- if (!sets[i].src_volatile)
- elt = lookup (src, sets[i].src_hash, mode);
-
- sets[i].src_elt = elt;
-
- if (elt && src_eqv_here && src_eqv_elt)
- {
- if (elt->first_same_value != src_eqv_elt->first_same_value)
- {
- /* The REG_EQUAL is indicating that two formerly distinct
- classes are now equivalent. So merge them. */
- merge_equiv_classes (elt, src_eqv_elt);
- src_eqv_hash = HASH (src_eqv, elt->mode);
- src_eqv_elt = lookup (src_eqv, src_eqv_hash, elt->mode);
- }
-
- src_eqv_here = 0;
- }
-
- else if (src_eqv_elt)
- elt = src_eqv_elt;
-
- /* Try to find a constant somewhere and record it in `src_const'.
- Record its table element, if any, in `src_const_elt'. Look in
- any known equivalences first. (If the constant is not in the
- table, also set `sets[i].src_const_hash'). */
- if (elt)
- for (p = elt->first_same_value; p; p = p->next_same_value)
- if (p->is_const)
- {
- src_const = p->exp;
- src_const_elt = elt;
- break;
- }
-
- if (src_const == 0
- && (CONSTANT_P (src_folded)
- /* Consider (minus (label_ref L1) (label_ref L2)) as
- "constant" here so we will record it. This allows us
- to fold switch statements when an ADDR_DIFF_VEC is used. */
- || (GET_CODE (src_folded) == MINUS
- && GET_CODE (XEXP (src_folded, 0)) == LABEL_REF
- && GET_CODE (XEXP (src_folded, 1)) == LABEL_REF)))
- src_const = src_folded, src_const_elt = elt;
- else if (src_const == 0 && src_eqv_here && CONSTANT_P (src_eqv_here))
- src_const = src_eqv_here, src_const_elt = src_eqv_elt;
-
- /* If we don't know if the constant is in the table, get its
- hash code and look it up. */
- if (src_const && src_const_elt == 0)
- {
- sets[i].src_const_hash = HASH (src_const, mode);
- src_const_elt = lookup (src_const, sets[i].src_const_hash, mode);
- }
-
- sets[i].src_const = src_const;
- sets[i].src_const_elt = src_const_elt;
-
- /* If the constant and our source are both in the table, mark them as
- equivalent. Otherwise, if a constant is in the table but the source
- isn't, set ELT to it. */
- if (src_const_elt && elt
- && src_const_elt->first_same_value != elt->first_same_value)
- merge_equiv_classes (elt, src_const_elt);
- else if (src_const_elt && elt == 0)
- elt = src_const_elt;
-
- /* See if there is a register linearly related to a constant
- equivalent of SRC. */
- if (src_const
- && (GET_CODE (src_const) == CONST
- || (src_const_elt && src_const_elt->related_value != 0)))
- {
- src_related = use_related_value (src_const, src_const_elt);
- if (src_related)
- {
- struct table_elt *src_related_elt
- = lookup (src_related, HASH (src_related, mode), mode);
- if (src_related_elt && elt)
- {
- if (elt->first_same_value
- != src_related_elt->first_same_value)
- /* This can occur when we previously saw a CONST
- involving a SYMBOL_REF and then see the SYMBOL_REF
- twice. Merge the involved classes. */
- merge_equiv_classes (elt, src_related_elt);
-
- src_related = 0;
- src_related_elt = 0;
- }
- else if (src_related_elt && elt == 0)
- elt = src_related_elt;
- }
- }
-
- /* See if we have a CONST_INT that is already in a register in a
- wider mode. */
-
- if (src_const && src_related == 0 && CONST_INT_P (src_const)
- && is_int_mode (mode, &int_mode)
- && GET_MODE_PRECISION (int_mode) < BITS_PER_WORD)
- {
- opt_scalar_int_mode wider_mode_iter;
- FOR_EACH_WIDER_MODE (wider_mode_iter, int_mode)
- {
- scalar_int_mode wider_mode = wider_mode_iter.require ();
- if (GET_MODE_PRECISION (wider_mode) > BITS_PER_WORD)
- break;
-
- struct table_elt *const_elt
- = lookup (src_const, HASH (src_const, wider_mode), wider_mode);
-
- if (const_elt == 0)
- continue;
-
- for (const_elt = const_elt->first_same_value;
- const_elt; const_elt = const_elt->next_same_value)
- if (REG_P (const_elt->exp))
- {
- src_related = gen_lowpart (int_mode, const_elt->exp);
- break;
- }
-
- if (src_related != 0)
- break;
- }
- }
-
- /* Another possibility is that we have an AND with a constant in
- a mode narrower than a word. If so, it might have been generated
- as part of an "if" which would narrow the AND. If we already
- have done the AND in a wider mode, we can use a SUBREG of that
- value. */
-
- if (flag_expensive_optimizations && ! src_related
- && is_a <scalar_int_mode> (mode, &int_mode)
- && GET_CODE (src) == AND && CONST_INT_P (XEXP (src, 1))
- && GET_MODE_SIZE (int_mode) < UNITS_PER_WORD)
- {
- opt_scalar_int_mode tmode_iter;
- rtx new_and = gen_rtx_AND (VOIDmode, NULL_RTX, XEXP (src, 1));
-
- FOR_EACH_WIDER_MODE (tmode_iter, int_mode)
- {
- scalar_int_mode tmode = tmode_iter.require ();
- if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
- break;
-
- rtx inner = gen_lowpart (tmode, XEXP (src, 0));
- struct table_elt *larger_elt;
-
- if (inner)
- {
- PUT_MODE (new_and, tmode);
- XEXP (new_and, 0) = inner;
- larger_elt = lookup (new_and, HASH (new_and, tmode), tmode);
- if (larger_elt == 0)
- continue;
-
- for (larger_elt = larger_elt->first_same_value;
- larger_elt; larger_elt = larger_elt->next_same_value)
- if (REG_P (larger_elt->exp))
- {
- src_related
- = gen_lowpart (int_mode, larger_elt->exp);
- break;
- }
-
- if (src_related)
- break;
- }
- }
- }
-
- /* See if a MEM has already been loaded with a widening operation;
- if it has, we can use a subreg of that. Many CISC machines
- also have such operations, but this is only likely to be
- beneficial on these machines. */
-
- rtx_code extend_op;
- if (flag_expensive_optimizations && src_related == 0
- && MEM_P (src) && ! do_not_record
- && is_a <scalar_int_mode> (mode, &int_mode)
- && (extend_op = load_extend_op (int_mode)) != UNKNOWN)
- {
- struct rtx_def memory_extend_buf;
- rtx memory_extend_rtx = &memory_extend_buf;
-
- /* Set what we are trying to extend and the operation it might
- have been extended with. */
- memset (memory_extend_rtx, 0, sizeof (*memory_extend_rtx));
- PUT_CODE (memory_extend_rtx, extend_op);
- XEXP (memory_extend_rtx, 0) = src;
-
- opt_scalar_int_mode tmode_iter;
- FOR_EACH_WIDER_MODE (tmode_iter, int_mode)
- {
- struct table_elt *larger_elt;
-
- scalar_int_mode tmode = tmode_iter.require ();
- if (GET_MODE_SIZE (tmode) > UNITS_PER_WORD)
- break;
-
- PUT_MODE (memory_extend_rtx, tmode);
- larger_elt = lookup (memory_extend_rtx,
- HASH (memory_extend_rtx, tmode), tmode);
- if (larger_elt == 0)
- continue;
-
- for (larger_elt = larger_elt->first_same_value;
- larger_elt; larger_elt = larger_elt->next_same_value)
- if (REG_P (larger_elt->exp))
- {
- src_related = gen_lowpart (int_mode, larger_elt->exp);
- break;
- }
-
- if (src_related)
- break;
- }
- }
-
- /* Try to express the constant using a register+offset expression
- derived from a constant anchor. */
-
- if (targetm.const_anchor
- && !src_related
- && src_const
- && GET_CODE (src_const) == CONST_INT)
- {
- src_related = try_const_anchors (src_const, mode);
- src_related_is_const_anchor = src_related != NULL_RTX;
- }
-
- /* Try to re-materialize a vec_dup with an existing constant. */
- rtx src_elt;
- if ((!src_eqv_here || CONSTANT_P (src_eqv_here))
- && const_vec_duplicate_p (src, &src_elt))
- {
- machine_mode const_mode = GET_MODE_INNER (GET_MODE (src));
- struct table_elt *related_elt
- = lookup (src_elt, HASH (src_elt, const_mode), const_mode);
- if (related_elt)
- {
- for (related_elt = related_elt->first_same_value;
- related_elt; related_elt = related_elt->next_same_value)
- if (REG_P (related_elt->exp))
- {
- /* We don't need to compare costs with an existing (constant)
- src_eqv_here, since any such src_eqv_here should already be
- available in src_const. */
- src_eqv_here
- = gen_rtx_VEC_DUPLICATE (GET_MODE (src),
- related_elt->exp);
- break;
- }
- }
- }
-
- if (src == src_folded)
- src_folded = 0;
-
- /* At this point, ELT, if nonzero, points to a class of expressions
- equivalent to the source of this SET and SRC, SRC_EQV, SRC_FOLDED,
- and SRC_RELATED, if nonzero, each contain additional equivalent
- expressions. Prune these latter expressions by deleting expressions
- already in the equivalence class.
-
- Check for an equivalent identical to the destination. If found,
- this is the preferred equivalent since it will likely lead to
- elimination of the insn. Indicate this by placing it in
- `src_related'. */
-
- if (elt)
- elt = elt->first_same_value;
- for (p = elt; p; p = p->next_same_value)
- {
- enum rtx_code code = GET_CODE (p->exp);
-
- /* If the expression is not valid, ignore it. Then we do not
- have to check for validity below. In most cases, we can use
- `rtx_equal_p', since canonicalization has already been done. */
- if (code != REG && ! exp_equiv_p (p->exp, p->exp, 1, false))
- continue;
-
- /* Also skip paradoxical subregs, unless that's what we're
- looking for. */
- if (paradoxical_subreg_p (p->exp)
- && ! (src != 0
- && GET_CODE (src) == SUBREG
- && GET_MODE (src) == GET_MODE (p->exp)
- && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
- GET_MODE (SUBREG_REG (p->exp)))))
- continue;
-
- if (src && GET_CODE (src) == code && rtx_equal_p (src, p->exp))
- src = 0;
- else if (src_folded && GET_CODE (src_folded) == code
- && rtx_equal_p (src_folded, p->exp))
- src_folded = 0;
- else if (src_eqv_here && GET_CODE (src_eqv_here) == code
- && rtx_equal_p (src_eqv_here, p->exp))
- src_eqv_here = 0;
- else if (src_related && GET_CODE (src_related) == code
- && rtx_equal_p (src_related, p->exp))
- src_related = 0;
-
- /* This is the same as the destination of the insns, we want
- to prefer it. Copy it to src_related. The code below will
- then give it a negative cost. */
- if (GET_CODE (dest) == code && rtx_equal_p (p->exp, dest))
- src_related = p->exp;
- }
-
- /* Find the cheapest valid equivalent, trying all the available
- possibilities. Prefer items not in the hash table to ones
- that are when they are equal cost. Note that we can never
- worsen an insn as the current contents will also succeed.
- If we find an equivalent identical to the destination, use it as best,
- since this insn will probably be eliminated in that case. */
- if (src)
- {
- if (rtx_equal_p (src, dest))
- src_cost = src_regcost = -1;
- else
- {
- src_cost = COST (src, mode);
- src_regcost = approx_reg_cost (src);
- }
- }
-
- if (src_eqv_here)
- {
- if (rtx_equal_p (src_eqv_here, dest))
- src_eqv_cost = src_eqv_regcost = -1;
- else
- {
- src_eqv_cost = COST (src_eqv_here, mode);
- src_eqv_regcost = approx_reg_cost (src_eqv_here);
- }
- }
-
- if (src_folded)
- {
- if (rtx_equal_p (src_folded, dest))
- src_folded_cost = src_folded_regcost = -1;
- else
- {
- src_folded_cost = COST (src_folded, mode);
- src_folded_regcost = approx_reg_cost (src_folded);
- }
- }
-
- if (src_related)
- {
- if (rtx_equal_p (src_related, dest))
- src_related_cost = src_related_regcost = -1;
- else
- {
- src_related_cost = COST (src_related, mode);
- src_related_regcost = approx_reg_cost (src_related);
-
- /* If a const-anchor is used to synthesize a constant that
- normally requires multiple instructions then slightly prefer
- it over the original sequence. These instructions are likely
- to become redundant now. We can't compare against the cost
- of src_eqv_here because, on MIPS for example, multi-insn
- constants have zero cost; they are assumed to be hoisted from
- loops. */
- if (src_related_is_const_anchor
- && src_related_cost == src_cost
- && src_eqv_here)
- src_related_cost--;
- }
- }
-
- /* If this was an indirect jump insn, a known label will really be
- cheaper even though it looks more expensive. */
- if (dest == pc_rtx && src_const && GET_CODE (src_const) == LABEL_REF)
- src_folded = src_const, src_folded_cost = src_folded_regcost = -1;
-
- /* Terminate loop when replacement made. This must terminate since
- the current contents will be tested and will always be valid. */
- while (1)
- {
- rtx trial;
-
- /* Skip invalid entries. */
- while (elt && !REG_P (elt->exp)
- && ! exp_equiv_p (elt->exp, elt->exp, 1, false))
- elt = elt->next_same_value;
-
- /* A paradoxical subreg would be bad here: it'll be the right
- size, but later may be adjusted so that the upper bits aren't
- what we want. So reject it. */
- if (elt != 0
- && paradoxical_subreg_p (elt->exp)
- /* It is okay, though, if the rtx we're trying to match
- will ignore any of the bits we can't predict. */
- && ! (src != 0
- && GET_CODE (src) == SUBREG
- && GET_MODE (src) == GET_MODE (elt->exp)
- && partial_subreg_p (GET_MODE (SUBREG_REG (src)),
- GET_MODE (SUBREG_REG (elt->exp)))))
- {
- elt = elt->next_same_value;
- continue;
- }
-
- if (elt)
- {
- src_elt_cost = elt->cost;
- src_elt_regcost = elt->regcost;
- }
-
- /* Find cheapest and skip it for the next time. For items
- of equal cost, use this order:
- src_folded, src, src_eqv, src_related and hash table entry. */
- if (src_folded
- && preferable (src_folded_cost, src_folded_regcost,
- src_cost, src_regcost) <= 0
- && preferable (src_folded_cost, src_folded_regcost,
- src_eqv_cost, src_eqv_regcost) <= 0
- && preferable (src_folded_cost, src_folded_regcost,
- src_related_cost, src_related_regcost) <= 0
- && preferable (src_folded_cost, src_folded_regcost,
- src_elt_cost, src_elt_regcost) <= 0)
- trial = src_folded, src_folded_cost = MAX_COST;
- else if (src
- && preferable (src_cost, src_regcost,
- src_eqv_cost, src_eqv_regcost) <= 0
- && preferable (src_cost, src_regcost,
- src_related_cost, src_related_regcost) <= 0
- && preferable (src_cost, src_regcost,
- src_elt_cost, src_elt_regcost) <= 0)
- trial = src, src_cost = MAX_COST;
- else if (src_eqv_here
- && preferable (src_eqv_cost, src_eqv_regcost,
- src_related_cost, src_related_regcost) <= 0
- && preferable (src_eqv_cost, src_eqv_regcost,
- src_elt_cost, src_elt_regcost) <= 0)
- trial = src_eqv_here, src_eqv_cost = MAX_COST;
- else if (src_related
- && preferable (src_related_cost, src_related_regcost,
- src_elt_cost, src_elt_regcost) <= 0)
- trial = src_related, src_related_cost = MAX_COST;
- else
- {
- trial = elt->exp;
- elt = elt->next_same_value;
- src_elt_cost = MAX_COST;
- }
-
- /* Try to optimize
- (set (reg:M N) (const_int A))
- (set (reg:M2 O) (const_int B))
- (set (zero_extract:M2 (reg:M N) (const_int C) (const_int D))
- (reg:M2 O)). */
- if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT
- && CONST_INT_P (trial)
- && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 1))
- && CONST_INT_P (XEXP (SET_DEST (sets[i].rtl), 2))
- && REG_P (XEXP (SET_DEST (sets[i].rtl), 0))
- && (known_ge
- (GET_MODE_PRECISION (GET_MODE (SET_DEST (sets[i].rtl))),
- INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))))
- && ((unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 1))
- + (unsigned) INTVAL (XEXP (SET_DEST (sets[i].rtl), 2))
- <= HOST_BITS_PER_WIDE_INT))
- {
- rtx dest_reg = XEXP (SET_DEST (sets[i].rtl), 0);
- rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
- rtx pos = XEXP (SET_DEST (sets[i].rtl), 2);
- unsigned int dest_hash = HASH (dest_reg, GET_MODE (dest_reg));
- struct table_elt *dest_elt
- = lookup (dest_reg, dest_hash, GET_MODE (dest_reg));
- rtx dest_cst = NULL;
-
- if (dest_elt)
- for (p = dest_elt->first_same_value; p; p = p->next_same_value)
- if (p->is_const && CONST_INT_P (p->exp))
- {
- dest_cst = p->exp;
- break;
- }
- if (dest_cst)
- {
- HOST_WIDE_INT val = INTVAL (dest_cst);
- HOST_WIDE_INT mask;
- unsigned int shift;
- /* This is the mode of DEST_CST as well. */
- scalar_int_mode dest_mode
- = as_a <scalar_int_mode> (GET_MODE (dest_reg));
- if (BITS_BIG_ENDIAN)
- shift = GET_MODE_PRECISION (dest_mode)
- - INTVAL (pos) - INTVAL (width);
- else
- shift = INTVAL (pos);
- if (INTVAL (width) == HOST_BITS_PER_WIDE_INT)
- mask = HOST_WIDE_INT_M1;
- else
- mask = (HOST_WIDE_INT_1 << INTVAL (width)) - 1;
- val &= ~(mask << shift);
- val |= (INTVAL (trial) & mask) << shift;
- val = trunc_int_for_mode (val, dest_mode);
- validate_unshare_change (insn, &SET_DEST (sets[i].rtl),
- dest_reg, 1);
- validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
- GEN_INT (val), 1);
- if (apply_change_group ())
- {
- rtx note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
- if (note)
- {
- remove_note (insn, note);
- df_notes_rescan (insn);
- }
- src_eqv = NULL_RTX;
- src_eqv_elt = NULL;
- src_eqv_volatile = 0;
- src_eqv_in_memory = 0;
- src_eqv_hash = 0;
- repeat = true;
- break;
- }
- }
- }
-
- /* We don't normally have an insn matching (set (pc) (pc)), so
- check for this separately here. We will delete such an
- insn below.
-
- For other cases such as a table jump or conditional jump
- where we know the ultimate target, go ahead and replace the
- operand. While that may not make a valid insn, we will
- reemit the jump below (and also insert any necessary
- barriers). */
- if (n_sets == 1 && dest == pc_rtx
- && (trial == pc_rtx
- || (GET_CODE (trial) == LABEL_REF
- && ! condjump_p (insn))))
- {
- /* Don't substitute non-local labels, this confuses CFG. */
- if (GET_CODE (trial) == LABEL_REF
- && LABEL_REF_NONLOCAL_P (trial))
- continue;
-
- SET_SRC (sets[i].rtl) = trial;
- cse_jumps_altered = true;
- break;
- }
-
- /* Similarly, lots of targets don't allow no-op
- (set (mem x) (mem x)) moves. Even (set (reg x) (reg x))
- might be impossible for certain registers (like CC registers). */
- else if (n_sets == 1
- && !CALL_P (insn)
- && (MEM_P (trial) || REG_P (trial))
- && rtx_equal_p (trial, dest)
- && !side_effects_p (dest)
- && (cfun->can_delete_dead_exceptions
- || insn_nothrow_p (insn))
- /* We can only remove the later store if the earlier aliases
- at least all accesses the later one. */
- && (!MEM_P (trial)
- || ((MEM_ALIAS_SET (dest) == MEM_ALIAS_SET (trial)
- || alias_set_subset_of (MEM_ALIAS_SET (dest),
- MEM_ALIAS_SET (trial)))
- && (!MEM_EXPR (trial)
- || refs_same_for_tbaa_p (MEM_EXPR (trial),
- MEM_EXPR (dest))))))
- {
- SET_SRC (sets[i].rtl) = trial;
- noop_insn = true;
- break;
- }
-
- /* Reject certain invalid forms of CONST that we create. */
- else if (CONSTANT_P (trial)
- && GET_CODE (trial) == CONST
- /* Reject cases that will cause decode_rtx_const to
- die. On the alpha when simplifying a switch, we
- get (const (truncate (minus (label_ref)
- (label_ref)))). */
- && (GET_CODE (XEXP (trial, 0)) == TRUNCATE
- /* Likewise on IA-64, except without the
- truncate. */
- || (GET_CODE (XEXP (trial, 0)) == MINUS
- && GET_CODE (XEXP (XEXP (trial, 0), 0)) == LABEL_REF
- && GET_CODE (XEXP (XEXP (trial, 0), 1)) == LABEL_REF)))
- /* Do nothing for this case. */
- ;
-
- /* Do not replace anything with a MEM, except the replacement
- is a no-op. This allows this loop to terminate. */
- else if (MEM_P (trial) && !rtx_equal_p (trial, SET_SRC(sets[i].rtl)))
- /* Do nothing for this case. */
- ;
-
- /* Look for a substitution that makes a valid insn. */
- else if (validate_unshare_change (insn, &SET_SRC (sets[i].rtl),
- trial, 0))
- {
- rtx new_rtx = canon_reg (SET_SRC (sets[i].rtl), insn);
-
- /* The result of apply_change_group can be ignored; see
- canon_reg. */
-
- validate_change (insn, &SET_SRC (sets[i].rtl), new_rtx, 1);
- apply_change_group ();
-
- break;
- }
-
- /* If the current function uses a constant pool and this is a
- constant, try making a pool entry. Put it in src_folded
- unless we already have done this since that is where it
- likely came from. */
-
- else if (crtl->uses_const_pool
- && CONSTANT_P (trial)
- && !CONST_INT_P (trial)
- && (src_folded == 0 || !MEM_P (src_folded))
- && GET_MODE_CLASS (mode) != MODE_CC
- && mode != VOIDmode)
- {
- src_folded = force_const_mem (mode, trial);
- if (src_folded)
- {
- src_folded_cost = COST (src_folded, mode);
- src_folded_regcost = approx_reg_cost (src_folded);
- }
- }
- }
-
- /* If we changed the insn too much, handle this set from scratch. */
- if (repeat)
- {
- i--;
- continue;
- }
-
- src = SET_SRC (sets[i].rtl);
-
- /* In general, it is good to have a SET with SET_SRC == SET_DEST.
- However, there is an important exception: If both are registers
- that are not the head of their equivalence class, replace SET_SRC
- with the head of the class. If we do not do this, we will have
- both registers live over a portion of the basic block. This way,
- their lifetimes will likely abut instead of overlapping. */
- if (REG_P (dest)
- && REGNO_QTY_VALID_P (REGNO (dest)))
- {
- int dest_q = REG_QTY (REGNO (dest));
- struct qty_table_elem *dest_ent = &qty_table[dest_q];
-
- if (dest_ent->mode == GET_MODE (dest)
- && dest_ent->first_reg != REGNO (dest)
- && REG_P (src) && REGNO (src) == REGNO (dest)
- /* Don't do this if the original insn had a hard reg as
- SET_SRC or SET_DEST. */
- && (!REG_P (sets[i].src)
- || REGNO (sets[i].src) >= FIRST_PSEUDO_REGISTER)
- && (!REG_P (dest) || REGNO (dest) >= FIRST_PSEUDO_REGISTER))
- /* We can't call canon_reg here because it won't do anything if
- SRC is a hard register. */
- {
- int src_q = REG_QTY (REGNO (src));
- struct qty_table_elem *src_ent = &qty_table[src_q];
- int first = src_ent->first_reg;
- rtx new_src
- = (first >= FIRST_PSEUDO_REGISTER
- ? regno_reg_rtx[first] : gen_rtx_REG (GET_MODE (src), first));
-
- /* We must use validate-change even for this, because this
- might be a special no-op instruction, suitable only to
- tag notes onto. */
- if (validate_change (insn, &SET_SRC (sets[i].rtl), new_src, 0))
- {
- src = new_src;
- /* If we had a constant that is cheaper than what we are now
- setting SRC to, use that constant. We ignored it when we
- thought we could make this into a no-op. */
- if (src_const && COST (src_const, mode) < COST (src, mode)
- && validate_change (insn, &SET_SRC (sets[i].rtl),
- src_const, 0))
- src = src_const;
- }
- }
- }
-
- /* If we made a change, recompute SRC values. */
- if (src != sets[i].src)
- {
- do_not_record = 0;
- hash_arg_in_memory = 0;
- sets[i].src = src;
- sets[i].src_hash = HASH (src, mode);
- sets[i].src_volatile = do_not_record;
- sets[i].src_in_memory = hash_arg_in_memory;
- sets[i].src_elt = lookup (src, sets[i].src_hash, mode);
- }
-
- /* If this is a single SET, we are setting a register, and we have an
- equivalent constant, we want to add a REG_EQUAL note if the constant
- is different from the source. We don't want to do it for a constant
- pseudo since verifying that this pseudo hasn't been eliminated is a
- pain; moreover such a note won't help anything.
-
- Avoid a REG_EQUAL note for (CONST (MINUS (LABEL_REF) (LABEL_REF)))
- which can be created for a reference to a compile time computable
- entry in a jump table. */
- if (n_sets == 1
- && REG_P (dest)
- && src_const
- && !REG_P (src_const)
- && !(GET_CODE (src_const) == SUBREG
- && REG_P (SUBREG_REG (src_const)))
- && !(GET_CODE (src_const) == CONST
- && GET_CODE (XEXP (src_const, 0)) == MINUS
- && GET_CODE (XEXP (XEXP (src_const, 0), 0)) == LABEL_REF
- && GET_CODE (XEXP (XEXP (src_const, 0), 1)) == LABEL_REF)
- && !rtx_equal_p (src, src_const))
- {
- /* Make sure that the rtx is not shared. */
- src_const = copy_rtx (src_const);
-
- /* Record the actual constant value in a REG_EQUAL note,
- making a new one if one does not already exist. */
- set_unique_reg_note (insn, REG_EQUAL, src_const);
- df_notes_rescan (insn);
- }
-
- /* Now deal with the destination. */
- do_not_record = 0;
-
- /* Look within any ZERO_EXTRACT to the MEM or REG within it. */
- while (GET_CODE (dest) == SUBREG
- || GET_CODE (dest) == ZERO_EXTRACT
- || GET_CODE (dest) == STRICT_LOW_PART)
- dest = XEXP (dest, 0);
-
- sets[i].inner_dest = dest;
-
- if (MEM_P (dest))
- {
-#ifdef PUSH_ROUNDING
- /* Stack pushes invalidate the stack pointer. */
- rtx addr = XEXP (dest, 0);
- if (GET_RTX_CLASS (GET_CODE (addr)) == RTX_AUTOINC
- && XEXP (addr, 0) == stack_pointer_rtx)
- invalidate (stack_pointer_rtx, VOIDmode);
-#endif
- dest = fold_rtx (dest, insn);
- }
-
- /* Compute the hash code of the destination now,
- before the effects of this instruction are recorded,
- since the register values used in the address computation
- are those before this instruction. */
- sets[i].dest_hash = HASH (dest, mode);
-
- /* Don't enter a bit-field in the hash table
- because the value in it after the store
- may not equal what was stored, due to truncation. */
-
- if (GET_CODE (SET_DEST (sets[i].rtl)) == ZERO_EXTRACT)
- {
- rtx width = XEXP (SET_DEST (sets[i].rtl), 1);
-
- if (src_const != 0 && CONST_INT_P (src_const)
- && CONST_INT_P (width)
- && INTVAL (width) < HOST_BITS_PER_WIDE_INT
- && ! (INTVAL (src_const)
- & (HOST_WIDE_INT_M1U << INTVAL (width))))
- /* Exception: if the value is constant,
- and it won't be truncated, record it. */
- ;
- else
- {
- /* This is chosen so that the destination will be invalidated
- but no new value will be recorded.
- We must invalidate because sometimes constant
- values can be recorded for bitfields. */
- sets[i].src_elt = 0;
- sets[i].src_volatile = 1;
- src_eqv = 0;
- src_eqv_elt = 0;
- }
- }
-
- /* If only one set in a JUMP_INSN and it is now a no-op, we can delete
- the insn. */
- else if (n_sets == 1 && dest == pc_rtx && src == pc_rtx)
- {
- /* One less use of the label this insn used to jump to. */
- cse_cfg_altered |= delete_insn_and_edges (insn);
- cse_jumps_altered = true;
- /* No more processing for this set. */
- sets[i].rtl = 0;
- }
-
- /* Similarly for no-op moves. */
- else if (noop_insn)
- {
- if (cfun->can_throw_non_call_exceptions && can_throw_internal (insn))
- cse_cfg_altered = true;
- cse_cfg_altered |= delete_insn_and_edges (insn);
- /* No more processing for this set. */
- sets[i].rtl = 0;
- }
-
- /* If this SET is now setting PC to a label, we know it used to
- be a conditional or computed branch. */
- else if (dest == pc_rtx && GET_CODE (src) == LABEL_REF
- && !LABEL_REF_NONLOCAL_P (src))
- {
- /* We reemit the jump in as many cases as possible just in
- case the form of an unconditional jump is significantly
- different than a computed jump or conditional jump.
-
- If this insn has multiple sets, then reemitting the
- jump is nontrivial. So instead we just force rerecognition
- and hope for the best. */
- if (n_sets == 1)
- {
- rtx_jump_insn *new_rtx;
- rtx note;
-
- rtx_insn *seq = targetm.gen_jump (XEXP (src, 0));
- new_rtx = emit_jump_insn_before (seq, insn);
- JUMP_LABEL (new_rtx) = XEXP (src, 0);
- LABEL_NUSES (XEXP (src, 0))++;
-
- /* Make sure to copy over REG_NON_LOCAL_GOTO. */
- note = find_reg_note (insn, REG_NON_LOCAL_GOTO, 0);
- if (note)
- {
- XEXP (note, 1) = NULL_RTX;
- REG_NOTES (new_rtx) = note;
- }
-
- cse_cfg_altered |= delete_insn_and_edges (insn);
- insn = new_rtx;
- }
- else
- INSN_CODE (insn) = -1;
-
- /* Do not bother deleting any unreachable code, let jump do it. */
- cse_jumps_altered = true;
- sets[i].rtl = 0;
- }
-
- /* If destination is volatile, invalidate it and then do no further
- processing for this assignment. */
-
- else if (do_not_record)
- {
- invalidate_dest (dest);
- sets[i].rtl = 0;
- }
-
- if (sets[i].rtl != 0 && dest != SET_DEST (sets[i].rtl))
- {
- do_not_record = 0;
- sets[i].dest_hash = HASH (SET_DEST (sets[i].rtl), mode);
- if (do_not_record)
- {
- invalidate_dest (SET_DEST (sets[i].rtl));
- sets[i].rtl = 0;
- }
- }
- }
-
- /* Now enter all non-volatile source expressions in the hash table
- if they are not already present.
- Record their equivalence classes in src_elt.
- This way we can insert the corresponding destinations into
- the same classes even if the actual sources are no longer in them
- (having been invalidated). */
-
- if (src_eqv && src_eqv_elt == 0 && sets[0].rtl != 0 && ! src_eqv_volatile
- && ! rtx_equal_p (src_eqv, SET_DEST (sets[0].rtl)))
- {
- struct table_elt *elt;
- struct table_elt *classp = sets[0].src_elt;
- rtx dest = SET_DEST (sets[0].rtl);
- machine_mode eqvmode = GET_MODE (dest);
-
- if (GET_CODE (dest) == STRICT_LOW_PART)
- {
- eqvmode = GET_MODE (SUBREG_REG (XEXP (dest, 0)));
- classp = 0;
- }
- if (insert_regs (src_eqv, classp, 0))
- {
- rehash_using_reg (src_eqv);
- src_eqv_hash = HASH (src_eqv, eqvmode);
- }
- elt = insert (src_eqv, classp, src_eqv_hash, eqvmode);
- elt->in_memory = src_eqv_in_memory;
- src_eqv_elt = elt;
-
- /* Check to see if src_eqv_elt is the same as a set source which
- does not yet have an elt, and if so set the elt of the set source
- to src_eqv_elt. */
- for (i = 0; i < n_sets; i++)
- if (sets[i].rtl && sets[i].src_elt == 0
- && rtx_equal_p (SET_SRC (sets[i].rtl), src_eqv))
- sets[i].src_elt = src_eqv_elt;
- }
-
- for (i = 0; i < n_sets; i++)
- if (sets[i].rtl && ! sets[i].src_volatile
- && ! rtx_equal_p (SET_SRC (sets[i].rtl), SET_DEST (sets[i].rtl)))
- {
- if (GET_CODE (SET_DEST (sets[i].rtl)) == STRICT_LOW_PART)
- {
- /* REG_EQUAL in setting a STRICT_LOW_PART
- gives an equivalent for the entire destination register,
- not just for the subreg being stored in now.
- This is a more interesting equivalence, so we arrange later
- to treat the entire reg as the destination. */
- sets[i].src_elt = src_eqv_elt;
- sets[i].src_hash = src_eqv_hash;
- }
- else
- {
- /* Insert source and constant equivalent into hash table, if not
- already present. */
- struct table_elt *classp = src_eqv_elt;
- rtx src = sets[i].src;
- rtx dest = SET_DEST (sets[i].rtl);
- machine_mode mode
- = GET_MODE (src) == VOIDmode ? GET_MODE (dest) : GET_MODE (src);
-
- /* It's possible that we have a source value known to be
- constant but don't have a REG_EQUAL note on the insn.
- Lack of a note will mean src_eqv_elt will be NULL. This
- can happen where we've generated a SUBREG to access a
- CONST_INT that is already in a register in a wider mode.
- Ensure that the source expression is put in the proper
- constant class. */
- if (!classp)
- classp = sets[i].src_const_elt;
-
- if (sets[i].src_elt == 0)
- {
- struct table_elt *elt;
-
- /* Note that these insert_regs calls cannot remove
- any of the src_elt's, because they would have failed to
- match if not still valid. */
- if (insert_regs (src, classp, 0))
- {
- rehash_using_reg (src);
- sets[i].src_hash = HASH (src, mode);
- }
- elt = insert (src, classp, sets[i].src_hash, mode);
- elt->in_memory = sets[i].src_in_memory;
- /* If inline asm has any clobbers, ensure we only reuse
- existing inline asms and never try to put the ASM_OPERANDS
- into an insn that isn't inline asm. */
- if (GET_CODE (src) == ASM_OPERANDS
- && GET_CODE (x) == PARALLEL)
- elt->cost = MAX_COST;
- sets[i].src_elt = classp = elt;
- }
- if (sets[i].src_const && sets[i].src_const_elt == 0
- && src != sets[i].src_const
- && ! rtx_equal_p (sets[i].src_const, src))
- sets[i].src_elt = insert (sets[i].src_const, classp,
- sets[i].src_const_hash, mode);
- }
- }
- else if (sets[i].src_elt == 0)
- /* If we did not insert the source into the hash table (e.g., it was
- volatile), note the equivalence class for the REG_EQUAL value, if any,
- so that the destination goes into that class. */
- sets[i].src_elt = src_eqv_elt;
-
- /* Record destination addresses in the hash table. This allows us to
- check if they are invalidated by other sets. */
- for (i = 0; i < n_sets; i++)
- {
- if (sets[i].rtl)
- {
- rtx x = sets[i].inner_dest;
- struct table_elt *elt;
- machine_mode mode;
- unsigned hash;
-
- if (MEM_P (x))
- {
- x = XEXP (x, 0);
- mode = GET_MODE (x);
- hash = HASH (x, mode);
- elt = lookup (x, hash, mode);
- if (!elt)
- {
- if (insert_regs (x, NULL, 0))
- {
- rtx dest = SET_DEST (sets[i].rtl);
-
- rehash_using_reg (x);
- hash = HASH (x, mode);
- sets[i].dest_hash = HASH (dest, GET_MODE (dest));
- }
- elt = insert (x, NULL, hash, mode);
- }
-
- sets[i].dest_addr_elt = elt;
- }
- else
- sets[i].dest_addr_elt = NULL;
- }
- }
-
- invalidate_from_clobbers (insn);
-
- /* Some registers are invalidated by subroutine calls. Memory is
- invalidated by non-constant calls. */
-
- if (CALL_P (insn))
- {
- if (!(RTL_CONST_OR_PURE_CALL_P (insn)))
- invalidate_memory ();
- else
- /* For const/pure calls, invalidate any argument slots, because
- those are owned by the callee. */
- for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
- if (GET_CODE (XEXP (tem, 0)) == USE
- && MEM_P (XEXP (XEXP (tem, 0), 0)))
- invalidate (XEXP (XEXP (tem, 0), 0), VOIDmode);
- invalidate_for_call (insn);
- }
-
- /* Now invalidate everything set by this instruction.
- If a SUBREG or other funny destination is being set,
- sets[i].rtl is still nonzero, so here we invalidate the reg
- a part of which is being set. */
-
- for (i = 0; i < n_sets; i++)
- if (sets[i].rtl)
- {
- /* We can't use the inner dest, because the mode associated with
- a ZERO_EXTRACT is significant. */
- rtx dest = SET_DEST (sets[i].rtl);
-
- /* Needed for registers to remove the register from its
- previous quantity's chain.
- Needed for memory if this is a nonvarying address, unless
- we have just done an invalidate_memory that covers even those. */
- if (REG_P (dest) || GET_CODE (dest) == SUBREG)
- invalidate (dest, VOIDmode);
- else if (MEM_P (dest))
- invalidate (dest, VOIDmode);
- else if (GET_CODE (dest) == STRICT_LOW_PART
- || GET_CODE (dest) == ZERO_EXTRACT)
- invalidate (XEXP (dest, 0), GET_MODE (dest));
- }
-
- /* Don't cse over a call to setjmp; on some machines (eg VAX)
- the regs restored by the longjmp come from a later time
- than the setjmp. */
- if (CALL_P (insn) && find_reg_note (insn, REG_SETJMP, NULL))
- {
- flush_hash_table ();
- goto done;
- }
-
- /* Make sure registers mentioned in destinations
- are safe for use in an expression to be inserted.
- This removes from the hash table
- any invalid entry that refers to one of these registers.
-
- We don't care about the return value from mention_regs because
- we are going to hash the SET_DEST values unconditionally. */
-
- for (i = 0; i < n_sets; i++)
- {
- if (sets[i].rtl)
- {
- rtx x = SET_DEST (sets[i].rtl);
-
- if (!REG_P (x))
- mention_regs (x);
- else
- {
- /* We used to rely on all references to a register becoming
- inaccessible when a register changes to a new quantity,
- since that changes the hash code. However, that is not
- safe, since after HASH_SIZE new quantities we get a
- hash 'collision' of a register with its own invalid
- entries. And since SUBREGs have been changed not to
- change their hash code with the hash code of the register,
- it wouldn't work any longer at all. So we have to check
- for any invalid references lying around now.
- This code is similar to the REG case in mention_regs,
- but it knows that reg_tick has been incremented, and
- it leaves reg_in_table as -1 . */
- unsigned int regno = REGNO (x);
- unsigned int endregno = END_REGNO (x);
- unsigned int i;
-
- for (i = regno; i < endregno; i++)
- {
- if (REG_IN_TABLE (i) >= 0)
- {
- remove_invalid_refs (i);
- REG_IN_TABLE (i) = -1;
- }
- }
- }
- }
- }
-
- /* We may have just removed some of the src_elt's from the hash table.
- So replace each one with the current head of the same class.
- Also check if destination addresses have been removed. */
-
- for (i = 0; i < n_sets; i++)
- if (sets[i].rtl)
- {
- if (sets[i].dest_addr_elt
- && sets[i].dest_addr_elt->first_same_value == 0)
- {
- /* The elt was removed, which means this destination is not
- valid after this instruction. */
- sets[i].rtl = NULL_RTX;
- }
- else if (sets[i].src_elt && sets[i].src_elt->first_same_value == 0)
- /* If elt was removed, find current head of same class,
- or 0 if nothing remains of that class. */
- {
- struct table_elt *elt = sets[i].src_elt;
-
- while (elt && elt->prev_same_value)
- elt = elt->prev_same_value;
-
- while (elt && elt->first_same_value == 0)
- elt = elt->next_same_value;
- sets[i].src_elt = elt ? elt->first_same_value : 0;
- }
- }
-
- /* Now insert the destinations into their equivalence classes. */
-
- for (i = 0; i < n_sets; i++)
- if (sets[i].rtl)
- {
- rtx dest = SET_DEST (sets[i].rtl);
- struct table_elt *elt;
-
- /* Don't record value if we are not supposed to risk allocating
- floating-point values in registers that might be wider than
- memory. */
- if ((flag_float_store
- && MEM_P (dest)
- && FLOAT_MODE_P (GET_MODE (dest)))
- /* Don't record BLKmode values, because we don't know the
- size of it, and can't be sure that other BLKmode values
- have the same or smaller size. */
- || GET_MODE (dest) == BLKmode
- /* If we didn't put a REG_EQUAL value or a source into the hash
- table, there is no point is recording DEST. */
- || sets[i].src_elt == 0)
- continue;
-
- /* STRICT_LOW_PART isn't part of the value BEING set,
- and neither is the SUBREG inside it.
- Note that in this case SETS[I].SRC_ELT is really SRC_EQV_ELT. */
- if (GET_CODE (dest) == STRICT_LOW_PART)
- dest = SUBREG_REG (XEXP (dest, 0));
-
- if (REG_P (dest) || GET_CODE (dest) == SUBREG)
- /* Registers must also be inserted into chains for quantities. */
- if (insert_regs (dest, sets[i].src_elt, 1))
- {
- /* If `insert_regs' changes something, the hash code must be
- recalculated. */
- rehash_using_reg (dest);
- sets[i].dest_hash = HASH (dest, GET_MODE (dest));
- }
-
- /* If DEST is a paradoxical SUBREG, don't record DEST since the bits
- outside the mode of GET_MODE (SUBREG_REG (dest)) are undefined. */
- if (paradoxical_subreg_p (dest))
- continue;
-
- elt = insert (dest, sets[i].src_elt,
- sets[i].dest_hash, GET_MODE (dest));
-
- /* If this is a constant, insert the constant anchors with the
- equivalent register-offset expressions using register DEST. */
- if (targetm.const_anchor
- && REG_P (dest)
- && SCALAR_INT_MODE_P (GET_MODE (dest))
- && GET_CODE (sets[i].src_elt->exp) == CONST_INT)
- insert_const_anchors (dest, sets[i].src_elt->exp, GET_MODE (dest));
-
- elt->in_memory = (MEM_P (sets[i].inner_dest)
- && !MEM_READONLY_P (sets[i].inner_dest));
-
- /* If we have (set (subreg:m1 (reg:m2 foo) 0) (bar:m1)), M1 is no
- narrower than M2, and both M1 and M2 are the same number of words,
- we are also doing (set (reg:m2 foo) (subreg:m2 (bar:m1) 0)) so
- make that equivalence as well.
-
- However, BAR may have equivalences for which gen_lowpart
- will produce a simpler value than gen_lowpart applied to
- BAR (e.g., if BAR was ZERO_EXTENDed from M2), so we will scan all
- BAR's equivalences. If we don't get a simplified form, make
- the SUBREG. It will not be used in an equivalence, but will
- cause two similar assignments to be detected.
-
- Note the loop below will find SUBREG_REG (DEST) since we have
- already entered SRC and DEST of the SET in the table. */
-
- if (GET_CODE (dest) == SUBREG
- && (known_equal_after_align_down
- (GET_MODE_SIZE (GET_MODE (SUBREG_REG (dest))) - 1,
- GET_MODE_SIZE (GET_MODE (dest)) - 1,
- UNITS_PER_WORD))
- && !partial_subreg_p (dest)
- && sets[i].src_elt != 0)
- {
- machine_mode new_mode = GET_MODE (SUBREG_REG (dest));
- struct table_elt *elt, *classp = 0;
-
- for (elt = sets[i].src_elt->first_same_value; elt;
- elt = elt->next_same_value)
- {
- rtx new_src = 0;
- unsigned src_hash;
- struct table_elt *src_elt;
-
- /* Ignore invalid entries. */
- if (!REG_P (elt->exp)
- && ! exp_equiv_p (elt->exp, elt->exp, 1, false))
- continue;
-
- /* We may have already been playing subreg games. If the
- mode is already correct for the destination, use it. */
- if (GET_MODE (elt->exp) == new_mode)
- new_src = elt->exp;
- else
- {
- poly_uint64 byte
- = subreg_lowpart_offset (new_mode, GET_MODE (dest));
- new_src = simplify_gen_subreg (new_mode, elt->exp,
- GET_MODE (dest), byte);
- }
-
- /* The call to simplify_gen_subreg fails if the value
- is VOIDmode, yet we can't do any simplification, e.g.
- for EXPR_LISTs denoting function call results.
- It is invalid to construct a SUBREG with a VOIDmode
- SUBREG_REG, hence a zero new_src means we can't do
- this substitution. */
- if (! new_src)
- continue;
-
- src_hash = HASH (new_src, new_mode);
- src_elt = lookup (new_src, src_hash, new_mode);
-
- /* Put the new source in the hash table is if isn't
- already. */
- if (src_elt == 0)
- {
- if (insert_regs (new_src, classp, 0))
- {
- rehash_using_reg (new_src);
- src_hash = HASH (new_src, new_mode);
- }
- src_elt = insert (new_src, classp, src_hash, new_mode);
- src_elt->in_memory = elt->in_memory;
- if (GET_CODE (new_src) == ASM_OPERANDS
- && elt->cost == MAX_COST)
- src_elt->cost = MAX_COST;
- }
- else if (classp && classp != src_elt->first_same_value)
- /* Show that two things that we've seen before are
- actually the same. */
- merge_equiv_classes (src_elt, classp);
-
- classp = src_elt->first_same_value;
- /* Ignore invalid entries. */
- while (classp
- && !REG_P (classp->exp)
- && ! exp_equiv_p (classp->exp, classp->exp, 1, false))
- classp = classp->next_same_value;
- }
- }
- }
-
- /* Special handling for (set REG0 REG1) where REG0 is the
- "cheapest", cheaper than REG1. After cse, REG1 will probably not
- be used in the sequel, so (if easily done) change this insn to
- (set REG1 REG0) and replace REG1 with REG0 in the previous insn
- that computed their value. Then REG1 will become a dead store
- and won't cloud the situation for later optimizations.
-
- Do not make this change if REG1 is a hard register, because it will
- then be used in the sequel and we may be changing a two-operand insn
- into a three-operand insn.
-
- Also do not do this if we are operating on a copy of INSN. */
-
- if (n_sets == 1 && sets[0].rtl)
- try_back_substitute_reg (sets[0].rtl, insn);
-
-done:;
-}
-
-/* Remove from the hash table all expressions that reference memory. */
-
-static void
-invalidate_memory (void)
-{
- int i;
- struct table_elt *p, *next;
-
- for (i = 0; i < HASH_SIZE; i++)
- for (p = table[i]; p; p = next)
- {
- next = p->next_same_hash;
- if (p->in_memory)
- remove_from_table (p, i);
- }
-}
-
-/* Perform invalidation on the basis of everything about INSN,
- except for invalidating the actual places that are SET in it.
- This includes the places CLOBBERed, and anything that might
- alias with something that is SET or CLOBBERed. */
-
-static void
-invalidate_from_clobbers (rtx_insn *insn)
-{
- rtx x = PATTERN (insn);
-
- if (GET_CODE (x) == CLOBBER)
- {
- rtx ref = XEXP (x, 0);
- if (ref)
- {
- if (REG_P (ref) || GET_CODE (ref) == SUBREG
- || MEM_P (ref))
- invalidate (ref, VOIDmode);
- else if (GET_CODE (ref) == STRICT_LOW_PART
- || GET_CODE (ref) == ZERO_EXTRACT)
- invalidate (XEXP (ref, 0), GET_MODE (ref));
- }
- }
- else if (GET_CODE (x) == PARALLEL)
- {
- int i;
- for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- {
- rtx y = XVECEXP (x, 0, i);
- if (GET_CODE (y) == CLOBBER)
- {
- rtx ref = XEXP (y, 0);
- if (REG_P (ref) || GET_CODE (ref) == SUBREG
- || MEM_P (ref))
- invalidate (ref, VOIDmode);
- else if (GET_CODE (ref) == STRICT_LOW_PART
- || GET_CODE (ref) == ZERO_EXTRACT)
- invalidate (XEXP (ref, 0), GET_MODE (ref));
- }
- }
- }
-}
-
-/* Perform invalidation on the basis of everything about INSN.
- This includes the places CLOBBERed, and anything that might
- alias with something that is SET or CLOBBERed. */
-
-static void
-invalidate_from_sets_and_clobbers (rtx_insn *insn)
-{
- rtx tem;
- rtx x = PATTERN (insn);
-
- if (CALL_P (insn))
- {
- for (tem = CALL_INSN_FUNCTION_USAGE (insn); tem; tem = XEXP (tem, 1))
- {
- rtx temx = XEXP (tem, 0);
- if (GET_CODE (temx) == CLOBBER)
- invalidate (SET_DEST (temx), VOIDmode);
- }
- }
-
- /* Ensure we invalidate the destination register of a CALL insn.
- This is necessary for machines where this register is a fixed_reg,
- because no other code would invalidate it. */
- if (GET_CODE (x) == SET && GET_CODE (SET_SRC (x)) == CALL)
- invalidate (SET_DEST (x), VOIDmode);
-
- else if (GET_CODE (x) == PARALLEL)
- {
- int i;
-
- for (i = XVECLEN (x, 0) - 1; i >= 0; i--)
- {
- rtx y = XVECEXP (x, 0, i);
- if (GET_CODE (y) == CLOBBER)
- {
- rtx clobbered = XEXP (y, 0);
-
- if (REG_P (clobbered)
- || GET_CODE (clobbered) == SUBREG)
- invalidate (clobbered, VOIDmode);
- else if (GET_CODE (clobbered) == STRICT_LOW_PART
- || GET_CODE (clobbered) == ZERO_EXTRACT)
- invalidate (XEXP (clobbered, 0), GET_MODE (clobbered));
- }
- else if (GET_CODE (y) == SET && GET_CODE (SET_SRC (y)) == CALL)
- invalidate (SET_DEST (y), VOIDmode);
- }
- }
-}
-
-static rtx cse_process_note (rtx);
-
-/* A simplify_replace_fn_rtx callback for cse_process_note. Process X,
- part of the REG_NOTES of an insn. Replace any registers with either
- an equivalent constant or the canonical form of the register.
- Only replace addresses if the containing MEM remains valid.
-
- Return the replacement for X, or null if it should be simplified
- recursively. */
-
-static rtx
-cse_process_note_1 (rtx x, const_rtx, void *)
-{
- if (MEM_P (x))
- {
- validate_change (x, &XEXP (x, 0), cse_process_note (XEXP (x, 0)), false);
- return x;
- }
-
- if (REG_P (x))
- {
- int i = REG_QTY (REGNO (x));
-
- /* Return a constant or a constant register. */
- if (REGNO_QTY_VALID_P (REGNO (x)))
- {
- struct qty_table_elem *ent = &qty_table[i];
-
- if (ent->const_rtx != NULL_RTX
- && (CONSTANT_P (ent->const_rtx)
- || REG_P (ent->const_rtx)))
- {
- rtx new_rtx = gen_lowpart (GET_MODE (x), ent->const_rtx);
- if (new_rtx)
- return copy_rtx (new_rtx);
- }
- }
-
- /* Otherwise, canonicalize this register. */
- return canon_reg (x, NULL);
- }
-
- return NULL_RTX;
-}
-
-/* Process X, part of the REG_NOTES of an insn. Replace any registers in it
- with either an equivalent constant or the canonical form of the register.
- Only replace addresses if the containing MEM remains valid. */
-
-static rtx
-cse_process_note (rtx x)
-{
- return simplify_replace_fn_rtx (x, NULL_RTX, cse_process_note_1, NULL);
-}
-
-
-/* Find a path in the CFG, starting with FIRST_BB to perform CSE on.
-
- DATA is a pointer to a struct cse_basic_block_data, that is used to
- describe the path.
- It is filled with a queue of basic blocks, starting with FIRST_BB
- and following a trace through the CFG.
-
- If all paths starting at FIRST_BB have been followed, or no new path
- starting at FIRST_BB can be constructed, this function returns FALSE.
- Otherwise, DATA->path is filled and the function returns TRUE indicating
- that a path to follow was found.
-
- If FOLLOW_JUMPS is false, the maximum path length is 1 and the only
- block in the path will be FIRST_BB. */
-
-static bool
-cse_find_path (basic_block first_bb, struct cse_basic_block_data *data,
- int follow_jumps)
-{
- basic_block bb;
- edge e;
- int path_size;
-
- bitmap_set_bit (cse_visited_basic_blocks, first_bb->index);
-
- /* See if there is a previous path. */
- path_size = data->path_size;
-
- /* There is a previous path. Make sure it started with FIRST_BB. */
- if (path_size)
- gcc_assert (data->path[0].bb == first_bb);
-
- /* There was only one basic block in the last path. Clear the path and
- return, so that paths starting at another basic block can be tried. */
- if (path_size == 1)
- {
- path_size = 0;
- goto done;
- }
-
- /* If the path was empty from the beginning, construct a new path. */
- if (path_size == 0)
- data->path[path_size++].bb = first_bb;
- else
- {
- /* Otherwise, path_size must be equal to or greater than 2, because
- a previous path exists that is at least two basic blocks long.
-
- Update the previous branch path, if any. If the last branch was
- previously along the branch edge, take the fallthrough edge now. */
- while (path_size >= 2)
- {
- basic_block last_bb_in_path, previous_bb_in_path;
- edge e;
-
- --path_size;
- last_bb_in_path = data->path[path_size].bb;
- previous_bb_in_path = data->path[path_size - 1].bb;
-
- /* If we previously followed a path along the branch edge, try
- the fallthru edge now. */
- if (EDGE_COUNT (previous_bb_in_path->succs) == 2
- && any_condjump_p (BB_END (previous_bb_in_path))
- && (e = find_edge (previous_bb_in_path, last_bb_in_path))
- && e == BRANCH_EDGE (previous_bb_in_path))
- {
- bb = FALLTHRU_EDGE (previous_bb_in_path)->dest;
- if (bb != EXIT_BLOCK_PTR_FOR_FN (cfun)
- && single_pred_p (bb)
- /* We used to assert here that we would only see blocks
- that we have not visited yet. But we may end up
- visiting basic blocks twice if the CFG has changed
- in this run of cse_main, because when the CFG changes
- the topological sort of the CFG also changes. A basic
- blocks that previously had more than two predecessors
- may now have a single predecessor, and become part of
- a path that starts at another basic block.
-
- We still want to visit each basic block only once, so
- halt the path here if we have already visited BB. */
- && !bitmap_bit_p (cse_visited_basic_blocks, bb->index))
- {
- bitmap_set_bit (cse_visited_basic_blocks, bb->index);
- data->path[path_size++].bb = bb;
- break;
- }
- }
-
- data->path[path_size].bb = NULL;
- }
-
- /* If only one block remains in the path, bail. */
- if (path_size == 1)
- {
- path_size = 0;
- goto done;
- }
- }
-
- /* Extend the path if possible. */
- if (follow_jumps)
- {
- bb = data->path[path_size - 1].bb;
- while (bb && path_size < param_max_cse_path_length)
- {
- if (single_succ_p (bb))
- e = single_succ_edge (bb);
- else if (EDGE_COUNT (bb->succs) == 2
- && any_condjump_p (BB_END (bb)))
- {
- /* First try to follow the branch. If that doesn't lead
- to a useful path, follow the fallthru edge. */
- e = BRANCH_EDGE (bb);
- if (!single_pred_p (e->dest))
- e = FALLTHRU_EDGE (bb);
- }
- else
- e = NULL;
-
- if (e
- && !((e->flags & EDGE_ABNORMAL_CALL) && cfun->has_nonlocal_label)
- && e->dest != EXIT_BLOCK_PTR_FOR_FN (cfun)
- && single_pred_p (e->dest)
- /* Avoid visiting basic blocks twice. The large comment
- above explains why this can happen. */
- && !bitmap_bit_p (cse_visited_basic_blocks, e->dest->index))
- {
- basic_block bb2 = e->dest;
- bitmap_set_bit (cse_visited_basic_blocks, bb2->index);
- data->path[path_size++].bb = bb2;
- bb = bb2;
- }
- else
- bb = NULL;
- }
- }
-
-done:
- data->path_size = path_size;
- return path_size != 0;
-}
-
-/* Dump the path in DATA to file F. NSETS is the number of sets
- in the path. */
-
-static void
-cse_dump_path (struct cse_basic_block_data *data, int nsets, FILE *f)
-{
- int path_entry;
-
- fprintf (f, ";; Following path with %d sets: ", nsets);
- for (path_entry = 0; path_entry < data->path_size; path_entry++)
- fprintf (f, "%d ", (data->path[path_entry].bb)->index);
- fputc ('\n', f);
- fflush (f);
-}
-
-
-/* Return true if BB has exception handling successor edges. */
-
-static bool
-have_eh_succ_edges (basic_block bb)
-{
- edge e;
- edge_iterator ei;
-
- FOR_EACH_EDGE (e, ei, bb->succs)
- if (e->flags & EDGE_EH)
- return true;
-
- return false;
-}
-
-
-/* Scan to the end of the path described by DATA. Return an estimate of
- the total number of SETs of all insns in the path. */
-
-static void
-cse_prescan_path (struct cse_basic_block_data *data)
-{
- int nsets = 0;
- int path_size = data->path_size;
- int path_entry;
-
- /* Scan to end of each basic block in the path. */
- for (path_entry = 0; path_entry < path_size; path_entry++)
- {
- basic_block bb;
- rtx_insn *insn;
-
- bb = data->path[path_entry].bb;
-
- FOR_BB_INSNS (bb, insn)
- {
- if (!INSN_P (insn))
- continue;
-
- /* A PARALLEL can have lots of SETs in it,
- especially if it is really an ASM_OPERANDS. */
- if (GET_CODE (PATTERN (insn)) == PARALLEL)
- nsets += XVECLEN (PATTERN (insn), 0);
- else
- nsets += 1;
- }
- }
-
- data->nsets = nsets;
-}
-
-/* Return true if the pattern of INSN uses a LABEL_REF for which
- there isn't a REG_LABEL_OPERAND note. */
-
-static bool
-check_for_label_ref (rtx_insn *insn)
-{
- /* If this insn uses a LABEL_REF and there isn't a REG_LABEL_OPERAND
- note for it, we must rerun jump since it needs to place the note. If
- this is a LABEL_REF for a CODE_LABEL that isn't in the insn chain,
- don't do this since no REG_LABEL_OPERAND will be added. */
- subrtx_iterator::array_type array;
- FOR_EACH_SUBRTX (iter, array, PATTERN (insn), ALL)
- {
- const_rtx x = *iter;
- if (GET_CODE (x) == LABEL_REF
- && !LABEL_REF_NONLOCAL_P (x)
- && (!JUMP_P (insn)
- || !label_is_jump_target_p (label_ref_label (x), insn))
- && LABEL_P (label_ref_label (x))
- && INSN_UID (label_ref_label (x)) != 0
- && !find_reg_note (insn, REG_LABEL_OPERAND, label_ref_label (x)))
- return true;
- }
- return false;
-}
-
-/* Process a single extended basic block described by EBB_DATA. */
-
-static void
-cse_extended_basic_block (struct cse_basic_block_data *ebb_data)
-{
- int path_size = ebb_data->path_size;
- int path_entry;
- int num_insns = 0;
-
- /* Allocate the space needed by qty_table. */
- qty_table = XNEWVEC (struct qty_table_elem, max_qty);
-
- new_basic_block ();
- cse_ebb_live_in = df_get_live_in (ebb_data->path[0].bb);
- cse_ebb_live_out = df_get_live_out (ebb_data->path[path_size - 1].bb);
- for (path_entry = 0; path_entry < path_size; path_entry++)
- {
- basic_block bb;
- rtx_insn *insn;
-
- bb = ebb_data->path[path_entry].bb;
-
- /* Invalidate recorded information for eh regs if there is an EH
- edge pointing to that bb. */
- if (bb_has_eh_pred (bb))
- {
- df_ref def;
-
- FOR_EACH_ARTIFICIAL_DEF (def, bb->index)
- if (DF_REF_FLAGS (def) & DF_REF_AT_TOP)
- invalidate (DF_REF_REG (def), GET_MODE (DF_REF_REG (def)));
- }
-
- optimize_this_for_speed_p = optimize_bb_for_speed_p (bb);
- FOR_BB_INSNS (bb, insn)
- {
- /* If we have processed 1,000 insns, flush the hash table to
- avoid extreme quadratic behavior. We must not include NOTEs
- in the count since there may be more of them when generating
- debugging information. If we clear the table at different
- times, code generated with -g -O might be different than code
- generated with -O but not -g.
-
- FIXME: This is a real kludge and needs to be done some other
- way. */
- if (NONDEBUG_INSN_P (insn)
- && num_insns++ > param_max_cse_insns)
- {
- flush_hash_table ();
- num_insns = 0;
- }
-
- if (INSN_P (insn))
- {
- /* Process notes first so we have all notes in canonical forms
- when looking for duplicate operations. */
- bool changed = false;
- for (rtx note = REG_NOTES (insn); note; note = XEXP (note, 1))
- if (REG_NOTE_KIND (note) == REG_EQUAL)
- {
- rtx newval = cse_process_note (XEXP (note, 0));
- if (newval != XEXP (note, 0))
- {
- XEXP (note, 0) = newval;
- changed = true;
- }
- }
- if (changed)
- df_notes_rescan (insn);
-
- cse_insn (insn);
-
- /* If we haven't already found an insn where we added a LABEL_REF,
- check this one. */
- if (INSN_P (insn) && !recorded_label_ref
- && check_for_label_ref (insn))
- recorded_label_ref = true;
- }
- }
-
- /* With non-call exceptions, we are not always able to update
- the CFG properly inside cse_insn. So clean up possibly
- redundant EH edges here. */
- if (cfun->can_throw_non_call_exceptions && have_eh_succ_edges (bb))
- cse_cfg_altered |= purge_dead_edges (bb);
-
- /* If we changed a conditional jump, we may have terminated
- the path we are following. Check that by verifying that
- the edge we would take still exists. If the edge does
- not exist anymore, purge the remainder of the path.
- Note that this will cause us to return to the caller. */
- if (path_entry < path_size - 1)
- {
- basic_block next_bb = ebb_data->path[path_entry + 1].bb;
- if (!find_edge (bb, next_bb))
- {
- do
- {
- path_size--;
-
- /* If we truncate the path, we must also reset the
- visited bit on the remaining blocks in the path,
- or we will never visit them at all. */
- bitmap_clear_bit (cse_visited_basic_blocks,
- ebb_data->path[path_size].bb->index);
- ebb_data->path[path_size].bb = NULL;
- }
- while (path_size - 1 != path_entry);
- ebb_data->path_size = path_size;
- }
- }
-
- /* If this is a conditional jump insn, record any known
- equivalences due to the condition being tested. */
- insn = BB_END (bb);
- if (path_entry < path_size - 1
- && EDGE_COUNT (bb->succs) == 2
- && JUMP_P (insn)
- && single_set (insn)
- && any_condjump_p (insn))
- {
- basic_block next_bb = ebb_data->path[path_entry + 1].bb;
- bool taken = (next_bb == BRANCH_EDGE (bb)->dest);
- record_jump_equiv (insn, taken);
- }
- }
-
- gcc_assert (next_qty <= max_qty);
-
- free (qty_table);
-}
-
-
-/* Perform cse on the instructions of a function.
- F is the first instruction.
- NREGS is one plus the highest pseudo-reg number used in the instruction.
-
- Return 2 if jump optimizations should be redone due to simplifications
- in conditional jump instructions.
- Return 1 if the CFG should be cleaned up because it has been modified.
- Return 0 otherwise. */
-
-static int
-cse_main (rtx_insn *f ATTRIBUTE_UNUSED, int nregs)
-{
- struct cse_basic_block_data ebb_data;
- basic_block bb;
- int *rc_order = XNEWVEC (int, last_basic_block_for_fn (cfun));
- int i, n_blocks;
-
- /* CSE doesn't use dominane info but can invalidate it in different ways.
- For simplicity free dominance info here. */
- free_dominance_info (CDI_DOMINATORS);
-
- df_set_flags (DF_LR_RUN_DCE);
- df_note_add_problem ();
- df_analyze ();
- df_set_flags (DF_DEFER_INSN_RESCAN);
-
- reg_scan (get_insns (), max_reg_num ());
- init_cse_reg_info (nregs);
-
- ebb_data.path = XNEWVEC (struct branch_path,
- param_max_cse_path_length);
-
- cse_cfg_altered = false;
- cse_jumps_altered = false;
- recorded_label_ref = false;
- ebb_data.path_size = 0;
- ebb_data.nsets = 0;
- rtl_hooks = cse_rtl_hooks;
-
- init_recog ();
- init_alias_analysis ();
-
- reg_eqv_table = XNEWVEC (struct reg_eqv_elem, nregs);
-
- /* Set up the table of already visited basic blocks. */
- cse_visited_basic_blocks = sbitmap_alloc (last_basic_block_for_fn (cfun));
- bitmap_clear (cse_visited_basic_blocks);
-
- /* Loop over basic blocks in reverse completion order (RPO),
- excluding the ENTRY and EXIT blocks. */
- n_blocks = pre_and_rev_post_order_compute (NULL, rc_order, false);
- i = 0;
- while (i < n_blocks)
- {
- /* Find the first block in the RPO queue that we have not yet
- processed before. */
- do
- {
- bb = BASIC_BLOCK_FOR_FN (cfun, rc_order[i++]);
- }
- while (bitmap_bit_p (cse_visited_basic_blocks, bb->index)
- && i < n_blocks);
-
- /* Find all paths starting with BB, and process them. */
- while (cse_find_path (bb, &ebb_data, flag_cse_follow_jumps))
- {
- /* Pre-scan the path. */
- cse_prescan_path (&ebb_data);
-
- /* If this basic block has no sets, skip it. */
- if (ebb_data.nsets == 0)
- continue;
-
- /* Get a reasonable estimate for the maximum number of qty's
- needed for this path. For this, we take the number of sets
- and multiply that by MAX_RECOG_OPERANDS. */
- max_qty = ebb_data.nsets * MAX_RECOG_OPERANDS;
-
- /* Dump the path we're about to process. */
- if (dump_file)
- cse_dump_path (&ebb_data, ebb_data.nsets, dump_file);
-
- cse_extended_basic_block (&ebb_data);
- }
- }
-
- /* Clean up. */
- end_alias_analysis ();
- free (reg_eqv_table);
- free (ebb_data.path);
- sbitmap_free (cse_visited_basic_blocks);
- free (rc_order);
- rtl_hooks = general_rtl_hooks;
-
- if (cse_jumps_altered || recorded_label_ref)
- return 2;
- else if (cse_cfg_altered)
- return 1;
- else
- return 0;
-}
-
-/* Count the number of times registers are used (not set) in X.
- COUNTS is an array in which we accumulate the count, INCR is how much
- we count each register usage.
-
- Don't count a usage of DEST, which is the SET_DEST of a SET which
- contains X in its SET_SRC. This is because such a SET does not
- modify the liveness of DEST.
- DEST is set to pc_rtx for a trapping insn, or for an insn with side effects.
- We must then count uses of a SET_DEST regardless, because the insn can't be
- deleted here. */
-
-static void
-count_reg_usage (rtx x, int *counts, rtx dest, int incr)
-{
- enum rtx_code code;
- rtx note;
- const char *fmt;
- int i, j;
-
- if (x == 0)
- return;
-
- switch (code = GET_CODE (x))
- {
- case REG:
- if (x != dest)
- counts[REGNO (x)] += incr;
- return;
-
- case PC:
- case CONST:
- CASE_CONST_ANY:
- case SYMBOL_REF:
- case LABEL_REF:
- return;
-
- case CLOBBER:
- /* If we are clobbering a MEM, mark any registers inside the address
- as being used. */
- if (MEM_P (XEXP (x, 0)))
- count_reg_usage (XEXP (XEXP (x, 0), 0), counts, NULL_RTX, incr);
- return;
-
- case SET:
- /* Unless we are setting a REG, count everything in SET_DEST. */
- if (!REG_P (SET_DEST (x)))
- count_reg_usage (SET_DEST (x), counts, NULL_RTX, incr);
- count_reg_usage (SET_SRC (x), counts,
- dest ? dest : SET_DEST (x),
- incr);
- return;
-
- case DEBUG_INSN:
- return;
-
- case CALL_INSN:
- case INSN:
- case JUMP_INSN:
- /* We expect dest to be NULL_RTX here. If the insn may throw,
- or if it cannot be deleted due to side-effects, mark this fact
- by setting DEST to pc_rtx. */
- if ((!cfun->can_delete_dead_exceptions && !insn_nothrow_p (x))
- || side_effects_p (PATTERN (x)))
- dest = pc_rtx;
- if (code == CALL_INSN)
- count_reg_usage (CALL_INSN_FUNCTION_USAGE (x), counts, dest, incr);
- count_reg_usage (PATTERN (x), counts, dest, incr);
-
- /* Things used in a REG_EQUAL note aren't dead since loop may try to
- use them. */
-
- note = find_reg_equal_equiv_note (x);
- if (note)
- {
- rtx eqv = XEXP (note, 0);
-
- if (GET_CODE (eqv) == EXPR_LIST)
- /* This REG_EQUAL note describes the result of a function call.
- Process all the arguments. */
- do
- {
- count_reg_usage (XEXP (eqv, 0), counts, dest, incr);
- eqv = XEXP (eqv, 1);
- }
- while (eqv && GET_CODE (eqv) == EXPR_LIST);
- else
- count_reg_usage (eqv, counts, dest, incr);
- }
- return;
-
- case EXPR_LIST:
- if (REG_NOTE_KIND (x) == REG_EQUAL
- || (REG_NOTE_KIND (x) != REG_NONNEG && GET_CODE (XEXP (x,0)) == USE)
- /* FUNCTION_USAGE expression lists may include (CLOBBER (mem /u)),
- involving registers in the address. */
- || GET_CODE (XEXP (x, 0)) == CLOBBER)
- count_reg_usage (XEXP (x, 0), counts, NULL_RTX, incr);
-
- count_reg_usage (XEXP (x, 1), counts, NULL_RTX, incr);
- return;
-
- case ASM_OPERANDS:
- /* Iterate over just the inputs, not the constraints as well. */
- for (i = ASM_OPERANDS_INPUT_LENGTH (x) - 1; i >= 0; i--)
- count_reg_usage (ASM_OPERANDS_INPUT (x, i), counts, dest, incr);
- return;
-
- case INSN_LIST:
- case INT_LIST:
- gcc_unreachable ();
-
- default:
- break;
- }
-
- fmt = GET_RTX_FORMAT (code);
- for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
- {
- if (fmt[i] == 'e')
- count_reg_usage (XEXP (x, i), counts, dest, incr);
- else if (fmt[i] == 'E')
- for (j = XVECLEN (x, i) - 1; j >= 0; j--)
- count_reg_usage (XVECEXP (x, i, j), counts, dest, incr);
- }
-}
-
-/* Return true if X is a dead register. */
-
-static inline int
-is_dead_reg (const_rtx x, int *counts)
-{
- return (REG_P (x)
- && REGNO (x) >= FIRST_PSEUDO_REGISTER
- && counts[REGNO (x)] == 0);
-}
-
-/* Return true if set is live. */
-static bool
-set_live_p (rtx set, int *counts)
-{
- if (set_noop_p (set))
- return false;
-
- if (!is_dead_reg (SET_DEST (set), counts)
- || side_effects_p (SET_SRC (set)))
- return true;
-
- return false;
-}
-
-/* Return true if insn is live. */
-
-static bool
-insn_live_p (rtx_insn *insn, int *counts)
-{
- int i;
- if (!cfun->can_delete_dead_exceptions && !insn_nothrow_p (insn))
- return true;
- else if (GET_CODE (PATTERN (insn)) == SET)
- return set_live_p (PATTERN (insn), counts);
- else if (GET_CODE (PATTERN (insn)) == PARALLEL)
- {
- for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
- {
- rtx elt = XVECEXP (PATTERN (insn), 0, i);
-
- if (GET_CODE (elt) == SET)
- {
- if (set_live_p (elt, counts))
- return true;
- }
- else if (GET_CODE (elt) != CLOBBER && GET_CODE (elt) != USE)
- return true;
- }
- return false;
- }
- else if (DEBUG_INSN_P (insn))
- {
- rtx_insn *next;
-
- if (DEBUG_MARKER_INSN_P (insn))
- return true;
-
- for (next = NEXT_INSN (insn); next; next = NEXT_INSN (next))
- if (NOTE_P (next))
- continue;
- else if (!DEBUG_INSN_P (next))
- return true;
- /* If we find an inspection point, such as a debug begin stmt,
- we want to keep the earlier debug insn. */
- else if (DEBUG_MARKER_INSN_P (next))
- return true;
- else if (INSN_VAR_LOCATION_DECL (insn) == INSN_VAR_LOCATION_DECL (next))
- return false;
-
- return true;
- }
- else
- return true;
-}
-
-/* Count the number of stores into pseudo. Callback for note_stores. */
-
-static void
-count_stores (rtx x, const_rtx set ATTRIBUTE_UNUSED, void *data)
-{
- int *counts = (int *) data;
- if (REG_P (x) && REGNO (x) >= FIRST_PSEUDO_REGISTER)
- counts[REGNO (x)]++;
-}
-
-/* Return if DEBUG_INSN pattern PAT needs to be reset because some dead
- pseudo doesn't have a replacement. COUNTS[X] is zero if register X
- is dead and REPLACEMENTS[X] is null if it has no replacemenet.
- Set *SEEN_REPL to true if we see a dead register that does have
- a replacement. */
-
-static bool
-is_dead_debug_insn (const_rtx pat, int *counts, rtx *replacements,
- bool *seen_repl)
-{
- subrtx_iterator::array_type array;
- FOR_EACH_SUBRTX (iter, array, pat, NONCONST)
- {
- const_rtx x = *iter;
- if (is_dead_reg (x, counts))
- {
- if (replacements && replacements[REGNO (x)] != NULL_RTX)
- *seen_repl = true;
- else
- return true;
- }
- }
- return false;
-}
-
-/* Replace a dead pseudo in a DEBUG_INSN with replacement DEBUG_EXPR.
- Callback for simplify_replace_fn_rtx. */
-
-static rtx
-replace_dead_reg (rtx x, const_rtx old_rtx ATTRIBUTE_UNUSED, void *data)
-{
- rtx *replacements = (rtx *) data;
-
- if (REG_P (x)
- && REGNO (x) >= FIRST_PSEUDO_REGISTER
- && replacements[REGNO (x)] != NULL_RTX)
- {
- if (GET_MODE (x) == GET_MODE (replacements[REGNO (x)]))
- return replacements[REGNO (x)];
- return lowpart_subreg (GET_MODE (x), replacements[REGNO (x)],
- GET_MODE (replacements[REGNO (x)]));
- }
- return NULL_RTX;
-}
-
-/* Scan all the insns and delete any that are dead; i.e., they store a register
- that is never used or they copy a register to itself.
-
- This is used to remove insns made obviously dead by cse, loop or other
- optimizations. It improves the heuristics in loop since it won't try to
- move dead invariants out of loops or make givs for dead quantities. The
- remaining passes of the compilation are also sped up. */
-
-int
-delete_trivially_dead_insns (rtx_insn *insns, int nreg)
-{
- int *counts;
- rtx_insn *insn, *prev;
- rtx *replacements = NULL;
- int ndead = 0;
-
- timevar_push (TV_DELETE_TRIVIALLY_DEAD);
- /* First count the number of times each register is used. */
- if (MAY_HAVE_DEBUG_BIND_INSNS)
- {
- counts = XCNEWVEC (int, nreg * 3);
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- if (DEBUG_BIND_INSN_P (insn))
- count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
- NULL_RTX, 1);
- else if (INSN_P (insn))
- {
- count_reg_usage (insn, counts, NULL_RTX, 1);
- note_stores (insn, count_stores, counts + nreg * 2);
- }
- /* If there can be debug insns, COUNTS are 3 consecutive arrays.
- First one counts how many times each pseudo is used outside
- of debug insns, second counts how many times each pseudo is
- used in debug insns and third counts how many times a pseudo
- is stored. */
- }
- else
- {
- counts = XCNEWVEC (int, nreg);
- for (insn = insns; insn; insn = NEXT_INSN (insn))
- if (INSN_P (insn))
- count_reg_usage (insn, counts, NULL_RTX, 1);
- /* If no debug insns can be present, COUNTS is just an array
- which counts how many times each pseudo is used. */
- }
- /* Pseudo PIC register should be considered as used due to possible
- new usages generated. */
- if (!reload_completed
- && pic_offset_table_rtx
- && REGNO (pic_offset_table_rtx) >= FIRST_PSEUDO_REGISTER)
- counts[REGNO (pic_offset_table_rtx)]++;
- /* Go from the last insn to the first and delete insns that only set unused
- registers or copy a register to itself. As we delete an insn, remove
- usage counts for registers it uses.
-
- The first jump optimization pass may leave a real insn as the last
- insn in the function. We must not skip that insn or we may end
- up deleting code that is not really dead.
-
- If some otherwise unused register is only used in DEBUG_INSNs,
- try to create a DEBUG_EXPR temporary and emit a DEBUG_INSN before
- the setter. Then go through DEBUG_INSNs and if a DEBUG_EXPR
- has been created for the unused register, replace it with
- the DEBUG_EXPR, otherwise reset the DEBUG_INSN. */
- for (insn = get_last_insn (); insn; insn = prev)
- {
- int live_insn = 0;
-
- prev = PREV_INSN (insn);
- if (!INSN_P (insn))
- continue;
-
- live_insn = insn_live_p (insn, counts);
-
- /* If this is a dead insn, delete it and show registers in it aren't
- being used. */
-
- if (! live_insn && dbg_cnt (delete_trivial_dead))
- {
- if (DEBUG_INSN_P (insn))
- {
- if (DEBUG_BIND_INSN_P (insn))
- count_reg_usage (INSN_VAR_LOCATION_LOC (insn), counts + nreg,
- NULL_RTX, -1);
- }
- else
- {
- rtx set;
- if (MAY_HAVE_DEBUG_BIND_INSNS
- && (set = single_set (insn)) != NULL_RTX
- && is_dead_reg (SET_DEST (set), counts)
- /* Used at least once in some DEBUG_INSN. */
- && counts[REGNO (SET_DEST (set)) + nreg] > 0
- /* And set exactly once. */
- && counts[REGNO (SET_DEST (set)) + nreg * 2] == 1
- && !side_effects_p (SET_SRC (set))
- && asm_noperands (PATTERN (insn)) < 0)
- {
- rtx dval, bind_var_loc;
- rtx_insn *bind;
-
- /* Create DEBUG_EXPR (and DEBUG_EXPR_DECL). */
- dval = make_debug_expr_from_rtl (SET_DEST (set));
-
- /* Emit a debug bind insn before the insn in which
- reg dies. */
- bind_var_loc =
- gen_rtx_VAR_LOCATION (GET_MODE (SET_DEST (set)),
- DEBUG_EXPR_TREE_DECL (dval),
- SET_SRC (set),
- VAR_INIT_STATUS_INITIALIZED);
- count_reg_usage (bind_var_loc, counts + nreg, NULL_RTX, 1);
-
- bind = emit_debug_insn_before (bind_var_loc, insn);
- df_insn_rescan (bind);
-
- if (replacements == NULL)
- replacements = XCNEWVEC (rtx, nreg);
- replacements[REGNO (SET_DEST (set))] = dval;
- }
-
- count_reg_usage (insn, counts, NULL_RTX, -1);
- ndead++;
- }
- cse_cfg_altered |= delete_insn_and_edges (insn);
- }
- }
-
- if (MAY_HAVE_DEBUG_BIND_INSNS)
- {
- for (insn = get_last_insn (); insn; insn = PREV_INSN (insn))
- if (DEBUG_BIND_INSN_P (insn))
- {
- /* If this debug insn references a dead register that wasn't replaced
- with an DEBUG_EXPR, reset the DEBUG_INSN. */
- bool seen_repl = false;
- if (is_dead_debug_insn (INSN_VAR_LOCATION_LOC (insn),
- counts, replacements, &seen_repl))
- {
- INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
- df_insn_rescan (insn);
- }
- else if (seen_repl)
- {
- INSN_VAR_LOCATION_LOC (insn)
- = simplify_replace_fn_rtx (INSN_VAR_LOCATION_LOC (insn),
- NULL_RTX, replace_dead_reg,
- replacements);
- df_insn_rescan (insn);
- }
- }
- free (replacements);
- }
-
- if (dump_file && ndead)
- fprintf (dump_file, "Deleted %i trivially dead insns\n",
- ndead);
- /* Clean up. */
- free (counts);
- timevar_pop (TV_DELETE_TRIVIALLY_DEAD);
- return ndead;
-}
-
-/* If LOC contains references to NEWREG in a different mode, change them
- to use NEWREG instead. */
-
-static void
-cse_change_cc_mode (subrtx_ptr_iterator::array_type &array,
- rtx *loc, rtx_insn *insn, rtx newreg)
-{
- FOR_EACH_SUBRTX_PTR (iter, array, loc, NONCONST)
- {
- rtx *loc = *iter;
- rtx x = *loc;
- if (x
- && REG_P (x)
- && REGNO (x) == REGNO (newreg)
- && GET_MODE (x) != GET_MODE (newreg))
- {
- validate_change (insn, loc, newreg, 1);
- iter.skip_subrtxes ();
- }
- }
-}
-
-/* Change the mode of any reference to the register REGNO (NEWREG) to
- GET_MODE (NEWREG) in INSN. */
-
-static void
-cse_change_cc_mode_insn (rtx_insn *insn, rtx newreg)
-{
- int success;
-
- if (!INSN_P (insn))
- return;
-
- subrtx_ptr_iterator::array_type array;
- cse_change_cc_mode (array, &PATTERN (insn), insn, newreg);
- cse_change_cc_mode (array, &REG_NOTES (insn), insn, newreg);
-
- /* If the following assertion was triggered, there is most probably
- something wrong with the cc_modes_compatible back end function.
- CC modes only can be considered compatible if the insn - with the mode
- replaced by any of the compatible modes - can still be recognized. */
- success = apply_change_group ();
- gcc_assert (success);
-}
-
-/* Change the mode of any reference to the register REGNO (NEWREG) to
- GET_MODE (NEWREG), starting at START. Stop before END. Stop at
- any instruction which modifies NEWREG. */
-
-static void
-cse_change_cc_mode_insns (rtx_insn *start, rtx_insn *end, rtx newreg)
-{
- rtx_insn *insn;
-
- for (insn = start; insn != end; insn = NEXT_INSN (insn))
- {
- if (! INSN_P (insn))
- continue;
-
- if (reg_set_p (newreg, insn))
- return;
-
- cse_change_cc_mode_insn (insn, newreg);
- }
-}
-
-/* BB is a basic block which finishes with CC_REG as a condition code
- register which is set to CC_SRC. Look through the successors of BB
- to find blocks which have a single predecessor (i.e., this one),
- and look through those blocks for an assignment to CC_REG which is
- equivalent to CC_SRC. CAN_CHANGE_MODE indicates whether we are
- permitted to change the mode of CC_SRC to a compatible mode. This
- returns VOIDmode if no equivalent assignments were found.
- Otherwise it returns the mode which CC_SRC should wind up with.
- ORIG_BB should be the same as BB in the outermost cse_cc_succs call,
- but is passed unmodified down to recursive calls in order to prevent
- endless recursion.
-
- The main complexity in this function is handling the mode issues.
- We may have more than one duplicate which we can eliminate, and we
- try to find a mode which will work for multiple duplicates. */
-
-static machine_mode
-cse_cc_succs (basic_block bb, basic_block orig_bb, rtx cc_reg, rtx cc_src,
- bool can_change_mode)
-{
- bool found_equiv;
- machine_mode mode;
- unsigned int insn_count;
- edge e;
- rtx_insn *insns[2];
- machine_mode modes[2];
- rtx_insn *last_insns[2];
- unsigned int i;
- rtx newreg;
- edge_iterator ei;
-
- /* We expect to have two successors. Look at both before picking
- the final mode for the comparison. If we have more successors
- (i.e., some sort of table jump, although that seems unlikely),
- then we require all beyond the first two to use the same
- mode. */
-
- found_equiv = false;
- mode = GET_MODE (cc_src);
- insn_count = 0;
- FOR_EACH_EDGE (e, ei, bb->succs)
- {
- rtx_insn *insn;
- rtx_insn *end;
-
- if (e->flags & EDGE_COMPLEX)
- continue;
-
- if (EDGE_COUNT (e->dest->preds) != 1
- || e->dest == EXIT_BLOCK_PTR_FOR_FN (cfun)
- /* Avoid endless recursion on unreachable blocks. */
- || e->dest == orig_bb)
- continue;
-
- end = NEXT_INSN (BB_END (e->dest));
- for (insn = BB_HEAD (e->dest); insn != end; insn = NEXT_INSN (insn))
- {
- rtx set;
-
- if (! INSN_P (insn))
- continue;
-
- /* If CC_SRC is modified, we have to stop looking for
- something which uses it. */
- if (modified_in_p (cc_src, insn))
- break;
-
- /* Check whether INSN sets CC_REG to CC_SRC. */
- set = single_set (insn);
- if (set
- && REG_P (SET_DEST (set))
- && REGNO (SET_DEST (set)) == REGNO (cc_reg))
- {
- bool found;
- machine_mode set_mode;
- machine_mode comp_mode;
-
- found = false;
- set_mode = GET_MODE (SET_SRC (set));
- comp_mode = set_mode;
- if (rtx_equal_p (cc_src, SET_SRC (set)))
- found = true;
- else if (GET_CODE (cc_src) == COMPARE
- && GET_CODE (SET_SRC (set)) == COMPARE
- && mode != set_mode
- && rtx_equal_p (XEXP (cc_src, 0),
- XEXP (SET_SRC (set), 0))
- && rtx_equal_p (XEXP (cc_src, 1),
- XEXP (SET_SRC (set), 1)))
-
- {
- comp_mode = targetm.cc_modes_compatible (mode, set_mode);
- if (comp_mode != VOIDmode
- && (can_change_mode || comp_mode == mode))
- found = true;
- }
-
- if (found)
- {
- found_equiv = true;
- if (insn_count < ARRAY_SIZE (insns))
- {
- insns[insn_count] = insn;
- modes[insn_count] = set_mode;
- last_insns[insn_count] = end;
- ++insn_count;
-
- if (mode != comp_mode)
- {
- gcc_assert (can_change_mode);
- mode = comp_mode;
-
- /* The modified insn will be re-recognized later. */
- PUT_MODE (cc_src, mode);
- }
- }
- else
- {
- if (set_mode != mode)
- {
- /* We found a matching expression in the
- wrong mode, but we don't have room to
- store it in the array. Punt. This case
- should be rare. */
- break;
- }
- /* INSN sets CC_REG to a value equal to CC_SRC
- with the right mode. We can simply delete
- it. */
- delete_insn (insn);
- }
-
- /* We found an instruction to delete. Keep looking,
- in the hopes of finding a three-way jump. */
- continue;
- }
-
- /* We found an instruction which sets the condition
- code, so don't look any farther. */
- break;
- }
-
- /* If INSN sets CC_REG in some other way, don't look any
- farther. */
- if (reg_set_p (cc_reg, insn))
- break;
- }
-
- /* If we fell off the bottom of the block, we can keep looking
- through successors. We pass CAN_CHANGE_MODE as false because
- we aren't prepared to handle compatibility between the
- further blocks and this block. */
- if (insn == end)
- {
- machine_mode submode;
-
- submode = cse_cc_succs (e->dest, orig_bb, cc_reg, cc_src, false);
- if (submode != VOIDmode)
- {
- gcc_assert (submode == mode);
- found_equiv = true;
- can_change_mode = false;
- }
- }
- }
-
- if (! found_equiv)
- return VOIDmode;
-
- /* Now INSN_COUNT is the number of instructions we found which set
- CC_REG to a value equivalent to CC_SRC. The instructions are in
- INSNS. The modes used by those instructions are in MODES. */
-
- newreg = NULL_RTX;
- for (i = 0; i < insn_count; ++i)
- {
- if (modes[i] != mode)
- {
- /* We need to change the mode of CC_REG in INSNS[i] and
- subsequent instructions. */
- if (! newreg)
- {
- if (GET_MODE (cc_reg) == mode)
- newreg = cc_reg;
- else
- newreg = gen_rtx_REG (mode, REGNO (cc_reg));
- }
- cse_change_cc_mode_insns (NEXT_INSN (insns[i]), last_insns[i],
- newreg);
- }
-
- cse_cfg_altered |= delete_insn_and_edges (insns[i]);
- }
-
- return mode;
-}
-
-/* If we have a fixed condition code register (or two), walk through
- the instructions and try to eliminate duplicate assignments. */
-
-static void
-cse_condition_code_reg (void)
-{
- unsigned int cc_regno_1;
- unsigned int cc_regno_2;
- rtx cc_reg_1;
- rtx cc_reg_2;
- basic_block bb;
-
- if (! targetm.fixed_condition_code_regs (&cc_regno_1, &cc_regno_2))
- return;
-
- cc_reg_1 = gen_rtx_REG (CCmode, cc_regno_1);
- if (cc_regno_2 != INVALID_REGNUM)
- cc_reg_2 = gen_rtx_REG (CCmode, cc_regno_2);
- else
- cc_reg_2 = NULL_RTX;
-
- FOR_EACH_BB_FN (bb, cfun)
- {
- rtx_insn *last_insn;
- rtx cc_reg;
- rtx_insn *insn;
- rtx_insn *cc_src_insn;
- rtx cc_src;
- machine_mode mode;
- machine_mode orig_mode;
-
- /* Look for blocks which end with a conditional jump based on a
- condition code register. Then look for the instruction which
- sets the condition code register. Then look through the
- successor blocks for instructions which set the condition
- code register to the same value. There are other possible
- uses of the condition code register, but these are by far the
- most common and the ones which we are most likely to be able
- to optimize. */
-
- last_insn = BB_END (bb);
- if (!JUMP_P (last_insn))
- continue;
-
- if (reg_referenced_p (cc_reg_1, PATTERN (last_insn)))
- cc_reg = cc_reg_1;
- else if (cc_reg_2 && reg_referenced_p (cc_reg_2, PATTERN (last_insn)))
- cc_reg = cc_reg_2;
- else
- continue;
-
- cc_src_insn = NULL;
- cc_src = NULL_RTX;
- for (insn = PREV_INSN (last_insn);
- insn && insn != PREV_INSN (BB_HEAD (bb));
- insn = PREV_INSN (insn))
- {
- rtx set;
-
- if (! INSN_P (insn))
- continue;
- set = single_set (insn);
- if (set
- && REG_P (SET_DEST (set))
- && REGNO (SET_DEST (set)) == REGNO (cc_reg))
- {
- cc_src_insn = insn;
- cc_src = SET_SRC (set);
- break;
- }
- else if (reg_set_p (cc_reg, insn))
- break;
- }
-
- if (! cc_src_insn)
- continue;
-
- if (modified_between_p (cc_src, cc_src_insn, NEXT_INSN (last_insn)))
- continue;
-
- /* Now CC_REG is a condition code register used for a
- conditional jump at the end of the block, and CC_SRC, in
- CC_SRC_INSN, is the value to which that condition code
- register is set, and CC_SRC is still meaningful at the end of
- the basic block. */
-
- orig_mode = GET_MODE (cc_src);
- mode = cse_cc_succs (bb, bb, cc_reg, cc_src, true);
- if (mode != VOIDmode)
- {
- gcc_assert (mode == GET_MODE (cc_src));
- if (mode != orig_mode)
- {
- rtx newreg = gen_rtx_REG (mode, REGNO (cc_reg));
-
- cse_change_cc_mode_insn (cc_src_insn, newreg);
-
- /* Do the same in the following insns that use the
- current value of CC_REG within BB. */
- cse_change_cc_mode_insns (NEXT_INSN (cc_src_insn),
- NEXT_INSN (last_insn),
- newreg);
- }
- }
- }
-}
-
-
-/* Perform common subexpression elimination. Nonzero value from
- `cse_main' means that jumps were simplified and some code may now
- be unreachable, so do jump optimization again. */
-static unsigned int
-rest_of_handle_cse (void)
-{
- int tem;
-
- if (dump_file)
- dump_flow_info (dump_file, dump_flags);
-
- tem = cse_main (get_insns (), max_reg_num ());
-
- /* If we are not running more CSE passes, then we are no longer
- expecting CSE to be run. But always rerun it in a cheap mode. */
- cse_not_expected = !flag_rerun_cse_after_loop && !flag_gcse;
-
- if (tem == 2)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
- timevar_pop (TV_JUMP);
- }
- else if (tem == 1 || optimize > 1)
- cse_cfg_altered |= cleanup_cfg (0);
-
- return 0;
-}
-
-namespace {
-
-const pass_data pass_data_cse =
-{
- RTL_PASS, /* type */
- "cse1", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_CSE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish, /* todo_flags_finish */
-};
-
-class pass_cse : public rtl_opt_pass
-{
-public:
- pass_cse (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_cse, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *) { return optimize > 0; }
- virtual unsigned int execute (function *) { return rest_of_handle_cse (); }
-
-}; // class pass_cse
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_cse (gcc::context *ctxt)
-{
- return new pass_cse (ctxt);
-}
-
-
-/* Run second CSE pass after loop optimizations. */
-static unsigned int
-rest_of_handle_cse2 (void)
-{
- int tem;
-
- if (dump_file)
- dump_flow_info (dump_file, dump_flags);
-
- tem = cse_main (get_insns (), max_reg_num ());
-
- /* Run a pass to eliminate duplicated assignments to condition code
- registers. We have to run this after bypass_jumps, because it
- makes it harder for that pass to determine whether a jump can be
- bypassed safely. */
- cse_condition_code_reg ();
-
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
- if (tem == 2)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
- timevar_pop (TV_JUMP);
- }
- else if (tem == 1 || cse_cfg_altered)
- cse_cfg_altered |= cleanup_cfg (0);
-
- cse_not_expected = 1;
- return 0;
-}
-
-
-namespace {
-
-const pass_data pass_data_cse2 =
-{
- RTL_PASS, /* type */
- "cse2", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_CSE2, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish, /* todo_flags_finish */
-};
-
-class pass_cse2 : public rtl_opt_pass
-{
-public:
- pass_cse2 (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_cse2, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- return optimize > 0 && flag_rerun_cse_after_loop;
- }
-
- virtual unsigned int execute (function *) { return rest_of_handle_cse2 (); }
-
-}; // class pass_cse2
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_cse2 (gcc::context *ctxt)
-{
- return new pass_cse2 (ctxt);
-}
-
-/* Run second CSE pass after loop optimizations. */
-static unsigned int
-rest_of_handle_cse_after_global_opts (void)
-{
- int save_cfj;
- int tem;
-
- /* We only want to do local CSE, so don't follow jumps. */
- save_cfj = flag_cse_follow_jumps;
- flag_cse_follow_jumps = 0;
-
- rebuild_jump_labels (get_insns ());
- tem = cse_main (get_insns (), max_reg_num ());
- cse_cfg_altered |= purge_all_dead_edges ();
- delete_trivially_dead_insns (get_insns (), max_reg_num ());
-
- cse_not_expected = !flag_rerun_cse_after_loop;
-
- /* If cse altered any jumps, rerun jump opts to clean things up. */
- if (tem == 2)
- {
- timevar_push (TV_JUMP);
- rebuild_jump_labels (get_insns ());
- cse_cfg_altered |= cleanup_cfg (CLEANUP_CFG_CHANGED);
- timevar_pop (TV_JUMP);
- }
- else if (tem == 1 || cse_cfg_altered)
- cse_cfg_altered |= cleanup_cfg (0);
-
- flag_cse_follow_jumps = save_cfj;
- return 0;
-}
-
-namespace {
-
-const pass_data pass_data_cse_after_global_opts =
-{
- RTL_PASS, /* type */
- "cse_local", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- TV_CSE, /* tv_id */
- 0, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_df_finish, /* todo_flags_finish */
-};
-
-class pass_cse_after_global_opts : public rtl_opt_pass
-{
-public:
- pass_cse_after_global_opts (gcc::context *ctxt)
- : rtl_opt_pass (pass_data_cse_after_global_opts, ctxt)
- {}
-
- /* opt_pass methods: */
- virtual bool gate (function *)
- {
- return optimize > 0 && flag_rerun_cse_after_global_opts;
- }
-
- virtual unsigned int execute (function *)
- {
- return rest_of_handle_cse_after_global_opts ();
- }
-
-}; // class pass_cse_after_global_opts
-
-} // anon namespace
-
-rtl_opt_pass *
-make_pass_cse_after_global_opts (gcc::context *ctxt)
-{
- return new pass_cse_after_global_opts (ctxt);
-}