diff options
author | Martin Liska <mliska@suse.cz> | 2022-01-14 16:56:44 +0100 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-01-17 22:12:04 +0100 |
commit | 5c69acb32329d49e58c26fa41ae74229a52b9106 (patch) | |
tree | ddb05f9d73afb6f998457d2ac4b720e3b3b60483 /gcc/reload1.c | |
parent | 490e23032baaece71f2ec09fa1805064b150fbc2 (diff) | |
download | gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.zip gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.gz gcc-5c69acb32329d49e58c26fa41ae74229a52b9106.tar.bz2 |
Rename .c files to .cc files.
gcc/ada/ChangeLog:
* adadecode.c: Moved to...
* adadecode.cc: ...here.
* affinity.c: Moved to...
* affinity.cc: ...here.
* argv-lynxos178-raven-cert.c: Moved to...
* argv-lynxos178-raven-cert.cc: ...here.
* argv.c: Moved to...
* argv.cc: ...here.
* aux-io.c: Moved to...
* aux-io.cc: ...here.
* cio.c: Moved to...
* cio.cc: ...here.
* cstreams.c: Moved to...
* cstreams.cc: ...here.
* env.c: Moved to...
* env.cc: ...here.
* exit.c: Moved to...
* exit.cc: ...here.
* expect.c: Moved to...
* expect.cc: ...here.
* final.c: Moved to...
* final.cc: ...here.
* gcc-interface/cuintp.c: Moved to...
* gcc-interface/cuintp.cc: ...here.
* gcc-interface/decl.c: Moved to...
* gcc-interface/decl.cc: ...here.
* gcc-interface/misc.c: Moved to...
* gcc-interface/misc.cc: ...here.
* gcc-interface/targtyps.c: Moved to...
* gcc-interface/targtyps.cc: ...here.
* gcc-interface/trans.c: Moved to...
* gcc-interface/trans.cc: ...here.
* gcc-interface/utils.c: Moved to...
* gcc-interface/utils.cc: ...here.
* gcc-interface/utils2.c: Moved to...
* gcc-interface/utils2.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* initialize.c: Moved to...
* initialize.cc: ...here.
* libgnarl/thread.c: Moved to...
* libgnarl/thread.cc: ...here.
* link.c: Moved to...
* link.cc: ...here.
* locales.c: Moved to...
* locales.cc: ...here.
* mkdir.c: Moved to...
* mkdir.cc: ...here.
* raise.c: Moved to...
* raise.cc: ...here.
* rtfinal.c: Moved to...
* rtfinal.cc: ...here.
* rtinit.c: Moved to...
* rtinit.cc: ...here.
* seh_init.c: Moved to...
* seh_init.cc: ...here.
* sigtramp-armdroid.c: Moved to...
* sigtramp-armdroid.cc: ...here.
* sigtramp-ios.c: Moved to...
* sigtramp-ios.cc: ...here.
* sigtramp-qnx.c: Moved to...
* sigtramp-qnx.cc: ...here.
* sigtramp-vxworks.c: Moved to...
* sigtramp-vxworks.cc: ...here.
* socket.c: Moved to...
* socket.cc: ...here.
* tracebak.c: Moved to...
* tracebak.cc: ...here.
* version.c: Moved to...
* version.cc: ...here.
* vx_stack_info.c: Moved to...
* vx_stack_info.cc: ...here.
gcc/ChangeLog:
* adjust-alignment.c: Moved to...
* adjust-alignment.cc: ...here.
* alias.c: Moved to...
* alias.cc: ...here.
* alloc-pool.c: Moved to...
* alloc-pool.cc: ...here.
* asan.c: Moved to...
* asan.cc: ...here.
* attribs.c: Moved to...
* attribs.cc: ...here.
* auto-inc-dec.c: Moved to...
* auto-inc-dec.cc: ...here.
* auto-profile.c: Moved to...
* auto-profile.cc: ...here.
* bb-reorder.c: Moved to...
* bb-reorder.cc: ...here.
* bitmap.c: Moved to...
* bitmap.cc: ...here.
* btfout.c: Moved to...
* btfout.cc: ...here.
* builtins.c: Moved to...
* builtins.cc: ...here.
* caller-save.c: Moved to...
* caller-save.cc: ...here.
* calls.c: Moved to...
* calls.cc: ...here.
* ccmp.c: Moved to...
* ccmp.cc: ...here.
* cfg.c: Moved to...
* cfg.cc: ...here.
* cfganal.c: Moved to...
* cfganal.cc: ...here.
* cfgbuild.c: Moved to...
* cfgbuild.cc: ...here.
* cfgcleanup.c: Moved to...
* cfgcleanup.cc: ...here.
* cfgexpand.c: Moved to...
* cfgexpand.cc: ...here.
* cfghooks.c: Moved to...
* cfghooks.cc: ...here.
* cfgloop.c: Moved to...
* cfgloop.cc: ...here.
* cfgloopanal.c: Moved to...
* cfgloopanal.cc: ...here.
* cfgloopmanip.c: Moved to...
* cfgloopmanip.cc: ...here.
* cfgrtl.c: Moved to...
* cfgrtl.cc: ...here.
* cgraph.c: Moved to...
* cgraph.cc: ...here.
* cgraphbuild.c: Moved to...
* cgraphbuild.cc: ...here.
* cgraphclones.c: Moved to...
* cgraphclones.cc: ...here.
* cgraphunit.c: Moved to...
* cgraphunit.cc: ...here.
* collect-utils.c: Moved to...
* collect-utils.cc: ...here.
* collect2-aix.c: Moved to...
* collect2-aix.cc: ...here.
* collect2.c: Moved to...
* collect2.cc: ...here.
* combine-stack-adj.c: Moved to...
* combine-stack-adj.cc: ...here.
* combine.c: Moved to...
* combine.cc: ...here.
* common/common-targhooks.c: Moved to...
* common/common-targhooks.cc: ...here.
* common/config/aarch64/aarch64-common.c: Moved to...
* common/config/aarch64/aarch64-common.cc: ...here.
* common/config/alpha/alpha-common.c: Moved to...
* common/config/alpha/alpha-common.cc: ...here.
* common/config/arc/arc-common.c: Moved to...
* common/config/arc/arc-common.cc: ...here.
* common/config/arm/arm-common.c: Moved to...
* common/config/arm/arm-common.cc: ...here.
* common/config/avr/avr-common.c: Moved to...
* common/config/avr/avr-common.cc: ...here.
* common/config/bfin/bfin-common.c: Moved to...
* common/config/bfin/bfin-common.cc: ...here.
* common/config/bpf/bpf-common.c: Moved to...
* common/config/bpf/bpf-common.cc: ...here.
* common/config/c6x/c6x-common.c: Moved to...
* common/config/c6x/c6x-common.cc: ...here.
* common/config/cr16/cr16-common.c: Moved to...
* common/config/cr16/cr16-common.cc: ...here.
* common/config/cris/cris-common.c: Moved to...
* common/config/cris/cris-common.cc: ...here.
* common/config/csky/csky-common.c: Moved to...
* common/config/csky/csky-common.cc: ...here.
* common/config/default-common.c: Moved to...
* common/config/default-common.cc: ...here.
* common/config/epiphany/epiphany-common.c: Moved to...
* common/config/epiphany/epiphany-common.cc: ...here.
* common/config/fr30/fr30-common.c: Moved to...
* common/config/fr30/fr30-common.cc: ...here.
* common/config/frv/frv-common.c: Moved to...
* common/config/frv/frv-common.cc: ...here.
* common/config/gcn/gcn-common.c: Moved to...
* common/config/gcn/gcn-common.cc: ...here.
* common/config/h8300/h8300-common.c: Moved to...
* common/config/h8300/h8300-common.cc: ...here.
* common/config/i386/i386-common.c: Moved to...
* common/config/i386/i386-common.cc: ...here.
* common/config/ia64/ia64-common.c: Moved to...
* common/config/ia64/ia64-common.cc: ...here.
* common/config/iq2000/iq2000-common.c: Moved to...
* common/config/iq2000/iq2000-common.cc: ...here.
* common/config/lm32/lm32-common.c: Moved to...
* common/config/lm32/lm32-common.cc: ...here.
* common/config/m32r/m32r-common.c: Moved to...
* common/config/m32r/m32r-common.cc: ...here.
* common/config/m68k/m68k-common.c: Moved to...
* common/config/m68k/m68k-common.cc: ...here.
* common/config/mcore/mcore-common.c: Moved to...
* common/config/mcore/mcore-common.cc: ...here.
* common/config/microblaze/microblaze-common.c: Moved to...
* common/config/microblaze/microblaze-common.cc: ...here.
* common/config/mips/mips-common.c: Moved to...
* common/config/mips/mips-common.cc: ...here.
* common/config/mmix/mmix-common.c: Moved to...
* common/config/mmix/mmix-common.cc: ...here.
* common/config/mn10300/mn10300-common.c: Moved to...
* common/config/mn10300/mn10300-common.cc: ...here.
* common/config/msp430/msp430-common.c: Moved to...
* common/config/msp430/msp430-common.cc: ...here.
* common/config/nds32/nds32-common.c: Moved to...
* common/config/nds32/nds32-common.cc: ...here.
* common/config/nios2/nios2-common.c: Moved to...
* common/config/nios2/nios2-common.cc: ...here.
* common/config/nvptx/nvptx-common.c: Moved to...
* common/config/nvptx/nvptx-common.cc: ...here.
* common/config/or1k/or1k-common.c: Moved to...
* common/config/or1k/or1k-common.cc: ...here.
* common/config/pa/pa-common.c: Moved to...
* common/config/pa/pa-common.cc: ...here.
* common/config/pdp11/pdp11-common.c: Moved to...
* common/config/pdp11/pdp11-common.cc: ...here.
* common/config/pru/pru-common.c: Moved to...
* common/config/pru/pru-common.cc: ...here.
* common/config/riscv/riscv-common.c: Moved to...
* common/config/riscv/riscv-common.cc: ...here.
* common/config/rs6000/rs6000-common.c: Moved to...
* common/config/rs6000/rs6000-common.cc: ...here.
* common/config/rx/rx-common.c: Moved to...
* common/config/rx/rx-common.cc: ...here.
* common/config/s390/s390-common.c: Moved to...
* common/config/s390/s390-common.cc: ...here.
* common/config/sh/sh-common.c: Moved to...
* common/config/sh/sh-common.cc: ...here.
* common/config/sparc/sparc-common.c: Moved to...
* common/config/sparc/sparc-common.cc: ...here.
* common/config/tilegx/tilegx-common.c: Moved to...
* common/config/tilegx/tilegx-common.cc: ...here.
* common/config/tilepro/tilepro-common.c: Moved to...
* common/config/tilepro/tilepro-common.cc: ...here.
* common/config/v850/v850-common.c: Moved to...
* common/config/v850/v850-common.cc: ...here.
* common/config/vax/vax-common.c: Moved to...
* common/config/vax/vax-common.cc: ...here.
* common/config/visium/visium-common.c: Moved to...
* common/config/visium/visium-common.cc: ...here.
* common/config/xstormy16/xstormy16-common.c: Moved to...
* common/config/xstormy16/xstormy16-common.cc: ...here.
* common/config/xtensa/xtensa-common.c: Moved to...
* common/config/xtensa/xtensa-common.cc: ...here.
* compare-elim.c: Moved to...
* compare-elim.cc: ...here.
* config/aarch64/aarch64-bti-insert.c: Moved to...
* config/aarch64/aarch64-bti-insert.cc: ...here.
* config/aarch64/aarch64-builtins.c: Moved to...
* config/aarch64/aarch64-builtins.cc: ...here.
* config/aarch64/aarch64-c.c: Moved to...
* config/aarch64/aarch64-c.cc: ...here.
* config/aarch64/aarch64-d.c: Moved to...
* config/aarch64/aarch64-d.cc: ...here.
* config/aarch64/aarch64.c: Moved to...
* config/aarch64/aarch64.cc: ...here.
* config/aarch64/cortex-a57-fma-steering.c: Moved to...
* config/aarch64/cortex-a57-fma-steering.cc: ...here.
* config/aarch64/driver-aarch64.c: Moved to...
* config/aarch64/driver-aarch64.cc: ...here.
* config/aarch64/falkor-tag-collision-avoidance.c: Moved to...
* config/aarch64/falkor-tag-collision-avoidance.cc: ...here.
* config/aarch64/host-aarch64-darwin.c: Moved to...
* config/aarch64/host-aarch64-darwin.cc: ...here.
* config/alpha/alpha.c: Moved to...
* config/alpha/alpha.cc: ...here.
* config/alpha/driver-alpha.c: Moved to...
* config/alpha/driver-alpha.cc: ...here.
* config/arc/arc-c.c: Moved to...
* config/arc/arc-c.cc: ...here.
* config/arc/arc.c: Moved to...
* config/arc/arc.cc: ...here.
* config/arc/driver-arc.c: Moved to...
* config/arc/driver-arc.cc: ...here.
* config/arm/aarch-common.c: Moved to...
* config/arm/aarch-common.cc: ...here.
* config/arm/arm-builtins.c: Moved to...
* config/arm/arm-builtins.cc: ...here.
* config/arm/arm-c.c: Moved to...
* config/arm/arm-c.cc: ...here.
* config/arm/arm-d.c: Moved to...
* config/arm/arm-d.cc: ...here.
* config/arm/arm.c: Moved to...
* config/arm/arm.cc: ...here.
* config/arm/driver-arm.c: Moved to...
* config/arm/driver-arm.cc: ...here.
* config/avr/avr-c.c: Moved to...
* config/avr/avr-c.cc: ...here.
* config/avr/avr-devices.c: Moved to...
* config/avr/avr-devices.cc: ...here.
* config/avr/avr-log.c: Moved to...
* config/avr/avr-log.cc: ...here.
* config/avr/avr.c: Moved to...
* config/avr/avr.cc: ...here.
* config/avr/driver-avr.c: Moved to...
* config/avr/driver-avr.cc: ...here.
* config/avr/gen-avr-mmcu-specs.c: Moved to...
* config/avr/gen-avr-mmcu-specs.cc: ...here.
* config/avr/gen-avr-mmcu-texi.c: Moved to...
* config/avr/gen-avr-mmcu-texi.cc: ...here.
* config/bfin/bfin.c: Moved to...
* config/bfin/bfin.cc: ...here.
* config/bpf/bpf.c: Moved to...
* config/bpf/bpf.cc: ...here.
* config/bpf/coreout.c: Moved to...
* config/bpf/coreout.cc: ...here.
* config/c6x/c6x.c: Moved to...
* config/c6x/c6x.cc: ...here.
* config/cr16/cr16.c: Moved to...
* config/cr16/cr16.cc: ...here.
* config/cris/cris.c: Moved to...
* config/cris/cris.cc: ...here.
* config/csky/csky.c: Moved to...
* config/csky/csky.cc: ...here.
* config/darwin-c.c: Moved to...
* config/darwin-c.cc: ...here.
* config/darwin-d.c: Moved to...
* config/darwin-d.cc: ...here.
* config/darwin-driver.c: Moved to...
* config/darwin-driver.cc: ...here.
* config/darwin-f.c: Moved to...
* config/darwin-f.cc: ...here.
* config/darwin.c: Moved to...
* config/darwin.cc: ...here.
* config/default-c.c: Moved to...
* config/default-c.cc: ...here.
* config/default-d.c: Moved to...
* config/default-d.cc: ...here.
* config/dragonfly-d.c: Moved to...
* config/dragonfly-d.cc: ...here.
* config/epiphany/epiphany.c: Moved to...
* config/epiphany/epiphany.cc: ...here.
* config/epiphany/mode-switch-use.c: Moved to...
* config/epiphany/mode-switch-use.cc: ...here.
* config/epiphany/resolve-sw-modes.c: Moved to...
* config/epiphany/resolve-sw-modes.cc: ...here.
* config/fr30/fr30.c: Moved to...
* config/fr30/fr30.cc: ...here.
* config/freebsd-d.c: Moved to...
* config/freebsd-d.cc: ...here.
* config/frv/frv.c: Moved to...
* config/frv/frv.cc: ...here.
* config/ft32/ft32.c: Moved to...
* config/ft32/ft32.cc: ...here.
* config/gcn/driver-gcn.c: Moved to...
* config/gcn/driver-gcn.cc: ...here.
* config/gcn/gcn-run.c: Moved to...
* config/gcn/gcn-run.cc: ...here.
* config/gcn/gcn-tree.c: Moved to...
* config/gcn/gcn-tree.cc: ...here.
* config/gcn/gcn.c: Moved to...
* config/gcn/gcn.cc: ...here.
* config/gcn/mkoffload.c: Moved to...
* config/gcn/mkoffload.cc: ...here.
* config/glibc-c.c: Moved to...
* config/glibc-c.cc: ...here.
* config/glibc-d.c: Moved to...
* config/glibc-d.cc: ...here.
* config/h8300/h8300.c: Moved to...
* config/h8300/h8300.cc: ...here.
* config/host-darwin.c: Moved to...
* config/host-darwin.cc: ...here.
* config/host-hpux.c: Moved to...
* config/host-hpux.cc: ...here.
* config/host-linux.c: Moved to...
* config/host-linux.cc: ...here.
* config/host-netbsd.c: Moved to...
* config/host-netbsd.cc: ...here.
* config/host-openbsd.c: Moved to...
* config/host-openbsd.cc: ...here.
* config/host-solaris.c: Moved to...
* config/host-solaris.cc: ...here.
* config/i386/djgpp.c: Moved to...
* config/i386/djgpp.cc: ...here.
* config/i386/driver-i386.c: Moved to...
* config/i386/driver-i386.cc: ...here.
* config/i386/driver-mingw32.c: Moved to...
* config/i386/driver-mingw32.cc: ...here.
* config/i386/gnu-property.c: Moved to...
* config/i386/gnu-property.cc: ...here.
* config/i386/host-cygwin.c: Moved to...
* config/i386/host-cygwin.cc: ...here.
* config/i386/host-i386-darwin.c: Moved to...
* config/i386/host-i386-darwin.cc: ...here.
* config/i386/host-mingw32.c: Moved to...
* config/i386/host-mingw32.cc: ...here.
* config/i386/i386-builtins.c: Moved to...
* config/i386/i386-builtins.cc: ...here.
* config/i386/i386-c.c: Moved to...
* config/i386/i386-c.cc: ...here.
* config/i386/i386-d.c: Moved to...
* config/i386/i386-d.cc: ...here.
* config/i386/i386-expand.c: Moved to...
* config/i386/i386-expand.cc: ...here.
* config/i386/i386-features.c: Moved to...
* config/i386/i386-features.cc: ...here.
* config/i386/i386-options.c: Moved to...
* config/i386/i386-options.cc: ...here.
* config/i386/i386.c: Moved to...
* config/i386/i386.cc: ...here.
* config/i386/intelmic-mkoffload.c: Moved to...
* config/i386/intelmic-mkoffload.cc: ...here.
* config/i386/msformat-c.c: Moved to...
* config/i386/msformat-c.cc: ...here.
* config/i386/winnt-cxx.c: Moved to...
* config/i386/winnt-cxx.cc: ...here.
* config/i386/winnt-d.c: Moved to...
* config/i386/winnt-d.cc: ...here.
* config/i386/winnt-stubs.c: Moved to...
* config/i386/winnt-stubs.cc: ...here.
* config/i386/winnt.c: Moved to...
* config/i386/winnt.cc: ...here.
* config/i386/x86-tune-sched-atom.c: Moved to...
* config/i386/x86-tune-sched-atom.cc: ...here.
* config/i386/x86-tune-sched-bd.c: Moved to...
* config/i386/x86-tune-sched-bd.cc: ...here.
* config/i386/x86-tune-sched-core.c: Moved to...
* config/i386/x86-tune-sched-core.cc: ...here.
* config/i386/x86-tune-sched.c: Moved to...
* config/i386/x86-tune-sched.cc: ...here.
* config/ia64/ia64-c.c: Moved to...
* config/ia64/ia64-c.cc: ...here.
* config/ia64/ia64.c: Moved to...
* config/ia64/ia64.cc: ...here.
* config/iq2000/iq2000.c: Moved to...
* config/iq2000/iq2000.cc: ...here.
* config/linux.c: Moved to...
* config/linux.cc: ...here.
* config/lm32/lm32.c: Moved to...
* config/lm32/lm32.cc: ...here.
* config/m32c/m32c-pragma.c: Moved to...
* config/m32c/m32c-pragma.cc: ...here.
* config/m32c/m32c.c: Moved to...
* config/m32c/m32c.cc: ...here.
* config/m32r/m32r.c: Moved to...
* config/m32r/m32r.cc: ...here.
* config/m68k/m68k.c: Moved to...
* config/m68k/m68k.cc: ...here.
* config/mcore/mcore.c: Moved to...
* config/mcore/mcore.cc: ...here.
* config/microblaze/microblaze-c.c: Moved to...
* config/microblaze/microblaze-c.cc: ...here.
* config/microblaze/microblaze.c: Moved to...
* config/microblaze/microblaze.cc: ...here.
* config/mips/driver-native.c: Moved to...
* config/mips/driver-native.cc: ...here.
* config/mips/frame-header-opt.c: Moved to...
* config/mips/frame-header-opt.cc: ...here.
* config/mips/mips-d.c: Moved to...
* config/mips/mips-d.cc: ...here.
* config/mips/mips.c: Moved to...
* config/mips/mips.cc: ...here.
* config/mmix/mmix.c: Moved to...
* config/mmix/mmix.cc: ...here.
* config/mn10300/mn10300.c: Moved to...
* config/mn10300/mn10300.cc: ...here.
* config/moxie/moxie.c: Moved to...
* config/moxie/moxie.cc: ...here.
* config/msp430/driver-msp430.c: Moved to...
* config/msp430/driver-msp430.cc: ...here.
* config/msp430/msp430-c.c: Moved to...
* config/msp430/msp430-c.cc: ...here.
* config/msp430/msp430-devices.c: Moved to...
* config/msp430/msp430-devices.cc: ...here.
* config/msp430/msp430.c: Moved to...
* config/msp430/msp430.cc: ...here.
* config/nds32/nds32-cost.c: Moved to...
* config/nds32/nds32-cost.cc: ...here.
* config/nds32/nds32-fp-as-gp.c: Moved to...
* config/nds32/nds32-fp-as-gp.cc: ...here.
* config/nds32/nds32-intrinsic.c: Moved to...
* config/nds32/nds32-intrinsic.cc: ...here.
* config/nds32/nds32-isr.c: Moved to...
* config/nds32/nds32-isr.cc: ...here.
* config/nds32/nds32-md-auxiliary.c: Moved to...
* config/nds32/nds32-md-auxiliary.cc: ...here.
* config/nds32/nds32-memory-manipulation.c: Moved to...
* config/nds32/nds32-memory-manipulation.cc: ...here.
* config/nds32/nds32-pipelines-auxiliary.c: Moved to...
* config/nds32/nds32-pipelines-auxiliary.cc: ...here.
* config/nds32/nds32-predicates.c: Moved to...
* config/nds32/nds32-predicates.cc: ...here.
* config/nds32/nds32-relax-opt.c: Moved to...
* config/nds32/nds32-relax-opt.cc: ...here.
* config/nds32/nds32-utils.c: Moved to...
* config/nds32/nds32-utils.cc: ...here.
* config/nds32/nds32.c: Moved to...
* config/nds32/nds32.cc: ...here.
* config/netbsd-d.c: Moved to...
* config/netbsd-d.cc: ...here.
* config/netbsd.c: Moved to...
* config/netbsd.cc: ...here.
* config/nios2/nios2.c: Moved to...
* config/nios2/nios2.cc: ...here.
* config/nvptx/mkoffload.c: Moved to...
* config/nvptx/mkoffload.cc: ...here.
* config/nvptx/nvptx-c.c: Moved to...
* config/nvptx/nvptx-c.cc: ...here.
* config/nvptx/nvptx.c: Moved to...
* config/nvptx/nvptx.cc: ...here.
* config/openbsd-d.c: Moved to...
* config/openbsd-d.cc: ...here.
* config/or1k/or1k.c: Moved to...
* config/or1k/or1k.cc: ...here.
* config/pa/pa-d.c: Moved to...
* config/pa/pa-d.cc: ...here.
* config/pa/pa.c: Moved to...
* config/pa/pa.cc: ...here.
* config/pdp11/pdp11.c: Moved to...
* config/pdp11/pdp11.cc: ...here.
* config/pru/pru-passes.c: Moved to...
* config/pru/pru-passes.cc: ...here.
* config/pru/pru-pragma.c: Moved to...
* config/pru/pru-pragma.cc: ...here.
* config/pru/pru.c: Moved to...
* config/pru/pru.cc: ...here.
* config/riscv/riscv-builtins.c: Moved to...
* config/riscv/riscv-builtins.cc: ...here.
* config/riscv/riscv-c.c: Moved to...
* config/riscv/riscv-c.cc: ...here.
* config/riscv/riscv-d.c: Moved to...
* config/riscv/riscv-d.cc: ...here.
* config/riscv/riscv-shorten-memrefs.c: Moved to...
* config/riscv/riscv-shorten-memrefs.cc: ...here.
* config/riscv/riscv-sr.c: Moved to...
* config/riscv/riscv-sr.cc: ...here.
* config/riscv/riscv.c: Moved to...
* config/riscv/riscv.cc: ...here.
* config/rl78/rl78-c.c: Moved to...
* config/rl78/rl78-c.cc: ...here.
* config/rl78/rl78.c: Moved to...
* config/rl78/rl78.cc: ...here.
* config/rs6000/driver-rs6000.c: Moved to...
* config/rs6000/driver-rs6000.cc: ...here.
* config/rs6000/host-darwin.c: Moved to...
* config/rs6000/host-darwin.cc: ...here.
* config/rs6000/host-ppc64-darwin.c: Moved to...
* config/rs6000/host-ppc64-darwin.cc: ...here.
* config/rs6000/rbtree.c: Moved to...
* config/rs6000/rbtree.cc: ...here.
* config/rs6000/rs6000-c.c: Moved to...
* config/rs6000/rs6000-c.cc: ...here.
* config/rs6000/rs6000-call.c: Moved to...
* config/rs6000/rs6000-call.cc: ...here.
* config/rs6000/rs6000-d.c: Moved to...
* config/rs6000/rs6000-d.cc: ...here.
* config/rs6000/rs6000-gen-builtins.c: Moved to...
* config/rs6000/rs6000-gen-builtins.cc: ...here.
* config/rs6000/rs6000-linux.c: Moved to...
* config/rs6000/rs6000-linux.cc: ...here.
* config/rs6000/rs6000-logue.c: Moved to...
* config/rs6000/rs6000-logue.cc: ...here.
* config/rs6000/rs6000-p8swap.c: Moved to...
* config/rs6000/rs6000-p8swap.cc: ...here.
* config/rs6000/rs6000-pcrel-opt.c: Moved to...
* config/rs6000/rs6000-pcrel-opt.cc: ...here.
* config/rs6000/rs6000-string.c: Moved to...
* config/rs6000/rs6000-string.cc: ...here.
* config/rs6000/rs6000.c: Moved to...
* config/rs6000/rs6000.cc: ...here.
* config/rx/rx.c: Moved to...
* config/rx/rx.cc: ...here.
* config/s390/driver-native.c: Moved to...
* config/s390/driver-native.cc: ...here.
* config/s390/s390-c.c: Moved to...
* config/s390/s390-c.cc: ...here.
* config/s390/s390-d.c: Moved to...
* config/s390/s390-d.cc: ...here.
* config/s390/s390.c: Moved to...
* config/s390/s390.cc: ...here.
* config/sh/divtab-sh4-300.c: Moved to...
* config/sh/divtab-sh4-300.cc: ...here.
* config/sh/divtab-sh4.c: Moved to...
* config/sh/divtab-sh4.cc: ...here.
* config/sh/divtab.c: Moved to...
* config/sh/divtab.cc: ...here.
* config/sh/sh-c.c: Moved to...
* config/sh/sh-c.cc: ...here.
* config/sh/sh.c: Moved to...
* config/sh/sh.cc: ...here.
* config/sol2-c.c: Moved to...
* config/sol2-c.cc: ...here.
* config/sol2-cxx.c: Moved to...
* config/sol2-cxx.cc: ...here.
* config/sol2-d.c: Moved to...
* config/sol2-d.cc: ...here.
* config/sol2-stubs.c: Moved to...
* config/sol2-stubs.cc: ...here.
* config/sol2.c: Moved to...
* config/sol2.cc: ...here.
* config/sparc/driver-sparc.c: Moved to...
* config/sparc/driver-sparc.cc: ...here.
* config/sparc/sparc-c.c: Moved to...
* config/sparc/sparc-c.cc: ...here.
* config/sparc/sparc-d.c: Moved to...
* config/sparc/sparc-d.cc: ...here.
* config/sparc/sparc.c: Moved to...
* config/sparc/sparc.cc: ...here.
* config/stormy16/stormy16.c: Moved to...
* config/stormy16/stormy16.cc: ...here.
* config/tilegx/mul-tables.c: Moved to...
* config/tilegx/mul-tables.cc: ...here.
* config/tilegx/tilegx-c.c: Moved to...
* config/tilegx/tilegx-c.cc: ...here.
* config/tilegx/tilegx.c: Moved to...
* config/tilegx/tilegx.cc: ...here.
* config/tilepro/mul-tables.c: Moved to...
* config/tilepro/mul-tables.cc: ...here.
* config/tilepro/tilepro-c.c: Moved to...
* config/tilepro/tilepro-c.cc: ...here.
* config/tilepro/tilepro.c: Moved to...
* config/tilepro/tilepro.cc: ...here.
* config/v850/v850-c.c: Moved to...
* config/v850/v850-c.cc: ...here.
* config/v850/v850.c: Moved to...
* config/v850/v850.cc: ...here.
* config/vax/vax.c: Moved to...
* config/vax/vax.cc: ...here.
* config/visium/visium.c: Moved to...
* config/visium/visium.cc: ...here.
* config/vms/vms-c.c: Moved to...
* config/vms/vms-c.cc: ...here.
* config/vms/vms-f.c: Moved to...
* config/vms/vms-f.cc: ...here.
* config/vms/vms.c: Moved to...
* config/vms/vms.cc: ...here.
* config/vxworks-c.c: Moved to...
* config/vxworks-c.cc: ...here.
* config/vxworks.c: Moved to...
* config/vxworks.cc: ...here.
* config/winnt-c.c: Moved to...
* config/winnt-c.cc: ...here.
* config/xtensa/xtensa.c: Moved to...
* config/xtensa/xtensa.cc: ...here.
* context.c: Moved to...
* context.cc: ...here.
* convert.c: Moved to...
* convert.cc: ...here.
* coverage.c: Moved to...
* coverage.cc: ...here.
* cppbuiltin.c: Moved to...
* cppbuiltin.cc: ...here.
* cppdefault.c: Moved to...
* cppdefault.cc: ...here.
* cprop.c: Moved to...
* cprop.cc: ...here.
* cse.c: Moved to...
* cse.cc: ...here.
* cselib.c: Moved to...
* cselib.cc: ...here.
* ctfc.c: Moved to...
* ctfc.cc: ...here.
* ctfout.c: Moved to...
* ctfout.cc: ...here.
* data-streamer-in.c: Moved to...
* data-streamer-in.cc: ...here.
* data-streamer-out.c: Moved to...
* data-streamer-out.cc: ...here.
* data-streamer.c: Moved to...
* data-streamer.cc: ...here.
* dbgcnt.c: Moved to...
* dbgcnt.cc: ...here.
* dbxout.c: Moved to...
* dbxout.cc: ...here.
* dce.c: Moved to...
* dce.cc: ...here.
* ddg.c: Moved to...
* ddg.cc: ...here.
* debug.c: Moved to...
* debug.cc: ...here.
* df-core.c: Moved to...
* df-core.cc: ...here.
* df-problems.c: Moved to...
* df-problems.cc: ...here.
* df-scan.c: Moved to...
* df-scan.cc: ...here.
* dfp.c: Moved to...
* dfp.cc: ...here.
* diagnostic-color.c: Moved to...
* diagnostic-color.cc: ...here.
* diagnostic-show-locus.c: Moved to...
* diagnostic-show-locus.cc: ...here.
* diagnostic-spec.c: Moved to...
* diagnostic-spec.cc: ...here.
* diagnostic.c: Moved to...
* diagnostic.cc: ...here.
* dojump.c: Moved to...
* dojump.cc: ...here.
* dominance.c: Moved to...
* dominance.cc: ...here.
* domwalk.c: Moved to...
* domwalk.cc: ...here.
* double-int.c: Moved to...
* double-int.cc: ...here.
* dse.c: Moved to...
* dse.cc: ...here.
* dumpfile.c: Moved to...
* dumpfile.cc: ...here.
* dwarf2asm.c: Moved to...
* dwarf2asm.cc: ...here.
* dwarf2cfi.c: Moved to...
* dwarf2cfi.cc: ...here.
* dwarf2ctf.c: Moved to...
* dwarf2ctf.cc: ...here.
* dwarf2out.c: Moved to...
* dwarf2out.cc: ...here.
* early-remat.c: Moved to...
* early-remat.cc: ...here.
* edit-context.c: Moved to...
* edit-context.cc: ...here.
* emit-rtl.c: Moved to...
* emit-rtl.cc: ...here.
* errors.c: Moved to...
* errors.cc: ...here.
* et-forest.c: Moved to...
* et-forest.cc: ...here.
* except.c: Moved to...
* except.cc: ...here.
* explow.c: Moved to...
* explow.cc: ...here.
* expmed.c: Moved to...
* expmed.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* fibonacci_heap.c: Moved to...
* fibonacci_heap.cc: ...here.
* file-find.c: Moved to...
* file-find.cc: ...here.
* file-prefix-map.c: Moved to...
* file-prefix-map.cc: ...here.
* final.c: Moved to...
* final.cc: ...here.
* fixed-value.c: Moved to...
* fixed-value.cc: ...here.
* fold-const-call.c: Moved to...
* fold-const-call.cc: ...here.
* fold-const.c: Moved to...
* fold-const.cc: ...here.
* fp-test.c: Moved to...
* fp-test.cc: ...here.
* function-tests.c: Moved to...
* function-tests.cc: ...here.
* function.c: Moved to...
* function.cc: ...here.
* fwprop.c: Moved to...
* fwprop.cc: ...here.
* gcc-ar.c: Moved to...
* gcc-ar.cc: ...here.
* gcc-main.c: Moved to...
* gcc-main.cc: ...here.
* gcc-rich-location.c: Moved to...
* gcc-rich-location.cc: ...here.
* gcc.c: Moved to...
* gcc.cc: ...here.
* gcov-dump.c: Moved to...
* gcov-dump.cc: ...here.
* gcov-io.c: Moved to...
* gcov-io.cc: ...here.
* gcov-tool.c: Moved to...
* gcov-tool.cc: ...here.
* gcov.c: Moved to...
* gcov.cc: ...here.
* gcse-common.c: Moved to...
* gcse-common.cc: ...here.
* gcse.c: Moved to...
* gcse.cc: ...here.
* genattr-common.c: Moved to...
* genattr-common.cc: ...here.
* genattr.c: Moved to...
* genattr.cc: ...here.
* genattrtab.c: Moved to...
* genattrtab.cc: ...here.
* genautomata.c: Moved to...
* genautomata.cc: ...here.
* gencfn-macros.c: Moved to...
* gencfn-macros.cc: ...here.
* gencheck.c: Moved to...
* gencheck.cc: ...here.
* genchecksum.c: Moved to...
* genchecksum.cc: ...here.
* gencodes.c: Moved to...
* gencodes.cc: ...here.
* genconditions.c: Moved to...
* genconditions.cc: ...here.
* genconfig.c: Moved to...
* genconfig.cc: ...here.
* genconstants.c: Moved to...
* genconstants.cc: ...here.
* genemit.c: Moved to...
* genemit.cc: ...here.
* genenums.c: Moved to...
* genenums.cc: ...here.
* generic-match-head.c: Moved to...
* generic-match-head.cc: ...here.
* genextract.c: Moved to...
* genextract.cc: ...here.
* genflags.c: Moved to...
* genflags.cc: ...here.
* gengenrtl.c: Moved to...
* gengenrtl.cc: ...here.
* gengtype-parse.c: Moved to...
* gengtype-parse.cc: ...here.
* gengtype-state.c: Moved to...
* gengtype-state.cc: ...here.
* gengtype.c: Moved to...
* gengtype.cc: ...here.
* genhooks.c: Moved to...
* genhooks.cc: ...here.
* genmatch.c: Moved to...
* genmatch.cc: ...here.
* genmddeps.c: Moved to...
* genmddeps.cc: ...here.
* genmddump.c: Moved to...
* genmddump.cc: ...here.
* genmodes.c: Moved to...
* genmodes.cc: ...here.
* genopinit.c: Moved to...
* genopinit.cc: ...here.
* genoutput.c: Moved to...
* genoutput.cc: ...here.
* genpeep.c: Moved to...
* genpeep.cc: ...here.
* genpreds.c: Moved to...
* genpreds.cc: ...here.
* genrecog.c: Moved to...
* genrecog.cc: ...here.
* gensupport.c: Moved to...
* gensupport.cc: ...here.
* gentarget-def.c: Moved to...
* gentarget-def.cc: ...here.
* genversion.c: Moved to...
* genversion.cc: ...here.
* ggc-common.c: Moved to...
* ggc-common.cc: ...here.
* ggc-none.c: Moved to...
* ggc-none.cc: ...here.
* ggc-page.c: Moved to...
* ggc-page.cc: ...here.
* ggc-tests.c: Moved to...
* ggc-tests.cc: ...here.
* gimple-builder.c: Moved to...
* gimple-builder.cc: ...here.
* gimple-expr.c: Moved to...
* gimple-expr.cc: ...here.
* gimple-fold.c: Moved to...
* gimple-fold.cc: ...here.
* gimple-iterator.c: Moved to...
* gimple-iterator.cc: ...here.
* gimple-laddress.c: Moved to...
* gimple-laddress.cc: ...here.
* gimple-loop-jam.c: Moved to...
* gimple-loop-jam.cc: ...here.
* gimple-low.c: Moved to...
* gimple-low.cc: ...here.
* gimple-match-head.c: Moved to...
* gimple-match-head.cc: ...here.
* gimple-pretty-print.c: Moved to...
* gimple-pretty-print.cc: ...here.
* gimple-ssa-backprop.c: Moved to...
* gimple-ssa-backprop.cc: ...here.
* gimple-ssa-evrp-analyze.c: Moved to...
* gimple-ssa-evrp-analyze.cc: ...here.
* gimple-ssa-evrp.c: Moved to...
* gimple-ssa-evrp.cc: ...here.
* gimple-ssa-isolate-paths.c: Moved to...
* gimple-ssa-isolate-paths.cc: ...here.
* gimple-ssa-nonnull-compare.c: Moved to...
* gimple-ssa-nonnull-compare.cc: ...here.
* gimple-ssa-split-paths.c: Moved to...
* gimple-ssa-split-paths.cc: ...here.
* gimple-ssa-sprintf.c: Moved to...
* gimple-ssa-sprintf.cc: ...here.
* gimple-ssa-store-merging.c: Moved to...
* gimple-ssa-store-merging.cc: ...here.
* gimple-ssa-strength-reduction.c: Moved to...
* gimple-ssa-strength-reduction.cc: ...here.
* gimple-ssa-warn-alloca.c: Moved to...
* gimple-ssa-warn-alloca.cc: ...here.
* gimple-ssa-warn-restrict.c: Moved to...
* gimple-ssa-warn-restrict.cc: ...here.
* gimple-streamer-in.c: Moved to...
* gimple-streamer-in.cc: ...here.
* gimple-streamer-out.c: Moved to...
* gimple-streamer-out.cc: ...here.
* gimple-walk.c: Moved to...
* gimple-walk.cc: ...here.
* gimple-warn-recursion.c: Moved to...
* gimple-warn-recursion.cc: ...here.
* gimple.c: Moved to...
* gimple.cc: ...here.
* gimplify-me.c: Moved to...
* gimplify-me.cc: ...here.
* gimplify.c: Moved to...
* gimplify.cc: ...here.
* godump.c: Moved to...
* godump.cc: ...here.
* graph.c: Moved to...
* graph.cc: ...here.
* graphds.c: Moved to...
* graphds.cc: ...here.
* graphite-dependences.c: Moved to...
* graphite-dependences.cc: ...here.
* graphite-isl-ast-to-gimple.c: Moved to...
* graphite-isl-ast-to-gimple.cc: ...here.
* graphite-optimize-isl.c: Moved to...
* graphite-optimize-isl.cc: ...here.
* graphite-poly.c: Moved to...
* graphite-poly.cc: ...here.
* graphite-scop-detection.c: Moved to...
* graphite-scop-detection.cc: ...here.
* graphite-sese-to-poly.c: Moved to...
* graphite-sese-to-poly.cc: ...here.
* graphite.c: Moved to...
* graphite.cc: ...here.
* haifa-sched.c: Moved to...
* haifa-sched.cc: ...here.
* hash-map-tests.c: Moved to...
* hash-map-tests.cc: ...here.
* hash-set-tests.c: Moved to...
* hash-set-tests.cc: ...here.
* hash-table.c: Moved to...
* hash-table.cc: ...here.
* hooks.c: Moved to...
* hooks.cc: ...here.
* host-default.c: Moved to...
* host-default.cc: ...here.
* hw-doloop.c: Moved to...
* hw-doloop.cc: ...here.
* hwint.c: Moved to...
* hwint.cc: ...here.
* ifcvt.c: Moved to...
* ifcvt.cc: ...here.
* inchash.c: Moved to...
* inchash.cc: ...here.
* incpath.c: Moved to...
* incpath.cc: ...here.
* init-regs.c: Moved to...
* init-regs.cc: ...here.
* input.c: Moved to...
* input.cc: ...here.
* internal-fn.c: Moved to...
* internal-fn.cc: ...here.
* intl.c: Moved to...
* intl.cc: ...here.
* ipa-comdats.c: Moved to...
* ipa-comdats.cc: ...here.
* ipa-cp.c: Moved to...
* ipa-cp.cc: ...here.
* ipa-devirt.c: Moved to...
* ipa-devirt.cc: ...here.
* ipa-fnsummary.c: Moved to...
* ipa-fnsummary.cc: ...here.
* ipa-icf-gimple.c: Moved to...
* ipa-icf-gimple.cc: ...here.
* ipa-icf.c: Moved to...
* ipa-icf.cc: ...here.
* ipa-inline-analysis.c: Moved to...
* ipa-inline-analysis.cc: ...here.
* ipa-inline-transform.c: Moved to...
* ipa-inline-transform.cc: ...here.
* ipa-inline.c: Moved to...
* ipa-inline.cc: ...here.
* ipa-modref-tree.c: Moved to...
* ipa-modref-tree.cc: ...here.
* ipa-modref.c: Moved to...
* ipa-modref.cc: ...here.
* ipa-param-manipulation.c: Moved to...
* ipa-param-manipulation.cc: ...here.
* ipa-polymorphic-call.c: Moved to...
* ipa-polymorphic-call.cc: ...here.
* ipa-predicate.c: Moved to...
* ipa-predicate.cc: ...here.
* ipa-profile.c: Moved to...
* ipa-profile.cc: ...here.
* ipa-prop.c: Moved to...
* ipa-prop.cc: ...here.
* ipa-pure-const.c: Moved to...
* ipa-pure-const.cc: ...here.
* ipa-ref.c: Moved to...
* ipa-ref.cc: ...here.
* ipa-reference.c: Moved to...
* ipa-reference.cc: ...here.
* ipa-split.c: Moved to...
* ipa-split.cc: ...here.
* ipa-sra.c: Moved to...
* ipa-sra.cc: ...here.
* ipa-utils.c: Moved to...
* ipa-utils.cc: ...here.
* ipa-visibility.c: Moved to...
* ipa-visibility.cc: ...here.
* ipa.c: Moved to...
* ipa.cc: ...here.
* ira-build.c: Moved to...
* ira-build.cc: ...here.
* ira-color.c: Moved to...
* ira-color.cc: ...here.
* ira-conflicts.c: Moved to...
* ira-conflicts.cc: ...here.
* ira-costs.c: Moved to...
* ira-costs.cc: ...here.
* ira-emit.c: Moved to...
* ira-emit.cc: ...here.
* ira-lives.c: Moved to...
* ira-lives.cc: ...here.
* ira.c: Moved to...
* ira.cc: ...here.
* jump.c: Moved to...
* jump.cc: ...here.
* langhooks.c: Moved to...
* langhooks.cc: ...here.
* lcm.c: Moved to...
* lcm.cc: ...here.
* lists.c: Moved to...
* lists.cc: ...here.
* loop-doloop.c: Moved to...
* loop-doloop.cc: ...here.
* loop-init.c: Moved to...
* loop-init.cc: ...here.
* loop-invariant.c: Moved to...
* loop-invariant.cc: ...here.
* loop-iv.c: Moved to...
* loop-iv.cc: ...here.
* loop-unroll.c: Moved to...
* loop-unroll.cc: ...here.
* lower-subreg.c: Moved to...
* lower-subreg.cc: ...here.
* lra-assigns.c: Moved to...
* lra-assigns.cc: ...here.
* lra-coalesce.c: Moved to...
* lra-coalesce.cc: ...here.
* lra-constraints.c: Moved to...
* lra-constraints.cc: ...here.
* lra-eliminations.c: Moved to...
* lra-eliminations.cc: ...here.
* lra-lives.c: Moved to...
* lra-lives.cc: ...here.
* lra-remat.c: Moved to...
* lra-remat.cc: ...here.
* lra-spills.c: Moved to...
* lra-spills.cc: ...here.
* lra.c: Moved to...
* lra.cc: ...here.
* lto-cgraph.c: Moved to...
* lto-cgraph.cc: ...here.
* lto-compress.c: Moved to...
* lto-compress.cc: ...here.
* lto-opts.c: Moved to...
* lto-opts.cc: ...here.
* lto-section-in.c: Moved to...
* lto-section-in.cc: ...here.
* lto-section-out.c: Moved to...
* lto-section-out.cc: ...here.
* lto-streamer-in.c: Moved to...
* lto-streamer-in.cc: ...here.
* lto-streamer-out.c: Moved to...
* lto-streamer-out.cc: ...here.
* lto-streamer.c: Moved to...
* lto-streamer.cc: ...here.
* lto-wrapper.c: Moved to...
* lto-wrapper.cc: ...here.
* main.c: Moved to...
* main.cc: ...here.
* mcf.c: Moved to...
* mcf.cc: ...here.
* mode-switching.c: Moved to...
* mode-switching.cc: ...here.
* modulo-sched.c: Moved to...
* modulo-sched.cc: ...here.
* multiple_target.c: Moved to...
* multiple_target.cc: ...here.
* omp-expand.c: Moved to...
* omp-expand.cc: ...here.
* omp-general.c: Moved to...
* omp-general.cc: ...here.
* omp-low.c: Moved to...
* omp-low.cc: ...here.
* omp-offload.c: Moved to...
* omp-offload.cc: ...here.
* omp-simd-clone.c: Moved to...
* omp-simd-clone.cc: ...here.
* opt-suggestions.c: Moved to...
* opt-suggestions.cc: ...here.
* optabs-libfuncs.c: Moved to...
* optabs-libfuncs.cc: ...here.
* optabs-query.c: Moved to...
* optabs-query.cc: ...here.
* optabs-tree.c: Moved to...
* optabs-tree.cc: ...here.
* optabs.c: Moved to...
* optabs.cc: ...here.
* opts-common.c: Moved to...
* opts-common.cc: ...here.
* opts-global.c: Moved to...
* opts-global.cc: ...here.
* opts.c: Moved to...
* opts.cc: ...here.
* passes.c: Moved to...
* passes.cc: ...here.
* plugin.c: Moved to...
* plugin.cc: ...here.
* postreload-gcse.c: Moved to...
* postreload-gcse.cc: ...here.
* postreload.c: Moved to...
* postreload.cc: ...here.
* predict.c: Moved to...
* predict.cc: ...here.
* prefix.c: Moved to...
* prefix.cc: ...here.
* pretty-print.c: Moved to...
* pretty-print.cc: ...here.
* print-rtl-function.c: Moved to...
* print-rtl-function.cc: ...here.
* print-rtl.c: Moved to...
* print-rtl.cc: ...here.
* print-tree.c: Moved to...
* print-tree.cc: ...here.
* profile-count.c: Moved to...
* profile-count.cc: ...here.
* profile.c: Moved to...
* profile.cc: ...here.
* read-md.c: Moved to...
* read-md.cc: ...here.
* read-rtl-function.c: Moved to...
* read-rtl-function.cc: ...here.
* read-rtl.c: Moved to...
* read-rtl.cc: ...here.
* real.c: Moved to...
* real.cc: ...here.
* realmpfr.c: Moved to...
* realmpfr.cc: ...here.
* recog.c: Moved to...
* recog.cc: ...here.
* ree.c: Moved to...
* ree.cc: ...here.
* reg-stack.c: Moved to...
* reg-stack.cc: ...here.
* regcprop.c: Moved to...
* regcprop.cc: ...here.
* reginfo.c: Moved to...
* reginfo.cc: ...here.
* regrename.c: Moved to...
* regrename.cc: ...here.
* regstat.c: Moved to...
* regstat.cc: ...here.
* reload.c: Moved to...
* reload.cc: ...here.
* reload1.c: Moved to...
* reload1.cc: ...here.
* reorg.c: Moved to...
* reorg.cc: ...here.
* resource.c: Moved to...
* resource.cc: ...here.
* rtl-error.c: Moved to...
* rtl-error.cc: ...here.
* rtl-tests.c: Moved to...
* rtl-tests.cc: ...here.
* rtl.c: Moved to...
* rtl.cc: ...here.
* rtlanal.c: Moved to...
* rtlanal.cc: ...here.
* rtlhash.c: Moved to...
* rtlhash.cc: ...here.
* rtlhooks.c: Moved to...
* rtlhooks.cc: ...here.
* rtx-vector-builder.c: Moved to...
* rtx-vector-builder.cc: ...here.
* run-rtl-passes.c: Moved to...
* run-rtl-passes.cc: ...here.
* sancov.c: Moved to...
* sancov.cc: ...here.
* sanopt.c: Moved to...
* sanopt.cc: ...here.
* sbitmap.c: Moved to...
* sbitmap.cc: ...here.
* sched-deps.c: Moved to...
* sched-deps.cc: ...here.
* sched-ebb.c: Moved to...
* sched-ebb.cc: ...here.
* sched-rgn.c: Moved to...
* sched-rgn.cc: ...here.
* sel-sched-dump.c: Moved to...
* sel-sched-dump.cc: ...here.
* sel-sched-ir.c: Moved to...
* sel-sched-ir.cc: ...here.
* sel-sched.c: Moved to...
* sel-sched.cc: ...here.
* selftest-diagnostic.c: Moved to...
* selftest-diagnostic.cc: ...here.
* selftest-rtl.c: Moved to...
* selftest-rtl.cc: ...here.
* selftest-run-tests.c: Moved to...
* selftest-run-tests.cc: ...here.
* selftest.c: Moved to...
* selftest.cc: ...here.
* sese.c: Moved to...
* sese.cc: ...here.
* shrink-wrap.c: Moved to...
* shrink-wrap.cc: ...here.
* simplify-rtx.c: Moved to...
* simplify-rtx.cc: ...here.
* sparseset.c: Moved to...
* sparseset.cc: ...here.
* spellcheck-tree.c: Moved to...
* spellcheck-tree.cc: ...here.
* spellcheck.c: Moved to...
* spellcheck.cc: ...here.
* sreal.c: Moved to...
* sreal.cc: ...here.
* stack-ptr-mod.c: Moved to...
* stack-ptr-mod.cc: ...here.
* statistics.c: Moved to...
* statistics.cc: ...here.
* stmt.c: Moved to...
* stmt.cc: ...here.
* stor-layout.c: Moved to...
* stor-layout.cc: ...here.
* store-motion.c: Moved to...
* store-motion.cc: ...here.
* streamer-hooks.c: Moved to...
* streamer-hooks.cc: ...here.
* stringpool.c: Moved to...
* stringpool.cc: ...here.
* substring-locations.c: Moved to...
* substring-locations.cc: ...here.
* symtab.c: Moved to...
* symtab.cc: ...here.
* target-globals.c: Moved to...
* target-globals.cc: ...here.
* targhooks.c: Moved to...
* targhooks.cc: ...here.
* timevar.c: Moved to...
* timevar.cc: ...here.
* toplev.c: Moved to...
* toplev.cc: ...here.
* tracer.c: Moved to...
* tracer.cc: ...here.
* trans-mem.c: Moved to...
* trans-mem.cc: ...here.
* tree-affine.c: Moved to...
* tree-affine.cc: ...here.
* tree-call-cdce.c: Moved to...
* tree-call-cdce.cc: ...here.
* tree-cfg.c: Moved to...
* tree-cfg.cc: ...here.
* tree-cfgcleanup.c: Moved to...
* tree-cfgcleanup.cc: ...here.
* tree-chrec.c: Moved to...
* tree-chrec.cc: ...here.
* tree-complex.c: Moved to...
* tree-complex.cc: ...here.
* tree-data-ref.c: Moved to...
* tree-data-ref.cc: ...here.
* tree-dfa.c: Moved to...
* tree-dfa.cc: ...here.
* tree-diagnostic.c: Moved to...
* tree-diagnostic.cc: ...here.
* tree-dump.c: Moved to...
* tree-dump.cc: ...here.
* tree-eh.c: Moved to...
* tree-eh.cc: ...here.
* tree-emutls.c: Moved to...
* tree-emutls.cc: ...here.
* tree-if-conv.c: Moved to...
* tree-if-conv.cc: ...here.
* tree-inline.c: Moved to...
* tree-inline.cc: ...here.
* tree-into-ssa.c: Moved to...
* tree-into-ssa.cc: ...here.
* tree-iterator.c: Moved to...
* tree-iterator.cc: ...here.
* tree-loop-distribution.c: Moved to...
* tree-loop-distribution.cc: ...here.
* tree-nested.c: Moved to...
* tree-nested.cc: ...here.
* tree-nrv.c: Moved to...
* tree-nrv.cc: ...here.
* tree-object-size.c: Moved to...
* tree-object-size.cc: ...here.
* tree-outof-ssa.c: Moved to...
* tree-outof-ssa.cc: ...here.
* tree-parloops.c: Moved to...
* tree-parloops.cc: ...here.
* tree-phinodes.c: Moved to...
* tree-phinodes.cc: ...here.
* tree-predcom.c: Moved to...
* tree-predcom.cc: ...here.
* tree-pretty-print.c: Moved to...
* tree-pretty-print.cc: ...here.
* tree-profile.c: Moved to...
* tree-profile.cc: ...here.
* tree-scalar-evolution.c: Moved to...
* tree-scalar-evolution.cc: ...here.
* tree-sra.c: Moved to...
* tree-sra.cc: ...here.
* tree-ssa-address.c: Moved to...
* tree-ssa-address.cc: ...here.
* tree-ssa-alias.c: Moved to...
* tree-ssa-alias.cc: ...here.
* tree-ssa-ccp.c: Moved to...
* tree-ssa-ccp.cc: ...here.
* tree-ssa-coalesce.c: Moved to...
* tree-ssa-coalesce.cc: ...here.
* tree-ssa-copy.c: Moved to...
* tree-ssa-copy.cc: ...here.
* tree-ssa-dce.c: Moved to...
* tree-ssa-dce.cc: ...here.
* tree-ssa-dom.c: Moved to...
* tree-ssa-dom.cc: ...here.
* tree-ssa-dse.c: Moved to...
* tree-ssa-dse.cc: ...here.
* tree-ssa-forwprop.c: Moved to...
* tree-ssa-forwprop.cc: ...here.
* tree-ssa-ifcombine.c: Moved to...
* tree-ssa-ifcombine.cc: ...here.
* tree-ssa-live.c: Moved to...
* tree-ssa-live.cc: ...here.
* tree-ssa-loop-ch.c: Moved to...
* tree-ssa-loop-ch.cc: ...here.
* tree-ssa-loop-im.c: Moved to...
* tree-ssa-loop-im.cc: ...here.
* tree-ssa-loop-ivcanon.c: Moved to...
* tree-ssa-loop-ivcanon.cc: ...here.
* tree-ssa-loop-ivopts.c: Moved to...
* tree-ssa-loop-ivopts.cc: ...here.
* tree-ssa-loop-manip.c: Moved to...
* tree-ssa-loop-manip.cc: ...here.
* tree-ssa-loop-niter.c: Moved to...
* tree-ssa-loop-niter.cc: ...here.
* tree-ssa-loop-prefetch.c: Moved to...
* tree-ssa-loop-prefetch.cc: ...here.
* tree-ssa-loop-split.c: Moved to...
* tree-ssa-loop-split.cc: ...here.
* tree-ssa-loop-unswitch.c: Moved to...
* tree-ssa-loop-unswitch.cc: ...here.
* tree-ssa-loop.c: Moved to...
* tree-ssa-loop.cc: ...here.
* tree-ssa-math-opts.c: Moved to...
* tree-ssa-math-opts.cc: ...here.
* tree-ssa-operands.c: Moved to...
* tree-ssa-operands.cc: ...here.
* tree-ssa-phiopt.c: Moved to...
* tree-ssa-phiopt.cc: ...here.
* tree-ssa-phiprop.c: Moved to...
* tree-ssa-phiprop.cc: ...here.
* tree-ssa-pre.c: Moved to...
* tree-ssa-pre.cc: ...here.
* tree-ssa-propagate.c: Moved to...
* tree-ssa-propagate.cc: ...here.
* tree-ssa-reassoc.c: Moved to...
* tree-ssa-reassoc.cc: ...here.
* tree-ssa-sccvn.c: Moved to...
* tree-ssa-sccvn.cc: ...here.
* tree-ssa-scopedtables.c: Moved to...
* tree-ssa-scopedtables.cc: ...here.
* tree-ssa-sink.c: Moved to...
* tree-ssa-sink.cc: ...here.
* tree-ssa-strlen.c: Moved to...
* tree-ssa-strlen.cc: ...here.
* tree-ssa-structalias.c: Moved to...
* tree-ssa-structalias.cc: ...here.
* tree-ssa-tail-merge.c: Moved to...
* tree-ssa-tail-merge.cc: ...here.
* tree-ssa-ter.c: Moved to...
* tree-ssa-ter.cc: ...here.
* tree-ssa-threadbackward.c: Moved to...
* tree-ssa-threadbackward.cc: ...here.
* tree-ssa-threadedge.c: Moved to...
* tree-ssa-threadedge.cc: ...here.
* tree-ssa-threadupdate.c: Moved to...
* tree-ssa-threadupdate.cc: ...here.
* tree-ssa-uncprop.c: Moved to...
* tree-ssa-uncprop.cc: ...here.
* tree-ssa-uninit.c: Moved to...
* tree-ssa-uninit.cc: ...here.
* tree-ssa.c: Moved to...
* tree-ssa.cc: ...here.
* tree-ssanames.c: Moved to...
* tree-ssanames.cc: ...here.
* tree-stdarg.c: Moved to...
* tree-stdarg.cc: ...here.
* tree-streamer-in.c: Moved to...
* tree-streamer-in.cc: ...here.
* tree-streamer-out.c: Moved to...
* tree-streamer-out.cc: ...here.
* tree-streamer.c: Moved to...
* tree-streamer.cc: ...here.
* tree-switch-conversion.c: Moved to...
* tree-switch-conversion.cc: ...here.
* tree-tailcall.c: Moved to...
* tree-tailcall.cc: ...here.
* tree-vect-data-refs.c: Moved to...
* tree-vect-data-refs.cc: ...here.
* tree-vect-generic.c: Moved to...
* tree-vect-generic.cc: ...here.
* tree-vect-loop-manip.c: Moved to...
* tree-vect-loop-manip.cc: ...here.
* tree-vect-loop.c: Moved to...
* tree-vect-loop.cc: ...here.
* tree-vect-patterns.c: Moved to...
* tree-vect-patterns.cc: ...here.
* tree-vect-slp-patterns.c: Moved to...
* tree-vect-slp-patterns.cc: ...here.
* tree-vect-slp.c: Moved to...
* tree-vect-slp.cc: ...here.
* tree-vect-stmts.c: Moved to...
* tree-vect-stmts.cc: ...here.
* tree-vector-builder.c: Moved to...
* tree-vector-builder.cc: ...here.
* tree-vectorizer.c: Moved to...
* tree-vectorizer.cc: ...here.
* tree-vrp.c: Moved to...
* tree-vrp.cc: ...here.
* tree.c: Moved to...
* tree.cc: ...here.
* tsan.c: Moved to...
* tsan.cc: ...here.
* typed-splay-tree.c: Moved to...
* typed-splay-tree.cc: ...here.
* ubsan.c: Moved to...
* ubsan.cc: ...here.
* valtrack.c: Moved to...
* valtrack.cc: ...here.
* value-prof.c: Moved to...
* value-prof.cc: ...here.
* var-tracking.c: Moved to...
* var-tracking.cc: ...here.
* varasm.c: Moved to...
* varasm.cc: ...here.
* varpool.c: Moved to...
* varpool.cc: ...here.
* vec-perm-indices.c: Moved to...
* vec-perm-indices.cc: ...here.
* vec.c: Moved to...
* vec.cc: ...here.
* vmsdbgout.c: Moved to...
* vmsdbgout.cc: ...here.
* vr-values.c: Moved to...
* vr-values.cc: ...here.
* vtable-verify.c: Moved to...
* vtable-verify.cc: ...here.
* web.c: Moved to...
* web.cc: ...here.
* xcoffout.c: Moved to...
* xcoffout.cc: ...here.
gcc/c-family/ChangeLog:
* c-ada-spec.c: Moved to...
* c-ada-spec.cc: ...here.
* c-attribs.c: Moved to...
* c-attribs.cc: ...here.
* c-common.c: Moved to...
* c-common.cc: ...here.
* c-cppbuiltin.c: Moved to...
* c-cppbuiltin.cc: ...here.
* c-dump.c: Moved to...
* c-dump.cc: ...here.
* c-format.c: Moved to...
* c-format.cc: ...here.
* c-gimplify.c: Moved to...
* c-gimplify.cc: ...here.
* c-indentation.c: Moved to...
* c-indentation.cc: ...here.
* c-lex.c: Moved to...
* c-lex.cc: ...here.
* c-omp.c: Moved to...
* c-omp.cc: ...here.
* c-opts.c: Moved to...
* c-opts.cc: ...here.
* c-pch.c: Moved to...
* c-pch.cc: ...here.
* c-ppoutput.c: Moved to...
* c-ppoutput.cc: ...here.
* c-pragma.c: Moved to...
* c-pragma.cc: ...here.
* c-pretty-print.c: Moved to...
* c-pretty-print.cc: ...here.
* c-semantics.c: Moved to...
* c-semantics.cc: ...here.
* c-ubsan.c: Moved to...
* c-ubsan.cc: ...here.
* c-warn.c: Moved to...
* c-warn.cc: ...here.
* cppspec.c: Moved to...
* cppspec.cc: ...here.
* stub-objc.c: Moved to...
* stub-objc.cc: ...here.
gcc/c/ChangeLog:
* c-aux-info.c: Moved to...
* c-aux-info.cc: ...here.
* c-convert.c: Moved to...
* c-convert.cc: ...here.
* c-decl.c: Moved to...
* c-decl.cc: ...here.
* c-errors.c: Moved to...
* c-errors.cc: ...here.
* c-fold.c: Moved to...
* c-fold.cc: ...here.
* c-lang.c: Moved to...
* c-lang.cc: ...here.
* c-objc-common.c: Moved to...
* c-objc-common.cc: ...here.
* c-parser.c: Moved to...
* c-parser.cc: ...here.
* c-typeck.c: Moved to...
* c-typeck.cc: ...here.
* gccspec.c: Moved to...
* gccspec.cc: ...here.
* gimple-parser.c: Moved to...
* gimple-parser.cc: ...here.
gcc/cp/ChangeLog:
* call.c: Moved to...
* call.cc: ...here.
* class.c: Moved to...
* class.cc: ...here.
* constexpr.c: Moved to...
* constexpr.cc: ...here.
* cp-gimplify.c: Moved to...
* cp-gimplify.cc: ...here.
* cp-lang.c: Moved to...
* cp-lang.cc: ...here.
* cp-objcp-common.c: Moved to...
* cp-objcp-common.cc: ...here.
* cp-ubsan.c: Moved to...
* cp-ubsan.cc: ...here.
* cvt.c: Moved to...
* cvt.cc: ...here.
* cxx-pretty-print.c: Moved to...
* cxx-pretty-print.cc: ...here.
* decl.c: Moved to...
* decl.cc: ...here.
* decl2.c: Moved to...
* decl2.cc: ...here.
* dump.c: Moved to...
* dump.cc: ...here.
* error.c: Moved to...
* error.cc: ...here.
* except.c: Moved to...
* except.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* friend.c: Moved to...
* friend.cc: ...here.
* g++spec.c: Moved to...
* g++spec.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* lambda.c: Moved to...
* lambda.cc: ...here.
* lex.c: Moved to...
* lex.cc: ...here.
* mangle.c: Moved to...
* mangle.cc: ...here.
* method.c: Moved to...
* method.cc: ...here.
* name-lookup.c: Moved to...
* name-lookup.cc: ...here.
* optimize.c: Moved to...
* optimize.cc: ...here.
* parser.c: Moved to...
* parser.cc: ...here.
* pt.c: Moved to...
* pt.cc: ...here.
* ptree.c: Moved to...
* ptree.cc: ...here.
* rtti.c: Moved to...
* rtti.cc: ...here.
* search.c: Moved to...
* search.cc: ...here.
* semantics.c: Moved to...
* semantics.cc: ...here.
* tree.c: Moved to...
* tree.cc: ...here.
* typeck.c: Moved to...
* typeck.cc: ...here.
* typeck2.c: Moved to...
* typeck2.cc: ...here.
* vtable-class-hierarchy.c: Moved to...
* vtable-class-hierarchy.cc: ...here.
gcc/fortran/ChangeLog:
* arith.c: Moved to...
* arith.cc: ...here.
* array.c: Moved to...
* array.cc: ...here.
* bbt.c: Moved to...
* bbt.cc: ...here.
* check.c: Moved to...
* check.cc: ...here.
* class.c: Moved to...
* class.cc: ...here.
* constructor.c: Moved to...
* constructor.cc: ...here.
* convert.c: Moved to...
* convert.cc: ...here.
* cpp.c: Moved to...
* cpp.cc: ...here.
* data.c: Moved to...
* data.cc: ...here.
* decl.c: Moved to...
* decl.cc: ...here.
* dependency.c: Moved to...
* dependency.cc: ...here.
* dump-parse-tree.c: Moved to...
* dump-parse-tree.cc: ...here.
* error.c: Moved to...
* error.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* f95-lang.c: Moved to...
* f95-lang.cc: ...here.
* frontend-passes.c: Moved to...
* frontend-passes.cc: ...here.
* gfortranspec.c: Moved to...
* gfortranspec.cc: ...here.
* interface.c: Moved to...
* interface.cc: ...here.
* intrinsic.c: Moved to...
* intrinsic.cc: ...here.
* io.c: Moved to...
* io.cc: ...here.
* iresolve.c: Moved to...
* iresolve.cc: ...here.
* match.c: Moved to...
* match.cc: ...here.
* matchexp.c: Moved to...
* matchexp.cc: ...here.
* misc.c: Moved to...
* misc.cc: ...here.
* module.c: Moved to...
* module.cc: ...here.
* openmp.c: Moved to...
* openmp.cc: ...here.
* options.c: Moved to...
* options.cc: ...here.
* parse.c: Moved to...
* parse.cc: ...here.
* primary.c: Moved to...
* primary.cc: ...here.
* resolve.c: Moved to...
* resolve.cc: ...here.
* scanner.c: Moved to...
* scanner.cc: ...here.
* simplify.c: Moved to...
* simplify.cc: ...here.
* st.c: Moved to...
* st.cc: ...here.
* symbol.c: Moved to...
* symbol.cc: ...here.
* target-memory.c: Moved to...
* target-memory.cc: ...here.
* trans-array.c: Moved to...
* trans-array.cc: ...here.
* trans-common.c: Moved to...
* trans-common.cc: ...here.
* trans-const.c: Moved to...
* trans-const.cc: ...here.
* trans-decl.c: Moved to...
* trans-decl.cc: ...here.
* trans-expr.c: Moved to...
* trans-expr.cc: ...here.
* trans-intrinsic.c: Moved to...
* trans-intrinsic.cc: ...here.
* trans-io.c: Moved to...
* trans-io.cc: ...here.
* trans-openmp.c: Moved to...
* trans-openmp.cc: ...here.
* trans-stmt.c: Moved to...
* trans-stmt.cc: ...here.
* trans-types.c: Moved to...
* trans-types.cc: ...here.
* trans.c: Moved to...
* trans.cc: ...here.
gcc/go/ChangeLog:
* go-backend.c: Moved to...
* go-backend.cc: ...here.
* go-lang.c: Moved to...
* go-lang.cc: ...here.
* gospec.c: Moved to...
* gospec.cc: ...here.
gcc/jit/ChangeLog:
* dummy-frontend.c: Moved to...
* dummy-frontend.cc: ...here.
* jit-builtins.c: Moved to...
* jit-builtins.cc: ...here.
* jit-logging.c: Moved to...
* jit-logging.cc: ...here.
* jit-playback.c: Moved to...
* jit-playback.cc: ...here.
* jit-recording.c: Moved to...
* jit-recording.cc: ...here.
* jit-result.c: Moved to...
* jit-result.cc: ...here.
* jit-spec.c: Moved to...
* jit-spec.cc: ...here.
* jit-tempdir.c: Moved to...
* jit-tempdir.cc: ...here.
* jit-w32.c: Moved to...
* jit-w32.cc: ...here.
* libgccjit.c: Moved to...
* libgccjit.cc: ...here.
gcc/lto/ChangeLog:
* common.c: Moved to...
* common.cc: ...here.
* lto-common.c: Moved to...
* lto-common.cc: ...here.
* lto-dump.c: Moved to...
* lto-dump.cc: ...here.
* lto-lang.c: Moved to...
* lto-lang.cc: ...here.
* lto-object.c: Moved to...
* lto-object.cc: ...here.
* lto-partition.c: Moved to...
* lto-partition.cc: ...here.
* lto-symtab.c: Moved to...
* lto-symtab.cc: ...here.
* lto.c: Moved to...
* lto.cc: ...here.
gcc/objc/ChangeLog:
* objc-act.c: Moved to...
* objc-act.cc: ...here.
* objc-encoding.c: Moved to...
* objc-encoding.cc: ...here.
* objc-gnu-runtime-abi-01.c: Moved to...
* objc-gnu-runtime-abi-01.cc: ...here.
* objc-lang.c: Moved to...
* objc-lang.cc: ...here.
* objc-map.c: Moved to...
* objc-map.cc: ...here.
* objc-next-runtime-abi-01.c: Moved to...
* objc-next-runtime-abi-01.cc: ...here.
* objc-next-runtime-abi-02.c: Moved to...
* objc-next-runtime-abi-02.cc: ...here.
* objc-runtime-shared-support.c: Moved to...
* objc-runtime-shared-support.cc: ...here.
gcc/objcp/ChangeLog:
* objcp-decl.c: Moved to...
* objcp-decl.cc: ...here.
* objcp-lang.c: Moved to...
* objcp-lang.cc: ...here.
libcpp/ChangeLog:
* charset.c: Moved to...
* charset.cc: ...here.
* directives.c: Moved to...
* directives.cc: ...here.
* errors.c: Moved to...
* errors.cc: ...here.
* expr.c: Moved to...
* expr.cc: ...here.
* files.c: Moved to...
* files.cc: ...here.
* identifiers.c: Moved to...
* identifiers.cc: ...here.
* init.c: Moved to...
* init.cc: ...here.
* lex.c: Moved to...
* lex.cc: ...here.
* line-map.c: Moved to...
* line-map.cc: ...here.
* macro.c: Moved to...
* macro.cc: ...here.
* makeucnid.c: Moved to...
* makeucnid.cc: ...here.
* mkdeps.c: Moved to...
* mkdeps.cc: ...here.
* pch.c: Moved to...
* pch.cc: ...here.
* symtab.c: Moved to...
* symtab.cc: ...here.
* traditional.c: Moved to...
* traditional.cc: ...here.
Diffstat (limited to 'gcc/reload1.c')
-rw-r--r-- | gcc/reload1.c | 9069 |
1 files changed, 0 insertions, 9069 deletions
diff --git a/gcc/reload1.c b/gcc/reload1.c deleted file mode 100644 index 358b368..0000000 --- a/gcc/reload1.c +++ /dev/null @@ -1,9069 +0,0 @@ -/* Reload pseudo regs into hard regs for insns that require hard regs. - 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 "predict.h" -#include "df.h" -#include "memmodel.h" -#include "tm_p.h" -#include "optabs.h" -#include "regs.h" -#include "ira.h" -#include "recog.h" - -#include "rtl-error.h" -#include "expr.h" -#include "addresses.h" -#include "cfgrtl.h" -#include "cfgbuild.h" -#include "reload.h" -#include "except.h" -#include "dumpfile.h" -#include "rtl-iter.h" -#include "function-abi.h" - -/* This file contains the reload pass of the compiler, which is - run after register allocation has been done. It checks that - each insn is valid (operands required to be in registers really - are in registers of the proper class) and fixes up invalid ones - by copying values temporarily into registers for the insns - that need them. - - The results of register allocation are described by the vector - reg_renumber; the insns still contain pseudo regs, but reg_renumber - can be used to find which hard reg, if any, a pseudo reg is in. - - The technique we always use is to free up a few hard regs that are - called ``reload regs'', and for each place where a pseudo reg - must be in a hard reg, copy it temporarily into one of the reload regs. - - Reload regs are allocated locally for every instruction that needs - reloads. When there are pseudos which are allocated to a register that - has been chosen as a reload reg, such pseudos must be ``spilled''. - This means that they go to other hard regs, or to stack slots if no other - available hard regs can be found. Spilling can invalidate more - insns, requiring additional need for reloads, so we must keep checking - until the process stabilizes. - - For machines with different classes of registers, we must keep track - of the register class needed for each reload, and make sure that - we allocate enough reload registers of each class. - - The file reload.c contains the code that checks one insn for - validity and reports the reloads that it needs. This file - is in charge of scanning the entire rtl code, accumulating the - reload needs, spilling, assigning reload registers to use for - fixing up each insn, and generating the new insns to copy values - into the reload registers. */ - -struct target_reload default_target_reload; -#if SWITCHABLE_TARGET -struct target_reload *this_target_reload = &default_target_reload; -#endif - -#define spill_indirect_levels \ - (this_target_reload->x_spill_indirect_levels) - -/* During reload_as_needed, element N contains a REG rtx for the hard reg - into which reg N has been reloaded (perhaps for a previous insn). */ -static rtx *reg_last_reload_reg; - -/* Elt N nonzero if reg_last_reload_reg[N] has been set in this insn - for an output reload that stores into reg N. */ -static regset_head reg_has_output_reload; - -/* Indicates which hard regs are reload-registers for an output reload - in the current insn. */ -static HARD_REG_SET reg_is_output_reload; - -/* Widest mode in which each pseudo reg is referred to (via subreg). */ -static machine_mode *reg_max_ref_mode; - -/* Vector to remember old contents of reg_renumber before spilling. */ -static short *reg_old_renumber; - -/* During reload_as_needed, element N contains the last pseudo regno reloaded - into hard register N. If that pseudo reg occupied more than one register, - reg_reloaded_contents points to that pseudo for each spill register in - use; all of these must remain set for an inheritance to occur. */ -static int reg_reloaded_contents[FIRST_PSEUDO_REGISTER]; - -/* During reload_as_needed, element N contains the insn for which - hard register N was last used. Its contents are significant only - when reg_reloaded_valid is set for this register. */ -static rtx_insn *reg_reloaded_insn[FIRST_PSEUDO_REGISTER]; - -/* Indicate if reg_reloaded_insn / reg_reloaded_contents is valid. */ -static HARD_REG_SET reg_reloaded_valid; -/* Indicate if the register was dead at the end of the reload. - This is only valid if reg_reloaded_contents is set and valid. */ -static HARD_REG_SET reg_reloaded_dead; - -/* Number of spill-regs so far; number of valid elements of spill_regs. */ -static int n_spills; - -/* In parallel with spill_regs, contains REG rtx's for those regs. - Holds the last rtx used for any given reg, or 0 if it has never - been used for spilling yet. This rtx is reused, provided it has - the proper mode. */ -static rtx spill_reg_rtx[FIRST_PSEUDO_REGISTER]; - -/* In parallel with spill_regs, contains nonzero for a spill reg - that was stored after the last time it was used. - The precise value is the insn generated to do the store. */ -static rtx_insn *spill_reg_store[FIRST_PSEUDO_REGISTER]; - -/* This is the register that was stored with spill_reg_store. This is a - copy of reload_out / reload_out_reg when the value was stored; if - reload_out is a MEM, spill_reg_stored_to will be set to reload_out_reg. */ -static rtx spill_reg_stored_to[FIRST_PSEUDO_REGISTER]; - -/* This table is the inverse mapping of spill_regs: - indexed by hard reg number, - it contains the position of that reg in spill_regs, - or -1 for something that is not in spill_regs. - - ?!? This is no longer accurate. */ -static short spill_reg_order[FIRST_PSEUDO_REGISTER]; - -/* This reg set indicates registers that can't be used as spill registers for - the currently processed insn. These are the hard registers which are live - during the insn, but not allocated to pseudos, as well as fixed - registers. */ -static HARD_REG_SET bad_spill_regs; - -/* These are the hard registers that can't be used as spill register for any - insn. This includes registers used for user variables and registers that - we can't eliminate. A register that appears in this set also can't be used - to retry register allocation. */ -static HARD_REG_SET bad_spill_regs_global; - -/* Describes order of use of registers for reloading - of spilled pseudo-registers. `n_spills' is the number of - elements that are actually valid; new ones are added at the end. - - Both spill_regs and spill_reg_order are used on two occasions: - once during find_reload_regs, where they keep track of the spill registers - for a single insn, but also during reload_as_needed where they show all - the registers ever used by reload. For the latter case, the information - is calculated during finish_spills. */ -static short spill_regs[FIRST_PSEUDO_REGISTER]; - -/* This vector of reg sets indicates, for each pseudo, which hard registers - may not be used for retrying global allocation because the register was - formerly spilled from one of them. If we allowed reallocating a pseudo to - a register that it was already allocated to, reload might not - terminate. */ -static HARD_REG_SET *pseudo_previous_regs; - -/* This vector of reg sets indicates, for each pseudo, which hard - registers may not be used for retrying global allocation because they - are used as spill registers during one of the insns in which the - pseudo is live. */ -static HARD_REG_SET *pseudo_forbidden_regs; - -/* All hard regs that have been used as spill registers for any insn are - marked in this set. */ -static HARD_REG_SET used_spill_regs; - -/* Index of last register assigned as a spill register. We allocate in - a round-robin fashion. */ -static int last_spill_reg; - -/* Record the stack slot for each spilled hard register. */ -static rtx spill_stack_slot[FIRST_PSEUDO_REGISTER]; - -/* Width allocated so far for that stack slot. */ -static poly_uint64_pod spill_stack_slot_width[FIRST_PSEUDO_REGISTER]; - -/* Record which pseudos needed to be spilled. */ -static regset_head spilled_pseudos; - -/* Record which pseudos changed their allocation in finish_spills. */ -static regset_head changed_allocation_pseudos; - -/* Used for communication between order_regs_for_reload and count_pseudo. - Used to avoid counting one pseudo twice. */ -static regset_head pseudos_counted; - -/* First uid used by insns created by reload in this function. - Used in find_equiv_reg. */ -int reload_first_uid; - -/* Flag set by local-alloc or global-alloc if anything is live in - a call-clobbered reg across calls. */ -int caller_save_needed; - -/* Set to 1 while reload_as_needed is operating. - Required by some machines to handle any generated moves differently. */ -int reload_in_progress = 0; - -/* This obstack is used for allocation of rtl during register elimination. - The allocated storage can be freed once find_reloads has processed the - insn. */ -static struct obstack reload_obstack; - -/* Points to the beginning of the reload_obstack. All insn_chain structures - are allocated first. */ -static char *reload_startobj; - -/* The point after all insn_chain structures. Used to quickly deallocate - memory allocated in copy_reloads during calculate_needs_all_insns. */ -static char *reload_firstobj; - -/* This points before all local rtl generated by register elimination. - Used to quickly free all memory after processing one insn. */ -static char *reload_insn_firstobj; - -/* List of insn_chain instructions, one for every insn that reload needs to - examine. */ -class insn_chain *reload_insn_chain; - -/* TRUE if we potentially left dead insns in the insn stream and want to - run DCE immediately after reload, FALSE otherwise. */ -static bool need_dce; - -/* List of all insns needing reloads. */ -static class insn_chain *insns_need_reload; - -/* This structure is used to record information about register eliminations. - Each array entry describes one possible way of eliminating a register - in favor of another. If there is more than one way of eliminating a - particular register, the most preferred should be specified first. */ - -struct elim_table -{ - int from; /* Register number to be eliminated. */ - int to; /* Register number used as replacement. */ - poly_int64_pod initial_offset; /* Initial difference between values. */ - int can_eliminate; /* Nonzero if this elimination can be done. */ - int can_eliminate_previous; /* Value returned by TARGET_CAN_ELIMINATE - target hook in previous scan over insns - made by reload. */ - poly_int64_pod offset; /* Current offset between the two regs. */ - poly_int64_pod previous_offset; /* Offset at end of previous insn. */ - int ref_outside_mem; /* "to" has been referenced outside a MEM. */ - rtx from_rtx; /* REG rtx for the register to be eliminated. - We cannot simply compare the number since - we might then spuriously replace a hard - register corresponding to a pseudo - assigned to the reg to be eliminated. */ - rtx to_rtx; /* REG rtx for the replacement. */ -}; - -static struct elim_table *reg_eliminate = 0; - -/* This is an intermediate structure to initialize the table. It has - exactly the members provided by ELIMINABLE_REGS. */ -static const struct elim_table_1 -{ - const int from; - const int to; -} reg_eliminate_1[] = - - ELIMINABLE_REGS; - -#define NUM_ELIMINABLE_REGS ARRAY_SIZE (reg_eliminate_1) - -/* Record the number of pending eliminations that have an offset not equal - to their initial offset. If nonzero, we use a new copy of each - replacement result in any insns encountered. */ -int num_not_at_initial_offset; - -/* Count the number of registers that we may be able to eliminate. */ -static int num_eliminable; -/* And the number of registers that are equivalent to a constant that - can be eliminated to frame_pointer / arg_pointer + constant. */ -static int num_eliminable_invariants; - -/* For each label, we record the offset of each elimination. If we reach - a label by more than one path and an offset differs, we cannot do the - elimination. This information is indexed by the difference of the - number of the label and the first label number. We can't offset the - pointer itself as this can cause problems on machines with segmented - memory. The first table is an array of flags that records whether we - have yet encountered a label and the second table is an array of arrays, - one entry in the latter array for each elimination. */ - -static int first_label_num; -static char *offsets_known_at; -static poly_int64_pod (*offsets_at)[NUM_ELIMINABLE_REGS]; - -vec<reg_equivs_t, va_gc> *reg_equivs; - -/* Stack of addresses where an rtx has been changed. We can undo the - changes by popping items off the stack and restoring the original - value at each location. - - We use this simplistic undo capability rather than copy_rtx as copy_rtx - will not make a deep copy of a normally sharable rtx, such as - (const (plus (symbol_ref) (const_int))). If such an expression appears - as R1 in gen_reload_chain_without_interm_reg_p, then a shared - rtx expression would be changed. See PR 42431. */ - -typedef rtx *rtx_p; -static vec<rtx_p> substitute_stack; - -/* Number of labels in the current function. */ - -static int num_labels; - -static void replace_pseudos_in (rtx *, machine_mode, rtx); -static void maybe_fix_stack_asms (void); -static void copy_reloads (class insn_chain *); -static void calculate_needs_all_insns (int); -static int find_reg (class insn_chain *, int); -static void find_reload_regs (class insn_chain *); -static void select_reload_regs (void); -static void delete_caller_save_insns (void); - -static void spill_failure (rtx_insn *, enum reg_class); -static void count_spilled_pseudo (int, int, int); -static void delete_dead_insn (rtx_insn *); -static void alter_reg (int, int, bool); -static void set_label_offsets (rtx, rtx_insn *, int); -static void check_eliminable_occurrences (rtx); -static void elimination_effects (rtx, machine_mode); -static rtx eliminate_regs_1 (rtx, machine_mode, rtx, bool, bool); -static int eliminate_regs_in_insn (rtx_insn *, int); -static void update_eliminable_offsets (void); -static void mark_not_eliminable (rtx, const_rtx, void *); -static void set_initial_elim_offsets (void); -static bool verify_initial_elim_offsets (void); -static void set_initial_label_offsets (void); -static void set_offsets_for_label (rtx_insn *); -static void init_eliminable_invariants (rtx_insn *, bool); -static void init_elim_table (void); -static void free_reg_equiv (void); -static void update_eliminables (HARD_REG_SET *); -static bool update_eliminables_and_spill (void); -static void elimination_costs_in_insn (rtx_insn *); -static void spill_hard_reg (unsigned int, int); -static int finish_spills (int); -static void scan_paradoxical_subregs (rtx); -static void count_pseudo (int); -static void order_regs_for_reload (class insn_chain *); -static void reload_as_needed (int); -static void forget_old_reloads_1 (rtx, const_rtx, void *); -static void forget_marked_reloads (regset); -static int reload_reg_class_lower (const void *, const void *); -static void mark_reload_reg_in_use (unsigned int, int, enum reload_type, - machine_mode); -static void clear_reload_reg_in_use (unsigned int, int, enum reload_type, - machine_mode); -static int reload_reg_free_p (unsigned int, int, enum reload_type); -static int reload_reg_free_for_value_p (int, int, int, enum reload_type, - rtx, rtx, int, int); -static int free_for_value_p (int, machine_mode, int, enum reload_type, - rtx, rtx, int, int); -static int allocate_reload_reg (class insn_chain *, int, int); -static int conflicts_with_override (rtx); -static void failed_reload (rtx_insn *, int); -static int set_reload_reg (int, int); -static void choose_reload_regs_init (class insn_chain *, rtx *); -static void choose_reload_regs (class insn_chain *); -static void emit_input_reload_insns (class insn_chain *, struct reload *, - rtx, int); -static void emit_output_reload_insns (class insn_chain *, struct reload *, - int); -static void do_input_reload (class insn_chain *, struct reload *, int); -static void do_output_reload (class insn_chain *, struct reload *, int); -static void emit_reload_insns (class insn_chain *); -static void delete_output_reload (rtx_insn *, int, int, rtx); -static void delete_address_reloads (rtx_insn *, rtx_insn *); -static void delete_address_reloads_1 (rtx_insn *, rtx, rtx_insn *); -static void inc_for_reload (rtx, rtx, rtx, poly_int64); -static void substitute (rtx *, const_rtx, rtx); -static bool gen_reload_chain_without_interm_reg_p (int, int); -static int reloads_conflict (int, int); -static rtx_insn *gen_reload (rtx, rtx, int, enum reload_type); -static rtx_insn *emit_insn_if_valid_for_reload (rtx); - -/* Initialize the reload pass. This is called at the beginning of compilation - and may be called again if the target is reinitialized. */ - -void -init_reload (void) -{ - int i; - - /* Often (MEM (REG n)) is still valid even if (REG n) is put on the stack. - Set spill_indirect_levels to the number of levels such addressing is - permitted, zero if it is not permitted at all. */ - - rtx tem - = gen_rtx_MEM (Pmode, - gen_rtx_PLUS (Pmode, - gen_rtx_REG (Pmode, - LAST_VIRTUAL_REGISTER + 1), - gen_int_mode (4, Pmode))); - spill_indirect_levels = 0; - - while (memory_address_p (QImode, tem)) - { - spill_indirect_levels++; - tem = gen_rtx_MEM (Pmode, tem); - } - - /* See if indirect addressing is valid for (MEM (SYMBOL_REF ...)). */ - - tem = gen_rtx_MEM (Pmode, gen_rtx_SYMBOL_REF (Pmode, "foo")); - indirect_symref_ok = memory_address_p (QImode, tem); - - /* See if reg+reg is a valid (and offsettable) address. */ - - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - { - tem = gen_rtx_PLUS (Pmode, - gen_rtx_REG (Pmode, HARD_FRAME_POINTER_REGNUM), - gen_rtx_REG (Pmode, i)); - - /* This way, we make sure that reg+reg is an offsettable address. */ - tem = plus_constant (Pmode, tem, 4); - - for (int mode = 0; mode < MAX_MACHINE_MODE; mode++) - if (!double_reg_address_ok[mode] - && memory_address_p ((enum machine_mode)mode, tem)) - double_reg_address_ok[mode] = 1; - } - - /* Initialize obstack for our rtl allocation. */ - if (reload_startobj == NULL) - { - gcc_obstack_init (&reload_obstack); - reload_startobj = XOBNEWVAR (&reload_obstack, char, 0); - } - - INIT_REG_SET (&spilled_pseudos); - INIT_REG_SET (&changed_allocation_pseudos); - INIT_REG_SET (&pseudos_counted); -} - -/* List of insn chains that are currently unused. */ -static class insn_chain *unused_insn_chains = 0; - -/* Allocate an empty insn_chain structure. */ -class insn_chain * -new_insn_chain (void) -{ - class insn_chain *c; - - if (unused_insn_chains == 0) - { - c = XOBNEW (&reload_obstack, class insn_chain); - INIT_REG_SET (&c->live_throughout); - INIT_REG_SET (&c->dead_or_set); - } - else - { - c = unused_insn_chains; - unused_insn_chains = c->next; - } - c->is_caller_save_insn = 0; - c->need_operand_change = 0; - c->need_reload = 0; - c->need_elim = 0; - return c; -} - -/* Small utility function to set all regs in hard reg set TO which are - allocated to pseudos in regset FROM. */ - -void -compute_use_by_pseudos (HARD_REG_SET *to, regset from) -{ - unsigned int regno; - reg_set_iterator rsi; - - EXECUTE_IF_SET_IN_REG_SET (from, FIRST_PSEUDO_REGISTER, regno, rsi) - { - int r = reg_renumber[regno]; - - if (r < 0) - { - /* reload_combine uses the information from DF_LIVE_IN, - which might still contain registers that have not - actually been allocated since they have an - equivalence. */ - gcc_assert (ira_conflicts_p || reload_completed); - } - else - add_to_hard_reg_set (to, PSEUDO_REGNO_MODE (regno), r); - } -} - -/* Replace all pseudos found in LOC with their corresponding - equivalences. */ - -static void -replace_pseudos_in (rtx *loc, machine_mode mem_mode, rtx usage) -{ - rtx x = *loc; - enum rtx_code code; - const char *fmt; - int i, j; - - if (! x) - return; - - code = GET_CODE (x); - if (code == REG) - { - unsigned int regno = REGNO (x); - - if (regno < FIRST_PSEUDO_REGISTER) - return; - - x = eliminate_regs_1 (x, mem_mode, usage, true, false); - if (x != *loc) - { - *loc = x; - replace_pseudos_in (loc, mem_mode, usage); - return; - } - - if (reg_equiv_constant (regno)) - *loc = reg_equiv_constant (regno); - else if (reg_equiv_invariant (regno)) - *loc = reg_equiv_invariant (regno); - else if (reg_equiv_mem (regno)) - *loc = reg_equiv_mem (regno); - else if (reg_equiv_address (regno)) - *loc = gen_rtx_MEM (GET_MODE (x), reg_equiv_address (regno)); - else - { - gcc_assert (!REG_P (regno_reg_rtx[regno]) - || REGNO (regno_reg_rtx[regno]) != regno); - *loc = regno_reg_rtx[regno]; - } - - return; - } - else if (code == MEM) - { - replace_pseudos_in (& XEXP (x, 0), GET_MODE (x), usage); - return; - } - - /* Process each of our operands recursively. */ - fmt = GET_RTX_FORMAT (code); - for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) - if (*fmt == 'e') - replace_pseudos_in (&XEXP (x, i), mem_mode, usage); - else if (*fmt == 'E') - for (j = 0; j < XVECLEN (x, i); j++) - replace_pseudos_in (& XVECEXP (x, i, j), mem_mode, usage); -} - -/* Determine if the current function has an exception receiver block - that reaches the exit block via non-exceptional edges */ - -static bool -has_nonexceptional_receiver (void) -{ - edge e; - edge_iterator ei; - basic_block *tos, *worklist, bb; - - /* If we're not optimizing, then just err on the safe side. */ - if (!optimize) - return true; - - /* First determine which blocks can reach exit via normal paths. */ - tos = worklist = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun) + 1); - - FOR_EACH_BB_FN (bb, cfun) - bb->flags &= ~BB_REACHABLE; - - /* Place the exit block on our worklist. */ - EXIT_BLOCK_PTR_FOR_FN (cfun)->flags |= BB_REACHABLE; - *tos++ = EXIT_BLOCK_PTR_FOR_FN (cfun); - - /* Iterate: find everything reachable from what we've already seen. */ - while (tos != worklist) - { - bb = *--tos; - - FOR_EACH_EDGE (e, ei, bb->preds) - if (!(e->flags & EDGE_ABNORMAL)) - { - basic_block src = e->src; - - if (!(src->flags & BB_REACHABLE)) - { - src->flags |= BB_REACHABLE; - *tos++ = src; - } - } - } - free (worklist); - - /* Now see if there's a reachable block with an exceptional incoming - edge. */ - FOR_EACH_BB_FN (bb, cfun) - if (bb->flags & BB_REACHABLE && bb_has_abnormal_pred (bb)) - return true; - - /* No exceptional block reached exit unexceptionally. */ - return false; -} - -/* Grow (or allocate) the REG_EQUIVS array from its current size (which may be - zero elements) to MAX_REG_NUM elements. - - Initialize all new fields to NULL and update REG_EQUIVS_SIZE. */ -void -grow_reg_equivs (void) -{ - int old_size = vec_safe_length (reg_equivs); - int max_regno = max_reg_num (); - int i; - reg_equivs_t ze; - - memset (&ze, 0, sizeof (reg_equivs_t)); - vec_safe_reserve (reg_equivs, max_regno); - for (i = old_size; i < max_regno; i++) - reg_equivs->quick_insert (i, ze); -} - - -/* Global variables used by reload and its subroutines. */ - -/* The current basic block while in calculate_elim_costs_all_insns. */ -static basic_block elim_bb; - -/* Set during calculate_needs if an insn needs register elimination. */ -static int something_needs_elimination; -/* Set during calculate_needs if an insn needs an operand changed. */ -static int something_needs_operands_changed; -/* Set by alter_regs if we spilled a register to the stack. */ -static bool something_was_spilled; - -/* Nonzero means we couldn't get enough spill regs. */ -static int failure; - -/* Temporary array of pseudo-register number. */ -static int *temp_pseudo_reg_arr; - -/* If a pseudo has no hard reg, delete the insns that made the equivalence. - If that insn didn't set the register (i.e., it copied the register to - memory), just delete that insn instead of the equivalencing insn plus - anything now dead. If we call delete_dead_insn on that insn, we may - delete the insn that actually sets the register if the register dies - there and that is incorrect. */ -static void -remove_init_insns () -{ - for (int i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - { - if (reg_renumber[i] < 0 && reg_equiv_init (i) != 0) - { - rtx list; - for (list = reg_equiv_init (i); list; list = XEXP (list, 1)) - { - rtx_insn *equiv_insn = as_a <rtx_insn *> (XEXP (list, 0)); - - /* If we already deleted the insn or if it may trap, we can't - delete it. The latter case shouldn't happen, but can - if an insn has a variable address, gets a REG_EH_REGION - note added to it, and then gets converted into a load - from a constant address. */ - if (NOTE_P (equiv_insn) - || can_throw_internal (equiv_insn)) - ; - else if (reg_set_p (regno_reg_rtx[i], PATTERN (equiv_insn))) - delete_dead_insn (equiv_insn); - else - SET_INSN_DELETED (equiv_insn); - } - } - } -} - -/* Return true if remove_init_insns will delete INSN. */ -static bool -will_delete_init_insn_p (rtx_insn *insn) -{ - rtx set = single_set (insn); - if (!set || !REG_P (SET_DEST (set))) - return false; - unsigned regno = REGNO (SET_DEST (set)); - - if (can_throw_internal (insn)) - return false; - - if (regno < FIRST_PSEUDO_REGISTER || reg_renumber[regno] >= 0) - return false; - - for (rtx list = reg_equiv_init (regno); list; list = XEXP (list, 1)) - { - rtx equiv_insn = XEXP (list, 0); - if (equiv_insn == insn) - return true; - } - return false; -} - -/* Main entry point for the reload pass. - - FIRST is the first insn of the function being compiled. - - GLOBAL nonzero means we were called from global_alloc - and should attempt to reallocate any pseudoregs that we - displace from hard regs we will use for reloads. - If GLOBAL is zero, we do not have enough information to do that, - so any pseudo reg that is spilled must go to the stack. - - Return value is TRUE if reload likely left dead insns in the - stream and a DCE pass should be run to elimiante them. Else the - return value is FALSE. */ - -bool -reload (rtx_insn *first, int global) -{ - int i, n; - rtx_insn *insn; - struct elim_table *ep; - basic_block bb; - bool inserted; - - /* Make sure even insns with volatile mem refs are recognizable. */ - init_recog (); - - failure = 0; - - reload_firstobj = XOBNEWVAR (&reload_obstack, char, 0); - - /* Make sure that the last insn in the chain - is not something that needs reloading. */ - emit_note (NOTE_INSN_DELETED); - - /* Enable find_equiv_reg to distinguish insns made by reload. */ - reload_first_uid = get_max_uid (); - - /* Initialize the secondary memory table. */ - clear_secondary_mem (); - - /* We don't have a stack slot for any spill reg yet. */ - memset (spill_stack_slot, 0, sizeof spill_stack_slot); - memset (spill_stack_slot_width, 0, sizeof spill_stack_slot_width); - - /* Initialize the save area information for caller-save, in case some - are needed. */ - init_save_areas (); - - /* Compute which hard registers are now in use - as homes for pseudo registers. - This is done here rather than (eg) in global_alloc - because this point is reached even if not optimizing. */ - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - mark_home_live (i); - - /* A function that has a nonlocal label that can reach the exit - block via non-exceptional paths must save all call-saved - registers. */ - if (cfun->has_nonlocal_label - && has_nonexceptional_receiver ()) - crtl->saves_all_registers = 1; - - if (crtl->saves_all_registers) - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (! crtl->abi->clobbers_full_reg_p (i) - && ! fixed_regs[i] - && ! LOCAL_REGNO (i)) - df_set_regs_ever_live (i, true); - - /* Find all the pseudo registers that didn't get hard regs - but do have known equivalent constants or memory slots. - These include parameters (known equivalent to parameter slots) - and cse'd or loop-moved constant memory addresses. - - Record constant equivalents in reg_equiv_constant - so they will be substituted by find_reloads. - Record memory equivalents in reg_mem_equiv so they can - be substituted eventually by altering the REG-rtx's. */ - - grow_reg_equivs (); - reg_old_renumber = XCNEWVEC (short, max_regno); - memcpy (reg_old_renumber, reg_renumber, max_regno * sizeof (short)); - pseudo_forbidden_regs = XNEWVEC (HARD_REG_SET, max_regno); - pseudo_previous_regs = XCNEWVEC (HARD_REG_SET, max_regno); - - CLEAR_HARD_REG_SET (bad_spill_regs_global); - - init_eliminable_invariants (first, true); - init_elim_table (); - - /* Alter each pseudo-reg rtx to contain its hard reg number. Assign - stack slots to the pseudos that lack hard regs or equivalents. - Do not touch virtual registers. */ - - temp_pseudo_reg_arr = XNEWVEC (int, max_regno - LAST_VIRTUAL_REGISTER - 1); - for (n = 0, i = LAST_VIRTUAL_REGISTER + 1; i < max_regno; i++) - temp_pseudo_reg_arr[n++] = i; - - if (ira_conflicts_p) - /* Ask IRA to order pseudo-registers for better stack slot - sharing. */ - ira_sort_regnos_for_alter_reg (temp_pseudo_reg_arr, n, reg_max_ref_mode); - - for (i = 0; i < n; i++) - alter_reg (temp_pseudo_reg_arr[i], -1, false); - - /* If we have some registers we think can be eliminated, scan all insns to - see if there is an insn that sets one of these registers to something - other than itself plus a constant. If so, the register cannot be - eliminated. Doing this scan here eliminates an extra pass through the - main reload loop in the most common case where register elimination - cannot be done. */ - for (insn = first; insn && num_eliminable; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - note_pattern_stores (PATTERN (insn), mark_not_eliminable, NULL); - - maybe_fix_stack_asms (); - - insns_need_reload = 0; - something_needs_elimination = 0; - - /* Initialize to -1, which means take the first spill register. */ - last_spill_reg = -1; - - /* Spill any hard regs that we know we can't eliminate. */ - CLEAR_HARD_REG_SET (used_spill_regs); - /* There can be multiple ways to eliminate a register; - they should be listed adjacently. - Elimination for any register fails only if all possible ways fail. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ) - { - int from = ep->from; - int can_eliminate = 0; - do - { - can_eliminate |= ep->can_eliminate; - ep++; - } - while (ep < ®_eliminate[NUM_ELIMINABLE_REGS] && ep->from == from); - if (! can_eliminate) - spill_hard_reg (from, 1); - } - - if (!HARD_FRAME_POINTER_IS_FRAME_POINTER && frame_pointer_needed) - spill_hard_reg (HARD_FRAME_POINTER_REGNUM, 1); - - finish_spills (global); - - /* From now on, we may need to generate moves differently. We may also - allow modifications of insns which cause them to not be recognized. - Any such modifications will be cleaned up during reload itself. */ - reload_in_progress = 1; - - /* This loop scans the entire function each go-round - and repeats until one repetition spills no additional hard regs. */ - for (;;) - { - int something_changed; - poly_int64 starting_frame_size; - - starting_frame_size = get_frame_size (); - something_was_spilled = false; - - set_initial_elim_offsets (); - set_initial_label_offsets (); - - /* For each pseudo register that has an equivalent location defined, - try to eliminate any eliminable registers (such as the frame pointer) - assuming initial offsets for the replacement register, which - is the normal case. - - If the resulting location is directly addressable, substitute - the MEM we just got directly for the old REG. - - If it is not addressable but is a constant or the sum of a hard reg - and constant, it is probably not addressable because the constant is - out of range, in that case record the address; we will generate - hairy code to compute the address in a register each time it is - needed. Similarly if it is a hard register, but one that is not - valid as an address register. - - If the location is not addressable, but does not have one of the - above forms, assign a stack slot. We have to do this to avoid the - potential of producing lots of reloads if, e.g., a location involves - a pseudo that didn't get a hard register and has an equivalent memory - location that also involves a pseudo that didn't get a hard register. - - Perhaps at some point we will improve reload_when_needed handling - so this problem goes away. But that's very hairy. */ - - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - if (reg_renumber[i] < 0 && reg_equiv_memory_loc (i)) - { - rtx x = eliminate_regs (reg_equiv_memory_loc (i), VOIDmode, - NULL_RTX); - - if (strict_memory_address_addr_space_p - (GET_MODE (regno_reg_rtx[i]), XEXP (x, 0), - MEM_ADDR_SPACE (x))) - reg_equiv_mem (i) = x, reg_equiv_address (i) = 0; - else if (CONSTANT_P (XEXP (x, 0)) - || (REG_P (XEXP (x, 0)) - && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER) - || (GET_CODE (XEXP (x, 0)) == PLUS - && REG_P (XEXP (XEXP (x, 0), 0)) - && (REGNO (XEXP (XEXP (x, 0), 0)) - < FIRST_PSEUDO_REGISTER) - && CONSTANT_P (XEXP (XEXP (x, 0), 1)))) - reg_equiv_address (i) = XEXP (x, 0), reg_equiv_mem (i) = 0; - else - { - /* Make a new stack slot. Then indicate that something - changed so we go back and recompute offsets for - eliminable registers because the allocation of memory - below might change some offset. reg_equiv_{mem,address} - will be set up for this pseudo on the next pass around - the loop. */ - reg_equiv_memory_loc (i) = 0; - reg_equiv_init (i) = 0; - alter_reg (i, -1, true); - } - } - - if (caller_save_needed) - setup_save_areas (); - - if (maybe_ne (starting_frame_size, 0) && crtl->stack_alignment_needed) - { - /* If we have a stack frame, we must align it now. The - stack size may be a part of the offset computation for - register elimination. So if this changes the stack size, - then repeat the elimination bookkeeping. We don't - realign when there is no stack, as that will cause a - stack frame when none is needed should - TARGET_STARTING_FRAME_OFFSET not be already aligned to - STACK_BOUNDARY. */ - assign_stack_local (BLKmode, 0, crtl->stack_alignment_needed); - } - /* If we allocated another stack slot, redo elimination bookkeeping. */ - if (something_was_spilled - || maybe_ne (starting_frame_size, get_frame_size ())) - { - if (update_eliminables_and_spill ()) - finish_spills (0); - continue; - } - - if (caller_save_needed) - { - save_call_clobbered_regs (); - /* That might have allocated new insn_chain structures. */ - reload_firstobj = XOBNEWVAR (&reload_obstack, char, 0); - } - - calculate_needs_all_insns (global); - - if (! ira_conflicts_p) - /* Don't do it for IRA. We need this info because we don't - change live_throughout and dead_or_set for chains when IRA - is used. */ - CLEAR_REG_SET (&spilled_pseudos); - - something_changed = 0; - - /* If we allocated any new memory locations, make another pass - since it might have changed elimination offsets. */ - if (something_was_spilled - || maybe_ne (starting_frame_size, get_frame_size ())) - something_changed = 1; - - /* Even if the frame size remained the same, we might still have - changed elimination offsets, e.g. if find_reloads called - force_const_mem requiring the back end to allocate a constant - pool base register that needs to be saved on the stack. */ - else if (!verify_initial_elim_offsets ()) - something_changed = 1; - - if (update_eliminables_and_spill ()) - { - finish_spills (0); - something_changed = 1; - } - else - { - select_reload_regs (); - if (failure) - goto failed; - if (insns_need_reload) - something_changed |= finish_spills (global); - } - - if (! something_changed) - break; - - if (caller_save_needed) - delete_caller_save_insns (); - - obstack_free (&reload_obstack, reload_firstobj); - } - - /* If global-alloc was run, notify it of any register eliminations we have - done. */ - if (global) - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->can_eliminate) - mark_elimination (ep->from, ep->to); - - remove_init_insns (); - - /* Use the reload registers where necessary - by generating move instructions to move the must-be-register - values into or out of the reload registers. */ - - if (insns_need_reload != 0 || something_needs_elimination - || something_needs_operands_changed) - { - poly_int64 old_frame_size = get_frame_size (); - - reload_as_needed (global); - - gcc_assert (known_eq (old_frame_size, get_frame_size ())); - - gcc_assert (verify_initial_elim_offsets ()); - } - - /* If we were able to eliminate the frame pointer, show that it is no - longer live at the start of any basic block. If it ls live by - virtue of being in a pseudo, that pseudo will be marked live - and hence the frame pointer will be known to be live via that - pseudo. */ - - if (! frame_pointer_needed) - FOR_EACH_BB_FN (bb, cfun) - bitmap_clear_bit (df_get_live_in (bb), HARD_FRAME_POINTER_REGNUM); - - /* Come here (with failure set nonzero) if we can't get enough spill - regs. */ - failed: - - CLEAR_REG_SET (&changed_allocation_pseudos); - CLEAR_REG_SET (&spilled_pseudos); - reload_in_progress = 0; - - /* Now eliminate all pseudo regs by modifying them into - their equivalent memory references. - The REG-rtx's for the pseudos are modified in place, - so all insns that used to refer to them now refer to memory. - - For a reg that has a reg_equiv_address, all those insns - were changed by reloading so that no insns refer to it any longer; - but the DECL_RTL of a variable decl may refer to it, - and if so this causes the debugging info to mention the variable. */ - - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - { - rtx addr = 0; - - if (reg_equiv_mem (i)) - addr = XEXP (reg_equiv_mem (i), 0); - - if (reg_equiv_address (i)) - addr = reg_equiv_address (i); - - if (addr) - { - if (reg_renumber[i] < 0) - { - rtx reg = regno_reg_rtx[i]; - - REG_USERVAR_P (reg) = 0; - PUT_CODE (reg, MEM); - XEXP (reg, 0) = addr; - if (reg_equiv_memory_loc (i)) - MEM_COPY_ATTRIBUTES (reg, reg_equiv_memory_loc (i)); - else - MEM_ATTRS (reg) = 0; - MEM_NOTRAP_P (reg) = 1; - } - else if (reg_equiv_mem (i)) - XEXP (reg_equiv_mem (i), 0) = addr; - } - - /* We don't want complex addressing modes in debug insns - if simpler ones will do, so delegitimize equivalences - in debug insns. */ - if (MAY_HAVE_DEBUG_BIND_INSNS && reg_renumber[i] < 0) - { - rtx reg = regno_reg_rtx[i]; - rtx equiv = 0; - df_ref use, next; - - if (reg_equiv_constant (i)) - equiv = reg_equiv_constant (i); - else if (reg_equiv_invariant (i)) - equiv = reg_equiv_invariant (i); - else if (reg && MEM_P (reg)) - equiv = targetm.delegitimize_address (reg); - else if (reg && REG_P (reg) && (int)REGNO (reg) != i) - equiv = reg; - - if (equiv == reg) - continue; - - for (use = DF_REG_USE_CHAIN (i); use; use = next) - { - insn = DF_REF_INSN (use); - - /* Make sure the next ref is for a different instruction, - so that we're not affected by the rescan. */ - next = DF_REF_NEXT_REG (use); - while (next && DF_REF_INSN (next) == insn) - next = DF_REF_NEXT_REG (next); - - if (DEBUG_BIND_INSN_P (insn)) - { - if (!equiv) - { - INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC (); - df_insn_rescan_debug_internal (insn); - } - else - INSN_VAR_LOCATION_LOC (insn) - = simplify_replace_rtx (INSN_VAR_LOCATION_LOC (insn), - reg, equiv); - } - } - } - } - - /* We must set reload_completed now since the cleanup_subreg_operands call - below will re-recognize each insn and reload may have generated insns - which are only valid during and after reload. */ - reload_completed = 1; - - /* Make a pass over all the insns and delete all USEs which we inserted - only to tag a REG_EQUAL note on them. Remove all REG_DEAD and REG_UNUSED - notes. Delete all CLOBBER insns, except those that refer to the return - value and the special mem:BLK CLOBBERs added to prevent the scheduler - from misarranging variable-array code, and simplify (subreg (reg)) - operands. Strip and regenerate REG_INC notes that may have been moved - around. */ - - for (insn = first; insn; insn = NEXT_INSN (insn)) - if (INSN_P (insn)) - { - rtx *pnote; - - if (CALL_P (insn)) - replace_pseudos_in (& CALL_INSN_FUNCTION_USAGE (insn), - VOIDmode, CALL_INSN_FUNCTION_USAGE (insn)); - - if ((GET_CODE (PATTERN (insn)) == USE - /* We mark with QImode USEs introduced by reload itself. */ - && (GET_MODE (insn) == QImode - || find_reg_note (insn, REG_EQUAL, NULL_RTX))) - || (GET_CODE (PATTERN (insn)) == CLOBBER - && (!MEM_P (XEXP (PATTERN (insn), 0)) - || GET_MODE (XEXP (PATTERN (insn), 0)) != BLKmode - || (GET_CODE (XEXP (XEXP (PATTERN (insn), 0), 0)) != SCRATCH - && XEXP (XEXP (PATTERN (insn), 0), 0) - != stack_pointer_rtx)) - && (!REG_P (XEXP (PATTERN (insn), 0)) - || ! REG_FUNCTION_VALUE_P (XEXP (PATTERN (insn), 0))))) - { - delete_insn (insn); - continue; - } - - /* Some CLOBBERs may survive until here and still reference unassigned - pseudos with const equivalent, which may in turn cause ICE in later - passes if the reference remains in place. */ - if (GET_CODE (PATTERN (insn)) == CLOBBER) - replace_pseudos_in (& XEXP (PATTERN (insn), 0), - VOIDmode, PATTERN (insn)); - - /* Discard obvious no-ops, even without -O. This optimization - is fast and doesn't interfere with debugging. */ - if (NONJUMP_INSN_P (insn) - && GET_CODE (PATTERN (insn)) == SET - && REG_P (SET_SRC (PATTERN (insn))) - && REG_P (SET_DEST (PATTERN (insn))) - && (REGNO (SET_SRC (PATTERN (insn))) - == REGNO (SET_DEST (PATTERN (insn))))) - { - delete_insn (insn); - continue; - } - - pnote = ®_NOTES (insn); - while (*pnote != 0) - { - if (REG_NOTE_KIND (*pnote) == REG_DEAD - || REG_NOTE_KIND (*pnote) == REG_UNUSED - || REG_NOTE_KIND (*pnote) == REG_INC) - *pnote = XEXP (*pnote, 1); - else - pnote = &XEXP (*pnote, 1); - } - - if (AUTO_INC_DEC) - add_auto_inc_notes (insn, PATTERN (insn)); - - /* Simplify (subreg (reg)) if it appears as an operand. */ - cleanup_subreg_operands (insn); - - /* Clean up invalid ASMs so that they don't confuse later passes. - See PR 21299. */ - if (asm_noperands (PATTERN (insn)) >= 0) - { - extract_insn (insn); - if (!constrain_operands (1, get_enabled_alternatives (insn))) - { - error_for_asm (insn, - "%<asm%> operand has impossible constraints"); - delete_insn (insn); - continue; - } - } - } - - free (temp_pseudo_reg_arr); - - /* Indicate that we no longer have known memory locations or constants. */ - free_reg_equiv (); - - free (reg_max_ref_mode); - free (reg_old_renumber); - free (pseudo_previous_regs); - free (pseudo_forbidden_regs); - - CLEAR_HARD_REG_SET (used_spill_regs); - for (i = 0; i < n_spills; i++) - SET_HARD_REG_BIT (used_spill_regs, spill_regs[i]); - - /* Free all the insn_chain structures at once. */ - obstack_free (&reload_obstack, reload_startobj); - unused_insn_chains = 0; - - inserted = fixup_abnormal_edges (); - - /* We've possibly turned single trapping insn into multiple ones. */ - if (cfun->can_throw_non_call_exceptions) - { - auto_sbitmap blocks (last_basic_block_for_fn (cfun)); - bitmap_ones (blocks); - find_many_sub_basic_blocks (blocks); - } - - if (inserted) - commit_edge_insertions (); - - /* Replacing pseudos with their memory equivalents might have - created shared rtx. Subsequent passes would get confused - by this, so unshare everything here. */ - unshare_all_rtl_again (first); - -#ifdef STACK_BOUNDARY - /* init_emit has set the alignment of the hard frame pointer - to STACK_BOUNDARY. It is very likely no longer valid if - the hard frame pointer was used for register allocation. */ - if (!frame_pointer_needed) - REGNO_POINTER_ALIGN (HARD_FRAME_POINTER_REGNUM) = BITS_PER_UNIT; -#endif - - substitute_stack.release (); - - gcc_assert (bitmap_empty_p (&spilled_pseudos)); - - reload_completed = !failure; - - return need_dce; -} - -/* Yet another special case. Unfortunately, reg-stack forces people to - write incorrect clobbers in asm statements. These clobbers must not - cause the register to appear in bad_spill_regs, otherwise we'll call - fatal_insn later. We clear the corresponding regnos in the live - register sets to avoid this. - The whole thing is rather sick, I'm afraid. */ - -static void -maybe_fix_stack_asms (void) -{ -#ifdef STACK_REGS - const char *constraints[MAX_RECOG_OPERANDS]; - machine_mode operand_mode[MAX_RECOG_OPERANDS]; - class insn_chain *chain; - - for (chain = reload_insn_chain; chain != 0; chain = chain->next) - { - int i, noperands; - HARD_REG_SET clobbered, allowed; - rtx pat; - - if (! INSN_P (chain->insn) - || (noperands = asm_noperands (PATTERN (chain->insn))) < 0) - continue; - pat = PATTERN (chain->insn); - if (GET_CODE (pat) != PARALLEL) - continue; - - CLEAR_HARD_REG_SET (clobbered); - CLEAR_HARD_REG_SET (allowed); - - /* First, make a mask of all stack regs that are clobbered. */ - for (i = 0; i < XVECLEN (pat, 0); i++) - { - rtx t = XVECEXP (pat, 0, i); - if (GET_CODE (t) == CLOBBER && STACK_REG_P (XEXP (t, 0))) - SET_HARD_REG_BIT (clobbered, REGNO (XEXP (t, 0))); - } - - /* Get the operand values and constraints out of the insn. */ - decode_asm_operands (pat, recog_data.operand, recog_data.operand_loc, - constraints, operand_mode, NULL); - - /* For every operand, see what registers are allowed. */ - for (i = 0; i < noperands; i++) - { - const char *p = constraints[i]; - /* For every alternative, we compute the class of registers allowed - for reloading in CLS, and merge its contents into the reg set - ALLOWED. */ - int cls = (int) NO_REGS; - - for (;;) - { - char c = *p; - - if (c == '\0' || c == ',' || c == '#') - { - /* End of one alternative - mark the regs in the current - class, and reset the class. */ - allowed |= reg_class_contents[cls]; - cls = NO_REGS; - p++; - if (c == '#') - do { - c = *p++; - } while (c != '\0' && c != ','); - if (c == '\0') - break; - continue; - } - - switch (c) - { - case 'g': - cls = (int) reg_class_subunion[cls][(int) GENERAL_REGS]; - break; - - default: - enum constraint_num cn = lookup_constraint (p); - if (insn_extra_address_constraint (cn)) - cls = (int) reg_class_subunion[cls] - [(int) base_reg_class (VOIDmode, ADDR_SPACE_GENERIC, - ADDRESS, SCRATCH)]; - else - cls = (int) reg_class_subunion[cls] - [reg_class_for_constraint (cn)]; - break; - } - p += CONSTRAINT_LEN (c, p); - } - } - /* Those of the registers which are clobbered, but allowed by the - constraints, must be usable as reload registers. So clear them - out of the life information. */ - allowed &= clobbered; - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (TEST_HARD_REG_BIT (allowed, i)) - { - CLEAR_REGNO_REG_SET (&chain->live_throughout, i); - CLEAR_REGNO_REG_SET (&chain->dead_or_set, i); - } - } - -#endif -} - -/* Copy the global variables n_reloads and rld into the corresponding elts - of CHAIN. */ -static void -copy_reloads (class insn_chain *chain) -{ - chain->n_reloads = n_reloads; - chain->rld = XOBNEWVEC (&reload_obstack, struct reload, n_reloads); - memcpy (chain->rld, rld, n_reloads * sizeof (struct reload)); - reload_insn_firstobj = XOBNEWVAR (&reload_obstack, char, 0); -} - -/* Walk the chain of insns, and determine for each whether it needs reloads - and/or eliminations. Build the corresponding insns_need_reload list, and - set something_needs_elimination as appropriate. */ -static void -calculate_needs_all_insns (int global) -{ - class insn_chain **pprev_reload = &insns_need_reload; - class insn_chain *chain, *next = 0; - - something_needs_elimination = 0; - - reload_insn_firstobj = XOBNEWVAR (&reload_obstack, char, 0); - for (chain = reload_insn_chain; chain != 0; chain = next) - { - rtx_insn *insn = chain->insn; - - next = chain->next; - - /* Clear out the shortcuts. */ - chain->n_reloads = 0; - chain->need_elim = 0; - chain->need_reload = 0; - chain->need_operand_change = 0; - - /* If this is a label, a JUMP_INSN, or has REG_NOTES (which might - include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see - what effects this has on the known offsets at labels. */ - - if (LABEL_P (insn) || JUMP_P (insn) || JUMP_TABLE_DATA_P (insn) - || (INSN_P (insn) && REG_NOTES (insn) != 0)) - set_label_offsets (insn, insn, 0); - - if (INSN_P (insn)) - { - rtx old_body = PATTERN (insn); - int old_code = INSN_CODE (insn); - rtx old_notes = REG_NOTES (insn); - int did_elimination = 0; - int operands_changed = 0; - - /* Skip insns that only set an equivalence. */ - if (will_delete_init_insn_p (insn)) - continue; - - /* If needed, eliminate any eliminable registers. */ - if (num_eliminable || num_eliminable_invariants) - did_elimination = eliminate_regs_in_insn (insn, 0); - - /* Analyze the instruction. */ - operands_changed = find_reloads (insn, 0, spill_indirect_levels, - global, spill_reg_order); - - /* If a no-op set needs more than one reload, this is likely - to be something that needs input address reloads. We - can't get rid of this cleanly later, and it is of no use - anyway, so discard it now. - We only do this when expensive_optimizations is enabled, - since this complements reload inheritance / output - reload deletion, and it can make debugging harder. */ - if (flag_expensive_optimizations && n_reloads > 1) - { - rtx set = single_set (insn); - if (set - && - ((SET_SRC (set) == SET_DEST (set) - && REG_P (SET_SRC (set)) - && REGNO (SET_SRC (set)) >= FIRST_PSEUDO_REGISTER) - || (REG_P (SET_SRC (set)) && REG_P (SET_DEST (set)) - && reg_renumber[REGNO (SET_SRC (set))] < 0 - && reg_renumber[REGNO (SET_DEST (set))] < 0 - && reg_equiv_memory_loc (REGNO (SET_SRC (set))) != NULL - && reg_equiv_memory_loc (REGNO (SET_DEST (set))) != NULL - && rtx_equal_p (reg_equiv_memory_loc (REGNO (SET_SRC (set))), - reg_equiv_memory_loc (REGNO (SET_DEST (set))))))) - { - if (ira_conflicts_p) - /* Inform IRA about the insn deletion. */ - ira_mark_memory_move_deletion (REGNO (SET_DEST (set)), - REGNO (SET_SRC (set))); - delete_insn (insn); - /* Delete it from the reload chain. */ - if (chain->prev) - chain->prev->next = next; - else - reload_insn_chain = next; - if (next) - next->prev = chain->prev; - chain->next = unused_insn_chains; - unused_insn_chains = chain; - continue; - } - } - if (num_eliminable) - update_eliminable_offsets (); - - /* Remember for later shortcuts which insns had any reloads or - register eliminations. */ - chain->need_elim = did_elimination; - chain->need_reload = n_reloads > 0; - chain->need_operand_change = operands_changed; - - /* Discard any register replacements done. */ - if (did_elimination) - { - obstack_free (&reload_obstack, reload_insn_firstobj); - PATTERN (insn) = old_body; - INSN_CODE (insn) = old_code; - REG_NOTES (insn) = old_notes; - something_needs_elimination = 1; - } - - something_needs_operands_changed |= operands_changed; - - if (n_reloads != 0) - { - copy_reloads (chain); - *pprev_reload = chain; - pprev_reload = &chain->next_need_reload; - } - } - } - *pprev_reload = 0; -} - -/* This function is called from the register allocator to set up estimates - for the cost of eliminating pseudos which have REG_EQUIV equivalences to - an invariant. The structure is similar to calculate_needs_all_insns. */ - -void -calculate_elim_costs_all_insns (void) -{ - int *reg_equiv_init_cost; - basic_block bb; - int i; - - reg_equiv_init_cost = XCNEWVEC (int, max_regno); - init_elim_table (); - init_eliminable_invariants (get_insns (), false); - - set_initial_elim_offsets (); - set_initial_label_offsets (); - - FOR_EACH_BB_FN (bb, cfun) - { - rtx_insn *insn; - elim_bb = bb; - - FOR_BB_INSNS (bb, insn) - { - /* If this is a label, a JUMP_INSN, or has REG_NOTES (which might - include REG_LABEL_OPERAND and REG_LABEL_TARGET), we need to see - what effects this has on the known offsets at labels. */ - - if (LABEL_P (insn) || JUMP_P (insn) || JUMP_TABLE_DATA_P (insn) - || (INSN_P (insn) && REG_NOTES (insn) != 0)) - set_label_offsets (insn, insn, 0); - - if (INSN_P (insn)) - { - rtx set = single_set (insn); - - /* Skip insns that only set an equivalence. */ - if (set && REG_P (SET_DEST (set)) - && reg_renumber[REGNO (SET_DEST (set))] < 0 - && (reg_equiv_constant (REGNO (SET_DEST (set))) - || reg_equiv_invariant (REGNO (SET_DEST (set))))) - { - unsigned regno = REGNO (SET_DEST (set)); - rtx_insn_list *init = reg_equiv_init (regno); - if (init) - { - rtx t = eliminate_regs_1 (SET_SRC (set), VOIDmode, insn, - false, true); - machine_mode mode = GET_MODE (SET_DEST (set)); - int cost = set_src_cost (t, mode, - optimize_bb_for_speed_p (bb)); - int freq = REG_FREQ_FROM_BB (bb); - - reg_equiv_init_cost[regno] = cost * freq; - continue; - } - } - /* If needed, eliminate any eliminable registers. */ - if (num_eliminable || num_eliminable_invariants) - elimination_costs_in_insn (insn); - - if (num_eliminable) - update_eliminable_offsets (); - } - } - } - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - { - if (reg_equiv_invariant (i)) - { - if (reg_equiv_init (i)) - { - int cost = reg_equiv_init_cost[i]; - if (dump_file) - fprintf (dump_file, - "Reg %d has equivalence, initial gains %d\n", i, cost); - if (cost != 0) - ira_adjust_equiv_reg_cost (i, cost); - } - else - { - if (dump_file) - fprintf (dump_file, - "Reg %d had equivalence, but can't be eliminated\n", - i); - ira_adjust_equiv_reg_cost (i, 0); - } - } - } - - free (reg_equiv_init_cost); - free (offsets_known_at); - free (offsets_at); - offsets_at = NULL; - offsets_known_at = NULL; -} - -/* Comparison function for qsort to decide which of two reloads - should be handled first. *P1 and *P2 are the reload numbers. */ - -static int -reload_reg_class_lower (const void *r1p, const void *r2p) -{ - int r1 = *(const short *) r1p, r2 = *(const short *) r2p; - int t; - - /* Consider required reloads before optional ones. */ - t = rld[r1].optional - rld[r2].optional; - if (t != 0) - return t; - - /* Count all solitary classes before non-solitary ones. */ - t = ((reg_class_size[(int) rld[r2].rclass] == 1) - - (reg_class_size[(int) rld[r1].rclass] == 1)); - if (t != 0) - return t; - - /* Aside from solitaires, consider all multi-reg groups first. */ - t = rld[r2].nregs - rld[r1].nregs; - if (t != 0) - return t; - - /* Consider reloads in order of increasing reg-class number. */ - t = (int) rld[r1].rclass - (int) rld[r2].rclass; - if (t != 0) - return t; - - /* If reloads are equally urgent, sort by reload number, - so that the results of qsort leave nothing to chance. */ - return r1 - r2; -} - -/* The cost of spilling each hard reg. */ -static int spill_cost[FIRST_PSEUDO_REGISTER]; - -/* When spilling multiple hard registers, we use SPILL_COST for the first - spilled hard reg and SPILL_ADD_COST for subsequent regs. SPILL_ADD_COST - only the first hard reg for a multi-reg pseudo. */ -static int spill_add_cost[FIRST_PSEUDO_REGISTER]; - -/* Map of hard regno to pseudo regno currently occupying the hard - reg. */ -static int hard_regno_to_pseudo_regno[FIRST_PSEUDO_REGISTER]; - -/* Update the spill cost arrays, considering that pseudo REG is live. */ - -static void -count_pseudo (int reg) -{ - int freq = REG_FREQ (reg); - int r = reg_renumber[reg]; - int nregs; - - /* Ignore spilled pseudo-registers which can be here only if IRA is used. */ - if (ira_conflicts_p && r < 0) - return; - - if (REGNO_REG_SET_P (&pseudos_counted, reg) - || REGNO_REG_SET_P (&spilled_pseudos, reg)) - return; - - SET_REGNO_REG_SET (&pseudos_counted, reg); - - gcc_assert (r >= 0); - - spill_add_cost[r] += freq; - nregs = hard_regno_nregs (r, PSEUDO_REGNO_MODE (reg)); - while (nregs-- > 0) - { - hard_regno_to_pseudo_regno[r + nregs] = reg; - spill_cost[r + nregs] += freq; - } -} - -/* Calculate the SPILL_COST and SPILL_ADD_COST arrays and determine the - contents of BAD_SPILL_REGS for the insn described by CHAIN. */ - -static void -order_regs_for_reload (class insn_chain *chain) -{ - unsigned i; - HARD_REG_SET used_by_pseudos; - HARD_REG_SET used_by_pseudos2; - reg_set_iterator rsi; - - bad_spill_regs = fixed_reg_set; - - memset (spill_cost, 0, sizeof spill_cost); - memset (spill_add_cost, 0, sizeof spill_add_cost); - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - hard_regno_to_pseudo_regno[i] = -1; - - /* Count number of uses of each hard reg by pseudo regs allocated to it - and then order them by decreasing use. First exclude hard registers - that are live in or across this insn. */ - - REG_SET_TO_HARD_REG_SET (used_by_pseudos, &chain->live_throughout); - REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set); - bad_spill_regs |= used_by_pseudos; - bad_spill_regs |= used_by_pseudos2; - - /* Now find out which pseudos are allocated to it, and update - hard_reg_n_uses. */ - CLEAR_REG_SET (&pseudos_counted); - - EXECUTE_IF_SET_IN_REG_SET - (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi) - { - count_pseudo (i); - } - EXECUTE_IF_SET_IN_REG_SET - (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi) - { - count_pseudo (i); - } - CLEAR_REG_SET (&pseudos_counted); -} - -/* Vector of reload-numbers showing the order in which the reloads should - be processed. */ -static short reload_order[MAX_RELOADS]; - -/* This is used to keep track of the spill regs used in one insn. */ -static HARD_REG_SET used_spill_regs_local; - -/* We decided to spill hard register SPILLED, which has a size of - SPILLED_NREGS. Determine how pseudo REG, which is live during the insn, - is affected. We will add it to SPILLED_PSEUDOS if necessary, and we will - update SPILL_COST/SPILL_ADD_COST. */ - -static void -count_spilled_pseudo (int spilled, int spilled_nregs, int reg) -{ - int freq = REG_FREQ (reg); - int r = reg_renumber[reg]; - int nregs; - - /* Ignore spilled pseudo-registers which can be here only if IRA is used. */ - if (ira_conflicts_p && r < 0) - return; - - gcc_assert (r >= 0); - - nregs = hard_regno_nregs (r, PSEUDO_REGNO_MODE (reg)); - - if (REGNO_REG_SET_P (&spilled_pseudos, reg) - || spilled + spilled_nregs <= r || r + nregs <= spilled) - return; - - SET_REGNO_REG_SET (&spilled_pseudos, reg); - - spill_add_cost[r] -= freq; - while (nregs-- > 0) - { - hard_regno_to_pseudo_regno[r + nregs] = -1; - spill_cost[r + nregs] -= freq; - } -} - -/* Find reload register to use for reload number ORDER. */ - -static int -find_reg (class insn_chain *chain, int order) -{ - int rnum = reload_order[order]; - struct reload *rl = rld + rnum; - int best_cost = INT_MAX; - int best_reg = -1; - unsigned int i, j, n; - int k; - HARD_REG_SET not_usable; - HARD_REG_SET used_by_other_reload; - reg_set_iterator rsi; - static int regno_pseudo_regs[FIRST_PSEUDO_REGISTER]; - static int best_regno_pseudo_regs[FIRST_PSEUDO_REGISTER]; - - not_usable = (bad_spill_regs - | bad_spill_regs_global - | ~reg_class_contents[rl->rclass]); - - CLEAR_HARD_REG_SET (used_by_other_reload); - for (k = 0; k < order; k++) - { - int other = reload_order[k]; - - if (rld[other].regno >= 0 && reloads_conflict (other, rnum)) - for (j = 0; j < rld[other].nregs; j++) - SET_HARD_REG_BIT (used_by_other_reload, rld[other].regno + j); - } - - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - { -#ifdef REG_ALLOC_ORDER - unsigned int regno = reg_alloc_order[i]; -#else - unsigned int regno = i; -#endif - - if (! TEST_HARD_REG_BIT (not_usable, regno) - && ! TEST_HARD_REG_BIT (used_by_other_reload, regno) - && targetm.hard_regno_mode_ok (regno, rl->mode)) - { - int this_cost = spill_cost[regno]; - int ok = 1; - unsigned int this_nregs = hard_regno_nregs (regno, rl->mode); - - for (j = 1; j < this_nregs; j++) - { - this_cost += spill_add_cost[regno + j]; - if ((TEST_HARD_REG_BIT (not_usable, regno + j)) - || TEST_HARD_REG_BIT (used_by_other_reload, regno + j)) - ok = 0; - } - if (! ok) - continue; - - if (ira_conflicts_p) - { - /* Ask IRA to find a better pseudo-register for - spilling. */ - for (n = j = 0; j < this_nregs; j++) - { - int r = hard_regno_to_pseudo_regno[regno + j]; - - if (r < 0) - continue; - if (n == 0 || regno_pseudo_regs[n - 1] != r) - regno_pseudo_regs[n++] = r; - } - regno_pseudo_regs[n++] = -1; - if (best_reg < 0 - || ira_better_spill_reload_regno_p (regno_pseudo_regs, - best_regno_pseudo_regs, - rl->in, rl->out, - chain->insn)) - { - best_reg = regno; - for (j = 0;; j++) - { - best_regno_pseudo_regs[j] = regno_pseudo_regs[j]; - if (regno_pseudo_regs[j] < 0) - break; - } - } - continue; - } - - if (rl->in && REG_P (rl->in) && REGNO (rl->in) == regno) - this_cost--; - if (rl->out && REG_P (rl->out) && REGNO (rl->out) == regno) - this_cost--; - if (this_cost < best_cost - /* Among registers with equal cost, prefer caller-saved ones, or - use REG_ALLOC_ORDER if it is defined. */ - || (this_cost == best_cost -#ifdef REG_ALLOC_ORDER - && (inv_reg_alloc_order[regno] - < inv_reg_alloc_order[best_reg]) -#else - && crtl->abi->clobbers_full_reg_p (regno) - && !crtl->abi->clobbers_full_reg_p (best_reg) -#endif - )) - { - best_reg = regno; - best_cost = this_cost; - } - } - } - if (best_reg == -1) - return 0; - - if (dump_file) - fprintf (dump_file, "Using reg %d for reload %d\n", best_reg, rnum); - - rl->nregs = hard_regno_nregs (best_reg, rl->mode); - rl->regno = best_reg; - - EXECUTE_IF_SET_IN_REG_SET - (&chain->live_throughout, FIRST_PSEUDO_REGISTER, j, rsi) - { - count_spilled_pseudo (best_reg, rl->nregs, j); - } - - EXECUTE_IF_SET_IN_REG_SET - (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, j, rsi) - { - count_spilled_pseudo (best_reg, rl->nregs, j); - } - - for (i = 0; i < rl->nregs; i++) - { - gcc_assert (spill_cost[best_reg + i] == 0); - gcc_assert (spill_add_cost[best_reg + i] == 0); - gcc_assert (hard_regno_to_pseudo_regno[best_reg + i] == -1); - SET_HARD_REG_BIT (used_spill_regs_local, best_reg + i); - } - return 1; -} - -/* Find more reload regs to satisfy the remaining need of an insn, which - is given by CHAIN. - Do it by ascending class number, since otherwise a reg - might be spilled for a big class and might fail to count - for a smaller class even though it belongs to that class. */ - -static void -find_reload_regs (class insn_chain *chain) -{ - int i; - - /* In order to be certain of getting the registers we need, - we must sort the reloads into order of increasing register class. - Then our grabbing of reload registers will parallel the process - that provided the reload registers. */ - for (i = 0; i < chain->n_reloads; i++) - { - /* Show whether this reload already has a hard reg. */ - if (chain->rld[i].reg_rtx) - { - chain->rld[i].regno = REGNO (chain->rld[i].reg_rtx); - chain->rld[i].nregs = REG_NREGS (chain->rld[i].reg_rtx); - } - else - chain->rld[i].regno = -1; - reload_order[i] = i; - } - - n_reloads = chain->n_reloads; - memcpy (rld, chain->rld, n_reloads * sizeof (struct reload)); - - CLEAR_HARD_REG_SET (used_spill_regs_local); - - if (dump_file) - fprintf (dump_file, "Spilling for insn %d.\n", INSN_UID (chain->insn)); - - qsort (reload_order, n_reloads, sizeof (short), reload_reg_class_lower); - - /* Compute the order of preference for hard registers to spill. */ - - order_regs_for_reload (chain); - - for (i = 0; i < n_reloads; i++) - { - int r = reload_order[i]; - - /* Ignore reloads that got marked inoperative. */ - if ((rld[r].out != 0 || rld[r].in != 0 || rld[r].secondary_p) - && ! rld[r].optional - && rld[r].regno == -1) - if (! find_reg (chain, i)) - { - if (dump_file) - fprintf (dump_file, "reload failure for reload %d\n", r); - spill_failure (chain->insn, rld[r].rclass); - failure = 1; - return; - } - } - - chain->used_spill_regs = used_spill_regs_local; - used_spill_regs |= used_spill_regs_local; - - memcpy (chain->rld, rld, n_reloads * sizeof (struct reload)); -} - -static void -select_reload_regs (void) -{ - class insn_chain *chain; - - /* Try to satisfy the needs for each insn. */ - for (chain = insns_need_reload; chain != 0; - chain = chain->next_need_reload) - find_reload_regs (chain); -} - -/* Delete all insns that were inserted by emit_caller_save_insns during - this iteration. */ -static void -delete_caller_save_insns (void) -{ - class insn_chain *c = reload_insn_chain; - - while (c != 0) - { - while (c != 0 && c->is_caller_save_insn) - { - class insn_chain *next = c->next; - rtx_insn *insn = c->insn; - - if (c == reload_insn_chain) - reload_insn_chain = next; - delete_insn (insn); - - if (next) - next->prev = c->prev; - if (c->prev) - c->prev->next = next; - c->next = unused_insn_chains; - unused_insn_chains = c; - c = next; - } - if (c != 0) - c = c->next; - } -} - -/* Handle the failure to find a register to spill. - INSN should be one of the insns which needed this particular spill reg. */ - -static void -spill_failure (rtx_insn *insn, enum reg_class rclass) -{ - if (asm_noperands (PATTERN (insn)) >= 0) - error_for_asm (insn, "cannot find a register in class %qs while " - "reloading %<asm%>", - reg_class_names[rclass]); - else - { - error ("unable to find a register to spill in class %qs", - reg_class_names[rclass]); - - if (dump_file) - { - fprintf (dump_file, "\nReloads for insn # %d\n", INSN_UID (insn)); - debug_reload_to_stream (dump_file); - } - fatal_insn ("this is the insn:", insn); - } -} - -/* Delete an unneeded INSN and any previous insns who sole purpose is loading - data that is dead in INSN. */ - -static void -delete_dead_insn (rtx_insn *insn) -{ - rtx_insn *prev = prev_active_insn (insn); - rtx prev_dest; - - /* If the previous insn sets a register that dies in our insn make - a note that we want to run DCE immediately after reload. - - We used to delete the previous insn & recurse, but that's wrong for - block local equivalences. Instead of trying to figure out the exact - circumstances where we can delete the potentially dead insns, just - let DCE do the job. */ - if (prev && BLOCK_FOR_INSN (prev) == BLOCK_FOR_INSN (insn) - && GET_CODE (PATTERN (prev)) == SET - && (prev_dest = SET_DEST (PATTERN (prev)), REG_P (prev_dest)) - && reg_mentioned_p (prev_dest, PATTERN (insn)) - && find_regno_note (insn, REG_DEAD, REGNO (prev_dest)) - && ! side_effects_p (SET_SRC (PATTERN (prev)))) - need_dce = 1; - - SET_INSN_DELETED (insn); -} - -/* Modify the home of pseudo-reg I. - The new home is present in reg_renumber[I]. - - FROM_REG may be the hard reg that the pseudo-reg is being spilled from; - or it may be -1, meaning there is none or it is not relevant. - This is used so that all pseudos spilled from a given hard reg - can share one stack slot. */ - -static void -alter_reg (int i, int from_reg, bool dont_share_p) -{ - /* When outputting an inline function, this can happen - for a reg that isn't actually used. */ - if (regno_reg_rtx[i] == 0) - return; - - /* If the reg got changed to a MEM at rtl-generation time, - ignore it. */ - if (!REG_P (regno_reg_rtx[i])) - return; - - /* Modify the reg-rtx to contain the new hard reg - number or else to contain its pseudo reg number. */ - SET_REGNO (regno_reg_rtx[i], - reg_renumber[i] >= 0 ? reg_renumber[i] : i); - - /* If we have a pseudo that is needed but has no hard reg or equivalent, - allocate a stack slot for it. */ - - if (reg_renumber[i] < 0 - && REG_N_REFS (i) > 0 - && reg_equiv_constant (i) == 0 - && (reg_equiv_invariant (i) == 0 - || reg_equiv_init (i) == 0) - && reg_equiv_memory_loc (i) == 0) - { - rtx x = NULL_RTX; - machine_mode mode = GET_MODE (regno_reg_rtx[i]); - poly_uint64 inherent_size = GET_MODE_SIZE (mode); - unsigned int inherent_align = GET_MODE_ALIGNMENT (mode); - machine_mode wider_mode = wider_subreg_mode (mode, reg_max_ref_mode[i]); - poly_uint64 total_size = GET_MODE_SIZE (wider_mode); - /* ??? Seems strange to derive the minimum alignment from the size, - but that's the traditional behavior. For polynomial-size modes, - the natural extension is to use the minimum possible size. */ - unsigned int min_align - = constant_lower_bound (GET_MODE_BITSIZE (reg_max_ref_mode[i])); - poly_int64 adjust = 0; - - something_was_spilled = true; - - if (ira_conflicts_p) - { - /* Mark the spill for IRA. */ - SET_REGNO_REG_SET (&spilled_pseudos, i); - if (!dont_share_p) - x = ira_reuse_stack_slot (i, inherent_size, total_size); - } - - if (x) - ; - - /* Each pseudo reg has an inherent size which comes from its own mode, - and a total size which provides room for paradoxical subregs - which refer to the pseudo reg in wider modes. - - We can use a slot already allocated if it provides both - enough inherent space and enough total space. - Otherwise, we allocate a new slot, making sure that it has no less - inherent space, and no less total space, then the previous slot. */ - else if (from_reg == -1 || (!dont_share_p && ira_conflicts_p)) - { - rtx stack_slot; - - /* The sizes are taken from a subreg operation, which guarantees - that they're ordered. */ - gcc_checking_assert (ordered_p (total_size, inherent_size)); - - /* No known place to spill from => no slot to reuse. */ - x = assign_stack_local (mode, total_size, - min_align > inherent_align - || maybe_gt (total_size, inherent_size) - ? -1 : 0); - - stack_slot = x; - - /* Cancel the big-endian correction done in assign_stack_local. - Get the address of the beginning of the slot. This is so we - can do a big-endian correction unconditionally below. */ - if (BYTES_BIG_ENDIAN) - { - adjust = inherent_size - total_size; - if (maybe_ne (adjust, 0)) - { - poly_uint64 total_bits = total_size * BITS_PER_UNIT; - machine_mode mem_mode - = int_mode_for_size (total_bits, 1).else_blk (); - stack_slot = adjust_address_nv (x, mem_mode, adjust); - } - } - - if (! dont_share_p && ira_conflicts_p) - /* Inform IRA about allocation a new stack slot. */ - ira_mark_new_stack_slot (stack_slot, i, total_size); - } - - /* Reuse a stack slot if possible. */ - else if (spill_stack_slot[from_reg] != 0 - && known_ge (spill_stack_slot_width[from_reg], total_size) - && known_ge (GET_MODE_SIZE - (GET_MODE (spill_stack_slot[from_reg])), - inherent_size) - && MEM_ALIGN (spill_stack_slot[from_reg]) >= min_align) - x = spill_stack_slot[from_reg]; - - /* Allocate a bigger slot. */ - else - { - /* Compute maximum size needed, both for inherent size - and for total size. */ - rtx stack_slot; - - if (spill_stack_slot[from_reg]) - { - if (partial_subreg_p (mode, - GET_MODE (spill_stack_slot[from_reg]))) - mode = GET_MODE (spill_stack_slot[from_reg]); - total_size = ordered_max (total_size, - spill_stack_slot_width[from_reg]); - if (MEM_ALIGN (spill_stack_slot[from_reg]) > min_align) - min_align = MEM_ALIGN (spill_stack_slot[from_reg]); - } - - /* The sizes are taken from a subreg operation, which guarantees - that they're ordered. */ - gcc_checking_assert (ordered_p (total_size, inherent_size)); - - /* Make a slot with that size. */ - x = assign_stack_local (mode, total_size, - min_align > inherent_align - || maybe_gt (total_size, inherent_size) - ? -1 : 0); - stack_slot = x; - - /* Cancel the big-endian correction done in assign_stack_local. - Get the address of the beginning of the slot. This is so we - can do a big-endian correction unconditionally below. */ - if (BYTES_BIG_ENDIAN) - { - adjust = GET_MODE_SIZE (mode) - total_size; - if (maybe_ne (adjust, 0)) - { - poly_uint64 total_bits = total_size * BITS_PER_UNIT; - machine_mode mem_mode - = int_mode_for_size (total_bits, 1).else_blk (); - stack_slot = adjust_address_nv (x, mem_mode, adjust); - } - } - - spill_stack_slot[from_reg] = stack_slot; - spill_stack_slot_width[from_reg] = total_size; - } - - /* On a big endian machine, the "address" of the slot - is the address of the low part that fits its inherent mode. */ - adjust += subreg_size_lowpart_offset (inherent_size, total_size); - - /* If we have any adjustment to make, or if the stack slot is the - wrong mode, make a new stack slot. */ - x = adjust_address_nv (x, GET_MODE (regno_reg_rtx[i]), adjust); - - /* Set all of the memory attributes as appropriate for a spill. */ - set_mem_attrs_for_spill (x); - - /* Save the stack slot for later. */ - reg_equiv_memory_loc (i) = x; - } -} - -/* Mark the slots in regs_ever_live for the hard regs used by - pseudo-reg number REGNO, accessed in MODE. */ - -static void -mark_home_live_1 (int regno, machine_mode mode) -{ - int i, lim; - - i = reg_renumber[regno]; - if (i < 0) - return; - lim = end_hard_regno (mode, i); - while (i < lim) - df_set_regs_ever_live (i++, true); -} - -/* Mark the slots in regs_ever_live for the hard regs - used by pseudo-reg number REGNO. */ - -void -mark_home_live (int regno) -{ - if (reg_renumber[regno] >= 0) - mark_home_live_1 (regno, PSEUDO_REGNO_MODE (regno)); -} - -/* This function handles the tracking of elimination offsets around branches. - - X is a piece of RTL being scanned. - - INSN is the insn that it came from, if any. - - INITIAL_P is nonzero if we are to set the offset to be the initial - offset and zero if we are setting the offset of the label to be the - current offset. */ - -static void -set_label_offsets (rtx x, rtx_insn *insn, int initial_p) -{ - enum rtx_code code = GET_CODE (x); - rtx tem; - unsigned int i; - struct elim_table *p; - - switch (code) - { - case LABEL_REF: - if (LABEL_REF_NONLOCAL_P (x)) - return; - - x = label_ref_label (x); - - /* fall through */ - - case CODE_LABEL: - /* If we know nothing about this label, set the desired offsets. Note - that this sets the offset at a label to be the offset before a label - if we don't know anything about the label. This is not correct for - the label after a BARRIER, but is the best guess we can make. If - we guessed wrong, we will suppress an elimination that might have - been possible had we been able to guess correctly. */ - - if (! offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num]) - { - for (i = 0; i < NUM_ELIMINABLE_REGS; i++) - offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i] - = (initial_p ? reg_eliminate[i].initial_offset - : reg_eliminate[i].offset); - offsets_known_at[CODE_LABEL_NUMBER (x) - first_label_num] = 1; - } - - /* Otherwise, if this is the definition of a label and it is - preceded by a BARRIER, set our offsets to the known offset of - that label. */ - - else if (x == insn - && (tem = prev_nonnote_insn (insn)) != 0 - && BARRIER_P (tem)) - set_offsets_for_label (insn); - else - /* If neither of the above cases is true, compare each offset - with those previously recorded and suppress any eliminations - where the offsets disagree. */ - - for (i = 0; i < NUM_ELIMINABLE_REGS; i++) - if (maybe_ne (offsets_at[CODE_LABEL_NUMBER (x) - first_label_num][i], - (initial_p ? reg_eliminate[i].initial_offset - : reg_eliminate[i].offset))) - reg_eliminate[i].can_eliminate = 0; - - return; - - case JUMP_TABLE_DATA: - set_label_offsets (PATTERN (insn), insn, initial_p); - return; - - case JUMP_INSN: - set_label_offsets (PATTERN (insn), insn, initial_p); - - /* fall through */ - - case INSN: - case CALL_INSN: - /* Any labels mentioned in REG_LABEL_OPERAND notes can be branched - to indirectly and hence must have all eliminations at their - initial offsets. */ - for (tem = REG_NOTES (x); tem; tem = XEXP (tem, 1)) - if (REG_NOTE_KIND (tem) == REG_LABEL_OPERAND) - set_label_offsets (XEXP (tem, 0), insn, 1); - return; - - case PARALLEL: - case ADDR_VEC: - case ADDR_DIFF_VEC: - /* Each of the labels in the parallel or address vector must be - at their initial offsets. We want the first field for PARALLEL - and ADDR_VEC and the second field for ADDR_DIFF_VEC. */ - - for (i = 0; i < (unsigned) XVECLEN (x, code == ADDR_DIFF_VEC); i++) - set_label_offsets (XVECEXP (x, code == ADDR_DIFF_VEC, i), - insn, initial_p); - return; - - case SET: - /* We only care about setting PC. If the source is not RETURN, - IF_THEN_ELSE, or a label, disable any eliminations not at - their initial offsets. Similarly if any arm of the IF_THEN_ELSE - isn't one of those possibilities. For branches to a label, - call ourselves recursively. - - Note that this can disable elimination unnecessarily when we have - a non-local goto since it will look like a non-constant jump to - someplace in the current function. This isn't a significant - problem since such jumps will normally be when all elimination - pairs are back to their initial offsets. */ - - if (SET_DEST (x) != pc_rtx) - return; - - switch (GET_CODE (SET_SRC (x))) - { - case PC: - case RETURN: - return; - - case LABEL_REF: - set_label_offsets (SET_SRC (x), insn, initial_p); - return; - - case IF_THEN_ELSE: - tem = XEXP (SET_SRC (x), 1); - if (GET_CODE (tem) == LABEL_REF) - set_label_offsets (label_ref_label (tem), insn, initial_p); - else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN) - break; - - tem = XEXP (SET_SRC (x), 2); - if (GET_CODE (tem) == LABEL_REF) - set_label_offsets (label_ref_label (tem), insn, initial_p); - else if (GET_CODE (tem) != PC && GET_CODE (tem) != RETURN) - break; - return; - - default: - break; - } - - /* If we reach here, all eliminations must be at their initial - offset because we are doing a jump to a variable address. */ - for (p = reg_eliminate; p < ®_eliminate[NUM_ELIMINABLE_REGS]; p++) - if (maybe_ne (p->offset, p->initial_offset)) - p->can_eliminate = 0; - break; - - default: - break; - } -} - -/* This function examines every reg that occurs in X and adjusts the - costs for its elimination which are gathered by IRA. INSN is the - insn in which X occurs. We do not recurse into MEM expressions. */ - -static void -note_reg_elim_costly (const_rtx x, rtx insn) -{ - subrtx_iterator::array_type array; - FOR_EACH_SUBRTX (iter, array, x, NONCONST) - { - const_rtx x = *iter; - if (MEM_P (x)) - iter.skip_subrtxes (); - else if (REG_P (x) - && REGNO (x) >= FIRST_PSEUDO_REGISTER - && reg_equiv_init (REGNO (x)) - && reg_equiv_invariant (REGNO (x))) - { - rtx t = reg_equiv_invariant (REGNO (x)); - rtx new_rtx = eliminate_regs_1 (t, Pmode, insn, true, true); - int cost = set_src_cost (new_rtx, Pmode, - optimize_bb_for_speed_p (elim_bb)); - int freq = REG_FREQ_FROM_BB (elim_bb); - - if (cost != 0) - ira_adjust_equiv_reg_cost (REGNO (x), -cost * freq); - } - } -} - -/* Scan X and replace any eliminable registers (such as fp) with a - replacement (such as sp), plus an offset. - - MEM_MODE is the mode of an enclosing MEM. We need this to know how - much to adjust a register for, e.g., PRE_DEC. Also, if we are inside a - MEM, we are allowed to replace a sum of a register and the constant zero - with the register, which we cannot do outside a MEM. In addition, we need - to record the fact that a register is referenced outside a MEM. - - If INSN is an insn, it is the insn containing X. If we replace a REG - in a SET_DEST with an equivalent MEM and INSN is nonzero, write a - CLOBBER of the pseudo after INSN so find_equiv_regs will know that - the REG is being modified. - - Alternatively, INSN may be a note (an EXPR_LIST or INSN_LIST). - That's used when we eliminate in expressions stored in notes. - This means, do not set ref_outside_mem even if the reference - is outside of MEMs. - - If FOR_COSTS is true, we are being called before reload in order to - estimate the costs of keeping registers with an equivalence unallocated. - - REG_EQUIV_MEM and REG_EQUIV_ADDRESS contain address that have had - replacements done assuming all offsets are at their initial values. If - they are not, or if REG_EQUIV_ADDRESS is nonzero for a pseudo we - encounter, return the actual location so that find_reloads will do - the proper thing. */ - -static rtx -eliminate_regs_1 (rtx x, machine_mode mem_mode, rtx insn, - bool may_use_invariant, bool for_costs) -{ - enum rtx_code code = GET_CODE (x); - struct elim_table *ep; - int regno; - rtx new_rtx; - int i, j; - const char *fmt; - int copied = 0; - - if (! current_function_decl) - return x; - - switch (code) - { - CASE_CONST_ANY: - case CONST: - case SYMBOL_REF: - case CODE_LABEL: - case PC: - case ASM_INPUT: - case ADDR_VEC: - case ADDR_DIFF_VEC: - case RETURN: - return x; - - case REG: - regno = REGNO (x); - - /* First handle the case where we encounter a bare register that - is eliminable. Replace it with a PLUS. */ - if (regno < FIRST_PSEUDO_REGISTER) - { - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; - ep++) - if (ep->from_rtx == x && ep->can_eliminate) - return plus_constant (Pmode, ep->to_rtx, ep->previous_offset); - - } - else if (reg_renumber && reg_renumber[regno] < 0 - && reg_equivs - && reg_equiv_invariant (regno)) - { - if (may_use_invariant || (insn && DEBUG_INSN_P (insn))) - return eliminate_regs_1 (copy_rtx (reg_equiv_invariant (regno)), - mem_mode, insn, true, for_costs); - /* There exists at least one use of REGNO that cannot be - eliminated. Prevent the defining insn from being deleted. */ - reg_equiv_init (regno) = NULL; - if (!for_costs) - alter_reg (regno, -1, true); - } - return x; - - /* You might think handling MINUS in a manner similar to PLUS is a - good idea. It is not. It has been tried multiple times and every - time the change has had to have been reverted. - - Other parts of reload know a PLUS is special (gen_reload for example) - and require special code to handle code a reloaded PLUS operand. - - Also consider backends where the flags register is clobbered by a - MINUS, but we can emit a PLUS that does not clobber flags (IA-32, - lea instruction comes to mind). If we try to reload a MINUS, we - may kill the flags register that was holding a useful value. - - So, please before trying to handle MINUS, consider reload as a - whole instead of this little section as well as the backend issues. */ - case PLUS: - /* If this is the sum of an eliminable register and a constant, rework - the sum. */ - if (REG_P (XEXP (x, 0)) - && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER - && CONSTANT_P (XEXP (x, 1))) - { - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; - ep++) - if (ep->from_rtx == XEXP (x, 0) && ep->can_eliminate) - { - /* The only time we want to replace a PLUS with a REG (this - occurs when the constant operand of the PLUS is the negative - of the offset) is when we are inside a MEM. We won't want - to do so at other times because that would change the - structure of the insn in a way that reload can't handle. - We special-case the commonest situation in - eliminate_regs_in_insn, so just replace a PLUS with a - PLUS here, unless inside a MEM. In DEBUG_INSNs, it is - always ok to replace a PLUS with just a REG. */ - if ((mem_mode != 0 || (insn && DEBUG_INSN_P (insn))) - && CONST_INT_P (XEXP (x, 1)) - && known_eq (INTVAL (XEXP (x, 1)), -ep->previous_offset)) - return ep->to_rtx; - else - return gen_rtx_PLUS (Pmode, ep->to_rtx, - plus_constant (Pmode, XEXP (x, 1), - ep->previous_offset)); - } - - /* If the register is not eliminable, we are done since the other - operand is a constant. */ - return x; - } - - /* If this is part of an address, we want to bring any constant to the - outermost PLUS. We will do this by doing register replacement in - our operands and seeing if a constant shows up in one of them. - - Note that there is no risk of modifying the structure of the insn, - since we only get called for its operands, thus we are either - modifying the address inside a MEM, or something like an address - operand of a load-address insn. */ - - { - rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true, - for_costs); - rtx new1 = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true, - for_costs); - - if (reg_renumber && (new0 != XEXP (x, 0) || new1 != XEXP (x, 1))) - { - /* If one side is a PLUS and the other side is a pseudo that - didn't get a hard register but has a reg_equiv_constant, - we must replace the constant here since it may no longer - be in the position of any operand. */ - if (GET_CODE (new0) == PLUS && REG_P (new1) - && REGNO (new1) >= FIRST_PSEUDO_REGISTER - && reg_renumber[REGNO (new1)] < 0 - && reg_equivs - && reg_equiv_constant (REGNO (new1)) != 0) - new1 = reg_equiv_constant (REGNO (new1)); - else if (GET_CODE (new1) == PLUS && REG_P (new0) - && REGNO (new0) >= FIRST_PSEUDO_REGISTER - && reg_renumber[REGNO (new0)] < 0 - && reg_equiv_constant (REGNO (new0)) != 0) - new0 = reg_equiv_constant (REGNO (new0)); - - new_rtx = form_sum (GET_MODE (x), new0, new1); - - /* As above, if we are not inside a MEM we do not want to - turn a PLUS into something else. We might try to do so here - for an addition of 0 if we aren't optimizing. */ - if (! mem_mode && GET_CODE (new_rtx) != PLUS) - return gen_rtx_PLUS (GET_MODE (x), new_rtx, const0_rtx); - else - return new_rtx; - } - } - return x; - - case MULT: - /* If this is the product of an eliminable register and a - constant, apply the distribute law and move the constant out - so that we have (plus (mult ..) ..). This is needed in order - to keep load-address insns valid. This case is pathological. - We ignore the possibility of overflow here. */ - if (REG_P (XEXP (x, 0)) - && REGNO (XEXP (x, 0)) < FIRST_PSEUDO_REGISTER - && CONST_INT_P (XEXP (x, 1))) - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; - ep++) - if (ep->from_rtx == XEXP (x, 0) && ep->can_eliminate) - { - if (! mem_mode - /* Refs inside notes or in DEBUG_INSNs don't count for - this purpose. */ - && ! (insn != 0 && (GET_CODE (insn) == EXPR_LIST - || GET_CODE (insn) == INSN_LIST - || DEBUG_INSN_P (insn)))) - ep->ref_outside_mem = 1; - - return - plus_constant (Pmode, - gen_rtx_MULT (Pmode, ep->to_rtx, XEXP (x, 1)), - ep->previous_offset * INTVAL (XEXP (x, 1))); - } - - /* fall through */ - - case CALL: - case COMPARE: - /* See comments before PLUS about handling MINUS. */ - case MINUS: - case DIV: case UDIV: - case MOD: case UMOD: - case AND: case IOR: case XOR: - case ROTATERT: case ROTATE: - case ASHIFTRT: case LSHIFTRT: case ASHIFT: - case NE: case EQ: - case GE: case GT: case GEU: case GTU: - case LE: case LT: case LEU: case LTU: - { - rtx new0 = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false, - for_costs); - rtx new1 = XEXP (x, 1) - ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, false, - for_costs) : 0; - - if (new0 != XEXP (x, 0) || new1 != XEXP (x, 1)) - return gen_rtx_fmt_ee (code, GET_MODE (x), new0, new1); - } - return x; - - case EXPR_LIST: - /* If we have something in XEXP (x, 0), the usual case, eliminate it. */ - if (XEXP (x, 0)) - { - new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, true, - for_costs); - if (new_rtx != XEXP (x, 0)) - { - /* If this is a REG_DEAD note, it is not valid anymore. - Using the eliminated version could result in creating a - REG_DEAD note for the stack or frame pointer. */ - if (REG_NOTE_KIND (x) == REG_DEAD) - return (XEXP (x, 1) - ? eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true, - for_costs) - : NULL_RTX); - - x = alloc_reg_note (REG_NOTE_KIND (x), new_rtx, XEXP (x, 1)); - } - } - - /* fall through */ - - case INSN_LIST: - case INT_LIST: - /* Now do eliminations in the rest of the chain. If this was - an EXPR_LIST, this might result in allocating more memory than is - strictly needed, but it simplifies the code. */ - if (XEXP (x, 1)) - { - new_rtx = eliminate_regs_1 (XEXP (x, 1), mem_mode, insn, true, - for_costs); - if (new_rtx != XEXP (x, 1)) - return - gen_rtx_fmt_ee (GET_CODE (x), GET_MODE (x), XEXP (x, 0), new_rtx); - } - return x; - - case PRE_INC: - case POST_INC: - case PRE_DEC: - case POST_DEC: - /* We do not support elimination of a register that is modified. - elimination_effects has already make sure that this does not - happen. */ - return x; - - case PRE_MODIFY: - case POST_MODIFY: - /* We do not support elimination of a register that is modified. - elimination_effects has already make sure that this does not - happen. The only remaining case we need to consider here is - that the increment value may be an eliminable register. */ - if (GET_CODE (XEXP (x, 1)) == PLUS - && XEXP (XEXP (x, 1), 0) == XEXP (x, 0)) - { - rtx new_rtx = eliminate_regs_1 (XEXP (XEXP (x, 1), 1), mem_mode, - insn, true, for_costs); - - if (new_rtx != XEXP (XEXP (x, 1), 1)) - return gen_rtx_fmt_ee (code, GET_MODE (x), XEXP (x, 0), - gen_rtx_PLUS (GET_MODE (x), - XEXP (x, 0), new_rtx)); - } - return x; - - case STRICT_LOW_PART: - case NEG: case NOT: - case SIGN_EXTEND: case ZERO_EXTEND: - case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: - case FLOAT: case FIX: - case UNSIGNED_FIX: case UNSIGNED_FLOAT: - case ABS: - case SQRT: - case FFS: - case CLZ: - case CTZ: - case POPCOUNT: - case PARITY: - case BSWAP: - new_rtx = eliminate_regs_1 (XEXP (x, 0), mem_mode, insn, false, - for_costs); - if (new_rtx != XEXP (x, 0)) - return gen_rtx_fmt_e (code, GET_MODE (x), new_rtx); - return x; - - case SUBREG: - /* Similar to above processing, but preserve SUBREG_BYTE. - Convert (subreg (mem)) to (mem) if not paradoxical. - Also, if we have a non-paradoxical (subreg (pseudo)) and the - pseudo didn't get a hard reg, we must replace this with the - eliminated version of the memory location because push_reload - may do the replacement in certain circumstances. */ - if (REG_P (SUBREG_REG (x)) - && !paradoxical_subreg_p (x) - && reg_equivs - && reg_equiv_memory_loc (REGNO (SUBREG_REG (x))) != 0) - { - new_rtx = SUBREG_REG (x); - } - else - new_rtx = eliminate_regs_1 (SUBREG_REG (x), mem_mode, insn, false, for_costs); - - if (new_rtx != SUBREG_REG (x)) - { - poly_int64 x_size = GET_MODE_SIZE (GET_MODE (x)); - poly_int64 new_size = GET_MODE_SIZE (GET_MODE (new_rtx)); - - if (MEM_P (new_rtx) - && ((partial_subreg_p (GET_MODE (x), GET_MODE (new_rtx)) - /* On RISC machines, combine can create rtl of the form - (set (subreg:m1 (reg:m2 R) 0) ...) - where m1 < m2, and expects something interesting to - happen to the entire word. Moreover, it will use the - (reg:m2 R) later, expecting all bits to be preserved. - So if the number of words is the same, preserve the - subreg so that push_reload can see it. */ - && !(WORD_REGISTER_OPERATIONS - && known_equal_after_align_down (x_size - 1, - new_size - 1, - UNITS_PER_WORD))) - || known_eq (x_size, new_size)) - ) - return adjust_address_nv (new_rtx, GET_MODE (x), SUBREG_BYTE (x)); - else if (insn && GET_CODE (insn) == DEBUG_INSN) - return gen_rtx_raw_SUBREG (GET_MODE (x), new_rtx, SUBREG_BYTE (x)); - else - return gen_rtx_SUBREG (GET_MODE (x), new_rtx, SUBREG_BYTE (x)); - } - - return x; - - case MEM: - /* Our only special processing is to pass the mode of the MEM to our - recursive call and copy the flags. While we are here, handle this - case more efficiently. */ - - new_rtx = eliminate_regs_1 (XEXP (x, 0), GET_MODE (x), insn, true, - for_costs); - if (for_costs - && memory_address_p (GET_MODE (x), XEXP (x, 0)) - && !memory_address_p (GET_MODE (x), new_rtx)) - note_reg_elim_costly (XEXP (x, 0), insn); - - return replace_equiv_address_nv (x, new_rtx); - - case USE: - /* Handle insn_list USE that a call to a pure function may generate. */ - new_rtx = eliminate_regs_1 (XEXP (x, 0), VOIDmode, insn, false, - for_costs); - if (new_rtx != XEXP (x, 0)) - return gen_rtx_USE (GET_MODE (x), new_rtx); - return x; - - case CLOBBER: - case ASM_OPERANDS: - gcc_assert (insn && DEBUG_INSN_P (insn)); - break; - - case SET: - gcc_unreachable (); - - default: - break; - } - - /* Process each of our operands recursively. If any have changed, make a - copy of the rtx. */ - fmt = GET_RTX_FORMAT (code); - for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) - { - if (*fmt == 'e') - { - new_rtx = eliminate_regs_1 (XEXP (x, i), mem_mode, insn, false, - for_costs); - if (new_rtx != XEXP (x, i) && ! copied) - { - x = shallow_copy_rtx (x); - copied = 1; - } - XEXP (x, i) = new_rtx; - } - else if (*fmt == 'E') - { - int copied_vec = 0; - for (j = 0; j < XVECLEN (x, i); j++) - { - new_rtx = eliminate_regs_1 (XVECEXP (x, i, j), mem_mode, insn, false, - for_costs); - if (new_rtx != XVECEXP (x, i, j) && ! copied_vec) - { - rtvec new_v = gen_rtvec_v (XVECLEN (x, i), - XVEC (x, i)->elem); - if (! copied) - { - x = shallow_copy_rtx (x); - copied = 1; - } - XVEC (x, i) = new_v; - copied_vec = 1; - } - XVECEXP (x, i, j) = new_rtx; - } - } - } - - return x; -} - -rtx -eliminate_regs (rtx x, machine_mode mem_mode, rtx insn) -{ - if (reg_eliminate == NULL) - { - gcc_assert (targetm.no_register_allocation); - return x; - } - return eliminate_regs_1 (x, mem_mode, insn, false, false); -} - -/* Scan rtx X for modifications of elimination target registers. Update - the table of eliminables to reflect the changed state. MEM_MODE is - the mode of an enclosing MEM rtx, or VOIDmode if not within a MEM. */ - -static void -elimination_effects (rtx x, machine_mode mem_mode) -{ - enum rtx_code code = GET_CODE (x); - struct elim_table *ep; - int regno; - int i, j; - const char *fmt; - - switch (code) - { - CASE_CONST_ANY: - case CONST: - case SYMBOL_REF: - case CODE_LABEL: - case PC: - case ASM_INPUT: - case ADDR_VEC: - case ADDR_DIFF_VEC: - case RETURN: - return; - - case REG: - regno = REGNO (x); - - /* First handle the case where we encounter a bare register that - is eliminable. Replace it with a PLUS. */ - if (regno < FIRST_PSEUDO_REGISTER) - { - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; - ep++) - if (ep->from_rtx == x && ep->can_eliminate) - { - if (! mem_mode) - ep->ref_outside_mem = 1; - return; - } - - } - else if (reg_renumber[regno] < 0 - && reg_equivs - && reg_equiv_constant (regno) - && ! function_invariant_p (reg_equiv_constant (regno))) - elimination_effects (reg_equiv_constant (regno), mem_mode); - return; - - case PRE_INC: - case POST_INC: - case PRE_DEC: - case POST_DEC: - case POST_MODIFY: - case PRE_MODIFY: - /* If we modify the source of an elimination rule, disable it. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->from_rtx == XEXP (x, 0)) - ep->can_eliminate = 0; - - /* If we modify the target of an elimination rule by adding a constant, - update its offset. If we modify the target in any other way, we'll - have to disable the rule as well. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->to_rtx == XEXP (x, 0)) - { - poly_int64 size = GET_MODE_SIZE (mem_mode); - - /* If more bytes than MEM_MODE are pushed, account for them. */ -#ifdef PUSH_ROUNDING - if (ep->to_rtx == stack_pointer_rtx) - size = PUSH_ROUNDING (size); -#endif - if (code == PRE_DEC || code == POST_DEC) - ep->offset += size; - else if (code == PRE_INC || code == POST_INC) - ep->offset -= size; - else if (code == PRE_MODIFY || code == POST_MODIFY) - { - if (GET_CODE (XEXP (x, 1)) == PLUS - && XEXP (x, 0) == XEXP (XEXP (x, 1), 0) - && CONST_INT_P (XEXP (XEXP (x, 1), 1))) - ep->offset -= INTVAL (XEXP (XEXP (x, 1), 1)); - else - ep->can_eliminate = 0; - } - } - - /* These two aren't unary operators. */ - if (code == POST_MODIFY || code == PRE_MODIFY) - break; - - /* Fall through to generic unary operation case. */ - gcc_fallthrough (); - case STRICT_LOW_PART: - case NEG: case NOT: - case SIGN_EXTEND: case ZERO_EXTEND: - case TRUNCATE: case FLOAT_EXTEND: case FLOAT_TRUNCATE: - case FLOAT: case FIX: - case UNSIGNED_FIX: case UNSIGNED_FLOAT: - case ABS: - case SQRT: - case FFS: - case CLZ: - case CTZ: - case POPCOUNT: - case PARITY: - case BSWAP: - elimination_effects (XEXP (x, 0), mem_mode); - return; - - case SUBREG: - if (REG_P (SUBREG_REG (x)) - && !paradoxical_subreg_p (x) - && reg_equivs - && reg_equiv_memory_loc (REGNO (SUBREG_REG (x))) != 0) - return; - - elimination_effects (SUBREG_REG (x), mem_mode); - return; - - case USE: - /* If using a register that is the source of an eliminate we still - think can be performed, note it cannot be performed since we don't - know how this register is used. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->from_rtx == XEXP (x, 0)) - ep->can_eliminate = 0; - - elimination_effects (XEXP (x, 0), mem_mode); - return; - - case CLOBBER: - /* If clobbering a register that is the replacement register for an - elimination we still think can be performed, note that it cannot - be performed. Otherwise, we need not be concerned about it. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->to_rtx == XEXP (x, 0)) - ep->can_eliminate = 0; - - elimination_effects (XEXP (x, 0), mem_mode); - return; - - case SET: - /* Check for setting a register that we know about. */ - if (REG_P (SET_DEST (x))) - { - /* See if this is setting the replacement register for an - elimination. - - If DEST is the hard frame pointer, we do nothing because we - assume that all assignments to the frame pointer are for - non-local gotos and are being done at a time when they are valid - and do not disturb anything else. Some machines want to - eliminate a fake argument pointer (or even a fake frame pointer) - with either the real frame or the stack pointer. Assignments to - the hard frame pointer must not prevent this elimination. */ - - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; - ep++) - if (ep->to_rtx == SET_DEST (x) - && SET_DEST (x) != hard_frame_pointer_rtx) - { - /* If it is being incremented, adjust the offset. Otherwise, - this elimination can't be done. */ - rtx src = SET_SRC (x); - - if (GET_CODE (src) == PLUS - && XEXP (src, 0) == SET_DEST (x) - && CONST_INT_P (XEXP (src, 1))) - ep->offset -= INTVAL (XEXP (src, 1)); - else - ep->can_eliminate = 0; - } - } - - elimination_effects (SET_DEST (x), VOIDmode); - elimination_effects (SET_SRC (x), VOIDmode); - return; - - case MEM: - /* Our only special processing is to pass the mode of the MEM to our - recursive call. */ - elimination_effects (XEXP (x, 0), GET_MODE (x)); - return; - - default: - break; - } - - fmt = GET_RTX_FORMAT (code); - for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) - { - if (*fmt == 'e') - elimination_effects (XEXP (x, i), mem_mode); - else if (*fmt == 'E') - for (j = 0; j < XVECLEN (x, i); j++) - elimination_effects (XVECEXP (x, i, j), mem_mode); - } -} - -/* Descend through rtx X and verify that no references to eliminable registers - remain. If any do remain, mark the involved register as not - eliminable. */ - -static void -check_eliminable_occurrences (rtx x) -{ - const char *fmt; - int i; - enum rtx_code code; - - if (x == 0) - return; - - code = GET_CODE (x); - - if (code == REG && REGNO (x) < FIRST_PSEUDO_REGISTER) - { - struct elim_table *ep; - - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->from_rtx == x) - ep->can_eliminate = 0; - return; - } - - fmt = GET_RTX_FORMAT (code); - for (i = 0; i < GET_RTX_LENGTH (code); i++, fmt++) - { - if (*fmt == 'e') - check_eliminable_occurrences (XEXP (x, i)); - else if (*fmt == 'E') - { - int j; - for (j = 0; j < XVECLEN (x, i); j++) - check_eliminable_occurrences (XVECEXP (x, i, j)); - } - } -} - -/* Scan INSN and eliminate all eliminable registers in it. - - If REPLACE is nonzero, do the replacement destructively. Also - delete the insn as dead it if it is setting an eliminable register. - - If REPLACE is zero, do all our allocations in reload_obstack. - - If no eliminations were done and this insn doesn't require any elimination - processing (these are not identical conditions: it might be updating sp, - but not referencing fp; this needs to be seen during reload_as_needed so - that the offset between fp and sp can be taken into consideration), zero - is returned. Otherwise, 1 is returned. */ - -static int -eliminate_regs_in_insn (rtx_insn *insn, int replace) -{ - int icode = recog_memoized (insn); - rtx old_body = PATTERN (insn); - int insn_is_asm = asm_noperands (old_body) >= 0; - rtx old_set = single_set (insn); - rtx new_body; - int val = 0; - int i; - rtx substed_operand[MAX_RECOG_OPERANDS]; - rtx orig_operand[MAX_RECOG_OPERANDS]; - struct elim_table *ep; - rtx plus_src, plus_cst_src; - - if (! insn_is_asm && icode < 0) - { - gcc_assert (DEBUG_INSN_P (insn) - || GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER - || GET_CODE (PATTERN (insn)) == ASM_INPUT); - if (DEBUG_BIND_INSN_P (insn)) - INSN_VAR_LOCATION_LOC (insn) - = eliminate_regs (INSN_VAR_LOCATION_LOC (insn), VOIDmode, insn); - return 0; - } - - /* We allow one special case which happens to work on all machines we - currently support: a single set with the source or a REG_EQUAL - note being a PLUS of an eliminable register and a constant. */ - plus_src = plus_cst_src = 0; - if (old_set && REG_P (SET_DEST (old_set))) - { - if (GET_CODE (SET_SRC (old_set)) == PLUS) - plus_src = SET_SRC (old_set); - /* First see if the source is of the form (plus (...) CST). */ - if (plus_src - && CONST_INT_P (XEXP (plus_src, 1))) - plus_cst_src = plus_src; - else if (REG_P (SET_SRC (old_set)) - || plus_src) - { - /* Otherwise, see if we have a REG_EQUAL note of the form - (plus (...) CST). */ - rtx links; - for (links = REG_NOTES (insn); links; links = XEXP (links, 1)) - { - if ((REG_NOTE_KIND (links) == REG_EQUAL - || REG_NOTE_KIND (links) == REG_EQUIV) - && GET_CODE (XEXP (links, 0)) == PLUS - && CONST_INT_P (XEXP (XEXP (links, 0), 1))) - { - plus_cst_src = XEXP (links, 0); - break; - } - } - } - - /* Check that the first operand of the PLUS is a hard reg or - the lowpart subreg of one. */ - if (plus_cst_src) - { - rtx reg = XEXP (plus_cst_src, 0); - if (GET_CODE (reg) == SUBREG && subreg_lowpart_p (reg)) - reg = SUBREG_REG (reg); - - if (!REG_P (reg) || REGNO (reg) >= FIRST_PSEUDO_REGISTER) - plus_cst_src = 0; - } - } - if (plus_cst_src) - { - rtx reg = XEXP (plus_cst_src, 0); - poly_int64 offset = INTVAL (XEXP (plus_cst_src, 1)); - - if (GET_CODE (reg) == SUBREG) - reg = SUBREG_REG (reg); - - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->from_rtx == reg && ep->can_eliminate) - { - rtx to_rtx = ep->to_rtx; - offset += ep->offset; - offset = trunc_int_for_mode (offset, GET_MODE (plus_cst_src)); - - if (GET_CODE (XEXP (plus_cst_src, 0)) == SUBREG) - to_rtx = gen_lowpart (GET_MODE (XEXP (plus_cst_src, 0)), - to_rtx); - /* If we have a nonzero offset, and the source is already - a simple REG, the following transformation would - increase the cost of the insn by replacing a simple REG - with (plus (reg sp) CST). So try only when we already - had a PLUS before. */ - if (known_eq (offset, 0) || plus_src) - { - rtx new_src = plus_constant (GET_MODE (to_rtx), - to_rtx, offset); - - new_body = old_body; - if (! replace) - { - new_body = copy_insn (old_body); - if (REG_NOTES (insn)) - REG_NOTES (insn) = copy_insn_1 (REG_NOTES (insn)); - } - PATTERN (insn) = new_body; - old_set = single_set (insn); - - /* First see if this insn remains valid when we make the - change. If not, try to replace the whole pattern with - a simple set (this may help if the original insn was a - PARALLEL that was only recognized as single_set due to - REG_UNUSED notes). If this isn't valid either, keep - the INSN_CODE the same and let reload fix it up. */ - if (!validate_change (insn, &SET_SRC (old_set), new_src, 0)) - { - rtx new_pat = gen_rtx_SET (SET_DEST (old_set), new_src); - - if (!validate_change (insn, &PATTERN (insn), new_pat, 0)) - SET_SRC (old_set) = new_src; - } - } - else - break; - - val = 1; - /* This can't have an effect on elimination offsets, so skip right - to the end. */ - goto done; - } - } - - /* Determine the effects of this insn on elimination offsets. */ - elimination_effects (old_body, VOIDmode); - - /* Eliminate all eliminable registers occurring in operands that - can be handled by reload. */ - extract_insn (insn); - for (i = 0; i < recog_data.n_operands; i++) - { - orig_operand[i] = recog_data.operand[i]; - substed_operand[i] = recog_data.operand[i]; - - /* For an asm statement, every operand is eliminable. */ - if (insn_is_asm || insn_data[icode].operand[i].eliminable) - { - bool is_set_src, in_plus; - - /* Check for setting a register that we know about. */ - if (recog_data.operand_type[i] != OP_IN - && REG_P (orig_operand[i])) - { - /* If we are assigning to a register that can be eliminated, it - must be as part of a PARALLEL, since the code above handles - single SETs. We must indicate that we can no longer - eliminate this reg. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; - ep++) - if (ep->from_rtx == orig_operand[i]) - ep->can_eliminate = 0; - } - - /* Companion to the above plus substitution, we can allow - invariants as the source of a plain move. */ - is_set_src = false; - if (old_set - && recog_data.operand_loc[i] == &SET_SRC (old_set)) - is_set_src = true; - in_plus = false; - if (plus_src - && (recog_data.operand_loc[i] == &XEXP (plus_src, 0) - || recog_data.operand_loc[i] == &XEXP (plus_src, 1))) - in_plus = true; - - substed_operand[i] - = eliminate_regs_1 (recog_data.operand[i], VOIDmode, - replace ? insn : NULL_RTX, - is_set_src || in_plus, false); - if (substed_operand[i] != orig_operand[i]) - val = 1; - /* Terminate the search in check_eliminable_occurrences at - this point. */ - *recog_data.operand_loc[i] = 0; - - /* If an output operand changed from a REG to a MEM and INSN is an - insn, write a CLOBBER insn. */ - if (recog_data.operand_type[i] != OP_IN - && REG_P (orig_operand[i]) - && MEM_P (substed_operand[i]) - && replace) - emit_insn_after (gen_clobber (orig_operand[i]), insn); - } - } - - for (i = 0; i < recog_data.n_dups; i++) - *recog_data.dup_loc[i] - = *recog_data.operand_loc[(int) recog_data.dup_num[i]]; - - /* If any eliminable remain, they aren't eliminable anymore. */ - check_eliminable_occurrences (old_body); - - /* Substitute the operands; the new values are in the substed_operand - array. */ - for (i = 0; i < recog_data.n_operands; i++) - *recog_data.operand_loc[i] = substed_operand[i]; - for (i = 0; i < recog_data.n_dups; i++) - *recog_data.dup_loc[i] = substed_operand[(int) recog_data.dup_num[i]]; - - /* If we are replacing a body that was a (set X (plus Y Z)), try to - re-recognize the insn. We do this in case we had a simple addition - but now can do this as a load-address. This saves an insn in this - common case. - If re-recognition fails, the old insn code number will still be used, - and some register operands may have changed into PLUS expressions. - These will be handled by find_reloads by loading them into a register - again. */ - - if (val) - { - /* If we aren't replacing things permanently and we changed something, - make another copy to ensure that all the RTL is new. Otherwise - things can go wrong if find_reload swaps commutative operands - and one is inside RTL that has been copied while the other is not. */ - new_body = old_body; - if (! replace) - { - new_body = copy_insn (old_body); - if (REG_NOTES (insn)) - REG_NOTES (insn) = copy_insn_1 (REG_NOTES (insn)); - } - PATTERN (insn) = new_body; - - /* If we had a move insn but now we don't, rerecognize it. This will - cause spurious re-recognition if the old move had a PARALLEL since - the new one still will, but we can't call single_set without - having put NEW_BODY into the insn and the re-recognition won't - hurt in this rare case. */ - /* ??? Why this huge if statement - why don't we just rerecognize the - thing always? */ - if (! insn_is_asm - && old_set != 0 - && ((REG_P (SET_SRC (old_set)) - && (GET_CODE (new_body) != SET - || !REG_P (SET_SRC (new_body)))) - /* If this was a load from or store to memory, compare - the MEM in recog_data.operand to the one in the insn. - If they are not equal, then rerecognize the insn. */ - || (old_set != 0 - && ((MEM_P (SET_SRC (old_set)) - && SET_SRC (old_set) != recog_data.operand[1]) - || (MEM_P (SET_DEST (old_set)) - && SET_DEST (old_set) != recog_data.operand[0]))) - /* If this was an add insn before, rerecognize. */ - || GET_CODE (SET_SRC (old_set)) == PLUS)) - { - int new_icode = recog (PATTERN (insn), insn, 0); - if (new_icode >= 0) - INSN_CODE (insn) = new_icode; - } - } - - /* Restore the old body. If there were any changes to it, we made a copy - of it while the changes were still in place, so we'll correctly return - a modified insn below. */ - if (! replace) - { - /* Restore the old body. */ - for (i = 0; i < recog_data.n_operands; i++) - /* Restoring a top-level match_parallel would clobber the new_body - we installed in the insn. */ - if (recog_data.operand_loc[i] != &PATTERN (insn)) - *recog_data.operand_loc[i] = orig_operand[i]; - for (i = 0; i < recog_data.n_dups; i++) - *recog_data.dup_loc[i] = orig_operand[(int) recog_data.dup_num[i]]; - } - - /* Update all elimination pairs to reflect the status after the current - insn. The changes we make were determined by the earlier call to - elimination_effects. - - We also detect cases where register elimination cannot be done, - namely, if a register would be both changed and referenced outside a MEM - in the resulting insn since such an insn is often undefined and, even if - not, we cannot know what meaning will be given to it. Note that it is - valid to have a register used in an address in an insn that changes it - (presumably with a pre- or post-increment or decrement). - - If anything changes, return nonzero. */ - - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - { - if (maybe_ne (ep->previous_offset, ep->offset) && ep->ref_outside_mem) - ep->can_eliminate = 0; - - ep->ref_outside_mem = 0; - - if (maybe_ne (ep->previous_offset, ep->offset)) - val = 1; - } - - done: - /* If we changed something, perform elimination in REG_NOTES. This is - needed even when REPLACE is zero because a REG_DEAD note might refer - to a register that we eliminate and could cause a different number - of spill registers to be needed in the final reload pass than in - the pre-passes. */ - if (val && REG_NOTES (insn) != 0) - REG_NOTES (insn) - = eliminate_regs_1 (REG_NOTES (insn), VOIDmode, REG_NOTES (insn), true, - false); - - return val; -} - -/* Like eliminate_regs_in_insn, but only estimate costs for the use of the - register allocator. INSN is the instruction we need to examine, we perform - eliminations in its operands and record cases where eliminating a reg with - an invariant equivalence would add extra cost. */ - -#pragma GCC diagnostic push -#pragma GCC diagnostic warning "-Wmaybe-uninitialized" -static void -elimination_costs_in_insn (rtx_insn *insn) -{ - int icode = recog_memoized (insn); - rtx old_body = PATTERN (insn); - int insn_is_asm = asm_noperands (old_body) >= 0; - rtx old_set = single_set (insn); - int i; - rtx orig_operand[MAX_RECOG_OPERANDS]; - rtx orig_dup[MAX_RECOG_OPERANDS]; - struct elim_table *ep; - rtx plus_src, plus_cst_src; - bool sets_reg_p; - - if (! insn_is_asm && icode < 0) - { - gcc_assert (DEBUG_INSN_P (insn) - || GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER - || GET_CODE (PATTERN (insn)) == ASM_INPUT); - return; - } - - if (old_set != 0 && REG_P (SET_DEST (old_set)) - && REGNO (SET_DEST (old_set)) < FIRST_PSEUDO_REGISTER) - { - /* Check for setting an eliminable register. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->from_rtx == SET_DEST (old_set) && ep->can_eliminate) - return; - } - - /* We allow one special case which happens to work on all machines we - currently support: a single set with the source or a REG_EQUAL - note being a PLUS of an eliminable register and a constant. */ - plus_src = plus_cst_src = 0; - sets_reg_p = false; - if (old_set && REG_P (SET_DEST (old_set))) - { - sets_reg_p = true; - if (GET_CODE (SET_SRC (old_set)) == PLUS) - plus_src = SET_SRC (old_set); - /* First see if the source is of the form (plus (...) CST). */ - if (plus_src - && CONST_INT_P (XEXP (plus_src, 1))) - plus_cst_src = plus_src; - else if (REG_P (SET_SRC (old_set)) - || plus_src) - { - /* Otherwise, see if we have a REG_EQUAL note of the form - (plus (...) CST). */ - rtx links; - for (links = REG_NOTES (insn); links; links = XEXP (links, 1)) - { - if ((REG_NOTE_KIND (links) == REG_EQUAL - || REG_NOTE_KIND (links) == REG_EQUIV) - && GET_CODE (XEXP (links, 0)) == PLUS - && CONST_INT_P (XEXP (XEXP (links, 0), 1))) - { - plus_cst_src = XEXP (links, 0); - break; - } - } - } - } - - /* Determine the effects of this insn on elimination offsets. */ - elimination_effects (old_body, VOIDmode); - - /* Eliminate all eliminable registers occurring in operands that - can be handled by reload. */ - extract_insn (insn); - int n_dups = recog_data.n_dups; - for (i = 0; i < n_dups; i++) - orig_dup[i] = *recog_data.dup_loc[i]; - - int n_operands = recog_data.n_operands; - for (i = 0; i < n_operands; i++) - { - orig_operand[i] = recog_data.operand[i]; - - /* For an asm statement, every operand is eliminable. */ - if (insn_is_asm || insn_data[icode].operand[i].eliminable) - { - bool is_set_src, in_plus; - - /* Check for setting a register that we know about. */ - if (recog_data.operand_type[i] != OP_IN - && REG_P (orig_operand[i])) - { - /* If we are assigning to a register that can be eliminated, it - must be as part of a PARALLEL, since the code above handles - single SETs. We must indicate that we can no longer - eliminate this reg. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; - ep++) - if (ep->from_rtx == orig_operand[i]) - ep->can_eliminate = 0; - } - - /* Companion to the above plus substitution, we can allow - invariants as the source of a plain move. */ - is_set_src = false; - if (old_set && recog_data.operand_loc[i] == &SET_SRC (old_set)) - is_set_src = true; - if (is_set_src && !sets_reg_p) - note_reg_elim_costly (SET_SRC (old_set), insn); - in_plus = false; - if (plus_src && sets_reg_p - && (recog_data.operand_loc[i] == &XEXP (plus_src, 0) - || recog_data.operand_loc[i] == &XEXP (plus_src, 1))) - in_plus = true; - - eliminate_regs_1 (recog_data.operand[i], VOIDmode, - NULL_RTX, - is_set_src || in_plus, true); - /* Terminate the search in check_eliminable_occurrences at - this point. */ - *recog_data.operand_loc[i] = 0; - } - } - - for (i = 0; i < n_dups; i++) - *recog_data.dup_loc[i] - = *recog_data.operand_loc[(int) recog_data.dup_num[i]]; - - /* If any eliminable remain, they aren't eliminable anymore. */ - check_eliminable_occurrences (old_body); - - /* Restore the old body. */ - for (i = 0; i < n_operands; i++) - *recog_data.operand_loc[i] = orig_operand[i]; - for (i = 0; i < n_dups; i++) - *recog_data.dup_loc[i] = orig_dup[i]; - - /* Update all elimination pairs to reflect the status after the current - insn. The changes we make were determined by the earlier call to - elimination_effects. */ - - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - { - if (maybe_ne (ep->previous_offset, ep->offset) && ep->ref_outside_mem) - ep->can_eliminate = 0; - - ep->ref_outside_mem = 0; - } - - return; -} -#pragma GCC diagnostic pop - -/* Loop through all elimination pairs. - Recalculate the number not at initial offset. - - Compute the maximum offset (minimum offset if the stack does not - grow downward) for each elimination pair. */ - -static void -update_eliminable_offsets (void) -{ - struct elim_table *ep; - - num_not_at_initial_offset = 0; - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - { - ep->previous_offset = ep->offset; - if (ep->can_eliminate && maybe_ne (ep->offset, ep->initial_offset)) - num_not_at_initial_offset++; - } -} - -/* Given X, a SET or CLOBBER of DEST, if DEST is the target of a register - replacement we currently believe is valid, mark it as not eliminable if X - modifies DEST in any way other than by adding a constant integer to it. - - If DEST is the frame pointer, we do nothing because we assume that - all assignments to the hard frame pointer are nonlocal gotos and are being - done at a time when they are valid and do not disturb anything else. - Some machines want to eliminate a fake argument pointer with either the - frame or stack pointer. Assignments to the hard frame pointer must not - prevent this elimination. - - Called via note_stores from reload before starting its passes to scan - the insns of the function. */ - -static void -mark_not_eliminable (rtx dest, const_rtx x, void *data ATTRIBUTE_UNUSED) -{ - unsigned int i; - - /* A SUBREG of a hard register here is just changing its mode. We should - not see a SUBREG of an eliminable hard register, but check just in - case. */ - if (GET_CODE (dest) == SUBREG) - dest = SUBREG_REG (dest); - - if (dest == hard_frame_pointer_rtx) - return; - - for (i = 0; i < NUM_ELIMINABLE_REGS; i++) - if (reg_eliminate[i].can_eliminate && dest == reg_eliminate[i].to_rtx - && (GET_CODE (x) != SET - || GET_CODE (SET_SRC (x)) != PLUS - || XEXP (SET_SRC (x), 0) != dest - || !CONST_INT_P (XEXP (SET_SRC (x), 1)))) - { - reg_eliminate[i].can_eliminate_previous - = reg_eliminate[i].can_eliminate = 0; - num_eliminable--; - } -} - -/* Verify that the initial elimination offsets did not change since the - last call to set_initial_elim_offsets. This is used to catch cases - where something illegal happened during reload_as_needed that could - cause incorrect code to be generated if we did not check for it. */ - -static bool -verify_initial_elim_offsets (void) -{ - poly_int64 t; - struct elim_table *ep; - - if (!num_eliminable) - return true; - - targetm.compute_frame_layout (); - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - { - INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, t); - if (maybe_ne (t, ep->initial_offset)) - return false; - } - - return true; -} - -/* Reset all offsets on eliminable registers to their initial values. */ - -static void -set_initial_elim_offsets (void) -{ - struct elim_table *ep = reg_eliminate; - - targetm.compute_frame_layout (); - for (; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - { - INITIAL_ELIMINATION_OFFSET (ep->from, ep->to, ep->initial_offset); - ep->previous_offset = ep->offset = ep->initial_offset; - } - - num_not_at_initial_offset = 0; -} - -/* Subroutine of set_initial_label_offsets called via for_each_eh_label. */ - -static void -set_initial_eh_label_offset (rtx label) -{ - set_label_offsets (label, NULL, 1); -} - -/* Initialize the known label offsets. - Set a known offset for each forced label to be at the initial offset - of each elimination. We do this because we assume that all - computed jumps occur from a location where each elimination is - at its initial offset. - For all other labels, show that we don't know the offsets. */ - -static void -set_initial_label_offsets (void) -{ - memset (offsets_known_at, 0, num_labels); - - unsigned int i; - rtx_insn *insn; - FOR_EACH_VEC_SAFE_ELT (forced_labels, i, insn) - set_label_offsets (insn, NULL, 1); - - for (rtx_insn_list *x = nonlocal_goto_handler_labels; x; x = x->next ()) - if (x->insn ()) - set_label_offsets (x->insn (), NULL, 1); - - for_each_eh_label (set_initial_eh_label_offset); -} - -/* Set all elimination offsets to the known values for the code label given - by INSN. */ - -static void -set_offsets_for_label (rtx_insn *insn) -{ - unsigned int i; - int label_nr = CODE_LABEL_NUMBER (insn); - struct elim_table *ep; - - num_not_at_initial_offset = 0; - for (i = 0, ep = reg_eliminate; i < NUM_ELIMINABLE_REGS; ep++, i++) - { - ep->offset = ep->previous_offset - = offsets_at[label_nr - first_label_num][i]; - if (ep->can_eliminate && maybe_ne (ep->offset, ep->initial_offset)) - num_not_at_initial_offset++; - } -} - -/* See if anything that happened changes which eliminations are valid. - For example, on the SPARC, whether or not the frame pointer can - be eliminated can depend on what registers have been used. We need - not check some conditions again (such as flag_omit_frame_pointer) - since they can't have changed. */ - -static void -update_eliminables (HARD_REG_SET *pset) -{ - int previous_frame_pointer_needed = frame_pointer_needed; - struct elim_table *ep; - - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if ((ep->from == HARD_FRAME_POINTER_REGNUM - && targetm.frame_pointer_required ()) - || ! targetm.can_eliminate (ep->from, ep->to) - ) - ep->can_eliminate = 0; - - /* Look for the case where we have discovered that we can't replace - register A with register B and that means that we will now be - trying to replace register A with register C. This means we can - no longer replace register C with register B and we need to disable - such an elimination, if it exists. This occurs often with A == ap, - B == sp, and C == fp. */ - - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - { - struct elim_table *op; - int new_to = -1; - - if (! ep->can_eliminate && ep->can_eliminate_previous) - { - /* Find the current elimination for ep->from, if there is a - new one. */ - for (op = reg_eliminate; - op < ®_eliminate[NUM_ELIMINABLE_REGS]; op++) - if (op->from == ep->from && op->can_eliminate) - { - new_to = op->to; - break; - } - - /* See if there is an elimination of NEW_TO -> EP->TO. If so, - disable it. */ - for (op = reg_eliminate; - op < ®_eliminate[NUM_ELIMINABLE_REGS]; op++) - if (op->from == new_to && op->to == ep->to) - op->can_eliminate = 0; - } - } - - /* See if any registers that we thought we could eliminate the previous - time are no longer eliminable. If so, something has changed and we - must spill the register. Also, recompute the number of eliminable - registers and see if the frame pointer is needed; it is if there is - no elimination of the frame pointer that we can perform. */ - - frame_pointer_needed = 1; - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - { - if (ep->can_eliminate - && ep->from == FRAME_POINTER_REGNUM - && ep->to != HARD_FRAME_POINTER_REGNUM - && (! SUPPORTS_STACK_ALIGNMENT - || ! crtl->stack_realign_needed)) - frame_pointer_needed = 0; - - if (! ep->can_eliminate && ep->can_eliminate_previous) - { - ep->can_eliminate_previous = 0; - SET_HARD_REG_BIT (*pset, ep->from); - num_eliminable--; - } - } - - /* If we didn't need a frame pointer last time, but we do now, spill - the hard frame pointer. */ - if (frame_pointer_needed && ! previous_frame_pointer_needed) - SET_HARD_REG_BIT (*pset, HARD_FRAME_POINTER_REGNUM); -} - -/* Call update_eliminables an spill any registers we can't eliminate anymore. - Return true iff a register was spilled. */ - -static bool -update_eliminables_and_spill (void) -{ - int i; - bool did_spill = false; - HARD_REG_SET to_spill; - CLEAR_HARD_REG_SET (to_spill); - update_eliminables (&to_spill); - used_spill_regs &= ~to_spill; - - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (TEST_HARD_REG_BIT (to_spill, i)) - { - spill_hard_reg (i, 1); - did_spill = true; - - /* Regardless of the state of spills, if we previously had - a register that we thought we could eliminate, but now - cannot eliminate, we must run another pass. - - Consider pseudos which have an entry in reg_equiv_* which - reference an eliminable register. We must make another pass - to update reg_equiv_* so that we do not substitute in the - old value from when we thought the elimination could be - performed. */ - } - return did_spill; -} - -/* Return true if X is used as the target register of an elimination. */ - -bool -elimination_target_reg_p (rtx x) -{ - struct elim_table *ep; - - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - if (ep->to_rtx == x && ep->can_eliminate) - return true; - - return false; -} - -/* Initialize the table of registers to eliminate. - Pre-condition: global flag frame_pointer_needed has been set before - calling this function. */ - -static void -init_elim_table (void) -{ - struct elim_table *ep; - const struct elim_table_1 *ep1; - - if (!reg_eliminate) - reg_eliminate = XCNEWVEC (struct elim_table, NUM_ELIMINABLE_REGS); - - num_eliminable = 0; - - for (ep = reg_eliminate, ep1 = reg_eliminate_1; - ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++, ep1++) - { - ep->from = ep1->from; - ep->to = ep1->to; - ep->can_eliminate = ep->can_eliminate_previous - = (targetm.can_eliminate (ep->from, ep->to) - && ! (ep->to == STACK_POINTER_REGNUM - && frame_pointer_needed - && (! SUPPORTS_STACK_ALIGNMENT - || ! stack_realign_fp))); - } - - /* Count the number of eliminable registers and build the FROM and TO - REG rtx's. Note that code in gen_rtx_REG will cause, e.g., - gen_rtx_REG (Pmode, STACK_POINTER_REGNUM) to equal stack_pointer_rtx. - We depend on this. */ - for (ep = reg_eliminate; ep < ®_eliminate[NUM_ELIMINABLE_REGS]; ep++) - { - num_eliminable += ep->can_eliminate; - ep->from_rtx = gen_rtx_REG (Pmode, ep->from); - ep->to_rtx = gen_rtx_REG (Pmode, ep->to); - } -} - -/* Find all the pseudo registers that didn't get hard regs - but do have known equivalent constants or memory slots. - These include parameters (known equivalent to parameter slots) - and cse'd or loop-moved constant memory addresses. - - Record constant equivalents in reg_equiv_constant - so they will be substituted by find_reloads. - Record memory equivalents in reg_mem_equiv so they can - be substituted eventually by altering the REG-rtx's. */ - -static void -init_eliminable_invariants (rtx_insn *first, bool do_subregs) -{ - int i; - rtx_insn *insn; - - grow_reg_equivs (); - if (do_subregs) - reg_max_ref_mode = XCNEWVEC (machine_mode, max_regno); - else - reg_max_ref_mode = NULL; - - num_eliminable_invariants = 0; - - first_label_num = get_first_label_num (); - num_labels = max_label_num () - first_label_num; - - /* Allocate the tables used to store offset information at labels. */ - offsets_known_at = XNEWVEC (char, num_labels); - offsets_at = (poly_int64_pod (*)[NUM_ELIMINABLE_REGS]) - xmalloc (num_labels * NUM_ELIMINABLE_REGS * sizeof (poly_int64)); - -/* Look for REG_EQUIV notes; record what each pseudo is equivalent - to. If DO_SUBREGS is true, also find all paradoxical subregs and - find largest such for each pseudo. FIRST is the head of the insn - list. */ - - for (insn = first; insn; insn = NEXT_INSN (insn)) - { - rtx set = single_set (insn); - - /* We may introduce USEs that we want to remove at the end, so - we'll mark them with QImode. Make sure there are no - previously-marked insns left by say regmove. */ - if (INSN_P (insn) && GET_CODE (PATTERN (insn)) == USE - && GET_MODE (insn) != VOIDmode) - PUT_MODE (insn, VOIDmode); - - if (do_subregs && NONDEBUG_INSN_P (insn)) - scan_paradoxical_subregs (PATTERN (insn)); - - if (set != 0 && REG_P (SET_DEST (set))) - { - rtx note = find_reg_note (insn, REG_EQUIV, NULL_RTX); - rtx x; - - if (! note) - continue; - - i = REGNO (SET_DEST (set)); - x = XEXP (note, 0); - - if (i <= LAST_VIRTUAL_REGISTER) - continue; - - /* If flag_pic and we have constant, verify it's legitimate. */ - if (!CONSTANT_P (x) - || !flag_pic || LEGITIMATE_PIC_OPERAND_P (x)) - { - /* It can happen that a REG_EQUIV note contains a MEM - that is not a legitimate memory operand. As later - stages of reload assume that all addresses found - in the reg_equiv_* arrays were originally legitimate, - we ignore such REG_EQUIV notes. */ - if (memory_operand (x, VOIDmode)) - { - /* Always unshare the equivalence, so we can - substitute into this insn without touching the - equivalence. */ - reg_equiv_memory_loc (i) = copy_rtx (x); - } - else if (function_invariant_p (x)) - { - machine_mode mode; - - mode = GET_MODE (SET_DEST (set)); - if (GET_CODE (x) == PLUS) - { - /* This is PLUS of frame pointer and a constant, - and might be shared. Unshare it. */ - reg_equiv_invariant (i) = copy_rtx (x); - num_eliminable_invariants++; - } - else if (x == frame_pointer_rtx || x == arg_pointer_rtx) - { - reg_equiv_invariant (i) = x; - num_eliminable_invariants++; - } - else if (targetm.legitimate_constant_p (mode, x)) - reg_equiv_constant (i) = x; - else - { - reg_equiv_memory_loc (i) = force_const_mem (mode, x); - if (! reg_equiv_memory_loc (i)) - reg_equiv_init (i) = NULL; - } - } - else - { - reg_equiv_init (i) = NULL; - continue; - } - } - else - reg_equiv_init (i) = NULL; - } - } - - if (dump_file) - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - if (reg_equiv_init (i)) - { - fprintf (dump_file, "init_insns for %u: ", i); - print_inline_rtx (dump_file, reg_equiv_init (i), 20); - fprintf (dump_file, "\n"); - } -} - -/* Indicate that we no longer have known memory locations or constants. - Free all data involved in tracking these. */ - -static void -free_reg_equiv (void) -{ - int i; - - free (offsets_known_at); - free (offsets_at); - offsets_at = 0; - offsets_known_at = 0; - - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (reg_equiv_alt_mem_list (i)) - free_EXPR_LIST_list (®_equiv_alt_mem_list (i)); - vec_free (reg_equivs); -} - -/* Kick all pseudos out of hard register REGNO. - - If CANT_ELIMINATE is nonzero, it means that we are doing this spill - because we found we can't eliminate some register. In the case, no pseudos - are allowed to be in the register, even if they are only in a block that - doesn't require spill registers, unlike the case when we are spilling this - hard reg to produce another spill register. - - Return nonzero if any pseudos needed to be kicked out. */ - -static void -spill_hard_reg (unsigned int regno, int cant_eliminate) -{ - int i; - - if (cant_eliminate) - { - SET_HARD_REG_BIT (bad_spill_regs_global, regno); - df_set_regs_ever_live (regno, true); - } - - /* Spill every pseudo reg that was allocated to this reg - or to something that overlaps this reg. */ - - for (i = FIRST_PSEUDO_REGISTER; i < max_regno; i++) - if (reg_renumber[i] >= 0 - && (unsigned int) reg_renumber[i] <= regno - && end_hard_regno (PSEUDO_REGNO_MODE (i), reg_renumber[i]) > regno) - SET_REGNO_REG_SET (&spilled_pseudos, i); -} - -/* After spill_hard_reg was called and/or find_reload_regs was run for all - insns that need reloads, this function is used to actually spill pseudo - registers and try to reallocate them. It also sets up the spill_regs - array for use by choose_reload_regs. - - GLOBAL nonzero means we should attempt to reallocate any pseudo registers - that we displace from hard registers. */ - -static int -finish_spills (int global) -{ - class insn_chain *chain; - int something_changed = 0; - unsigned i; - reg_set_iterator rsi; - - /* Build the spill_regs array for the function. */ - /* If there are some registers still to eliminate and one of the spill regs - wasn't ever used before, additional stack space may have to be - allocated to store this register. Thus, we may have changed the offset - between the stack and frame pointers, so mark that something has changed. - - One might think that we need only set VAL to 1 if this is a call-used - register. However, the set of registers that must be saved by the - prologue is not identical to the call-used set. For example, the - register used by the call insn for the return PC is a call-used register, - but must be saved by the prologue. */ - - n_spills = 0; - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (TEST_HARD_REG_BIT (used_spill_regs, i)) - { - spill_reg_order[i] = n_spills; - spill_regs[n_spills++] = i; - if (num_eliminable && ! df_regs_ever_live_p (i)) - something_changed = 1; - df_set_regs_ever_live (i, true); - } - else - spill_reg_order[i] = -1; - - EXECUTE_IF_SET_IN_REG_SET (&spilled_pseudos, FIRST_PSEUDO_REGISTER, i, rsi) - if (reg_renumber[i] >= 0) - { - SET_HARD_REG_BIT (pseudo_previous_regs[i], reg_renumber[i]); - /* Mark it as no longer having a hard register home. */ - reg_renumber[i] = -1; - if (ira_conflicts_p) - /* Inform IRA about the change. */ - ira_mark_allocation_change (i); - /* We will need to scan everything again. */ - something_changed = 1; - } - - /* Retry global register allocation if possible. */ - if (global && ira_conflicts_p) - { - unsigned int n; - - memset (pseudo_forbidden_regs, 0, max_regno * sizeof (HARD_REG_SET)); - /* For every insn that needs reloads, set the registers used as spill - regs in pseudo_forbidden_regs for every pseudo live across the - insn. */ - for (chain = insns_need_reload; chain; chain = chain->next_need_reload) - { - EXECUTE_IF_SET_IN_REG_SET - (&chain->live_throughout, FIRST_PSEUDO_REGISTER, i, rsi) - { - pseudo_forbidden_regs[i] |= chain->used_spill_regs; - } - EXECUTE_IF_SET_IN_REG_SET - (&chain->dead_or_set, FIRST_PSEUDO_REGISTER, i, rsi) - { - pseudo_forbidden_regs[i] |= chain->used_spill_regs; - } - } - - /* Retry allocating the pseudos spilled in IRA and the - reload. For each reg, merge the various reg sets that - indicate which hard regs can't be used, and call - ira_reassign_pseudos. */ - for (n = 0, i = FIRST_PSEUDO_REGISTER; i < (unsigned) max_regno; i++) - if (reg_old_renumber[i] != reg_renumber[i]) - { - if (reg_renumber[i] < 0) - temp_pseudo_reg_arr[n++] = i; - else - CLEAR_REGNO_REG_SET (&spilled_pseudos, i); - } - if (ira_reassign_pseudos (temp_pseudo_reg_arr, n, - bad_spill_regs_global, - pseudo_forbidden_regs, pseudo_previous_regs, - &spilled_pseudos)) - something_changed = 1; - } - /* Fix up the register information in the insn chain. - This involves deleting those of the spilled pseudos which did not get - a new hard register home from the live_{before,after} sets. */ - for (chain = reload_insn_chain; chain; chain = chain->next) - { - HARD_REG_SET used_by_pseudos; - HARD_REG_SET used_by_pseudos2; - - if (! ira_conflicts_p) - { - /* Don't do it for IRA because IRA and the reload still can - assign hard registers to the spilled pseudos on next - reload iterations. */ - AND_COMPL_REG_SET (&chain->live_throughout, &spilled_pseudos); - AND_COMPL_REG_SET (&chain->dead_or_set, &spilled_pseudos); - } - /* Mark any unallocated hard regs as available for spills. That - makes inheritance work somewhat better. */ - if (chain->need_reload) - { - REG_SET_TO_HARD_REG_SET (used_by_pseudos, &chain->live_throughout); - REG_SET_TO_HARD_REG_SET (used_by_pseudos2, &chain->dead_or_set); - used_by_pseudos |= used_by_pseudos2; - - compute_use_by_pseudos (&used_by_pseudos, &chain->live_throughout); - compute_use_by_pseudos (&used_by_pseudos, &chain->dead_or_set); - /* Value of chain->used_spill_regs from previous iteration - may be not included in the value calculated here because - of possible removing caller-saves insns (see function - delete_caller_save_insns. */ - chain->used_spill_regs = ~used_by_pseudos & used_spill_regs; - } - } - - CLEAR_REG_SET (&changed_allocation_pseudos); - /* Let alter_reg modify the reg rtx's for the modified pseudos. */ - for (i = FIRST_PSEUDO_REGISTER; i < (unsigned)max_regno; i++) - { - int regno = reg_renumber[i]; - if (reg_old_renumber[i] == regno) - continue; - - SET_REGNO_REG_SET (&changed_allocation_pseudos, i); - - alter_reg (i, reg_old_renumber[i], false); - reg_old_renumber[i] = regno; - if (dump_file) - { - if (regno == -1) - fprintf (dump_file, " Register %d now on stack.\n\n", i); - else - fprintf (dump_file, " Register %d now in %d.\n\n", - i, reg_renumber[i]); - } - } - - return something_changed; -} - -/* Find all paradoxical subregs within X and update reg_max_ref_mode. */ - -static void -scan_paradoxical_subregs (rtx x) -{ - int i; - const char *fmt; - enum rtx_code code = GET_CODE (x); - - switch (code) - { - case REG: - case CONST: - case SYMBOL_REF: - case LABEL_REF: - CASE_CONST_ANY: - case PC: - case USE: - case CLOBBER: - return; - - case SUBREG: - if (REG_P (SUBREG_REG (x))) - { - unsigned int regno = REGNO (SUBREG_REG (x)); - if (partial_subreg_p (reg_max_ref_mode[regno], GET_MODE (x))) - { - reg_max_ref_mode[regno] = GET_MODE (x); - mark_home_live_1 (regno, GET_MODE (x)); - } - } - return; - - default: - break; - } - - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - scan_paradoxical_subregs (XEXP (x, i)); - else if (fmt[i] == 'E') - { - int j; - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - scan_paradoxical_subregs (XVECEXP (x, i, j)); - } - } -} - -/* *OP_PTR and *OTHER_PTR are two operands to a conceptual reload. - If *OP_PTR is a paradoxical subreg, try to remove that subreg - and apply the corresponding narrowing subreg to *OTHER_PTR. - Return true if the operands were changed, false otherwise. */ - -static bool -strip_paradoxical_subreg (rtx *op_ptr, rtx *other_ptr) -{ - rtx op, inner, other, tem; - - op = *op_ptr; - if (!paradoxical_subreg_p (op)) - return false; - inner = SUBREG_REG (op); - - other = *other_ptr; - tem = gen_lowpart_common (GET_MODE (inner), other); - if (!tem) - return false; - - /* If the lowpart operation turned a hard register into a subreg, - rather than simplifying it to another hard register, then the - mode change cannot be properly represented. For example, OTHER - might be valid in its current mode, but not in the new one. */ - if (GET_CODE (tem) == SUBREG - && REG_P (other) - && HARD_REGISTER_P (other)) - return false; - - *op_ptr = inner; - *other_ptr = tem; - return true; -} - -/* A subroutine of reload_as_needed. If INSN has a REG_EH_REGION note, - examine all of the reload insns between PREV and NEXT exclusive, and - annotate all that may trap. */ - -static void -fixup_eh_region_note (rtx_insn *insn, rtx_insn *prev, rtx_insn *next) -{ - rtx note = find_reg_note (insn, REG_EH_REGION, NULL_RTX); - if (note == NULL) - return; - if (!insn_could_throw_p (insn)) - remove_note (insn, note); - copy_reg_eh_region_note_forward (note, NEXT_INSN (prev), next); -} - -/* Reload pseudo-registers into hard regs around each insn as needed. - Additional register load insns are output before the insn that needs it - and perhaps store insns after insns that modify the reloaded pseudo reg. - - reg_last_reload_reg and reg_reloaded_contents keep track of - which registers are already available in reload registers. - We update these for the reloads that we perform, - as the insns are scanned. */ - -static void -reload_as_needed (int live_known) -{ - class insn_chain *chain; -#if AUTO_INC_DEC - int i; -#endif - rtx_note *marker; - - memset (spill_reg_rtx, 0, sizeof spill_reg_rtx); - memset (spill_reg_store, 0, sizeof spill_reg_store); - reg_last_reload_reg = XCNEWVEC (rtx, max_regno); - INIT_REG_SET (®_has_output_reload); - CLEAR_HARD_REG_SET (reg_reloaded_valid); - - set_initial_elim_offsets (); - - /* Generate a marker insn that we will move around. */ - marker = emit_note (NOTE_INSN_DELETED); - unlink_insn_chain (marker, marker); - - for (chain = reload_insn_chain; chain; chain = chain->next) - { - rtx_insn *prev = 0; - rtx_insn *insn = chain->insn; - rtx_insn *old_next = NEXT_INSN (insn); -#if AUTO_INC_DEC - rtx_insn *old_prev = PREV_INSN (insn); -#endif - - if (will_delete_init_insn_p (insn)) - continue; - - /* If we pass a label, copy the offsets from the label information - into the current offsets of each elimination. */ - if (LABEL_P (insn)) - set_offsets_for_label (insn); - - else if (INSN_P (insn)) - { - regset_head regs_to_forget; - INIT_REG_SET (®s_to_forget); - note_stores (insn, forget_old_reloads_1, ®s_to_forget); - - /* If this is a USE and CLOBBER of a MEM, ensure that any - references to eliminable registers have been removed. */ - - if ((GET_CODE (PATTERN (insn)) == USE - || GET_CODE (PATTERN (insn)) == CLOBBER) - && MEM_P (XEXP (PATTERN (insn), 0))) - XEXP (XEXP (PATTERN (insn), 0), 0) - = eliminate_regs (XEXP (XEXP (PATTERN (insn), 0), 0), - GET_MODE (XEXP (PATTERN (insn), 0)), - NULL_RTX); - - /* If we need to do register elimination processing, do so. - This might delete the insn, in which case we are done. */ - if ((num_eliminable || num_eliminable_invariants) && chain->need_elim) - { - eliminate_regs_in_insn (insn, 1); - if (NOTE_P (insn)) - { - update_eliminable_offsets (); - CLEAR_REG_SET (®s_to_forget); - continue; - } - } - - /* If need_elim is nonzero but need_reload is zero, one might think - that we could simply set n_reloads to 0. However, find_reloads - could have done some manipulation of the insn (such as swapping - commutative operands), and these manipulations are lost during - the first pass for every insn that needs register elimination. - So the actions of find_reloads must be redone here. */ - - if (! chain->need_elim && ! chain->need_reload - && ! chain->need_operand_change) - n_reloads = 0; - /* First find the pseudo regs that must be reloaded for this insn. - This info is returned in the tables reload_... (see reload.h). - Also modify the body of INSN by substituting RELOAD - rtx's for those pseudo regs. */ - else - { - CLEAR_REG_SET (®_has_output_reload); - CLEAR_HARD_REG_SET (reg_is_output_reload); - - find_reloads (insn, 1, spill_indirect_levels, live_known, - spill_reg_order); - } - - if (n_reloads > 0) - { - rtx_insn *next = NEXT_INSN (insn); - - /* ??? PREV can get deleted by reload inheritance. - Work around this by emitting a marker note. */ - prev = PREV_INSN (insn); - reorder_insns_nobb (marker, marker, prev); - - /* Now compute which reload regs to reload them into. Perhaps - reusing reload regs from previous insns, or else output - load insns to reload them. Maybe output store insns too. - Record the choices of reload reg in reload_reg_rtx. */ - choose_reload_regs (chain); - - /* Generate the insns to reload operands into or out of - their reload regs. */ - emit_reload_insns (chain); - - /* Substitute the chosen reload regs from reload_reg_rtx - into the insn's body (or perhaps into the bodies of other - load and store insn that we just made for reloading - and that we moved the structure into). */ - subst_reloads (insn); - - prev = PREV_INSN (marker); - unlink_insn_chain (marker, marker); - - /* Adjust the exception region notes for loads and stores. */ - if (cfun->can_throw_non_call_exceptions && !CALL_P (insn)) - fixup_eh_region_note (insn, prev, next); - - /* Adjust the location of REG_ARGS_SIZE. */ - rtx p = find_reg_note (insn, REG_ARGS_SIZE, NULL_RTX); - if (p) - { - remove_note (insn, p); - fixup_args_size_notes (prev, PREV_INSN (next), - get_args_size (p)); - } - - /* If this was an ASM, make sure that all the reload insns - we have generated are valid. If not, give an error - and delete them. */ - if (asm_noperands (PATTERN (insn)) >= 0) - for (rtx_insn *p = NEXT_INSN (prev); - p != next; - p = NEXT_INSN (p)) - if (p != insn && INSN_P (p) - && GET_CODE (PATTERN (p)) != USE - && (recog_memoized (p) < 0 - || (extract_insn (p), - !(constrain_operands (1, - get_enabled_alternatives (p)))))) - { - error_for_asm (insn, - "%<asm%> operand requires " - "impossible reload"); - delete_insn (p); - } - } - - if (num_eliminable && chain->need_elim) - update_eliminable_offsets (); - - /* Any previously reloaded spilled pseudo reg, stored in this insn, - is no longer validly lying around to save a future reload. - Note that this does not detect pseudos that were reloaded - for this insn in order to be stored in - (obeying register constraints). That is correct; such reload - registers ARE still valid. */ - forget_marked_reloads (®s_to_forget); - CLEAR_REG_SET (®s_to_forget); - - /* There may have been CLOBBER insns placed after INSN. So scan - between INSN and NEXT and use them to forget old reloads. */ - for (rtx_insn *x = NEXT_INSN (insn); x != old_next; x = NEXT_INSN (x)) - if (NONJUMP_INSN_P (x) && GET_CODE (PATTERN (x)) == CLOBBER) - note_stores (x, forget_old_reloads_1, NULL); - -#if AUTO_INC_DEC - /* Likewise for regs altered by auto-increment in this insn. - REG_INC notes have been changed by reloading: - find_reloads_address_1 records substitutions for them, - which have been performed by subst_reloads above. */ - for (i = n_reloads - 1; i >= 0; i--) - { - rtx in_reg = rld[i].in_reg; - if (in_reg) - { - enum rtx_code code = GET_CODE (in_reg); - /* PRE_INC / PRE_DEC will have the reload register ending up - with the same value as the stack slot, but that doesn't - hold true for POST_INC / POST_DEC. Either we have to - convert the memory access to a true POST_INC / POST_DEC, - or we can't use the reload register for inheritance. */ - if ((code == POST_INC || code == POST_DEC) - && TEST_HARD_REG_BIT (reg_reloaded_valid, - REGNO (rld[i].reg_rtx)) - /* Make sure it is the inc/dec pseudo, and not - some other (e.g. output operand) pseudo. */ - && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)] - == REGNO (XEXP (in_reg, 0)))) - - { - rtx reload_reg = rld[i].reg_rtx; - machine_mode mode = GET_MODE (reload_reg); - int n = 0; - rtx_insn *p; - - for (p = PREV_INSN (old_next); p != prev; p = PREV_INSN (p)) - { - /* We really want to ignore REG_INC notes here, so - use PATTERN (p) as argument to reg_set_p . */ - if (reg_set_p (reload_reg, PATTERN (p))) - break; - n = count_occurrences (PATTERN (p), reload_reg, 0); - if (! n) - continue; - if (n == 1) - { - rtx replace_reg - = gen_rtx_fmt_e (code, mode, reload_reg); - - validate_replace_rtx_group (reload_reg, - replace_reg, p); - n = verify_changes (0); - - /* We must also verify that the constraints - are met after the replacement. Make sure - extract_insn is only called for an insn - where the replacements were found to be - valid so far. */ - if (n) - { - extract_insn (p); - n = constrain_operands (1, - get_enabled_alternatives (p)); - } - - /* If the constraints were not met, then - undo the replacement, else confirm it. */ - if (!n) - cancel_changes (0); - else - confirm_change_group (); - } - break; - } - if (n == 1) - { - add_reg_note (p, REG_INC, reload_reg); - /* Mark this as having an output reload so that the - REG_INC processing code below won't invalidate - the reload for inheritance. */ - SET_HARD_REG_BIT (reg_is_output_reload, - REGNO (reload_reg)); - SET_REGNO_REG_SET (®_has_output_reload, - REGNO (XEXP (in_reg, 0))); - } - else - forget_old_reloads_1 (XEXP (in_reg, 0), NULL_RTX, - NULL); - } - else if ((code == PRE_INC || code == PRE_DEC) - && TEST_HARD_REG_BIT (reg_reloaded_valid, - REGNO (rld[i].reg_rtx)) - /* Make sure it is the inc/dec pseudo, and not - some other (e.g. output operand) pseudo. */ - && ((unsigned) reg_reloaded_contents[REGNO (rld[i].reg_rtx)] - == REGNO (XEXP (in_reg, 0)))) - { - SET_HARD_REG_BIT (reg_is_output_reload, - REGNO (rld[i].reg_rtx)); - SET_REGNO_REG_SET (®_has_output_reload, - REGNO (XEXP (in_reg, 0))); - } - else if (code == PRE_INC || code == PRE_DEC - || code == POST_INC || code == POST_DEC) - { - int in_regno = REGNO (XEXP (in_reg, 0)); - - if (reg_last_reload_reg[in_regno] != NULL_RTX) - { - int in_hard_regno; - bool forget_p = true; - - in_hard_regno = REGNO (reg_last_reload_reg[in_regno]); - if (TEST_HARD_REG_BIT (reg_reloaded_valid, - in_hard_regno)) - { - for (rtx_insn *x = (old_prev ? - NEXT_INSN (old_prev) : insn); - x != old_next; - x = NEXT_INSN (x)) - if (x == reg_reloaded_insn[in_hard_regno]) - { - forget_p = false; - break; - } - } - /* If for some reasons, we didn't set up - reg_last_reload_reg in this insn, - invalidate inheritance from previous - insns for the incremented/decremented - register. Such registers will be not in - reg_has_output_reload. Invalidate it - also if the corresponding element in - reg_reloaded_insn is also - invalidated. */ - if (forget_p) - forget_old_reloads_1 (XEXP (in_reg, 0), - NULL_RTX, NULL); - } - } - } - } - /* If a pseudo that got a hard register is auto-incremented, - we must purge records of copying it into pseudos without - hard registers. */ - for (rtx x = REG_NOTES (insn); x; x = XEXP (x, 1)) - if (REG_NOTE_KIND (x) == REG_INC) - { - /* See if this pseudo reg was reloaded in this insn. - If so, its last-reload info is still valid - because it is based on this insn's reload. */ - for (i = 0; i < n_reloads; i++) - if (rld[i].out == XEXP (x, 0)) - break; - - if (i == n_reloads) - forget_old_reloads_1 (XEXP (x, 0), NULL_RTX, NULL); - } -#endif - } - /* A reload reg's contents are unknown after a label. */ - if (LABEL_P (insn)) - CLEAR_HARD_REG_SET (reg_reloaded_valid); - - /* Don't assume a reload reg is still good after a call insn - if it is a call-used reg, or if it contains a value that will - be partially clobbered by the call. */ - else if (CALL_P (insn)) - { - reg_reloaded_valid - &= ~insn_callee_abi (insn).full_and_partial_reg_clobbers (); - - /* If this is a call to a setjmp-type function, we must not - reuse any reload reg contents across the call; that will - just be clobbered by other uses of the register in later - code, before the longjmp. */ - if (find_reg_note (insn, REG_SETJMP, NULL_RTX)) - CLEAR_HARD_REG_SET (reg_reloaded_valid); - } - } - - /* Clean up. */ - free (reg_last_reload_reg); - CLEAR_REG_SET (®_has_output_reload); -} - -/* Discard all record of any value reloaded from X, - or reloaded in X from someplace else; - unless X is an output reload reg of the current insn. - - X may be a hard reg (the reload reg) - or it may be a pseudo reg that was reloaded from. - - When DATA is non-NULL just mark the registers in regset - to be forgotten later. */ - -static void -forget_old_reloads_1 (rtx x, const_rtx, void *data) -{ - unsigned int regno; - unsigned int nr; - regset regs = (regset) data; - - /* note_stores does give us subregs of hard regs, - subreg_regno_offset requires a hard reg. */ - while (GET_CODE (x) == SUBREG) - { - /* We ignore the subreg offset when calculating the regno, - because we are using the entire underlying hard register - below. */ - x = SUBREG_REG (x); - } - - if (!REG_P (x)) - return; - - regno = REGNO (x); - - if (regno >= FIRST_PSEUDO_REGISTER) - nr = 1; - else - { - unsigned int i; - - nr = REG_NREGS (x); - /* Storing into a spilled-reg invalidates its contents. - This can happen if a block-local pseudo is allocated to that reg - and it wasn't spilled because this block's total need is 0. - Then some insn might have an optional reload and use this reg. */ - if (!regs) - for (i = 0; i < nr; i++) - /* But don't do this if the reg actually serves as an output - reload reg in the current instruction. */ - if (n_reloads == 0 - || ! TEST_HARD_REG_BIT (reg_is_output_reload, regno + i)) - { - CLEAR_HARD_REG_BIT (reg_reloaded_valid, regno + i); - spill_reg_store[regno + i] = 0; - } - } - - if (regs) - while (nr-- > 0) - SET_REGNO_REG_SET (regs, regno + nr); - else - { - /* Since value of X has changed, - forget any value previously copied from it. */ - - while (nr-- > 0) - /* But don't forget a copy if this is the output reload - that establishes the copy's validity. */ - if (n_reloads == 0 - || !REGNO_REG_SET_P (®_has_output_reload, regno + nr)) - reg_last_reload_reg[regno + nr] = 0; - } -} - -/* Forget the reloads marked in regset by previous function. */ -static void -forget_marked_reloads (regset regs) -{ - unsigned int reg; - reg_set_iterator rsi; - EXECUTE_IF_SET_IN_REG_SET (regs, 0, reg, rsi) - { - if (reg < FIRST_PSEUDO_REGISTER - /* But don't do this if the reg actually serves as an output - reload reg in the current instruction. */ - && (n_reloads == 0 - || ! TEST_HARD_REG_BIT (reg_is_output_reload, reg))) - { - CLEAR_HARD_REG_BIT (reg_reloaded_valid, reg); - spill_reg_store[reg] = 0; - } - if (n_reloads == 0 - || !REGNO_REG_SET_P (®_has_output_reload, reg)) - reg_last_reload_reg[reg] = 0; - } -} - -/* The following HARD_REG_SETs indicate when each hard register is - used for a reload of various parts of the current insn. */ - -/* If reg is unavailable for all reloads. */ -static HARD_REG_SET reload_reg_unavailable; -/* If reg is in use as a reload reg for a RELOAD_OTHER reload. */ -static HARD_REG_SET reload_reg_used; -/* If reg is in use for a RELOAD_FOR_INPUT_ADDRESS reload for operand I. */ -static HARD_REG_SET reload_reg_used_in_input_addr[MAX_RECOG_OPERANDS]; -/* If reg is in use for a RELOAD_FOR_INPADDR_ADDRESS reload for operand I. */ -static HARD_REG_SET reload_reg_used_in_inpaddr_addr[MAX_RECOG_OPERANDS]; -/* If reg is in use for a RELOAD_FOR_OUTPUT_ADDRESS reload for operand I. */ -static HARD_REG_SET reload_reg_used_in_output_addr[MAX_RECOG_OPERANDS]; -/* If reg is in use for a RELOAD_FOR_OUTADDR_ADDRESS reload for operand I. */ -static HARD_REG_SET reload_reg_used_in_outaddr_addr[MAX_RECOG_OPERANDS]; -/* If reg is in use for a RELOAD_FOR_INPUT reload for operand I. */ -static HARD_REG_SET reload_reg_used_in_input[MAX_RECOG_OPERANDS]; -/* If reg is in use for a RELOAD_FOR_OUTPUT reload for operand I. */ -static HARD_REG_SET reload_reg_used_in_output[MAX_RECOG_OPERANDS]; -/* If reg is in use for a RELOAD_FOR_OPERAND_ADDRESS reload. */ -static HARD_REG_SET reload_reg_used_in_op_addr; -/* If reg is in use for a RELOAD_FOR_OPADDR_ADDR reload. */ -static HARD_REG_SET reload_reg_used_in_op_addr_reload; -/* If reg is in use for a RELOAD_FOR_INSN reload. */ -static HARD_REG_SET reload_reg_used_in_insn; -/* If reg is in use for a RELOAD_FOR_OTHER_ADDRESS reload. */ -static HARD_REG_SET reload_reg_used_in_other_addr; - -/* If reg is in use as a reload reg for any sort of reload. */ -static HARD_REG_SET reload_reg_used_at_all; - -/* If reg is use as an inherited reload. We just mark the first register - in the group. */ -static HARD_REG_SET reload_reg_used_for_inherit; - -/* Records which hard regs are used in any way, either as explicit use or - by being allocated to a pseudo during any point of the current insn. */ -static HARD_REG_SET reg_used_in_insn; - -/* Mark reg REGNO as in use for a reload of the sort spec'd by OPNUM and - TYPE. MODE is used to indicate how many consecutive regs are - actually used. */ - -static void -mark_reload_reg_in_use (unsigned int regno, int opnum, enum reload_type type, - machine_mode mode) -{ - switch (type) - { - case RELOAD_OTHER: - add_to_hard_reg_set (&reload_reg_used, mode, regno); - break; - - case RELOAD_FOR_INPUT_ADDRESS: - add_to_hard_reg_set (&reload_reg_used_in_input_addr[opnum], mode, regno); - break; - - case RELOAD_FOR_INPADDR_ADDRESS: - add_to_hard_reg_set (&reload_reg_used_in_inpaddr_addr[opnum], mode, regno); - break; - - case RELOAD_FOR_OUTPUT_ADDRESS: - add_to_hard_reg_set (&reload_reg_used_in_output_addr[opnum], mode, regno); - break; - - case RELOAD_FOR_OUTADDR_ADDRESS: - add_to_hard_reg_set (&reload_reg_used_in_outaddr_addr[opnum], mode, regno); - break; - - case RELOAD_FOR_OPERAND_ADDRESS: - add_to_hard_reg_set (&reload_reg_used_in_op_addr, mode, regno); - break; - - case RELOAD_FOR_OPADDR_ADDR: - add_to_hard_reg_set (&reload_reg_used_in_op_addr_reload, mode, regno); - break; - - case RELOAD_FOR_OTHER_ADDRESS: - add_to_hard_reg_set (&reload_reg_used_in_other_addr, mode, regno); - break; - - case RELOAD_FOR_INPUT: - add_to_hard_reg_set (&reload_reg_used_in_input[opnum], mode, regno); - break; - - case RELOAD_FOR_OUTPUT: - add_to_hard_reg_set (&reload_reg_used_in_output[opnum], mode, regno); - break; - - case RELOAD_FOR_INSN: - add_to_hard_reg_set (&reload_reg_used_in_insn, mode, regno); - break; - } - - add_to_hard_reg_set (&reload_reg_used_at_all, mode, regno); -} - -/* Similarly, but show REGNO is no longer in use for a reload. */ - -static void -clear_reload_reg_in_use (unsigned int regno, int opnum, - enum reload_type type, machine_mode mode) -{ - unsigned int nregs = hard_regno_nregs (regno, mode); - unsigned int start_regno, end_regno, r; - int i; - /* A complication is that for some reload types, inheritance might - allow multiple reloads of the same types to share a reload register. - We set check_opnum if we have to check only reloads with the same - operand number, and check_any if we have to check all reloads. */ - int check_opnum = 0; - int check_any = 0; - HARD_REG_SET *used_in_set; - - switch (type) - { - case RELOAD_OTHER: - used_in_set = &reload_reg_used; - break; - - case RELOAD_FOR_INPUT_ADDRESS: - used_in_set = &reload_reg_used_in_input_addr[opnum]; - break; - - case RELOAD_FOR_INPADDR_ADDRESS: - check_opnum = 1; - used_in_set = &reload_reg_used_in_inpaddr_addr[opnum]; - break; - - case RELOAD_FOR_OUTPUT_ADDRESS: - used_in_set = &reload_reg_used_in_output_addr[opnum]; - break; - - case RELOAD_FOR_OUTADDR_ADDRESS: - check_opnum = 1; - used_in_set = &reload_reg_used_in_outaddr_addr[opnum]; - break; - - case RELOAD_FOR_OPERAND_ADDRESS: - used_in_set = &reload_reg_used_in_op_addr; - break; - - case RELOAD_FOR_OPADDR_ADDR: - check_any = 1; - used_in_set = &reload_reg_used_in_op_addr_reload; - break; - - case RELOAD_FOR_OTHER_ADDRESS: - used_in_set = &reload_reg_used_in_other_addr; - check_any = 1; - break; - - case RELOAD_FOR_INPUT: - used_in_set = &reload_reg_used_in_input[opnum]; - break; - - case RELOAD_FOR_OUTPUT: - used_in_set = &reload_reg_used_in_output[opnum]; - break; - - case RELOAD_FOR_INSN: - used_in_set = &reload_reg_used_in_insn; - break; - default: - gcc_unreachable (); - } - /* We resolve conflicts with remaining reloads of the same type by - excluding the intervals of reload registers by them from the - interval of freed reload registers. Since we only keep track of - one set of interval bounds, we might have to exclude somewhat - more than what would be necessary if we used a HARD_REG_SET here. - But this should only happen very infrequently, so there should - be no reason to worry about it. */ - - start_regno = regno; - end_regno = regno + nregs; - if (check_opnum || check_any) - { - for (i = n_reloads - 1; i >= 0; i--) - { - if (rld[i].when_needed == type - && (check_any || rld[i].opnum == opnum) - && rld[i].reg_rtx) - { - unsigned int conflict_start = true_regnum (rld[i].reg_rtx); - unsigned int conflict_end - = end_hard_regno (rld[i].mode, conflict_start); - - /* If there is an overlap with the first to-be-freed register, - adjust the interval start. */ - if (conflict_start <= start_regno && conflict_end > start_regno) - start_regno = conflict_end; - /* Otherwise, if there is a conflict with one of the other - to-be-freed registers, adjust the interval end. */ - if (conflict_start > start_regno && conflict_start < end_regno) - end_regno = conflict_start; - } - } - } - - for (r = start_regno; r < end_regno; r++) - CLEAR_HARD_REG_BIT (*used_in_set, r); -} - -/* 1 if reg REGNO is free as a reload reg for a reload of the sort - specified by OPNUM and TYPE. */ - -static int -reload_reg_free_p (unsigned int regno, int opnum, enum reload_type type) -{ - int i; - - /* In use for a RELOAD_OTHER means it's not available for anything. */ - if (TEST_HARD_REG_BIT (reload_reg_used, regno) - || TEST_HARD_REG_BIT (reload_reg_unavailable, regno)) - return 0; - - switch (type) - { - case RELOAD_OTHER: - /* In use for anything means we can't use it for RELOAD_OTHER. */ - if (TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)) - return 0; - - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) - return 0; - - return 1; - - case RELOAD_FOR_INPUT: - if (TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)) - return 0; - - if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)) - return 0; - - /* If it is used for some other input, can't use it. */ - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) - return 0; - - /* If it is used in a later operand's address, can't use it. */ - for (i = opnum + 1; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)) - return 0; - - return 1; - - case RELOAD_FOR_INPUT_ADDRESS: - /* Can't use a register if it is used for an input address for this - operand or used as an input in an earlier one. */ - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno)) - return 0; - - for (i = 0; i < opnum; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) - return 0; - - return 1; - - case RELOAD_FOR_INPADDR_ADDRESS: - /* Can't use a register if it is used for an input address - for this operand or used as an input in an earlier - one. */ - if (TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[opnum], regno)) - return 0; - - for (i = 0; i < opnum; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) - return 0; - - return 1; - - case RELOAD_FOR_OUTPUT_ADDRESS: - /* Can't use a register if it is used for an output address for this - operand or used as an output in this or a later operand. Note - that multiple output operands are emitted in reverse order, so - the conflicting ones are those with lower indices. */ - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[opnum], regno)) - return 0; - - for (i = 0; i <= opnum; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) - return 0; - - return 1; - - case RELOAD_FOR_OUTADDR_ADDRESS: - /* Can't use a register if it is used for an output address - for this operand or used as an output in this or a - later operand. Note that multiple output operands are - emitted in reverse order, so the conflicting ones are - those with lower indices. */ - if (TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno)) - return 0; - - for (i = 0; i <= opnum; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) - return 0; - - return 1; - - case RELOAD_FOR_OPERAND_ADDRESS: - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) - return 0; - - return (! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno) - && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)); - - case RELOAD_FOR_OPADDR_ADDR: - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) - return 0; - - return (!TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)); - - case RELOAD_FOR_OUTPUT: - /* This cannot share a register with RELOAD_FOR_INSN reloads, other - outputs, or an operand address for this or an earlier output. - Note that multiple output operands are emitted in reverse order, - so the conflicting ones are those with higher indices. */ - if (TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno)) - return 0; - - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) - return 0; - - for (i = opnum; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)) - return 0; - - return 1; - - case RELOAD_FOR_INSN: - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) - return 0; - - return (! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno) - && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno)); - - case RELOAD_FOR_OTHER_ADDRESS: - return ! TEST_HARD_REG_BIT (reload_reg_used_in_other_addr, regno); - - default: - gcc_unreachable (); - } -} - -/* Return 1 if the value in reload reg REGNO, as used by the reload with - the number RELOADNUM, is still available in REGNO at the end of the insn. - - We can assume that the reload reg was already tested for availability - at the time it is needed, and we should not check this again, - in case the reg has already been marked in use. */ - -static int -reload_reg_reaches_end_p (unsigned int regno, int reloadnum) -{ - int opnum = rld[reloadnum].opnum; - enum reload_type type = rld[reloadnum].when_needed; - int i; - - /* See if there is a reload with the same type for this operand, using - the same register. This case is not handled by the code below. */ - for (i = reloadnum + 1; i < n_reloads; i++) - { - rtx reg; - - if (rld[i].opnum != opnum || rld[i].when_needed != type) - continue; - reg = rld[i].reg_rtx; - if (reg == NULL_RTX) - continue; - if (regno >= REGNO (reg) && regno < END_REGNO (reg)) - return 0; - } - - switch (type) - { - case RELOAD_OTHER: - /* Since a RELOAD_OTHER reload claims the reg for the entire insn, - its value must reach the end. */ - return 1; - - /* If this use is for part of the insn, - its value reaches if no subsequent part uses the same register. - Just like the above function, don't try to do this with lots - of fallthroughs. */ - - case RELOAD_FOR_OTHER_ADDRESS: - /* Here we check for everything else, since these don't conflict - with anything else and everything comes later. */ - - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) - return 0; - - return (! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno) - && ! TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno) - && ! TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno) - && ! TEST_HARD_REG_BIT (reload_reg_used, regno)); - - case RELOAD_FOR_INPUT_ADDRESS: - case RELOAD_FOR_INPADDR_ADDRESS: - /* Similar, except that we check only for this and subsequent inputs - and the address of only subsequent inputs and we do not need - to check for RELOAD_OTHER objects since they are known not to - conflict. */ - - for (i = opnum; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) - return 0; - - /* Reload register of reload with type RELOAD_FOR_INPADDR_ADDRESS - could be killed if the register is also used by reload with type - RELOAD_FOR_INPUT_ADDRESS, so check it. */ - if (type == RELOAD_FOR_INPADDR_ADDRESS - && TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[opnum], regno)) - return 0; - - for (i = opnum + 1; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno)) - return 0; - - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) - return 0; - - if (TEST_HARD_REG_BIT (reload_reg_used_in_op_addr_reload, regno)) - return 0; - - return (!TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno) - && !TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno) - && !TEST_HARD_REG_BIT (reload_reg_used, regno)); - - case RELOAD_FOR_INPUT: - /* Similar to input address, except we start at the next operand for - both input and input address and we do not check for - RELOAD_FOR_OPERAND_ADDRESS and RELOAD_FOR_INSN since these - would conflict. */ - - for (i = opnum + 1; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_input_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_inpaddr_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_input[i], regno)) - return 0; - - /* ... fall through ... */ - - case RELOAD_FOR_OPERAND_ADDRESS: - /* Check outputs and their addresses. */ - - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) - return 0; - - return (!TEST_HARD_REG_BIT (reload_reg_used, regno)); - - case RELOAD_FOR_OPADDR_ADDR: - for (i = 0; i < reload_n_operands; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_output[i], regno)) - return 0; - - return (!TEST_HARD_REG_BIT (reload_reg_used_in_op_addr, regno) - && !TEST_HARD_REG_BIT (reload_reg_used_in_insn, regno) - && !TEST_HARD_REG_BIT (reload_reg_used, regno)); - - case RELOAD_FOR_INSN: - /* These conflict with other outputs with RELOAD_OTHER. So - we need only check for output addresses. */ - - opnum = reload_n_operands; - - /* fall through */ - - case RELOAD_FOR_OUTPUT: - case RELOAD_FOR_OUTPUT_ADDRESS: - case RELOAD_FOR_OUTADDR_ADDRESS: - /* We already know these can't conflict with a later output. So the - only thing to check are later output addresses. - Note that multiple output operands are emitted in reverse order, - so the conflicting ones are those with lower indices. */ - for (i = 0; i < opnum; i++) - if (TEST_HARD_REG_BIT (reload_reg_used_in_output_addr[i], regno) - || TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[i], regno)) - return 0; - - /* Reload register of reload with type RELOAD_FOR_OUTADDR_ADDRESS - could be killed if the register is also used by reload with type - RELOAD_FOR_OUTPUT_ADDRESS, so check it. */ - if (type == RELOAD_FOR_OUTADDR_ADDRESS - && TEST_HARD_REG_BIT (reload_reg_used_in_outaddr_addr[opnum], regno)) - return 0; - - return 1; - - default: - gcc_unreachable (); - } -} - -/* Like reload_reg_reaches_end_p, but check that the condition holds for - every register in REG. */ - -static bool -reload_reg_rtx_reaches_end_p (rtx reg, int reloadnum) -{ - unsigned int i; - - for (i = REGNO (reg); i < END_REGNO (reg); i++) - if (!reload_reg_reaches_end_p (i, reloadnum)) - return false; - return true; -} - - -/* Returns whether R1 and R2 are uniquely chained: the value of one - is used by the other, and that value is not used by any other - reload for this insn. This is used to partially undo the decision - made in find_reloads when in the case of multiple - RELOAD_FOR_OPERAND_ADDRESS reloads it converts all - RELOAD_FOR_OPADDR_ADDR reloads into RELOAD_FOR_OPERAND_ADDRESS - reloads. This code tries to avoid the conflict created by that - change. It might be cleaner to explicitly keep track of which - RELOAD_FOR_OPADDR_ADDR reload is associated with which - RELOAD_FOR_OPERAND_ADDRESS reload, rather than to try to detect - this after the fact. */ -static bool -reloads_unique_chain_p (int r1, int r2) -{ - int i; - - /* We only check input reloads. */ - if (! rld[r1].in || ! rld[r2].in) - return false; - - /* Avoid anything with output reloads. */ - if (rld[r1].out || rld[r2].out) - return false; - - /* "chained" means one reload is a component of the other reload, - not the same as the other reload. */ - if (rld[r1].opnum != rld[r2].opnum - || rtx_equal_p (rld[r1].in, rld[r2].in) - || rld[r1].optional || rld[r2].optional - || ! (reg_mentioned_p (rld[r1].in, rld[r2].in) - || reg_mentioned_p (rld[r2].in, rld[r1].in))) - return false; - - /* The following loop assumes that r1 is the reload that feeds r2. */ - if (r1 > r2) - std::swap (r1, r2); - - for (i = 0; i < n_reloads; i ++) - /* Look for input reloads that aren't our two */ - if (i != r1 && i != r2 && rld[i].in) - { - /* If our reload is mentioned at all, it isn't a simple chain. */ - if (reg_mentioned_p (rld[r1].in, rld[i].in)) - return false; - } - return true; -} - -/* The recursive function change all occurrences of WHAT in *WHERE - to REPL. */ -static void -substitute (rtx *where, const_rtx what, rtx repl) -{ - const char *fmt; - int i; - enum rtx_code code; - - if (*where == 0) - return; - - if (*where == what || rtx_equal_p (*where, what)) - { - /* Record the location of the changed rtx. */ - substitute_stack.safe_push (where); - *where = repl; - return; - } - - code = GET_CODE (*where); - fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'E') - { - int j; - - for (j = XVECLEN (*where, i) - 1; j >= 0; j--) - substitute (&XVECEXP (*where, i, j), what, repl); - } - else if (fmt[i] == 'e') - substitute (&XEXP (*where, i), what, repl); - } -} - -/* The function returns TRUE if chain of reload R1 and R2 (in any - order) can be evaluated without usage of intermediate register for - the reload containing another reload. It is important to see - gen_reload to understand what the function is trying to do. As an - example, let us have reload chain - - r2: const - r1: <something> + const - - and reload R2 got reload reg HR. The function returns true if - there is a correct insn HR = HR + <something>. Otherwise, - gen_reload will use intermediate register (and this is the reload - reg for R1) to reload <something>. - - We need this function to find a conflict for chain reloads. In our - example, if HR = HR + <something> is incorrect insn, then we cannot - use HR as a reload register for R2. If we do use it then we get a - wrong code: - - HR = const - HR = <something> - HR = HR + HR - -*/ -static bool -gen_reload_chain_without_interm_reg_p (int r1, int r2) -{ - /* Assume other cases in gen_reload are not possible for - chain reloads or do need an intermediate hard registers. */ - bool result = true; - int regno, code; - rtx out, in; - rtx_insn *insn; - rtx_insn *last = get_last_insn (); - - /* Make r2 a component of r1. */ - if (reg_mentioned_p (rld[r1].in, rld[r2].in)) - std::swap (r1, r2); - - gcc_assert (reg_mentioned_p (rld[r2].in, rld[r1].in)); - regno = rld[r1].regno >= 0 ? rld[r1].regno : rld[r2].regno; - gcc_assert (regno >= 0); - out = gen_rtx_REG (rld[r1].mode, regno); - in = rld[r1].in; - substitute (&in, rld[r2].in, gen_rtx_REG (rld[r2].mode, regno)); - - /* If IN is a paradoxical SUBREG, remove it and try to put the - opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */ - strip_paradoxical_subreg (&in, &out); - - if (GET_CODE (in) == PLUS - && (REG_P (XEXP (in, 0)) - || GET_CODE (XEXP (in, 0)) == SUBREG - || MEM_P (XEXP (in, 0))) - && (REG_P (XEXP (in, 1)) - || GET_CODE (XEXP (in, 1)) == SUBREG - || CONSTANT_P (XEXP (in, 1)) - || MEM_P (XEXP (in, 1)))) - { - insn = emit_insn (gen_rtx_SET (out, in)); - code = recog_memoized (insn); - result = false; - - if (code >= 0) - { - extract_insn (insn); - /* We want constrain operands to treat this insn strictly in - its validity determination, i.e., the way it would after - reload has completed. */ - result = constrain_operands (1, get_enabled_alternatives (insn)); - } - - delete_insns_since (last); - } - - /* Restore the original value at each changed address within R1. */ - while (!substitute_stack.is_empty ()) - { - rtx *where = substitute_stack.pop (); - *where = rld[r2].in; - } - - return result; -} - -/* Return 1 if the reloads denoted by R1 and R2 cannot share a register. - Return 0 otherwise. - - This function uses the same algorithm as reload_reg_free_p above. */ - -static int -reloads_conflict (int r1, int r2) -{ - enum reload_type r1_type = rld[r1].when_needed; - enum reload_type r2_type = rld[r2].when_needed; - int r1_opnum = rld[r1].opnum; - int r2_opnum = rld[r2].opnum; - - /* RELOAD_OTHER conflicts with everything. */ - if (r2_type == RELOAD_OTHER) - return 1; - - /* Otherwise, check conflicts differently for each type. */ - - switch (r1_type) - { - case RELOAD_FOR_INPUT: - return (r2_type == RELOAD_FOR_INSN - || r2_type == RELOAD_FOR_OPERAND_ADDRESS - || r2_type == RELOAD_FOR_OPADDR_ADDR - || r2_type == RELOAD_FOR_INPUT - || ((r2_type == RELOAD_FOR_INPUT_ADDRESS - || r2_type == RELOAD_FOR_INPADDR_ADDRESS) - && r2_opnum > r1_opnum)); - - case RELOAD_FOR_INPUT_ADDRESS: - return ((r2_type == RELOAD_FOR_INPUT_ADDRESS && r1_opnum == r2_opnum) - || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum)); - - case RELOAD_FOR_INPADDR_ADDRESS: - return ((r2_type == RELOAD_FOR_INPADDR_ADDRESS && r1_opnum == r2_opnum) - || (r2_type == RELOAD_FOR_INPUT && r2_opnum < r1_opnum)); - - case RELOAD_FOR_OUTPUT_ADDRESS: - return ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS && r2_opnum == r1_opnum) - || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum <= r1_opnum)); - - case RELOAD_FOR_OUTADDR_ADDRESS: - return ((r2_type == RELOAD_FOR_OUTADDR_ADDRESS && r2_opnum == r1_opnum) - || (r2_type == RELOAD_FOR_OUTPUT && r2_opnum <= r1_opnum)); - - case RELOAD_FOR_OPERAND_ADDRESS: - return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_INSN - || (r2_type == RELOAD_FOR_OPERAND_ADDRESS - && (!reloads_unique_chain_p (r1, r2) - || !gen_reload_chain_without_interm_reg_p (r1, r2)))); - - case RELOAD_FOR_OPADDR_ADDR: - return (r2_type == RELOAD_FOR_INPUT - || r2_type == RELOAD_FOR_OPADDR_ADDR); - - case RELOAD_FOR_OUTPUT: - return (r2_type == RELOAD_FOR_INSN || r2_type == RELOAD_FOR_OUTPUT - || ((r2_type == RELOAD_FOR_OUTPUT_ADDRESS - || r2_type == RELOAD_FOR_OUTADDR_ADDRESS) - && r2_opnum >= r1_opnum)); - - case RELOAD_FOR_INSN: - return (r2_type == RELOAD_FOR_INPUT || r2_type == RELOAD_FOR_OUTPUT - || r2_type == RELOAD_FOR_INSN - || r2_type == RELOAD_FOR_OPERAND_ADDRESS); - - case RELOAD_FOR_OTHER_ADDRESS: - return r2_type == RELOAD_FOR_OTHER_ADDRESS; - - case RELOAD_OTHER: - return 1; - - default: - gcc_unreachable (); - } -} - -/* Indexed by reload number, 1 if incoming value - inherited from previous insns. */ -static char reload_inherited[MAX_RELOADS]; - -/* For an inherited reload, this is the insn the reload was inherited from, - if we know it. Otherwise, this is 0. */ -static rtx_insn *reload_inheritance_insn[MAX_RELOADS]; - -/* If nonzero, this is a place to get the value of the reload, - rather than using reload_in. */ -static rtx reload_override_in[MAX_RELOADS]; - -/* For each reload, the hard register number of the register used, - or -1 if we did not need a register for this reload. */ -static int reload_spill_index[MAX_RELOADS]; - -/* Index X is the value of rld[X].reg_rtx, adjusted for the input mode. */ -static rtx reload_reg_rtx_for_input[MAX_RELOADS]; - -/* Index X is the value of rld[X].reg_rtx, adjusted for the output mode. */ -static rtx reload_reg_rtx_for_output[MAX_RELOADS]; - -/* Subroutine of free_for_value_p, used to check a single register. - START_REGNO is the starting regno of the full reload register - (possibly comprising multiple hard registers) that we are considering. */ - -static int -reload_reg_free_for_value_p (int start_regno, int regno, int opnum, - enum reload_type type, rtx value, rtx out, - int reloadnum, int ignore_address_reloads) -{ - int time1; - /* Set if we see an input reload that must not share its reload register - with any new earlyclobber, but might otherwise share the reload - register with an output or input-output reload. */ - int check_earlyclobber = 0; - int i; - int copy = 0; - - if (TEST_HARD_REG_BIT (reload_reg_unavailable, regno)) - return 0; - - if (out == const0_rtx) - { - copy = 1; - out = NULL_RTX; - } - - /* We use some pseudo 'time' value to check if the lifetimes of the - new register use would overlap with the one of a previous reload - that is not read-only or uses a different value. - The 'time' used doesn't have to be linear in any shape or form, just - monotonic. - Some reload types use different 'buckets' for each operand. - So there are MAX_RECOG_OPERANDS different time values for each - such reload type. - We compute TIME1 as the time when the register for the prospective - new reload ceases to be live, and TIME2 for each existing - reload as the time when that the reload register of that reload - becomes live. - Where there is little to be gained by exact lifetime calculations, - we just make conservative assumptions, i.e. a longer lifetime; - this is done in the 'default:' cases. */ - switch (type) - { - case RELOAD_FOR_OTHER_ADDRESS: - /* RELOAD_FOR_OTHER_ADDRESS conflicts with RELOAD_OTHER reloads. */ - time1 = copy ? 0 : 1; - break; - case RELOAD_OTHER: - time1 = copy ? 1 : MAX_RECOG_OPERANDS * 5 + 5; - break; - /* For each input, we may have a sequence of RELOAD_FOR_INPADDR_ADDRESS, - RELOAD_FOR_INPUT_ADDRESS and RELOAD_FOR_INPUT. By adding 0 / 1 / 2 , - respectively, to the time values for these, we get distinct time - values. To get distinct time values for each operand, we have to - multiply opnum by at least three. We round that up to four because - multiply by four is often cheaper. */ - case RELOAD_FOR_INPADDR_ADDRESS: - time1 = opnum * 4 + 2; - break; - case RELOAD_FOR_INPUT_ADDRESS: - time1 = opnum * 4 + 3; - break; - case RELOAD_FOR_INPUT: - /* All RELOAD_FOR_INPUT reloads remain live till the instruction - executes (inclusive). */ - time1 = copy ? opnum * 4 + 4 : MAX_RECOG_OPERANDS * 4 + 3; - break; - case RELOAD_FOR_OPADDR_ADDR: - /* opnum * 4 + 4 - <= (MAX_RECOG_OPERANDS - 1) * 4 + 4 == MAX_RECOG_OPERANDS * 4 */ - time1 = MAX_RECOG_OPERANDS * 4 + 1; - break; - case RELOAD_FOR_OPERAND_ADDRESS: - /* RELOAD_FOR_OPERAND_ADDRESS reloads are live even while the insn - is executed. */ - time1 = copy ? MAX_RECOG_OPERANDS * 4 + 2 : MAX_RECOG_OPERANDS * 4 + 3; - break; - case RELOAD_FOR_OUTADDR_ADDRESS: - time1 = MAX_RECOG_OPERANDS * 4 + 4 + opnum; - break; - case RELOAD_FOR_OUTPUT_ADDRESS: - time1 = MAX_RECOG_OPERANDS * 4 + 5 + opnum; - break; - default: - time1 = MAX_RECOG_OPERANDS * 5 + 5; - } - - for (i = 0; i < n_reloads; i++) - { - rtx reg = rld[i].reg_rtx; - if (reg && REG_P (reg) - && (unsigned) regno - true_regnum (reg) < REG_NREGS (reg) - && i != reloadnum) - { - rtx other_input = rld[i].in; - - /* If the other reload loads the same input value, that - will not cause a conflict only if it's loading it into - the same register. */ - if (true_regnum (reg) != start_regno) - other_input = NULL_RTX; - if (! other_input || ! rtx_equal_p (other_input, value) - || rld[i].out || out) - { - int time2; - switch (rld[i].when_needed) - { - case RELOAD_FOR_OTHER_ADDRESS: - time2 = 0; - break; - case RELOAD_FOR_INPADDR_ADDRESS: - /* find_reloads makes sure that a - RELOAD_FOR_{INP,OP,OUT}ADDR_ADDRESS reload is only used - by at most one - the first - - RELOAD_FOR_{INPUT,OPERAND,OUTPUT}_ADDRESS . If the - address reload is inherited, the address address reload - goes away, so we can ignore this conflict. */ - if (type == RELOAD_FOR_INPUT_ADDRESS && reloadnum == i + 1 - && ignore_address_reloads - /* Unless the RELOAD_FOR_INPUT is an auto_inc expression. - Then the address address is still needed to store - back the new address. */ - && ! rld[reloadnum].out) - continue; - /* Likewise, if a RELOAD_FOR_INPUT can inherit a value, its - RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS - reloads go away. */ - if (type == RELOAD_FOR_INPUT && opnum == rld[i].opnum - && ignore_address_reloads - /* Unless we are reloading an auto_inc expression. */ - && ! rld[reloadnum].out) - continue; - time2 = rld[i].opnum * 4 + 2; - break; - case RELOAD_FOR_INPUT_ADDRESS: - if (type == RELOAD_FOR_INPUT && opnum == rld[i].opnum - && ignore_address_reloads - && ! rld[reloadnum].out) - continue; - time2 = rld[i].opnum * 4 + 3; - break; - case RELOAD_FOR_INPUT: - time2 = rld[i].opnum * 4 + 4; - check_earlyclobber = 1; - break; - /* rld[i].opnum * 4 + 4 <= (MAX_RECOG_OPERAND - 1) * 4 + 4 - == MAX_RECOG_OPERAND * 4 */ - case RELOAD_FOR_OPADDR_ADDR: - if (type == RELOAD_FOR_OPERAND_ADDRESS && reloadnum == i + 1 - && ignore_address_reloads - && ! rld[reloadnum].out) - continue; - time2 = MAX_RECOG_OPERANDS * 4 + 1; - break; - case RELOAD_FOR_OPERAND_ADDRESS: - time2 = MAX_RECOG_OPERANDS * 4 + 2; - check_earlyclobber = 1; - break; - case RELOAD_FOR_INSN: - time2 = MAX_RECOG_OPERANDS * 4 + 3; - break; - case RELOAD_FOR_OUTPUT: - /* All RELOAD_FOR_OUTPUT reloads become live just after the - instruction is executed. */ - time2 = MAX_RECOG_OPERANDS * 4 + 4; - break; - /* The first RELOAD_FOR_OUTADDR_ADDRESS reload conflicts with - the RELOAD_FOR_OUTPUT reloads, so assign it the same time - value. */ - case RELOAD_FOR_OUTADDR_ADDRESS: - if (type == RELOAD_FOR_OUTPUT_ADDRESS && reloadnum == i + 1 - && ignore_address_reloads - && ! rld[reloadnum].out) - continue; - time2 = MAX_RECOG_OPERANDS * 4 + 4 + rld[i].opnum; - break; - case RELOAD_FOR_OUTPUT_ADDRESS: - time2 = MAX_RECOG_OPERANDS * 4 + 5 + rld[i].opnum; - break; - case RELOAD_OTHER: - /* If there is no conflict in the input part, handle this - like an output reload. */ - if (! rld[i].in || rtx_equal_p (other_input, value)) - { - time2 = MAX_RECOG_OPERANDS * 4 + 4; - /* Earlyclobbered outputs must conflict with inputs. */ - if (earlyclobber_operand_p (rld[i].out)) - time2 = MAX_RECOG_OPERANDS * 4 + 3; - - break; - } - time2 = 1; - /* RELOAD_OTHER might be live beyond instruction execution, - but this is not obvious when we set time2 = 1. So check - here if there might be a problem with the new reload - clobbering the register used by the RELOAD_OTHER. */ - if (out) - return 0; - break; - default: - return 0; - } - if ((time1 >= time2 - && (! rld[i].in || rld[i].out - || ! rtx_equal_p (other_input, value))) - || (out && rld[reloadnum].out_reg - && time2 >= MAX_RECOG_OPERANDS * 4 + 3)) - return 0; - } - } - } - - /* Earlyclobbered outputs must conflict with inputs. */ - if (check_earlyclobber && out && earlyclobber_operand_p (out)) - return 0; - - return 1; -} - -/* Return 1 if the value in reload reg REGNO, as used by a reload - needed for the part of the insn specified by OPNUM and TYPE, - may be used to load VALUE into it. - - MODE is the mode in which the register is used, this is needed to - determine how many hard regs to test. - - Other read-only reloads with the same value do not conflict - unless OUT is nonzero and these other reloads have to live while - output reloads live. - If OUT is CONST0_RTX, this is a special case: it means that the - test should not be for using register REGNO as reload register, but - for copying from register REGNO into the reload register. - - RELOADNUM is the number of the reload we want to load this value for; - a reload does not conflict with itself. - - When IGNORE_ADDRESS_RELOADS is set, we cannot have conflicts with - reloads that load an address for the very reload we are considering. - - The caller has to make sure that there is no conflict with the return - register. */ - -static int -free_for_value_p (int regno, machine_mode mode, int opnum, - enum reload_type type, rtx value, rtx out, int reloadnum, - int ignore_address_reloads) -{ - int nregs = hard_regno_nregs (regno, mode); - while (nregs-- > 0) - if (! reload_reg_free_for_value_p (regno, regno + nregs, opnum, type, - value, out, reloadnum, - ignore_address_reloads)) - return 0; - return 1; -} - -/* Return nonzero if the rtx X is invariant over the current function. */ -/* ??? Actually, the places where we use this expect exactly what is - tested here, and not everything that is function invariant. In - particular, the frame pointer and arg pointer are special cased; - pic_offset_table_rtx is not, and we must not spill these things to - memory. */ - -int -function_invariant_p (const_rtx x) -{ - if (CONSTANT_P (x)) - return 1; - if (x == frame_pointer_rtx || x == arg_pointer_rtx) - return 1; - if (GET_CODE (x) == PLUS - && (XEXP (x, 0) == frame_pointer_rtx || XEXP (x, 0) == arg_pointer_rtx) - && GET_CODE (XEXP (x, 1)) == CONST_INT) - return 1; - return 0; -} - -/* Determine whether the reload reg X overlaps any rtx'es used for - overriding inheritance. Return nonzero if so. */ - -static int -conflicts_with_override (rtx x) -{ - int i; - for (i = 0; i < n_reloads; i++) - if (reload_override_in[i] - && reg_overlap_mentioned_p (x, reload_override_in[i])) - return 1; - return 0; -} - -/* Give an error message saying we failed to find a reload for INSN, - and clear out reload R. */ -static void -failed_reload (rtx_insn *insn, int r) -{ - if (asm_noperands (PATTERN (insn)) < 0) - /* It's the compiler's fault. */ - fatal_insn ("could not find a spill register", insn); - - /* It's the user's fault; the operand's mode and constraint - don't match. Disable this reload so we don't crash in final. */ - error_for_asm (insn, - "%<asm%> operand constraint incompatible with operand size"); - rld[r].in = 0; - rld[r].out = 0; - rld[r].reg_rtx = 0; - rld[r].optional = 1; - rld[r].secondary_p = 1; -} - -/* I is the index in SPILL_REG_RTX of the reload register we are to allocate - for reload R. If it's valid, get an rtx for it. Return nonzero if - successful. */ -static int -set_reload_reg (int i, int r) -{ - int regno; - rtx reg = spill_reg_rtx[i]; - - if (reg == 0 || GET_MODE (reg) != rld[r].mode) - spill_reg_rtx[i] = reg - = gen_rtx_REG (rld[r].mode, spill_regs[i]); - - regno = true_regnum (reg); - - /* Detect when the reload reg can't hold the reload mode. - This used to be one `if', but Sequent compiler can't handle that. */ - if (targetm.hard_regno_mode_ok (regno, rld[r].mode)) - { - machine_mode test_mode = VOIDmode; - if (rld[r].in) - test_mode = GET_MODE (rld[r].in); - /* If rld[r].in has VOIDmode, it means we will load it - in whatever mode the reload reg has: to wit, rld[r].mode. - We have already tested that for validity. */ - /* Aside from that, we need to test that the expressions - to reload from or into have modes which are valid for this - reload register. Otherwise the reload insns would be invalid. */ - if (! (rld[r].in != 0 && test_mode != VOIDmode - && !targetm.hard_regno_mode_ok (regno, test_mode))) - if (! (rld[r].out != 0 - && !targetm.hard_regno_mode_ok (regno, GET_MODE (rld[r].out)))) - { - /* The reg is OK. */ - last_spill_reg = i; - - /* Mark as in use for this insn the reload regs we use - for this. */ - mark_reload_reg_in_use (spill_regs[i], rld[r].opnum, - rld[r].when_needed, rld[r].mode); - - rld[r].reg_rtx = reg; - reload_spill_index[r] = spill_regs[i]; - return 1; - } - } - return 0; -} - -/* Find a spill register to use as a reload register for reload R. - LAST_RELOAD is nonzero if this is the last reload for the insn being - processed. - - Set rld[R].reg_rtx to the register allocated. - - We return 1 if successful, or 0 if we couldn't find a spill reg and - we didn't change anything. */ - -static int -allocate_reload_reg (class insn_chain *chain ATTRIBUTE_UNUSED, int r, - int last_reload) -{ - int i, pass, count; - - /* If we put this reload ahead, thinking it is a group, - then insist on finding a group. Otherwise we can grab a - reg that some other reload needs. - (That can happen when we have a 68000 DATA_OR_FP_REG - which is a group of data regs or one fp reg.) - We need not be so restrictive if there are no more reloads - for this insn. - - ??? Really it would be nicer to have smarter handling - for that kind of reg class, where a problem like this is normal. - Perhaps those classes should be avoided for reloading - by use of more alternatives. */ - - int force_group = rld[r].nregs > 1 && ! last_reload; - - /* If we want a single register and haven't yet found one, - take any reg in the right class and not in use. - If we want a consecutive group, here is where we look for it. - - We use three passes so we can first look for reload regs to - reuse, which are already in use for other reloads in this insn, - and only then use additional registers which are not "bad", then - finally any register. - - I think that maximizing reuse is needed to make sure we don't - run out of reload regs. Suppose we have three reloads, and - reloads A and B can share regs. These need two regs. - Suppose A and B are given different regs. - That leaves none for C. */ - for (pass = 0; pass < 3; pass++) - { - /* I is the index in spill_regs. - We advance it round-robin between insns to use all spill regs - equally, so that inherited reloads have a chance - of leapfrogging each other. */ - - i = last_spill_reg; - - for (count = 0; count < n_spills; count++) - { - int rclass = (int) rld[r].rclass; - int regnum; - - i++; - if (i >= n_spills) - i -= n_spills; - regnum = spill_regs[i]; - - if ((reload_reg_free_p (regnum, rld[r].opnum, - rld[r].when_needed) - || (rld[r].in - /* We check reload_reg_used to make sure we - don't clobber the return register. */ - && ! TEST_HARD_REG_BIT (reload_reg_used, regnum) - && free_for_value_p (regnum, rld[r].mode, rld[r].opnum, - rld[r].when_needed, rld[r].in, - rld[r].out, r, 1))) - && TEST_HARD_REG_BIT (reg_class_contents[rclass], regnum) - && targetm.hard_regno_mode_ok (regnum, rld[r].mode) - /* Look first for regs to share, then for unshared. But - don't share regs used for inherited reloads; they are - the ones we want to preserve. */ - && (pass - || (TEST_HARD_REG_BIT (reload_reg_used_at_all, - regnum) - && ! TEST_HARD_REG_BIT (reload_reg_used_for_inherit, - regnum)))) - { - int nr = hard_regno_nregs (regnum, rld[r].mode); - - /* During the second pass we want to avoid reload registers - which are "bad" for this reload. */ - if (pass == 1 - && ira_bad_reload_regno (regnum, rld[r].in, rld[r].out)) - continue; - - /* Avoid the problem where spilling a GENERAL_OR_FP_REG - (on 68000) got us two FP regs. If NR is 1, - we would reject both of them. */ - if (force_group) - nr = rld[r].nregs; - /* If we need only one reg, we have already won. */ - if (nr == 1) - { - /* But reject a single reg if we demand a group. */ - if (force_group) - continue; - break; - } - /* Otherwise check that as many consecutive regs as we need - are available here. */ - while (nr > 1) - { - int regno = regnum + nr - 1; - if (!(TEST_HARD_REG_BIT (reg_class_contents[rclass], regno) - && spill_reg_order[regno] >= 0 - && reload_reg_free_p (regno, rld[r].opnum, - rld[r].when_needed))) - break; - nr--; - } - if (nr == 1) - break; - } - } - - /* If we found something on the current pass, omit later passes. */ - if (count < n_spills) - break; - } - - /* We should have found a spill register by now. */ - if (count >= n_spills) - return 0; - - /* I is the index in SPILL_REG_RTX of the reload register we are to - allocate. Get an rtx for it and find its register number. */ - - return set_reload_reg (i, r); -} - -/* Initialize all the tables needed to allocate reload registers. - CHAIN is the insn currently being processed; SAVE_RELOAD_REG_RTX - is the array we use to restore the reg_rtx field for every reload. */ - -static void -choose_reload_regs_init (class insn_chain *chain, rtx *save_reload_reg_rtx) -{ - int i; - - for (i = 0; i < n_reloads; i++) - rld[i].reg_rtx = save_reload_reg_rtx[i]; - - memset (reload_inherited, 0, MAX_RELOADS); - memset (reload_inheritance_insn, 0, MAX_RELOADS * sizeof (rtx)); - memset (reload_override_in, 0, MAX_RELOADS * sizeof (rtx)); - - CLEAR_HARD_REG_SET (reload_reg_used); - CLEAR_HARD_REG_SET (reload_reg_used_at_all); - CLEAR_HARD_REG_SET (reload_reg_used_in_op_addr); - CLEAR_HARD_REG_SET (reload_reg_used_in_op_addr_reload); - CLEAR_HARD_REG_SET (reload_reg_used_in_insn); - CLEAR_HARD_REG_SET (reload_reg_used_in_other_addr); - - CLEAR_HARD_REG_SET (reg_used_in_insn); - { - HARD_REG_SET tmp; - REG_SET_TO_HARD_REG_SET (tmp, &chain->live_throughout); - reg_used_in_insn |= tmp; - REG_SET_TO_HARD_REG_SET (tmp, &chain->dead_or_set); - reg_used_in_insn |= tmp; - compute_use_by_pseudos (®_used_in_insn, &chain->live_throughout); - compute_use_by_pseudos (®_used_in_insn, &chain->dead_or_set); - } - - for (i = 0; i < reload_n_operands; i++) - { - CLEAR_HARD_REG_SET (reload_reg_used_in_output[i]); - CLEAR_HARD_REG_SET (reload_reg_used_in_input[i]); - CLEAR_HARD_REG_SET (reload_reg_used_in_input_addr[i]); - CLEAR_HARD_REG_SET (reload_reg_used_in_inpaddr_addr[i]); - CLEAR_HARD_REG_SET (reload_reg_used_in_output_addr[i]); - CLEAR_HARD_REG_SET (reload_reg_used_in_outaddr_addr[i]); - } - - reload_reg_unavailable = ~chain->used_spill_regs; - - CLEAR_HARD_REG_SET (reload_reg_used_for_inherit); - - for (i = 0; i < n_reloads; i++) - /* If we have already decided to use a certain register, - don't use it in another way. */ - if (rld[i].reg_rtx) - mark_reload_reg_in_use (REGNO (rld[i].reg_rtx), rld[i].opnum, - rld[i].when_needed, rld[i].mode); -} - -/* If X is not a subreg, return it unmodified. If it is a subreg, - look up whether we made a replacement for the SUBREG_REG. Return - either the replacement or the SUBREG_REG. */ - -static rtx -replaced_subreg (rtx x) -{ - if (GET_CODE (x) == SUBREG) - return find_replacement (&SUBREG_REG (x)); - return x; -} - -/* Compute the offset to pass to subreg_regno_offset, for a pseudo of - mode OUTERMODE that is available in a hard reg of mode INNERMODE. - SUBREG is non-NULL if the pseudo is a subreg whose reg is a pseudo, - otherwise it is NULL. */ - -static poly_int64 -compute_reload_subreg_offset (machine_mode outermode, - rtx subreg, - machine_mode innermode) -{ - poly_int64 outer_offset; - machine_mode middlemode; - - if (!subreg) - return subreg_lowpart_offset (outermode, innermode); - - outer_offset = SUBREG_BYTE (subreg); - middlemode = GET_MODE (SUBREG_REG (subreg)); - - /* If SUBREG is paradoxical then return the normal lowpart offset - for OUTERMODE and INNERMODE. Our caller has already checked - that OUTERMODE fits in INNERMODE. */ - if (paradoxical_subreg_p (outermode, middlemode)) - return subreg_lowpart_offset (outermode, innermode); - - /* SUBREG is normal, but may not be lowpart; return OUTER_OFFSET - plus the normal lowpart offset for MIDDLEMODE and INNERMODE. */ - return outer_offset + subreg_lowpart_offset (middlemode, innermode); -} - -/* Assign hard reg targets for the pseudo-registers we must reload - into hard regs for this insn. - Also output the instructions to copy them in and out of the hard regs. - - For machines with register classes, we are responsible for - finding a reload reg in the proper class. */ - -static void -choose_reload_regs (class insn_chain *chain) -{ - rtx_insn *insn = chain->insn; - int i, j; - unsigned int max_group_size = 1; - enum reg_class group_class = NO_REGS; - int pass, win, inheritance; - - rtx save_reload_reg_rtx[MAX_RELOADS]; - - /* In order to be certain of getting the registers we need, - we must sort the reloads into order of increasing register class. - Then our grabbing of reload registers will parallel the process - that provided the reload registers. - - Also note whether any of the reloads wants a consecutive group of regs. - If so, record the maximum size of the group desired and what - register class contains all the groups needed by this insn. */ - - for (j = 0; j < n_reloads; j++) - { - reload_order[j] = j; - if (rld[j].reg_rtx != NULL_RTX) - { - gcc_assert (REG_P (rld[j].reg_rtx) - && HARD_REGISTER_P (rld[j].reg_rtx)); - reload_spill_index[j] = REGNO (rld[j].reg_rtx); - } - else - reload_spill_index[j] = -1; - - if (rld[j].nregs > 1) - { - max_group_size = MAX (rld[j].nregs, max_group_size); - group_class - = reg_class_superunion[(int) rld[j].rclass][(int) group_class]; - } - - save_reload_reg_rtx[j] = rld[j].reg_rtx; - } - - if (n_reloads > 1) - qsort (reload_order, n_reloads, sizeof (short), reload_reg_class_lower); - - /* If -O, try first with inheritance, then turning it off. - If not -O, don't do inheritance. - Using inheritance when not optimizing leads to paradoxes - with fp on the 68k: fp numbers (not NaNs) fail to be equal to themselves - because one side of the comparison might be inherited. */ - win = 0; - for (inheritance = optimize > 0; inheritance >= 0; inheritance--) - { - choose_reload_regs_init (chain, save_reload_reg_rtx); - - /* Process the reloads in order of preference just found. - Beyond this point, subregs can be found in reload_reg_rtx. - - This used to look for an existing reloaded home for all of the - reloads, and only then perform any new reloads. But that could lose - if the reloads were done out of reg-class order because a later - reload with a looser constraint might have an old home in a register - needed by an earlier reload with a tighter constraint. - - To solve this, we make two passes over the reloads, in the order - described above. In the first pass we try to inherit a reload - from a previous insn. If there is a later reload that needs a - class that is a proper subset of the class being processed, we must - also allocate a spill register during the first pass. - - Then make a second pass over the reloads to allocate any reloads - that haven't been given registers yet. */ - - for (j = 0; j < n_reloads; j++) - { - int r = reload_order[j]; - rtx search_equiv = NULL_RTX; - - /* Ignore reloads that got marked inoperative. */ - if (rld[r].out == 0 && rld[r].in == 0 - && ! rld[r].secondary_p) - continue; - - /* If find_reloads chose to use reload_in or reload_out as a reload - register, we don't need to chose one. Otherwise, try even if it - found one since we might save an insn if we find the value lying - around. - Try also when reload_in is a pseudo without a hard reg. */ - if (rld[r].in != 0 && rld[r].reg_rtx != 0 - && (rtx_equal_p (rld[r].in, rld[r].reg_rtx) - || (rtx_equal_p (rld[r].out, rld[r].reg_rtx) - && !MEM_P (rld[r].in) - && true_regnum (rld[r].in) < FIRST_PSEUDO_REGISTER))) - continue; - -#if 0 /* No longer needed for correct operation. - It might give better code, or might not; worth an experiment? */ - /* If this is an optional reload, we can't inherit from earlier insns - until we are sure that any non-optional reloads have been allocated. - The following code takes advantage of the fact that optional reloads - are at the end of reload_order. */ - if (rld[r].optional != 0) - for (i = 0; i < j; i++) - if ((rld[reload_order[i]].out != 0 - || rld[reload_order[i]].in != 0 - || rld[reload_order[i]].secondary_p) - && ! rld[reload_order[i]].optional - && rld[reload_order[i]].reg_rtx == 0) - allocate_reload_reg (chain, reload_order[i], 0); -#endif - - /* First see if this pseudo is already available as reloaded - for a previous insn. We cannot try to inherit for reloads - that are smaller than the maximum number of registers needed - for groups unless the register we would allocate cannot be used - for the groups. - - We could check here to see if this is a secondary reload for - an object that is already in a register of the desired class. - This would avoid the need for the secondary reload register. - But this is complex because we can't easily determine what - objects might want to be loaded via this reload. So let a - register be allocated here. In `emit_reload_insns' we suppress - one of the loads in the case described above. */ - - if (inheritance) - { - poly_int64 byte = 0; - int regno = -1; - machine_mode mode = VOIDmode; - rtx subreg = NULL_RTX; - - if (rld[r].in == 0) - ; - else if (REG_P (rld[r].in)) - { - regno = REGNO (rld[r].in); - mode = GET_MODE (rld[r].in); - } - else if (REG_P (rld[r].in_reg)) - { - regno = REGNO (rld[r].in_reg); - mode = GET_MODE (rld[r].in_reg); - } - else if (GET_CODE (rld[r].in_reg) == SUBREG - && REG_P (SUBREG_REG (rld[r].in_reg))) - { - regno = REGNO (SUBREG_REG (rld[r].in_reg)); - if (regno < FIRST_PSEUDO_REGISTER) - regno = subreg_regno (rld[r].in_reg); - else - { - subreg = rld[r].in_reg; - byte = SUBREG_BYTE (subreg); - } - mode = GET_MODE (rld[r].in_reg); - } -#if AUTO_INC_DEC - else if (GET_RTX_CLASS (GET_CODE (rld[r].in_reg)) == RTX_AUTOINC - && REG_P (XEXP (rld[r].in_reg, 0))) - { - regno = REGNO (XEXP (rld[r].in_reg, 0)); - mode = GET_MODE (XEXP (rld[r].in_reg, 0)); - rld[r].out = rld[r].in; - } -#endif -#if 0 - /* This won't work, since REGNO can be a pseudo reg number. - Also, it takes much more hair to keep track of all the things - that can invalidate an inherited reload of part of a pseudoreg. */ - else if (GET_CODE (rld[r].in) == SUBREG - && REG_P (SUBREG_REG (rld[r].in))) - regno = subreg_regno (rld[r].in); -#endif - - if (regno >= 0 - && reg_last_reload_reg[regno] != 0 - && (known_ge - (GET_MODE_SIZE (GET_MODE (reg_last_reload_reg[regno])), - GET_MODE_SIZE (mode) + byte)) - /* Verify that the register it's in can be used in - mode MODE. */ - && (REG_CAN_CHANGE_MODE_P - (REGNO (reg_last_reload_reg[regno]), - GET_MODE (reg_last_reload_reg[regno]), - mode))) - { - enum reg_class rclass = rld[r].rclass, last_class; - rtx last_reg = reg_last_reload_reg[regno]; - - i = REGNO (last_reg); - byte = compute_reload_subreg_offset (mode, - subreg, - GET_MODE (last_reg)); - i += subreg_regno_offset (i, GET_MODE (last_reg), byte, mode); - last_class = REGNO_REG_CLASS (i); - - if (reg_reloaded_contents[i] == regno - && TEST_HARD_REG_BIT (reg_reloaded_valid, i) - && targetm.hard_regno_mode_ok (i, rld[r].mode) - && (TEST_HARD_REG_BIT (reg_class_contents[(int) rclass], i) - /* Even if we can't use this register as a reload - register, we might use it for reload_override_in, - if copying it to the desired class is cheap - enough. */ - || ((register_move_cost (mode, last_class, rclass) - < memory_move_cost (mode, rclass, true)) - && (secondary_reload_class (1, rclass, mode, - last_reg) - == NO_REGS) - && !(targetm.secondary_memory_needed - (mode, last_class, rclass)))) - && (rld[r].nregs == max_group_size - || ! TEST_HARD_REG_BIT (reg_class_contents[(int) group_class], - i)) - && free_for_value_p (i, rld[r].mode, rld[r].opnum, - rld[r].when_needed, rld[r].in, - const0_rtx, r, 1)) - { - /* If a group is needed, verify that all the subsequent - registers still have their values intact. */ - int nr = hard_regno_nregs (i, rld[r].mode); - int k; - - for (k = 1; k < nr; k++) - if (reg_reloaded_contents[i + k] != regno - || ! TEST_HARD_REG_BIT (reg_reloaded_valid, i + k)) - break; - - if (k == nr) - { - int i1; - int bad_for_class; - - last_reg = (GET_MODE (last_reg) == mode - ? last_reg : gen_rtx_REG (mode, i)); - - bad_for_class = 0; - for (k = 0; k < nr; k++) - bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].rclass], - i+k); - - /* We found a register that contains the - value we need. If this register is the - same as an `earlyclobber' operand of the - current insn, just mark it as a place to - reload from since we can't use it as the - reload register itself. */ - - for (i1 = 0; i1 < n_earlyclobbers; i1++) - if (reg_overlap_mentioned_for_reload_p - (reg_last_reload_reg[regno], - reload_earlyclobbers[i1])) - break; - - if (i1 != n_earlyclobbers - || ! (free_for_value_p (i, rld[r].mode, - rld[r].opnum, - rld[r].when_needed, rld[r].in, - rld[r].out, r, 1)) - /* Don't use it if we'd clobber a pseudo reg. */ - || (TEST_HARD_REG_BIT (reg_used_in_insn, i) - && rld[r].out - && ! TEST_HARD_REG_BIT (reg_reloaded_dead, i)) - /* Don't clobber the frame pointer. */ - || (i == HARD_FRAME_POINTER_REGNUM - && frame_pointer_needed - && rld[r].out) - /* Don't really use the inherited spill reg - if we need it wider than we've got it. */ - || paradoxical_subreg_p (rld[r].mode, mode) - || bad_for_class - - /* If find_reloads chose reload_out as reload - register, stay with it - that leaves the - inherited register for subsequent reloads. */ - || (rld[r].out && rld[r].reg_rtx - && rtx_equal_p (rld[r].out, rld[r].reg_rtx))) - { - if (! rld[r].optional) - { - reload_override_in[r] = last_reg; - reload_inheritance_insn[r] - = reg_reloaded_insn[i]; - } - } - else - { - int k; - /* We can use this as a reload reg. */ - /* Mark the register as in use for this part of - the insn. */ - mark_reload_reg_in_use (i, - rld[r].opnum, - rld[r].when_needed, - rld[r].mode); - rld[r].reg_rtx = last_reg; - reload_inherited[r] = 1; - reload_inheritance_insn[r] - = reg_reloaded_insn[i]; - reload_spill_index[r] = i; - for (k = 0; k < nr; k++) - SET_HARD_REG_BIT (reload_reg_used_for_inherit, - i + k); - } - } - } - } - } - - /* Here's another way to see if the value is already lying around. */ - if (inheritance - && rld[r].in != 0 - && ! reload_inherited[r] - && rld[r].out == 0 - && (CONSTANT_P (rld[r].in) - || GET_CODE (rld[r].in) == PLUS - || REG_P (rld[r].in) - || MEM_P (rld[r].in)) - && (rld[r].nregs == max_group_size - || ! reg_classes_intersect_p (rld[r].rclass, group_class))) - search_equiv = rld[r].in; - - if (search_equiv) - { - rtx equiv - = find_equiv_reg (search_equiv, insn, rld[r].rclass, - -1, NULL, 0, rld[r].mode); - int regno = 0; - - if (equiv != 0) - { - if (REG_P (equiv)) - regno = REGNO (equiv); - else - { - /* This must be a SUBREG of a hard register. - Make a new REG since this might be used in an - address and not all machines support SUBREGs - there. */ - gcc_assert (GET_CODE (equiv) == SUBREG); - regno = subreg_regno (equiv); - equiv = gen_rtx_REG (rld[r].mode, regno); - /* If we choose EQUIV as the reload register, but the - loop below decides to cancel the inheritance, we'll - end up reloading EQUIV in rld[r].mode, not the mode - it had originally. That isn't safe when EQUIV isn't - available as a spill register since its value might - still be live at this point. */ - for (i = regno; i < regno + (int) rld[r].nregs; i++) - if (TEST_HARD_REG_BIT (reload_reg_unavailable, i)) - equiv = 0; - } - } - - /* If we found a spill reg, reject it unless it is free - and of the desired class. */ - if (equiv != 0) - { - int regs_used = 0; - int bad_for_class = 0; - int max_regno = regno + rld[r].nregs; - - for (i = regno; i < max_regno; i++) - { - regs_used |= TEST_HARD_REG_BIT (reload_reg_used_at_all, - i); - bad_for_class |= ! TEST_HARD_REG_BIT (reg_class_contents[(int) rld[r].rclass], - i); - } - - if ((regs_used - && ! free_for_value_p (regno, rld[r].mode, - rld[r].opnum, rld[r].when_needed, - rld[r].in, rld[r].out, r, 1)) - || bad_for_class) - equiv = 0; - } - - if (equiv != 0 - && !targetm.hard_regno_mode_ok (regno, rld[r].mode)) - equiv = 0; - - /* We found a register that contains the value we need. - If this register is the same as an `earlyclobber' operand - of the current insn, just mark it as a place to reload from - since we can't use it as the reload register itself. */ - - if (equiv != 0) - for (i = 0; i < n_earlyclobbers; i++) - if (reg_overlap_mentioned_for_reload_p (equiv, - reload_earlyclobbers[i])) - { - if (! rld[r].optional) - reload_override_in[r] = equiv; - equiv = 0; - break; - } - - /* If the equiv register we have found is explicitly clobbered - in the current insn, it depends on the reload type if we - can use it, use it for reload_override_in, or not at all. - In particular, we then can't use EQUIV for a - RELOAD_FOR_OUTPUT_ADDRESS reload. */ - - if (equiv != 0) - { - if (regno_clobbered_p (regno, insn, rld[r].mode, 2)) - switch (rld[r].when_needed) - { - case RELOAD_FOR_OTHER_ADDRESS: - case RELOAD_FOR_INPADDR_ADDRESS: - case RELOAD_FOR_INPUT_ADDRESS: - case RELOAD_FOR_OPADDR_ADDR: - break; - case RELOAD_OTHER: - case RELOAD_FOR_INPUT: - case RELOAD_FOR_OPERAND_ADDRESS: - if (! rld[r].optional) - reload_override_in[r] = equiv; - /* Fall through. */ - default: - equiv = 0; - break; - } - else if (regno_clobbered_p (regno, insn, rld[r].mode, 1)) - switch (rld[r].when_needed) - { - case RELOAD_FOR_OTHER_ADDRESS: - case RELOAD_FOR_INPADDR_ADDRESS: - case RELOAD_FOR_INPUT_ADDRESS: - case RELOAD_FOR_OPADDR_ADDR: - case RELOAD_FOR_OPERAND_ADDRESS: - case RELOAD_FOR_INPUT: - break; - case RELOAD_OTHER: - if (! rld[r].optional) - reload_override_in[r] = equiv; - /* Fall through. */ - default: - equiv = 0; - break; - } - } - - /* If we found an equivalent reg, say no code need be generated - to load it, and use it as our reload reg. */ - if (equiv != 0 - && (regno != HARD_FRAME_POINTER_REGNUM - || !frame_pointer_needed)) - { - int nr = hard_regno_nregs (regno, rld[r].mode); - int k; - rld[r].reg_rtx = equiv; - reload_spill_index[r] = regno; - reload_inherited[r] = 1; - - /* If reg_reloaded_valid is not set for this register, - there might be a stale spill_reg_store lying around. - We must clear it, since otherwise emit_reload_insns - might delete the store. */ - if (! TEST_HARD_REG_BIT (reg_reloaded_valid, regno)) - spill_reg_store[regno] = NULL; - /* If any of the hard registers in EQUIV are spill - registers, mark them as in use for this insn. */ - for (k = 0; k < nr; k++) - { - i = spill_reg_order[regno + k]; - if (i >= 0) - { - mark_reload_reg_in_use (regno, rld[r].opnum, - rld[r].when_needed, - rld[r].mode); - SET_HARD_REG_BIT (reload_reg_used_for_inherit, - regno + k); - } - } - } - } - - /* If we found a register to use already, or if this is an optional - reload, we are done. */ - if (rld[r].reg_rtx != 0 || rld[r].optional != 0) - continue; - -#if 0 - /* No longer needed for correct operation. Might or might - not give better code on the average. Want to experiment? */ - - /* See if there is a later reload that has a class different from our - class that intersects our class or that requires less register - than our reload. If so, we must allocate a register to this - reload now, since that reload might inherit a previous reload - and take the only available register in our class. Don't do this - for optional reloads since they will force all previous reloads - to be allocated. Also don't do this for reloads that have been - turned off. */ - - for (i = j + 1; i < n_reloads; i++) - { - int s = reload_order[i]; - - if ((rld[s].in == 0 && rld[s].out == 0 - && ! rld[s].secondary_p) - || rld[s].optional) - continue; - - if ((rld[s].rclass != rld[r].rclass - && reg_classes_intersect_p (rld[r].rclass, - rld[s].rclass)) - || rld[s].nregs < rld[r].nregs) - break; - } - - if (i == n_reloads) - continue; - - allocate_reload_reg (chain, r, j == n_reloads - 1); -#endif - } - - /* Now allocate reload registers for anything non-optional that - didn't get one yet. */ - for (j = 0; j < n_reloads; j++) - { - int r = reload_order[j]; - - /* Ignore reloads that got marked inoperative. */ - if (rld[r].out == 0 && rld[r].in == 0 && ! rld[r].secondary_p) - continue; - - /* Skip reloads that already have a register allocated or are - optional. */ - if (rld[r].reg_rtx != 0 || rld[r].optional) - continue; - - if (! allocate_reload_reg (chain, r, j == n_reloads - 1)) - break; - } - - /* If that loop got all the way, we have won. */ - if (j == n_reloads) - { - win = 1; - break; - } - - /* Loop around and try without any inheritance. */ - } - - if (! win) - { - /* First undo everything done by the failed attempt - to allocate with inheritance. */ - choose_reload_regs_init (chain, save_reload_reg_rtx); - - /* Some sanity tests to verify that the reloads found in the first - pass are identical to the ones we have now. */ - gcc_assert (chain->n_reloads == n_reloads); - - for (i = 0; i < n_reloads; i++) - { - if (chain->rld[i].regno < 0 || chain->rld[i].reg_rtx != 0) - continue; - gcc_assert (chain->rld[i].when_needed == rld[i].when_needed); - for (j = 0; j < n_spills; j++) - if (spill_regs[j] == chain->rld[i].regno) - if (! set_reload_reg (j, i)) - failed_reload (chain->insn, i); - } - } - - /* If we thought we could inherit a reload, because it seemed that - nothing else wanted the same reload register earlier in the insn, - verify that assumption, now that all reloads have been assigned. - Likewise for reloads where reload_override_in has been set. */ - - /* If doing expensive optimizations, do one preliminary pass that doesn't - cancel any inheritance, but removes reloads that have been needed only - for reloads that we know can be inherited. */ - for (pass = flag_expensive_optimizations; pass >= 0; pass--) - { - for (j = 0; j < n_reloads; j++) - { - int r = reload_order[j]; - rtx check_reg; - rtx tem; - if (reload_inherited[r] && rld[r].reg_rtx) - check_reg = rld[r].reg_rtx; - else if (reload_override_in[r] - && (REG_P (reload_override_in[r]) - || GET_CODE (reload_override_in[r]) == SUBREG)) - check_reg = reload_override_in[r]; - else - continue; - if (! free_for_value_p (true_regnum (check_reg), rld[r].mode, - rld[r].opnum, rld[r].when_needed, rld[r].in, - (reload_inherited[r] - ? rld[r].out : const0_rtx), - r, 1)) - { - if (pass) - continue; - reload_inherited[r] = 0; - reload_override_in[r] = 0; - } - /* If we can inherit a RELOAD_FOR_INPUT, or can use a - reload_override_in, then we do not need its related - RELOAD_FOR_INPUT_ADDRESS / RELOAD_FOR_INPADDR_ADDRESS reloads; - likewise for other reload types. - We handle this by removing a reload when its only replacement - is mentioned in reload_in of the reload we are going to inherit. - A special case are auto_inc expressions; even if the input is - inherited, we still need the address for the output. We can - recognize them because they have RELOAD_OUT set to RELOAD_IN. - If we succeeded removing some reload and we are doing a preliminary - pass just to remove such reloads, make another pass, since the - removal of one reload might allow us to inherit another one. */ - else if (rld[r].in - && rld[r].out != rld[r].in - && remove_address_replacements (rld[r].in)) - { - if (pass) - pass = 2; - } - /* If we needed a memory location for the reload, we also have to - remove its related reloads. */ - else if (rld[r].in - && rld[r].out != rld[r].in - && (tem = replaced_subreg (rld[r].in), REG_P (tem)) - && REGNO (tem) < FIRST_PSEUDO_REGISTER - && (targetm.secondary_memory_needed - (rld[r].inmode, REGNO_REG_CLASS (REGNO (tem)), - rld[r].rclass)) - && remove_address_replacements - (get_secondary_mem (tem, rld[r].inmode, rld[r].opnum, - rld[r].when_needed))) - { - if (pass) - pass = 2; - } - } - } - - /* Now that reload_override_in is known valid, - actually override reload_in. */ - for (j = 0; j < n_reloads; j++) - if (reload_override_in[j]) - rld[j].in = reload_override_in[j]; - - /* If this reload won't be done because it has been canceled or is - optional and not inherited, clear reload_reg_rtx so other - routines (such as subst_reloads) don't get confused. */ - for (j = 0; j < n_reloads; j++) - if (rld[j].reg_rtx != 0 - && ((rld[j].optional && ! reload_inherited[j]) - || (rld[j].in == 0 && rld[j].out == 0 - && ! rld[j].secondary_p))) - { - int regno = true_regnum (rld[j].reg_rtx); - - if (spill_reg_order[regno] >= 0) - clear_reload_reg_in_use (regno, rld[j].opnum, - rld[j].when_needed, rld[j].mode); - rld[j].reg_rtx = 0; - reload_spill_index[j] = -1; - } - - /* Record which pseudos and which spill regs have output reloads. */ - for (j = 0; j < n_reloads; j++) - { - int r = reload_order[j]; - - i = reload_spill_index[r]; - - /* I is nonneg if this reload uses a register. - If rld[r].reg_rtx is 0, this is an optional reload - that we opted to ignore. */ - if (rld[r].out_reg != 0 && REG_P (rld[r].out_reg) - && rld[r].reg_rtx != 0) - { - int nregno = REGNO (rld[r].out_reg); - int nr = 1; - - if (nregno < FIRST_PSEUDO_REGISTER) - nr = hard_regno_nregs (nregno, rld[r].mode); - - while (--nr >= 0) - SET_REGNO_REG_SET (®_has_output_reload, - nregno + nr); - - if (i >= 0) - add_to_hard_reg_set (®_is_output_reload, rld[r].mode, i); - - gcc_assert (rld[r].when_needed == RELOAD_OTHER - || rld[r].when_needed == RELOAD_FOR_OUTPUT - || rld[r].when_needed == RELOAD_FOR_INSN); - } - } -} - -/* Deallocate the reload register for reload R. This is called from - remove_address_replacements. */ - -void -deallocate_reload_reg (int r) -{ - int regno; - - if (! rld[r].reg_rtx) - return; - regno = true_regnum (rld[r].reg_rtx); - rld[r].reg_rtx = 0; - if (spill_reg_order[regno] >= 0) - clear_reload_reg_in_use (regno, rld[r].opnum, rld[r].when_needed, - rld[r].mode); - reload_spill_index[r] = -1; -} - -/* These arrays are filled by emit_reload_insns and its subroutines. */ -static rtx_insn *input_reload_insns[MAX_RECOG_OPERANDS]; -static rtx_insn *other_input_address_reload_insns = 0; -static rtx_insn *other_input_reload_insns = 0; -static rtx_insn *input_address_reload_insns[MAX_RECOG_OPERANDS]; -static rtx_insn *inpaddr_address_reload_insns[MAX_RECOG_OPERANDS]; -static rtx_insn *output_reload_insns[MAX_RECOG_OPERANDS]; -static rtx_insn *output_address_reload_insns[MAX_RECOG_OPERANDS]; -static rtx_insn *outaddr_address_reload_insns[MAX_RECOG_OPERANDS]; -static rtx_insn *operand_reload_insns = 0; -static rtx_insn *other_operand_reload_insns = 0; -static rtx_insn *other_output_reload_insns[MAX_RECOG_OPERANDS]; - -/* Values to be put in spill_reg_store are put here first. Instructions - must only be placed here if the associated reload register reaches - the end of the instruction's reload sequence. */ -static rtx_insn *new_spill_reg_store[FIRST_PSEUDO_REGISTER]; -static HARD_REG_SET reg_reloaded_died; - -/* Check if *RELOAD_REG is suitable as an intermediate or scratch register - of class NEW_CLASS with mode NEW_MODE. Or alternatively, if alt_reload_reg - is nonzero, if that is suitable. On success, change *RELOAD_REG to the - adjusted register, and return true. Otherwise, return false. */ -static bool -reload_adjust_reg_for_temp (rtx *reload_reg, rtx alt_reload_reg, - enum reg_class new_class, - machine_mode new_mode) - -{ - rtx reg; - - for (reg = *reload_reg; reg; reg = alt_reload_reg, alt_reload_reg = 0) - { - unsigned regno = REGNO (reg); - - if (!TEST_HARD_REG_BIT (reg_class_contents[(int) new_class], regno)) - continue; - if (GET_MODE (reg) != new_mode) - { - if (!targetm.hard_regno_mode_ok (regno, new_mode)) - continue; - if (hard_regno_nregs (regno, new_mode) > REG_NREGS (reg)) - continue; - reg = reload_adjust_reg_for_mode (reg, new_mode); - } - *reload_reg = reg; - return true; - } - return false; -} - -/* Check if *RELOAD_REG is suitable as a scratch register for the reload - pattern with insn_code ICODE, or alternatively, if alt_reload_reg is - nonzero, if that is suitable. On success, change *RELOAD_REG to the - adjusted register, and return true. Otherwise, return false. */ -static bool -reload_adjust_reg_for_icode (rtx *reload_reg, rtx alt_reload_reg, - enum insn_code icode) - -{ - enum reg_class new_class = scratch_reload_class (icode); - machine_mode new_mode = insn_data[(int) icode].operand[2].mode; - - return reload_adjust_reg_for_temp (reload_reg, alt_reload_reg, - new_class, new_mode); -} - -/* Generate insns to perform reload RL, which is for the insn in CHAIN and - has the number J. OLD contains the value to be used as input. */ - -static void -emit_input_reload_insns (class insn_chain *chain, struct reload *rl, - rtx old, int j) -{ - rtx_insn *insn = chain->insn; - rtx reloadreg; - rtx oldequiv_reg = 0; - rtx oldequiv = 0; - int special = 0; - machine_mode mode; - rtx_insn **where; - - /* delete_output_reload is only invoked properly if old contains - the original pseudo register. Since this is replaced with a - hard reg when RELOAD_OVERRIDE_IN is set, see if we can - find the pseudo in RELOAD_IN_REG. This is also used to - determine whether a secondary reload is needed. */ - if (reload_override_in[j] - && (REG_P (rl->in_reg) - || (GET_CODE (rl->in_reg) == SUBREG - && REG_P (SUBREG_REG (rl->in_reg))))) - { - oldequiv = old; - old = rl->in_reg; - } - if (oldequiv == 0) - oldequiv = old; - else if (REG_P (oldequiv)) - oldequiv_reg = oldequiv; - else if (GET_CODE (oldequiv) == SUBREG) - oldequiv_reg = SUBREG_REG (oldequiv); - - reloadreg = reload_reg_rtx_for_input[j]; - mode = GET_MODE (reloadreg); - - /* If we are reloading from a register that was recently stored in - with an output-reload, see if we can prove there was - actually no need to store the old value in it. */ - - if (optimize && REG_P (oldequiv) - && REGNO (oldequiv) < FIRST_PSEUDO_REGISTER - && spill_reg_store[REGNO (oldequiv)] - && REG_P (old) - && (dead_or_set_p (insn, spill_reg_stored_to[REGNO (oldequiv)]) - || rtx_equal_p (spill_reg_stored_to[REGNO (oldequiv)], - rl->out_reg))) - delete_output_reload (insn, j, REGNO (oldequiv), reloadreg); - - /* Encapsulate OLDEQUIV into the reload mode, then load RELOADREG from - OLDEQUIV. */ - - while (GET_CODE (oldequiv) == SUBREG && GET_MODE (oldequiv) != mode) - oldequiv = SUBREG_REG (oldequiv); - if (GET_MODE (oldequiv) != VOIDmode - && mode != GET_MODE (oldequiv)) - oldequiv = gen_lowpart_SUBREG (mode, oldequiv); - - /* Switch to the right place to emit the reload insns. */ - switch (rl->when_needed) - { - case RELOAD_OTHER: - where = &other_input_reload_insns; - break; - case RELOAD_FOR_INPUT: - where = &input_reload_insns[rl->opnum]; - break; - case RELOAD_FOR_INPUT_ADDRESS: - where = &input_address_reload_insns[rl->opnum]; - break; - case RELOAD_FOR_INPADDR_ADDRESS: - where = &inpaddr_address_reload_insns[rl->opnum]; - break; - case RELOAD_FOR_OUTPUT_ADDRESS: - where = &output_address_reload_insns[rl->opnum]; - break; - case RELOAD_FOR_OUTADDR_ADDRESS: - where = &outaddr_address_reload_insns[rl->opnum]; - break; - case RELOAD_FOR_OPERAND_ADDRESS: - where = &operand_reload_insns; - break; - case RELOAD_FOR_OPADDR_ADDR: - where = &other_operand_reload_insns; - break; - case RELOAD_FOR_OTHER_ADDRESS: - where = &other_input_address_reload_insns; - break; - default: - gcc_unreachable (); - } - - push_to_sequence (*where); - - /* Auto-increment addresses must be reloaded in a special way. */ - if (rl->out && ! rl->out_reg) - { - /* We are not going to bother supporting the case where a - incremented register can't be copied directly from - OLDEQUIV since this seems highly unlikely. */ - gcc_assert (rl->secondary_in_reload < 0); - - if (reload_inherited[j]) - oldequiv = reloadreg; - - old = XEXP (rl->in_reg, 0); - - /* Prevent normal processing of this reload. */ - special = 1; - /* Output a special code sequence for this case. */ - inc_for_reload (reloadreg, oldequiv, rl->out, rl->inc); - } - - /* If we are reloading a pseudo-register that was set by the previous - insn, see if we can get rid of that pseudo-register entirely - by redirecting the previous insn into our reload register. */ - - else if (optimize && REG_P (old) - && REGNO (old) >= FIRST_PSEUDO_REGISTER - && dead_or_set_p (insn, old) - /* This is unsafe if some other reload - uses the same reg first. */ - && ! conflicts_with_override (reloadreg) - && free_for_value_p (REGNO (reloadreg), rl->mode, rl->opnum, - rl->when_needed, old, rl->out, j, 0)) - { - rtx_insn *temp = PREV_INSN (insn); - while (temp && (NOTE_P (temp) || DEBUG_INSN_P (temp))) - temp = PREV_INSN (temp); - if (temp - && NONJUMP_INSN_P (temp) - && GET_CODE (PATTERN (temp)) == SET - && SET_DEST (PATTERN (temp)) == old - /* Make sure we can access insn_operand_constraint. */ - && asm_noperands (PATTERN (temp)) < 0 - /* This is unsafe if operand occurs more than once in current - insn. Perhaps some occurrences aren't reloaded. */ - && count_occurrences (PATTERN (insn), old, 0) == 1) - { - rtx old = SET_DEST (PATTERN (temp)); - /* Store into the reload register instead of the pseudo. */ - SET_DEST (PATTERN (temp)) = reloadreg; - - /* Verify that resulting insn is valid. - - Note that we have replaced the destination of TEMP with - RELOADREG. If TEMP references RELOADREG within an - autoincrement addressing mode, then the resulting insn - is ill-formed and we must reject this optimization. */ - extract_insn (temp); - if (constrain_operands (1, get_enabled_alternatives (temp)) - && (!AUTO_INC_DEC || ! find_reg_note (temp, REG_INC, reloadreg))) - { - /* If the previous insn is an output reload, the source is - a reload register, and its spill_reg_store entry will - contain the previous destination. This is now - invalid. */ - if (REG_P (SET_SRC (PATTERN (temp))) - && REGNO (SET_SRC (PATTERN (temp))) < FIRST_PSEUDO_REGISTER) - { - spill_reg_store[REGNO (SET_SRC (PATTERN (temp)))] = 0; - spill_reg_stored_to[REGNO (SET_SRC (PATTERN (temp)))] = 0; - } - - /* If these are the only uses of the pseudo reg, - pretend for GDB it lives in the reload reg we used. */ - if (REG_N_DEATHS (REGNO (old)) == 1 - && REG_N_SETS (REGNO (old)) == 1) - { - reg_renumber[REGNO (old)] = REGNO (reloadreg); - if (ira_conflicts_p) - /* Inform IRA about the change. */ - ira_mark_allocation_change (REGNO (old)); - alter_reg (REGNO (old), -1, false); - } - special = 1; - - /* Adjust any debug insns between temp and insn. */ - while ((temp = NEXT_INSN (temp)) != insn) - if (DEBUG_BIND_INSN_P (temp)) - INSN_VAR_LOCATION_LOC (temp) - = simplify_replace_rtx (INSN_VAR_LOCATION_LOC (temp), - old, reloadreg); - else - gcc_assert (DEBUG_INSN_P (temp) || NOTE_P (temp)); - } - else - { - SET_DEST (PATTERN (temp)) = old; - } - } - } - - /* We can't do that, so output an insn to load RELOADREG. */ - - /* If we have a secondary reload, pick up the secondary register - and icode, if any. If OLDEQUIV and OLD are different or - if this is an in-out reload, recompute whether or not we - still need a secondary register and what the icode should - be. If we still need a secondary register and the class or - icode is different, go back to reloading from OLD if using - OLDEQUIV means that we got the wrong type of register. We - cannot have different class or icode due to an in-out reload - because we don't make such reloads when both the input and - output need secondary reload registers. */ - - if (! special && rl->secondary_in_reload >= 0) - { - rtx second_reload_reg = 0; - rtx third_reload_reg = 0; - int secondary_reload = rl->secondary_in_reload; - rtx real_oldequiv = oldequiv; - rtx real_old = old; - rtx tmp; - enum insn_code icode; - enum insn_code tertiary_icode = CODE_FOR_nothing; - - /* If OLDEQUIV is a pseudo with a MEM, get the real MEM - and similarly for OLD. - See comments in get_secondary_reload in reload.c. */ - /* If it is a pseudo that cannot be replaced with its - equivalent MEM, we must fall back to reload_in, which - will have all the necessary substitutions registered. - Likewise for a pseudo that can't be replaced with its - equivalent constant. - - Take extra care for subregs of such pseudos. Note that - we cannot use reg_equiv_mem in this case because it is - not in the right mode. */ - - tmp = oldequiv; - if (GET_CODE (tmp) == SUBREG) - tmp = SUBREG_REG (tmp); - if (REG_P (tmp) - && REGNO (tmp) >= FIRST_PSEUDO_REGISTER - && (reg_equiv_memory_loc (REGNO (tmp)) != 0 - || reg_equiv_constant (REGNO (tmp)) != 0)) - { - if (! reg_equiv_mem (REGNO (tmp)) - || num_not_at_initial_offset - || GET_CODE (oldequiv) == SUBREG) - real_oldequiv = rl->in; - else - real_oldequiv = reg_equiv_mem (REGNO (tmp)); - } - - tmp = old; - if (GET_CODE (tmp) == SUBREG) - tmp = SUBREG_REG (tmp); - if (REG_P (tmp) - && REGNO (tmp) >= FIRST_PSEUDO_REGISTER - && (reg_equiv_memory_loc (REGNO (tmp)) != 0 - || reg_equiv_constant (REGNO (tmp)) != 0)) - { - if (! reg_equiv_mem (REGNO (tmp)) - || num_not_at_initial_offset - || GET_CODE (old) == SUBREG) - real_old = rl->in; - else - real_old = reg_equiv_mem (REGNO (tmp)); - } - - second_reload_reg = rld[secondary_reload].reg_rtx; - if (rld[secondary_reload].secondary_in_reload >= 0) - { - int tertiary_reload = rld[secondary_reload].secondary_in_reload; - - third_reload_reg = rld[tertiary_reload].reg_rtx; - tertiary_icode = rld[secondary_reload].secondary_in_icode; - /* We'd have to add more code for quartary reloads. */ - gcc_assert (rld[tertiary_reload].secondary_in_reload < 0); - } - icode = rl->secondary_in_icode; - - if ((old != oldequiv && ! rtx_equal_p (old, oldequiv)) - || (rl->in != 0 && rl->out != 0)) - { - secondary_reload_info sri, sri2; - enum reg_class new_class, new_t_class; - - sri.icode = CODE_FOR_nothing; - sri.prev_sri = NULL; - new_class - = (enum reg_class) targetm.secondary_reload (1, real_oldequiv, - rl->rclass, mode, - &sri); - - if (new_class == NO_REGS && sri.icode == CODE_FOR_nothing) - second_reload_reg = 0; - else if (new_class == NO_REGS) - { - if (reload_adjust_reg_for_icode (&second_reload_reg, - third_reload_reg, - (enum insn_code) sri.icode)) - { - icode = (enum insn_code) sri.icode; - third_reload_reg = 0; - } - else - { - oldequiv = old; - real_oldequiv = real_old; - } - } - else if (sri.icode != CODE_FOR_nothing) - /* We currently lack a way to express this in reloads. */ - gcc_unreachable (); - else - { - sri2.icode = CODE_FOR_nothing; - sri2.prev_sri = &sri; - new_t_class - = (enum reg_class) targetm.secondary_reload (1, real_oldequiv, - new_class, mode, - &sri); - if (new_t_class == NO_REGS && sri2.icode == CODE_FOR_nothing) - { - if (reload_adjust_reg_for_temp (&second_reload_reg, - third_reload_reg, - new_class, mode)) - { - third_reload_reg = 0; - tertiary_icode = (enum insn_code) sri2.icode; - } - else - { - oldequiv = old; - real_oldequiv = real_old; - } - } - else if (new_t_class == NO_REGS && sri2.icode != CODE_FOR_nothing) - { - rtx intermediate = second_reload_reg; - - if (reload_adjust_reg_for_temp (&intermediate, NULL, - new_class, mode) - && reload_adjust_reg_for_icode (&third_reload_reg, NULL, - ((enum insn_code) - sri2.icode))) - { - second_reload_reg = intermediate; - tertiary_icode = (enum insn_code) sri2.icode; - } - else - { - oldequiv = old; - real_oldequiv = real_old; - } - } - else if (new_t_class != NO_REGS && sri2.icode == CODE_FOR_nothing) - { - rtx intermediate = second_reload_reg; - - if (reload_adjust_reg_for_temp (&intermediate, NULL, - new_class, mode) - && reload_adjust_reg_for_temp (&third_reload_reg, NULL, - new_t_class, mode)) - { - second_reload_reg = intermediate; - tertiary_icode = (enum insn_code) sri2.icode; - } - else - { - oldequiv = old; - real_oldequiv = real_old; - } - } - else - { - /* This could be handled more intelligently too. */ - oldequiv = old; - real_oldequiv = real_old; - } - } - } - - /* If we still need a secondary reload register, check - to see if it is being used as a scratch or intermediate - register and generate code appropriately. If we need - a scratch register, use REAL_OLDEQUIV since the form of - the insn may depend on the actual address if it is - a MEM. */ - - if (second_reload_reg) - { - if (icode != CODE_FOR_nothing) - { - /* We'd have to add extra code to handle this case. */ - gcc_assert (!third_reload_reg); - - emit_insn (GEN_FCN (icode) (reloadreg, real_oldequiv, - second_reload_reg)); - special = 1; - } - else - { - /* See if we need a scratch register to load the - intermediate register (a tertiary reload). */ - if (tertiary_icode != CODE_FOR_nothing) - { - emit_insn ((GEN_FCN (tertiary_icode) - (second_reload_reg, real_oldequiv, - third_reload_reg))); - } - else if (third_reload_reg) - { - gen_reload (third_reload_reg, real_oldequiv, - rl->opnum, - rl->when_needed); - gen_reload (second_reload_reg, third_reload_reg, - rl->opnum, - rl->when_needed); - } - else - gen_reload (second_reload_reg, real_oldequiv, - rl->opnum, - rl->when_needed); - - oldequiv = second_reload_reg; - } - } - } - - if (! special && ! rtx_equal_p (reloadreg, oldequiv)) - { - rtx real_oldequiv = oldequiv; - - if ((REG_P (oldequiv) - && REGNO (oldequiv) >= FIRST_PSEUDO_REGISTER - && (reg_equiv_memory_loc (REGNO (oldequiv)) != 0 - || reg_equiv_constant (REGNO (oldequiv)) != 0)) - || (GET_CODE (oldequiv) == SUBREG - && REG_P (SUBREG_REG (oldequiv)) - && (REGNO (SUBREG_REG (oldequiv)) - >= FIRST_PSEUDO_REGISTER) - && ((reg_equiv_memory_loc (REGNO (SUBREG_REG (oldequiv))) != 0) - || (reg_equiv_constant (REGNO (SUBREG_REG (oldequiv))) != 0))) - || (CONSTANT_P (oldequiv) - && (targetm.preferred_reload_class (oldequiv, - REGNO_REG_CLASS (REGNO (reloadreg))) - == NO_REGS))) - real_oldequiv = rl->in; - gen_reload (reloadreg, real_oldequiv, rl->opnum, - rl->when_needed); - } - - if (cfun->can_throw_non_call_exceptions) - copy_reg_eh_region_note_forward (insn, get_insns (), NULL); - - /* End this sequence. */ - *where = get_insns (); - end_sequence (); - - /* Update reload_override_in so that delete_address_reloads_1 - can see the actual register usage. */ - if (oldequiv_reg) - reload_override_in[j] = oldequiv; -} - -/* Generate insns to for the output reload RL, which is for the insn described - by CHAIN and has the number J. */ -static void -emit_output_reload_insns (class insn_chain *chain, struct reload *rl, - int j) -{ - rtx reloadreg; - rtx_insn *insn = chain->insn; - int special = 0; - rtx old = rl->out; - machine_mode mode; - rtx_insn *p; - rtx rl_reg_rtx; - - if (rl->when_needed == RELOAD_OTHER) - start_sequence (); - else - push_to_sequence (output_reload_insns[rl->opnum]); - - rl_reg_rtx = reload_reg_rtx_for_output[j]; - mode = GET_MODE (rl_reg_rtx); - - reloadreg = rl_reg_rtx; - - /* If we need two reload regs, set RELOADREG to the intermediate - one, since it will be stored into OLD. We might need a secondary - register only for an input reload, so check again here. */ - - if (rl->secondary_out_reload >= 0) - { - rtx real_old = old; - int secondary_reload = rl->secondary_out_reload; - int tertiary_reload = rld[secondary_reload].secondary_out_reload; - - if (REG_P (old) && REGNO (old) >= FIRST_PSEUDO_REGISTER - && reg_equiv_mem (REGNO (old)) != 0) - real_old = reg_equiv_mem (REGNO (old)); - - if (secondary_reload_class (0, rl->rclass, mode, real_old) != NO_REGS) - { - rtx second_reloadreg = reloadreg; - reloadreg = rld[secondary_reload].reg_rtx; - - /* See if RELOADREG is to be used as a scratch register - or as an intermediate register. */ - if (rl->secondary_out_icode != CODE_FOR_nothing) - { - /* We'd have to add extra code to handle this case. */ - gcc_assert (tertiary_reload < 0); - - emit_insn ((GEN_FCN (rl->secondary_out_icode) - (real_old, second_reloadreg, reloadreg))); - special = 1; - } - else - { - /* See if we need both a scratch and intermediate reload - register. */ - - enum insn_code tertiary_icode - = rld[secondary_reload].secondary_out_icode; - - /* We'd have to add more code for quartary reloads. */ - gcc_assert (tertiary_reload < 0 - || rld[tertiary_reload].secondary_out_reload < 0); - - if (GET_MODE (reloadreg) != mode) - reloadreg = reload_adjust_reg_for_mode (reloadreg, mode); - - if (tertiary_icode != CODE_FOR_nothing) - { - rtx third_reloadreg = rld[tertiary_reload].reg_rtx; - - /* Copy primary reload reg to secondary reload reg. - (Note that these have been swapped above, then - secondary reload reg to OLD using our insn.) */ - - /* If REAL_OLD is a paradoxical SUBREG, remove it - and try to put the opposite SUBREG on - RELOADREG. */ - strip_paradoxical_subreg (&real_old, &reloadreg); - - gen_reload (reloadreg, second_reloadreg, - rl->opnum, rl->when_needed); - emit_insn ((GEN_FCN (tertiary_icode) - (real_old, reloadreg, third_reloadreg))); - special = 1; - } - - else - { - /* Copy between the reload regs here and then to - OUT later. */ - - gen_reload (reloadreg, second_reloadreg, - rl->opnum, rl->when_needed); - if (tertiary_reload >= 0) - { - rtx third_reloadreg = rld[tertiary_reload].reg_rtx; - - gen_reload (third_reloadreg, reloadreg, - rl->opnum, rl->when_needed); - reloadreg = third_reloadreg; - } - } - } - } - } - - /* Output the last reload insn. */ - if (! special) - { - rtx set; - - /* Don't output the last reload if OLD is not the dest of - INSN and is in the src and is clobbered by INSN. */ - if (! flag_expensive_optimizations - || !REG_P (old) - || !(set = single_set (insn)) - || rtx_equal_p (old, SET_DEST (set)) - || !reg_mentioned_p (old, SET_SRC (set)) - || !((REGNO (old) < FIRST_PSEUDO_REGISTER) - && regno_clobbered_p (REGNO (old), insn, rl->mode, 0))) - gen_reload (old, reloadreg, rl->opnum, - rl->when_needed); - } - - /* Look at all insns we emitted, just to be safe. */ - for (p = get_insns (); p; p = NEXT_INSN (p)) - if (INSN_P (p)) - { - rtx pat = PATTERN (p); - - /* If this output reload doesn't come from a spill reg, - clear any memory of reloaded copies of the pseudo reg. - If this output reload comes from a spill reg, - reg_has_output_reload will make this do nothing. */ - note_stores (p, forget_old_reloads_1, NULL); - - if (reg_mentioned_p (rl_reg_rtx, pat)) - { - rtx set = single_set (insn); - if (reload_spill_index[j] < 0 - && set - && SET_SRC (set) == rl_reg_rtx) - { - int src = REGNO (SET_SRC (set)); - - reload_spill_index[j] = src; - SET_HARD_REG_BIT (reg_is_output_reload, src); - if (find_regno_note (insn, REG_DEAD, src)) - SET_HARD_REG_BIT (reg_reloaded_died, src); - } - if (HARD_REGISTER_P (rl_reg_rtx)) - { - int s = rl->secondary_out_reload; - set = single_set (p); - /* If this reload copies only to the secondary reload - register, the secondary reload does the actual - store. */ - if (s >= 0 && set == NULL_RTX) - /* We can't tell what function the secondary reload - has and where the actual store to the pseudo is - made; leave new_spill_reg_store alone. */ - ; - else if (s >= 0 - && SET_SRC (set) == rl_reg_rtx - && SET_DEST (set) == rld[s].reg_rtx) - { - /* Usually the next instruction will be the - secondary reload insn; if we can confirm - that it is, setting new_spill_reg_store to - that insn will allow an extra optimization. */ - rtx s_reg = rld[s].reg_rtx; - rtx_insn *next = NEXT_INSN (p); - rld[s].out = rl->out; - rld[s].out_reg = rl->out_reg; - set = single_set (next); - if (set && SET_SRC (set) == s_reg - && reload_reg_rtx_reaches_end_p (s_reg, s)) - { - SET_HARD_REG_BIT (reg_is_output_reload, - REGNO (s_reg)); - new_spill_reg_store[REGNO (s_reg)] = next; - } - } - else if (reload_reg_rtx_reaches_end_p (rl_reg_rtx, j)) - new_spill_reg_store[REGNO (rl_reg_rtx)] = p; - } - } - } - - if (rl->when_needed == RELOAD_OTHER) - { - emit_insn (other_output_reload_insns[rl->opnum]); - other_output_reload_insns[rl->opnum] = get_insns (); - } - else - output_reload_insns[rl->opnum] = get_insns (); - - if (cfun->can_throw_non_call_exceptions) - copy_reg_eh_region_note_forward (insn, get_insns (), NULL); - - end_sequence (); -} - -/* Do input reloading for reload RL, which is for the insn described by CHAIN - and has the number J. */ -static void -do_input_reload (class insn_chain *chain, struct reload *rl, int j) -{ - rtx_insn *insn = chain->insn; - rtx old = (rl->in && MEM_P (rl->in) - ? rl->in_reg : rl->in); - rtx reg_rtx = rl->reg_rtx; - - if (old && reg_rtx) - { - machine_mode mode; - - /* Determine the mode to reload in. - This is very tricky because we have three to choose from. - There is the mode the insn operand wants (rl->inmode). - There is the mode of the reload register RELOADREG. - There is the intrinsic mode of the operand, which we could find - by stripping some SUBREGs. - It turns out that RELOADREG's mode is irrelevant: - we can change that arbitrarily. - - Consider (SUBREG:SI foo:QI) as an operand that must be SImode; - then the reload reg may not support QImode moves, so use SImode. - If foo is in memory due to spilling a pseudo reg, this is safe, - because the QImode value is in the least significant part of a - slot big enough for a SImode. If foo is some other sort of - memory reference, then it is impossible to reload this case, - so previous passes had better make sure this never happens. - - Then consider a one-word union which has SImode and one of its - members is a float, being fetched as (SUBREG:SF union:SI). - We must fetch that as SFmode because we could be loading into - a float-only register. In this case OLD's mode is correct. - - Consider an immediate integer: it has VOIDmode. Here we need - to get a mode from something else. - - In some cases, there is a fourth mode, the operand's - containing mode. If the insn specifies a containing mode for - this operand, it overrides all others. - - I am not sure whether the algorithm here is always right, - but it does the right things in those cases. */ - - mode = GET_MODE (old); - if (mode == VOIDmode) - mode = rl->inmode; - - /* We cannot use gen_lowpart_common since it can do the wrong thing - when REG_RTX has a multi-word mode. Note that REG_RTX must - always be a REG here. */ - if (GET_MODE (reg_rtx) != mode) - reg_rtx = reload_adjust_reg_for_mode (reg_rtx, mode); - } - reload_reg_rtx_for_input[j] = reg_rtx; - - if (old != 0 - /* AUTO_INC reloads need to be handled even if inherited. We got an - AUTO_INC reload if reload_out is set but reload_out_reg isn't. */ - && (! reload_inherited[j] || (rl->out && ! rl->out_reg)) - && ! rtx_equal_p (reg_rtx, old) - && reg_rtx != 0) - emit_input_reload_insns (chain, rld + j, old, j); - - /* When inheriting a wider reload, we have a MEM in rl->in, - e.g. inheriting a SImode output reload for - (mem:HI (plus:SI (reg:SI 14 fp) (const_int 10))) */ - if (optimize && reload_inherited[j] && rl->in - && MEM_P (rl->in) - && MEM_P (rl->in_reg) - && reload_spill_index[j] >= 0 - && TEST_HARD_REG_BIT (reg_reloaded_valid, reload_spill_index[j])) - rl->in = regno_reg_rtx[reg_reloaded_contents[reload_spill_index[j]]]; - - /* If we are reloading a register that was recently stored in with an - output-reload, see if we can prove there was - actually no need to store the old value in it. */ - - if (optimize - && (reload_inherited[j] || reload_override_in[j]) - && reg_rtx - && REG_P (reg_rtx) - && spill_reg_store[REGNO (reg_rtx)] != 0 -#if 0 - /* There doesn't seem to be any reason to restrict this to pseudos - and doing so loses in the case where we are copying from a - register of the wrong class. */ - && !HARD_REGISTER_P (spill_reg_stored_to[REGNO (reg_rtx)]) -#endif - /* The insn might have already some references to stackslots - replaced by MEMs, while reload_out_reg still names the - original pseudo. */ - && (dead_or_set_p (insn, spill_reg_stored_to[REGNO (reg_rtx)]) - || rtx_equal_p (spill_reg_stored_to[REGNO (reg_rtx)], rl->out_reg))) - delete_output_reload (insn, j, REGNO (reg_rtx), reg_rtx); -} - -/* Do output reloading for reload RL, which is for the insn described by - CHAIN and has the number J. - ??? At some point we need to support handling output reloads of - JUMP_INSNs. */ -static void -do_output_reload (class insn_chain *chain, struct reload *rl, int j) -{ - rtx note, old; - rtx_insn *insn = chain->insn; - /* If this is an output reload that stores something that is - not loaded in this same reload, see if we can eliminate a previous - store. */ - rtx pseudo = rl->out_reg; - rtx reg_rtx = rl->reg_rtx; - - if (rl->out && reg_rtx) - { - machine_mode mode; - - /* Determine the mode to reload in. - See comments above (for input reloading). */ - mode = GET_MODE (rl->out); - if (mode == VOIDmode) - { - /* VOIDmode should never happen for an output. */ - if (asm_noperands (PATTERN (insn)) < 0) - /* It's the compiler's fault. */ - fatal_insn ("VOIDmode on an output", insn); - error_for_asm (insn, "output operand is constant in %<asm%>"); - /* Prevent crash--use something we know is valid. */ - mode = word_mode; - rl->out = gen_rtx_REG (mode, REGNO (reg_rtx)); - } - if (GET_MODE (reg_rtx) != mode) - reg_rtx = reload_adjust_reg_for_mode (reg_rtx, mode); - } - reload_reg_rtx_for_output[j] = reg_rtx; - - if (pseudo - && optimize - && REG_P (pseudo) - && ! rtx_equal_p (rl->in_reg, pseudo) - && REGNO (pseudo) >= FIRST_PSEUDO_REGISTER - && reg_last_reload_reg[REGNO (pseudo)]) - { - int pseudo_no = REGNO (pseudo); - int last_regno = REGNO (reg_last_reload_reg[pseudo_no]); - - /* We don't need to test full validity of last_regno for - inherit here; we only want to know if the store actually - matches the pseudo. */ - if (TEST_HARD_REG_BIT (reg_reloaded_valid, last_regno) - && reg_reloaded_contents[last_regno] == pseudo_no - && spill_reg_store[last_regno] - && rtx_equal_p (pseudo, spill_reg_stored_to[last_regno])) - delete_output_reload (insn, j, last_regno, reg_rtx); - } - - old = rl->out_reg; - if (old == 0 - || reg_rtx == 0 - || rtx_equal_p (old, reg_rtx)) - return; - - /* An output operand that dies right away does need a reload, - but need not be copied from it. Show the new location in the - REG_UNUSED note. */ - if ((REG_P (old) || GET_CODE (old) == SCRATCH) - && (note = find_reg_note (insn, REG_UNUSED, old)) != 0) - { - XEXP (note, 0) = reg_rtx; - return; - } - /* Likewise for a SUBREG of an operand that dies. */ - else if (GET_CODE (old) == SUBREG - && REG_P (SUBREG_REG (old)) - && (note = find_reg_note (insn, REG_UNUSED, - SUBREG_REG (old))) != 0) - { - XEXP (note, 0) = gen_lowpart_common (GET_MODE (old), reg_rtx); - return; - } - else if (GET_CODE (old) == SCRATCH) - /* If we aren't optimizing, there won't be a REG_UNUSED note, - but we don't want to make an output reload. */ - return; - - /* If is a JUMP_INSN, we can't support output reloads yet. */ - gcc_assert (NONJUMP_INSN_P (insn)); - - emit_output_reload_insns (chain, rld + j, j); -} - -/* A reload copies values of MODE from register SRC to register DEST. - Return true if it can be treated for inheritance purposes like a - group of reloads, each one reloading a single hard register. The - caller has already checked that (reg:MODE SRC) and (reg:MODE DEST) - occupy the same number of hard registers. */ - -static bool -inherit_piecemeal_p (int dest ATTRIBUTE_UNUSED, - int src ATTRIBUTE_UNUSED, - machine_mode mode ATTRIBUTE_UNUSED) -{ - return (REG_CAN_CHANGE_MODE_P (dest, mode, reg_raw_mode[dest]) - && REG_CAN_CHANGE_MODE_P (src, mode, reg_raw_mode[src])); -} - -/* Output insns to reload values in and out of the chosen reload regs. */ - -static void -emit_reload_insns (class insn_chain *chain) -{ - rtx_insn *insn = chain->insn; - - int j; - - CLEAR_HARD_REG_SET (reg_reloaded_died); - - for (j = 0; j < reload_n_operands; j++) - input_reload_insns[j] = input_address_reload_insns[j] - = inpaddr_address_reload_insns[j] - = output_reload_insns[j] = output_address_reload_insns[j] - = outaddr_address_reload_insns[j] - = other_output_reload_insns[j] = 0; - other_input_address_reload_insns = 0; - other_input_reload_insns = 0; - operand_reload_insns = 0; - other_operand_reload_insns = 0; - - /* Dump reloads into the dump file. */ - if (dump_file) - { - fprintf (dump_file, "\nReloads for insn # %d\n", INSN_UID (insn)); - debug_reload_to_stream (dump_file); - } - - for (j = 0; j < n_reloads; j++) - if (rld[j].reg_rtx && HARD_REGISTER_P (rld[j].reg_rtx)) - { - unsigned int i; - - for (i = REGNO (rld[j].reg_rtx); i < END_REGNO (rld[j].reg_rtx); i++) - new_spill_reg_store[i] = 0; - } - - /* Now output the instructions to copy the data into and out of the - reload registers. Do these in the order that the reloads were reported, - since reloads of base and index registers precede reloads of operands - and the operands may need the base and index registers reloaded. */ - - for (j = 0; j < n_reloads; j++) - { - do_input_reload (chain, rld + j, j); - do_output_reload (chain, rld + j, j); - } - - /* Now write all the insns we made for reloads in the order expected by - the allocation functions. Prior to the insn being reloaded, we write - the following reloads: - - RELOAD_FOR_OTHER_ADDRESS reloads for input addresses. - - RELOAD_OTHER reloads. - - For each operand, any RELOAD_FOR_INPADDR_ADDRESS reloads followed - by any RELOAD_FOR_INPUT_ADDRESS reloads followed by the - RELOAD_FOR_INPUT reload for the operand. - - RELOAD_FOR_OPADDR_ADDRS reloads. - - RELOAD_FOR_OPERAND_ADDRESS reloads. - - After the insn being reloaded, we write the following: - - For each operand, any RELOAD_FOR_OUTADDR_ADDRESS reloads followed - by any RELOAD_FOR_OUTPUT_ADDRESS reload followed by the - RELOAD_FOR_OUTPUT reload, followed by any RELOAD_OTHER output - reloads for the operand. The RELOAD_OTHER output reloads are - output in descending order by reload number. */ - - emit_insn_before (other_input_address_reload_insns, insn); - emit_insn_before (other_input_reload_insns, insn); - - for (j = 0; j < reload_n_operands; j++) - { - emit_insn_before (inpaddr_address_reload_insns[j], insn); - emit_insn_before (input_address_reload_insns[j], insn); - emit_insn_before (input_reload_insns[j], insn); - } - - emit_insn_before (other_operand_reload_insns, insn); - emit_insn_before (operand_reload_insns, insn); - - for (j = 0; j < reload_n_operands; j++) - { - rtx_insn *x = emit_insn_after (outaddr_address_reload_insns[j], insn); - x = emit_insn_after (output_address_reload_insns[j], x); - x = emit_insn_after (output_reload_insns[j], x); - emit_insn_after (other_output_reload_insns[j], x); - } - - /* For all the spill regs newly reloaded in this instruction, - record what they were reloaded from, so subsequent instructions - can inherit the reloads. - - Update spill_reg_store for the reloads of this insn. - Copy the elements that were updated in the loop above. */ - - for (j = 0; j < n_reloads; j++) - { - int r = reload_order[j]; - int i = reload_spill_index[r]; - - /* If this is a non-inherited input reload from a pseudo, we must - clear any memory of a previous store to the same pseudo. Only do - something if there will not be an output reload for the pseudo - being reloaded. */ - if (rld[r].in_reg != 0 - && ! (reload_inherited[r] || reload_override_in[r])) - { - rtx reg = rld[r].in_reg; - - if (GET_CODE (reg) == SUBREG) - reg = SUBREG_REG (reg); - - if (REG_P (reg) - && REGNO (reg) >= FIRST_PSEUDO_REGISTER - && !REGNO_REG_SET_P (®_has_output_reload, REGNO (reg))) - { - int nregno = REGNO (reg); - - if (reg_last_reload_reg[nregno]) - { - int last_regno = REGNO (reg_last_reload_reg[nregno]); - - if (reg_reloaded_contents[last_regno] == nregno) - spill_reg_store[last_regno] = 0; - } - } - } - - /* I is nonneg if this reload used a register. - If rld[r].reg_rtx is 0, this is an optional reload - that we opted to ignore. */ - - if (i >= 0 && rld[r].reg_rtx != 0) - { - int nr = hard_regno_nregs (i, GET_MODE (rld[r].reg_rtx)); - int k; - - /* For a multi register reload, we need to check if all or part - of the value lives to the end. */ - for (k = 0; k < nr; k++) - if (reload_reg_reaches_end_p (i + k, r)) - CLEAR_HARD_REG_BIT (reg_reloaded_valid, i + k); - - /* Maybe the spill reg contains a copy of reload_out. */ - if (rld[r].out != 0 - && (REG_P (rld[r].out) - || (rld[r].out_reg - ? REG_P (rld[r].out_reg) - /* The reload value is an auto-modification of - some kind. For PRE_INC, POST_INC, PRE_DEC - and POST_DEC, we record an equivalence - between the reload register and the operand - on the optimistic assumption that we can make - the equivalence hold. reload_as_needed must - then either make it hold or invalidate the - equivalence. - - PRE_MODIFY and POST_MODIFY addresses are reloaded - somewhat differently, and allowing them here leads - to problems. */ - : (GET_CODE (rld[r].out) != POST_MODIFY - && GET_CODE (rld[r].out) != PRE_MODIFY)))) - { - rtx reg; - - reg = reload_reg_rtx_for_output[r]; - if (reload_reg_rtx_reaches_end_p (reg, r)) - { - machine_mode mode = GET_MODE (reg); - int regno = REGNO (reg); - int nregs = REG_NREGS (reg); - rtx out = (REG_P (rld[r].out) - ? rld[r].out - : rld[r].out_reg - ? rld[r].out_reg -/* AUTO_INC */ : XEXP (rld[r].in_reg, 0)); - int out_regno = REGNO (out); - int out_nregs = (!HARD_REGISTER_NUM_P (out_regno) ? 1 - : hard_regno_nregs (out_regno, mode)); - bool piecemeal; - - spill_reg_store[regno] = new_spill_reg_store[regno]; - spill_reg_stored_to[regno] = out; - reg_last_reload_reg[out_regno] = reg; - - piecemeal = (HARD_REGISTER_NUM_P (out_regno) - && nregs == out_nregs - && inherit_piecemeal_p (out_regno, regno, mode)); - - /* If OUT_REGNO is a hard register, it may occupy more than - one register. If it does, say what is in the - rest of the registers assuming that both registers - agree on how many words the object takes. If not, - invalidate the subsequent registers. */ - - if (HARD_REGISTER_NUM_P (out_regno)) - for (k = 1; k < out_nregs; k++) - reg_last_reload_reg[out_regno + k] - = (piecemeal ? regno_reg_rtx[regno + k] : 0); - - /* Now do the inverse operation. */ - for (k = 0; k < nregs; k++) - { - CLEAR_HARD_REG_BIT (reg_reloaded_dead, regno + k); - reg_reloaded_contents[regno + k] - = (!HARD_REGISTER_NUM_P (out_regno) || !piecemeal - ? out_regno - : out_regno + k); - reg_reloaded_insn[regno + k] = insn; - SET_HARD_REG_BIT (reg_reloaded_valid, regno + k); - } - } - } - /* Maybe the spill reg contains a copy of reload_in. Only do - something if there will not be an output reload for - the register being reloaded. */ - else if (rld[r].out_reg == 0 - && rld[r].in != 0 - && ((REG_P (rld[r].in) - && !HARD_REGISTER_P (rld[r].in) - && !REGNO_REG_SET_P (®_has_output_reload, - REGNO (rld[r].in))) - || (REG_P (rld[r].in_reg) - && !REGNO_REG_SET_P (®_has_output_reload, - REGNO (rld[r].in_reg)))) - && !reg_set_p (reload_reg_rtx_for_input[r], PATTERN (insn))) - { - rtx reg; - - reg = reload_reg_rtx_for_input[r]; - if (reload_reg_rtx_reaches_end_p (reg, r)) - { - machine_mode mode; - int regno; - int nregs; - int in_regno; - int in_nregs; - rtx in; - bool piecemeal; - - mode = GET_MODE (reg); - regno = REGNO (reg); - nregs = REG_NREGS (reg); - if (REG_P (rld[r].in) - && REGNO (rld[r].in) >= FIRST_PSEUDO_REGISTER) - in = rld[r].in; - else if (REG_P (rld[r].in_reg)) - in = rld[r].in_reg; - else - in = XEXP (rld[r].in_reg, 0); - in_regno = REGNO (in); - - in_nregs = (!HARD_REGISTER_NUM_P (in_regno) ? 1 - : hard_regno_nregs (in_regno, mode)); - - reg_last_reload_reg[in_regno] = reg; - - piecemeal = (HARD_REGISTER_NUM_P (in_regno) - && nregs == in_nregs - && inherit_piecemeal_p (regno, in_regno, mode)); - - if (HARD_REGISTER_NUM_P (in_regno)) - for (k = 1; k < in_nregs; k++) - reg_last_reload_reg[in_regno + k] - = (piecemeal ? regno_reg_rtx[regno + k] : 0); - - /* Unless we inherited this reload, show we haven't - recently done a store. - Previous stores of inherited auto_inc expressions - also have to be discarded. */ - if (! reload_inherited[r] - || (rld[r].out && ! rld[r].out_reg)) - spill_reg_store[regno] = 0; - - for (k = 0; k < nregs; k++) - { - CLEAR_HARD_REG_BIT (reg_reloaded_dead, regno + k); - reg_reloaded_contents[regno + k] - = (!HARD_REGISTER_NUM_P (in_regno) || !piecemeal - ? in_regno - : in_regno + k); - reg_reloaded_insn[regno + k] = insn; - SET_HARD_REG_BIT (reg_reloaded_valid, regno + k); - } - } - } - } - - /* The following if-statement was #if 0'd in 1.34 (or before...). - It's reenabled in 1.35 because supposedly nothing else - deals with this problem. */ - - /* If a register gets output-reloaded from a non-spill register, - that invalidates any previous reloaded copy of it. - But forget_old_reloads_1 won't get to see it, because - it thinks only about the original insn. So invalidate it here. - Also do the same thing for RELOAD_OTHER constraints where the - output is discarded. */ - if (i < 0 - && ((rld[r].out != 0 - && (REG_P (rld[r].out) - || (MEM_P (rld[r].out) - && REG_P (rld[r].out_reg)))) - || (rld[r].out == 0 && rld[r].out_reg - && REG_P (rld[r].out_reg)))) - { - rtx out = ((rld[r].out && REG_P (rld[r].out)) - ? rld[r].out : rld[r].out_reg); - int out_regno = REGNO (out); - machine_mode mode = GET_MODE (out); - - /* REG_RTX is now set or clobbered by the main instruction. - As the comment above explains, forget_old_reloads_1 only - sees the original instruction, and there is no guarantee - that the original instruction also clobbered REG_RTX. - For example, if find_reloads sees that the input side of - a matched operand pair dies in this instruction, it may - use the input register as the reload register. - - Calling forget_old_reloads_1 is a waste of effort if - REG_RTX is also the output register. - - If we know that REG_RTX holds the value of a pseudo - register, the code after the call will record that fact. */ - if (rld[r].reg_rtx && rld[r].reg_rtx != out) - forget_old_reloads_1 (rld[r].reg_rtx, NULL_RTX, NULL); - - if (!HARD_REGISTER_NUM_P (out_regno)) - { - rtx src_reg; - rtx_insn *store_insn = NULL; - - reg_last_reload_reg[out_regno] = 0; - - /* If we can find a hard register that is stored, record - the storing insn so that we may delete this insn with - delete_output_reload. */ - src_reg = reload_reg_rtx_for_output[r]; - - if (src_reg) - { - if (reload_reg_rtx_reaches_end_p (src_reg, r)) - store_insn = new_spill_reg_store[REGNO (src_reg)]; - else - src_reg = NULL_RTX; - } - else - { - /* If this is an optional reload, try to find the - source reg from an input reload. */ - rtx set = single_set (insn); - if (set && SET_DEST (set) == rld[r].out) - { - int k; - - src_reg = SET_SRC (set); - store_insn = insn; - for (k = 0; k < n_reloads; k++) - { - if (rld[k].in == src_reg) - { - src_reg = reload_reg_rtx_for_input[k]; - break; - } - } - } - } - if (src_reg && REG_P (src_reg) - && REGNO (src_reg) < FIRST_PSEUDO_REGISTER) - { - int src_regno, src_nregs, k; - rtx note; - - gcc_assert (GET_MODE (src_reg) == mode); - src_regno = REGNO (src_reg); - src_nregs = hard_regno_nregs (src_regno, mode); - /* The place where to find a death note varies with - PRESERVE_DEATH_INFO_REGNO_P . The condition is not - necessarily checked exactly in the code that moves - notes, so just check both locations. */ - note = find_regno_note (insn, REG_DEAD, src_regno); - if (! note && store_insn) - note = find_regno_note (store_insn, REG_DEAD, src_regno); - for (k = 0; k < src_nregs; k++) - { - spill_reg_store[src_regno + k] = store_insn; - spill_reg_stored_to[src_regno + k] = out; - reg_reloaded_contents[src_regno + k] = out_regno; - reg_reloaded_insn[src_regno + k] = store_insn; - CLEAR_HARD_REG_BIT (reg_reloaded_dead, src_regno + k); - SET_HARD_REG_BIT (reg_reloaded_valid, src_regno + k); - SET_HARD_REG_BIT (reg_is_output_reload, src_regno + k); - if (note) - SET_HARD_REG_BIT (reg_reloaded_died, src_regno); - else - CLEAR_HARD_REG_BIT (reg_reloaded_died, src_regno); - } - reg_last_reload_reg[out_regno] = src_reg; - /* We have to set reg_has_output_reload here, or else - forget_old_reloads_1 will clear reg_last_reload_reg - right away. */ - SET_REGNO_REG_SET (®_has_output_reload, - out_regno); - } - } - else - { - int k, out_nregs = hard_regno_nregs (out_regno, mode); - - for (k = 0; k < out_nregs; k++) - reg_last_reload_reg[out_regno + k] = 0; - } - } - } - reg_reloaded_dead |= reg_reloaded_died; -} - -/* Go through the motions to emit INSN and test if it is strictly valid. - Return the emitted insn if valid, else return NULL. */ - -static rtx_insn * -emit_insn_if_valid_for_reload (rtx pat) -{ - rtx_insn *last = get_last_insn (); - int code; - - rtx_insn *insn = emit_insn (pat); - code = recog_memoized (insn); - - if (code >= 0) - { - extract_insn (insn); - /* We want constrain operands to treat this insn strictly in its - validity determination, i.e., the way it would after reload has - completed. */ - if (constrain_operands (1, get_enabled_alternatives (insn))) - return insn; - } - - delete_insns_since (last); - return NULL; -} - -/* Emit code to perform a reload from IN (which may be a reload register) to - OUT (which may also be a reload register). IN or OUT is from operand - OPNUM with reload type TYPE. - - Returns first insn emitted. */ - -static rtx_insn * -gen_reload (rtx out, rtx in, int opnum, enum reload_type type) -{ - rtx_insn *last = get_last_insn (); - rtx_insn *tem; - rtx tem1, tem2; - - /* If IN is a paradoxical SUBREG, remove it and try to put the - opposite SUBREG on OUT. Likewise for a paradoxical SUBREG on OUT. */ - if (!strip_paradoxical_subreg (&in, &out)) - strip_paradoxical_subreg (&out, &in); - - /* How to do this reload can get quite tricky. Normally, we are being - asked to reload a simple operand, such as a MEM, a constant, or a pseudo - register that didn't get a hard register. In that case we can just - call emit_move_insn. - - We can also be asked to reload a PLUS that adds a register or a MEM to - another register, constant or MEM. This can occur during frame pointer - elimination and while reloading addresses. This case is handled by - trying to emit a single insn to perform the add. If it is not valid, - we use a two insn sequence. - - Or we can be asked to reload an unary operand that was a fragment of - an addressing mode, into a register. If it isn't recognized as-is, - we try making the unop operand and the reload-register the same: - (set reg:X (unop:X expr:Y)) - -> (set reg:Y expr:Y) (set reg:X (unop:X reg:Y)). - - Finally, we could be called to handle an 'o' constraint by putting - an address into a register. In that case, we first try to do this - with a named pattern of "reload_load_address". If no such pattern - exists, we just emit a SET insn and hope for the best (it will normally - be valid on machines that use 'o'). - - This entire process is made complex because reload will never - process the insns we generate here and so we must ensure that - they will fit their constraints and also by the fact that parts of - IN might be being reloaded separately and replaced with spill registers. - Because of this, we are, in some sense, just guessing the right approach - here. The one listed above seems to work. - - ??? At some point, this whole thing needs to be rethought. */ - - if (GET_CODE (in) == PLUS - && (REG_P (XEXP (in, 0)) - || GET_CODE (XEXP (in, 0)) == SUBREG - || MEM_P (XEXP (in, 0))) - && (REG_P (XEXP (in, 1)) - || GET_CODE (XEXP (in, 1)) == SUBREG - || CONSTANT_P (XEXP (in, 1)) - || MEM_P (XEXP (in, 1)))) - { - /* We need to compute the sum of a register or a MEM and another - register, constant, or MEM, and put it into the reload - register. The best possible way of doing this is if the machine - has a three-operand ADD insn that accepts the required operands. - - The simplest approach is to try to generate such an insn and see if it - is recognized and matches its constraints. If so, it can be used. - - It might be better not to actually emit the insn unless it is valid, - but we need to pass the insn as an operand to `recog' and - `extract_insn' and it is simpler to emit and then delete the insn if - not valid than to dummy things up. */ - - rtx op0, op1, tem; - rtx_insn *insn; - enum insn_code code; - - op0 = find_replacement (&XEXP (in, 0)); - op1 = find_replacement (&XEXP (in, 1)); - - /* Since constraint checking is strict, commutativity won't be - checked, so we need to do that here to avoid spurious failure - if the add instruction is two-address and the second operand - of the add is the same as the reload reg, which is frequently - the case. If the insn would be A = B + A, rearrange it so - it will be A = A + B as constrain_operands expects. */ - - if (REG_P (XEXP (in, 1)) - && REGNO (out) == REGNO (XEXP (in, 1))) - tem = op0, op0 = op1, op1 = tem; - - if (op0 != XEXP (in, 0) || op1 != XEXP (in, 1)) - in = gen_rtx_PLUS (GET_MODE (in), op0, op1); - - insn = emit_insn_if_valid_for_reload (gen_rtx_SET (out, in)); - if (insn) - return insn; - - /* If that failed, we must use a conservative two-insn sequence. - - Use a move to copy one operand into the reload register. Prefer - to reload a constant, MEM or pseudo since the move patterns can - handle an arbitrary operand. If OP1 is not a constant, MEM or - pseudo and OP1 is not a valid operand for an add instruction, then - reload OP1. - - After reloading one of the operands into the reload register, add - the reload register to the output register. - - If there is another way to do this for a specific machine, a - DEFINE_PEEPHOLE should be specified that recognizes the sequence - we emit below. */ - - code = optab_handler (add_optab, GET_MODE (out)); - - if (CONSTANT_P (op1) || MEM_P (op1) || GET_CODE (op1) == SUBREG - || (REG_P (op1) - && REGNO (op1) >= FIRST_PSEUDO_REGISTER) - || (code != CODE_FOR_nothing - && !insn_operand_matches (code, 2, op1))) - tem = op0, op0 = op1, op1 = tem; - - gen_reload (out, op0, opnum, type); - - /* If OP0 and OP1 are the same, we can use OUT for OP1. - This fixes a problem on the 32K where the stack pointer cannot - be used as an operand of an add insn. */ - - if (rtx_equal_p (op0, op1)) - op1 = out; - - insn = emit_insn_if_valid_for_reload (gen_add2_insn (out, op1)); - if (insn) - { - /* Add a REG_EQUIV note so that find_equiv_reg can find it. */ - set_dst_reg_note (insn, REG_EQUIV, in, out); - return insn; - } - - /* If that failed, copy the address register to the reload register. - Then add the constant to the reload register. */ - - gcc_assert (!reg_overlap_mentioned_p (out, op0)); - gen_reload (out, op1, opnum, type); - insn = emit_insn (gen_add2_insn (out, op0)); - set_dst_reg_note (insn, REG_EQUIV, in, out); - } - - /* If we need a memory location to do the move, do it that way. */ - else if ((tem1 = replaced_subreg (in), tem2 = replaced_subreg (out), - (REG_P (tem1) && REG_P (tem2))) - && REGNO (tem1) < FIRST_PSEUDO_REGISTER - && REGNO (tem2) < FIRST_PSEUDO_REGISTER - && targetm.secondary_memory_needed (GET_MODE (out), - REGNO_REG_CLASS (REGNO (tem1)), - REGNO_REG_CLASS (REGNO (tem2)))) - { - /* Get the memory to use and rewrite both registers to its mode. */ - rtx loc = get_secondary_mem (in, GET_MODE (out), opnum, type); - - if (GET_MODE (loc) != GET_MODE (out)) - out = gen_rtx_REG (GET_MODE (loc), reg_or_subregno (out)); - - if (GET_MODE (loc) != GET_MODE (in)) - in = gen_rtx_REG (GET_MODE (loc), reg_or_subregno (in)); - - gen_reload (loc, in, opnum, type); - gen_reload (out, loc, opnum, type); - } - else if (REG_P (out) && UNARY_P (in)) - { - rtx op1; - rtx out_moded; - rtx_insn *set; - - op1 = find_replacement (&XEXP (in, 0)); - if (op1 != XEXP (in, 0)) - in = gen_rtx_fmt_e (GET_CODE (in), GET_MODE (in), op1); - - /* First, try a plain SET. */ - set = emit_insn_if_valid_for_reload (gen_rtx_SET (out, in)); - if (set) - return set; - - /* If that failed, move the inner operand to the reload - register, and try the same unop with the inner expression - replaced with the reload register. */ - - if (GET_MODE (op1) != GET_MODE (out)) - out_moded = gen_rtx_REG (GET_MODE (op1), REGNO (out)); - else - out_moded = out; - - gen_reload (out_moded, op1, opnum, type); - - rtx temp = gen_rtx_SET (out, gen_rtx_fmt_e (GET_CODE (in), GET_MODE (in), - out_moded)); - rtx_insn *insn = emit_insn_if_valid_for_reload (temp); - if (insn) - { - set_unique_reg_note (insn, REG_EQUIV, in); - return insn; - } - - fatal_insn ("failure trying to reload:", set); - } - /* If IN is a simple operand, use gen_move_insn. */ - else if (OBJECT_P (in) || GET_CODE (in) == SUBREG) - { - tem = emit_insn (gen_move_insn (out, in)); - /* IN may contain a LABEL_REF, if so add a REG_LABEL_OPERAND note. */ - mark_jump_label (in, tem, 0); - } - - else if (targetm.have_reload_load_address ()) - emit_insn (targetm.gen_reload_load_address (out, in)); - - /* Otherwise, just write (set OUT IN) and hope for the best. */ - else - emit_insn (gen_rtx_SET (out, in)); - - /* Return the first insn emitted. - We cannot just return get_last_insn, because there may have - been multiple instructions emitted. Also note that gen_move_insn may - emit more than one insn itself, so we cannot assume that there is one - insn emitted per emit_insn_before call. */ - - return last ? NEXT_INSN (last) : get_insns (); -} - -/* Delete a previously made output-reload whose result we now believe - is not needed. First we double-check. - - INSN is the insn now being processed. - LAST_RELOAD_REG is the hard register number for which we want to delete - the last output reload. - J is the reload-number that originally used REG. The caller has made - certain that reload J doesn't use REG any longer for input. - NEW_RELOAD_REG is reload register that reload J is using for REG. */ - -static void -delete_output_reload (rtx_insn *insn, int j, int last_reload_reg, - rtx new_reload_reg) -{ - rtx_insn *output_reload_insn = spill_reg_store[last_reload_reg]; - rtx reg = spill_reg_stored_to[last_reload_reg]; - int k; - int n_occurrences; - int n_inherited = 0; - rtx substed; - unsigned regno; - int nregs; - - /* It is possible that this reload has been only used to set another reload - we eliminated earlier and thus deleted this instruction too. */ - if (output_reload_insn->deleted ()) - return; - - /* Get the raw pseudo-register referred to. */ - - while (GET_CODE (reg) == SUBREG) - reg = SUBREG_REG (reg); - substed = reg_equiv_memory_loc (REGNO (reg)); - - /* This is unsafe if the operand occurs more often in the current - insn than it is inherited. */ - for (k = n_reloads - 1; k >= 0; k--) - { - rtx reg2 = rld[k].in; - if (! reg2) - continue; - if (MEM_P (reg2) || reload_override_in[k]) - reg2 = rld[k].in_reg; - - if (AUTO_INC_DEC && rld[k].out && ! rld[k].out_reg) - reg2 = XEXP (rld[k].in_reg, 0); - - while (GET_CODE (reg2) == SUBREG) - reg2 = SUBREG_REG (reg2); - if (rtx_equal_p (reg2, reg)) - { - if (reload_inherited[k] || reload_override_in[k] || k == j) - n_inherited++; - else - return; - } - } - n_occurrences = count_occurrences (PATTERN (insn), reg, 0); - if (CALL_P (insn) && CALL_INSN_FUNCTION_USAGE (insn)) - n_occurrences += count_occurrences (CALL_INSN_FUNCTION_USAGE (insn), - reg, 0); - if (substed) - n_occurrences += count_occurrences (PATTERN (insn), - eliminate_regs (substed, VOIDmode, - NULL_RTX), 0); - for (rtx i1 = reg_equiv_alt_mem_list (REGNO (reg)); i1; i1 = XEXP (i1, 1)) - { - gcc_assert (!rtx_equal_p (XEXP (i1, 0), substed)); - n_occurrences += count_occurrences (PATTERN (insn), XEXP (i1, 0), 0); - } - if (n_occurrences > n_inherited) - return; - - regno = REGNO (reg); - nregs = REG_NREGS (reg); - - /* If the pseudo-reg we are reloading is no longer referenced - anywhere between the store into it and here, - and we're within the same basic block, then the value can only - pass through the reload reg and end up here. - Otherwise, give up--return. */ - for (rtx_insn *i1 = NEXT_INSN (output_reload_insn); - i1 != insn; i1 = NEXT_INSN (i1)) - { - if (NOTE_INSN_BASIC_BLOCK_P (i1)) - return; - if ((NONJUMP_INSN_P (i1) || CALL_P (i1)) - && refers_to_regno_p (regno, regno + nregs, PATTERN (i1), NULL)) - { - /* If this is USE in front of INSN, we only have to check that - there are no more references than accounted for by inheritance. */ - while (NONJUMP_INSN_P (i1) && GET_CODE (PATTERN (i1)) == USE) - { - n_occurrences += rtx_equal_p (reg, XEXP (PATTERN (i1), 0)) != 0; - i1 = NEXT_INSN (i1); - } - if (n_occurrences <= n_inherited && i1 == insn) - break; - return; - } - } - - /* We will be deleting the insn. Remove the spill reg information. */ - for (k = hard_regno_nregs (last_reload_reg, GET_MODE (reg)); k-- > 0; ) - { - spill_reg_store[last_reload_reg + k] = 0; - spill_reg_stored_to[last_reload_reg + k] = 0; - } - - /* The caller has already checked that REG dies or is set in INSN. - It has also checked that we are optimizing, and thus some - inaccuracies in the debugging information are acceptable. - So we could just delete output_reload_insn. But in some cases - we can improve the debugging information without sacrificing - optimization - maybe even improving the code: See if the pseudo - reg has been completely replaced with reload regs. If so, delete - the store insn and forget we had a stack slot for the pseudo. */ - if (rld[j].out != rld[j].in - && REG_N_DEATHS (REGNO (reg)) == 1 - && REG_N_SETS (REGNO (reg)) == 1 - && REG_BASIC_BLOCK (REGNO (reg)) >= NUM_FIXED_BLOCKS - && find_regno_note (insn, REG_DEAD, REGNO (reg))) - { - rtx_insn *i2; - - /* We know that it was used only between here and the beginning of - the current basic block. (We also know that the last use before - INSN was the output reload we are thinking of deleting, but never - mind that.) Search that range; see if any ref remains. */ - for (i2 = PREV_INSN (insn); i2; i2 = PREV_INSN (i2)) - { - rtx set = single_set (i2); - - /* Uses which just store in the pseudo don't count, - since if they are the only uses, they are dead. */ - if (set != 0 && SET_DEST (set) == reg) - continue; - if (LABEL_P (i2) || JUMP_P (i2)) - break; - if ((NONJUMP_INSN_P (i2) || CALL_P (i2)) - && reg_mentioned_p (reg, PATTERN (i2))) - { - /* Some other ref remains; just delete the output reload we - know to be dead. */ - delete_address_reloads (output_reload_insn, insn); - delete_insn (output_reload_insn); - return; - } - } - - /* Delete the now-dead stores into this pseudo. Note that this - loop also takes care of deleting output_reload_insn. */ - for (i2 = PREV_INSN (insn); i2; i2 = PREV_INSN (i2)) - { - rtx set = single_set (i2); - - if (set != 0 && SET_DEST (set) == reg) - { - delete_address_reloads (i2, insn); - delete_insn (i2); - } - if (LABEL_P (i2) || JUMP_P (i2)) - break; - } - - /* For the debugging info, say the pseudo lives in this reload reg. */ - reg_renumber[REGNO (reg)] = REGNO (new_reload_reg); - if (ira_conflicts_p) - /* Inform IRA about the change. */ - ira_mark_allocation_change (REGNO (reg)); - alter_reg (REGNO (reg), -1, false); - } - else - { - delete_address_reloads (output_reload_insn, insn); - delete_insn (output_reload_insn); - } -} - -/* We are going to delete DEAD_INSN. Recursively delete loads of - reload registers used in DEAD_INSN that are not used till CURRENT_INSN. - CURRENT_INSN is being reloaded, so we have to check its reloads too. */ -static void -delete_address_reloads (rtx_insn *dead_insn, rtx_insn *current_insn) -{ - rtx set = single_set (dead_insn); - rtx set2, dst; - rtx_insn *prev, *next; - if (set) - { - rtx dst = SET_DEST (set); - if (MEM_P (dst)) - delete_address_reloads_1 (dead_insn, XEXP (dst, 0), current_insn); - } - /* If we deleted the store from a reloaded post_{in,de}c expression, - we can delete the matching adds. */ - prev = PREV_INSN (dead_insn); - next = NEXT_INSN (dead_insn); - if (! prev || ! next) - return; - set = single_set (next); - set2 = single_set (prev); - if (! set || ! set2 - || GET_CODE (SET_SRC (set)) != PLUS || GET_CODE (SET_SRC (set2)) != PLUS - || !CONST_INT_P (XEXP (SET_SRC (set), 1)) - || !CONST_INT_P (XEXP (SET_SRC (set2), 1))) - return; - dst = SET_DEST (set); - if (! rtx_equal_p (dst, SET_DEST (set2)) - || ! rtx_equal_p (dst, XEXP (SET_SRC (set), 0)) - || ! rtx_equal_p (dst, XEXP (SET_SRC (set2), 0)) - || (INTVAL (XEXP (SET_SRC (set), 1)) - != -INTVAL (XEXP (SET_SRC (set2), 1)))) - return; - delete_related_insns (prev); - delete_related_insns (next); -} - -/* Subfunction of delete_address_reloads: process registers found in X. */ -static void -delete_address_reloads_1 (rtx_insn *dead_insn, rtx x, rtx_insn *current_insn) -{ - rtx_insn *prev, *i2; - rtx set, dst; - int i, j; - enum rtx_code code = GET_CODE (x); - - if (code != REG) - { - const char *fmt = GET_RTX_FORMAT (code); - for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--) - { - if (fmt[i] == 'e') - delete_address_reloads_1 (dead_insn, XEXP (x, i), current_insn); - else if (fmt[i] == 'E') - { - for (j = XVECLEN (x, i) - 1; j >= 0; j--) - delete_address_reloads_1 (dead_insn, XVECEXP (x, i, j), - current_insn); - } - } - return; - } - - if (spill_reg_order[REGNO (x)] < 0) - return; - - /* Scan backwards for the insn that sets x. This might be a way back due - to inheritance. */ - for (prev = PREV_INSN (dead_insn); prev; prev = PREV_INSN (prev)) - { - code = GET_CODE (prev); - if (code == CODE_LABEL || code == JUMP_INSN) - return; - if (!INSN_P (prev)) - continue; - if (reg_set_p (x, PATTERN (prev))) - break; - if (reg_referenced_p (x, PATTERN (prev))) - return; - } - if (! prev || INSN_UID (prev) < reload_first_uid) - return; - /* Check that PREV only sets the reload register. */ - set = single_set (prev); - if (! set) - return; - dst = SET_DEST (set); - if (!REG_P (dst) - || ! rtx_equal_p (dst, x)) - return; - if (! reg_set_p (dst, PATTERN (dead_insn))) - { - /* Check if DST was used in a later insn - - it might have been inherited. */ - for (i2 = NEXT_INSN (dead_insn); i2; i2 = NEXT_INSN (i2)) - { - if (LABEL_P (i2)) - break; - if (! INSN_P (i2)) - continue; - if (reg_referenced_p (dst, PATTERN (i2))) - { - /* If there is a reference to the register in the current insn, - it might be loaded in a non-inherited reload. If no other - reload uses it, that means the register is set before - referenced. */ - if (i2 == current_insn) - { - for (j = n_reloads - 1; j >= 0; j--) - if ((rld[j].reg_rtx == dst && reload_inherited[j]) - || reload_override_in[j] == dst) - return; - for (j = n_reloads - 1; j >= 0; j--) - if (rld[j].in && rld[j].reg_rtx == dst) - break; - if (j >= 0) - break; - } - return; - } - if (JUMP_P (i2)) - break; - /* If DST is still live at CURRENT_INSN, check if it is used for - any reload. Note that even if CURRENT_INSN sets DST, we still - have to check the reloads. */ - if (i2 == current_insn) - { - for (j = n_reloads - 1; j >= 0; j--) - if ((rld[j].reg_rtx == dst && reload_inherited[j]) - || reload_override_in[j] == dst) - return; - /* ??? We can't finish the loop here, because dst might be - allocated to a pseudo in this block if no reload in this - block needs any of the classes containing DST - see - spill_hard_reg. There is no easy way to tell this, so we - have to scan till the end of the basic block. */ - } - if (reg_set_p (dst, PATTERN (i2))) - break; - } - } - delete_address_reloads_1 (prev, SET_SRC (set), current_insn); - reg_reloaded_contents[REGNO (dst)] = -1; - delete_insn (prev); -} - -/* Output reload-insns to reload VALUE into RELOADREG. - VALUE is an autoincrement or autodecrement RTX whose operand - is a register or memory location; - so reloading involves incrementing that location. - IN is either identical to VALUE, or some cheaper place to reload from. - - INC_AMOUNT is the number to increment or decrement by (always positive). - This cannot be deduced from VALUE. */ - -static void -inc_for_reload (rtx reloadreg, rtx in, rtx value, poly_int64 inc_amount) -{ - /* REG or MEM to be copied and incremented. */ - rtx incloc = find_replacement (&XEXP (value, 0)); - /* Nonzero if increment after copying. */ - int post = (GET_CODE (value) == POST_DEC || GET_CODE (value) == POST_INC - || GET_CODE (value) == POST_MODIFY); - rtx_insn *last; - rtx inc; - rtx_insn *add_insn; - int code; - rtx real_in = in == value ? incloc : in; - - /* No hard register is equivalent to this register after - inc/dec operation. If REG_LAST_RELOAD_REG were nonzero, - we could inc/dec that register as well (maybe even using it for - the source), but I'm not sure it's worth worrying about. */ - if (REG_P (incloc)) - reg_last_reload_reg[REGNO (incloc)] = 0; - - if (GET_CODE (value) == PRE_MODIFY || GET_CODE (value) == POST_MODIFY) - { - gcc_assert (GET_CODE (XEXP (value, 1)) == PLUS); - inc = find_replacement (&XEXP (XEXP (value, 1), 1)); - } - else - { - if (GET_CODE (value) == PRE_DEC || GET_CODE (value) == POST_DEC) - inc_amount = -inc_amount; - - inc = gen_int_mode (inc_amount, Pmode); - } - - /* If this is post-increment, first copy the location to the reload reg. */ - if (post && real_in != reloadreg) - emit_insn (gen_move_insn (reloadreg, real_in)); - - if (in == value) - { - /* See if we can directly increment INCLOC. Use a method similar to - that in gen_reload. */ - - last = get_last_insn (); - add_insn = emit_insn (gen_rtx_SET (incloc, - gen_rtx_PLUS (GET_MODE (incloc), - incloc, inc))); - - code = recog_memoized (add_insn); - if (code >= 0) - { - extract_insn (add_insn); - if (constrain_operands (1, get_enabled_alternatives (add_insn))) - { - /* If this is a pre-increment and we have incremented the value - where it lives, copy the incremented value to RELOADREG to - be used as an address. */ - - if (! post) - emit_insn (gen_move_insn (reloadreg, incloc)); - return; - } - } - delete_insns_since (last); - } - - /* If couldn't do the increment directly, must increment in RELOADREG. - The way we do this depends on whether this is pre- or post-increment. - For pre-increment, copy INCLOC to the reload register, increment it - there, then save back. */ - - if (! post) - { - if (in != reloadreg) - emit_insn (gen_move_insn (reloadreg, real_in)); - emit_insn (gen_add2_insn (reloadreg, inc)); - emit_insn (gen_move_insn (incloc, reloadreg)); - } - else - { - /* Postincrement. - Because this might be a jump insn or a compare, and because RELOADREG - may not be available after the insn in an input reload, we must do - the incrementation before the insn being reloaded for. - - We have already copied IN to RELOADREG. Increment the copy in - RELOADREG, save that back, then decrement RELOADREG so it has - the original value. */ - - emit_insn (gen_add2_insn (reloadreg, inc)); - emit_insn (gen_move_insn (incloc, reloadreg)); - if (CONST_INT_P (inc)) - emit_insn (gen_add2_insn (reloadreg, - gen_int_mode (-INTVAL (inc), - GET_MODE (reloadreg)))); - else - emit_insn (gen_sub2_insn (reloadreg, inc)); - } -} |